/* ── Buttons ──────────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
  font-weight: 500;
  border: 1px solid transparent;
  transition: background var(--transition), border-color var(--transition), color var(--transition);
  white-space: nowrap;
}
.btn:disabled { opacity: 0.5; cursor: not-allowed; }

.btn-primary {
  background: var(--color-primary);
  color: #fff;
  border-color: var(--color-primary);
}
.btn-primary:hover:not(:disabled) { background: var(--color-primary-hover); border-color: var(--color-primary-hover); }

.btn-secondary {
  background: var(--color-surface);
  color: var(--color-text);
  border-color: var(--color-border);
}
.btn-secondary:hover:not(:disabled) { background: var(--color-subtle); }

.btn-danger {
  background: var(--color-danger);
  color: #fff;
  border-color: var(--color-danger);
}
.btn-danger:hover:not(:disabled) { background: var(--color-danger-hover); border-color: var(--color-danger-hover); }

.btn-ghost {
  background: none;
  color: var(--color-muted);
  border-color: transparent;
}
.btn-ghost:hover:not(:disabled) { background: var(--color-subtle); color: var(--color-text); }

/* ── Forms ────────────────────────────────────────────────────────────────── */
.form-group {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  margin-bottom: var(--space-4);
}

label {
  font-size: var(--text-sm);
  font-weight: 500;
  color: var(--color-text);
}

.input {
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  color: var(--color-text);
  transition: border-color var(--transition), box-shadow var(--transition);
  width: 100%;
}
.input:focus {
  border-color: var(--color-primary);
  box-shadow: 0 0 0 3px rgba(29,78,216,.15);
}
.input.error { border-color: var(--color-danger); }

select.input { appearance: none; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%2364748b' d='M6 8L1 3h10z'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 10px center; padding-right: 2rem; }

/* ── Cards ────────────────────────────────────────────────────────────────── */
.card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: var(--space-6);
  box-shadow: var(--shadow-sm);
}

/* ── Badge ────────────────────────────────────────────────────────────────── */
.badge {
  display: inline-flex;
  align-items: center;
  padding: 2px var(--space-2);
  border-radius: 999px;
  font-size: 0.7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.badge-blue   { background: #dbeafe; color: #1d4ed8; }
.badge-amber  { background: #fef3c7; color: #92400e; }
.badge-red    { background: #fee2e2; color: #991b1b; }
.badge-green  { background: #dcfce7; color: #166534; }
.badge-gray   { background: var(--color-subtle); color: var(--color-muted); }

/* Period status badges */
.status-wish_open   { background: #dcfce7; color: #166534; }
.status-wish_closed { background: #fef3c7; color: #92400e; }
.status-draft       { background: #dbeafe; color: #1e40af; }
.status-locked      { background: #f3e8ff; color: #6b21a8; }
.status-published   { background: #e0f2fe; color: #075985; }

/* Category badges — identity, not severity (see base.css's --cat-* tokens
   and CHANGELOG.md "Anesthesiologist clarity pass"). Never mix with
   .badge-red/amber/green/blue, which stay reserved for status/outcome. */
.badge-cat-rose  { background: var(--cat-rose-bg);  color: var(--cat-rose); }
.badge-cat-denim { background: var(--cat-denim-bg); color: var(--cat-denim); }
.badge-cat-clay  { background: var(--cat-clay-bg);  color: var(--cat-clay); }
.badge-cat-moss  { background: var(--cat-moss-bg);  color: var(--cat-moss); }
.badge-cat-plum  { background: var(--cat-plum-bg);  color: var(--cat-plum); }

/* ── Icons (fixed vocabulary, components/icons.js) ───────────────────────── */
.icon {
  display: inline-flex;
  flex-shrink: 0;
  vertical-align: -3px;
}
.icon-muted { color: var(--color-muted); }

/* ── Modal ────────────────────────────────────────────────────────────────── */
.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,.45);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 500;
  padding: var(--space-4);
}

.modal {
  background: var(--color-surface);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  width: 100%;
  max-width: 480px;
  max-height: 90vh;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
}

.modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-4) var(--space-6);
  border-bottom: 1px solid var(--color-border);
}

.modal-header h2 { font-size: var(--text-base); font-weight: 600; }

.modal-body { padding: var(--space-6); flex: 1; }

.modal-footer {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-6);
  border-top: 1px solid var(--color-border);
}

/* ── Toast ────────────────────────────────────────────────────────────────── */
#toast-container {
  position: fixed;
  bottom: var(--space-6);
  right: var(--space-6);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  z-index: 1000;
}

.toast {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  font-size: var(--text-sm);
  font-weight: 500;
  animation: slideIn 200ms ease;
  max-width: 360px;
}

@keyframes slideIn {
  from { transform: translateX(120%); opacity: 0; }
  to   { transform: translateX(0);   opacity: 1; }
}

.toast-success { background: #166534; color: #fff; }
.toast-error   { background: var(--color-danger); color: #fff; }
.toast-info    { background: var(--color-primary); color: #fff; }

/* ── Calendar ─────────────────────────────────────────────────────────────── */
/* A 7-column grid, not a <table> — components/calendar.js renders header
   cells and day cells as plain sibling divs and lets grid auto-placement
   wrap every 7 into a row. Two things this buys over the table markup it
   replaced:
   - `grid-template-columns: repeat(7, 1fr)` keeps all 7 day columns equal-
     width regardless of cell content, the same guarantee `table-layout:
     fixed` used to give.
   - Grid's default `align-items: stretch` makes every cell in a row match
     its tallest sibling for free. A table cell's child can't reliably do
     this — percentage heights don't resolve against a table cell whose own
     height is auto — so a lightly-loaded day used to visibly stop short of
     a heavier one in the same week (more wish/shift badges, more avatars).
   `gap` replaces the old per-cell `<td>` padding as the gutter between
   cells, now that cells are direct grid children with no wrapper. */
.calendar {
  width: 100%;
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 4px;
  user-select: none;
}

.cal-th {
  padding: var(--space-2) var(--space-1);
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--color-muted);
  text-align: center;
}

.cal-cell {
  min-height: 80px;
  padding: var(--space-2);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  cursor: default;
  transition: background var(--transition);
  position: relative;
}

/* Only cells wired up with onDayClick get role="button" (components/calendar.js)
   — a display-only grid (my-schedule.js, schedules.js) stays non-interactive-
   looking: no pointer cursor, no hover/focus tint. */
.cal-cell[role="button"] { cursor: pointer; }
.cal-cell[role="button"]:hover { background: #eff6ff; }
.cal-cell[role="button"]:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: -2px;
  background: #eff6ff;
}
.cal-cell.other-month { background: var(--color-subtle); opacity: 0.5; cursor: default; }
.cal-cell.today { border-color: var(--color-primary); }
.cal-cell.locked { cursor: not-allowed; background: var(--color-subtle); }
.cal-cell.selected { border-color: var(--color-primary); box-shadow: 0 0 0 2px rgba(29,78,216,.2); }

/* Weekend shading — a translucent overlay layer rather than a `background`
   rule, so it composites on top of whatever background a cell already has
   (heatmap colour, .sc-holiday, plain surface) instead of fighting those
   rules for specificity. Matches the neutral-gray weekend wash roster-grid's
   .rgv2-row-weekend already established. */
.cal-cell.weekend::after {
  content: '';
  position: absolute;
  inset: 0;
  background: rgba(15, 23, 42, .035);
  pointer-events: none;
  border-radius: inherit;
}

/* Off-wish density heatmap (wish-overview.js) — a class rather than an inline
   colour so dark mode can override it here instead of every consumer having
   to do its own inline-style dark-mode dance. Standalone (not compounded
   with .cal-cell) so the legend key's .heatmap-swatch spans share the same
   colours/dark overrides. */
.cal-heat-low  { background: #fee2e2; }
.cal-heat-med  { background: #fca5a5; }
.cal-heat-high { background: #ef4444; }

/* "Likely understaffed" forecast flag (wish-overview.js) */
.cal-cell.shortage { border: 2px solid var(--color-danger); }

/* Staffing calendar override / holiday markers (staffing-calendar.js) — same
   amber "informational, not a hard violation" treatment as .conflict-soft. */
.cal-cell.sc-has-override { border-color: var(--color-warning); }
.cal-cell.sc-holiday { background: #fffbeb; }
.sc-badge {
  position: absolute;
  top: var(--space-1);
  right: var(--space-1);
  font-size: 0.7rem;
  line-height: 1;
}
.sc-badge-holiday { right: auto; left: var(--space-1); }

/* Standardized month/period navigation bar (components/calendar-nav.js) — the
   single prev/next + jump-to-period control every calendar/period-scoped view
   mounts, replacing what used to be a different hand-rolled <select> or
   button pair per view (some period-based, some raw month arithmetic — see
   that file's header comment). The jump control is a real <select>
   (.calendar-nav-select) styled to read as a clickable label rather than a
   boxed dropdown, so views that only ever showed a plain text label
   (staffing-calendar.js's freeform month mode) and views that showed a full
   dropdown both end up visually consistent. */
.calendar-nav {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}
.calendar-nav-btn {
  min-width: 2rem;
  justify-content: center;
}
.calendar-nav-label {
  font-weight: 600;
  min-width: 10ch;
  text-align: center;
}
.calendar-nav-select {
  appearance: auto;
  border: none;
  background: transparent;
  color: var(--color-text);
  font-weight: 600;
  font-size: var(--text-base);
  text-align: center;
  text-align-last: center;
  cursor: pointer;
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-sm);
  max-width: 220px;
}
.calendar-nav-select:hover { background: var(--color-subtle); }
.calendar-nav-select:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: -2px;
}

/* staffing-calendar.js's day cells can carry BOTH an override and a holiday
   badge at once (unlike wish-submission.js/current-schedule.js, which only
   ever show one or the other) — .sc-badge-row groups them into a single
   top-right cluster instead of reusing .sc-badge/.sc-badge-holiday's fixed
   opposite-corner placement, which would stack one directly on the day number. */
.sc-badge-row {
  position: absolute;
  top: var(--space-1);
  right: var(--space-1);
  display: flex;
  gap: 4px;
  font-size: 0.7rem;
  line-height: 1;
}

/* Per-location color slots — the app-wide location identity axis (see
   location-colors.js). One explicit CSS class per palette slot (.loc-1..8,
   plus a .loc-other overflow slot) rather than an inline custom property
   holding a nested var() reference — the same direct-class approach the
   app's existing .badge-cat-rose/.badge-cat-denim category badges already
   use, and safer than custom-property indirection across browsers. Each
   component defines its own application of these slots (background here for
   the small circular need-badges below; border-left-color for .shift-chip,
   background tint for .ms-hero, etc. — see each component's own rules). */
.sc-need-badge.loc-1 { background: var(--loc-1); }
.sc-need-badge.loc-2 { background: var(--loc-2); }
.sc-need-badge.loc-3 { background: var(--loc-3); }
.sc-need-badge.loc-4 { background: var(--loc-4); }
.sc-need-badge.loc-5 { background: var(--loc-5); }
.sc-need-badge.loc-6 { background: var(--loc-6); }
.sc-need-badge.loc-7 { background: var(--loc-7); }
.sc-need-badge.loc-8 { background: var(--loc-8); }
.sc-need-badge.loc-other { background: var(--color-muted); }

/* Per-location staffing-need badges (staffing-calendar.js) — same small-circle
   idiom as .curr-sched-avatar. */
#sc-calendar .cal-cell { min-height: 104px; }

.sc-need-row {
  display: flex;
  flex-wrap: wrap;
  gap: 3px;
  margin-top: var(--space-1);
}

.sc-need-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  font-size: 0.65rem;
  font-weight: 700;
  line-height: 1;
  color: #fff;
  flex-shrink: 0;
  cursor: default;
  user-select: none;
}

/* On-call/off-hour need — a ring instead of a solid fill, same hue, so it
   reads as "the same location, a different kind of need" rather than a
   different location entirely. */
.sc-need-badge.oncall {
  width: 18px;
  height: 18px;
  background: var(--color-surface);
  border: 2px solid var(--color-muted);
  color: var(--color-muted);
}
.sc-need-badge.oncall.loc-1 { border-color: var(--loc-1); color: var(--loc-1); }
.sc-need-badge.oncall.loc-2 { border-color: var(--loc-2); color: var(--loc-2); }
.sc-need-badge.oncall.loc-3 { border-color: var(--loc-3); color: var(--loc-3); }
.sc-need-badge.oncall.loc-4 { border-color: var(--loc-4); color: var(--loc-4); }
.sc-need-badge.oncall.loc-5 { border-color: var(--loc-5); color: var(--loc-5); }
.sc-need-badge.oncall.loc-6 { border-color: var(--loc-6); color: var(--loc-6); }
.sc-need-badge.oncall.loc-7 { border-color: var(--loc-7); color: var(--loc-7); }
.sc-need-badge.oncall.loc-8 { border-color: var(--loc-8); color: var(--loc-8); }
.sc-need-badge.oncall.loc-other { border-color: var(--color-muted); color: var(--color-muted); }

.sc-legend {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  margin-top: var(--space-2);
}

.sc-legend-item {
  display: flex;
  align-items: center;
  gap: 5px;
  font-size: var(--text-sm);
  color: var(--color-muted);
}

.sc-legend-swatch {
  display: inline-block;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  flex-shrink: 0;
  background: var(--color-muted);
}
.sc-legend-swatch.loc-1 { background: var(--loc-1); }
.sc-legend-swatch.loc-2 { background: var(--loc-2); }
.sc-legend-swatch.loc-3 { background: var(--loc-3); }
.sc-legend-swatch.loc-4 { background: var(--loc-4); }
.sc-legend-swatch.loc-5 { background: var(--loc-5); }
.sc-legend-swatch.loc-6 { background: var(--loc-6); }
.sc-legend-swatch.loc-7 { background: var(--loc-7); }
.sc-legend-swatch.loc-8 { background: var(--loc-8); }

.cal-day {
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--color-muted);
  margin-bottom: var(--space-1);
}

.cal-cell.today .cal-day { color: var(--color-primary); }

/* Aggregate-only "N colleagues also want this off" hint — deliberately more
   muted than the .sch-shift-badge wish chips above it since it's density
   context, not the user's own commitment. */
.cal-wish-density {
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: 0.68rem;
  color: var(--color-muted);
  margin-top: 2px;
}
.cal-wish-density .icon { vertical-align: -2px; }

/* ── Wish submission page ─────────────────────────────────────────────────── */
/* The base .calendar rule above already keeps columns equal-width; this just
   lets badge text truncate cleanly inside its fixed-width cell instead of
   overflowing or wrapping awkwardly when it doesn't fit. */
#calendar-container .sch-shift-name,
#calendar-container .sch-loc-name,
#calendar-container .sch-shift-times {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}

.wish-page-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-4);
  margin-bottom: var(--space-6);
  flex-wrap: wrap;
}

.wish-page-controls {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  flex-wrap: wrap;
  justify-content: flex-end;
}

/* One legend item per active location (location-colors.js) plus the fixed
   "preferred off" and on-call/off-hours entries — mirrors my-schedule.js's
   .schedule-legend key (CLAUDE.md §13.1) rather than the old fixed two-swatch
   off/shift key, since a "preferred shift type" wish's colour now depends on
   its optional location, not its wish type alone. */
.wish-legend {
  display: flex;
  gap: var(--space-3);
  align-items: center;
  flex-wrap: wrap;
  font-size: var(--text-sm);
}

/* A preferred_off wish carries no location, so it keeps this fixed rose tint
   (the same token the old .cal-wish-off chip used) instead of a location hue
   — reuses .sch-shift-badge's shape/dot so it still looks like one visual
   family with the location-coloured shift-wish badges beside it. */
.sch-shift-badge.wish-off-badge {
  background: var(--cat-rose-bg);
  color: var(--cat-rose);
  border-left-color: var(--cat-rose);
}

/* ── Wish modal: review vs. commit ─────────────────────────────────────────
   Existing wishes for a day and the add/update form are different tasks
   (review vs. commit) — a real panel boundary instead of a thin <hr>, so the
   eye doesn't have to guess where one ends and the other begins. */
.wish-existing-panel {
  background: var(--color-subtle);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: var(--space-3);
  margin-bottom: var(--space-4);
}
.wish-existing-title {
  font-size: var(--text-2xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-muted);
  margin-bottom: var(--space-2);
}
.wish-existing-row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-1) 0;
}
.wish-existing-row:not(:last-child) { border-bottom: 1px solid var(--color-border); }
.wish-existing-note { flex: 1; }
.wish-existing-row .delete-wish { margin-left: auto; color: var(--status-danger); flex-shrink: 0; }

.wish-form-section h3 { margin-bottom: var(--space-3); }

.legend-item {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

/* .legend-dot itself is defined once, in the Schedule legend section below —
   this section's .legend-item already provides flex + gap spacing, so that
   shared definition's own margin/display/vertical-align are harmless here. */

/* ── Login page ───────────────────────────────────────────────────────────── */
.login-page {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  background: var(--color-bg);
}

.login-card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-8);
  width: 100%;
  max-width: 400px;
  box-shadow: var(--shadow);
}

.login-card .brand {
  font-size: var(--text-xl);
  font-weight: 700;
  color: var(--color-primary);
  text-align: center;
  margin-bottom: var(--space-2);
}

.login-card .subtitle {
  text-align: center;
  color: var(--color-muted);
  font-size: var(--text-sm);
  margin-bottom: var(--space-8);
}

.login-theme-button {
  position: fixed;
  top: var(--space-4);
  right: var(--space-4);
  display: grid;
  width: 42px;
  height: 42px;
  padding: 0;
  place-items: center;
  border: 1px solid var(--color-border);
  border-radius: 50%;
  background: var(--color-surface);
  color: var(--color-text);
  font: inherit;
  font-size: 1.15rem;
  line-height: 1;
  cursor: pointer;
  box-shadow: var(--shadow-sm);
  transition: background var(--transition), border-color var(--transition), transform var(--transition);
}
.login-theme-button:hover { background: var(--color-subtle); transform: translateY(-1px); }
.login-theme-button:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 2px; }

/* Sits to the left of the theme button (42px + gap) rather than its own fixed slot. */
.login-lang-button { right: calc(var(--space-4) + 42px + var(--space-2)); }

/* ── Period status bar ────────────────────────────────────────────────────── */
.status-bar {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-3) var(--space-4);
  background: var(--color-subtle);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  margin-bottom: var(--space-6);
  flex-wrap: wrap;
}

.status-bar .label { font-size: var(--text-sm); color: var(--color-muted); }
.status-bar .value { font-weight: 600; }

/* ── Notification dropdown ────────────────────────────────────────────────── */
.notif-panel {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  width: 340px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  z-index: 200;
  overflow: hidden;
}

/* Anchor the topbar so the panel can use position:absolute */
#topbar { position: relative; }
#btn-notifications { position: relative; }

.notif-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--color-border);
  background: var(--color-subtle);
}

.notif-title { font-weight: 600; font-size: var(--text-sm); }

.notif-mark-all {
  font-size: var(--text-sm);
  color: var(--color-primary);
  padding: 0;
}

.notif-list {
  max-height: 380px;
  overflow-y: auto;
}

.notif-item {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--color-border);
  cursor: pointer;
  transition: background var(--transition);
  position: relative;
  background: #fffbeb; /* unread tint */
}
.notif-item:last-child { border-bottom: none; }
.notif-item:hover { background: var(--color-subtle); }
.notif-item.notif-read { background: var(--color-surface); }

.notif-icon { font-size: 1.1rem; flex-shrink: 0; margin-top: 1px; }

.notif-body { flex: 1; min-width: 0; }

.notif-text {
  font-size: var(--text-sm);
  line-height: 1.4;
  color: var(--color-text);
}

.notif-time {
  font-size: 0.72rem;
  margin-top: 2px;
}

.notif-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--color-primary);
  flex-shrink: 0;
  margin-top: 5px;
}

.notif-empty {
  padding: var(--space-6);
  text-align: center;
}

.notif-loading {
  padding: var(--space-4);
  text-align: center;
}

/* ── Roster editor ────────────────────────────────────────────────────────── */
.roster-layout {
  display: grid;
  grid-template-columns: 1fr 260px;
  gap: var(--space-6);
  align-items: start;
}

.roster-statusbar {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
  margin-bottom: var(--space-5);
  padding: var(--space-3) var(--space-4);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
}

/* ── Autosuggest progress bar ─────────────────────────────────────────────── */
/* Estimated, not real progress: the autosuggest request is one blocking call
   (see CLAUDE.md §6 — CP-SAT's wall-clock time is bounded by server config,
   not reported incrementally), so this approaches but never reaches 100% on
   its own — it only reaches 100% when the response actually arrives. */
.autosuggest-progress {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin: calc(-1 * var(--space-3)) 0 var(--space-5);
  padding: var(--space-2) var(--space-4);
  font-size: var(--text-sm);
  color: var(--color-muted);
}

.autosuggest-progress-track {
  flex: 1;
  height: 6px;
  background: var(--color-border);
  border-radius: 3px;
  overflow: hidden;
}

.autosuggest-progress-fill {
  height: 100%;
  width: 0%;
  background: var(--color-primary);
  border-radius: 3px;
}

/* ── Violation panel ──────────────────────────────────────────────────────── */
.violation-panel {
  position: sticky;
  top: 72px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
  max-height: calc(100vh - 100px);
  overflow-y: auto;
}

.violation-panel-header {
  padding: var(--space-3) var(--space-4);
  font-weight: 600;
  font-size: var(--text-sm);
  border-bottom: 1px solid var(--color-border);
  background: var(--color-subtle);
  position: sticky;
  top: 0;
}

.violation-item {
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--color-border);
  cursor: pointer;
  transition: background var(--transition);
}
.violation-item:hover { background: #fff5f5; }
.violation-item:last-child { border-bottom: none; }

.violation-date {
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--color-danger);
  margin-bottom: 2px;
}

.violation-detail {
  font-size: 0.72rem;
  color: var(--color-muted);
  line-height: 1.4;
}

.violation-ok {
  padding: var(--space-4);
  font-size: var(--text-sm);
  color: var(--color-success);
  font-weight: 500;
  text-align: center;
}

/* ── Assignment modal extras ─────────────────────────────────────────────── */
.modal-current-assign {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-2) var(--space-3);
  background: var(--color-subtle);
  border-radius: var(--radius-sm);
  margin-bottom: var(--space-4);
  font-size: var(--text-sm);
}

.user-list {
  max-height: 280px;
  overflow-y: auto;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
}

.user-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  cursor: pointer;
  border-bottom: 1px solid var(--color-border);
  transition: background var(--transition);
}
.user-row:last-child { border-bottom: none; }
.user-row:hover { background: var(--color-subtle); }
.user-row.user-row-current { background: #eff6ff; }
.user-row.user-row-disabled { opacity: 0.6; }
.user-row input[type="radio"] { flex-shrink: 0; }
.user-row-name { flex: 1; font-size: var(--text-sm); font-weight: 500; }
.user-row-icons { display: flex; gap: 4px; align-items: center; }

.user-badge {
  font-size: 0.68rem;
  padding: 1px 5px;
  border-radius: 3px;
  font-weight: 600;
}
.user-badge.wish-match { background: #dbeafe; color: #1e40af; }
.user-badge.wish-off   { background: #fef3c7; color: #92400e; }
.user-badge.conflict   { background: #fee2e2; color: #991b1b; }

.btn-sm { padding: 2px 8px; font-size: var(--text-sm); }

/* ── My Schedule ──────────────────────────────────────────────────────────── */
.my-schedule-layout {
  display: grid;
  grid-template-columns: 1fr 220px;
  gap: var(--space-6);
  align-items: start;
}

/* ── My Schedule: hero panel ──────────────────────────────────────────────
   One hero per page (design principle: "every screen has exactly one
   hero"). Replaces what used to be two equal-weight boxes — a Today card
   and a separate 3-tile stat bar — with a single panel: today's shift is
   the one big fact, the at-a-glance numbers are a quiet line underneath
   it instead of their own boxed row. Background tints to the category
   colour of today's shift (see shiftCategory() in my-schedule.js) so the
   hero visually rhymes with the same shift's colour on the calendar below. */
.ms-hero {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding: var(--space-6);
  margin-bottom: var(--space-6);
  border-radius: var(--radius-lg);
  background: var(--color-subtle);
}
/* Location tint (location-colors.js) — a pale wash derived from the solid
   --loc-N hue via color-mix(), the same technique shift-distribution.js's
   dist-heat-* classes already use, rather than minting 8 more "-bg" tokens. */
.ms-hero.loc-1 { background: color-mix(in srgb, var(--loc-1) 14%, var(--color-surface)); }
.ms-hero.loc-2 { background: color-mix(in srgb, var(--loc-2) 14%, var(--color-surface)); }
.ms-hero.loc-3 { background: color-mix(in srgb, var(--loc-3) 14%, var(--color-surface)); }
.ms-hero.loc-4 { background: color-mix(in srgb, var(--loc-4) 14%, var(--color-surface)); }
.ms-hero.loc-5 { background: color-mix(in srgb, var(--loc-5) 14%, var(--color-surface)); }
.ms-hero.loc-6 { background: color-mix(in srgb, var(--loc-6) 14%, var(--color-surface)); }
.ms-hero.loc-7 { background: color-mix(in srgb, var(--loc-7) 14%, var(--color-surface)); }
.ms-hero.loc-8 { background: color-mix(in srgb, var(--loc-8) 14%, var(--color-surface)); }

.ms-hero-label {
  font-size: var(--text-xs);
  font-weight: 600;
  color: var(--color-muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.ms-hero-body { font-size: var(--text-base); }

.ms-hero-shift {
  font-size: var(--text-2xl);
  font-weight: 700;
  line-height: 1.25;
  margin-top: 2px;
}
.ms-hero.loc-1 .ms-hero-shift { color: var(--loc-1); }
.ms-hero.loc-2 .ms-hero-shift { color: var(--loc-2); }
.ms-hero.loc-3 .ms-hero-shift { color: var(--loc-3); }
.ms-hero.loc-4 .ms-hero-shift { color: var(--loc-4); }
.ms-hero.loc-5 .ms-hero-shift { color: var(--loc-5); }
.ms-hero.loc-6 .ms-hero-shift { color: var(--loc-6); }
.ms-hero.loc-7 .ms-hero-shift { color: var(--loc-7); }
.ms-hero.loc-8 .ms-hero-shift { color: var(--loc-8); }

.ms-hero-shift-meta { margin-top: 2px; }
.ms-hero-shift-meta:first-child { margin-top: 0; }

.ms-hero-stats {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-6);
  margin-top: var(--space-3);
  padding-top: var(--space-3);
  border-top: 1px solid rgba(0,0,0,.08);
}
[data-theme="dark"] .ms-hero-stats { border-top-color: rgba(255,255,255,.08); }
.ms-hero-stat-value { font-weight: 700; font-size: var(--text-lg); }
.ms-hero-stat-label { font-size: var(--text-2xs); color: var(--color-muted); text-transform: uppercase; letter-spacing: 0.04em; }

.sch-shift-badge {
  border-radius: var(--radius-sm);
  padding: 2px var(--space-2);
  margin-bottom: 2px;
  font-size: 0.7rem;
  font-weight: 600;
  display: flex;
  flex-direction: column;
  gap: 1px;
  border-left: 5px solid transparent;
}
/* Location colour (identity) — location-colors.js, the same axis the hero
   panel and upcoming-shift cards use, so a shift's colour means the same
   thing everywhere it appears. A thick left border alone reads weakly at
   this badge's compact size, so .sch-shift-name also carries a .chip-dot
   (same dot markup roster-grid.js/day-detail.js use) — it inherits the
   badge's own `color`, so no separate per-slot dot rules are needed here,
   unlike .shift-chip's below (which doesn't tint its own text). A hollow
   ring (chip-oncall) marks on-call/off-hours instead of the solid dot —
   the fill-style channel §13.1 defines, stronger than the previous
   dashed-vs-solid border alone. */
.sch-shift-badge.loc-1 { background: color-mix(in srgb, var(--loc-1) 14%, var(--color-surface)); color: var(--loc-1); border-left-color: var(--loc-1); }
.sch-shift-badge.loc-2 { background: color-mix(in srgb, var(--loc-2) 14%, var(--color-surface)); color: var(--loc-2); border-left-color: var(--loc-2); }
.sch-shift-badge.loc-3 { background: color-mix(in srgb, var(--loc-3) 14%, var(--color-surface)); color: var(--loc-3); border-left-color: var(--loc-3); }
.sch-shift-badge.loc-4 { background: color-mix(in srgb, var(--loc-4) 14%, var(--color-surface)); color: var(--loc-4); border-left-color: var(--loc-4); }
.sch-shift-badge.loc-5 { background: color-mix(in srgb, var(--loc-5) 14%, var(--color-surface)); color: var(--loc-5); border-left-color: var(--loc-5); }
.sch-shift-badge.loc-6 { background: color-mix(in srgb, var(--loc-6) 14%, var(--color-surface)); color: var(--loc-6); border-left-color: var(--loc-6); }
.sch-shift-badge.loc-7 { background: color-mix(in srgb, var(--loc-7) 14%, var(--color-surface)); color: var(--loc-7); border-left-color: var(--loc-7); }
.sch-shift-badge.loc-8 { background: color-mix(in srgb, var(--loc-8) 14%, var(--color-surface)); color: var(--loc-8); border-left-color: var(--loc-8); }
/* Overflow slot — also hit by wish-submission.js's shift-type wishes that
   have no location preference set at all (location_id is optional, §3.6). */
.sch-shift-badge.loc-other { background: var(--color-subtle); color: var(--color-muted); border-left-color: var(--color-muted); }
.sch-shift-badge.chip-oncall { border-left-style: dashed; }
.sch-shift-badge .chip-dot { background: currentColor; }
.sch-shift-badge.chip-oncall .chip-dot { background: transparent; border: 1.5px solid currentColor; }
.sch-shift-name { font-weight: 700; display: flex; align-items: center; gap: 4px; }
.sch-loc-name   { font-weight: 400; opacity: 0.8; }
/* Future shifts render as an <a> (shiftBadgeHTML, my-schedule.js) — a direct
   "click a date to request a swap" affordance; reset link chrome and add a
   focus/hover cue so it still reads as clickable. */
a.sch-shift-badge { text-decoration: none; color: inherit; cursor: pointer; }
a.sch-shift-badge:hover, a.sch-shift-badge:focus-visible { outline: 2px solid currentColor; outline-offset: 1px; }

/* Upcoming panel */
.upcoming-panel {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: var(--shadow-sm);
  margin-bottom: var(--space-4);
}

.upcoming-header {
  padding: var(--space-3) var(--space-4);
  font-weight: 600;
  font-size: var(--text-sm);
  border-bottom: 1px solid var(--color-border);
  background: var(--color-subtle);
}

.upcoming-card {
  padding: var(--space-3) var(--space-4);
  border-left: 5px solid var(--color-border);
  border-bottom: 1px solid var(--color-border);
  transition: background var(--transition);
}
.upcoming-card:last-child { border-bottom: none; }
.upcoming-card:hover      { background: var(--color-subtle); }
.upcoming-card.loc-1 { border-left-color: var(--loc-1); } .upcoming-card.loc-1 .chip-dot { background: var(--loc-1); }
.upcoming-card.loc-2 { border-left-color: var(--loc-2); } .upcoming-card.loc-2 .chip-dot { background: var(--loc-2); }
.upcoming-card.loc-3 { border-left-color: var(--loc-3); } .upcoming-card.loc-3 .chip-dot { background: var(--loc-3); }
.upcoming-card.loc-4 { border-left-color: var(--loc-4); } .upcoming-card.loc-4 .chip-dot { background: var(--loc-4); }
.upcoming-card.loc-5 { border-left-color: var(--loc-5); } .upcoming-card.loc-5 .chip-dot { background: var(--loc-5); }
.upcoming-card.loc-6 { border-left-color: var(--loc-6); } .upcoming-card.loc-6 .chip-dot { background: var(--loc-6); }
.upcoming-card.loc-7 { border-left-color: var(--loc-7); } .upcoming-card.loc-7 .chip-dot { background: var(--loc-7); }
.upcoming-card.loc-8 { border-left-color: var(--loc-8); } .upcoming-card.loc-8 .chip-dot { background: var(--loc-8); }
.upcoming-card.chip-oncall { border-left-style: dashed; }
.upcoming-card.chip-oncall .chip-dot { background: transparent; border: 1.5px solid var(--color-muted); }
.upcoming-card.chip-oncall.loc-1 .chip-dot { border-color: var(--loc-1); }
.upcoming-card.chip-oncall.loc-2 .chip-dot { border-color: var(--loc-2); }
.upcoming-card.chip-oncall.loc-3 .chip-dot { border-color: var(--loc-3); }
.upcoming-card.chip-oncall.loc-4 .chip-dot { border-color: var(--loc-4); }
.upcoming-card.chip-oncall.loc-5 .chip-dot { border-color: var(--loc-5); }
.upcoming-card.chip-oncall.loc-6 .chip-dot { border-color: var(--loc-6); }
.upcoming-card.chip-oncall.loc-7 .chip-dot { border-color: var(--loc-7); }
.upcoming-card.chip-oncall.loc-8 .chip-dot { border-color: var(--loc-8); }

.upcoming-date  { font-size: var(--text-sm); color: var(--color-muted); }
.upcoming-shift { font-weight: 600; font-size: var(--text-sm); margin: 2px 0; display: flex; align-items: center; gap: 6px; }
.upcoming-loc   { font-size: var(--text-sm); }

.upcoming-swap-link {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin-top: var(--space-2);
  color: var(--color-primary, #2563eb);
  text-decoration: none;
}
.upcoming-swap-link:hover { text-decoration: underline; }

/* Cross-link to Schedules, under the period nav — makes the My Schedule /
   Schedules split legible in the UI instead of tribal knowledge (see
   CHANGELOG.md "Anesthesiologist clarity pass"). */
.ms-schedules-link {
  font-size: var(--text-sm);
  color: var(--color-muted);
  margin: calc(-1 * var(--space-3)) 0 var(--space-4);
}
.ms-schedules-link a { color: var(--color-muted); text-decoration: underline; text-underline-offset: 2px; }
.ms-schedules-link a:hover { color: var(--color-primary); }

.upcoming-empty {
  padding: var(--space-4);
  text-align: center;
}

.schedule-legend {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: var(--space-3) var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.legend-dot {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 2px;
  margin-right: var(--space-2);
  vertical-align: middle;
  background: var(--color-muted);
}
.legend-dot.loc-1 { background: var(--loc-1); }
.legend-dot.loc-2 { background: var(--loc-2); }
.legend-dot.loc-3 { background: var(--loc-3); }
.legend-dot.loc-4 { background: var(--loc-4); }
.legend-dot.loc-5 { background: var(--loc-5); }
.legend-dot.loc-6 { background: var(--loc-6); }
.legend-dot.loc-7 { background: var(--loc-7); }
.legend-dot.loc-8 { background: var(--loc-8); }

/* ── Wish overview ────────────────────────────────────────────────────────── */
.wish-stats-bar {
  display: flex;
  gap: var(--space-6);
  padding: var(--space-4) var(--space-6);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  margin-bottom: var(--space-6);
  box-shadow: var(--shadow-sm);
  flex-wrap: wrap;
}

.wish-stat { text-align: center; }
.wish-stat-value { font-size: 1.5rem; font-weight: 700; line-height: 1; }
.wish-stat-label { font-size: var(--text-sm); color: var(--color-muted); margin-top: 2px; }

.wish-overview-layout {
  display: grid;
  grid-template-columns: 1fr 260px;
  gap: var(--space-6);
  align-items: start;
}

.wish-calendar-wrap {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: var(--space-4);
  box-shadow: var(--shadow-sm);
}

/* Heatmap legend */
.wish-heatmap-legend {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
  flex-wrap: wrap;
}

.heatmap-scale { display: flex; align-items: center; gap: var(--space-2); font-size: var(--text-sm); }

.heatmap-swatch {
  display: inline-block;
  width: 14px;
  height: 14px;
  border-radius: 3px;
  vertical-align: middle;
}

.wish-dot-legend {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  vertical-align: middle;
  margin-right: 4px;
}
.wish-dot-legend.shift { background: var(--color-primary); }
.wish-dot-legend.leave { background: var(--cat-moss); }

/* Heatmap cell content — the grid itself renders through the shared
   .calendar/.cal-cell (components/calendar.js); .cal-heat-;.selected/.shortage
   modifiers live in that shared block above. */
.hm-counts { display: flex; gap: 3px; flex-wrap: wrap; }

.hm-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  border-radius: 9px;
  font-size: 0.65rem;
  font-weight: 700;
  padding: 0 4px;
}
.hm-badge.off   { background: #fee2e2; color: #991b1b; }
.hm-badge.shift { background: #dbeafe; color: #1e40af; }
.hm-badge.leave { background: var(--cat-moss-bg); color: var(--cat-moss); }

/* Day detail panel */
.wish-day-panel {
  position: sticky;
  top: 72px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
  max-height: calc(100vh - 100px);
  overflow-y: auto;
}

.wish-day-panel-empty {
  padding: var(--space-6);
  text-align: center;
}

.day-panel-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--color-border);
  background: var(--color-subtle);
  position: sticky;
  top: 0;
}

.day-panel-section { padding: var(--space-3) var(--space-4); }

.day-panel-section-title {
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-muted);
  margin-bottom: var(--space-2);
}

.day-wish-row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-1) 0;
  font-size: var(--text-sm);
  border-bottom: 1px solid var(--color-border);
}
.day-wish-row:last-child { border-bottom: none; }

.day-wish-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
}
.day-wish-dot.off   { background: var(--color-danger); }
.day-wish-dot.shift { background: var(--color-primary); }
.day-wish-dot.leave { background: var(--cat-moss); }

.day-wish-name  { font-weight: 500; }
.day-wish-note  { flex: 1; text-align: right; }

/* ── My Leave: balance cards ──────────────────────────────────────────────
   Hero tier for this page (design principle: "every screen has exactly one
   hero" — here, two, since holiday and educational are equally primary).
   Category-tinted (moss/plum) rather than a plain stat tile, so the figure
   that matters most on this screen reads at a glance. */
.leave-balance {
  background: var(--color-subtle);
  border-radius: var(--radius-lg);
  padding: var(--space-5) var(--space-6);
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.leave-balance.cat-moss { background: var(--cat-moss-bg); }
.leave-balance.cat-plum { background: var(--cat-plum-bg); }
.leave-balance-label {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: var(--text-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-muted);
}
.leave-balance.cat-moss .leave-balance-label { color: var(--cat-moss); }
.leave-balance.cat-plum .leave-balance-label { color: var(--cat-plum); }
.leave-balance-value { font-size: var(--text-2xl); font-weight: 700; margin: 2px 0; }
.leave-balance-unit { font-size: var(--text-sm); font-weight: 500; color: var(--color-muted); margin-left: 4px; }
.leave-balance-pending {
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: var(--text-2xs);
  color: var(--color-muted);
  margin-top: var(--space-1);
}

/* ── Swap requests ────────────────────────────────────────────────────────── */
.swap-columns {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-6);
  align-items: start;
}

.swap-section-title {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-bottom: var(--space-4);
  font-size: var(--text-base);
  font-weight: 600;
}

.swap-card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  margin-bottom: var(--space-3);
  overflow: hidden;
  box-shadow: var(--shadow-sm);
}

.swap-card-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--color-border);
  background: var(--color-subtle);
}

.swap-shift {
  font-weight: 600;
  font-size: var(--text-sm);
  display: block;
}

.swap-date {
  display: block;
  margin-top: 2px;
}

.swap-card-body {
  padding: var(--space-3) var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.swap-message {
  color: var(--color-muted);
  font-style: italic;
  padding: var(--space-2) var(--space-3);
  background: var(--color-subtle);
  border-radius: var(--radius-sm);
  border-left: 3px solid var(--color-border);
}

.swap-card-footer {
  display: flex;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-4);
  border-top: 1px solid var(--color-border);
  background: var(--color-subtle);
}

.swap-empty {
  padding: var(--space-6);
  text-align: center;
  background: var(--color-surface);
  border: 1px dashed var(--color-border);
  border-radius: var(--radius);
}

/* ── Empty state (components/empty-state.js) ─────────────────────────────── */
.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-8) var(--space-4);
  text-align: center;
  background: var(--color-surface);
  border: 1px dashed var(--color-border);
  border-radius: var(--radius);
  color: var(--color-muted);
}
.empty-state .icon { color: var(--color-muted); opacity: 0.6; }
.empty-state-title { font-size: var(--text-base); color: var(--color-text); font-weight: 500; }
.empty-state-sub { font-size: var(--text-sm); color: var(--color-muted); }

/* ── Chat ──────────────────────────────────────────────────────────────────── */
.chat-filter-bar {
  display: flex;
  gap: var(--space-2);
  margin-bottom: var(--space-3);
}

.chat-layout {
  display: grid;
  grid-template-columns: 300px 1fr;
  gap: var(--space-4);
  height: 70vh;
  min-height: 420px;
}

.chat-thread-list {
  overflow-y: auto;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-surface);
}

.chat-thread-item {
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--color-border);
  cursor: pointer;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.chat-thread-item:last-child { border-bottom: none; }
.chat-thread-item:hover { background: var(--color-subtle); }
.chat-thread-item.active { background: var(--color-subtle); border-left: 3px solid var(--color-primary); }

.chat-thread-item-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
}

.chat-thread-subject { font-weight: 600; font-size: var(--text-sm); }

.chat-unread-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--color-danger);
  flex-shrink: 0;
}

.chat-detail {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-surface);
  overflow: hidden;
}

.chat-empty {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-6);
  text-align: center;
}

.chat-detail-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--color-border);
  background: var(--color-subtle);
}
.chat-detail-header h2 { font-size: var(--text-base); margin: 0; }

.chat-controls { display: flex; gap: var(--space-2); align-items: center; }

.chat-messages {
  flex: 1;
  overflow-y: auto;
  padding: var(--space-4);
  display: flex;
  flex-direction: column;
}

.chat-bubble-row { display: flex; margin-bottom: var(--space-3); }
.chat-bubble-row.mine { justify-content: flex-end; }

.chat-bubble {
  max-width: 70%;
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius);
  background: var(--color-subtle);
}
.chat-bubble-row.mine .chat-bubble { background: var(--color-primary); color: #fff; }

.chat-bubble-sender { font-weight: 600; margin-bottom: 2px; }
.chat-bubble-body { white-space: pre-wrap; word-break: break-word; }
.chat-bubble-time {
  margin-top: 4px;
  opacity: 0.7;
}
.chat-bubble-row.mine .chat-bubble-time { color: #fff; }

.chat-composer {
  display: flex;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-4);
  border-top: 1px solid var(--color-border);
  align-items: flex-end;
}
.chat-composer textarea { flex: 1; resize: vertical; }

/* ── Spinner ───────────────────────────────────────────────────────────────── */
.spinner-wrap {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-8, 3rem);
}

.spinner {
  display: inline-block;
  width: 2rem;
  height: 2rem;
  border: 3px solid var(--color-border);
  border-top-color: var(--color-primary);
  border-radius: 50%;
  animation: spin 0.7s linear infinite;
}

@keyframes spin {
  to { transform: rotate(360deg); }
}

/* ── Admin table ───────────────────────────────────────────────────────────── */
/* .coverage-gaps-table shares this styling but is a deliberately distinct class
   (not .admin-table) — admin-locations.js already renders three .admin-table
   instances on one page (Locations / Shift Types / Staffing Rules), and E2E
   specs scope selectors like `.admin-table tr, { hasText: 'SomeLocationName' }`
   assuming exactly one relevant match; a fourth .admin-table for coverage gaps
   (which lists location names too) broke that assumption. */
.admin-table, .coverage-gaps-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--text-sm);
}

.admin-table th, .coverage-gaps-table th {
  text-align: left;
  padding: var(--space-3) var(--space-4);
  background: var(--color-subtle);
  border-bottom: 1px solid var(--color-border);
  font-weight: 600;
  color: var(--color-muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-size: 0.7rem;
}

.admin-table td, .coverage-gaps-table td {
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--color-border);
  vertical-align: middle;
}

.admin-table tr:last-child td, .coverage-gaps-table tr:last-child td { border-bottom: none; }
.admin-table tr.row-inactive td { opacity: 0.55; }

/* Keep the wide Users table inside its card. The table retains its natural
   width and scrolls within this boundary instead of pushing the final action
   (History) through the card's right border. */
.admin-users-table-card {
  width: 100%;
  max-width: 100%;
  min-width: 0;
  padding: 0;
  overflow-x: auto;
}

.admin-users-table-card .admin-table { min-width: max-content; }

.admin-users-section + .admin-users-section { margin-top: var(--space-6); }
.admin-users-section > h2 {
  margin-bottom: var(--space-3);
  font-size: var(--text-lg);
}
.admin-users-section > h2 .text-muted { font-weight: 400; }
.admin-users-inactive-section[hidden] { display: none; }
.admin-users-empty { padding: var(--space-6); text-align: center; }

.admin-users-toolbar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--space-3);
}

.admin-users-inactive-toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--color-text);
  font-size: var(--text-sm);
  font-weight: 500;
  white-space: nowrap;
  cursor: pointer;
}

@media (max-width: 700px) {
  .admin-users-toolbar { justify-content: flex-start; }
}

/* ── Audit log ────────────────────────────────────────────────────────────── */
.audit-page-header { margin-bottom: var(--space-4); }
.audit-page-subtitle { margin-top: var(--space-1); }

.audit-toolbar {
  margin-bottom: var(--space-4);
}

/* ── Account security ─────────────────────────────────────────────────────── */
.security-page-header { margin-bottom: var(--space-4); }
.security-page-subtitle { margin-top: var(--space-1); }
.security-summary { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--space-3); margin-bottom: var(--space-4); }
.security-metric { padding: var(--space-4); }
.security-metric > span { display: block; color: var(--color-muted); font-size: var(--text-sm); }
.security-metric > strong { display: block; margin: var(--space-1) 0; font-size: var(--text-xl); }
.security-metric > div { display: flex; align-items: center; gap: var(--space-2); color: var(--color-muted); font-size: var(--text-xs); }
.security-status-dot { width: 8px; height: 8px; flex: 0 0 auto; border-radius: 50%; background: var(--color-muted); }
.security-status-green { background: var(--color-success); }
.security-status-amber { background: var(--color-warning); }
.security-status-blue { background: var(--color-primary); }
.security-alert { display: flex; align-items: center; justify-content: space-between; gap: var(--space-4); margin-bottom: var(--space-4); padding: var(--space-3) var(--space-4); border: 1px solid #f5c36a; border-radius: var(--radius); background: var(--status-warning-bg); color: #78350f; }
.security-alert p { margin-top: 2px; font-size: var(--text-sm); }
.security-section { margin-bottom: var(--space-4); padding: 0; overflow: hidden; }
.security-section > form, .security-section > .security-table-wrap, .security-section > .security-toolbar-main, .security-section > .security-filter-panel, .security-section > .security-active-filters, .security-section > .security-session-note, .security-section > #session-results { margin-right: var(--space-4); margin-left: var(--space-4); }
.security-section > form { margin-bottom: 0; }
.security-section-header { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-3); padding: var(--space-4); border-bottom: 1px solid var(--color-border); }
.security-section-header h2 { font-size: 1rem; }
.security-section-header p { margin-top: var(--space-1); }
.security-switch-row { display: flex; align-items: center; justify-content: space-between; gap: var(--space-4); margin: var(--space-4) 0; padding: var(--space-4); border: 1px solid var(--color-border); border-radius: var(--radius-sm); background: var(--color-surface); cursor: pointer; }
.security-switch-row:hover { border-color: color-mix(in srgb, var(--color-primary) 45%, var(--color-border)); }
.security-setting-copy, .security-setting-copy small { display: block; }
.security-setting-copy small { margin-top: 3px; color: var(--color-muted); font-size: var(--text-sm); font-weight: 400; }
.security-switch { position: relative; display: block; width: 44px; height: 24px; flex: 0 0 auto; }
.security-switch input { position: absolute; width: 1px; height: 1px; opacity: 0; }
.security-switch > span { display: block; width: 100%; height: 100%; border-radius: 999px; background: var(--color-border); transition: background var(--transition), box-shadow var(--transition); }
.security-switch > span::after { content: ''; position: absolute; top: 3px; left: 3px; width: 18px; height: 18px; border-radius: 50%; background: white; box-shadow: 0 1px 3px rgb(0 0 0 / 25%); transition: transform var(--transition); }
.security-switch input:checked + span { background: var(--color-primary); }
.security-switch input:checked + span::after { transform: translateX(20px); }
.security-switch input:focus-visible + span { box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-primary) 22%, transparent); }
.security-policy-scope { margin: 0; padding: var(--space-4); border: 1px solid var(--color-border); border-radius: var(--radius-sm); background: var(--color-subtle); }
.security-policy-scope:disabled { opacity: .55; }
.security-policy-scope legend { padding: 0 var(--space-1); font-size: var(--text-sm); font-weight: 700; }
.security-scope-help { margin-bottom: var(--space-3); color: var(--color-muted); font-size: var(--text-sm); }
.security-scope-options { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-3); }
.security-scope-card { position: relative; cursor: pointer; }
.security-scope-card input { position: absolute; width: 1px; height: 1px; opacity: 0; }
.security-scope-card > span { display: block; height: 100%; padding: var(--space-3); border: 1px solid var(--color-border); border-radius: var(--radius-sm); background: var(--color-surface); transition: border-color var(--transition), box-shadow var(--transition), background var(--transition); }
.security-scope-card small { display: block; margin-top: 3px; color: var(--color-muted); font-size: var(--text-sm); font-weight: 400; }
.security-scope-card:hover > span { border-color: color-mix(in srgb, var(--color-primary) 45%, var(--color-border)); }
.security-scope-card input:checked + span { border-color: var(--color-primary); background: color-mix(in srgb, var(--color-primary) 7%, var(--color-surface)); box-shadow: inset 0 0 0 1px var(--color-primary); }
.security-scope-card input:focus-visible + span { box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-primary) 22%, transparent); }
.security-role-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--space-2); margin-top: var(--space-3); }
.security-role-grid[hidden] { display: none; }
.security-role-option { display: flex; align-items: center; gap: var(--space-2); min-height: 44px; padding: var(--space-2) var(--space-3); border: 1px solid var(--color-border); border-radius: var(--radius-sm); background: var(--color-surface); font-size: var(--text-sm); cursor: pointer; }
.security-role-option:has(input:checked) { border-color: var(--color-primary); background: color-mix(in srgb, var(--color-primary) 7%, var(--color-surface)); }
.security-role-option:has(input:focus-visible) { box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-primary) 22%, transparent); }
.security-role-option input { width: 17px; height: 17px; margin: 0; accent-color: var(--color-primary); }
.security-impact { margin-top: var(--space-3); padding: var(--space-3); border: 1px solid var(--color-border); border-radius: var(--radius-sm); background: var(--color-subtle); font-size: var(--text-sm); }
.security-impact-warning { border-color: #f5c36a; background: var(--status-warning-bg); }
.security-form-actions { display: flex; align-items: center; justify-content: flex-end; gap: var(--space-3); margin: var(--space-4) calc(-1 * var(--space-4)) 0; padding: var(--space-3) var(--space-4); border-top: 1px solid var(--color-border); background: var(--color-subtle); }
.security-table-wrap { margin-top: var(--space-3); margin-bottom: var(--space-3); overflow-x: auto; border: 1px solid var(--color-border); border-radius: var(--radius-sm); }
.security-compliance-table tbody tr { cursor: pointer; }
.security-compliance-table tbody tr:hover { background: var(--color-subtle); }
.security-exception-header { padding: var(--space-3) var(--space-4); border-top: 1px solid var(--color-border); background: var(--color-subtle); font-size: var(--text-sm); }
.security-exception-row { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); padding: var(--space-3) var(--space-4); border-top: 1px solid var(--color-border); }
.security-exception-row span { display: block; margin-top: 2px; color: var(--color-muted); font-size: var(--text-sm); }
.security-exception-row > div:last-child { display: flex; align-items: center; gap: var(--space-1); }
.security-toolbar-main { display: flex; gap: var(--space-2); margin-top: var(--space-4); }
.security-filter-panel { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-3); margin-top: var(--space-3); padding: var(--space-3); border: 1px solid var(--color-border); border-radius: var(--radius-sm); background: var(--color-subtle); }
.security-filter-panel[hidden] { display: none; }
.security-filter-panel label { font-size: var(--text-sm); font-weight: 500; }
.security-filter-panel .input { margin-top: var(--space-1); }
.security-active-filters { display: flex; flex-wrap: wrap; gap: var(--space-2); min-height: 34px; padding-top: var(--space-2); }
.security-session-note { margin-bottom: var(--space-3); }
.security-session-group { margin-bottom: var(--space-3); border: 1px solid var(--color-border); border-radius: var(--radius-sm); overflow: hidden; }
.security-session-group > header { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); padding: var(--space-3); background: var(--color-subtle); }
.security-session-group > header > div { display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-2); }
.security-session-user { display: flex; align-items: center; gap: var(--space-2); padding: 0; border: 0; background: none; color: var(--color-text); text-align: left; cursor: pointer; }
.security-session-user strong, .security-session-user small { display: block; }
.security-session-user small { margin-top: 2px; color: var(--color-muted); }
.security-disclosure { transition: transform var(--transition); }
.security-session-group.collapsed .security-disclosure { transform: rotate(-90deg); }
.security-session-group.collapsed .security-session-list { display: none; }
.security-session-row { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); padding: var(--space-3); border-top: 1px solid var(--color-border); }
.security-session-row:first-child { border-top: 0; }
.security-session-row p { margin-top: 3px; }
.security-state { padding: var(--space-6); text-align: center; }

@media (max-width: 1000px) { .security-summary { grid-template-columns: repeat(2, minmax(0, 1fr)); } .security-role-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 700px) {
  .security-summary, .security-filter-panel, .security-role-grid, .security-scope-options { grid-template-columns: 1fr; }
  .security-alert, .security-exception-row, .security-session-group > header, .security-session-row { align-items: flex-start; flex-direction: column; }
  .security-switch-row { align-items: flex-start; }
  .security-section > .security-table-wrap { margin-right: 0; margin-left: 0; border-right: 0; border-left: 0; border-radius: 0; }
  .security-compliance-table thead { display: none; }
  .security-compliance-table, .security-compliance-table tbody, .security-compliance-table tr, .security-compliance-table td { display: block; }
  .security-compliance-table tr { padding: var(--space-3); border-bottom: 1px solid var(--color-border); }
  .security-compliance-table td { display: flex; justify-content: space-between; padding: var(--space-1) 0; border: 0; }
  .security-compliance-table td::before { content: attr(data-label); color: var(--color-muted); font-size: var(--text-sm); }
}

.audit-toolbar-main {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.audit-search-wrap {
  position: relative;
  display: block;
  width: min(440px, 100%);
}

.audit-search-icon {
  position: absolute;
  left: var(--space-3);
  top: 50%;
  transform: translateY(-50%);
  color: var(--color-muted);
  font-size: 1.1rem;
  pointer-events: none;
}

.audit-search { padding-left: 2.25rem; }
.audit-filter-toggle { white-space: nowrap; }

.audit-filter-count {
  margin-left: var(--space-1);
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: 9px;
  background: var(--color-primary);
  color: white;
  font-size: .7rem;
  line-height: 18px;
}

.audit-filter-panel {
  display: grid;
  grid-template-columns: minmax(150px, 1fr) minmax(120px, .65fr) minmax(150px, 1fr) minmax(300px, 1.7fr);
  gap: var(--space-3);
  align-items: end;
  max-width: 1050px;
  margin-top: var(--space-3);
  padding: var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-subtle);
}

.audit-filter-panel[hidden] { display: none; }
.audit-filter-field { min-width: 0; }
.audit-filter-field label,
.audit-date-field legend { display: block; margin-bottom: var(--space-1); font-size: var(--text-sm); font-weight: 500; }
.audit-date-field { min-width: 0; margin: 0; padding: 0; border: 0; }

.audit-date-presets {
  display: flex;
  overflow: hidden;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
}

.audit-preset {
  flex: 1;
  min-height: 34px;
  padding: 0 var(--space-2);
  border: 0;
  border-right: 1px solid var(--color-border);
  background: transparent;
  color: var(--color-muted);
  cursor: pointer;
  white-space: nowrap;
}

.audit-preset:last-child { border-right: 0; }
.audit-preset:hover { background: var(--color-surface); color: var(--color-text); }
.audit-preset.active { background: var(--color-primary); color: white; }

.audit-custom-dates { display: flex; gap: var(--space-2); margin-top: var(--space-2); }
.audit-custom-dates[hidden] { display: none; }
.audit-custom-dates label { flex: 1; color: var(--color-muted); font-size: .75rem; }
.audit-custom-dates .input { margin-top: 2px; }

.audit-active-filters {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  min-height: 34px;
  margin-top: var(--space-2);
}

.audit-filter-chips { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.audit-filter-chip {
  padding: 3px 8px;
  border: 1px solid var(--color-border);
  border-radius: 999px;
  background: var(--color-surface);
  color: var(--color-muted);
  font-size: var(--text-sm);
  cursor: pointer;
}
.audit-filter-chip:hover { border-color: var(--color-primary); color: var(--color-text); }
.audit-filter-chip-static { cursor: default; background: var(--color-subtle); }
.audit-filter-chip-static:hover { border-color: var(--color-border); color: var(--color-muted); }

.audit-result-summary { margin-bottom: var(--space-2); color: var(--color-muted); font-size: var(--text-sm); }
.audit-result-summary strong { color: var(--color-text); }
.audit-results-loading { opacity: .65; transition: opacity var(--transition); }
.audit-table-card { padding: 0; overflow-x: auto; }
.audit-time { white-space: nowrap; }
.audit-time span, .audit-time small { display: block; }
.audit-time small { margin-top: 2px; color: var(--color-muted); font-size: .7rem; }
.audit-entity { font-weight: 600; }
.audit-detail-text { display: -webkit-box; overflow: hidden; -webkit-line-clamp: 2; -webkit-box-orient: vertical; color: var(--color-muted); }
.audit-detail-meta { display: none; margin-top: var(--space-1); color: var(--color-muted); font-size: .75rem; }
.audit-detail-toggle { padding: 2px 0; border: 0; background: transparent; color: var(--color-primary); font-size: .75rem; cursor: pointer; }
.audit-detail-toggle:focus-visible,
.audit-filter-chip:focus-visible,
.audit-preset:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 2px; }
.audit-detail-expanded .audit-detail-text { display: block; overflow: visible; }
.audit-detail-expanded .audit-detail-meta { display: block; }
.audit-pagination { display: flex; flex-direction: column; align-items: center; gap: var(--space-2); margin-top: var(--space-3); }
.audit-pagination p { margin: 0; }

@media (max-width: 1000px) {
  .audit-filter-panel { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 700px) {
  .page-header.audit-page-header { flex-direction: row; align-items: flex-start; }
  .audit-toolbar-main { align-items: stretch; }
  .audit-search-wrap { flex: 1; min-width: 0; }
  .audit-filter-panel { grid-template-columns: 1fr; }
  .audit-date-presets { overflow-x: auto; }
  .audit-preset { flex: 0 0 auto; }
  .audit-custom-dates { flex-direction: column; }
  .audit-active-filters { align-items: flex-start; }

  .audit-table-card { overflow: visible; border: 0; box-shadow: none; background: transparent; }
  .audit-table-card .admin-table,
  .audit-table-card .admin-table tbody { display: block; }
  .audit-table-card .admin-table thead { display: none; }
  .audit-table-card .admin-table tr {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: var(--space-2) var(--space-3);
    margin-bottom: var(--space-2);
    padding: var(--space-3);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    background: var(--color-surface);
    box-shadow: var(--shadow-sm);
  }
  .audit-table-card .admin-table td { display: block; padding: 0; border: 0; }
  .audit-table-card .audit-time { grid-column: 1; grid-row: 1; }
  .audit-table-card td[data-label="Action"] { grid-column: 2; grid-row: 1; }
  .audit-table-card td[data-label="Actor"] { grid-column: 1 / -1; grid-row: 2; color: var(--color-muted); font-size: var(--text-sm); }
  .audit-table-card td[data-label="Actor"]::before { content: "By "; }
  .audit-table-card td[data-label="Entity type"] { grid-column: 1 / -1; grid-row: 3; }
  .audit-table-card .audit-entity { grid-column: 1 / -1; grid-row: 4; font-size: 1rem; }
  .audit-table-card .audit-detail-cell { grid-column: 1 / -1; grid-row: 5; }
  .audit-table-card tr:has(td[colspan]) { display: block; }
}

/* Compact view (admin/users): hide the lowest-signal columns by default —
   both stay one click away via "Show all columns" or the row's Edit modal. */
.admin-table.compact-users .col-dob,
.admin-table.compact-users .col-emp-start {
  display: none;
}

.sortable-th {
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
}
.sortable-th:hover { background: var(--color-surface-hover, rgba(0,0,0,0.04)); }
.sort-indicator { color: var(--color-muted); margin-left: 4px; font-size: 0.7em; }
.sort-indicator.active { color: var(--color-text); }

/* ── Shift distribution report ────────────────────────────────────────────── */
/* Cell shading for the Total/FTE column, scaled by how far a user's shift
   load deviates from the team average — color-mix() against the existing
   theme variables means this needs no separate dark-theme block (unlike the
   hardcoded hex heatmap in wish-overview.js). */
.dist-heat-swatch {
  display: inline-block;
  width: 14px;
  height: 14px;
  border-radius: 3px;
  vertical-align: middle;
}
.dist-heat-high-1, .dist-heat-swatch.dist-heat-high-1 { background: color-mix(in srgb, var(--color-danger) 12%, transparent); }
.dist-heat-high-2, .dist-heat-swatch.dist-heat-high-2 { background: color-mix(in srgb, var(--color-danger) 24%, transparent); }
.dist-heat-high-3, .dist-heat-swatch.dist-heat-high-3 { background: color-mix(in srgb, var(--color-danger) 36%, transparent); font-weight: 600; }
.dist-heat-low-1, .dist-heat-swatch.dist-heat-low-1 { background: color-mix(in srgb, var(--color-primary) 12%, transparent); }
.dist-heat-low-2, .dist-heat-swatch.dist-heat-low-2 { background: color-mix(in srgb, var(--color-primary) 24%, transparent); }
.dist-heat-low-3, .dist-heat-swatch.dist-heat-low-3 { background: color-mix(in srgb, var(--color-primary) 36%, transparent); font-weight: 600; }

.admin-actions-cell {
  white-space: nowrap;
}

.admin-actions {
  display: flex;
  gap: var(--space-2);
  justify-content: flex-start;
  align-items: center;
}

.admin-section-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin: var(--space-6) 0 var(--space-3);
}

.admin-section-header h2 {
  font-size: var(--text-lg);
  font-weight: 600;
  margin: 0;
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

/* ── Admin dashboard ──────────────────────────────────────────────────────── */
.dash-empty {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  margin-bottom: var(--space-6);
}
.dash-empty-icon {
  font-size: 1.5rem;
  color: var(--color-success, #16a34a);
  background: #dcfce7;
  width: 40px; height: 40px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 999px;
  flex-shrink: 0;
}

/* Action-needed queue */
.dash-action {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-3) var(--space-4);
  border-left: 3px solid transparent;
  border-bottom: 1px solid var(--color-border);
}
.dash-action:last-child { border-bottom: none; }
.dash-action.tone-red   { border-left-color: #dc2626; }
.dash-action.tone-amber { border-left-color: #d97706; }
.dash-action.tone-blue  { border-left-color: #2563eb; }
.dash-action-msg { font-size: var(--text-sm); }
.dash-action .btn { flex-shrink: 0; }

/* Period pipeline */
.dash-pipeline {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
}
.dash-stage {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  min-width: 84px;
}
.dash-stage-count {
  font-size: var(--text-xl);
  font-weight: 700;
}
.dash-stage-arrow {
  color: var(--color-muted);
  font-size: var(--text-lg);
}

/* Stat cards */
.dash-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: var(--space-4);
}
.dash-stat {
  text-decoration: none;
  color: inherit;
  display: block;
  transition: border-color .12s ease, box-shadow .12s ease;
}
.dash-stat:hover {
  border-color: var(--color-primary, #2563eb);
  box-shadow: var(--shadow-md, 0 4px 12px rgba(0,0,0,.08));
}
.dash-stat-value {
  font-size: var(--text-2xl, 1.5rem);
  font-weight: 700;
  line-height: 1.1;
}
.dash-stat-label {
  font-weight: 600;
  margin: 2px 0;
}

/* ── My Stats ─────────────────────────────────────────────────────────────
   Self-context strip (FTE/comp-days/leave) + the fairness-group cards' meter
   component, reused unchanged for the "you vs. department" rows below them —
   one visual (a filled bar against a reference-line target) for both
   comparisons instead of two different widgets. */
.ms-context-strip {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: var(--space-4);
  margin-bottom: var(--space-6);
}
.ms-mini-stat {
  background: var(--color-subtle);
  border-radius: var(--radius-lg);
  padding: var(--space-4) var(--space-5);
  display: flex;
  flex-direction: column;
  gap: 2px;
  text-decoration: none;
  color: inherit;
  transition: box-shadow .12s ease;
}
a.ms-mini-stat:hover { box-shadow: var(--shadow-md, 0 4px 12px rgba(0,0,0,.08)); }
.ms-mini-stat.cat-moss { background: var(--cat-moss-bg); }
.ms-mini-stat.cat-plum { background: var(--cat-plum-bg); }
.ms-mini-stat.cat-clay { background: var(--cat-clay-bg); }
.ms-mini-stat-label {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: var(--text-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-muted);
}
.ms-mini-stat.cat-moss .ms-mini-stat-label { color: var(--cat-moss); }
.ms-mini-stat.cat-plum .ms-mini-stat-label { color: var(--cat-plum); }
.ms-mini-stat.cat-clay .ms-mini-stat-label { color: var(--cat-clay); }
.ms-mini-stat-value { font-size: var(--text-xl); font-weight: 700; margin: 2px 0; }
.ms-mini-stat-sub { font-size: var(--text-2xs); color: var(--color-muted); }

.ms-fairness-groups {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: var(--space-4);
  margin-bottom: var(--space-6);
}
.ms-group-card { padding: var(--space-5); }
.ms-group-header {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-weight: 700;
  margin-bottom: var(--space-3);
}
.ms-group-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--color-primary);
  flex: none;
}
/* On-call gets the ring cue (§13.1's timing channel), not a fill swap —
   matching the shift-chip "hollow ring = on-call" convention elsewhere. */
.ms-group-dot.oncall {
  background: var(--color-surface);
  border: 2px solid var(--cat-clay);
}
.ms-group-row {
  display: flex;
  justify-content: space-between;
  font-size: var(--text-sm);
  padding: 1px 0;
}
.ms-group-row .label { color: var(--color-muted); }
.ms-group-deviation {
  font-weight: 700;
  padding: 0 6px;
  border-radius: var(--radius-sm, 4px);
}

.ms-meter { margin: var(--space-1) 0 var(--space-3); }
.ms-meter-track {
  position: relative;
  height: 8px;
  border-radius: 999px;
  background: var(--color-border);
  overflow: hidden;
}
.ms-meter-fill {
  position: absolute;
  top: 0;
  bottom: 0;
  background: var(--color-primary);
}
.ms-meter-fill.over { background: var(--color-danger); }
.ms-meter-target {
  position: absolute;
  top: -2px;
  bottom: -2px;
  width: 2px;
  background: var(--color-text);
  opacity: .4;
}

.ms-trend-card, .ms-breakdown-card { margin-bottom: var(--space-6); }
.ms-trend-scroll { overflow-x: auto; }
.ms-trend-chart {
  position: relative;
  height: 140px;
  border-bottom: 1px solid var(--color-border);
}
.ms-trend-target-line {
  position: absolute;
  left: 0;
  right: 0;
  border-top: 1px dashed var(--color-muted);
  opacity: .6;
}
/* Columns and bars are positioned via top/bottom/left/right inset, not a
   computed percentage height on a flex item — a row-flex item's percentage
   cross-axis height, nested this deep (scroll wrapper > chart > column >
   bar), proved unreliable on first paint in practice (computed to ~0
   despite a correct explicit height/100%, self-correcting only once some
   later, unrelated DOM mutation forced a relayout). Plain inset positioning
   against a position:relative ancestor of definite height doesn't share
   that failure mode — verified directly against this page before settling
   on it. */
.ms-trend-col {
  position: absolute;
  top: 0;
  bottom: 0;
  min-width: 0;
}
.ms-trend-bar {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  width: 100%;
  max-width: 24px;
  min-height: 2px;
  margin: 0 auto;
  border-radius: 4px 4px 0 0;
  background: var(--color-primary);
  opacity: .55;
}
.ms-trend-bar.current { opacity: 1; background: var(--color-primary-hover); }
.ms-trend-axis {
  display: flex;
  gap: 4px;
  margin-top: var(--space-2);
}
.ms-trend-axis-label {
  flex: 1 1 0;
  text-align: center;
  font-size: var(--text-2xs);
  color: var(--color-muted);
  min-width: 0;
}

.ms-breakdown-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: 6px 0;
}
.ms-breakdown-name {
  width: 150px;
  flex: none;
  font-size: var(--text-sm);
  display: flex;
  align-items: center;
  gap: 6px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ms-breakdown-oncall-ring {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  border: 2px solid var(--cat-clay);
  flex: none;
}
.ms-breakdown-track {
  flex: 1;
  height: 10px;
  background: var(--color-subtle);
  border-radius: 999px;
  overflow: hidden;
}
.ms-breakdown-fill {
  height: 100%;
  background: var(--color-primary);
  border-radius: 999px;
}
.ms-breakdown-value {
  width: 110px;
  flex: none;
  text-align: right;
  font-size: var(--text-sm);
  color: var(--color-muted);
}

.ms-dept-rows {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  margin-top: var(--space-3);
}
.ms-dept-row-header {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  font-weight: 600;
  margin-bottom: 4px;
}

@media (max-width: 768px) {
  .ms-breakdown-name { width: 100px; }
  .ms-breakdown-value { width: 90px; }
}

/* ── Roster grid v2 (date rows × location columns) ───────────────────────── */
#roster-grid-area {
  overflow-x: auto;
}

.roster-grid-v2 {
  border-collapse: collapse;
  width: 100%;
  font-size: var(--text-sm);
  min-width: 600px;
}

/* Header row */
.roster-grid-v2 thead th {
  background: var(--color-surface);
  border-bottom: 2px solid var(--color-border);
  padding: var(--space-2) var(--space-3);
  font-weight: 600;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--color-muted);
  white-space: nowrap;
  position: sticky;
  top: 0;
  z-index: 2;
}

/* Date column — sticky left */
.rgv2-date-th {
  min-width: 90px;
  width: 90px;
  text-align: left;
  position: sticky !important;
  left: 0;
  z-index: 3 !important;
  background: var(--color-surface) !important;
}

.rgv2-date-td {
  position: sticky;
  left: 0;
  z-index: 1;
  background: var(--color-surface);
  border-right: 1px solid var(--color-border);
  border-bottom: 1px solid var(--color-border);
  padding: var(--space-2) var(--space-3);
  vertical-align: middle;
  white-space: nowrap;
  min-width: 90px;
  width: 90px;
}

.rgv2-day-num {
  font-size: var(--text-sm);
  font-weight: 700;
  color: var(--color-text);
  line-height: 1;
}

.rgv2-day-name {
  font-size: 0.68rem;
  font-weight: 400;
  color: var(--color-muted);
  margin-top: 2px;
}

/* Staffing calendar override marker (CLAUDE.md §3.x) — set independently of
   any period, shown in the sticky date cell so it's visible before the
   rostermaker even opens a chip. Emoji-only, no colour to override in dark
   mode. */
.rgv2-cal-override {
  font-size: 0.75rem;
  margin-left: 4px;
}

.day-info-badge, .rgv2-day-information {
  display:inline-flex; align-items:center; gap:2px; color:var(--color-primary);
  font-size:.8rem; font-weight:700; margin-left:4px;
}
.day-info-badge.important, .rgv2-day-information.important { color:var(--color-warning); }
.day-info-badge small, .rgv2-day-information small { font-size:.62rem; }
.day-information-panel { margin-bottom:var(--space-4); }
.day-information-item { border-left:3px solid var(--color-primary); background:var(--color-subtle); padding:var(--space-2) var(--space-3); margin-top:var(--space-2); border-radius:var(--radius-sm); }
.day-information-item.important { border-left-color:var(--color-warning); }
.day-information-title { font-weight:700; }
.day-information-meta { color:var(--color-muted); font-size:.8rem; margin-top:2px; }
.day-information-description { margin-top:var(--space-2); white-space:pre-wrap; }
.day-information-form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-3); }
.day-information-form-grid .input { width: 100%; }
.modal-day-information-notify { max-width: 520px; }

/* Staffing Calendar day workflow — one continuous screen, two sections
   (day information, staffing requirements). Every list row is an accordion:
   clicking it expands its edit form in place, right below it, instead of
   navigating the whole modal to a dedicated screen — the list stays visible
   and every edit is at most one click away. "Notify" is the one exception
   (openNotifyPopup, staffing-calendar.js) — a real send-a-message side
   effect gets a small deliberate popup instead of living inside an
   accordion someone could open by accident. */
.modal-day-workflow {
  width: min(720px, calc(100vw - 2 * var(--space-4)));
  max-width: 720px;
  max-height: min(860px, calc(100dvh - 2 * var(--space-4)));
  overflow: hidden;
}
.modal-day-workflow .modal-body { min-height: 0; padding: 0; overflow-y: auto; }
.modal-day-workflow .modal-header,
.modal-day-workflow .modal-footer { flex: none; }
.day-workflow-section { padding: var(--space-6); border-bottom: 1px solid var(--color-border); }
.day-workflow-section-heading {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-4);
  margin-bottom: var(--space-4);
}
.day-workflow-section-heading h3 { margin: 0; font-size: var(--text-base); }
.day-workflow-section-heading p { margin: 4px 0 0; color: var(--color-muted); font-size: var(--text-sm); line-height: 1.5; }
.day-workflow-section-heading .btn { flex: none; }
.day-workflow-filters { display: flex; align-items: center; gap: var(--space-3); margin-bottom: var(--space-3); }
.day-workflow-filters .input { flex: 1; }
.day-workflow-filters .checkbox-label { flex: none; margin: 0; white-space: nowrap; }
.day-workflow-list { display: grid; gap: var(--space-3); }
.day-workflow-empty { padding: var(--space-4); border: 1px dashed var(--color-border); border-radius: var(--radius); color: var(--color-muted); font-size: var(--text-sm); }

/* Rows sit on a tinted (--color-subtle) fill, not --color-surface — the
   modal itself is --color-surface, so a same-color "card" would be
   indistinguishable from its own background in light mode and read as a
   flat, borderless list instead of a set of distinct rows. */
.day-workflow-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  align-items: center;
  width: 100%;
  min-height: 56px;
  gap: var(--space-3);
  padding: var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-subtle);
  color: var(--color-text);
  text-align: left;
  cursor: pointer;
}
.day-workflow-row:hover,
.day-workflow-row-toggle:hover { border-color: var(--color-primary); background: color-mix(in srgb, var(--color-primary) 8%, var(--color-subtle)); }
.day-workflow-row:focus-visible,
.day-workflow-row-toggle:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 2px; }
.day-workflow-row[aria-expanded="true"],
.day-workflow-row-toggle[aria-expanded="true"] { border-color: var(--color-primary); background: color-mix(in srgb, var(--color-primary) 10%, var(--color-subtle)); }

/* Day-information rows carry a second action (Notify) alongside the
   expand/collapse toggle — unlike a plain requirement row, the row itself
   wraps two real, non-nested buttons rather than being one big button. */
.day-workflow-info-row { display: flex; align-items: stretch; gap: var(--space-2); }
.day-workflow-info-row > .btn { flex: none; align-self: center; }
.day-workflow-row-toggle {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  flex: 1;
  min-width: 0;
  min-height: 56px;
  gap: var(--space-3);
  padding: var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-subtle);
  color: var(--color-text);
  text-align: left;
  cursor: pointer;
}

.day-workflow-row-copy { display: grid; min-width: 0; gap: 4px; }
.day-workflow-row-copy strong { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.day-workflow-row-copy > span { color: var(--color-muted); font-size: var(--text-sm); overflow-wrap: anywhere; }
.day-workflow-row-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: color-mix(in srgb, var(--color-primary) 12%, transparent);
  color: var(--color-primary);
  font-weight: 700;
}
.day-workflow-row-icon.important { background: color-mix(in srgb, var(--color-warning) 15%, transparent); color: var(--color-warning); }
.day-workflow-caret { flex: none; color: var(--color-muted); font-size: var(--text-sm); }

/* The panel a row expands into. Sits directly under its row (small gap, no
   screen transition) and never needs to be sticky/scroll-tracked — it's a
   compact in-place form, not a tall full-screen one. Plain --color-surface
   (not --color-subtle) so the form reads as "lifted" above the row it
   belongs to, rather than the same flat tint continuing underneath it. */
.day-workflow-expanded-form { margin-top: var(--space-2); padding: var(--space-4); border: 1px solid var(--color-primary); border-radius: var(--radius); background: var(--color-surface); }
.day-workflow-expanded-form .staffing-default-strip { margin-top: 0; }
.day-workflow-form-hint { margin: 0 0 var(--space-3); }
.day-workflow-row-actions-bar { display: flex; align-items: center; justify-content: flex-end; gap: var(--space-2); margin-top: var(--space-4); }
.day-workflow-row-actions-bar > span { flex: 1; }

/* "Copy this day to another date" (roster-editor.js only) */
.btn-copy-day {
  border: none;
  background: transparent;
  color: var(--color-muted);
  cursor: pointer;
  font-size: 0.85rem;
  line-height: 1;
  padding: 1px 3px;
  margin-left: 4px;
  border-radius: var(--radius-sm, 4px);
}
.btn-copy-day:hover,
.btn-copy-day:focus-visible {
  color: var(--color-primary);
  background: var(--color-subtle);
}

/* Weekend date styling */
.rgv2-row-weekend .rgv2-date-td {
  background: var(--color-subtle);
}

/* Approved-leave caption under the date cell (roster-editor.js/current-schedule.js
   only — published-roster.js never passes approvedLeaveByDate, since viewers
   have no access to the leave-requests endpoint). */
.rgv2-on-leave {
  font-size: 0.65rem;
  font-weight: 500;
  color: var(--color-warning);
  white-space: normal;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 84px;
  line-height: 1.2;
  margin-top: 2px;
}

/* Published Roster: the date cell opens the day-detail drill-down modal */
.rgv2-date-clickable {
  cursor: pointer;
  transition: background var(--transition);
}
.rgv2-date-clickable:hover,
.rgv2-date-clickable:focus-visible {
  background: #eff6ff;
  outline: none;
}
.rgv2-row-weekend .rgv2-date-clickable:hover,
.rgv2-row-weekend .rgv2-date-clickable:focus-visible {
  background: #dbeafe;
}

.rgv2-row-weekend .rgv2-date-td .rgv2-day-num {
  color: var(--color-muted);
}

/* Location columns */
.rgv2-loc-th {
  min-width: 160px;
  text-align: left;
}

.rgv2-loc-td {
  vertical-align: top;
  border-bottom: 1px solid var(--color-border);
  padding: var(--space-2);
  min-width: 160px;
}

.rgv2-row-weekend .rgv2-loc-td {
  background: #fafafa;
}

/* No rule — hatched cell */
.rgv2-norule {
  background: repeating-linear-gradient(
    45deg,
    transparent,
    transparent 4px,
    #f0f0f0 4px,
    #f0f0f0 8px
  ) !important;
}

.rgv2-row-weekend .rgv2-norule {
  background: repeating-linear-gradient(
    45deg,
    transparent,
    transparent 4px,
    #ebebeb 4px,
    #ebebeb 8px
  ) !important;
}

/* Conflicts column */
.rgv2-conflict-th {
  min-width: 130px;
  text-align: left;
  color: var(--color-danger) !important;
}

.rgv2-conflict-td {
  vertical-align: top;
  border-bottom: 1px solid var(--color-border);
  border-left: 1px solid var(--color-border);
  padding: var(--space-2);
  min-width: 130px;
}

.rgv2-row-weekend .rgv2-conflict-td {
  background: #fafafa;
}

/* ── Shift chips ─────────────────────────────────────────────────────────── */
.shift-chip {
  display: flex;
  align-items: center;
  gap: 5px;
  padding: 3px 6px;
  border-radius: var(--radius-sm);
  border-left: 3px solid var(--color-muted);
  background: var(--color-surface);
  margin-bottom: 3px;
  font-size: 0.72rem;
  font-weight: 500;
  line-height: 1.2;
  min-height: 24px;
  position: relative;
  box-shadow: 0 1px 2px rgba(0,0,0,.06);
}

.shift-chip:last-child {
  margin-bottom: 0;
}

.chip-dot {
  flex-shrink: 0;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--color-muted);
}

/* Location identity (see location-colors.js) — border-left + dot carry the
   location's hue, the same identity axis Staffing Calendar's need-badges
   use. Explicit per-slot classes, not an inline custom-property reference —
   see components.css's earlier .sc-need-badge.loc-* note for why. */
.shift-chip.loc-1 { border-left-color: var(--loc-1); } .shift-chip.loc-1 .chip-dot { background: var(--loc-1); }
.shift-chip.loc-2 { border-left-color: var(--loc-2); } .shift-chip.loc-2 .chip-dot { background: var(--loc-2); }
.shift-chip.loc-3 { border-left-color: var(--loc-3); } .shift-chip.loc-3 .chip-dot { background: var(--loc-3); }
.shift-chip.loc-4 { border-left-color: var(--loc-4); } .shift-chip.loc-4 .chip-dot { background: var(--loc-4); }
.shift-chip.loc-5 { border-left-color: var(--loc-5); } .shift-chip.loc-5 .chip-dot { background: var(--loc-5); }
.shift-chip.loc-6 { border-left-color: var(--loc-6); } .shift-chip.loc-6 .chip-dot { background: var(--loc-6); }
.shift-chip.loc-7 { border-left-color: var(--loc-7); } .shift-chip.loc-7 .chip-dot { background: var(--loc-7); }
.shift-chip.loc-8 { border-left-color: var(--loc-8); } .shift-chip.loc-8 .chip-dot { background: var(--loc-8); }

/* Timing (shift_types.is_oncall) — a hollow ring instead of a solid dot,
   same hue, so it reads as "the same location, off-hours" rather than a
   different location. A pure dot-level cue, deliberately not a
   border-style change — the auto-suggested marker below uses a corner
   dot rather than the border for the same reason (see .chip-auto). */
.shift-chip.chip-oncall .chip-dot { background: transparent; border: 1.5px solid var(--color-muted); }
.shift-chip.chip-oncall.loc-1 .chip-dot { border-color: var(--loc-1); }
.shift-chip.chip-oncall.loc-2 .chip-dot { border-color: var(--loc-2); }
.shift-chip.chip-oncall.loc-3 .chip-dot { border-color: var(--loc-3); }
.shift-chip.chip-oncall.loc-4 .chip-dot { border-color: var(--loc-4); }
.shift-chip.chip-oncall.loc-5 .chip-dot { border-color: var(--loc-5); }
.shift-chip.chip-oncall.loc-6 .chip-dot { border-color: var(--loc-6); }
.shift-chip.chip-oncall.loc-7 .chip-dot { border-color: var(--loc-7); }
.shift-chip.chip-oncall.loc-8 .chip-dot { border-color: var(--loc-8); }

.chip-name {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--color-text);
}

/* Unfilled slot */
.chip-unfilled {
  background: #fff5f5;
  border-left-color: var(--color-danger) !important;
}

.chip-unfilled .chip-dot {
  background: var(--color-danger);
}

.chip-unfilled .chip-name {
  color: var(--color-danger);
  font-style: italic;
}

/* Outlines the specific (date, location) roster-grid cell affected by an
   understaffing or required-specialty conflict. Uses an inset shadow so the
   signal never shifts the table layout. */
.rgv2-loc-td.cell-specialty-shortage {
  box-shadow: inset 0 0 0 2px var(--color-danger);
}

.rgv2-loc-td.cell-specialty-shortage.conflict-soft {
  box-shadow: inset 0 0 0 2px var(--color-warning, #d97706);
}

/* Add-another affordance — appended to a cell that isn't at its staffing
   max, or shown alone for a zero-requirement rule (Non-OR Work, Management
   Day). Deliberately neutral, not alarming like .chip-unfilled, since there
   is no unmet requirement here. */
.chip-add {
  background: var(--color-bg-muted, #f8f9fa);
  border-left-color: var(--color-border) !important;
  justify-content: center;
}

.chip-add .chip-name {
  color: var(--color-muted);
  font-style: normal;
}

.chip-add.chip-clickable:hover {
  background: #eff6ff;
  border-left-color: var(--color-primary) !important;
}

[data-theme="dark"] .chip-add { background: #1f2937; }

/* Clickable state */
.chip-clickable {
  cursor: pointer;
  transition: background var(--transition), box-shadow var(--transition);
}

.chip-clickable:hover {
  background: #eff6ff;
  box-shadow: 0 2px 4px rgba(0,0,0,.12);
}

.chip-clickable:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 1px;
  background: #eff6ff;
}

/* Drag-and-drop reassignment (roster-editor.js) */
.shift-chip.roster-being-edited {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
  position: relative;
}
.roster-editor-presence {
  position: absolute;
  right: 2px;
  top: -9px;
  max-width: 90%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  padding: 1px 5px;
  border-radius: 999px;
  background: var(--color-primary);
  color: white;
  font-size: 10px;
  line-height: 14px;
  z-index: 2;
}
.shift-chip.dragging {
  opacity: 0.4;
}

.shift-chip.drop-target {
  outline: 2px dashed var(--color-primary);
  outline-offset: 1px;
  background: #eff6ff;
}

/* Bulk multi-select (roster-editor.js) */
.shift-chip.chip-selected {
  outline: 2px solid var(--color-primary);
  outline-offset: 1px;
  background: #dbeafe;
}

/* Auto-suggested — a small neutral dot in the chip's top-right corner,
   independent of the location dot (left) and the on-call ring (also on
   that same left dot): a third, non-competing signal rather than doubling
   up on either existing channel. Only ever rendered on interactive/draft
   chips (see roster-grid.js's buildChips) — a locked/published chip is
   already committed, so the auto-vs-manual distinction stops mattering. */
.shift-chip.chip-auto::after {
  content: '';
  position: absolute;
  top: 3px;
  right: 3px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--color-muted);
}

/* ── Conflict chips (last column) ────────────────────────────────────────── */
.conflict-chip {
  display: flex;
  align-items: flex-start;
  gap: 4px;
  padding: 3px 6px;
  border-radius: var(--radius-sm);
  background: #fff5f5;
  border-left: 3px solid var(--color-danger);
  margin-bottom: 3px;
  font-size: 0.68rem;
  color: var(--color-danger);
  line-height: 1.3;
}

.conflict-chip:last-child {
  margin-bottom: 0;
}

/* Soft compensation overrides (part-time day / standard-rule day worked) —
   amber, not red, since these are informational alerts, not hard violations. */
.conflict-chip.conflict-soft {
  background: #fffbeb;
  border-left-color: var(--color-warning, #d97706);
  color: var(--color-warning, #d97706);
}

/* Inline advisory warnings inside forms (e.g. the wish-submission
   consecutive-off-days heads-up) — same amber treatment as .conflict-soft. */
.inline-warning {
  background: #fffbeb;
  border-left: 3px solid var(--color-warning, #d97706);
  color: var(--color-warning, #d97706);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm, 4px);
  font-size: 0.85rem;
  line-height: 1.4;
}

.inline-warning a {
  color: inherit;
  font-weight: 600;
  text-decoration: underline;
}

/* ── Violation summary panel (above the grid) ────────────────────────────── */
.violation-summary {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-bottom: var(--space-4);
}

.violation-summary-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 8px 5px 10px;
  border-radius: 100px;
  background: #fff5f5;
  border: 1px solid transparent;
  color: var(--color-danger);
  font: inherit;
  font-size: var(--text-sm);
  font-weight: 500;
  cursor: pointer;
  transition: background var(--transition), border-color var(--transition);
}
.violation-summary-chip:hover,
.violation-summary-chip:focus-visible {
  border-color: var(--color-danger);
  outline: none;
}

.violation-summary-chip.conflict-soft {
  background: #fffbeb;
  color: var(--color-warning, #d97706);
}
.violation-summary-chip.conflict-soft:hover,
.violation-summary-chip.conflict-soft:focus-visible {
  border-color: var(--color-warning, #d97706);
}

.violation-summary-count {
  background: var(--color-danger);
  color: #fff;
  border-radius: 100px;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 0.7rem;
  font-weight: 700;
}
.violation-summary-chip.conflict-soft .violation-summary-count {
  background: var(--color-warning, #d97706);
}

.violation-summary-ok {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  border-radius: var(--radius-sm);
  background: #f0fdf4;
  color: var(--color-success);
  font-size: var(--text-sm);
  font-weight: 500;
  margin-bottom: var(--space-4);
}

/* Clicking a violation-summary chip scrolls to and briefly flashes the
   offending grid row so the eye finds it without a background swap that
   would clobber the row's own styling (weekend tint, no-rule stripes). */
@keyframes rgv2-row-flash {
  0%, 100% { box-shadow: none; }
  30%      { box-shadow: inset 0 0 0 999px rgba(37, 99, 235, .18); }
}
tr.rgv2-flash-row > td {
  animation: rgv2-row-flash 1.1s ease-in-out;
}

/* ── Grid v2 legend ──────────────────────────────────────────────────────── */
.roster-grid-legend {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  margin-bottom: var(--space-3);
  font-size: var(--text-sm);
  flex-wrap: wrap;
}

.legend-swatch {
  display: inline-block;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  vertical-align: middle;
  margin-right: 4px;
  background: var(--color-muted);
}
.legend-swatch.loc-1 { background: var(--loc-1); }
.legend-swatch.loc-2 { background: var(--loc-2); }
.legend-swatch.loc-3 { background: var(--loc-3); }
.legend-swatch.loc-4 { background: var(--loc-4); }
.legend-swatch.loc-5 { background: var(--loc-5); }
.legend-swatch.loc-6 { background: var(--loc-6); }
.legend-swatch.loc-7 { background: var(--loc-7); }
.legend-swatch.loc-8 { background: var(--loc-8); }

.chip-oncall-sample {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: transparent;
  border: 1.5px solid var(--color-muted);
  vertical-align: middle;
  margin-right: 4px;
}

.chip-auto-sample {
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--color-muted);
  vertical-align: middle;
  margin-right: 4px;
}

/* Staffing override indicator */
.chip-overridden {
  outline: 2px solid #d97706;
  outline-offset: -2px;
}

.chip-overridden-sample {
  display: inline-block;
  width: 20px;
  height: 10px;
  border-left: 3px solid #94a3b8;
  outline: 2px solid #d97706;
  outline-offset: -2px;
  border-radius: 1px;
  vertical-align: middle;
  margin-right: 4px;
}

/* Sick leave indicator */
.chip-sick-leave {
  opacity: 0.72;
  text-decoration: line-through;
}

.chip-sick {
  font-size: 0.75rem;
  margin-left: 2px;
  text-decoration: none;
  display: inline-block;
}

/* Specialty badge (see specialty-labels.js) — deliberately monochrome, not
   a location-hue or duty-text channel (CLAUDE.md §13.1): a small identity
   marker on top of the existing chip, same slot as .chip-sick above. Built
   on --color-subtle/--color-muted, which already carry their own dark
   values (base.css), so no separate [data-theme="dark"] override is needed. */
.chip-specialty {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 15px;
  height: 15px;
  padding: 0 3px;
  margin-left: 2px;
  border-radius: 50%;
  background: var(--color-subtle);
  color: var(--color-muted);
  border: 1px solid var(--color-border);
  font-size: 0.62rem;
  font-weight: 700;
  line-height: 1;
}

.chip-specialty-more {
  border-radius: var(--radius-sm);
}

/* Amendment banner shown when editing a published roster */
.amendment-banner {
  background: #fef3c7;
  border-left: 4px solid #d97706;
  color: #92400e;
  font-size: 0.85rem;
  padding: var(--space-2) var(--space-4);
  margin-bottom: var(--space-3);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}

/* ── Current schedule — staff avatar circles ──────────────────────────────── */
.curr-sched-card {
  padding: var(--space-4);
}

/* Give calendar cells enough room for two rows of circles (equal-width
   columns already come from the base .calendar rule) */
.curr-sched-card .cal-cell {
  min-height: 96px;
  overflow: hidden;
  position: relative;
  cursor: pointer;
  transition: box-shadow var(--transition);
}

.curr-sched-avatars {
  display: flex;
  flex-wrap: wrap;
  gap: 3px;
  margin-top: 5px;
}

.curr-sched-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  font-size: 0.62rem;
  font-weight: 700;
  color: #fff;
  background: var(--color-muted);
  flex-shrink: 0;
  cursor: default;
  user-select: none;
  letter-spacing: -0.5px;
}

/* Location identity + on-call ring — same axes as roster-grid.js's chips
   (location-colors.js). A ring (transparent fill, colored border/text)
   instead of a solid fill marks an on-call/off-hours shift. */
.curr-sched-avatar.loc-1 { background: var(--loc-1); } .curr-sched-avatar.chip-oncall.loc-1 { border-color: var(--loc-1); color: var(--loc-1); }
.curr-sched-avatar.loc-2 { background: var(--loc-2); } .curr-sched-avatar.chip-oncall.loc-2 { border-color: var(--loc-2); color: var(--loc-2); }
.curr-sched-avatar.loc-3 { background: var(--loc-3); } .curr-sched-avatar.chip-oncall.loc-3 { border-color: var(--loc-3); color: var(--loc-3); }
.curr-sched-avatar.loc-4 { background: var(--loc-4); } .curr-sched-avatar.chip-oncall.loc-4 { border-color: var(--loc-4); color: var(--loc-4); }
.curr-sched-avatar.loc-5 { background: var(--loc-5); } .curr-sched-avatar.chip-oncall.loc-5 { border-color: var(--loc-5); color: var(--loc-5); }
.curr-sched-avatar.loc-6 { background: var(--loc-6); } .curr-sched-avatar.chip-oncall.loc-6 { border-color: var(--loc-6); color: var(--loc-6); }
.curr-sched-avatar.loc-7 { background: var(--loc-7); } .curr-sched-avatar.chip-oncall.loc-7 { border-color: var(--loc-7); color: var(--loc-7); }
.curr-sched-avatar.loc-8 { background: var(--loc-8); } .curr-sched-avatar.chip-oncall.loc-8 { border-color: var(--loc-8); color: var(--loc-8); }
.curr-sched-avatar.chip-oncall {
  background: var(--color-surface);
  border: 2px solid var(--color-muted);
  color: var(--color-muted);
}

/* "+N more" overflow indicator */
.curr-sched-overflow {
  background: var(--color-border) !important;
  color: var(--color-muted) !important;
  font-weight: 600;
  font-size: 0.6rem;
  letter-spacing: 0;
}

/* Legend bar */
.curr-sched-legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-5);
  margin-bottom: var(--space-4);
  align-items: center;
  font-size: var(--text-sm);
  color: var(--color-muted);
}

.curr-sched-legend-item {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

/* Clickable day cells (day-detail drill-down) */
.curr-sched-card .cal-cell:hover {
  box-shadow: inset 0 0 0 2px var(--color-primary);
}

.curr-sched-card .cal-cell.today {
  outline: 2px solid var(--color-primary);
  outline-offset: -2px;
}

/* Per-day violation dot + understaffed border, drawn on the cal-cell itself */
.curr-sched-card .cal-cell.has-understaffed {
  box-shadow: inset 0 -3px 0 0 var(--color-danger);
}

.curr-sched-day-flags {
  position: absolute;
  top: 4px;
  right: 4px;
  display: flex;
  gap: 3px;
}

.curr-sched-flag-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
}

.curr-sched-flag-dot.hard { background: var(--color-danger); }
.curr-sched-flag-dot.soft { background: var(--color-warning, #d97706); }

/* "Jump to today" briefly flashes the target cell so the eye finds it */
@keyframes curr-sched-flash {
  0%, 100% { background: transparent; }
  30%      { background: rgba(37, 99, 235, .18); }
}
.curr-sched-card .cal-cell.flash {
  animation: curr-sched-flash 1.1s ease-in-out;
}

/* ── Day-detail modal (Current Schedule drill-down) ───────────────────────── */
.modal-lg { max-width: 720px; }

/* Shared between the day-workflow requirement editor (staffing-calendar.js's
   renderRequirementEditor) and nothing else — the older two-pane day modal
   these were originally written for was removed in favor of day-workflow's
   progressive-disclosure screens above. */
.staffing-source {
  display: inline-flex;
  flex: none;
  align-items: center;
  width: fit-content;
  padding: 2px 7px;
  border-radius: 999px;
  font-size: .72rem;
  font-weight: 600;
  line-height: 1.4;
}
.staffing-source.rule { color: var(--color-muted); background: var(--color-subtle); }
.staffing-source.template { color: var(--color-primary); background: color-mix(in srgb, var(--color-primary) 12%, transparent); }
.staffing-source.adjusted { color: var(--color-warning); background: color-mix(in srgb, var(--color-warning) 14%, transparent); }

.staffing-default-strip {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
  padding: var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-subtle);
  font-size: var(--text-sm);
}
.staffing-fields {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-3);
}
.staffing-fields .input { width: 100%; }
.staffing-specialties {
  margin: var(--space-4) 0;
  padding: var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
}
.staffing-specialties summary { cursor: pointer; font-weight: 600; }
.staffing-specialty-toggle { margin-top: var(--space-4); }
.form-error { min-height: 1.25rem; margin: calc(-1 * var(--space-2)) 0 var(--space-2); color: var(--color-danger); font-size: var(--text-sm); }

@media (max-width: 700px) {
  .modal-day-workflow {
    width: min(100%, calc(100vw - 2 * var(--space-2)));
    max-height: calc(100dvh - 2 * var(--space-2));
  }
  .day-workflow-section { padding: var(--space-4); }
  .day-workflow-section-heading { align-items: stretch; flex-direction: column; }
  .day-workflow-section-heading .btn { width: 100%; min-height: 44px; }
  .day-workflow-filters { flex-direction: column; align-items: stretch; }
  .day-workflow-row,
  .day-workflow-row-toggle { min-height: 64px; }
  .day-workflow-expanded-form { padding: var(--space-3); }
  .day-workflow-row-actions-bar { align-items: stretch; flex-direction: column-reverse; }
  .day-workflow-row-actions-bar > span { display: none; }
  .day-workflow-row-actions-bar .btn { width: 100%; min-height: 44px; }
  .staffing-fields { grid-template-columns: 1fr; gap: 0; }
  .day-information-form-grid { grid-template-columns: 1fr; gap: 0; }
}

.day-detail-loc {
  margin-bottom: var(--space-4);
}

.day-detail-loc:last-child {
  margin-bottom: 0;
}

.day-detail-loc-title {
  font-size: var(--text-sm);
  font-weight: 700;
  margin-bottom: var(--space-2);
  padding-bottom: var(--space-1);
  border-bottom: 1px solid var(--color-border);
}

.day-detail-shift-row {
  display: flex;
  gap: var(--space-3);
  align-items: flex-start;
  margin-bottom: var(--space-2);
}

.day-detail-shift-row:last-child {
  margin-bottom: 0;
}

.day-detail-shift-label {
  flex: 0 0 150px;
  font-size: var(--text-sm);
  font-weight: 600;
  padding-top: 4px;
}

.day-detail-shift-fill {
  font-weight: 500;
  font-size: 0.72rem;
  color: var(--color-muted);
  display: block;
}

.day-detail-shift-fill.understaffed {
  color: var(--color-danger);
}

.day-detail-chips {
  flex: 1;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.day-detail-chips .shift-chip,
.day-detail-chips .chip-unfilled {
  flex: 0 0 auto;
  min-width: 140px;
  margin-bottom: 0;
}

.day-detail-leave,
.day-detail-violations {
  margin-top: var(--space-4);
  padding-top: var(--space-3);
  border-top: 1px solid var(--color-border);
}

.day-detail-violations .conflict-chip {
  margin-bottom: var(--space-2);
}

.day-detail-empty {
  color: var(--color-muted);
  font-size: var(--text-sm);
  padding: var(--space-4) 0;
}

/* Print a single day's roster from the day-detail modal, hiding chrome */
@media print {
  body.printing-day-detail > *:not(.modal-overlay) { display: none !important; }
  body.printing-day-detail .modal-overlay {
    position: static;
    background: none;
    padding: 0;
  }
  body.printing-day-detail .modal {
    max-width: none;
    max-height: none;
    box-shadow: none;
  }
  body.printing-day-detail .modal-header .btn-close,
  body.printing-day-detail .modal-footer {
    display: none !important;
  }
}

/* Print a whole published-roster month grid, hiding app chrome and the page
   header's interactive controls (search, period picker, print button itself)
   — the same "body.guest #app { display: block }" pattern layout.css already
   uses to drop the sidebar/topbar grid columns cleanly. See UX_SPEC.md §4.3.
   Shared with the Roster Editor's own "Print roster" button (printing-draft-
   roster below) — same chrome-hiding rules, only the toolbar selector differs
   since the editor's controls live in .roster-statusbar, not .page-header. */
@media print {
  body.printing-full-roster #sidebar,
  body.printing-full-roster #topbar,
  body.printing-full-roster #attention-banner,
  body.printing-draft-roster #sidebar,
  body.printing-draft-roster #topbar,
  body.printing-draft-roster #attention-banner { display: none !important; }
  body.printing-full-roster #app,
  body.printing-draft-roster #app { display: block !important; }
  body.printing-full-roster #main-content,
  body.printing-draft-roster #main-content { padding: 0; }
  body.printing-full-roster .page-header select,
  body.printing-full-roster .page-header input,
  body.printing-full-roster .page-header button { display: none !important; }

  /* Roster Editor is interactive (draggable/clickable chips, an "+ Assign"
     affordance, a copy-day button) in a way the read-only Published Roster
     grid isn't — none of that makes sense on paper, so it's hidden here on
     top of the shared chrome rules above. */
  body.printing-draft-roster .roster-statusbar,
  body.printing-draft-roster #bulk-action-bar,
  body.printing-draft-roster #violation-summary,
  body.printing-draft-roster .amendment-banner,
  body.printing-draft-roster .chip-add,
  body.printing-draft-roster .btn-copy-day { display: none !important; }
}

/* ══════════════════════════════════════════════════════════════════════════
   DARK THEME — overrides for hardcoded colour values
   All these selectors are prefixed with [data-theme="dark"] so they only
   activate when the <html> element carries that attribute.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── Badges ──────────────────────────────────────────────────────────────── */
[data-theme="dark"] .badge-blue   { background: #1e3a5f; color: #93c5fd; }
[data-theme="dark"] .badge-amber  { background: #3d2510; color: #fcd34d; }
[data-theme="dark"] .badge-red    { background: #3d1515; color: #fca5a5; }
[data-theme="dark"] .badge-green  { background: #143d25; color: #86efac; }
[data-theme="dark"] .badge-gray   { background: var(--color-subtle); color: var(--color-muted); }

/* ── Account security page (2FA compliance gap alert) ────────────────────── */
/* .security-alert's background already tracks --status-warning-bg (which
   flips to a dark amber-brown here), but its text was hardcoded to a
   light-mode-only shade — same fix as .badge-amber above. */
[data-theme="dark"] .security-alert { color: #fcd34d; }

/* ── Admin dashboard ─────────────────────────────────────────────────────── */
[data-theme="dark"] .dash-empty-icon { background: #143d25; color: #86efac; }

/* ── Period status badges ────────────────────────────────────────────────── */
[data-theme="dark"] .status-wish_open   { background: #143d25; color: #86efac; }
[data-theme="dark"] .status-wish_closed { background: #3d2510; color: #fcd34d; }
[data-theme="dark"] .status-draft       { background: #1e3a5f; color: #93c5fd; }
[data-theme="dark"] .status-locked      { background: #2e1a44; color: #d8b4fe; }
[data-theme="dark"] .status-published   { background: #0c2d42; color: #7dd3fc; }

/* ── Select arrow (data-URI colour baked in) ─────────────────────────────── */
[data-theme="dark"] select.input {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%2394a3b8' d='M6 8L1 3h10z'/%3E%3C/svg%3E");
}

/* ── Calendar cells ──────────────────────────────────────────────────────── */
[data-theme="dark"] .cal-cell[role="button"]:hover          { background: #243347; }
[data-theme="dark"] .cal-cell[role="button"]:focus-visible  { background: #243347; }

/* Weekend shading overlay — lighten instead of darken against dark surfaces */
[data-theme="dark"] .cal-cell.weekend::after { background: rgba(255, 255, 255, .045); }

/* Off-wish density heatmap — dark-safe reds (see the light-mode .cal-heat-* rules) */
[data-theme="dark"] .cal-heat-low  { background: #3a1a1a; }
[data-theme="dark"] .cal-heat-med  { background: #5c2323; color: #f1f1f1; }
[data-theme="dark"] .cal-heat-high { background: #8f2f2f; color: #fff; }

/* Staffing calendar override / holiday markers — same dark amber as
   .conflict-soft's dark override. */
[data-theme="dark"] .cal-cell.sc-holiday { background: #2d2410; }
/* .wish-off-badge and the location-tinted .sch-shift-badge.loc-* rules need
   no dark override here — they're built on --cat-rose-bg / color-mix() over
   the --loc-* tokens, which already resolve to their dark values via
   base.css's [data-theme="dark"] block. */

/* ── Notification items (unread tint) ────────────────────────────────────── */
[data-theme="dark"] .notif-item             { background: #26200e; }
[data-theme="dark"] .notif-item:hover       { background: var(--color-subtle); }
[data-theme="dark"] .notif-item.notif-read  { background: var(--color-surface); }

/* ── Violation panel ─────────────────────────────────────────────────────── */
[data-theme="dark"] .violation-item:hover { background: #2d1515; }

/* ── User row in assignment modal ────────────────────────────────────────── */
[data-theme="dark"] .user-row.user-row-current    { background: #243347; }
[data-theme="dark"] .user-badge.wish-match        { background: #1e3a5f; color: #93c5fd; }
[data-theme="dark"] .user-badge.wish-off          { background: #3d2510; color: #fcd34d; }
[data-theme="dark"] .user-badge.conflict          { background: #3d1515; color: #fca5a5; }

/* ── Wish heatmap badges ─────────────────────────────────────────────────── */
[data-theme="dark"] .hm-badge.off   { background: #3d1515; color: #fca5a5; }
[data-theme="dark"] .hm-badge.shift { background: #1e3a5f; color: #93c5fd; }
/* .hm-badge.leave needs no dark override here — it's built from --cat-moss/
   --cat-moss-bg, which already flip under [data-theme="dark"] in base.css. */

/* ── Roster grid v2 ──────────────────────────────────────────────────────── */
[data-theme="dark"] .rgv2-row-weekend .rgv2-loc-td      { background: #1a2737; }
[data-theme="dark"] .rgv2-row-weekend .rgv2-conflict-td { background: #1a2737; }
[data-theme="dark"] .rgv2-norule {
  background: repeating-linear-gradient(
    45deg, transparent, transparent 4px, #253040 4px, #253040 8px
  ) !important;
}
[data-theme="dark"] .rgv2-row-weekend .rgv2-norule {
  background: repeating-linear-gradient(
    45deg, transparent, transparent 4px, #2a3545 4px, #2a3545 8px
  ) !important;
}

/* ── Shift chips ─────────────────────────────────────────────────────────── */
[data-theme="dark"] .chip-unfilled          { background: #2d1515; }
[data-theme="dark"] .chip-clickable:hover   { background: #243347; }
[data-theme="dark"] .chip-clickable:focus-visible { background: #243347; }
[data-theme="dark"] .shift-chip.drop-target { background: #243347; }
[data-theme="dark"] .shift-chip.chip-selected { background: #1e3a5f; }
[data-theme="dark"] .conflict-chip          { background: #2d1515; }
[data-theme="dark"] .conflict-chip.conflict-soft { background: #2d2410; }
[data-theme="dark"] .inline-warning { background: #2d2410; }

/* ── Violation summary panel ──────────────────────────────────────────────── */
[data-theme="dark"] .violation-summary-chip { background: #2d1515; }
[data-theme="dark"] .violation-summary-chip.conflict-soft { background: #2d2410; }
[data-theme="dark"] .violation-summary-ok   { background: #143d25; }
[data-theme="dark"] tr.rgv2-flash-row > td {
  animation-name: rgv2-row-flash-dark;
}
@keyframes rgv2-row-flash-dark {
  0%, 100% { box-shadow: none; }
  30%      { box-shadow: inset 0 0 0 999px rgba(96, 165, 250, .28); }
}

/* ── Current schedule day-detail drill-down ──────────────────────────────── */
[data-theme="dark"] .curr-sched-card .cal-cell:hover { box-shadow: inset 0 0 0 2px var(--color-primary); background: #243347; }
[data-theme="dark"] .curr-sched-card .cal-cell.flash { animation-name: curr-sched-flash-dark; }
@keyframes curr-sched-flash-dark {
  0%, 100% { background: transparent; }
  30%      { background: rgba(96, 165, 250, .28); }
}

/* ════════════════════════════════════════════════════════════════════════════
   ENHANCEMENTS — ALL2, A1, A2, A3, R1, R4, V1, AD1, AD2
   ════════════════════════════════════════════════════════════════════════════ */

/* ── ALL2: Password show/hide toggle ─────────────────────────────────────── */
.pw-wrapper {
  position: relative;
  display: flex;
  align-items: center;
}
.pw-wrapper .input {
  padding-right: 2.5rem;
  width: 100%;
}
.pw-toggle {
  position: absolute;
  right: var(--space-2);
  background: none;
  border: none;
  cursor: pointer;
  font-size: 1rem;
  padding: var(--space-1);
  color: var(--color-muted);
  line-height: 1;
  flex-shrink: 0;
}
.pw-toggle:hover { color: var(--color-text); }

/* ── A3: Wish submission — summary bar + past-date cell ──────────────────── */
.wish-summary-bar {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
  font-size: var(--text-sm);
}
.wish-summary-item { font-weight: 500; }
.wish-summary-off  { color: var(--color-danger); }
.wish-summary-shift { color: var(--color-primary); }
.wish-summary-sep  { color: var(--color-muted); }

.cal-past {
  opacity: 0.45;
  cursor: default !important;
  pointer-events: none;
}

/* ── A1: Shift times in My Schedule calendar badges ──────────────────────── */
.sch-shift-times {
  display: block;
  font-size: 0.68rem;
  color: var(--color-muted);
  margin-top: 1px;
}

/* ── R1: Sticky date column in roster grid ───────────────────────────────── */
.roster-grid-v2 .rgv2-date-th,
.roster-grid-v2 .rgv2-date-td {
  position: sticky;
  left: 0;
  z-index: 2;
  background: var(--color-surface);
  box-shadow: 2px 0 6px rgba(0,0,0,0.07);
}

/* ── R4: Wish overview user highlight ────────────────────────────────────── */
.heatmap-user-highlight {
  outline: 2px solid var(--color-primary);
  outline-offset: -2px;
}
.wish-user-filter-badge {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-sm);
  padding: var(--space-1) var(--space-3);
  background: var(--color-subtle);
  border-radius: var(--radius-sm);
}
.day-wish-user-btn {
  background: none;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  padding: 1px var(--space-2);
  font-size: inherit;
  cursor: pointer;
  color: var(--color-text);
  text-align: left;
}
.day-wish-user-btn:hover  { background: var(--color-subtle); }
.day-wish-user-btn.active { background: var(--color-primary); color: #fff; border-color: var(--color-primary); }

/* ── Published roster user search highlight ──────────────────────────────── */
.shift-chip.search-match { background: #fef08a !important; color: #713f12; box-shadow: 0 0 0 1px #ca8a04; }
.shift-chip.search-match .chip-name { color: #713f12; }
.shift-chip.search-dim   { opacity: 0.3; }

/* ════════════════════════════════════════════════════════════════════════════
   DARK THEME — enhancement overrides
   ════════════════════════════════════════════════════════════════════════════ */

/* ── ALL2 dark ────────────────────────────────────────────────────────────── */
[data-theme="dark"] .pw-toggle { color: var(--color-muted); }
[data-theme="dark"] .pw-toggle:hover { color: var(--color-text); }

/* ── R1 dark: sticky date column needs explicit dark bg ──────────────────── */
[data-theme="dark"] .roster-grid-v2 .rgv2-date-th,
[data-theme="dark"] .roster-grid-v2 .rgv2-date-td {
  background: var(--color-surface);
  box-shadow: 2px 0 6px rgba(0,0,0,0.25);
}
[data-theme="dark"] .rgv2-row-weekend .rgv2-date-td {
  background: #1a2737;
}
[data-theme="dark"] .rgv2-date-clickable:hover,
[data-theme="dark"] .rgv2-date-clickable:focus-visible {
  background: #243347;
}

/* ── R4 dark ─────────────────────────────────────────────────────────────── */
[data-theme="dark"] .wish-user-filter-badge { background: #1e2d3d; }
[data-theme="dark"] .day-wish-user-btn { border-color: var(--color-border); color: var(--color-text); }
[data-theme="dark"] .day-wish-user-btn:hover { background: #1e2d3d; }

/* ── V1 dark ─────────────────────────────────────────────────────────────── */
[data-theme="dark"] .shift-chip.search-match { background: #713f12 !important; color: #fef08a; box-shadow: 0 0 0 1px #fbbf24; }
[data-theme="dark"] .shift-chip.search-match .chip-name { color: #fef08a; }
[data-theme="dark"] .shift-chip.search-dim   { opacity: 0.25; }

/* ── U1 dark: sortable column headers ───────────────────────────────────── */
[data-theme="dark"] .sortable-th:hover { background: rgba(255,255,255,0.05); }
[data-theme="dark"] .sort-indicator.active { color: var(--color-text); }


/* ── Amendment/sick-leave dark overrides ────────────────────────────────── */
[data-theme="dark"] .amendment-banner {
  background: #3d2510;
  border-left-color: #d97706;
  color: #fcd34d;
}

/* ── Action-needed (shared component, components/action-needed.js) ───────────
   One visual language for "here's a fact, here's what to do" — used both in
   the persistent banner slot (banner.js) and inline on My Schedule's "Next
   schedule" card, so the same underlying fact never looks like two unrelated
   features that happen to say similar things. Urgency reads primarily through
   hue (amber/orange = worth knowing soon, red = acting now), reinforced at
   three levels — a background wash, a solid icon badge, and a solid CTA
   button — the same escalation every other status-coded surface in this app
   uses (badges, status pills, violation chips), just applied with more
   weight since this is the one surface meant to interrupt, not just label. */
.action-needed {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-6);
  font-size: var(--text-sm);
  line-height: 1.4;
  background: var(--color-surface);
  box-shadow: 0 1px 3px rgba(0,0,0,0.1);
  position: relative;
  z-index: 1;
}
.action-needed.tone-amber {
  background: var(--status-warning-bg);
  color: #92400e;
}
.action-needed.tone-blue {
  background: var(--status-info-bg);
  color: #1e40af;
}
.action-needed.tone-red {
  background: var(--status-danger-bg);
  color: #7f1d1d;
}

/* A solid colour swatch pinned to the top edge reads as a stronger urgency
   signal than a left stripe on a full-bleed banner, and stays legible at a
   glance even before the message text is read. */
.action-needed::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 3px;
}
.action-needed.tone-amber::before { background: var(--status-warning); }
.action-needed.tone-blue::before  { background: var(--status-info); }
.action-needed.tone-red::before   { background: var(--status-danger); }
.action-needed-list .action-needed::before { border-radius: var(--radius) var(--radius) 0 0; }

.action-needed-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  flex-shrink: 0;
  color: #fff;
}
.action-needed.tone-amber .action-needed-icon { background: var(--status-warning); }
.action-needed.tone-blue .action-needed-icon  { background: var(--status-info); }
.action-needed.tone-red .action-needed-icon   { background: var(--status-danger); }

/* min-width:0 overrides the flex-item default of min-width:auto, which
   otherwise refuses to shrink below the message's unwrapped width and forces
   the whole single-column mobile grid (#app) to overflow the viewport. */
.action-needed-msg { flex: 1; min-width: 0; font-weight: 500; }
.action-needed-msg strong { font-weight: 700; }

.action-needed-action {
  color: #fff;
  border: none;
  padding: 6px var(--space-4);
  border-radius: var(--radius-sm);
  font-weight: 600;
  font-size: var(--text-sm);
  cursor: pointer;
  transition: filter var(--transition), transform var(--transition);
  flex-shrink: 0;
  box-shadow: 0 1px 2px rgba(0,0,0,0.15);
}
.action-needed.tone-amber .action-needed-action { background: var(--status-warning); }
.action-needed.tone-blue .action-needed-action  { background: var(--status-info); }
.action-needed.tone-red .action-needed-action   { background: var(--status-danger); }
.action-needed-action:hover { filter: brightness(1.08); }
.action-needed-action:active { filter: brightness(0.94); transform: scale(0.98); }

.action-needed-close {
  background: none;
  border: none;
  color: inherit;
  opacity: 0.55;
  font-size: 1.2rem;
  line-height: 1;
  cursor: pointer;
  padding: 2px 6px;
  border-radius: var(--radius-sm);
  flex-shrink: 0;
}
.action-needed-close:hover { opacity: 1; background: rgba(0,0,0,0.08); }

/* Standalone rows (My Schedule's "Next schedule" card) render one
   action-needed row per period inside a plain card rather than the fixed
   banner slot — same classes and same tone colours, just not full-bleed and
   with rounded corners instead of a bottom border. */
.action-needed-list .action-needed {
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius);
  box-shadow: none;
  overflow: hidden;
}

[data-theme="dark"] .action-needed.tone-amber { color: #fcd34d; }
[data-theme="dark"] .action-needed.tone-blue  { color: #93c5fd; }
[data-theme="dark"] .action-needed.tone-red   { color: #fca5a5; }
[data-theme="dark"] .action-needed { box-shadow: 0 1px 3px rgba(0,0,0,0.4); }
[data-theme="dark"] .action-needed-close:hover { background: rgba(255,255,255,0.1); }

/* ════════════════════════════════════════════════════════════════════════════
   WISH SUBMISSION — deliberate mobile pass (CLAUDE.md's one explicit
   exception to "mobile is not a primary target"). Scoped to #calendar-container
   and the wish-page-* classes so the current-schedule / my-schedule calendars
   (desk-facing screens) are unaffected.
   ════════════════════════════════════════════════════════════════════════════ */
@media (max-width: 600px) {
  .wish-page-header {
    flex-direction: column;
    align-items: stretch;
  }

  .wish-page-controls {
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-2);
  }

  .wish-page-controls #period-select {
    width: 100% !important;
  }

  .wish-legend {
    gap: var(--space-3);
  }

  .wish-summary-bar {
    flex-wrap: wrap;
    row-gap: var(--space-1);
  }

  /* Seven columns at phone width leaves almost no room per cell — shrink
     padding/min-height and collapse each wish badge into a small coloured
     dot (font-size:0 hides the label text visually only; screen readers
     still read it) instead of truncating "Preferred off" mid-word. Tapping
     the day still opens the full-detail modal. */
  #calendar-container .cal-th {
    padding: 3px 1px;
    font-size: 0.68rem;
  }

  #calendar-container .cal-cell {
    min-height: 44px;
    padding: 3px;
  }

  #calendar-container .cal-day {
    font-size: 0.75rem;
    margin-bottom: 2px;
  }

  /* Wish badges now render through .sch-shift-badge (see wish-submission.js's
     shiftWishBadgeHTML/offWishBadgeHTML) — collapse the same way .cal-wish
     used to: hide the text/secondary lines (font-size:0/display:none, screen
     readers still get the full label via the badge's title attribute) and
     strip the chip's own box chrome, leaving only its .chip-dot (location hue
     + on-call ring, CLAUDE.md §13.1) visible as a small coloured dot. */
  #calendar-container .sch-shift-badge {
    display: inline-flex;
    padding: 0;
    margin: 0 3px 3px 0;
    background: none !important;
    border-left: none;
  }
  #calendar-container .sch-shift-badge .sch-shift-name {
    font-size: 0;
    gap: 0;
  }
  #calendar-container .sch-shift-badge .sch-loc-name,
  #calendar-container .sch-shift-badge .sch-shift-times {
    display: none;
  }
  #calendar-container .sch-shift-badge .chip-dot {
    width: 8px;
    height: 8px;
  }
}

/* ── Mandatory account-security onboarding ─────────────────────────────── */
.security-setup-page {
  width: min(100%, 780px);
  margin: 0 auto;
  padding-bottom: var(--space-6);
}
.security-setup-header { margin-bottom: var(--space-6); }
.security-setup-header h2,
.security-setup-success h2 { margin: var(--space-2) 0 var(--space-3); }
.security-kicker {
  margin: 0;
  color: var(--color-primary);
  font-size: var(--text-sm);
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
}
.security-privacy-note,
.security-browser-help,
.security-recovery-tip {
  margin-top: var(--space-4);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius);
  background: var(--color-subtle);
  color: var(--color-muted);
}
.security-choice-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-4);
  margin-top: var(--space-4);
}
.security-choice-card {
  position: relative;
  display: flex;
  min-height: 245px;
  padding: var(--space-6);
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-surface);
  color: var(--color-text);
  font: inherit;
  text-align: left;
  cursor: pointer;
  box-shadow: var(--shadow-sm);
}
.security-choice-card:hover:not(:disabled),
.security-choice-card:focus-visible { border-color: var(--color-primary); box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-primary) 18%, transparent); }
.security-choice-card.recommended { border-width: 2px; border-color: var(--color-primary); }
.security-choice-card:disabled { cursor: not-allowed; opacity: .62; }
.security-choice-card strong { font-size: 1.15rem; }
.security-choice-icon { font-size: 2rem; }
.security-choice-action { margin-top: auto; color: var(--color-primary); font-weight: 700; }
.security-recommended {
  position: absolute;
  top: 0;
  right: var(--space-4);
  padding: .3rem .65rem;
  border-radius: 0 0 var(--radius-sm) var(--radius-sm);
  background: var(--color-primary);
  color: white;
  font-size: .72rem;
  font-weight: 700;
  text-transform: uppercase;
}
.security-back { margin-bottom: var(--space-3); }
.security-method-card { padding: clamp(var(--space-4), 4vw, var(--space-6)); }
.security-step-badge {
  display: inline-block;
  margin-bottom: var(--space-2);
  color: var(--color-primary);
  font-size: var(--text-sm);
  font-weight: 700;
}
.security-steps { padding: 0; margin: var(--space-5) 0; list-style: none; }
.security-steps li { display: flex; gap: var(--space-3); margin-bottom: var(--space-4); }
.security-steps li > span {
  display: grid;
  width: 28px;
  height: 28px;
  flex: 0 0 28px;
  place-items: center;
  border-radius: 50%;
  background: var(--color-primary);
  color: white;
  font-weight: 700;
}
.security-device-guides { margin-top: var(--space-6); border-top: 1px solid var(--color-border); padding-top: var(--space-4); }
.security-device-guides details { border-bottom: 1px solid var(--color-border); }
.security-device-guides summary { padding: var(--space-4) 0; cursor: pointer; font-weight: 600; }
.security-guide-body { padding: 0 var(--space-3) var(--space-4); }
.security-guide-body li { margin-bottom: var(--space-2); }
.security-progress { display: flex; align-items: flex-start; margin-bottom: var(--space-6); }
.security-progress > span {
  display: flex;
  width: 34px;
  height: 34px;
  flex: 0 0 34px;
  align-items: center;
  justify-content: center;
  position: relative;
  border: 2px solid var(--color-border);
  border-radius: 50%;
  color: var(--color-muted);
  font-weight: 700;
}
.security-progress > span.active { border-color: var(--color-primary); background: var(--color-primary); color: white; }
.security-progress > span > span { position: absolute; top: 38px; white-space: nowrap; color: var(--color-muted); font-size: .72rem; font-weight: 400; }
.security-progress > i { height: 2px; flex: 1; margin-top: 16px; background: var(--color-border); }
.security-setup-success { max-width: 600px; margin: var(--space-6) auto; text-align: center; padding: clamp(var(--space-5), 6vw, 3rem); }
.security-success-icon { display: grid; width: 64px; height: 64px; margin: 0 auto var(--space-4); place-items: center; border-radius: 50%; background: var(--color-success); color: white; font-size: 2rem; }
.security-setup-success .btn { margin-top: var(--space-4); }

@media (max-width: 600px) {
  .security-choice-grid { grid-template-columns: 1fr; }
  .security-choice-card { min-height: 210px; padding: var(--space-5); }
  .security-method-card { border-radius: 0; margin-inline: calc(-1 * var(--space-3)); }
}
