:root {
  --ckv-navy: #1b3a5c;
  --ckv-green: #2f8f4e;
  --ckv-bg: #f5f7fa;
}

body {
  background-color: var(--ckv-bg);
  color: #22303f;
}

.ckv-navbar .navbar-brand { letter-spacing: .3px; }
.ckv-navbar .nav-link.active { font-weight: 600; color: var(--ckv-navy) !important; }

/* ---------- Login ---------- */
.login-shell {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(135deg, var(--ckv-navy), #274d74);
}
.login-card {
  width: 100%;
  max-width: 420px;
  border: none;
  border-radius: 16px;
  box-shadow: 0 20px 50px rgba(0,0,0,.25);
}

/* ---------- Candidate list ---------- */
.headshot-thumb {
  width: 48px; height: 48px; object-fit: cover; border-radius: 50%;
  border: 2px solid #fff; box-shadow: 0 0 0 1px #dfe4ea;
}
.candidate-row:hover { background-color: #eef4ff; cursor: pointer; }

/* ---------- Profile page ---------- */
.profile-hero {
  background: linear-gradient(135deg, var(--ckv-navy), #2d5c8a);
  border-radius: 16px;
  color: #fff;
  padding: 2rem;
}
.profile-headshot {
  width: 140px; height: 140px; object-fit: cover; border-radius: 50%;
  border: 4px solid #fff; box-shadow: 0 6px 18px rgba(0,0,0,.35);
  background: #fff;
}
.role-pill {
  font-size: .85rem;
  letter-spacing: .5px;
  text-transform: uppercase;
}
.ckv-card {
  border: none;
  border-radius: 14px;
  box-shadow: 0 2px 12px rgba(20, 30, 45, .06);
}
.ckv-card .card-header {
  background: #fff;
  border-bottom: 1px solid #eef1f5;
  border-radius: 14px 14px 0 0 !important;
  font-weight: 600;
  color: var(--ckv-navy);
}
table.requirements-table th { color: #6b7787; font-weight: 600; font-size: .8rem; text-transform: uppercase; letter-spacing: .4px; }
table.requirements-table td { vertical-align: middle; }

.status-pill { font-size: .78rem; padding: .35em .7em; }

/* Review action buttons */
.review-actions .btn { min-width: 130px; }

/* Calendar */
.cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px; }
.cal-day { background: #fff; border-radius: 10px; min-height: 100px; padding: 6px; border: 1px solid #eef1f5; }
.cal-day.today { border-color: var(--ckv-green); box-shadow: inset 0 0 0 2px var(--ckv-green); }
.cal-day .cal-date { font-size: .75rem; color: #8a95a3; font-weight: 600; }
.cal-event { font-size: .72rem; background: #eaf2ff; color: #1b3a5c; border-radius: 6px; padding: 2px 5px; margin-top: 3px; display: block; text-decoration: none; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cal-event.type-Interview { background: #fdeecb; color: #7a4e00; }
.cal-event.type-Orientation { background: #e2f6e8; color: #1e6b39; }
.cal-event.type-Expiration { background: #fbe1e1; color: #8c1f1f; }
.cal-event.type-Shift { background: #e5e0fb; color: #4b2e9e; }
/* Shift for a candidate not marked "Added to Roster" (v1.65) - flagged, not
   hidden, so a real worked shift never silently disappears just because the
   roster status hasn't caught up yet; the dashed amber border calls out that
   the mismatch itself needs a look. */
.cal-event.not-roster { border: 1px dashed #b8860b; background: #fdf3d9; color: #7a5c00; }
/* Shaded per-designation boxes within a day cell (v1.68, requested directly:
   "a shaded block... that shows CNA, then another that shows RN/LPN") - a
   distinct tinted container per role, sitting around that day's .cal-event
   entries for that role, so who's covering what role each day is visible as
   a shape/pattern, not just a flat undifferentiated list. */
.cal-role-group { border-radius: 8px; padding: 3px 4px 4px; margin-top: 4px; }
.cal-role-group.role-CNA { background: #e7f3fb; }
.cal-role-group.role-Nurse { background: #eafaf0; }
.cal-role-label { font-size: .65rem; font-weight: 700; text-transform: uppercase; letter-spacing: .3px; color: #5a6b7a; margin-bottom: 2px; }
/* Open/unfilled shift (v1.69) - a real coverage gap, not a confirmed person,
   so it's styled to read as an empty slot rather than a name: dashed border,
   no fill color, muted text - sits in the same CNA/RN-LPN box as everyone
   else covering that day, but visually unmistakable as "nobody yet." */
.cal-event.open-shift { background: transparent; border: 1px dashed #9aa5b1; color: #6b7787; }

.avatar-placeholder {
  display: flex; align-items: center; justify-content: center;
  background: #dfe6ee; color: #7c8b9c; font-weight: 700;
}

/* ---------- Candidate self-upload portal ---------- */
.doc-card { position: relative; border: none; border-radius: 14px; box-shadow: 0 2px 12px rgba(20, 30, 45, .06); height: 100%; }
.doc-card .card-body { display: flex; flex-direction: column; }
.doc-card .doc-card-criteria { flex-grow: 1; }
/* Uploaded state (v1.45) - a bigger, unmistakable "done" cue than the small
   status badge alone: the whole card tints green and gets a corner checkmark
   badge, while Replace stays a normal button (uploading again is still one
   click, this is purely a visual state). */
.doc-card.doc-card-complete { background: #eef8f1; border: 1px solid var(--ckv-green); box-shadow: 0 2px 12px rgba(47, 143, 78, .12); }
.doc-card-checkmark {
  position: absolute;
  top: -10px;
  right: -10px;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: var(--ckv-green);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.1rem;
  box-shadow: 0 2px 6px rgba(0, 0, 0, .2);
}

/* ---------- Admin quick-upload (drag and drop) ---------- */
.qu-dropzone {
  border: 2px dashed #cdd5e0;
  border-radius: 10px;
  padding: 1rem;
  text-align: center;
  font-size: .85rem;
  color: #6b7787;
  cursor: pointer;
  transition: border-color .15s, background-color .15s;
}
.qu-dropzone:hover { border-color: var(--ckv-navy); background: #f5f8fc; }

/* ---------- Shifts calendar drag-and-drop ---------- */
.shift-chip { cursor: grab; }
.shift-chip:active { cursor: grabbing; }
.roster-chip:active { cursor: grabbing; }
.shift-chip.shift-dragover { outline: 2px solid var(--ckv-green); outline-offset: 1px; background: #eefaf1 !important; }
.cal-day.shift-dragover { outline: 2px solid var(--ckv-green); outline-offset: -2px; background: #eefaf1; }
.qu-dropzone.qu-dragover { border-color: var(--ckv-green); background: #eefaf1; color: #1e6b39; }
.qu-dropzone.qu-error { border-color: #dc3545; background: #fdecee; color: #8c1f1f; }

/* ---------- "Needs Confirmed" (added v1.84, moved here v1.89 so both
   calendar.php and candidate.php's Calendar widget can share it without
   duplicating the CSS) - deliberately loud: solid red, bold, all-caps, and
   a slow pulse via box-shadow so it can't be mistaken for a routine
   calendar entry at a glance. ---------- */
.needs-confirm-chip {
  display: block; background: #dc3545; color: #fff; font-weight: 700;
  letter-spacing: .02em; cursor: pointer; animation: needsConfirmPulse 1.6s ease-in-out infinite;
  line-height: 1.3; padding-top: 3px; padding-bottom: 3px; border-radius: 6px;
}
.needs-confirm-chip:hover { background: #c82333; color: #fff; }
/* Second line - who/when, so the shift can be identified at a glance while
   it's still pulsing, not just after clicking in. */
.needs-confirm-chip span:last-child { font-weight: 500; letter-spacing: normal; }
@keyframes needsConfirmPulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(220, 53, 69, .55); }
  50% { box-shadow: 0 0 0 5px rgba(220, 53, 69, 0); }
}
/* Whole-row variant for candidates.php's list (added v1.89, widened v1.90
   from an inset glow to a real outer one - "make the whole thing pulsing,
   may add a couple pixel around it so you can see the effect"). A plain
   box-shadow on a <tr> gets clipped by adjacent rows under the default
   collapsed table border model, so .candidates-table switches to a
   separated model with a little vertical gap between every row - that gap
   is what gives the glow room to actually show above and below the row,
   not just at the edges. */
.candidates-table { border-collapse: separate; border-spacing: 0 6px; }
.candidates-table tbody tr:not(.needs-confirm-row) { box-shadow: none; }
.needs-confirm-row { animation: needsConfirmRowPulse 1.6s ease-in-out infinite; }
@keyframes needsConfirmRowPulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(220, 53, 69, .55); }
  50% { box-shadow: 0 0 0 4px rgba(220, 53, 69, .55); }
}

/* ---------- Print (candidate profile doubles as the CKV summary sheet) ---------- */
/* Collapsible card-header toggle (e.g. All Documents on candidate.php,
   collapsed by default) - chevron flips to point up when expanded. */
[data-bs-toggle="collapse"] { cursor: pointer; }
[data-bs-toggle="collapse"] .bi-chevron-down { transition: transform .15s ease; }
[data-bs-toggle="collapse"][aria-expanded="true"] .bi-chevron-down { transform: rotate(180deg); }

@media print {
  .d-print-none { display: none !important; }
  /* A collapsed section must still show up on the printable candidate
     summary sheet - candidate.php doubles as that sheet (see CSS.md). */
  .collapse { display: block !important; height: auto !important; }
  /* Same principle for the Credentials/Schedule tabs (added v1.94) - only
     the active tab-pane would otherwise print, since Bootstrap's own CSS
     hides inactive ones with a plain display:none this block overrides.
     The tab nav itself is already .d-print-none in the markup (a row of
     clickable tab buttons means nothing on paper), same as everywhere else
     interactive-only chrome gets hidden for print. */
  .tab-pane { display: block !important; opacity: 1 !important; }
  body { background: #fff !important; }
  main { padding: 0 !important; }
  .profile-hero {
    background: #fff !important;
    color: #000 !important;
    border: 1px solid #ccc;
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }
  .profile-hero .badge, .profile-hero .opacity-75 { color: #000 !important; }
  .ckv-card { box-shadow: none !important; border: 1px solid #ddd !important; }
  .col-lg-8, .col-lg-4 { width: 100% !important; max-width: 100% !important; flex: 0 0 100% !important; }
  a[href]:after { content: none !important; } /* some browsers auto-append URLs when printing */
}
