/* ============================================================
   SFHI Cardiology Coverage — "Telemetry Paper" theme
   Visual language borrows from EKG chart paper: warm ivory
   ground, fine pink graph grid, ink-navy type, trace-red accent
   for the thing that matters most (who's on call tonight).
   ============================================================ */

@font-face {
  /* no external fonts — everything below resolves to locally installed faces */
  font-family: "system-fallback";
  src: local("Helvetica Neue");
}

:root {
  --paper: #fdf6f1;
  --paper-line: #eccdd2;
  --paper-line-strong: #e3b4bc;
  --ink: #201c2b;
  --ink-soft: #5b5568;
  --ink-faint: #948da3;
  --rule: #d8c3c8;

  --trace-red: #c31432;
  --trace-red-deep: #8f0e24;
  --trace-red-tint: #fbe2e5;

  --team-a: #0d7d6d;
  --team-a-tint: #dcf2ee;
  --team-b: #a9660a;
  --team-b-tint: #f8ead2;
  --team-c: #5b3a8e;
  --team-c-tint: #ebe1f7;

  --vacation: #6b7280;
  --vacation-tint: #e7e8ea;

  --alert: #d1670b;
  --alert-tint: #fdead2;

  --ekg-glow: #ffb703;

  --stemi-yellow: #8a6d1a;
  --stemi-yellow-tint: #fdf3cf;
  --stemi-yellow-deep: #e0c766;

  --font-display: "Iowan Old Style", "Palatino Linotype", Palatino, "Book Antiqua", Georgia, serif;
  --font-ui: "Avenir Next", "Futura", "Century Gothic", "Segoe UI", sans-serif;
  --font-mono: ui-monospace, "SF Mono", "Cascadia Code", "Roboto Mono", Menlo, Consolas, monospace;

  --radius: 10px;
  --shadow-card: 0 1px 2px rgba(32, 28, 43, 0.06), 0 6px 20px rgba(32, 28, 43, 0.07);
}

* {
  box-sizing: border-box;
}

html, body {
  margin: 0;
  padding: 0;
}

/* Safety net alongside the min-width/minmax fixes below -- nothing on this site relies on
   horizontal scroll (the one internal scroller, .discrepancy-list, is vertical-only), so this
   only ever hides an unintended overflow, never a real one. Scoped to html only, not body --
   setting overflow-x on *both* independently forces each into its own overflow-y:auto scroll
   container (per the CSS overflow-coupling rule: non-visible overflow-x with visible overflow-y
   computes the latter to auto), which breaks position:sticky elsewhere on the page (the call
   planner's sticky calendar/tally sidebar) since its containing block for stickiness becomes
   ambiguous between the two nested scrollers. One scroll container is enough for the same
   protection. */
html {
  overflow-x: hidden;
}

body {
  font-family: var(--font-ui);
  color: var(--ink);
  background-color: var(--paper);
  background-image:
    repeating-linear-gradient(to right, var(--paper-line) 0 1px, transparent 1px 20px),
    repeating-linear-gradient(to bottom, var(--paper-line) 0 1px, transparent 1px 20px),
    repeating-linear-gradient(to right, var(--paper-line-strong) 0 1.5px, transparent 1.5px 100px),
    repeating-linear-gradient(to bottom, var(--paper-line-strong) 0 1.5px, transparent 1.5px 100px);
  min-height: 100vh;
  line-height: 1.4;
}

.wrap {
  max-width: 1240px;
  margin: 0 auto;
  padding: 28px 24px 64px;
}

/* ---------------- Header ---------------- */

.site-header {
  position: relative;
  padding: 28px 32px 22px;
  margin-bottom: 22px;
  background: linear-gradient(180deg, #fffdfb 0%, #fdf6f1 100%);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  box-shadow: var(--shadow-card);
  overflow: hidden;
}

.site-header .ekg-trace {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 64px;
  opacity: 0.9;
}

.ekg-trace path {
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.ekg-trace .trace-base {
  stroke: var(--trace-red);
  stroke-width: 1.75;
  opacity: 0.32;
}

.ekg-trace .trace-sweep {
  stroke: var(--trace-red);
  stroke-width: 2.5;
  stroke-dasharray: 90 2000;
  animation: trace-sweep 7s linear infinite;
  filter: drop-shadow(0 0 3px rgba(195, 20, 50, 0.55));
}

@keyframes trace-sweep {
  from { stroke-dashoffset: 900; }
  to { stroke-dashoffset: -1200; }
}

.header-content {
  position: relative;
  margin-top: 46px;
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 24px;
  flex-wrap: wrap;
}

.header-title-block {
  /* Flex items default to min-width:auto, which for a text-containing child means it won't
     shrink below its content's unwrapped width -- without this, the subtitle line (window range
     + provider count) refuses to wrap and pushes the whole header wider than the viewport on
     narrow screens, a real bug this fixes rather than works around. */
  min-width: 0;
}

.site-title {
  font-family: var(--font-display);
  font-size: 32px;
  font-weight: 600;
  letter-spacing: 0.2px;
  margin: 0;
  color: var(--ink);
}

.site-title small {
  display: block;
  font-family: var(--font-ui);
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: 2.5px;
  text-transform: uppercase;
  color: var(--trace-red-deep);
  margin-bottom: 6px;
}

.source-links {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}

.source-link {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-family: var(--font-ui);
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-soft);
  text-decoration: none;
  padding: 5px 11px;
  border: 1px solid var(--rule);
  border-radius: 999px;
  background: #fffefc;
  transition: border-color 0.12s ease, color 0.12s ease;
}

.source-link:hover {
  border-color: var(--trace-red);
  color: var(--ink);
}

.source-link-icon {
  width: 13px;
  height: 13px;
  flex-shrink: 0;
}

.source-link-amion .source-link-icon {
  color: var(--trace-red);
}

.source-link-gcal .source-link-icon {
  color: #4285f4;
}

.site-subtitle {
  font-size: 13.5px;
  color: var(--ink-soft);
  margin: 6px 0 0;
  font-family: var(--font-mono);
}

/* The page-level explanatory paragraph (the long prose under the title on most pages) collapses
   behind a small "About" caret toggle, closed by default -- per explicit user request, so the
   header reads as a title first, not a wall of text. Visually a near-duplicate of
   .filters-collapsible/.filters-toggle/.filters-caret (same caret-rotate affordance) but kept as
   its own small rule set rather than renaming/sharing those, since this sits in a different part
   of the page (the header, not the calendar toolbar) and the two features have no reason to stay
   coupled going forward. */
.about-collapsible {
  margin-top: 4px;
}

.about-toggle {
  display: flex;
  align-items: center;
  gap: 6px;
  width: fit-content;
  cursor: pointer;
  list-style: none;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  color: var(--ink-faint);
  user-select: none;
  transition: color 0.12s ease;
}

.about-toggle::-webkit-details-marker {
  display: none;
}

.about-toggle:hover {
  color: var(--trace-red-deep);
}

.about-caret {
  display: inline-flex;
  font-size: 9px;
  transition: transform 0.15s ease;
}

.about-collapsible[open] > .about-toggle .about-caret {
  transform: rotate(-180deg);
}

.about-collapsible .site-subtitle {
  margin-top: 8px;
}

/* ---------------- Site nav ---------------- */

/* Grouped-hierarchy nav (replaced a flat 7-item bracket list per explicit user request, chosen
   from three mocked-up directions): splits the pages by what they actually are rather than
   weighting all seven equally. Calendar/At a Glance/Call Planner/Mismatch Review are things you
   *do* -- bold primary tabs. Template/Holiday History/Spreadsheet Reference are things you *look
   up* -- a quieter reference row underneath, with no bracket styling (deliberately lighter than
   the old flat list, to read as secondary rather than another set of equal peers). */
.site-nav {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-bottom: 22px;
}

.site-nav-primary {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.site-nav-tab {
  font-family: var(--font-ui);
  font-size: 13px;
  font-weight: 700;
  text-decoration: none;
  padding: 8px 18px;
  border-radius: 8px;
  border: 1.5px solid var(--rule);
  color: var(--ink-soft);
  background: #fffefc;
  transition: border-color 0.12s ease, color 0.12s ease;
}

.site-nav-tab:hover {
  border-color: var(--trace-red);
  color: var(--ink);
}

/* .site-nav-current marks the page you're actually on, same convention the old flat nav used
   (a plain <span> in place of that one entry's <a>) -- but it now needs two different looks
   depending on which row it's in, so it's scoped by ancestor rather than given its own fixed style. */
.site-nav-primary .site-nav-current {
  display: inline-block;
  font-family: var(--font-ui);
  font-size: 13px;
  font-weight: 700;
  padding: 8px 18px;
  border-radius: 8px;
  border: 1.5px solid var(--trace-red);
  background: var(--trace-red-tint);
  color: var(--trace-red-deep);
}

.site-nav-reference {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  padding-left: 2px;
}

.site-nav-reference-label {
  font-family: var(--font-ui);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.site-nav-reference-links {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  font-family: var(--font-mono);
  font-size: 12px;
}

.site-nav-reference-links a {
  color: var(--ink-soft);
  text-decoration: none;
}

.site-nav-reference-links a:hover {
  color: var(--trace-red-deep);
  text-decoration: underline;
}

.site-nav-reference .site-nav-current {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--ink-faint);
  font-weight: 600;
}

/* ---------------- Provider filter ---------------- */

.filters-collapsible {
  margin-bottom: 22px;
}

/* The browser's native rule that hides a closed <details>'s non-summary children has lower
   specificity than our own .filter-row { display: flex } below, so without this override the
   filter rows would stay visible even while collapsed -- confirmed as a real bug during testing,
   not a hypothetical. */
.filters-collapsible:not([open]) .filter-row {
  display: none;
}

.filters-toggle {
  display: flex;
  align-items: center;
  gap: 6px;
  width: fit-content;
  cursor: pointer;
  list-style: none;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  color: var(--ink-faint);
  user-select: none;
  transition: color 0.12s ease;
}

.filters-toggle::-webkit-details-marker {
  display: none;
}

.filters-toggle:hover {
  color: var(--trace-red-deep);
}

.filters-caret {
  display: inline-flex;
  font-size: 9px;
  transition: transform 0.15s ease;
}

.filters-collapsible[open] > .filters-toggle .filters-caret {
  transform: rotate(-180deg);
}

.filters-collapsible .filter-row:first-of-type {
  margin-top: 14px;
}

.filters-collapsible .filter-row:last-of-type {
  margin-bottom: 0;
}

.filter-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin-bottom: 22px;
}

.filter-label {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin-right: 4px;
}

.chip {
  appearance: none;
  border: 1.5px solid var(--rule);
  background: #fffdfb;
  color: var(--ink-soft);
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 600;
  padding: 6px 13px;
  border-radius: 999px;
  cursor: pointer;
  transition: all 0.15s ease;
}

.chip:hover {
  border-color: var(--trace-red);
  color: var(--trace-red-deep);
}

.chip.active {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--paper);
}

/* ---------------- Calendar ---------------- */

.card {
  background: #fffdfb;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  box-shadow: var(--shadow-card);
  padding: 20px 22px 24px;
  margin-bottom: 24px;
}

/* A .card holding nothing but one control row (a Range picker, a toggle) doesn't need the full
   20px/22px/24px padding + 24px margin a content card gets -- that's ~100px of chrome spent on a
   single line of inputs. Shared across discrepancy_review.html (its merged Range + show-resolved
   toolbar) and call_planner.html (its Range card) rather than duplicated per page. */
.toolbar-card {
  padding: 14px 18px;
  margin-bottom: 16px;
}

.cal-nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 16px;
}

.cal-nav h2 {
  font-family: var(--font-display);
  font-size: 22px;
  margin: 0;
  text-align: left;
}

.cal-nav-controls {
  display: flex;
  align-items: center;
  gap: 10px;
}

.cal-nav-buttons {
  display: flex;
  gap: 8px;
}

.cal-nav-divider {
  width: 1px;
  height: 22px;
  background: var(--rule);
}

.nav-btn {
  border: 1.5px solid var(--rule);
  background: #fffdfb;
  color: var(--ink);
  font-family: var(--font-ui);
  font-size: 13px;
  font-weight: 700;
  padding: 7px 14px;
  border-radius: 8px;
  cursor: pointer;
}

.nav-btn:hover {
  border-color: var(--trace-red);
  color: var(--trace-red-deep);
}

.cal-grid {
  display: grid;
  /* minmax(0, 1fr), not plain 1fr -- a grid track's implicit minimum is its content's unwrapped
     width, so a cell with a long badge/label would otherwise refuse to shrink and blow the whole
     grid (and page) wider than the viewport on narrow screens. minmax(0, ...) removes that floor
     and lets individual cell content wrap/truncate within its column instead. */
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 6px;
  max-width: 100%;
}

.cal-weekday {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--ink-faint);
  text-align: center;
  padding-bottom: 4px;
}

.cal-weekday.is-weekend {
  color: var(--trace-red-deep);
}

.cal-cell {
  position: relative;
  min-height: 108px;
  border: 1px solid var(--rule);
  border-radius: 8px;
  background: #fffefc;
  padding: 6px 6px 8px;
  cursor: pointer;
  transition: box-shadow 0.12s ease, transform 0.12s ease;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.cal-cell:hover {
  box-shadow: 0 3px 12px rgba(32, 28, 43, 0.1);
  transform: translateY(-1px);
}

.cal-cell.is-weekend {
  background: #fef8f5;
}

.cal-cell.is-today {
  border-color: var(--trace-red);
  border-width: 2px;
}

.cal-cell.is-ekg::before {
  content: "";
  position: absolute;
  inset: -1px;
  border: 2px solid var(--ekg-glow);
  border-radius: 8px;
  pointer-events: none;
}

.cal-cell.dimmed {
  opacity: 0.32;
}

.cal-cell.other-month {
  opacity: 0.4;
}

.cal-cell.other-month:hover {
  opacity: 0.6;
}

.cal-lane-row {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 3px;
  align-content: start;
}

.cal-bar {
  border-radius: 5px;
  padding: 2px 7px;
  font-family: var(--font-mono);
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.2px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  cursor: default;
  transition: opacity 0.12s ease;
}

.cal-bar-vacation {
  background: var(--vacation-tint);
  color: var(--vacation);
}

.cal-bar-ekg {
  background: #fff3d6;
  color: #8a5c00;
}

.cal-bar-fellow {
  background: #d6eefc;
  color: #0d6d9e;
}

.cal-bar.dimmed {
  opacity: 0.28;
}

.cell-date-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
}

.cell-date {
  font-family: var(--font-mono);
  font-size: 12.5px;
  font-weight: 700;
  color: var(--ink-soft);
}

.cell-holiday {
  font-size: 9px;
  color: var(--trace-red-deep);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.4px;
  max-width: 60%;
  text-align: right;
  line-height: 1.15;
}

.cell-oncall {
  display: inline-flex;
  align-self: flex-start;
  align-items: center;
  background: var(--trace-red);
  color: #fff8f6;
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: 12px;
  padding: 2px 8px;
  border-radius: 5px;
  letter-spacing: 0.3px;
}

.cell-top-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
}

.cell-ic {
  font-family: var(--font-mono);
  font-weight: 600;
  font-size: 11px;
  color: var(--ink-faint);
  letter-spacing: 0.2px;
}

.cell-badges {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.cell-badges-group {
  display: flex;
  flex-wrap: wrap;
  gap: 3px;
}

.cell-badges-divider {
  border-top: 1px dashed var(--rule);
  margin: 1px 0;
}

.badge {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 700;
  padding: 1px 6px;
  border-radius: 4px;
  line-height: 1.5;
  white-space: nowrap;
}

.badge-team-A { background: var(--team-a-tint); color: var(--team-a); }
.badge-team-B { background: var(--team-b-tint); color: var(--team-b); }
.badge-team-C { background: var(--team-c-tint); color: var(--team-c); }
.badge-team-combo { background: #f2eef5; color: var(--ink-soft); }

.badge-role {
  background: #f0eef3;
  color: var(--ink-soft);
  border: 1px solid var(--rule);
}

/* "No nucs" chip -- the radiation emoji struck through, for a date the spreadsheet explicitly
   marks as having no nuclear stress testing coverage (day.noNucs). Muted like .badge-role since
   it's informational, not a real assignment. */
.badge-no-nucs {
  text-decoration: line-through;
  text-decoration-color: var(--alert);
  text-decoration-thickness: 2px;
}

/* Plain-location chip (template.html's summary table) -- a provider with no named duty that
   half-day still gets a chip so every doc is accounted for, but deliberately more muted than
   .badge-role (dashed border, no fill) so a real duty assignment still reads as more significant
   at a glance than "just here". */
.badge-location {
  background: transparent;
  color: var(--ink-faint);
  border: 1px dashed var(--rule);
}

.badge-stemi {
  background: var(--stemi-yellow-tint);
  color: var(--stemi-yellow);
  border: 1px solid var(--stemi-yellow-deep);
}

.cell-alert {
  position: absolute;
  top: 5px;
  right: 5px;
  width: 15px;
  height: 15px;
  border-radius: 50%;
  background: var(--alert);
  color: #fffdfb;
  font-size: 10px;
  font-weight: 900;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 0 0 2px #fffefc;
}

.cell-deviation-flag {
  margin-top: auto;
  align-self: stretch;
  text-align: center;
  font-family: var(--font-mono);
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.3px;
  color: var(--ink-soft);
  background: #f0eef3;
  border: 1px solid var(--rule);
  border-radius: 4px;
  padding: 2px 4px;
  cursor: help;
}

.cell-unaccounted-flag {
  margin-top: auto;
  align-self: stretch;
  text-align: center;
  font-family: var(--font-mono);
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.3px;
  color: var(--alert);
  background: var(--alert-tint);
  border: 1px solid #f0d3ab;
  border-radius: 4px;
  padding: 2px 4px;
  cursor: help;
}

.cell-conflict-flag {
  margin-top: auto;
  align-self: stretch;
  text-align: center;
  font-family: var(--font-mono);
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.3px;
  color: var(--trace-red-deep);
  background: var(--trace-red-tint);
  border: 1px solid var(--trace-red);
  border-radius: 4px;
  padding: 2px 4px;
  cursor: help;
}

/* ---------------- Day inspector ---------------- */

.inspector {
  border-left: 4px solid var(--trace-red);
  background: var(--trace-red-tint);
}

.inspector-header {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0 0 10px;
}

.inspector h3 {
  font-family: var(--font-display);
  margin: 0;
  font-size: 19px;
  flex: 1;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
}

.inspector-title-holiday {
  font-family: var(--font-ui);
  font-size: 12px;
  font-weight: 700;
  color: var(--trace-red-deep);
  text-transform: uppercase;
  letter-spacing: 0.4px;
  white-space: nowrap;
}

.inspector-day-nav {
  flex-shrink: 0;
  width: 26px;
  height: 26px;
  border: 1.5px solid var(--rule);
  background: #fffdfb;
  color: var(--ink-soft);
  font-size: 13px;
  font-weight: 700;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
  cursor: pointer;
  transition: border-color 0.12s ease, color 0.12s ease;
}

.inspector-day-nav:hover:not(:disabled) {
  border-color: var(--trace-red);
  color: var(--trace-red-deep);
}

.inspector-day-nav:disabled {
  opacity: 0.35;
  cursor: default;
}

.inspector .empty-note {
  color: var(--ink-soft);
  font-size: 13.5px;
}

.inspector-section {
  font-family: var(--font-ui);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--trace-red-deep);
  margin: 16px 0 4px;
  padding-top: 10px;
  border-top: 1px solid var(--rule);
}

#inspector-body > .inspector-section:first-child {
  margin-top: 0;
  padding-top: 0;
  border-top: none;
}

.inspector-column > .inspector-section:first-child {
  margin-top: 0;
  padding-top: 0;
  border-top: none;
}

.inspector-row {
  display: flex;
  gap: 10px;
  align-items: baseline;
  font-size: 13.5px;
  padding: 5px 0;
  border-bottom: 1px dashed var(--rule);
}

.inspector-row:last-child {
  border-bottom: none;
}

/* The last row of any section (per renderInspector()/buildSections()'s own sectionRows array, not
   just the panel's literal last DOM child) never needs its own dashed border-bottom -- the next
   section's heading (or nothing) already draws its own solid border-top, so the plain default
   would just double that line. :last-child alone can't catch this since sections render as flat
   siblings sharing one parent (#inspector-body), so every section's own last row needs the same
   override individually. */
.inspector-row.inspector-row-section-end {
  border-bottom: none;
}

/* Sets the Lecture row apart like a small heading rather than a plain data row -- a solid rule
   above it (vs. the plain dashed row separator) at the same weight as a section heading's own
   border-top (.inspector-section), plus a matching red heading-weight label. (Its own
   border-bottom is already handled by .inspector-row-section-end above -- Lecture's section
   always holds exactly this one row.) */
.inspector-row.inspector-row-lecture {
  border-top: 1px solid var(--rule);
  margin-top: 4px;
}

.inspector-row.inspector-row-lecture .label {
  color: var(--trace-red-deep);
}

/* A meeting row's clickable "(Teams)" suffix -- plain inline link, not the pill-styled
   .source-link (too heavy for text embedded mid-row). */
.inspector-meeting-link {
  color: var(--trace-red-deep);
  text-decoration: underline;
}

.inspector-row .label {
  font-weight: 700;
  min-width: 110px;
  color: var(--ink-soft);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.8px;
}

.inspector-columns {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
  align-items: start;
}

/* ---------------- Two column section ---------------- */

.two-col {
  display: grid;
  grid-template-columns: 1.35fr 1fr;
  gap: 20px;
  align-items: start;
}

@media (max-width: 900px) {
  .two-col {
    grid-template-columns: 1fr;
  }

  /* Single-column stacked layout puts the sidebar below the (now equally full-width) list --
     nothing left for it to stay visible "over", so sticky would just awkwardly pin it mid-scroll
     for no benefit. Let it flow normally instead. */
  .plan-sidebar {
    position: static;
    /* Per explicit user request, the calendar+tally sidebar should render *above* the Assign
       Nights list on mobile, not below it -- order only changes visual position within the grid
       (.plan-main-layout is still display:grid at this width), not DOM order, so nothing about
       tab order or the desktop layout (unaffected -- this whole block is already scoped to
       max-width:900px) changes. */
    order: -1;
  }
}

.card .card-title {
  font-family: var(--font-display);
  font-size: 20px;
  margin: 0 0 4px;
  display: block;
}

.card .card-note {
  font-size: 12.5px;
  color: var(--ink-soft);
  margin: 0 0 16px;
}

/* ---------------- Collapsible cards (Call Tallies / Discrepancies) ---------------- */

.collapsible {
  padding-top: 0;
  padding-bottom: 0;
}

.collapsible[open] {
  padding-bottom: 24px;
}

.collapsible > summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding: 20px 0;
  margin: 0 -22px;
  padding-left: 22px;
  padding-right: 22px;
}

.collapsible > summary::-webkit-details-marker {
  display: none;
}

.collapsible > summary .card-title {
  margin: 0;
}

.collapsible[open] > summary {
  border-bottom: 1px dashed var(--rule);
  margin-bottom: 4px;
}

.toggle-badge {
  flex-shrink: 0;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: var(--trace-red-deep);
  border: 1.5px solid var(--rule);
  border-radius: 999px;
  padding: 4px 12px;
}

.toggle-badge::after {
  content: "Show";
}

.collapsible[open] .toggle-badge::after {
  content: "Hide";
}

.collapsible > summary:hover .toggle-badge {
  border-color: var(--trace-red);
}

.collapsible > .card-note,
.collapsible > table,
.collapsible > .discrepancy-list {
  margin-top: 14px;
}

/* ---------------- Tallies table ---------------- */

table.tallies {
  width: 100%;
  border-collapse: collapse;
  font-family: var(--font-mono);
  font-size: 13px;
}

table.tallies th, table.tallies td {
  padding: 8px 8px;
  text-align: right;
  border-bottom: 1px solid var(--rule);
  /* Cells that append a "(+N so far)" hint (see call_planner.js) vary in text length row to
     row -- without nowrap, a longer hint wraps onto a second line while shorter rows stay on
     one, so row heights differ and the table's horizontal rules visibly stop lining up. */
  white-space: nowrap;
}

table.tallies th:first-child, table.tallies td:first-child {
  text-align: left;
}

table.tallies th {
  font-family: var(--font-ui);
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.7px;
  color: var(--ink-faint);
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
}

table.tallies th:hover {
  color: var(--trace-red-deep);
}

table.tallies th.sorted::after {
  content: " " attr(data-dir);
  font-size: 9px;
}

table.tallies td.name-cell {
  display: flex;
  flex-direction: column;
  gap: 1px;
}

table.tallies td.name-cell .full {
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: 13px;
  color: var(--ink);
}

table.tallies td.name-cell .initials {
  font-size: 10.5px;
  color: var(--ink-faint);
}

table.tallies tbody tr:hover {
  background: #fdf6f1;
}

/* ---------------- Discrepancies ---------------- */

/* Combines the Range controls and the type filter onto one row where there's room, now that
   Discrepancies is a full-width card (Call Tallies used to share this row's width via .two-col --
   split out to its own page, see call_tallies.html) rather than squeezed into half the page. */
.discrepancy-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 8px 20px;
  margin-bottom: 10px;
}

.discrepancy-toolbar .discrepancy-filter-row {
  margin-bottom: 0;
}

.discrepancy-filter-row {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 10px;
}

.discrepancy-filter-row label {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.6px;
  color: var(--ink-soft);
}

.discrepancy-filter-row select {
  font-family: var(--font-ui);
  font-size: 12.5px;
  padding: 4px 8px;
  border: 1.5px solid var(--rule);
  border-radius: 6px;
  background: #fffdfb;
  color: var(--ink);
}

.discrepancy-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  max-height: 420px;
  overflow-y: auto;
  padding-right: 4px;
}

/* Now that Discrepancies is a full-width card (see .discrepancy-toolbar above), a single stretched
   column of short 2-line items reads as sparse -- lay them out as a wrapping grid instead so the
   list actually fills the extra width on a wide screen. minmax(0, ...) on the item track, not a
   bare px, for the same reason .cal-grid needed it (see the mobile-layout note below): a long
   unwrapped line inside an item shouldn't be able to force a column wider than the grid allows. */
.discrepancy-list-wide {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  grid-auto-rows: min-content;
  align-items: start;
}

@media (max-width: 700px) {
  .discrepancy-list-wide {
    grid-template-columns: minmax(0, 1fr);
  }
}

.discrepancy-item {
  border: 1px solid #f0d3ab;
  background: var(--alert-tint);
  border-radius: 8px;
  padding: 9px 12px;
  font-size: 12.5px;
  cursor: pointer;
  transition: box-shadow 0.12s ease, border-color 0.12s ease;
}

.discrepancy-item:hover {
  border-color: var(--alert);
  box-shadow: 0 0 0 1px var(--alert);
}

.discrepancy-item .d-head {
  display: flex;
  justify-content: space-between;
  font-family: var(--font-mono);
  font-weight: 700;
  color: var(--alert);
  margin-bottom: 3px;
}

/* ---------------- Call planner ---------------- */

.plan-range-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 12px;
}

.plan-range-row label {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.6px;
  color: var(--ink-soft);
  display: flex;
  align-items: center;
  gap: 6px;
}

.plan-range-row input[type="date"] {
  font-family: var(--font-ui);
  font-size: 12.5px;
  padding: 4px 8px;
  border: 1.5px solid var(--rule);
  border-radius: 6px;
  background: #fffdfb;
  color: var(--ink);
}

/* Quick 3/6-month range shortcuts on discrepancy_review.html's toolbar -- a small gap between the
   two preset buttons, matching the row's own 12px gap to its left-hand neighbor for free (it's
   just another flex item in .plan-range-row). */
.review-range-presets {
  display: flex;
  gap: 6px;
}

.plan-range-note {
  font-size: 11.5px;
  color: var(--ink-faint);
}

.plan-warn-sample {
  color: var(--alert);
}

/* Tall enough to roughly match the sidebar's total height when both the Calendar and Live Tally
   cards are open (per explicit user request) -- .plan-main-layout's align-items:start means the
   two columns don't natively stretch to match each other (see .plan-sidebar's own comment on why
   that's required for its sticky positioning to work), so this is a plain static estimate, not a
   guaranteed exact match: the sidebar's real height still varies with the visible month's row
   count and how many years the plan's tally spans. Close enough in the common case to read as
   lined up rather than a hard constraint. */
.plan-table-wrap {
  max-height: 760px;
  overflow-y: auto;
}

table.plan-table {
  width: 100%;
  border-collapse: collapse;
  font-family: var(--font-mono);
  font-size: 12.5px;
}

table.plan-table th, table.plan-table td {
  padding: 6px 8px;
  text-align: left;
  border-bottom: 1px solid var(--rule);
  vertical-align: middle;
}

table.plan-table th {
  font-family: var(--font-ui);
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.7px;
  color: var(--ink-faint);
  position: sticky;
  top: 0;
  background: #fffdfb;
}

.plan-row-weekend {
  background: var(--paper-line);
  background: color-mix(in srgb, var(--paper-line) 35%, transparent);
}

.plan-notes-cell {
  color: var(--ink-soft);
  font-size: 11.5px;
}

.plan-assigned-cell {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
}

.plan-assigned-top {
  display: flex;
  align-items: center;
  gap: 6px;
}

.plan-chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}

.plan-provider-chip {
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: 10.5px;
  letter-spacing: 0.2px;
  padding: 2px 8px;
  border-radius: 999px;
  border: 1.5px solid var(--rule);
  background: #fffdfb;
  color: var(--ink-soft);
  cursor: pointer;
  transition: border-color 0.12s ease;
}

.plan-provider-chip:hover {
  border-color: var(--trace-red);
}

/* Selected reuses the same solid-red "on call" look as .cell-oncall elsewhere on the site, so a
   chosen chip reads the same way a real on-call badge does. Warning-but-not-selected mirrors
   .plan-cal-chip-warning's outlined orange. A chip that's both selected *and* flagged (the
   currently-assigned person is the one with the conflict) combines the two -- solid fill so it
   still reads as "chosen", recolored to the alert orange so the conflict stays visible without
   needing to hover. */
.plan-provider-chip-selected {
  background: var(--trace-red);
  border-color: var(--trace-red);
  color: #fff8f6;
}

.plan-provider-chip-warning {
  border-color: var(--alert);
  color: var(--alert);
  background: var(--alert-tint);
}

.plan-provider-chip-selected.plan-provider-chip-warning {
  background: var(--alert);
  border-color: var(--alert);
  color: #fff;
}

/* Vacation is a hard unavailability, not a soft rule conflict like the warning states above --
   grayed out + struck through rather than orange, and takes priority over the warning styling
   (buildProviderChip() in call_planner.js only adds -warning when -unavailable isn't already
   set) even though the underlying warningFor() message is the same "away" text either way. */
.plan-provider-chip-unavailable {
  border-color: var(--rule);
  color: var(--ink-faint);
  background: #f2efe9;
  text-decoration: line-through;
  cursor: not-allowed;
}

/* Disabled (see call_planner.js's buildProviderChip()) so it never picks up the plain chip's red
   hover affordance -- there's nothing to click through to anymore. */
.plan-provider-chip-unavailable:hover {
  border-color: var(--rule);
}

.plan-provider-chip-selected.plan-provider-chip-unavailable {
  background: var(--ink-faint);
  border-color: var(--ink-faint);
  color: #fff;
  text-decoration: line-through;
}

.plan-input {
  width: 48px;
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: 12.5px;
  text-transform: uppercase;
  padding: 3px 6px;
  border: 1.5px solid var(--rule);
  border-radius: 6px;
  background: #fffdfb;
  color: var(--ink);
}

.plan-input:focus {
  outline: none;
  border-color: var(--trace-red);
}

.plan-input.plan-input-warning {
  border-color: var(--trace-red);
  box-shadow: 0 0 0 1px var(--trace-red);
}

.plan-warning {
  color: var(--alert);
  font-size: 13px;
  cursor: help;
  /* Fixed width regardless of empty/⚠ content -- without this, a cell gaining or losing its
     warning glyph shifts every other cell's horizontal position in the row, which is the same
     kind of misalignment the inline warning text caused in the first place, just smaller. */
  display: inline-block;
  width: 14px;
  text-align: center;
}

.plan-locked {
  font-weight: 700;
  color: var(--ink-faint);
  cursor: default;
}

/* Each numeric tally cell is [.plan-count][.plan-existing] rather than one plain right-aligned
   string, specifically so the plan's own count lines up in the same screen column on every row
   regardless of how wide the "(+N)" hint next to it happens to be (a real bug reported live: a
   row with a double-digit hint like "(+34)" visibly dragged its own single-digit count out of
   line with a row whose hint was narrower, e.g. "(+2)", since text-align:right on one combined
   string anchors the *end* of the whole string, not the count itself). Both spans get a fixed
   min-width and are laid out via flex on the td (see table.tallies td.name-cell ~ sibling rule
   below) so each row's count sits at a constant x-position independent of the other row's hint
   widths, and .plan-existing reserves its slot even when empty (no hint that cell) so a bare
   count doesn't shift right to fill the missing space either. */
.plan-count {
  display: inline-block;
  min-width: 16px;
  text-align: right;
}

.plan-existing {
  display: inline-block;
  min-width: 38px;
  text-align: left;
  color: var(--ink-faint);
  font-weight: 400;
}

.plan-export-row {
  display: flex;
  align-items: center;
  gap: 10px;
}

.plan-export-note {
  font-size: 11.5px;
  color: var(--ink-faint);
}

.plan-json-details {
  margin-top: 12px;
}

.plan-json-details summary {
  font-size: 11.5px;
  color: var(--ink-soft);
  cursor: pointer;
}

.plan-json-textarea {
  width: 100%;
  margin-top: 8px;
  font-family: var(--font-mono);
  font-size: 11px;
  padding: 8px;
  border: 1px solid var(--rule);
  border-radius: 6px;
  background: #fffdfb;
  color: var(--ink-soft);
  resize: vertical;
}

.plan-tally-year + .plan-tally-year {
  margin-top: 22px;
}

.plan-tally-year-heading {
  font-family: var(--font-ui);
  font-size: 13px;
  font-weight: 700;
  color: var(--ink-soft);
  margin: 0 0 6px;
}

/* Tightened rows for the planner's tally table specifically, per explicit user request ("mobile
   ... takes up most of the screen") -- scoped to #plan-tallies-container so index.html's Call
   Tallies table (same "tallies" class, deliberately left alone) is unaffected either width. */
#plan-tallies-container table.tallies th,
#plan-tallies-container table.tallies td {
  padding: 4px 6px;
}

#plan-tallies-container table.tallies {
  font-size: 12px;
}

/* One line ("Phillip Habib (PH)") instead of the main site's stacked full-name/initials layout --
   the selector needs to out-specificity table.tallies td.name-cell's flex-column rule further up
   this file (a bare .plan-tally-name-cell class alone is specificity (0,1,0), weaker than that
   rule's (0,2,2) -- confirmed while building this, an easy trap since the element carries both
   classes), hence the fully-qualified selector here rather than the shorter one that seemed like
   it should work. */
#plan-tallies-container table.tallies td.name-cell.plan-tally-name-cell {
  display: block;
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: 12px;
  color: var(--ink);
  white-space: nowrap;
}

/* Numeric cells (.plan-count + .plan-existing, see call_planner.js): text-align:right on the td
   flushes the [.plan-count][.plan-existing] inline-block pair against the column's right edge
   (matching the right-aligned header above it). Deliberately NOT display:flex on the td itself --
   that was tried first and is a real bug, not just a style choice: setting display:flex on a real
   <td> pulls it out of the table layout algorithm entirely (it stops being a table-cell box), so
   every cell in the row collapses onto the same rect instead of sitting in its own column --
   confirmed live via getBoundingClientRect(), all 4 cells in a row reporting identical
   left/right/width. Each span's own fixed min-width (set above) is what keeps .plan-count's digit
   at a constant x-position row to row, same as intended -- just achieved by ordinary inline-block
   flow plus text-align, not flex. */
#plan-tallies-container table.tallies td:not(.name-cell) {
  text-align: right;
}

.discrepancy-item .d-body {
  color: var(--ink-soft);
}

.discrepancy-item .d-body b {
  color: var(--ink);
}

/* One row per open role's suggested substitute (see computeGapSuggestions() in app.js) --
   cursor:help matches the row's title tooltip (the full evaluated-candidates breakdown), and the
   top margin only applies between rows so a single-gap day isn't pushed away from the date/kind
   header above it. */
.discrepancy-item .d-gap-row {
  cursor: help;
}

.discrepancy-item .d-gap-row + .d-gap-row {
  margin-top: 3px;
}

.no-discrepancies {
  color: var(--ink-soft);
  font-size: 13.5px;
  padding: 8px 0;
}

/* ---------------- Legend ---------------- */

.legend {
  display: flex;
  flex-wrap: wrap;
  gap: 18px;
  font-size: 12.5px;
  color: var(--ink-soft);
}

.legend-item {
  display: flex;
  align-items: center;
  gap: 7px;
}

.legend-swatch {
  width: 16px;
  height: 16px;
  border-radius: 4px;
  flex-shrink: 0;
}

/* ---------------- Footer ---------------- */

.site-footer {
  margin-top: 8px;
  text-align: center;
  font-family: var(--font-mono);
  font-size: 11.5px;
  color: var(--ink-faint);
  letter-spacing: 0.3px;
}

.footer-link-row {
  margin-top: 14px;
  text-align: center;
  font-family: var(--font-mono);
  font-size: 12.5px;
}

.footer-link-row a {
  color: var(--trace-red-deep);
  text-decoration: none;
}

.footer-link-row a:hover {
  text-decoration: underline;
}

/* ---------------- Schedule template page ---------------- */

table.template-table {
  width: 100%;
  border-collapse: collapse;
  font-family: var(--font-mono);
  font-size: 13px;
  margin-bottom: 4px;
}

table.template-table th, table.template-table td {
  padding: 8px 10px;
  text-align: left;
  border-bottom: 1px solid var(--rule);
  vertical-align: top;
}

table.template-table th {
  font-family: var(--font-ui);
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.7px;
  color: var(--ink-faint);
  white-space: nowrap;
}

table.template-table td.provider-cell {
  font-family: var(--font-ui);
  font-weight: 700;
  white-space: nowrap;
}

table.template-table td.provider-cell .initials {
  font-weight: 400;
  color: var(--ink-faint);
}

table.template-table .half-day-cell-inner {
  display: flex;
  flex-direction: column;
  gap: 4px;
  white-space: nowrap;
}

table.template-table .half-day-location {
  font-family: var(--font-ui);
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-soft);
}

table.template-table .duties-cell {
  white-space: nowrap;
}

table.template-table .duties-cell .badge {
  margin-right: 4px;
}

/* Fallback shown in place of a duty badge when a half-day has none -- the raw time parsed out of
   ScheduleTemplate.txt's description (see halfDayTimeFallback() in template.js). Muted/italic so
   it still reads as clearly secondary to an actual duty badge, not competing with it. */
table.template-table .duties-time {
  color: var(--ink-faint);
  font-style: italic;
  font-size: 12px;
}

table.template-table td.raw-cell {
  color: var(--ink-soft);
  font-family: var(--font-ui);
  font-size: 12.5px;
}

table.template-table tbody tr:hover {
  background: #fdf6f1;
}

/* ---------------- Week-at-a-glance summary table (template.html) ---------------- */

/* table-layout:fixed (not the per-day cards' default auto) is the whole responsive strategy here:
   with preset proportional column widths, a cell's chips wrap onto multiple lines instead of
   forcing the table wider than its container, so this needs no stacked-card mobile treatment or
   scroll wrapper the way table.template-table below does. */
table.template-summary-table {
  width: 100%;
  table-layout: fixed;
  border-collapse: collapse;
  font-family: var(--font-mono);
  font-size: 13px;
  margin-bottom: 4px;
}

table.template-summary-table th,
table.template-summary-table td {
  padding: 8px 8px;
  border-bottom: 1px solid var(--rule);
  vertical-align: top;
}

table.template-summary-table th:first-child,
table.template-summary-table td:first-child {
  width: 78px;
}

table.template-summary-table thead th {
  font-family: var(--font-ui);
  font-size: 10.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.7px;
  color: var(--ink-faint);
  text-align: left;
}

table.template-summary-table tbody th {
  font-family: var(--font-ui);
  font-size: 12px;
  font-weight: 700;
  color: var(--ink-soft);
  text-align: left;
  white-space: nowrap;
}

.summary-chip-group {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 6px;
}

.summary-empty {
  color: var(--ink-faint);
}

table.template-summary-table tbody tr:hover {
  background: #fdf6f1;
}

/* ---------------- holiday_history.html ---------------- */

table.holiday-table {
  width: 100%;
  table-layout: fixed;
  border-collapse: collapse;
  font-family: var(--font-mono);
  font-size: 13px;
  margin-bottom: 4px;
}

/* Fixed per-column widths (rather than the default table-layout:auto, which sizes each column to
   that table's own longest content) so the Date/Day/On Call columns line up at the same x-position
   across every year's separately-rendered table -- otherwise a year containing a long name like
   "Independence Day (2 days)" pushes its own Holiday column wider than a year without one. */
table.holiday-table th:nth-child(1), table.holiday-table td:nth-child(1) { width: 34%; }
table.holiday-table th:nth-child(2), table.holiday-table td:nth-child(2) { width: 22%; }
table.holiday-table th:nth-child(3), table.holiday-table td:nth-child(3) { width: 18%; }
table.holiday-table th:nth-child(4), table.holiday-table td:nth-child(4) { width: 26%; }

table.holiday-table th, table.holiday-table td {
  padding: 7px 10px;
  text-align: left;
  border-bottom: 1px solid var(--rule);
  vertical-align: top;
}

table.holiday-table th {
  font-family: var(--font-ui);
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.7px;
  color: var(--ink-faint);
  white-space: nowrap;
}

table.holiday-table td.holiday-name-cell {
  font-family: var(--font-ui);
  font-weight: 700;
}

.holiday-observed-note {
  font-family: var(--font-ui);
  font-size: 10px;
  color: var(--ink-faint);
  text-transform: uppercase;
  letter-spacing: 0.4px;
}

.holiday-oncall-chip {
  margin-right: 4px;
}

.holiday-no-record {
  color: var(--ink-faint);
  font-style: italic;
  font-size: 12px;
}

table.holiday-table tbody tr:hover {
  background: #fdf6f1;
}

/* ---------------- Holiday grid table (holiday_history.html) ---------------- */

/* Ten columns (Year + 9 holidays) comfortably fit one line at desktop widths, so table-layout:fixed
   at 100% width is enough there with no scrolling. But squeezed to a 375px viewport with no floor,
   a word like "Independence" word-breaks one or two letters per line -- unreadable. min-width plus
   a horizontal-scroll wrapper gives each column enough room for its header to wrap onto a clean
   *second* line (not shatter across six), while desktop -- already wider than the min-width --
   never triggers the scrollbar at all. */
.holiday-grid-wrap {
  overflow-x: auto;
}

table.holiday-grid-table {
  width: 100%;
  min-width: 800px;
  table-layout: fixed;
  border-collapse: collapse;
  font-family: var(--font-mono);
  font-size: 13px;
  margin-bottom: 4px;
}

table.holiday-grid-table th,
table.holiday-grid-table td {
  padding: 8px 6px;
  border-bottom: 1px solid var(--rule);
  vertical-align: top;
  text-align: left;
  word-break: break-word;
}

table.holiday-grid-table th:first-child,
table.holiday-grid-table td:first-child {
  width: 48px;
}

table.holiday-grid-table thead th {
  font-family: var(--font-ui);
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.3px;
  line-height: 1.3;
  color: var(--ink-faint);
}

table.holiday-grid-table tbody th {
  font-family: var(--font-ui);
  font-size: 13px;
  font-weight: 700;
  color: var(--ink-soft);
}

table.holiday-grid-table tbody tr:hover {
  background: #fdf6f1;
}

.footer-sources {
  margin-top: 3px;
  font-size: 10px;
  opacity: 0.7;
}

/* ---------------- Call planner: sticky sidebar layout ---------------- */

/* Assign Nights (the potentially-long list) is the tall left column; the calendar+tally sidebar
   sticks in place as that list is scrolled, per explicit user request ("calendars and tallies
   show up at all times so we can edit the list and see results") -- align-self:start is required
   for position:sticky to work on a grid item (without it the item stretches to the row's full
   height, which is already the tall left column's height, leaving nothing to "stick" within). */
.plan-main-layout {
  align-items: start;
}

.plan-sidebar {
  display: flex;
  flex-direction: column;
  gap: 20px;
  position: sticky;
  top: 20px;
  align-self: start;
}

/* .card's own margin-bottom (24px) was stacking with the flex gap above (20px) between the
   Calendar/Live Tally cards -- 44px of dead space where 20px was intended. gap alone is enough
   inside a flex container. */
.plan-sidebar > .card {
  margin-bottom: 0;
}

/* A closed Calendar/Live Tally card should read as a compact tab, not a full card's worth of
   whitespace -- most visible on mobile, where call_planner.js collapses both by default (see its
   DOMContentLoaded handler) so Assign Nights stays reachable without scrolling past them first.
   Tightens just the closed-state summary padding; .collapsible[open] (defined above) is untouched,
   so an expanded card still gets its usual breathing room. */
.plan-sidebar .collapsible:not([open]) > summary {
  padding-top: 10px;
  padding-bottom: 10px;
}

/* Per explicit user follow-up request, the Calendar and Live Tally cards each collapse
   independently now (superseding the single combined "Calendar & Tally" toggle this used to be --
   the complaint had been the sidebar's total footprint on mobile, but the fix for that turned out
   to want per-card control instead) -- both are plain `.collapsible` cards reusing the exact
   Show/Hide summary/toggle-badge pattern already defined above for the main site's Call
   Tallies/Discrepancies cards, no new CSS needed for the toggle mechanics themselves. Both default
   `open` so nothing changes until a user collapses one. Purely presentational: native <details>
   just toggles display on non-summary children, so renderPlanCalendar()/renderTallies() (which
   populate #plan-cal-grid/#plan-tallies-container regardless of open/closed state) need no
   changes. */
.plan-cal-card {
  /* No top padding (unlike a plain .card) -- .collapsible already zeroes it and expects its own
     summary's padding to control that spacing instead; a nonzero value here would win over
     .collapsible's via source order (same specificity, this rule comes later) and double up the
     gap above the "Calendar" title. Left/right stay reduced from a plain .card's padding, compact
     for this narrow sidebar column. */
  padding: 0 16px;
}

/* Bottom padding only when open -- gated the same way .collapsible[open] gates its own
   padding-bottom, so a closed card doesn't carry 14px of dead space under the summary row. */
.plan-cal-card[open] {
  padding-bottom: 14px;
}

/* Caps the sidebar's other main height contributor (a multi-year plan renders one full
   table per year -- see computePlanTalliesByYear() in call_planner.js) with its own internal
   scroll, matching .discrepancy-list's pattern above. Without this the sidebar's natural height
   can exceed the list's, which leaves position:sticky above nothing to actually stick within --
   keeping both columns roughly viewport-height-sized is what makes "calendar and tally visible
   at all times" hold in practice, not the sticky positioning alone. */
#plan-tallies-container {
  max-height: 360px;
  overflow-y: auto;
  padding-right: 4px;
}

/* ---------------- Call planner calendar preview ---------------- */

.plan-cal-nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 10px;
}

.plan-cal-nav h3 {
  font-family: var(--font-display);
  font-size: 14.5px;
  margin: 0;
  text-align: center;
}

.plan-cal-nav .nav-btn {
  padding: 4px 10px;
}

/* Compact variant of the main calendar's cells -- scoped to #plan-cal-grid specifically (not the
   shared .cal-grid/.cal-cell rules above) so the main site's real calendar is completely
   unaffected. Sitting in the sticky sidebar's narrower column, this needs to be short enough that
   a full month plus the Live Tally card underneath it can both fit within a typical viewport. */
#plan-cal-grid.cal-grid {
  gap: 3px;
}

#plan-cal-grid .cal-weekday {
  font-size: 8.5px;
  padding-bottom: 2px;
}

#plan-cal-grid .cal-cell {
  min-height: 40px;
  padding: 2px 3px;
  gap: 1px;
}

#plan-cal-grid .cell-date {
  font-size: 9.5px;
}

/* Solid chip for real Google Calendar data reuses .cell-oncall as-is (see the main calendar's
   rules above) -- this outlined variant is the plan-draft equivalent, deliberately less "final"
   looking (transparent fill, dashed-feeling outline via a plain border) so the two are never
   confused at a glance. */
.plan-cal-chip {
  display: inline-flex;
  align-self: flex-start;
  align-items: center;
  border: 1.5px solid var(--trace-red);
  color: var(--trace-red-deep);
  background: #fff8f6;
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: 12px;
  padding: 1px 7px;
  border-radius: 5px;
  letter-spacing: 0.3px;
}

.plan-cal-chip-warning {
  border-color: var(--alert);
  color: var(--alert);
  background: var(--alert-tint);
}

#plan-cal-grid .cell-oncall,
#plan-cal-grid .plan-cal-chip {
  font-size: 9px;
  padding: 0 3px;
  letter-spacing: 0;
}

/* Emoji-only (no label text, unlike the main calendar's .cell-holiday) -- this preview is too
   compact for the full holiday name, so just the icon, sized up a bit from the 9px text badges
   above since it's carrying all the meaning on its own here. */
#plan-cal-grid .plan-cal-holiday {
  font-size: 12px;
  max-width: none;
}

.plan-cal-clickable {
  cursor: pointer;
}

@media (max-width: 700px) {
  .wrap { padding: 16px 12px 40px; }

  .site-header { padding: 20px 16px 16px; }
  .header-content { margin-top: 38px; gap: 12px; }
  .site-title { font-size: 22px; }
  .site-subtitle { font-size: 12px; }
  .source-links { gap: 6px; }
  .source-link { font-size: 11px; padding: 4px 9px; }

  .card { padding: 14px 14px 18px; }

  .filter-row { gap: 6px; margin-bottom: 16px; }
  .chip { font-size: 11.5px; padding: 5px 10px; }

  .cal-nav h2 { min-width: 0; flex: 1 1 100%; order: -1; font-size: 18px; text-align: center; }
  .cal-nav-controls { flex: 1 1 100%; justify-content: center; }

  .plan-cal-nav h3 { min-width: 0; flex: 1 1 100%; order: -1; font-size: 16px; }
  .plan-cal-chip { font-size: 10px; padding: 1px 5px; }

  .cal-grid { gap: 3px; }
  .cal-weekday { font-size: 8.5px; }
  .cal-cell {
    min-height: 74px;
    padding: 3px;
    gap: 2px;
    /* Last-resort clip for the rare single badge/label whose text still can't wrap narrow
       enough (e.g. a combo team badge) -- the minmax(0,1fr) grid fix above keeps this from ever
       widening the page itself; this just keeps an individual cell's own overflow contained. */
    overflow: hidden;
  }
  .cell-date { font-size: 10.5px; }
  .cell-holiday { font-size: 7.5px; max-width: 55%; }
  .cell-oncall { font-size: 10px; padding: 1px 5px; }
  .cell-ic { font-size: 9px; }
  .badge { font-size: 8.5px; padding: 1px 4px; }
  .cell-deviation-flag, .cell-unaccounted-flag, .cell-conflict-flag { font-size: 8px; }
  .cal-bar { font-size: 8px; padding: 2px 5px; }

  .inspector-columns { grid-template-columns: 1fr; }
  .inspector-row { flex-wrap: wrap; }
  .inspector-row .label { min-width: 0; }

  table.tallies { font-size: 11.5px; }
  table.tallies th, table.tallies td { padding: 6px 5px; }

  /* table.template-table (template.html) uses the browser's default table-layout:auto, which
     grows the table wider than its container to avoid wrapping the long Description sentences --
     harmless on desktop, but on a narrow screen it pushed the table (and silently, via the
     overflow-x:hidden safety net above) the Description column entirely out of view rather than
     wrapping. Below this breakpoint the table becomes a stacked list of labeled rows instead
     (the standard responsive-table pattern: thead hidden, each td labeled via a data-label
     attribute set in template.js and shown through ::before), which reflows within the viewport
     regardless of content length instead of relying on horizontal space that isn't there. */
  table.template-table thead { display: none; }
  table.template-table, table.template-table tbody, table.template-table tr, table.template-table td {
    display: block;
    width: 100%;
  }
  table.template-table tr {
    margin-bottom: 10px;
    border: 1px solid var(--rule);
    border-radius: 8px;
    padding: 8px 10px;
  }
  table.template-table tr:last-child { margin-bottom: 0; }
  table.template-table td {
    border-bottom: none;
    padding: 5px 0;
  }
  table.template-table td.provider-cell {
    font-size: 14px;
    border-bottom: 1px dashed var(--rule);
    padding-bottom: 6px;
    margin-bottom: 2px;
  }
  table.template-table td[data-label]::before {
    content: attr(data-label);
    display: block;
    font-family: var(--font-ui);
    font-size: 9.5px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.6px;
    color: var(--ink-faint);
    margin-bottom: 2px;
  }

  /* table.holiday-table (holiday_history.html) hits the same table-layout:auto overflow this file
     documents above for table.template-table -- confirmed live at 375px, the On Call column ran
     off the right edge and was silently clipped by the site-wide overflow-x:hidden safety net.
     Same fix, same stacked-card pattern (thead hidden, each td labeled via data-label, shown via
     ::before). */
  table.holiday-table thead { display: none; }
  table.holiday-table, table.holiday-table tbody, table.holiday-table tr, table.holiday-table td {
    display: block;
    width: 100%;
  }
  table.holiday-table tr {
    margin-bottom: 10px;
    border: 1px solid var(--rule);
    border-radius: 8px;
    padding: 8px 10px;
  }
  table.holiday-table tr:last-child { margin-bottom: 0; }
  table.holiday-table td {
    border-bottom: none;
    padding: 5px 0;
  }
  table.holiday-table td.holiday-name-cell {
    font-size: 14px;
    border-bottom: 1px dashed var(--rule);
    padding-bottom: 6px;
    margin-bottom: 2px;
  }
  table.holiday-table td[data-label]::before {
    content: attr(data-label);
    display: block;
    font-family: var(--font-ui);
    font-size: 9.5px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.6px;
    color: var(--ink-faint);
    margin-bottom: 2px;
  }

  /* table.sheet-table (spreadsheet_view.html) has 14 columns including several long free-text
     ones (Schedule Adjustment, Verification Notes) -- same overflow pitfall and same stacked-card
     fix as table.template-table/table.holiday-table above. The .sheet-table-scroll wrapper's
     overflow-x:auto is the desktop-only fallback; below this breakpoint the table itself switches
     to the stacked layout so there's no horizontal scroll to fight on a phone. */
  table.sheet-table thead { display: none; }
  table.sheet-table, table.sheet-table tbody, table.sheet-table tr, table.sheet-table td {
    display: block;
    width: 100%;
    min-width: 0;
  }
  table.sheet-table tr {
    margin-bottom: 10px;
    border: 1px solid var(--rule);
    border-radius: 8px;
    padding: 8px 10px;
  }
  table.sheet-table tr:last-child { margin-bottom: 0; }
  table.sheet-table td {
    border-bottom: none;
    padding: 5px 0;
  }
  table.sheet-table td.provider-cell {
    font-size: 14px;
    border-bottom: 1px dashed var(--rule);
    padding-bottom: 6px;
    margin-bottom: 2px;
  }
  table.sheet-table td[data-label]::before {
    content: attr(data-label);
    display: block;
    font-family: var(--font-ui);
    font-size: 9.5px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.6px;
    color: var(--ink-faint);
    margin-bottom: 2px;
  }
  table.sheet-table td:empty::after {
    content: "—";
    color: var(--ink-faint);
  }

  /* plan-table has the same long-free-text-column pitfall documented above for
     table.template-table (its Notes column can hold a holiday name + an "away: ..." list), but a
     plain stacked mini-card (one full-width block per column, same as template-table) made each
     night very tall here specifically -- DATE/DAY/NOTES/ASSIGNED each got their own labeled block,
     and ASSIGNED alone held the input plus up to three chip rows. Per explicit user request, each
     night is instead a compact two-line card: line 1 is Date + Day + the text input (or the
     locked/real badge, if this night already has real Google Calendar data), line 2 is Notes
     followed by the provider chips. Achieved by turning `tr` into a flex row-wrap container and
     giving `td.plan-assigned-cell` `display: contents` -- that unwraps it so its own children
     (`.plan-assigned-top`, i.e. the input+warning, and `.plan-chip-rows`, the chip-row wrapper
     from call_planner.js's renderTable()) become direct flex items of `tr` in their own right,
     which lets them be given their own explicit `order` alongside the Date/Day/Notes `<td>`s
     instead of staying trapped inside one block under the Assigned column. */
  .plan-table-wrap { max-height: none; overflow-y: visible; }
  table.plan-table thead { display: none; }
  table.plan-table, table.plan-table tbody {
    display: block;
    width: 100%;
  }
  table.plan-table tr {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    column-gap: 8px;
    row-gap: 4px;
    margin-bottom: 10px;
    border: 1px solid var(--rule);
    border-radius: 8px;
    padding: 8px 10px;
  }
  table.plan-table tr:last-child { margin-bottom: 0; }
  table.plan-table td {
    display: block;
    border-bottom: none;
    padding: 0;
  }
  table.plan-table td[data-label]::before {
    content: attr(data-label);
    display: block;
    font-family: var(--font-ui);
    font-size: 9.5px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.6px;
    color: var(--ink-faint);
    margin-bottom: 2px;
  }
  /* Date/Day sit plainly on line 1 next to the input, no caption above them -- unlike Notes
     below, "2026-12-28" and "Mon" are self-explanatory without one, and a caption would push each
     onto its own line, defeating the point of a compact first line. */
  table.plan-table td[data-label="Date"]::before,
  table.plan-table td[data-label="Day"]::before {
    display: none;
  }
  table.plan-table td[data-label="Date"] { order: 1; }
  table.plan-table td[data-label="Day"] {
    order: 2;
    color: var(--ink-faint);
    font-size: 11px;
  }
  table.plan-table td.plan-assigned-cell {
    display: contents;
  }
  /* display:contents unwraps the element's box but NOT its ::before/::after pseudo-elements --
     they still get spliced into the parent as their own flex items (a real gotcha hit while
     building this), which without this rule showed a stray "ASSIGNED" caption line floating
     above Date/Day. Nothing else needs its own caption here (the input/warning/locked-badge are
     self-explanatory), so this is simplest as a hard "never generate it" rather than trying to
     order/hide the generated box after the fact. */
  table.plan-table td.plan-assigned-cell::before {
    content: none;
    display: none;
  }
  /* Both the editable case (.plan-assigned-top, the input+warning) and the locked/real case
     (.plan-locked) take the same line-1 slot, pushed to the end of the line -- a given night is
     always exactly one or the other, never both. */
  .plan-assigned-top,
  .plan-locked {
    order: 3;
    margin-left: auto;
  }
  table.plan-table td.plan-notes-cell {
    order: 4;
    flex: 1 1 100%;
  }
  .plan-chip-rows {
    order: 5;
    flex: 1 1 100%;
  }
}

/* ---------------- Discrepancy review page ---------------- */

.review-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 10px 20px;
}

.review-toolbar-controls {
  display: flex;
  align-items: center;
  gap: 10px;
}

.review-toolbar-checkbox {
  font-size: 12.5px;
  color: var(--ink-soft);
  display: flex;
  align-items: center;
  gap: 6px;
  white-space: nowrap;
}

/* Shared by the NUCS row's "No Nucs" checkbox and the missing-vacation post-call row's "No
   echos" checkbox -- both are the same small inline checkbox+label shape. */
.review-inline-checkbox-label {
  font-size: 11.5px;
  color: var(--ink-soft);
  display: inline-flex;
  align-items: center;
  gap: 4px;
  white-space: nowrap;
}

.review-count-note {
  font-size: 11.5px;
  color: var(--ink-faint);
}

.review-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.review-item {
  border: 1px solid #f0d3ab;
  background: var(--alert-tint);
  border-radius: 8px;
  padding: 8px 14px;
  font-size: 12.5px;
}

.review-head {
  display: flex;
  justify-content: space-between;
  font-family: var(--font-mono);
  font-weight: 700;
  color: var(--alert);
  margin-bottom: 3px;
}

.review-body {
  color: var(--ink-soft);
  margin-bottom: 8px;
}

.review-body b {
  color: var(--ink);
}

.review-spreadsheet-notes {
  font-size: 11.5px;
  font-style: italic;
  color: var(--ink-soft);
  margin-bottom: 8px;
}

.review-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}

.review-conflict-role {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
}

.review-substitute-input {
  width: 62px;
  font-family: var(--font-mono);
  font-size: 12.5px;
  text-transform: uppercase;
  padding: 4px 6px;
  border: 1.5px solid var(--rule);
  border-radius: 6px;
  background: #fffdfb;
  color: var(--ink);
}

/* One merged card per date (renderDateCard() in discrepancy_review.js) -- every tracked role is
   its own row, so an issue's description sits directly above the same editable field that would
   fix it instead of a separate disconnected "day roster" pane the human had to cross-reference by
   eye against a stack of issue cards above it.

   Each role gets its own small bordered box (the same #fffdfb/var(--rule)/var(--radius) language
   .card uses elsewhere on the site, just lighter), replacing a plain dashed-line separator --
   per explicit user feedback that the page read as cluttered, with no clear boundary between one
   role's content and the next. */
.review-role-row {
  padding: 8px 10px;
  border: 1px solid var(--rule);
  border-radius: 8px;
  background: #fffdfb;
  margin-bottom: 8px;
}

.review-role-row:last-child {
  margin-bottom: 0;
}

.review-role-row-head {
  font-size: 11.5px;
  font-weight: 700;
  color: var(--ink-soft);
  text-transform: uppercase;
  letter-spacing: 0.3px;
  margin-bottom: 3px;
}

/* Prefixed onto the first issue line instead of a standalone .review-role-row-head, whenever the
   role has an actual issue -- the role name and its problem type read as one compact line
   ("TEAM C ROUNDING · UNCOVERED") instead of two stacked lines. A role with no issue (an "OK" row)
   still uses the standalone header above, since there's no issue line to attach the label to. */
.review-role-label {
  font-size: 11.5px;
  font-weight: 700;
  color: var(--ink-soft);
  text-transform: uppercase;
  letter-spacing: 0.3px;
  flex-shrink: 0;
}

.review-role-label::after {
  content: "·";
  margin-left: 6px;
  color: var(--ink-faint);
  font-weight: 400;
}

.review-issue-line {
  margin: 2px 0 4px;
}

.review-issue-line.review-resolved {
  opacity: 0.8;
}

.review-issue-line-head {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 3px;
}

/* A compact action (Dismiss, Generate row, a checkbox) joining lineHead itself (see
   renderIssueLine()) sits at the end of the same line instead of dropping to its own row below --
   wraps onto its own line only if the row genuinely has no room, still right-aligned there via the
   same margin. */
.review-issue-line-head .review-actions {
  margin-left: auto;
  flex-shrink: 0;
}

.review-issue-kind {
  flex-shrink: 0;
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.3px;
  color: var(--alert);
  border: 1px solid currentColor;
  border-radius: 4px;
  padding: 1px 5px;
}

.review-issue-body {
  color: var(--ink-soft);
  font-size: 12.5px;
}

/* Explanatory, not a problem -- "No nucs today" on an already-intentional day, shown outside any
   .review-issue-line (no kind tag, nothing to acknowledge), so it needs its own small spacing. */
.review-ok-note {
  margin: 2px 0 4px;
}

.review-role-row-input {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin-top: 2px;
}

/* Narrowed from an original 140px (down to roughly 5 characters -- half the old width) per
   explicit user feedback that the field read as oversized for what it typically holds (a bare
   1-3 letter initials, occasionally a short comma-separated pair). A longer multi-provider list
   just scrolls within the input rather than growing it, same tradeoff every other fixed-width
   text input on this page already makes. */
.review-roster-input {
  width: 70px;
}

/* Free-text "Notes for spreadsheet" input on each role row -- flex-basis: 100% (same trick
   .review-chip-row uses) drops it onto its own full-width line below the initials input/chips
   rather than squeezing into the same flex-wrap line. Hidden by default (see .review-note-toggle);
   [hidden] already forces display: none, overriding flex-basis, so no extra rule needed for that. */
.review-roster-note-input {
  flex-basis: 100%;
  width: 100%;
  max-width: 420px;
  margin-top: 2px;
  font-size: 12px;
}

/* Small text-link-style toggle that reveals the notes input above -- plain-text, no border/
   background, matching the low-emphasis .review-ok-roles summary caret rather than a real button
   (a note is the exception, not the expected action, on most role rows). */
.review-note-toggle {
  flex-basis: 100%;
  border: none;
  background: none;
  padding: 0;
  margin-top: 2px;
  font-family: var(--font-ui);
  font-size: 11px;
  color: var(--ink-faint);
  cursor: pointer;
  text-align: left;
}

.review-note-toggle:hover {
  color: var(--ink-soft);
  text-decoration: underline;
}

/* Roles with no flagged issue are tucked behind this caret, collapsed by default, so a day with
   one or two real problems doesn't force six full rows of visual noise -- still real rows (with
   real inputs) once expanded, for the rare case a fix means reassigning an otherwise-fine role. */
.review-ok-roles {
  margin-top: 4px;
}

.review-ok-roles summary {
  cursor: pointer;
  color: var(--ink-faint);
  font-size: 11px;
  padding: 4px 0;
}

.review-csv-preview-count {
  font-size: 11.5px;
  color: var(--ink-faint);
  margin: 10px 0 4px;
}

.review-csv-preview-scroll {
  overflow-x: auto;
  max-height: 260px;
  overflow-y: auto;
  border: 1px solid var(--rule);
  border-radius: 6px;
}

table.review-csv-preview-table {
  width: 100%;
  min-width: 900px;
  border-collapse: collapse;
  font-family: var(--font-mono);
  font-size: 11px;
}

table.review-csv-preview-table th,
table.review-csv-preview-table td {
  padding: 4px 8px;
  border-bottom: 1px solid var(--rule);
  white-space: nowrap;
  text-align: left;
}

table.review-csv-preview-table thead th {
  position: sticky;
  top: 0;
  background: #fdf6f1;
  color: var(--ink-soft);
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.4px;
}

.review-chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  flex-basis: 100%;
  margin-top: 2px;
}

/* Within the Day Roster editor's own role rows specifically (not renderRoleConflictAction()'s
   separate use of the same .review-chip-row, inside .review-actions, which still wants its own
   full-width line above the Record/Dismiss buttons) -- override flex-basis so the provider chips
   flow on the same line as the initials input instead of always wrapping below it. Narrowing
   .review-roster-input (see above) freed up enough room for this per explicit user request. */
.review-role-row-input .review-chip-row {
  flex-basis: auto;
  margin-top: 0;
}

.review-btn {
  font-size: 12px;
  padding: 5px 10px;
}

.review-btn-primary {
  border-color: var(--trace-red);
  color: var(--trace-red-deep);
}

.review-btn-dismiss {
  color: var(--ink-faint);
}

.review-resolved-controls {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.review-status {
  font-size: 12.5px;
  color: var(--ink);
}

.review-generated-textarea {
  width: 100%;
  font-family: var(--font-mono);
  font-size: 11.5px;
  padding: 8px;
  border: 1px solid var(--rule);
  border-radius: 6px;
  background: #fffdfb;
  color: var(--ink-soft);
  resize: vertical;
}

.review-generated-hint,
.review-generated-note {
  font-size: 11px;
  color: var(--ink-faint);
}

.review-resolved-controls .review-btn {
  align-self: flex-start;
}

/* Role rows (a label, a short description, a 140px input, a few chips) rarely fill a wide
   screen's full width -- the collapsed "Full day detail" toggle sits in that empty space as a
   side column instead of one more full-width row stacked at the very bottom. 380px (up from an
   original 300px, per explicit feedback that the side column read as too compressed) still
   leaves the main column comfortably wider on a typical desktop width. minmax(0, ...) on both
   tracks, not a bare 1fr/px, for the same reason .cal-grid needed it (see the mobile-layout note
   in CLAUDE.md): a long unwrapped line in either column would otherwise force the grid wider
   than the card. */
.review-day-card-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 380px);
  gap: 4px 24px;
  align-items: start;
}

.review-day-side {
  border-left: 1px dashed var(--rule);
  padding-left: 20px;
}

@media (max-width: 900px) {
  .review-day-card-body {
    grid-template-columns: minmax(0, 1fr);
  }
  .review-day-side {
    border-left: none;
    border-top: 1px dashed var(--rule);
    padding: 8px 0 0;
    margin-top: 4px;
  }
}

/* Static, always-visible full day-inspector-equivalent detail for the card's date -- was a
   collapsed-by-default <details>/<summary>; per explicit user feedback the side column already
   has its own dedicated room, so a hide/show toggle was pure friction with nothing to save. */
.review-day-details {
  margin-top: 0;
  font-size: 12px;
}

.review-day-details-head {
  color: var(--ink-soft);
  font-size: 11.5px;
}

.review-day-summary-row {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 2px 0 2px 14px;
}

.review-day-summary-label {
  min-width: 130px;
  flex-shrink: 0;
  font-weight: 700;
  color: var(--ink-soft);
}

/* \n-joined multi-provider values (Spreadsheet notes/remarks -- see buildDaySummaryRows()) get
   one line per provider under a single shared label instead of repeating the label per provider.
   pre-line is a no-op for any value with no newline, so every other row renders unchanged. */
.review-day-summary-value {
  white-space: pre-line;
}

.review-day-summary-empty {
  padding: 4px 0 4px 14px;
  color: var(--ink-faint);
  font-size: 11.5px;
}

/* Consecutive rows sharing the same "group" (buildDaySummaryRows()' third array element) get
   wrapped in one bordered box instead of every row -- the vacation line and the block of assigned
   roles (Team A/B/C, Nuclear, PM Consults, Echo) are the two spots most worth the eye snagging on
   while triaging a day, per explicit feedback. Rows outside a group render exactly as before,
   flush against .review-day-details with no box. */
.review-day-summary-group {
  border-radius: 6px;
  margin: 3px 0 5px 14px;
  padding: 2px 10px;
}

.review-day-summary-group .review-day-summary-row {
  padding-left: 0;
}

.review-day-summary-group-vacation {
  border: 1.5px solid var(--vacation);
  background: var(--vacation-tint);
}

.review-day-summary-group-assigned {
  border: 1.5px solid var(--rule);
  background: #fffdfb;
}

/* ---------------- Spreadsheet reference page (spreadsheet_view.html) ---------------- */

.sheet-table-header-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 10px;
}

.sheet-row-count {
  font-size: 12px;
  color: var(--ink-faint);
}

.sheet-table-scroll {
  overflow-x: auto;
}

table.sheet-table {
  width: 100%;
  border-collapse: collapse;
  font-family: var(--font-mono);
  font-size: 12.5px;
  min-width: 1100px;
}

table.sheet-table th, table.sheet-table td {
  padding: 7px 9px;
  text-align: left;
  border-bottom: 1px solid var(--rule);
  vertical-align: top;
}

table.sheet-table th {
  font-family: var(--font-ui);
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.7px;
  color: var(--ink-faint);
  white-space: nowrap;
}

table.sheet-table th.sheet-sortable {
  cursor: pointer;
  user-select: none;
}

table.sheet-table th.sheet-sortable:hover {
  color: var(--trace-red-deep);
}

table.sheet-table th.sheet-sort-active {
  color: var(--ink);
}

table.sheet-table td.provider-cell {
  font-family: var(--font-ui);
  font-weight: 700;
  white-space: nowrap;
}

table.sheet-table tbody tr:hover {
  background: #fdf6f1;
}

/* ---------------- Today page (today.html) ---------------- */

.today-nav-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  flex-wrap: wrap;
}

/* Deliberately larger than .inspector-day-nav's 26px -- this page's whole point is a one-thumb
   mobile lookup, so the day-step buttons need a real touch target (roughly the 44px Apple/Google
   both recommend), not the compact size that's fine next to a mouse cursor on index.html. */
.today-day-btn {
  flex-shrink: 0;
  width: 44px;
  height: 44px;
  border: 1.5px solid var(--rule);
  background: #fffdfb;
  color: var(--ink-soft);
  font-size: 18px;
  font-weight: 700;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
  cursor: pointer;
  transition: border-color 0.12s ease, color 0.12s ease;
}

.today-day-btn:hover {
  border-color: var(--trace-red);
  color: var(--trace-red-deep);
}

.today-jump-btn:disabled {
  opacity: 0.4;
  cursor: default;
}

#today-date-input {
  font-family: var(--font-ui);
  font-size: 13px;
  padding: 9px 10px;
  border: 1.5px solid var(--rule);
  border-radius: 8px;
  background: #fffdfb;
  color: var(--ink);
}

@media (max-width: 700px) {
  /* Full-width stacked toolbar and a taller inspector card border on a narrow screen -- this page
     has nothing else competing for space, so it can afford to give the date controls more room
     than they'd get squeezed into index.html's layout. */
  .today-nav-row {
    justify-content: space-between;
  }
  #today-date-input {
    flex: 1 1 auto;
    min-width: 0;
  }
}
