/* ─────────────────────────────────────────────────────────────────────────────
   SVP — design tokens
   Deep navy substrate · gold/yellow accent · warm off-white type
   ───────────────────────────────────────────────────────────────────────────── */

:root {
  /* surfaces — layered navy substrate (literal hex, matches preview exactly) */
  --bg-0: #041030;
  /* deepest, outside chrome / sidebar */
  --bg-1: #0E1A3A;
  /* canvas */
  --bg-2: #182444;
  /* raised card */
  --bg-3: #222E4E;
  /* elevated input / hover */
  --bg-4: #2F3B5B;
  /* primary button rest */
  --bg-5: #28407E;
  /* button hover when not gold */
  --bg-overlay: rgba(10, 18, 40, 0.72);
  --scrim: rgba(4, 16, 48, 0.38);
  /* full-screen loader dimmer. Its OWN role: deep navy in BOTH themes (see the light override) so the gold CMW shines against a genuinely low-tinted backdrop regardless of theme. Value = --bg-0 dark (#041030) @ 38% — preserves the dark-mode look exactly; was borrowing --bg-0 directly, which flips to the LIGHTEST cream in light mode and fogged the page. */

  /* surface roles — semantic. Lets us tune one role (e.g. form sections)
     without affecting unrelated components that share the same raw bg. */
  --surface-card: var(--bg-2);
  /* the default raised card */
  --surface-form: #1B2A5E;
  /* form fields / sections / context rail —
                                     a touch more lifted than --bg-2 so the
                                     interactive area reads as a clear sheet */

  /* borders */
  --border-faint: rgba(255, 255, 255, 0.06);
  --border-soft: rgba(255, 255, 255, 0.10);
  --border-strong: rgba(255, 255, 255, 0.16);
  --border-gold: rgba(224, 179, 74, 0.45);

  /* text — warm off-white over cool navy */
  --text-1: #F1EEE0;
  /* primary */
  --text-2: #B6BDD0;
  /* secondary */
  --text-3: #818AA5;
  /* tertiary / labels */
  --text-4: #5B6485;
  /* placeholder / disabled */

  /* accent — gold (literal hex, matches preview exactly) */
  --gold-12: #FFE67D;
  /* brightest, hover */
  --gold-10: #FACD64;
  /* bright — text / links / icons */
  --gold-9: #E0B34A;
  /* base accent */
  --gold-8: #C99935;
  /* pressed */
  --gold-7: #AD8017;
  /* deep — progress-bar start */
  --gold-tint: rgba(224, 179, 74, 0.12);
  --gold-tint-2: rgba(224, 179, 74, 0.20);
  --gold-tint-3: rgba(224, 179, 74, 0.30);
  --gold-on-dark: #0E1A3A;
  /* text on gold fill */
  /* Solid gold FILL behind dark content (buttons, icon tiles) — a role apart from
     gold-9 so light mode can darken gold-9 for TEXT contrast without dragging the
     fills muddy with it. In dark the bright base accent already IS the fill, so
     reference it directly (re-tuning gold-9 then drags the fill along). */
  --gold-fill: var(--gold-9);
  /* Hover brightening for the gold CTAs. In dark the accent already lifted to
     gold-12 on hover — keep that. */
  --gold-fill-hover: var(--gold-12);

  /* A mood-agnostic magnitude RAMP (deep -> bright) — e.g. the grade-amendments bar,
     where the three segments must stay distinct AND read as a ramp in both themes but
     must NOT imply good/bad (a school could be inflating). The raw gold-7/9/12 scale
     ramps deep->bright only in DARK (gold-12 is lightest there); in light gold-12 is
     the DARKEST, so that scale inverts. These keep the ramp monotonic. Text-free
     (bars/swatches), so free to be vivid. */
  --gold-ramp-lo: var(--gold-7);
  --gold-ramp-mid: var(--gold-9);
  --gold-ramp-hi: var(--gold-12);

  /* status — oklch family, harmonised at chroma .11 */
  --status-ok: oklch(75% 0.11 150);
  /* validated */
  --status-ok-tint: oklch(75% 0.11 150 / 0.15);
  --status-warn: oklch(75% 0.11 70);
  /* concern */
  --status-warn-tint: oklch(75% 0.11 70 / 0.15);
  --status-info: oklch(75% 0.11 230);
  /* in progress */
  --status-info-tint: oklch(75% 0.11 230 / 0.15);
  --status-danger: oklch(67% 0.13 25);
  /* safeguarding / overdue */
  --status-danger-tint: oklch(67% 0.13 25 / 0.18);
  --status-neutral: #818AA5;
  --status-neutral-tint: rgba(129, 138, 165, 0.12);

  /* Status colours as FILL — a role apart from the base status tokens, mirroring
     --gold-fill. Light mode DARKENS the base status colours (~48-50% L) so they clear
     AA as TEXT on the pale tints; that same dark value looks muddy/dingy as a solid
     fill (dots, bars, accent stripes). These -fill tokens carry the vivid value for
     text-free fills, leaving the base tokens for text/borders. In dark the base is
     already vivid, so reference it directly — dark renders unchanged. ONLY for fills
     that carry no text: a text-bearing fill (btn-danger, banners) keeps the darker
     base so its on-fill text still contrasts. Neutral has no -fill (achromatic grey
     doesn't go muddy). */
  --status-ok-fill: var(--status-ok);
  --status-warn-fill: var(--status-warn);
  --status-info-fill: var(--status-info);
  --status-danger-fill: var(--status-danger);

  /* feedback toasts — stronger + more saturated than the calm pill statuses
     above, because a transient alert must grab the eye: a deep amber clear of
     the gold accent (warning), a proper strong red for errors (server 5xx,
     network, timeout), a clean green (success). Info toasts use the theme gold. */
  --toast-warn: oklch(70% 0.16 60);
  /* deep amber — distinct from gold */
  --toast-danger: oklch(60% 0.21 25);
  /* strong red */
  --toast-ok: oklch(70% 0.15 150);
  /* clean green */

  /* type */
  --font-sans: 'Inter', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-mono: 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, monospace;
  --font-display: 'Inter', ui-sans-serif, system-ui, sans-serif;

  /* radii */
  --r-1: 4px;
  --r-2: 6px;
  --r-3: 10px;
  --r-4: 14px;
  --r-5: 20px;

  /* surface mixers — subtle hover/press tints, swap to dark in light mode */
  --surface-hover: rgba(255, 255, 255, 0.03);
  --surface-hover-strong: rgba(255, 255, 255, 0.05);
  --surface-press: rgba(255, 255, 255, 0.08);
  --row-hover: rgba(255, 255, 255, 0.025);
  --scroll-thumb: rgba(255, 255, 255, 0.08);
  --scroll-thumb-hover: rgba(255, 255, 255, 0.16);

  /* tints over canvas — reused for gradients on hero cards, banners, etc.
     Defined alongside their target so light/dark can swap correctly. */
  --tint-gold-soft: rgba(224, 179, 74, 0.10);
  /* radial glow on login left panel */
  --tint-gold-medium: rgba(224, 179, 74, 0.18);
  /* hero card glow */
  --tint-warn-soft: rgba(212, 156, 75, 0.08);
  /* returned banner */
  --tint-danger-soft: rgba(213, 131, 106, 0.06);
  /* safeguarding panel */

  /* shadows — gentle, mostly inset highlights on navy */
  --shadow-1: 0 1px 0 rgba(255, 255, 255, 0.04) inset, 0 1px 2px rgba(0, 0, 0, 0.3);
  --shadow-2: 0 1px 0 rgba(255, 255, 255, 0.05) inset, 0 4px 14px rgba(0, 0, 0, 0.35);
  --shadow-pop: 0 1px 0 rgba(255, 255, 255, 0.08) inset, 0 18px 50px rgba(0, 0, 0, 0.55);
  --shadow-gold: 0 0 0 1px rgba(224, 179, 74, 0.35), 0 8px 28px rgba(224, 179, 74, 0.18);

  /* motion */
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-flow: cubic-bezier(0.65, 0, 0.35, 1);

  /* spacing scale */
  --s-1: 4px;
  --s-2: 8px;
  --s-3: 12px;
  --s-4: 16px;
  --s-5: 20px;
  --s-6: 24px;
  --s-7: 32px;
  --s-8: 40px;
  --s-9: 56px;
  --s-10: 80px;

  /* density */
  --row-h: 52px;
}

[data-density="compact"] {
  --row-h: 40px;
  --s-4: 12px;
  --s-5: 16px;
  --s-6: 20px;
}

[data-density="comfy"] {
  --row-h: 64px;
}

/* ─────────────── base ─────────────── */
*,
*::before,
*::after {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  padding: 0;
  height: 100%;
}

body {
  font-family: var(--font-sans);
  font-size: 14px;
  line-height: 1.45;
  color: var(--text-1);
  background: var(--bg-1);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  font-feature-settings: 'cv11', 'ss01', 'ss03';
}

button {
  font-family: inherit;
}

:focus-visible {
  outline: 2px solid var(--gold-10);
  outline-offset: 2px;
  border-radius: var(--r-1);
}

/* ─────────────── primitives ─────────────── */
.mono {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}

.tnum {
  font-variant-numeric: tabular-nums;
}

.eyebrow {
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-3);
  font-weight: 500;
}

.kbd {
  font-family: var(--font-mono);
  font-size: 11px;
  padding: 2px 6px;
  border-radius: 4px;
  background: var(--bg-3);
  color: var(--text-2);
  border: 1px solid var(--border-soft);
}

/* the chevron flow motif */
.flow-line {
  --flow-color: var(--gold-9);
  height: 1px;
  background: linear-gradient(90deg,
      transparent 0%,
      var(--flow-color) 20%,
      var(--flow-color) 80%,
      transparent 100%);
  opacity: 0.5;
}

.flow-line.faint {
  opacity: 0.18;
}

.chev::after {
  content: '›';
  color: var(--gold-9);
  margin-left: 0.4em;
  opacity: 0.7;
  display: inline-block;
  transition: transform 240ms var(--ease-out);
}

.chev:hover::after {
  transform: translateX(3px);
  opacity: 1;
}

/* ── Next-action hero top-edge gleam ───────────────────────────────────
   A single soft gold highlight sweeps left→right across the hero's top edge
   every few seconds, then rests — a subtle, deliberate "act here" glint on the
   primary CTA. Replaces the old repeating pinstripe, whose gold-TINT ticks were
   lost against the hero's own gold radial tint (invisible on desktop; faint
   verticals only on narrow displays, where the tint fades sooner). The gleam is
   a BRIGHT --gold-fill-hover highlight so it reads over that tint, on an otherwise
   transparent track (nothing persists between sweeps), swept via transform on
   ::before (compositor-only, no repaint). Honours prefers-reduced-motion. */
@keyframes gleam {

  0%,
  8% {
    transform: translateX(-100%);
  }

  /* rest, off the left edge */
  46% {
    transform: translateX(238%);
  }

  /* swept across (the band is 42% wide) */
  100% {
    transform: translateX(238%);
  }

  /* rest, off the right edge (the pause) */
}

.hero-gleam {
  overflow: hidden;
}

.hero-gleam::before {
  content: "";
  position: absolute;
  inset: 0 auto auto 0;
  width: 42%;
  height: 100%;
  max-height: 4px;
  /* own height + cap: on slim the top+bottom-pinned sweep rendered taller than the 3px bar and broke out (Matt, UAT) */
  background: linear-gradient(90deg, transparent, var(--gold-fill-hover), transparent);
  transform: translateX(-100%);
  animation: gleam 5s ease-in-out infinite;
}

@media (prefers-reduced-motion: reduce) {
  .hero-gleam::before {
    animation: none;
  }
}

/* ─────────────── buttons ─────────────── */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 0 16px;
  height: 36px;
  border-radius: var(--r-2);
  border: 1px solid transparent;
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.005em;
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
  text-decoration: none;
  /* <a class="btn"> must never underline its text */
  transition: background 160ms var(--ease-out), color 160ms var(--ease-out),
    border-color 160ms var(--ease-out), transform 80ms ease;
}

.btn:active {
  transform: translateY(1px);
}

/* Disabled / in-flight (e.g. hx-disabled-elt during a save): a muted GREY (not
   opacity — opacity would dim an inline loader inside it too), inert so it reads
   as non-clickable and can't hover-flip (no gold) or bounce. The CMW/text then
   keep full contrast against the grey. `.btn.is-busy` is the no-Alpine equivalent
   (the magic-link interstitial toggles it via its inline submit-guard instead of
   `:disabled="submitting"`) — it must read identically, so it shares this rule. */
.btn:disabled,
.btn.is-busy {
  background: var(--bg-3);
  color: var(--text-3);
  border-color: var(--border-soft);
  pointer-events: none;
}

.btn-primary {
  background: var(--bg-4);
  color: var(--btn-primary-text, var(--text-1));
  border-color: var(--border-soft);
  box-shadow: var(--shadow-1);
}

.btn-primary:hover {
  background: var(--gold-fill);
  color: var(--gold-on-dark);
  border-color: var(--gold-10);
}

.btn-primary:hover .chev-i {
  transform: translateX(3px);
}

.btn-gold {
  background: var(--gold-fill);
  color: var(--gold-on-dark);
  border-color: var(--gold-10);
}

.btn-gold:hover,
.btn-secondary:hover {
  background: var(--gold-fill-hover);
  color: var(--gold-on-dark);
  border-color: var(--gold-fill-hover);
}

/* Secondary: the navy 'usable but not the hero' button, used only where a gold
   primary sits beside it (the submit bar) so the non-preferred actions read as
   clearly clickable — NOT like the disabled grey. Same navy rest as btn-primary;
   hovers to the gold exactly like the yellow buttons (grouped above). */
.btn-secondary {
  background: var(--bg-4);
  color: var(--btn-primary-text, var(--text-1));
  border-color: var(--border-soft);
  box-shadow: var(--shadow-1);
}

.btn-ghost {
  background: transparent;
  color: var(--text-2);
  border-color: var(--border-soft);
}

.btn-ghost:hover {
  background: var(--bg-3);
  color: var(--text-1);
  border-color: var(--border-strong);
}

.btn-quiet {
  background: transparent;
  color: var(--text-2);
  border-color: transparent;
  padding: 0 10px;
}

.btn-quiet:hover {
  background: var(--bg-3);
  color: var(--text-1);
}

/* Destructive actions. .btn-danger = the solid commit in the confirm modal;
   .btn-danger-ghost = the quiet trigger in a drawer footer (danger only on
   hover, so it doesn't shout at rest beside Cancel/Save). The hardened
   `.btn:disabled` rule (compound selector, higher specificity) still wins when
   either is disabled, so an unarmed Delete reads inert/grey regardless. */
.btn-danger {
  background: var(--status-danger);
  color: #fff;
  border-color: var(--status-danger);
}

.btn-danger:hover {
  filter: brightness(1.08);
}

.btn-danger-ghost {
  background: transparent;
  color: var(--status-danger);
  border-color: transparent;
}

.btn-danger-ghost:hover {
  background: var(--status-danger-tint);
  color: var(--status-danger);
}

.btn-sm {
  height: 28px;
  padding: 0 10px;
  font-size: 12px;
  border-radius: var(--r-1);
}

.btn-lg {
  height: 44px;
  padding: 0 22px;
  font-size: 14px;
  border-radius: var(--r-2);
}

/* ─────────────── inputs ─────────────── */
.input,
.select,
.textarea {
  width: 100%;
  background: var(--bg-3);
  color: var(--text-1);
  border: 1px solid var(--border-soft);
  border-radius: var(--r-2);
  padding: 10px 12px;
  font-family: inherit;
  font-size: 13.5px;
  line-height: 1.4;
  transition: border-color 160ms, background 160ms;
}

.input::placeholder,
.textarea::placeholder {
  color: var(--text-4);
}

.input:hover,
.select:hover,
.textarea:hover {
  border-color: var(--border-strong);
}

.input:focus,
.select:focus,
.textarea:focus {
  outline: none;
  border-color: var(--gold-9);
  background: var(--bg-3);
  box-shadow: 0 0 0 3px var(--gold-tint);
}

.textarea {
  resize: vertical;
  min-height: 80px;
}

label.field {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

label.field>.lbl {
  font-size: 12px;
  color: var(--text-3);
  font-weight: 500;
  display: flex;
  justify-content: space-between;
  align-items: baseline;
}

label.field>.lbl .req {
  color: var(--gold-9);
  margin-left: 4px;
}

/* ─────────────── cards ─────────────── */
.card {
  background: var(--bg-2);
  border: 1px solid var(--border-soft);
  border-radius: var(--r-3);
  box-shadow: var(--shadow-1);
}

.card-pad {
  padding: 20px;
}

.card-pad-sm {
  padding: 14px;
}

.card-hd {
  padding: 14px 18px;
  border-bottom: 1px solid var(--border-faint);
  border-top-left-radius: var(--r-3);
  border-top-right-radius: var(--r-3);
  background: var(--bg-1);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
}

.card-hd h3 {
  font-size: 14px;
  font-weight: 600;
  margin: 0;
  letter-spacing: -0.005em;
}

/* A card carrying orientation/guidance — a subtle top-to-bottom gradient lifts it
   off the plain .card data panels so it reads as a note, not another data card. */
.card-note {
  background: linear-gradient(180deg, var(--bg-2), var(--bg-1));
}

/* The category header's behaviour pills: right-aligned on the header row by
   default; full-width + left-aligned below the title once the header wraps narrow.
   Alignment lives here (not inline) so the media query can actually override it. */
.svp-status-flags {
  justify-content: flex-end;
}

@media (max-width: 640px) {
  .card-hd .svp-status-flags {
    width: 100%;
    justify-content: flex-start;
  }
}

/* ─────────────── status pills ─────────────── */
.pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 22px;
  padding: 0 8px;
  border-radius: 11px;
  font-size: 11.5px;
  font-weight: 500;
  letter-spacing: 0.01em;
  white-space: nowrap;
}

.pill-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  flex-shrink: 0;
}

.pill-ok {
  background: var(--status-ok-tint);
  color: var(--status-ok);
}

.pill-ok .pill-dot {
  background: var(--status-ok-fill);
}

.pill-warn {
  background: var(--status-warn-tint);
  color: var(--status-warn);
}

.pill-warn .pill-dot {
  background: var(--status-warn-fill);
}

.pill-info {
  background: var(--status-info-tint);
  color: var(--status-info);
}

.pill-info .pill-dot {
  background: var(--status-info-fill);
}

.pill-danger {
  background: var(--status-danger-tint);
  color: var(--status-danger);
}

.pill-danger .pill-dot {
  background: var(--status-danger-fill);
}

.pill-neutral {
  background: var(--status-neutral-tint);
  color: var(--text-2);
}

.pill-neutral .pill-dot {
  background: var(--status-neutral);
}

.pill-gold {
  background: var(--gold-tint);
  color: var(--gold-10);
  border: 1px solid var(--gold-tint-3);
}

.pill-gold .pill-dot {
  background: var(--gold-fill);
}

/* ─────────────── tables ─────────────── */
.tbl {
  width: 100%;
  border-collapse: collapse;
}

.tbl th {
  text-align: left;
  font-size: 11px;
  font-weight: 500;
  color: var(--text-3);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  padding: 10px 12px;
  border-bottom: 1px solid var(--border-soft);
  background: transparent;
}

.tbl td {
  padding: 12px;
  border-bottom: 1px solid var(--border-faint);
  font-size: 13.5px;
  color: var(--text-1);
  height: var(--row-h);
}

.tbl tbody tr {
  cursor: pointer;
  transition: background 120ms;
}

.tbl tbody tr:hover {
  background: var(--row-hover);
}

.tbl tbody tr:hover td:first-child {
  box-shadow: inset 2px 0 0 var(--gold-fill);
}

.tbl tbody tr.is-active {
  background: var(--gold-tint);
}

.tbl tbody tr:last-child td {
  border-bottom: 0;
}

/* ─────────────── validation mode ─────────────── */
/* Subtle warm tint + gold rail on the topbar so users feel they're in a focused task */
.validation-mode {
  background:
    radial-gradient(140% 60% at 100% 0%, rgba(224, 179, 74, 0.06), transparent 50%),
    radial-gradient(140% 60% at 0% 100%, rgba(224, 179, 74, 0.04), transparent 55%),
    var(--bg-1);
}

.validation-mode header {
  border-bottom: 1px solid var(--gold-tint-3);
  background: linear-gradient(180deg, var(--bg-1), var(--bg-1) 70%, var(--gold-tint));
  position: relative;
}

.validation-mode header::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 2px;
  background: linear-gradient(90deg, transparent, var(--gold-fill) 20%, var(--gold-fill-hover) 50%, var(--gold-fill) 80%, transparent);
  opacity: 0.6;
}

/* ─────────────── scroll ─────────────── */
::-webkit-scrollbar {
  width: 10px;
  height: 10px;
}

::-webkit-scrollbar-track {
  background: transparent;
}

::-webkit-scrollbar-thumb {
  background: var(--scroll-thumb);
  border-radius: 5px;
  border: 2px solid transparent;
  background-clip: content-box;
}

::-webkit-scrollbar-thumb:hover {
  background: var(--scroll-thumb-hover);
  background-clip: content-box;
  border: 2px solid transparent;
}

/* ─────────────── utilities ─────────────── */
.row {
  display: flex;
  align-items: center;
}

.col {
  display: flex;
  flex-direction: column;
}

.gap-1 {
  gap: 4px;
}

.gap-2 {
  gap: 8px;
}

.gap-3 {
  gap: 12px;
}

.gap-4 {
  gap: 16px;
}

.gap-5 {
  gap: 20px;
}

.gap-6 {
  gap: 24px;
}

.gap-8 {
  gap: 32px;
}

.grow {
  flex: 1;
}

.muted {
  color: var(--text-3);
}

.muted-2 {
  color: var(--text-2);
}

.dim {
  color: var(--text-4);
}

.gold {
  color: var(--gold-10);
}

.center {
  display: flex;
  align-items: center;
  justify-content: center;
}

.between {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.hidden {
  display: none !important;
}

.sr {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* avatar */
.avi {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-1);
  background: var(--bg-3);
  border: 1px solid var(--border-soft);
  letter-spacing: 0.01em;
  flex-shrink: 0;
}

.avi-sm {
  width: 24px;
  height: 24px;
  font-size: 10px;
}

.avi-lg {
  width: 44px;
  height: 44px;
  font-size: 14px;
}

.avi-gold {
  background: var(--gold-tint-2);
  color: var(--gold-10);
  border-color: var(--gold-tint-3);
}

/* segmented control */
.seg {
  display: inline-flex;
  padding: 3px;
  background: var(--bg-3);
  border-radius: var(--r-2);
  border: 1px solid var(--border-soft);
}

.seg>button {
  appearance: none;
  border: 0;
  background: transparent;
  height: 26px;
  padding: 0 12px;
  border-radius: 4px;
  font-size: 12px;
  font-weight: 500;
  color: var(--text-3);
  cursor: pointer;
  transition: all 120ms;
}

.seg>button:hover {
  color: var(--text-1);
}

.seg>button.is-active {
  background: var(--bg-1);
  color: var(--text-1);
  box-shadow: 0 1px 0 var(--surface-press) inset, 0 1px 2px rgba(0, 0, 0, 0.18);
}

/* ─────────────── switch (styled boolean toggle) ───────────────
   A pro toggle for an on/off control where two seg radios are overkill — the
   real <input type=checkbox> is visually hidden but stays the focus/click
   target; :checked drives the gold track + slides the thumb. Reduced-motion
   users get the colour flip without the slide. */
.svp-switch {
  position: relative;
  display: inline-flex;
  flex-shrink: 0;
}

.svp-switch input {
  position: absolute;
  inset: 0;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}

.svp-switch-track {
  display: inline-block;
  width: 34px;
  height: 20px;
  border-radius: 10px;
  background: var(--bg-3);
  border: 1px solid var(--border-soft);
  transition: background 160ms var(--ease-out), border-color 160ms var(--ease-out);
}

.svp-switch-thumb {
  display: block;
  width: 14px;
  height: 14px;
  margin: 2px;
  border-radius: 50%;
  background: var(--text-3);
  box-shadow: var(--shadow-1);
  transition: transform 160ms var(--ease-out), background 160ms var(--ease-out);
}

.svp-switch input:checked+.svp-switch-track {
  background: var(--gold-fill);
  border-color: var(--gold-10);
}

.svp-switch input:checked+.svp-switch-track .svp-switch-thumb {
  background: var(--gold-on-dark);
  transform: translateX(14px);
}

.svp-switch input:focus-visible+.svp-switch-track {
  outline: 2px solid var(--gold-9);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {

  .svp-switch-track,
  .svp-switch-thumb {
    transition: background 160ms var(--ease-out);
  }
}

/* ─────────────────────────────────────────────────────────────────────────────
   Light theme — WCAG AA compliant
   Cream substrate · deepened gold (so gold can still meet contrast on light)
   Navy primary buttons stay navy; their gold-on-hover deepens to amber.
   ───────────────────────────────────────────────────────────────────────────── */
[data-theme="light"] {
  /* surfaces */
  --bg-0: #ECE9DD;
  --bg-1: #F6F4ED;
  --bg-2: #FFFFFF;
  --bg-3: #EFECE2;
  --bg-4: #1F3068;
  /* primary button stays navy */
  --bg-5: #142250;
  --bg-overlay: rgba(15, 26, 58, 0.45);
  --scrim: rgba(15, 26, 58, 0.30);
  /* gentle navy dim — the frosted loader card carries legibility, so the full-screen scrim only needs a soft push-back, not a deep dip (a light --bg-* here would FOG the page instead of dimming it) */
  --btn-primary-text: #FFFFFF;
  /* WCAG-AA white on #1F3068 = 8.6:1 */

  /* surface roles — in light mode the form sheet is plain white */
  --surface-card: #FFFFFF;
  --surface-form: #FFFFFF;

  /* borders — dark hairlines on cream */
  --border-faint: rgba(15, 26, 58, 0.08);
  --border-soft: rgba(15, 26, 58, 0.14);
  --border-strong: rgba(15, 26, 58, 0.22);
  --border-gold: rgba(122, 90, 15, 0.40);

  /* text — near-navy on cream, all AA-compliant for body text */
  --text-1: #0F1A3A;
  /* ~13:1 on bg-1   */
  --text-2: #3A4258;
  /* ~ 8:1 on bg-1   */
  --text-3: #5E667E;
  /* ~ 5.1:1 on bg-1 (AA normal) */
  --text-4: #8B91A3;
  /* placeholders / disabled only */

  /* gold — visibly gold but darkened so it actually meets contrast on cream.
     • gold-9  (main accent, dots, dividers)            = #A87B26 → 3.5:1 vs cream (AA UI)
     • gold-10 (text/links/icons)                       = #946618 → 4.6:1 (AA text)
     • gold-12 (brightest, hover-on-hover, focus rings) = #7A5A0F → 7.0:1
     • gold-7  (deep, dividers on white)                = #61480D → 9.5:1
     Gold used as a solid FILL is --gold-fill (below), not gold-9 — kept bright. */
  --gold-12: #7A5A0F;
  --gold-10: #946618;
  --gold-9: #A87B26;
  --gold-8: #946618;
  --gold-7: #61480D;
  /* Gold TINTS are translucent glows / halos / soft backgrounds — a fill role, not
     text. Built on the BRIGHT gold RGB (matching --gold-fill #EDBB42), NOT the darkened
     text-gold above: a low-alpha muddy-gold over warm cream goes grey-taupe (the
     "poo-blob" journey halo). The alpha carries the paleness; the RGB must stay vivid so
     the glow reads as gold. Dark tints (:root) already use the bright RGB, same reason. */
  --gold-tint: rgba(237, 187, 66, 0.10);
  --gold-tint-2: rgba(237, 187, 66, 0.18);
  --gold-tint-3: rgba(237, 187, 66, 0.32);
  --gold-on-dark: #0F1A3A;
  /* Fill stays BRIGHT even though gold-9 (above) darkened for text: fills carry
     navy text (contrast RISES on a brighter fill, not falls) and take their
     boundary from the gold-10 border — so the fill is free to look premium, not
     muddy. This one value is the light-mode gold-CTA dial; tune to taste. */
  --gold-fill: #EDBB42;
  /* Hover brightening — a brighter amber so gold CTAs visibly lift on hover (light
     mode used to only shift the border/glow). Navy on it is still AAA; tune with
     the fill above. */
  --gold-fill-hover: #F7CE52;

  /* status — deeper for cream-bg compliance */
  --status-ok: oklch(48% 0.13 150);
  --status-ok-tint: oklch(96% 0.05 150);
  --status-warn: oklch(50% 0.13 65);
  --status-warn-tint: oklch(96% 0.05 75);
  --status-info: oklch(48% 0.14 240);
  --status-info-tint: oklch(96% 0.05 240);
  --status-danger: oklch(48% 0.16 25);
  --status-danger-tint: oklch(95% 0.06 25);
  --status-neutral: #6B7390;
  --status-neutral-tint: rgba(107, 115, 144, 0.10);

  /* Fill-role status colours: vivid values for text-free fills (see the :root note).
     Lightness is tuned per hue — amber (warn) sits higher because yellow is
     intrinsically light and needs it to read vivid; green/red/blue land at 70%.
     Matt-validated on the KPI accent cards. */
  --status-ok-fill: oklch(70% 0.13 150);
  --status-warn-fill: oklch(80% 0.13 65);
  --status-info-fill: oklch(70% 0.14 240);
  --status-danger-fill: oklch(70% 0.16 25);

  /* Mood-agnostic magnitude ramp (see the :root note) — a light-legible deep->bright
     amber that stays monotonic where the raw gold-7/9/12 scale would invert. */
  --gold-ramp-lo: oklch(60% 0.13 68);
  --gold-ramp-mid: oklch(73% 0.14 75);
  --gold-ramp-hi: oklch(85% 0.13 88);

  /* surface mixers */
  --surface-hover: rgba(15, 26, 58, 0.04);
  --surface-hover-strong: rgba(15, 26, 58, 0.06);
  --surface-press: rgba(15, 26, 58, 0.10);
  --row-hover: rgba(168, 123, 38, 0.06);
  --scroll-thumb: rgba(15, 26, 58, 0.18);
  --scroll-thumb-hover: rgba(15, 26, 58, 0.32);

  /* Radial-glow tints (login left panel, hero card). Bright gold RGB — matching the
     --gold-tint trio above — NOT the darkened text-gold: a glow built on darkened gold
     goes grey-taupe on cream (same bug). The alpha carries the presence. */
  --tint-gold-soft: rgba(237, 187, 66, 0.10);
  --tint-gold-medium: rgba(237, 187, 66, 0.16);
  --tint-warn-soft: rgba(180, 120, 40, 0.10);
  --tint-danger-soft: rgba(170, 70, 50, 0.07);

  /* shadows — heavier drops, no inset highlights */
  --shadow-1: 0 1px 2px rgba(15, 26, 58, 0.06), 0 1px 0 rgba(255, 255, 255, 0.6) inset;
  --shadow-2: 0 2px 8px rgba(15, 26, 58, 0.06), 0 1px 2px rgba(15, 26, 58, 0.04);
  --shadow-pop: 0 18px 50px rgba(15, 26, 58, 0.18), 0 2px 6px rgba(15, 26, 58, 0.08);
  --shadow-gold: 0 0 0 1px rgba(122, 90, 15, 0.35), 0 6px 22px rgba(168, 123, 38, 0.18);
}

/* Light-mode-specific tweaks that aren't expressible as plain token swaps */
[data-theme="light"] .pill-gold {
  background: var(--gold-tint-2);
  color: var(--gold-12);
  border-color: var(--gold-tint-3);
}

/* The grade picker's selected pill lifts by being LIGHTER than the bar — which
   works in dark (bg-1 sits deeper than the bg-3 bar, a pressed look) but not on
   cream, where bg-1 and bg-3 are both pale and nearly identical, so the selection
   barely registers. On light, give it a white fill + a crisp ring + soft drop so
   the chosen grade clearly reads as picked. */
[data-theme="light"] .svp-grade-picker input:checked+label {
  background: #fff;
  box-shadow: 0 0 0 1px rgba(15, 26, 58, 0.14), 0 1px 3px rgba(15, 26, 58, 0.18);
}

/* The progress track's default bg-3 is near-invisible on cream (a hair off the
   page/bar colour), so the "how much is left" channel disappears. The beige bg scale
   has nothing dark enough to read as a recessed channel behind the bright gold fill,
   so borrow --border-strong's navy tint (a muted blue-grey on cream) — clearly darker
   than the fill and tonally opposite the amber, so the two separate cleanly. A bg this
   definite needs no inset outline. Light-scoped, so dark keeps its plain bg-3
   (recessed against the bg-0 bar). */
[data-theme="light"] .svp-progress-track {
  background: var(--border-strong);
}

/* Hover on the gold fills in light mode: BRIGHTEN the fill to --gold-fill-hover so
   the CTA visibly lifts — brightening RAISES navy-on-gold contrast so it's AA-safe
   (only DARKENING would drop it, which the base .btn-gold:hover would do via the
   dark light-mode gold-12). A darker border + tinted glow ride along. */
[data-theme="light"] .btn-gold:hover,
[data-theme="light"] .btn-secondary:hover {
  background: var(--gold-fill-hover);
  color: var(--gold-on-dark);
  border-color: var(--gold-12);
  box-shadow: 0 0 0 3px var(--gold-tint-3);
}

[data-theme="light"] .btn-primary:hover {
  background: var(--gold-fill);
  color: var(--gold-on-dark);
  border-color: var(--gold-12);
  box-shadow: 0 0 0 3px var(--gold-tint-3);
}

/* Ghost/quiet buttons hover to --bg-3 (a visibly-raised navy) in DARK, but in light
   --bg-3 is a pale cream ≈ the page — so the hover vanished (the logout icon, table
   action buttons, the account "Edit" links etc. showed no change on hover). Give them
   a real navy wash on cream so the interaction actually reads. The base :hover already
   sets color/border, which are fine on light; only the background needs the override. */
[data-theme="light"] .btn-ghost:hover,
[data-theme="light"] .btn-quiet:hover {
  background: color-mix(in srgb, var(--bg-4) 10%, transparent);
}

/* Disabled must WIN every state fight. A button disabled mid-press can keep a
   STUCK :hover — once pointer-events:none lands, touch/emulated pointers never
   re-hit-test to clear it — and the variant hover golds above outrank the base
   .btn:disabled grey in the cascade (same specificity, later in file). So this
   block sits AFTER every hover variant and names the states explicitly: a
   held-down Save reads grey on desktop, touch, slim widths, either theme.
   (Caught by Matt's UAT on PR #70 — the "still nice and yellow" button.) */
.btn:disabled,
.btn:disabled:hover,
.btn:disabled:active,
.btn.is-busy,
.btn.is-busy:hover,
.btn.is-busy:active,
[data-theme="light"] .btn:disabled:hover,
[data-theme="light"] .btn.is-busy:hover {
  background: var(--bg-3);
  color: var(--text-3);
  border-color: var(--border-soft);
  box-shadow: none;
  transform: none;
  pointer-events: none;
}

[data-theme="light"] .validation-mode header {
  border-bottom: 1px solid var(--gold-tint-3);
  background: linear-gradient(180deg, var(--bg-1), var(--bg-1) 70%, var(--gold-tint));
}

[data-theme="light"] body {
  /* Slightly different rendering tuning for dark-on-light */
  font-feature-settings: 'cv11', 'ss01';
}

/* ─────────────────────────────────────────────────────────────────────────────
   Responsive layer
   Breakpoints:
     ≤ 1024px  tablet & below — sidebar becomes drawer
     ≤  768px  small tablet / large phone
     ≤  640px  phone

   Strategy: never touch desktop layout above 1024px. All overrides scoped via
   class hooks (.svp-app, .svp-sidebar, .svp-mobile-bar, etc.) so this whole
   section can be deleted/replaced without affecting the main stylesheet.

   !important is used sparingly to override inline component styles. We accept
   that cost in exchange for keeping JSX free of media queries.
   ───────────────────────────────────────────────────────────────────────────── */

/* The hamburger row is hidden on desktop; the sidebar shows inline. */
.svp-mobile-bar {
  display: none;
}

/* Xaverian College logo (auth pages): deep navy #01083e natively on light;
   whitened on dark so the single-colour mark reads on the dark panel —
   brightness(0)→black then invert(1)→white gives a clean white silhouette. */
[data-theme="dark"] .svp-xav-logo {
  filter: brightness(0) invert(1);
}

/* ──────────────────────── ≤ 1024px (tablet & below) ──────────────────────── */
@media (max-width: 1024px) {

  /* App shell: app stops being a row, becomes a column. Sidebar floats. */
  .svp-app {
    flex-direction: column !important;
  }

  /* Sidebar → off-canvas drawer */
  .svp-sidebar {
    position: fixed !important;
    top: 0;
    bottom: 0;
    left: 0;
    width: 280px !important;
    z-index: 80;
    transform: translateX(-100%);
    /* Transparent shadow at rest (alpha 0) so nothing bleeds ~50px onto the page
       while the drawer sits off-canvas; it fades IN to full only when open. Same
       geometry both ends so the alpha interpolates smoothly (box-shadow can't
       transition to/from `none`). Matt's UAT: the shadow was showing when closed. */
    transition: transform 240ms var(--ease-out), box-shadow 240ms var(--ease-out);
    box-shadow: 0 18px 50px rgba(0, 0, 0, 0);
  }

  .svp-app[data-nav-open="true"] .svp-sidebar {
    transform: translateX(0);
    box-shadow: 0 18px 50px rgba(0, 0, 0, 0.45);
  }

  /* scrim behind drawer */
  .svp-app[data-nav-open="true"]::after {
    content: '';
    position: fixed;
    inset: 0;
    background: var(--bg-overlay);
    z-index: 70;
    animation: svp-fade-in 160ms var(--ease-out);
  }

  @keyframes svp-fade-in {
    from {
      opacity: 0
    }

    to {
      opacity: 1
    }
  }

  /* Mobile topbar: hamburger + brand mark, sits above the desktop topbar */
  .svp-mobile-bar {
    display: flex !important;
    align-items: center;
    height: 52px;
    flex-shrink: 0;
    padding: 0 16px;
    background: var(--bg-0);
    border-bottom: 1px solid var(--border-faint);
    gap: 12px;
    z-index: 60;
  }

  .svp-mobile-bar .svp-burger {
    appearance: none;
    border: 0;
    background: transparent;
    width: 36px;
    height: 36px;
    border-radius: var(--r-2);
    color: var(--text-1);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: background 120ms;
  }

  .svp-mobile-bar .svp-burger:hover {
    background: var(--surface-hover);
  }

  /* Desktop topbar adapts: lower padding, smaller title, right cluster wraps */
  .svp-topbar {
    height: auto !important;
    min-height: 56px;
    padding: 12px 18px !important;
    flex-wrap: wrap;
    gap: 12px !important;
  }

  .svp-topbar h1 {
    font-size: 16px !important;
  }

  .svp-topbar-right {
    flex-wrap: wrap;
    gap: 8px !important;
  }

  /* Theme selection moves to the mobile top bar (.svp-mobile-bar) at this
     breakpoint — hide the topbar copy so it doesn't crowd the wrapping right
     cluster / double up. Above 1024px the mobile bar is display:none, so the
     topbar is the only theme control there. */
  .svp-topbar .svp-theme-switch {
    display: none;
  }

  /* Main content paddings */
  .svp-page-pad {
    padding: 16px 18px 80px !important;
    gap: 18px !important;
  }

  /* Validation hero: flatten both zones' padding, and stack the "Up next" CTA
     below the applicant info (inert on the meter zone, which is a flex column). */
  .svp-validation-hero>div {
    grid-template-columns: 1fr !important;
    padding: 18px 18px !important;
  }

  .svp-validation-hero .svp-hero-cta {
    align-items: stretch !important;
    width: 100%;
  }

  .svp-validation-hero .svp-hero-cta>a,
  .svp-validation-hero .svp-hero-cta>button {
    width: 100% !important;
    justify-content: center;
  }

  /* Cohort journey: keep horizontal, but allow horizontal scroll on narrow */
  .svp-cohort-rail {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    padding-bottom: 4px;
  }

  .svp-cohort-rail>.row {
    min-width: 560px;
  }

  /* Toolbar in tables: search + filters wrap onto multiple lines */
  .svp-toolbar {
    flex-wrap: wrap;
    align-items: stretch !important;
  }

  .svp-toolbar>div[style*="width: 280"] {
    width: 100% !important;
  }

  .svp-toolbar .seg {
    overflow-x: auto;
    max-width: 100%;
  }

  /* Applicant table — keep table layout but let it scroll horizontally inside
     its card. The header sticks visually. */
  .svp-table-scroll {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }

  .svp-table-scroll table {
    min-width: 760px;
  }

  /* College dashboard: KPI grid collapses to 2 columns, then 1 */
  .svp-kpi-grid {
    grid-template-columns: repeat(2, 1fr) !important;
  }

  .svp-college-cols {
    grid-template-columns: 1fr !important;
  }

  /* Validation form: column on tablet, with the context rail above the form */
  .svp-validation-body {
    flex-direction: column !important;
    overflow: auto !important;
  }

  .svp-context-rail {
    width: 100% !important;
    border-right: 0 !important;
    border-bottom: 1px solid var(--border-faint);
    /* Becomes a collapsible disclosure header below this size */
    max-height: 64px;
    overflow: hidden !important;
    padding: 0 !important;
    transition: max-height 320ms var(--ease-out);
  }

  .svp-context-rail[data-open="true"] {
    max-height: 1200px;
    padding: 16px 18px 22px !important;
    overflow: auto !important;
  }

  /* Only show the disclosure header when collapsed; show everything when open */
  .svp-context-rail:not([data-open="true"])>*:not(.svp-context-toggle) {
    display: none !important;
  }

  .svp-context-toggle {
    display: flex !important;
    width: 100%;
    align-items: center;
    justify-content: space-between;
    padding: 14px 18px;
    background: var(--bg-1);
    border: 0;
    cursor: pointer;
    color: var(--text-1);
    font-size: 13px;
    font-family: inherit;
  }

  .svp-context-toggle .svp-context-name {
    font-weight: 600;
  }

  .svp-context-toggle .svp-context-chev {
    transition: transform 240ms var(--ease-out);
    color: var(--text-3);
  }

  .svp-context-rail[data-open="true"] .svp-context-toggle .svp-context-chev {
    transform: rotate(180deg);
  }

  .svp-validation-main {
    padding: 18px 18px 140px !important;
  }

  /* Submit bar — wrap into rows, keep gold CTA full-width and prominent */
  .svp-submit-bar {
    height: auto !important;
    min-height: 64px;
    padding: 12px 18px !important;
    flex-direction: column;
    align-items: stretch !important;
    gap: 10px;
  }

  .svp-submit-bar .svp-submit-progress {
    flex-wrap: wrap;
  }

  .svp-submit-bar .svp-submit-actions {
    flex-wrap: wrap;
    width: 100%;
  }

  .svp-submit-bar .svp-submit-actions>* {
    flex: 1;
  }

  .svp-submit-bar .svp-submit-actions .svp-submit-gold {
    flex: 1 1 100%;
    order: -1;
    /* primary CTA on top */
  }

  /* Login: hide the brand panel, auth panel takes full width */
  .svp-login {
    grid-template-columns: 1fr !important;
  }

  .svp-login-brand {
    display: none !important;
  }

  .svp-login-auth {
    padding: 32px 24px !important;
  }

  /* Reveal the auth-panel's own brand mark once the left panel is gone, so slim
     viewports still say what they're signing into (base is inline display:none).
     Inflated ~1.5x: at its base (desktop corner-chrome) size the mark reads timid
     alone atop a tall slim screen and sits unbalanced against the 65px Xaverian
     mark below — scaling the WHOLE lockup (the chevron AND the macro's fixed-px
     text, which the size arg alone cannot grow) lends it app-header presence.
     Anchor the scale with a fixed-px transform-origin, NOT a translate nudge:
     scale() grows from the centre by default, so the left edge shifts by a
     fraction of the element's WIDTH — and this wrapper is full-column-width, so
     that shift changes with the viewport (a fixed translate is then right at one
     width and hangs the mark off-screen at others). A fixed-px origin re-seats it
     identically at every slim width — x≈0 grows the lockup rightward from its left
     edge (chevron flush with the content's left margin, not blooming from centre),
     and the y anchor lifts it where a plain margin can't (a transform doesn't
     reflow the box, so margin moves an invisible box while the pixels stay put).
     Values dialled in by eye on the UAT render. */
  .svp-login-auth-brand {
    display: flex !important;
    align-items: center;
    transform: scale(1.5);
    transform-origin: 1px 30px;
  }

  /* Tweaks panel can also drop to mobile-bottom-sheet if needed.
     Leaving alone for now — it's a designer-only affordance. */
}

/* ──────────────────────── ≤ 640px (phone) ──────────────────────── */
@media (max-width: 640px) {

  /* Tighter type scale on phones to keep titles from wrapping awkwardly */
  .svp-topbar h1 {
    font-size: 15px !important;
  }

  .svp-topbar-right .mono {
    display: none;
  }

  /* hide the "CYCLE CLOSES" date */

  /* Next action: smaller name, course chips wrap */
  .svp-validation-hero span[style*="font-size:28px"],
  .svp-validation-hero span[style*="font-size: 28px"] {
    font-size: 22px !important;
  }

  /* Cohort journey labels get smaller + percentage hidden */
  .svp-cohort-rail .svp-cohort-pct {
    display: none;
  }

  /* (Grade picker wrapping is handled in the base rule now — it wraps whenever
     the column is tight, at any width, so no breakpoint-specific rule needed.) */

  /* Applicant table: hide course-choices and updated columns to keep it
     scannable on phone. Name + status + ref still visible. */
  .svp-applicant-table th:nth-child(4),
  .svp-applicant-table td:nth-child(4),
  .svp-applicant-table th:nth-child(6),
  .svp-applicant-table td:nth-child(6) {
    display: none;
  }

  .svp-table-scroll table {
    min-width: 0;
  }

  /* KPI grid collapses to single column on phone */
  .svp-kpi-grid {
    grid-template-columns: 1fr !important;
  }

  /* Validation page: form padding even tighter */
  .svp-validation-main {
    padding: 14px 14px 160px !important;
  }

  /* ─── Grades table: convert each row into a stacked card.
     Layout per row at this width:
         Subject (full width, with estimate inline to the right)
         School-validated picker (full width)
         Comment input (full width)
     We rely on data-col attrs on the <td> elements. */
  .svp-grades-table thead {
    display: none;
  }

  .svp-grades-table,
  .svp-grades-table tbody {
    display: block;
  }

  .svp-grades-table tr {
    display: grid;
    grid-template-columns: 1fr auto;
    grid-template-areas:
      "subject estimate"
      "picker  picker"
      "comment comment";
    gap: 8px 12px;
    padding: 12px 14px;
    border-bottom: 1px solid var(--border-faint);
  }

  .svp-grades-table tr:last-child {
    border-bottom: 0;
  }

  .svp-grades-table td {
    border-bottom: 0 !important;
    padding: 0 !important;
    height: auto !important;
    display: block;
  }

  .svp-grades-table td[data-col="subject"] {
    grid-area: subject;
    align-self: center;
  }

  .svp-grades-table td[data-col="estimate"] {
    grid-area: estimate;
    align-self: center;
    justify-self: end;
  }

  .svp-grades-table td[data-col="picker"] {
    grid-area: picker;
  }

  .svp-grades-table td[data-col="comment"] {
    grid-area: comment;
  }

  /* Add a tiny inline label before estimate + picker so context is preserved */
  .svp-grades-table td[data-col="estimate"]::before {
    content: 'Estimate ';
    font-size: 10.5px;
    color: var(--text-3);
    letter-spacing: 0.04em;
    text-transform: uppercase;
    margin-right: 6px;
  }

  .svp-grades-table td[data-col="picker"]::before {
    content: 'School validated';
    display: block;
    font-size: 10.5px;
    color: var(--text-3);
    letter-spacing: 0.04em;
    text-transform: uppercase;
    margin-bottom: 6px;
  }

  /* Picker itself can wrap if needed — already handled in the phone block */

  /* Sticky bottom submit bar gets a translucent navy backdrop so it
     reads cleanly when content scrolls under it */
  .svp-submit-bar {
    background: var(--bg-0) !important;
    box-shadow: 0 -10px 24px rgba(0, 0, 0, 0.25);
  }

  [data-theme="light"] .svp-submit-bar {
    box-shadow: 0 -10px 24px rgba(15, 26, 58, 0.10);
  }
}

/* ──────────────── Helper: only show on mobile / desktop ──────────────── */
.svp-only-mobile {
  display: none !important;
}

.svp-only-desktop {
  display: inherit;
}

@media (max-width: 1024px) {
  .svp-only-mobile {
    display: inherit !important;
  }

  .svp-only-desktop {
    display: none !important;
  }
}