/* ============================================================================
   Premeducated Match Strategy — design system

   THEMING RULE: every theme-dependent value is a token, and tokens are
   redefined in exactly three places (the :root default, the prefers-color-scheme
   block, and the two explicit [data-theme] blocks). No component rule below the
   token block may reference a raw colour or duplicate itself per theme. The
   mock-up carried nine such duplicate rules; they are all gone.

   Contrast: every foreground/background pair used for text clears WCAG AA 4.5:1
   in both themes. Three light-mode values were darkened to get there
   (--teal 0D8A82 -> 0A736D, --gold 9C6F12 -> 8A6110), which also fixed the
   teal kicker text and the gold badge, both of which were failing.
   ========================================================================== */

:root {
  color-scheme: light;
  --paper:#F5F8FC; --card:rgba(255,255,255,.80); --rule:#DCE5F0;
  --ink:#0F2430; --body:#40555F;
  /* --soft was #7B8D96, which measured 3.17:1 against --paper. It carries real
     text (tile subtitles, shelf counts, source lines), so it has to clear 4.5. */
  --soft:#5C6E77;

  /* brand + semantics. *-lo is the tinted background for its own colour. */
  --navy:#1A4568; --navy-lo:#E6EEF5;
  --teal:#0A736D; --teal-lo:#E0F0EE;
  --skip:#B03A2B; --skip-lo:#FBEAE7;
  --gold:#8A6110; --gold-lo:#F7EEDA;
  /* The fourth DO band, added 2026-08-25 on Lucas's "a nice bright blue" for
     programs that are notably osteopathic for their specialty. Not --navy:
     navy is the structural blue and reads as another piece of chrome, and this
     has to be legible as its own class beside --teal on the same bar. Measured
     against --paper / --card / --rule at 5.07 / 5.51 / 4.39, which puts it in
     the same contrast band as --teal (5.24 / 5.70 / 4.54) and clears AA for
     text as well as the 3:1 the bar itself needs. */
  --osteo:#1668C4; --osteo-lo:#E4EEFB;

  /* text drawn ON a saturated fill (buttons, chart bars, map pin glyphs) */
  --on-accent:#FFFFFF;

  /* inverted slabs: the top bar, the CTA panel */
  --invert-bg:#0F2430; --invert-ink:#F3F6F6;

  /* selected pill / pressed toggle */
  /* Pill ink darker than --teal: #0A736D on the translucent neon-soft wash
     composites to 4.46:1, under the 4.5 floor. #08635E measures 5.06 on the
     worst composite (the mini switch over a tinted table row). */
  --pill-bg:#E0F0EE; --pill-ink:#08635E;
  --focus:#0A736D; --tint:rgba(10,115,109,.055);

  /* CURRICULUM BAR SHADES, AND WHAT THEY DO NOT MEAN.
     Seven steps of one hue, plus a flat grey for the part of a year a program
     does not break out. They are indexed by a segment's POSITION in its own bar,
     largest first, and never by what kind of rotation it is. That is deliberate
     and it is the whole honesty of the section: if teal meant "clinic" on every
     row, a reader would compare the teal across rows, and clinic is not counted
     the same way twice. A program running a half-day clinic every week publishes
     no clinic block at all, so a comparable colour would show it as having no
     outpatient training. The shade says how big, and nothing else. */
  --cur-1: #0A736D;  --cur-2: #2A8B84;  --cur-3: #4CA39C;
  --cur-4: #71BAB4;  --cur-5: #97D0CB;  --cur-6: #BCE0DD;
  --cur-7: #DCEFED;  --cur-rest: #C9D4D4;

  --shade:0 0 0 1px rgba(15,36,48,.025),0 14px 34px -18px rgba(15,36,48,.25);
  --surface:#FFFFFF; --surface-2:#F0F4F9; --surface-3:#E8EEF6;
  --line-hover:#C2D0E2; --brand:#1e8a9a; --brand-deep:#0e6b7a;
  --neon:#0A736D; --neon-soft:rgba(10,115,109,.16); --neon-faint:rgba(10,115,109,.06); --neon-glow:rgba(10,115,109,.25);
  --warn:#8A6110; --danger:#B03A2B;
  --page-glows:radial-gradient(ellipse 60% 50% at 18% 22%,rgba(30,138,154,.10),transparent 60%),radial-gradient(ellipse 50% 40% at 82% 78%,rgba(94,234,212,.08),transparent 60%),radial-gradient(ellipse 40% 30% at 50% 50%,rgba(34,211,238,.05),transparent 60%);
  --page-grid:linear-gradient(rgba(14,107,122,.04) 1px,transparent 1px),linear-gradient(90deg,rgba(14,107,122,.04) 1px,transparent 1px);
  --font-display:"Funnel Display",-apple-system,BlinkMacSystemFont,system-ui,sans-serif;
  --font-body:"Funnel Sans",-apple-system,BlinkMacSystemFont,system-ui,sans-serif;
  --font-mono:"JetBrains Mono",ui-monospace,"SF Mono",Menlo,monospace;
  --sans:var(--font-body); --ease:cubic-bezier(.22,.61,.36,1); --ease-spring:cubic-bezier(.34,1.4,.64,1);
  --measure: 64ch;
}

/* One dark definition, reached two ways: the OS preference when the user has
   not chosen, and data-theme="dark" when they have. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    /* Card, rule and surface lifted 2026-08-29 on Lucas's beta pass: "these
       boxes all over are in general too dark on the dark background." One
       token change brightens every box on the site at once; --body/--soft on
       the lifted card still measure over 5:1. Keep the two dark blocks
       identical. */
    color-scheme:dark; --paper:#060912; --card:rgba(24,33,62,.88); --rule:#2b3762;
    --ink:#e8eef8; --body:#a8b3cc; --soft:#91a0bd;
    --navy:#9CBDF8; --navy-lo:#162440; --teal:#71DED0; --teal-lo:#12332f;
    --skip:#FB8A9C; --skip-lo:#3b1d28; --gold:#FBCB4E; --gold-lo:#382c12;
    --osteo:#67E8F9; --osteo-lo:#103142; --on-accent:#06181D;
    --invert-bg:#0a0f1f; --invert-ink:#e8eef8; --pill-bg:rgba(94,234,212,.16); --pill-ink:#79F0DE;
    --focus:#5eead4; --tint:rgba(94,234,212,.06); --shade:0 8px 24px rgba(0,0,0,.45),0 0 32px rgba(94,234,212,.055);
    --surface:#141d38; --surface-2:#1a2547; --surface-3:#223058; --line-hover:#3d4f80;
    --brand:#1e8a9a; --brand-deep:#0e6b7a; --neon:#5eead4; --neon-soft:rgba(94,234,212,.16); --neon-faint:rgba(94,234,212,.06); --neon-glow:rgba(94,234,212,.55); --warn:#fbbf24; --danger:#fb7185;
    --page-glows:radial-gradient(ellipse 60% 50% at 18% 22%,rgba(30,138,154,.32),transparent 60%),radial-gradient(ellipse 50% 40% at 82% 78%,rgba(94,234,212,.18),transparent 60%),radial-gradient(ellipse 40% 30% at 50% 50%,rgba(34,211,238,.10),transparent 60%);
    --page-grid:linear-gradient(rgba(94,234,212,.045) 1px,transparent 1px),linear-gradient(90deg,rgba(94,234,212,.045) 1px,transparent 1px);
    --cur-1: #45C2B9;  --cur-2: #3AA79F;  --cur-3: #2F8C86;
    --cur-4: #26726D;  --cur-5: #1D5854;  --cur-6: #17423F;
    --cur-7: #123330;  --cur-rest: #2F4149;
  }
}
:root[data-theme="dark"] {
  color-scheme:dark; --paper:#060912; --card:rgba(24,33,62,.88); --rule:#2b3762;
  --ink:#e8eef8; --body:#a8b3cc; --soft:#91a0bd;
  --navy:#9CBDF8; --navy-lo:#162440; --teal:#71DED0; --teal-lo:#12332f;
  --skip:#FB8A9C; --skip-lo:#3b1d28; --gold:#FBCB4E; --gold-lo:#382c12;
  --osteo:#67E8F9; --osteo-lo:#103142; --on-accent:#06181D;
  --invert-bg:#0a0f1f; --invert-ink:#e8eef8; --pill-bg:rgba(94,234,212,.16); --pill-ink:#79F0DE;
  --focus:#5eead4; --tint:rgba(94,234,212,.06); --shade:0 8px 24px rgba(0,0,0,.45),0 0 32px rgba(94,234,212,.055);
  --surface:#141d38; --surface-2:#1a2547; --surface-3:#223058; --line-hover:#3d4f80;
  --brand:#1e8a9a; --brand-deep:#0e6b7a; --neon:#5eead4; --neon-soft:rgba(94,234,212,.16); --neon-faint:rgba(94,234,212,.06); --neon-glow:rgba(94,234,212,.55); --warn:#fbbf24; --danger:#fb7185;
  --page-glows:radial-gradient(ellipse 60% 50% at 18% 22%,rgba(30,138,154,.32),transparent 60%),radial-gradient(ellipse 50% 40% at 82% 78%,rgba(94,234,212,.18),transparent 60%),radial-gradient(ellipse 40% 30% at 50% 50%,rgba(34,211,238,.10),transparent 60%);
  --page-grid:linear-gradient(rgba(94,234,212,.045) 1px,transparent 1px),linear-gradient(90deg,rgba(94,234,212,.045) 1px,transparent 1px);
  --cur-1: #45C2B9;  --cur-2: #3AA79F;  --cur-3: #2F8C86;
  --cur-4: #26726D;  --cur-5: #1D5854;  --cur-6: #17423F;
  --cur-7: #123330;  --cur-rest: #2F4149;
}
:root[data-theme="light"] {
  color-scheme:light; --paper:#F5F8FC; --card:rgba(255,255,255,.80); --rule:#DCE5F0;
  --ink:#0F2430; --body:#40555F; --soft:#5C6E77; --navy:#1A4568; --navy-lo:#E6EEF5;
  --teal:#0A736D; --teal-lo:#E0F0EE; --skip:#B03A2B; --skip-lo:#FBEAE7; --gold:#8A6110; --gold-lo:#F7EEDA; --osteo:#1668C4; --osteo-lo:#E4EEFB;
  --on-accent:#FFFFFF; --invert-bg:#0F2430; --invert-ink:#F3F6F6; --pill-bg:#E0F0EE; --pill-ink:#08635E; --focus:#0A736D; --tint:rgba(10,115,109,.055);
  --shade:0 0 0 1px rgba(15,36,48,.025),0 14px 34px -18px rgba(15,36,48,.25); --surface:#FFFFFF; --surface-2:#F0F4F9; --surface-3:#E8EEF6; --line-hover:#C2D0E2;
  --brand:#1e8a9a; --brand-deep:#0e6b7a; --neon:#0A736D; --neon-soft:rgba(10,115,109,.16); --neon-faint:rgba(10,115,109,.06); --neon-glow:rgba(10,115,109,.25); --warn:#8A6110; --danger:#B03A2B;
  --page-glows:radial-gradient(ellipse 60% 50% at 18% 22%,rgba(30,138,154,.10),transparent 60%),radial-gradient(ellipse 50% 40% at 82% 78%,rgba(94,234,212,.08),transparent 60%),radial-gradient(ellipse 40% 30% at 50% 50%,rgba(34,211,238,.05),transparent 60%);
  --page-grid:linear-gradient(rgba(14,107,122,.04) 1px,transparent 1px),linear-gradient(90deg,rgba(14,107,122,.04) 1px,transparent 1px);
  --cur-1:#0A736D; --cur-2:#2A8B84; --cur-3:#4CA39C; --cur-4:#71BAB4; --cur-5:#97D0CB; --cur-6:#BCE0DD; --cur-7:#DCEFED; --cur-rest:#C9D4D4;
}

/* ---------------------------------------------------------------- base ---- */
* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 18px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

.wrap { max-width: 700px; margin: 0 auto; padding: 0 22px; }
.wide { max-width: 920px; margin: 0 auto; padding: 0 22px; }

h1, h2, h3 { margin: 0; font-weight: 750; letter-spacing: -.024em; text-wrap: balance; line-height: 1.12; }
h1 { font-size: clamp(2.2rem, 6vw, 3.2rem); }
h2 { font-size: clamp(1.5rem, 3.4vw, 2rem); }
h3 { font-size: 1.2rem; letter-spacing: -.015em; }
p  { margin: 0; }

.lede  { font-size: 1.15rem; color: var(--body); }
.small { font-size: .93rem; color: var(--soft); }
.kicker { font-size: 13px; letter-spacing: .15em; text-transform: uppercase; color: var(--teal); font-weight: 650; margin-bottom: 12px; }
section { padding: 52px 0; }

:where(a) { color: var(--teal); }
:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; border-radius: 4px; }

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

/* -------------------------------------------------------------- chrome ---- */
/* The step nav (Welcome / About you / Your report) is gone, Lucas 2026-08-30:
   the intake pager carries all forward and back motion, and the report's
   profile circle reopens the questions. The envbar is the only chrome band
   left, so it lays out as a row with the theme control at its right. */
.bar {
  background: var(--invert-bg); color: var(--invert-ink);
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  font-size: 12px; letter-spacing: .12em; text-transform: uppercase;
  /* The bar's paint runs edge to edge, but its CONTENT lines up with the .wide
     column (920px incl. 22px padding), so the wordmark and the tabs below sit
     on the same left edge as the page text instead of hugging the viewport.
     His 2026-08-30 flag: full-bleed chrome, column-aligned content. */
  padding: 9px max(20px, calc((100% - 920px) / 2 + 22px));
}

/* theme control: three states, at the right edge of the envbar */
.themectl { margin-left: auto; display: inline-flex; gap: 2px; padding: 3px; background: var(--card); border: 1px solid var(--rule); border-radius: 40px; }
.themectl button {
  appearance: none; border: 0; background: none; cursor: pointer; font: inherit;
  color: var(--soft); padding: 5px 9px; border-radius: 30px; display: grid; place-items: center; line-height: 0;
}
.themectl button svg { width: 15px; height: 15px; }
.themectl button:hover { color: var(--ink); }
.themectl button[aria-pressed="true"] { background: var(--pill-bg); color: var(--pill-ink); }

/* The advising CTA in the chrome, Lucas 2026-08-31: the tiers page gets a
   button on every screen, not only at the report's foot. One pill at the
   envbar's right edge, and a twin in the report strip (.rcta, with the
   profile circle) that stays put while the tabs scroll. Same destination
   as the report-end CTA. */
.barcta {
  flex: none; text-decoration: none; font: inherit; font-weight: 700;
  background: var(--teal); color: var(--on-accent); padding: 6px 13px; border-radius: 30px;
}
.barcta:hover { filter: brightness(1.08); }
/* On the report screen the strip right below the envbar carries the same
   pill, and two identical buttons 45px apart read as a mistake, so the
   envbar's stands down there and the strip's (which also survives the
   scroll, docked) is the one that shows. */
body:has(#s3.on) .barcta { display: none; }

/* --------------------------------------------------------------- screens -- */
.screen { display: none; }
.screen.on { display: block; animation: fade .3s ease both; }
/* Screens take programmatic focus on navigation (tabindex="-1") so keyboard
   readers are not stranded when the control they pressed hides with its
   screen; the container itself is not interactive, so no ring. */
.screen:focus { outline: none; }
@keyframes fade { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

.btn {
  appearance: none; border: 0; cursor: pointer; font: inherit; font-weight: 650; font-size: 1.05rem;
  background: var(--teal); color: var(--on-accent); padding: 17px 32px; border-radius: 50px;
}
.btn:hover:not(:disabled) { filter: brightness(1.08); }
.btn:disabled { opacity: .45; cursor: not-allowed; }
/* The CTA is a LINK now (Lucas 2026-08-29: the report's call to action goes to
   the residency-advising sales page, not a booking widget), so the button
   class has to dress an anchor without the UA's underline and blue. */
a.btn { display: inline-block; text-decoration: none; text-align: center; }
.btn.line { background: none; color: var(--teal); box-shadow: inset 0 0 0 1.5px var(--rule); }
.btn.sm { font-size: .95rem; padding: 12px 22px; }

/* ---------------------------------------------------------------- offer --- */
.offer { padding: 64px 0 30px; }
.offer h1 { max-width: 15ch; }
.offer .lede { margin-top: 20px; max-width: 40ch; }
.three { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 14px; margin-top: 42px; }
.three > div { background: var(--card); border-radius: 14px; padding: 20px; box-shadow: var(--shade); display: flex; gap: 14px; align-items: flex-start; }
.three svg { flex: 0 0 24px; width: 24px; height: 24px; color: var(--teal); margin-top: 3px; }
.three h3 { font-size: 1.02rem; margin-bottom: 4px; }
.three p { font-size: .93rem; color: var(--body); line-height: 1.45; }
.pricerow { margin-top: 36px; display: flex; align-items: center; gap: 22px; flex-wrap: wrap; }
.pricerow .amt { font-size: 2.9rem; font-weight: 750; letter-spacing: -.04em; }

/* --------------------------------------------------------------- intake --- */
.q { background: var(--card); border-radius: 16px; padding: 24px; box-shadow: var(--shade); margin-top: 16px; }
.q .t { display: block; font-weight: 650; font-size: 1.06rem; }
.q .why { font-size: .92rem; color: var(--soft); margin: 2px 0 14px; }
.q input[type="text"], .q input[type="email"], .q select {
  font: inherit; font-size: 1rem; width: 100%; padding: 12px 14px; border-radius: 10px;
  border: 1.5px solid var(--rule); background: var(--paper); color: var(--ink);
}
.q select {
  appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%), linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: calc(100% - 19px) calc(50% + 1px), calc(100% - 13px) calc(50% + 1px);
  background-size: 6px 6px, 6px 6px;
  background-repeat: no-repeat;
  padding-right: 38px;
}
.q input:focus-visible, .q select:focus-visible { outline: 2px solid var(--focus); outline-offset: -1px; }

/* A three-digit score in a full-width box reads as a question we expect an
   essay for. Sized to its answer instead, with tabular figures so the digits
   do not shift under the caret as they are typed. */
.q input.num { width: 12ch; min-width: 12ch; font-variant-numeric: tabular-nums; }
/* Shown only while the number is outside the plausible band, and never
   blocking: the engine drops an implausible score, and this is the sentence
   that says so rather than silently ignoring it. */
.fieldhint { font-size: .88rem; color: var(--gold); margin: 10px 0 0; max-width: 58ch; }

/* AN UNANSWERED REQUIRED QUESTION, MARKED ON THE QUESTION ITSELF.
 *
 * Lucas, 2026-08-14: "the 'show me the plan' button is greyed out and there's no
 * way for me to know which fields are missing if any even are. needs
 * indicators." Measured before this existed: zero per-field markers in every
 * state of the form.
 *
 * GOLD, NOT RED, and the choice is on the record because §38(a)(4) is. Red here
 * is --skip, which means "we are telling you not to spend an application on
 * this". Gold is what the form already uses for "read this before you go on",
 * which is the .fieldhint above. A student with two unanswered questions on a
 * form they have not started has done nothing wrong, and painting that the
 * colour of a rejection is the same error as painting the strongest programs
 * the colour of the ones to skip.
 *
 * The stripe is an inset shadow, not a border, so marking a question cannot
 * move a single box in the layout audit. */
.q[data-missing] { box-shadow: inset 3px 0 0 var(--gold), var(--shade); }
.need {
  display: inline-block; margin-left: 10px; vertical-align: 2px;
  font-size: .68rem; font-weight: 700; letter-spacing: .09em; text-transform: uppercase;
  color: var(--gold); background: var(--gold-lo); border-radius: 20px; padding: 3px 9px;
}

/* WHAT IS STILL NEEDED, beside the button that is refusing to go.
 *
 * Teal rather than the gold of .gate, because these are two different messages
 * and they can appear together: .gate is a verdict about what we have not
 * researched, and this is a list of things the student can fix in one click.
 * Two gold panels stacked would read as one long complaint. */
.needs {
  margin-top: 22px; border-radius: 16px; padding: 18px 20px;
  background: var(--teal-lo); border: 1.5px solid color-mix(in srgb, var(--teal) 30%, transparent);
}
.needs .t { display: block; font-weight: 650; color: var(--teal); font-size: 1.02rem; }
.needs .small { margin-top: 2px; }
.needlist { display: flex; flex-wrap: wrap; gap: 9px; margin-top: 12px; }
.needgo {
  font: inherit; font-size: .94rem; cursor: pointer;
  border: 1.5px solid color-mix(in srgb, var(--teal) 45%, transparent); border-radius: 40px;
  padding: 9px 16px; background: var(--card); color: var(--teal); font-weight: 650;
}
.needgo:hover { border-color: var(--teal); background: var(--paper); }
.needgo:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }

.picks { display: flex; flex-wrap: wrap; gap: 9px; }
.picks label {
  position: relative; border: 1.5px solid var(--rule); border-radius: 40px; padding: 10px 17px;
  cursor: pointer; font-size: .96rem; background: var(--paper); color: var(--ink);
}
.picks input { position: absolute; inset: 0; opacity: 0; cursor: pointer; }
.picks label:has(input:checked) { border-color: var(--teal); background: var(--teal-lo); color: var(--teal); font-weight: 650; }
.picks label:has(input:focus-visible) { outline: 2px solid var(--focus); outline-offset: 2px; }
.picks label:has(input:disabled) { opacity: .4; cursor: not-allowed; }

/* ---- the ordered cities ----
   The named list reads as a numbered list because that is what it is, and the
   unnamed cities keep the pill shape they have everywhere else in this form, so
   the control looks like the checkbox rows above it with one extra step rather
   than like a new kind of question. Nothing here is draggable: see the note in
   taxonomy.js about a median student holding twelve cities. */
.ordered { list-style: none; margin: 0 0 14px; padding: 0; display: flex; flex-direction: column; gap: 7px; }
.ordered:focus-visible { outline: 2px solid var(--focus); outline-offset: 6px; border-radius: 10px; }
.ordered li {
  display: flex; align-items: center; gap: 11px; padding: 9px 12px 9px 10px;
  border: 1.5px solid var(--teal); background: var(--teal-lo); border-radius: 12px;
}
.ordered li b {
  flex: 0 0 auto; min-width: 22px; height: 22px; border-radius: 50%; background: var(--teal);
  color: var(--card); font-size: .82rem; font-weight: 700; display: grid; place-items: center;
  font-variant-numeric: tabular-nums; padding: 0 5px;
}
.ordered li span { flex: 1 1 auto; color: var(--teal); font-weight: 650; font-size: .96rem; }
.ordered li .drop {
  flex: 0 0 auto; border: 0; background: none; color: var(--teal); cursor: pointer;
  font-size: 1.25rem; line-height: 1; padding: 2px 6px; border-radius: 8px;
}
.ordered li .drop:hover { background: var(--card); }
.ordered li .drop:focus-visible { outline: 2px solid var(--focus); outline-offset: 1px; }
.picks.addpicks button {
  border: 1.5px solid var(--rule); border-radius: 40px; padding: 10px 17px;
  cursor: pointer; font-size: .96rem; background: var(--paper); color: var(--ink);
  font-family: inherit;
}
.picks.addpicks button:hover { border-color: var(--teal); color: var(--teal); }
.picks.addpicks button:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
.q .emptylvl:focus-visible { outline: 2px solid var(--focus); outline-offset: 4px; border-radius: 8px; }

.two { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.cascade { display: flex; flex-direction: column; gap: 14px; }
.cascade .lvl { display: grid; grid-template-columns: 110px 1fr; gap: 14px; align-items: start; }
.cascade .lvl > span { font-size: .88rem; color: var(--soft); text-align: right; padding-top: 11px; }
.cascade .lvl[hidden] { display: none; }
.emptylvl { font-size: .92rem; color: var(--soft); padding-top: 11px; }

/* ---- school combobox ----
   A native <select> of sixty-odd campuses cannot be searched by the name a
   student actually uses. Nobody types "Midwestern University Arizona College of
   Osteopathic Medicine"; they type AZCOM. So this is a filtered listbox that
   searches the formal name, the abbreviation, former names and the city, and it
   always keeps a "use what I typed" escape at the bottom of the list. */
.combo { position: relative; }
.combo input { width: 100%; }
.combolist {
  position: absolute; z-index: 30; left: 0; right: 0; top: calc(100% + 6px);
  margin: 0; padding: 6px; list-style: none; max-height: 300px; overflow-y: auto;
  background: var(--card); border: 1.5px solid var(--rule); border-radius: 12px;
  box-shadow: 0 8px 30px -8px rgba(0, 0, 0, .28);
}
.combolist[hidden] { display: none; }
/* The card's backdrop-filter USED TO make it a stacking context, so the
   list's own z-index could not escape it and the intake's Back/Next buttons
   (later in the DOM) painted OVER an open dropdown. Lucas hit this on the
   third-year hospital picker, 2026-08-30. The filter was removed 2026-08-31
   (the hero-blanking compositor bug, see the card rule), which dissolves that
   stacking context, but the lift stays: it is what guarantees the open list
   wins regardless of what else forms a context around the card. */
.q:has(.combolist:not([hidden])) { position: relative; z-index: 40; }
.combolist li {
  padding: 9px 11px; border-radius: 8px; cursor: pointer; display: block; line-height: 1.3;
}
.combolist li b { display: block; font-size: .97rem; font-weight: 650; }
.combolist li em { display: block; font-style: normal; font-size: .82rem; color: var(--soft); margin-top: 1px; }
.combolist li[aria-selected="true"], .combolist li:hover { background: var(--teal-lo); }
.combolist li[aria-selected="true"] b, .combolist li:hover b { color: var(--teal); }
.combolist li.freetext b { color: var(--body); font-weight: 600; }
.combolist li.none { cursor: default; color: var(--soft); font-size: .93rem; }
.combolist li.none:hover { background: none; }
.combomark { margin-top: 9px; font-size: .88rem; display: flex; gap: 7px; align-items: flex-start; }
.combomark.ok { color: var(--teal); }
.combomark.warn { color: var(--gold); }
.combomark svg { width: 15px; height: 15px; flex: 0 0 15px; margin-top: 2px; }

/* coverage gate */
.gate { margin-top: 16px; border-radius: 16px; padding: 22px 24px; background: var(--gold-lo); border: 1.5px solid color-mix(in srgb, var(--gold) 40%, transparent); }
.gate h3 { color: var(--gold); font-size: 1.05rem; margin-bottom: 6px; }
.gate p { font-size: .97rem; color: var(--body); max-width: 58ch; }
.gate .row { display: flex; gap: 10px; margin-top: 14px; flex-wrap: wrap; }
.gate input[type="email"] { flex: 1 1 240px; font: inherit; font-size: 1rem; padding: 12px 14px; border-radius: 10px; border: 1.5px solid var(--rule); background: var(--card); color: var(--ink); }
.livemark { display: inline-flex; align-items: center; gap: 6px; font-size: .8rem; font-weight: 650; color: var(--teal); text-transform: uppercase; letter-spacing: .08em; }
.livemark i { width: 7px; height: 7px; border-radius: 50%; background: var(--teal); display: block; }

/* --------------------------------------------------------------- report --- */
/* The first-visit walkthrough (Lucas 2026-08-31: "easy to read and brief
   maybe larger text size"). Its lines run LARGER than body copy on purpose,
   and the number chips borrow the ordered-cities idiom so the page's one
   numbered-steps look stays one look. Gone for good on Got it. */
.howfirst { border: 1.5px solid var(--rule); background: var(--card); border-radius: 16px; padding: 20px 22px 18px; margin: 0 0 28px; max-width: 62ch; }
.howfirst ol { list-style: none; margin: 12px 0 16px; padding: 0; display: flex; flex-direction: column; gap: 13px; }
.howfirst li { display: flex; align-items: flex-start; gap: 13px; }
.howfirst li > b {
  flex: 0 0 auto; min-width: 26px; height: 26px; border-radius: 50%; background: var(--teal);
  color: var(--card); font-size: .92rem; font-weight: 700; display: grid; place-items: center;
  font-variant-numeric: tabular-nums; margin-top: 2px;
}
.howfirst li span { font-size: 1.14rem; line-height: 1.55; }
.yeartog { display: inline-flex; background: var(--card); border-radius: 50px; padding: 5px; box-shadow: var(--shade); gap: 4px; }
.yeartog button {
  appearance: none; border: 0; background: none; font: inherit; font-size: .95rem; font-weight: 600;
  color: var(--soft); padding: 10px 22px; border-radius: 40px; cursor: pointer;
}
.yeartog button[aria-pressed="true"] { background: var(--pill-bg); color: var(--pill-ink); }
[data-year="3"] .y4, [data-year="4"] .y3 { display: none !important; }

/* The safest/preferred switch borrows the year toggle's shape on purpose: two
   controls that both swap the whole page between two readings should not look
   like two different kinds of thing. It is smaller because it is the second
   question a reader asks, not the first. */
.viewtog { display: inline-flex; background: var(--card); border-radius: 50px; padding: 4px; box-shadow: var(--shade); gap: 4px; }
.viewtog button {
  appearance: none; border: 0; background: none; font: inherit; font-size: .88rem; font-weight: 600;
  color: var(--soft); padding: 8px 18px; border-radius: 40px; cursor: pointer;
}
.viewtog button[aria-pressed="true"] { background: var(--pill-bg); color: var(--pill-ink); }

.plan { background: var(--card); border-radius: 20px; padding: 30px 28px; box-shadow: var(--shade); margin-top: 18px; }
.plan ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 18px; }
.plan li { display: grid; grid-template-columns: 34px 1fr; gap: 14px; align-items: start; font-size: 1.14rem; }
.plan li svg { width: 24px; height: 24px; margin-top: 4px; }
.stress { margin-top: 24px; padding: 17px 19px; background: var(--teal-lo); border-radius: 12px; font-size: 1rem; }

.mapbox, .chartbox { background: var(--card); border-radius: 20px; padding: 12px; box-shadow: var(--shade); overflow-x: auto; }
.mapbox { position: relative; }
.mapbox svg, .chartbox svg { display: block; width: 100%; height: auto; }
.mapbox svg { min-width: 460px; touch-action: pan-y; }
.mapbox.map-zoomed svg { touch-action: none; }
.mapbox svg.map-pannable { cursor: grab; }
.mapbox svg.map-panning { cursor: grabbing; }
.mapzoom { position: absolute; z-index: 2; top: 20px; right: 20px; display: flex; gap: 4px; padding: 4px; border: 1px solid var(--rule); border-radius: 10px; background: var(--card); box-shadow: var(--shade); }
.mapzoom button { appearance: none; min-width: 34px; min-height: 34px; padding: 5px 8px; border: 1px solid var(--rule); border-radius: 7px; background: var(--card); color: var(--ink); font: 600 .88rem var(--font-mono); cursor: pointer; }
.mapzoom button:hover, .mapzoom button:focus-visible { border-color: var(--teal); color: var(--teal); }
.chartbox svg { min-width: 500px; }
.maplegend { display: flex; gap: 20px; flex-wrap: wrap; justify-content: center; margin-top: 14px; font-size: .94rem; color: var(--body); }
.maplegend > span { display: inline-flex; align-items: center; gap: 7px; }
.pin { width: 13px; height: 13px; border-radius: 50%; display: inline-block; }

/* at-a-glance shelves */
.glance .shelf { margin-bottom: 16px; }
.shelfhead { display: flex; gap: 10px; align-items: baseline; margin-bottom: 9px; flex-wrap: wrap; }
.shelfhead b { font-size: 1rem; }
.shelfhead span { font-size: .86rem; color: var(--soft); }
.tiles { display: flex; gap: 16px; flex-wrap: wrap; }
.tile {
  appearance: none; font: inherit; text-align: left; cursor: pointer; border: 0;
  background: var(--card); border-radius: 12px; padding: 14px 16px; box-shadow: var(--shade);
  min-width: 172px; flex: 1 1 172px; color: var(--ink);
  transition: transform .12s ease;
}
.tile:hover { transform: translateY(-1px); }
.tile.hero { width: 100%; flex: 1 1 100%; background: var(--teal-lo); box-shadow: none; border: 1.5px solid var(--teal); }
/* THE TIER-A TILE. Gold, because gold is the only semantic left: teal is the
   spend, navy is the real chance, --skip is the fee you should not pay, --soft
   is the long shot. `:not(.hero)` rather than source order, because the hero
   fill is an instruction and an instruction outranks a program fact for the
   same surface. The mark inside the tile shows either way, so nothing is lost.
   1px rather than the hero's 1.5px: a tier A tile is common and the hero is
   one per report, and they must not read as the same weight. */
/* THE FILL IS GONE AND THE OUTLINE STAYS. Lucas, driving it in dark mode on
   2026-08-13: "i don't understand the color scheme it looks like everything is
   red on my screen but these are the ones you're recommending?"
   He was reading it correctly. In dark mode --gold-lo is #332715 and --skip-lo
   is #361F1B, two dark warm browns three points apart, so the tiles for the
   STRONGEST programs on the page were painted almost exactly the colour of the
   ones we tell him not to pay for. A recommendation wearing the warning colour
   is the visual form of the accurate-but-misleading failure.
   So the strongest tiles are ordinary cards now and the gold survives only in
   the outlined mark inside them, which is the element that actually names what
   it means. The only filled tile left on the page is the hero, which is one per
   report and is an instruction rather than a category. */
.tile.open:not(.hero) {
  border: 1px solid color-mix(in srgb, var(--gold) 40%, transparent);
}
/* THE RANK BADGE. Top right, out of the text flow, and deliberately quiet: it
   answers "where does this sit" for a reader who is scanning, and must not
   compete with the program's name for the same glance. */
.tile { position: relative; }
.tile .rank {
  position: absolute; top: 10px; right: 12px;
  font-size: .78rem; font-weight: 700; color: var(--soft); letter-spacing: .01em;
}
.tile.hero .rank { top: 14px; right: 16px; font-size: .85rem; }
.tile.flat .rank { position: static; margin-right: 6px; }
.tile b { display: block; font-size: 1rem; font-weight: 700; padding-right: 34px; }
.tile.flat b { padding-right: 0; display: inline; }
.tile.hero b { font-size: 1.2rem; }
.tile em { display: block; font-style: normal; font-size: .8rem; color: var(--soft); margin-top: 2px; }
.tile .why { display: block; font-size: .87rem; color: var(--body); margin-top: 8px; }
.tile.hero .why { font-size: .98rem; max-width: 70ch; }
/* THE MARK ITSELF. Outlined, never filled, and that is the load-bearing half of
   this rule. A filled gold pill is already taken: .chip.gold and .chip.signal
   are the signal instruction (a handful of rows per report since the budget
   went per-specialty) and .sigmark.g/.sig are its badges. Filled gold here too
   would make gold mean "signal" and "open door" at the same time, and a row
   carrying both would have the chip disappear into it. An outline is the same
   colour family in a different form, so the two read as related rather than as
   the same thing.
   Sentence case, not the chips' uppercase, for the same reason. */
.openmark {
  display: inline-block; margin-top: 6px;
  font-size: 10.5px; font-weight: 700; letter-spacing: .015em; line-height: 1.5;
  padding: 2px 9px; border-radius: 30px; white-space: nowrap;
  color: var(--gold); background: none;
  border: 1.5px solid color-mix(in srgb, var(--gold) 46%, transparent);
}
.tile .openmark { margin-top: 8px; }

/* flex:0 0 auto sizes a skip tile to its content, which on a phone is wider
   than the screen. The cap lets the label wrap instead of pushing the page. */
.tile { max-width: 100%; }
.tile.flat { background: none; box-shadow: none; border: 1px dashed var(--rule); min-width: 0; flex: 0 1 auto; padding: 10px 14px; }
.tile.flat b { font-size: .89rem; color: var(--soft); font-weight: 600; }
.tile.flat:hover b { color: var(--skip); }

/* interactive program table */
.tblwrap { overflow-x: auto; border-radius: 14px; box-shadow: var(--shade); }

/* THE DISPLAY CAP, Lucas's ruling 2026-08-13: the table opens on the strongest
   ten and the rest are revealed by the button or the arrow keys. Hidden by class
   and never removed from the DOM, so every row a tile jumps to still exists.
   The detail row keeps its own `hidden` attribute as the accordion's business:
   revealing a program must not also open its panel, so the rule below never
   overrides `[hidden]`. */
.ptable tbody tr.over { display: none; }
.morewrap { display: flex; justify-content: center; margin-top: 18px; }
/* The curriculum browser opens on its first CUR_CAP cards, same reveal idiom
   as the table rows above (long lists need pagination always, 2026-08-31). */
.curlist .curow.over { display: none; }
/* The numbers pane stacks three sections and pane sections carry no vertical
   padding of their own, so without this the personal paragraphs ran into the
   curriculum kicker 1px apart (Lucas 2026-08-31: "there needs to be padding
   between these two"). The fold below already spaces itself with its own
   margin-top and ruled border. */
#sec-curriculum { padding-top: 44px; }
.morerows[hidden] { display: none; }
/* 800 rather than 720 since the Fit column landed: at 720 the program names
   wrapped to three lines and the table scrolls inside .tblwrap anyway. */
.ptable { width: 100%; border-collapse: collapse; background: var(--card); min-width: 800px; }
.ptable td.nm { min-width: 170px; }
.ptable th {
  text-align: left; font-size: 11px; letter-spacing: .11em; text-transform: uppercase;
  color: var(--soft); font-weight: 700; padding: 13px 10px; border-bottom: 1.5px solid var(--rule); white-space: nowrap;
}
/* 10px side padding, not 14: at a 1280 viewport the wrap gives the table 874px
   and 14px pushed it to 934, which cut the What-to-do chips mid-word behind a
   scrollbar. Measured 2026-08-28, batch 3 screenshot pass. */
.ptable td { padding: 0 10px; border-bottom: 1px solid var(--rule); font-size: .93rem; vertical-align: middle; }
.ptable tbody tr.prow td { padding-block: 11px; }
.ptable tbody tr:last-child td { border-bottom: 0; }
.ptable tr.prow td:first-child { border-left: 4px solid transparent; padding-left: 0; }
/* The row accent is the fit band, matching the meter in the Fit column. It is
   not the instruction: instructions change with the year and a border cannot. */
.ptable tr.prow.strong td:first-child { border-left-color: var(--teal); }
.ptable tr.prow.real   td:first-child { border-left-color: var(--navy); }
.ptable tr.prow.long   td:first-child { border-left-color: var(--soft); }
.ptable tr.prow.skip   td:first-child { border-left-color: var(--skip); }
.ptable tr.prow.skip td { color: var(--soft); }
/* No open-row wash. It used to be background:var(--gold-lo), and in a query
   where every program is open to outside DOs that painted the WHOLE table the
   dark-mode brown Lucas already vetoed on tiles 2026-08-13 (see above). The
   "Open to outside DOs" pill under the name carries the fact on its own. */
.ptable tr.prow:hover { background: var(--tint); }

.rowtoggle {
  appearance: none; border: 0; background: none; font: inherit; cursor: pointer; color: inherit;
  display: flex; align-items: center; gap: 9px; padding: 11px 0 11px 12px; width: 100%; text-align: left;
}
.rowtoggle:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; border-radius: 6px; }
/* The program name holds one line while there is room, and wraps when there
   is not. It used to be white-space:nowrap, which also made the column's
   minimum width the longest name on the list, and a fourth-year list
   ("Banner Desert...") pushed the whole table 35px past its wrap on a full
   desktop. Lucas 2026-08-31: Your list must not scroll sideways. Auto table
   layout only wraps a wrappable name once the table is genuinely out of
   room, and td.nm's min-width keeps a squeezed name at two lines rather
   than the three "Mayo Scottsdale" once broke into. */
.rowtoggle > span { font-weight: 650; line-height: 1.25; }
.rowtoggle em { white-space: normal; }
.rowtoggle em { display: block; font-style: normal; font-weight: 400; font-size: .79rem; color: var(--soft); }
.chev { width: 12px; height: 12px; flex: 0 0 12px; color: var(--soft); transition: transform .18s ease; }
.rowtoggle[aria-expanded="true"] .chev { transform: rotate(90deg); color: var(--teal); }

.ptable td.num { font-variant-numeric: tabular-nums; }
.pctcell { white-space: nowrap; }
/* THE UNIVERSAL METER, Lucas's ruling 2026-08-28: one scale for every
   specialty and no verdict encoded in the display. The four bands
   (skip/soft/teal/osteo) died here; the engine's HIGH_DO_SHARE prose still
   says "notably osteopathic" where that holds, and doShareClass remains the
   single engine-side copy of the policy. The tick (<u>) marks the specialty's
   national DO share, so 15% reads as above average in orthopaedics and below
   average in family medicine without the bar passing judgment. The 1px card
   ring keeps the tick legible whether it lands on the empty track or on the
   teal fill. */
.dobar { display: inline-block; position: relative; height: 7px; width: 52px; border-radius: 4px; overflow: hidden; background: var(--rule); vertical-align: middle; }
.dobar i { display: block; height: 100%; background: var(--teal); }
.dobar u { position: absolute; top: 0; bottom: 0; width: 2px; margin-left: -1px; background: var(--ink); box-shadow: 0 0 0 1px var(--card); }
.pct { font-size: .85rem; font-weight: 650; margin-left: 8px; font-variant-numeric: tabular-nums; }
.ptable td.rs { color: var(--body); min-width: 224px; }

.chip {
  font-size: 11.5px; font-weight: 750; letter-spacing: .1em; text-transform: uppercase;
  padding: 7px 13px; border-radius: 30px; white-space: nowrap; display: inline-block;
  background: var(--navy-lo); color: var(--navy);
}
/* Chips are instructions, one per currency. Apply is the unstyled default. */
.chip.month { background: var(--teal-lo); color: var(--teal); }
.chip.home { background: var(--teal-lo); color: var(--teal); }
.chip.gold { background: var(--gold-lo); color: var(--gold); }
.chip.silver { background: var(--navy-lo); color: var(--navy); }
/* The flat-specialty signal (data/signals.js): gold family, because it is the
   same instruction gold carries in a tiered specialty: spend one here. */
.chip.signal { background: var(--gold-lo); color: var(--gold); }
.chip.skip { background: var(--skip-lo); color: var(--skip); }
.chip.low { background: var(--rule); color: var(--body); }

/* The fit meter. Four dots, filled to the band, in the band's own colour so the
   rating and the row accent agree without a second legend. */
/* The fit track. A fixed scale, so two rows a pixel apart are a quarter of a
   point apart, which is the whole reason it replaced four dots. The tick is the
   apply cut, positioned by the engine so the page holds no second geometry. */
.ftrack {
  position: relative; display: inline-block; vertical-align: middle;
  width: 74px; height: 7px; border-radius: 4px; background: var(--rule);
}
.ftrack .ftick {
  position: absolute; top: -2px; width: 1px; height: 11px;
  background: var(--rule); filter: brightness(.82);
}
.ftrack .fmark {
  position: absolute; top: 50%; width: 9px; height: 9px; border-radius: 50%;
  /* Centred on its own value, and never clipped at either end of the track. */
  transform: translate(-50%, -50%); background: var(--navy);
  box-shadow: 0 0 0 2px var(--card);
}
.ftrack.strong .fmark { background: var(--teal); }
.ftrack.real   .fmark { background: var(--navy); }
.ftrack.long   .fmark { background: var(--soft); }
.ftrack.skip   .fmark { background: var(--skip); }
.fnum {
  margin-left: 9px; font-variant-numeric: tabular-nums; font-weight: 650;
  font-size: .93rem; color: var(--ink);
}
.prow.skip .fnum, .prow.long .fnum { color: var(--soft); }
/* A hard exclusion overrode the arithmetic, so there is no number to show. */
.fout { font-size: .82rem; color: var(--soft); white-space: nowrap; }

.fit { display: inline-flex; gap: 4px; align-items: center; }
.fit i {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--rule); display: block;
}
.fit.strong i.on { background: var(--teal); }
.fit.real i.on { background: var(--navy); }
.fit.long i.on { background: var(--soft); }
.fit.skip i.on { background: var(--skip); }
.ptable td.fitcell { white-space: nowrap; }

.drow > td { padding: 0 !important; background: var(--tint); }
.dpan { padding: 20px 22px 22px 30px; animation: dslide .2s ease both; }
@keyframes dslide { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }
.dstats { display: flex; gap: 26px; flex-wrap: wrap; margin-bottom: 14px; }
.dstats b { display: block; font-size: 1.25rem; font-weight: 750; letter-spacing: -.02em; line-height: 1.1; }
.dstats span { font-size: .78rem; color: var(--soft); }
.dwhy { font-size: 1rem; max-width: 74ch; }
.dpol { margin-top: 12px; font-size: .93rem; color: var(--body); display: flex; gap: 10px; max-width: 74ch; }
.polmark { flex: 0 0 3px; background: var(--rule); border-radius: 2px; align-self: stretch; }
.dpol.hard .polmark { background: var(--skip); }

/* THE WARNINGS. Sits above the program's own note, which is the one place in the
   panel that reads before the reader has decided whether to keep reading.
   No new colour tokens: --skip and --skip-lo are already defined in all four
   theme blocks (light, prefers-dark, [data-theme=dark] and print), so this block
   inherits the theme contract instead of restating it and getting it wrong in
   one of them. Same 74ch measure and same 3px rule as .dpol, because it is the
   same kind of object, said louder. */
.dwarns {
  margin: 0 0 14px; max-width: 74ch;
  background: var(--skip-lo); border-radius: 7px; padding: 11px 13px;
  display: flex; flex-direction: column; gap: 8px;
}
.dwarn { font-size: .93rem; color: var(--ink); display: flex; gap: 10px; line-height: 1.45; }
.warnmark { flex: 0 0 3px; background: var(--skip); border-radius: 2px; align-self: stretch; }

/* THE TICKS AND CROSSES, §38(b)(4). Four lines answering the four things the
   student asked for, in the order the intake asks them, identical on every panel
   so three panels can be compared down the same column.

   TEAL AND SLATE, NOT GREEN AND RED. A cross here means "this is not the thing
   you asked for", which is not the same as --skip's "do not spend an
   application on this": a program can miss every preference and still be the
   strongest thing on the list. Painting the two the same colour is §38(a)(4)
   again, where the recommended tiles were tinted almost exactly the colour of
   the ones to avoid. The warning block above this one owns --skip and keeps it.

   The glyph is drawn in CSS and the word is in the markup behind .vh, so the
   mark is never carried by colour or shape alone. */
.dmarks { margin: 0 0 14px; max-width: 74ch; list-style: none; display: flex; flex-direction: column; gap: 7px; }
.dmarks li { display: flex; gap: 10px; align-items: baseline; font-size: .93rem; line-height: 1.45; }
.dmarks li i {
  flex: 0 0 15px; height: 15px; border-radius: 50%; position: relative; top: 2px;
  background: var(--rule);
}
.dmarks li.yes i { background: var(--teal); }
.dmarks li.no i { background: color-mix(in srgb, var(--soft) 38%, transparent); }
.dmarks li i::before, .dmarks li i::after {
  content: ''; position: absolute; background: var(--on-accent); border-radius: 1px;
}
/* A tick: two strokes, short one down-right, long one up-right. */
.dmarks li.yes i::before { width: 2px; height: 5px; left: 4.5px; top: 6.5px; transform: rotate(-45deg); }
.dmarks li.yes i::after { width: 2px; height: 8px; left: 8px; top: 3.5px; transform: rotate(35deg); }
/* A cross: two strokes through the middle. */
.dmarks li.no i::before, .dmarks li.no i::after { width: 2px; height: 9px; left: 6.5px; top: 3px; background: var(--card); }
.dmarks li.no i::before { transform: rotate(45deg); }
.dmarks li.no i::after { transform: rotate(-45deg); }
.dmarks li.yes span { color: var(--ink); }
.dmarks li.no span { color: var(--soft); }
/* Read by a screen reader, never drawn. Without it the mark is a coloured circle
   and the sentence beside it reads the same whether it matched or did not. */
.vh {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

/* The one key point, which is the only part of the ranking a student sees. It
   reads as the panel's conclusion, so it sits below the policy quotes with a
   rule above it and slightly more weight than the body around it. */
.dstand {
  margin-top: 16px; padding-top: 13px; border-top: 1px solid var(--rule);
  font-size: .95rem; color: var(--ink); max-width: 74ch; line-height: 1.5;
}

/* Why it sits where it sits. Two columns on anything wide enough, stacked on a
   phone, because a two-column ledger at 390px produces four-word lines. The
   point values are tabular so they form a readable column instead of drifting
   with the digit widths. */
.drank { margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--rule); }
.drank h4 { font-size: .95rem; font-weight: 750; letter-spacing: -.01em; margin-bottom: 10px; }
.drankcols { display: flex; gap: 30px; flex-wrap: wrap; align-items: flex-start; }
.drankcols > div { flex: 1 1 260px; min-width: 0; max-width: 44ch; }
.drank h5 {
  font-size: .7rem; font-weight: 700; letter-spacing: .07em; text-transform: uppercase;
  color: var(--soft); margin-bottom: 6px;
}
.drank ul { list-style: none; margin: 0; padding: 0; }
.drank li { display: flex; gap: 9px; font-size: .9rem; color: var(--body); margin-bottom: 4px; line-height: 1.4; }
.drank li b {
  flex: 0 0 5.4em; text-align: right; font-variant-numeric: tabular-nums;
  font-weight: 650; color: var(--teal); white-space: nowrap;
}
.drankcols > div:last-child li b { color: var(--skip); }
/* An assumed default is neither a strength nor a real weakness, it is a gap in
   what anybody published. It reads as a caveat rather than a mark against. */
.drank li.assumed { color: var(--soft); font-style: italic; }
.drank li.assumed b { color: var(--soft); font-style: normal; }
.drank .none { font-size: .9rem; color: var(--soft); }

/* away calendar */
.months { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 13px; }
.mo { background: var(--card); border-radius: 16px; padding: 20px; box-shadow: var(--shade); }
.mo.hi { background: var(--teal); color: var(--on-accent); }
.mo .m { font-size: 12px; letter-spacing: .13em; text-transform: uppercase; opacity: .72; }
.mo .n { font-size: 1.25rem; font-weight: 750; margin-top: 6px; letter-spacing: -.02em; }
.mo .c { font-size: .92rem; opacity: .85; margin-top: 5px; line-height: 1.45; }
.alts { margin-top: 16px; font-size: .97rem; color: var(--body); display: flex; flex-direction: column; gap: 8px; }

/* signals */
.sigs { display: flex; flex-direction: column; gap: 12px; }
.sig { background: var(--card); border-radius: 14px; padding: 18px 20px; box-shadow: var(--shade); display: grid; grid-template-columns: auto 1fr; gap: 16px; align-items: center; }
.sigmark { font-size: 11.5px; font-weight: 750; letter-spacing: .1em; text-transform: uppercase; padding: 8px 14px; border-radius: 30px; white-space: nowrap; }
.sigmark.g { background: var(--gold-lo); color: var(--gold); }
.sigmark.s { background: var(--navy-lo); color: var(--navy); }
.sigmark.sig { background: var(--gold-lo); color: var(--gold); }
/* The compact tail of the signal list: names only, each a button on the same
   data-open jump the tiles use. */
.siglist { margin: 8px 0 0 20px; padding: 0; }
.siglist li { margin: 3px 0; font-size: .95rem; }
.siglist button { appearance: none; background: none; border: 0; padding: 0; font: inherit; color: var(--body); cursor: pointer; text-align: left; }
.siglist button:hover, .siglist button:focus-visible { color: var(--teal); }
.sigmark.geo { background: var(--teal-lo); color: var(--teal); }
/* Same pair as .geo on purpose. Both rows are instructions about the
   application rather than a program to spend a shot on, and the token pair is
   already contrast-checked in both themes. */
.sigmark.home { background: var(--teal-lo); color: var(--teal); }
.sigmark.no { background: var(--skip-lo); color: var(--skip); }
.sig b { font-weight: 700; }
.sig p { font-size: .95rem; color: var(--body); margin-top: 2px; }

/* to-dos */
.todo { display: flex; flex-direction: column; gap: 12px; }
.td { background: var(--card); border-radius: 16px; padding: 18px 20px; box-shadow: var(--shade); display: grid; grid-template-columns: 44px 1fr; gap: 15px; align-items: center; }
.td .ic { width: 44px; height: 44px; border-radius: 50%; background: var(--teal-lo); color: var(--teal); display: grid; place-items: center; }
.td .ic svg { width: 22px; height: 22px; }
.td p { font-size: 1.02rem; }
.td .when { font-size: .86rem; color: var(--soft); margin-top: 2px; }

.readit { margin-top: 16px; padding: 14px 16px; background: var(--teal-lo); border-radius: 12px; font-size: .96rem; }

/* The report telling the student what it did to their answers. Gold rather than
   teal: this is not a finding about a program, it is the page explaining itself,
   and it has to be the first thing read on a report that widened the geography
   or found nothing at all. */
.notice { margin: 0 0 8px; padding: 18px 20px; border-radius: 14px; background: var(--gold-lo);
  border: 1.5px solid color-mix(in srgb, var(--gold) 40%, transparent); font-size: 1rem; }
.notice b { display: block; margin-bottom: 4px; }
.notice p { margin: 0; }
/* Always present, on a good report as well as a widened one. The silent version
   is what made a list built on 2 of 27 programs look like a list built on all
   of them. */
.scopeline { margin: 0 0 20px; font-size: .92rem; color: var(--soft); max-width: 64ch; }

.cta { background: var(--invert-bg); color: var(--invert-ink); border-radius: 20px; padding: 36px 30px; text-align: center; }
.cta h2 { max-width: 20ch; margin: 0 auto; color: var(--invert-ink); }
.cta p { margin: 14px auto 24px; max-width: 44ch; opacity: .78; font-size: 1.02rem; }

.notes { border-top: 2px solid var(--rule); margin-top: 56px; padding: 26px 0 70px; }
.notes ul { margin: 14px 0 0; padding-left: 20px; display: flex; flex-direction: column; gap: 10px; font-size: .94rem; color: var(--body); }
.notes strong { color: var(--ink); }

.srcline { font-size: .93rem; color: var(--soft); margin-top: 12px; }

/* ---------------------------------------------------------- curriculum -- */
/* One card per program, and nothing that lines a program up against another.
   No shared legend, no shared category axis, no colour that means the same
   thing on two cards. See the comment on --cur-1 and report.js. */
.curlist { display: flex; flex-direction: column; gap: 14px; }
.curow {
  background: var(--card); border-radius: 16px; padding: 18px 20px;
  box-shadow: var(--shade);
}
.curhd { display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px; }
.curhd b { font-size: 1.05rem; }
.curhd em { font-style: normal; color: var(--soft); font-size: .93rem; }
.curchip {
  font-size: .8rem; font-weight: 650; letter-spacing: .02em;
  background: var(--teal-lo); color: var(--teal);
  border-radius: 999px; padding: 2px 10px;
}
.curyear { margin-top: 14px; }
.curyhd { font-size: .93rem; color: var(--body); margin-bottom: 8px; }
/* The bar is a flex row of shares, so it cannot exceed its own container and
   cannot make the page scroll sideways however many segments a year has. */
.curbar {
  display: flex; width: 100%; height: 16px; border-radius: 5px;
  overflow: hidden; background: var(--rule); gap: 2px;
}
.curbar i { display: block; min-width: 2px; }
.curkey { list-style: none; margin: 12px 0 0; padding: 0; display: flex;
  flex-direction: column; gap: 7px; }
.curkey li { display: flex; gap: 9px; align-items: baseline; font-size: .93rem;
  color: var(--body); }
.curkey em { display: block; font-style: normal; color: var(--soft);
  font-size: .88rem; }
.cursw { flex: none; width: 12px; height: 12px; border-radius: 3px;
  transform: translateY(1px); }
.curnote { font-size: .93rem; color: var(--body); margin-top: 12px;
  max-width: 68ch; }
.curq { font-size: .93rem; color: var(--soft); margin-top: 10px;
  max-width: 72ch; }
.cursrc { color: var(--teal); }
@media (max-width: 760px) {
  .curow { padding: 16px; }
}

/* ------------------------------------------------------ SPB design layer -- */
@property --angle { syntax: "<angle>"; initial-value: 0deg; inherits: false; }
@keyframes spbFadeUp { from { opacity:0; transform:translateY(14px); filter:blur(2px); } to { opacity:1; transform:translateY(0); filter:blur(0); } }
@keyframes spbOrbDrift { 0%,100% { transform:translate(0,0); } 25% { transform:translate(60px,-50px); } 50% { transform:translate(-40px,40px); } 75% { transform:translate(40px,60px); } }
@keyframes spbGridScroll { from { background-position:0 0; } to { background-position:56px 56px; } }
@keyframes spbSpin { to { --angle:360deg; } }

/* clip, NOT hidden. overflow-x:hidden on body makes body a scroll container,
   and every position:sticky inside then sticks to a scrollport that never
   scrolls (the viewport scrolls the html box instead), which is why the
   report's tab bar sat still while Lucas scrolled (his 2026-08-30 item).
   overflow-x:clip clips the same horizontal overflow without creating a
   scroll container, so sticky works. */
html { scroll-behavior:smooth; overflow-x:clip; }
body { position:relative; isolation:isolate; overflow-x:clip; min-width:0; font-family:var(--font-body); font-size:14.5px; line-height:1.55; letter-spacing:-.005em; }
body::before, body::after { content:""; position:fixed; inset:-80px; z-index:-2; pointer-events:none; }
body::before { background:var(--page-glows); animation:spbOrbDrift 28s ease-in-out infinite; }
body::after { z-index:-1; background-image:var(--page-grid); background-size:56px 56px; mask-image:radial-gradient(ellipse at center,black,transparent 72%); animation:spbGridScroll 60s linear infinite; }

h1,h2,h3,.cta h2 { font-family:var(--font-display); } h1 { letter-spacing:-.035em; line-height:1; } h2 { letter-spacing:-.03em; } h3 { letter-spacing:-.015em; }
/* MONO CAPS ARE FOR LABELS, NEVER FOR PARAGRAPHS. .small and .srcline were in
   this list and they carry full multi-sentence explainers ("Read it like
   this: ...", the switch note, the scope footnotes), which his 2026-08-30
   "lots of text ... I want maximum ease" pass called out. The research is
   settled: all-caps slows continuous reading about 10-13% (NN/g; uniform
   word shapes force letter-by-letter reading), and caps are fine only for
   the 2-3-word labels the rest of this list holds. So the two prose classes
   moved to the body face below and everything label-shaped stays as it was. */
.kicker,.chip,.sigmark,.mo .m,.rank,.shelfhead span,.ptable th,.specialty-group-label,.state-group>p,.livemark,.need,.needs,.fieldhint,.curchip { font-family:var(--font-mono); font-size:clamp(10px,.72rem,11.5px); font-weight:500; letter-spacing:.12em; text-transform:uppercase; }
.kicker { letter-spacing:.22em; color:var(--teal); }
/* --body, not --soft: the mono explainer paragraphs carry real sentences and
   measured too dim on the dark ground. Lucas 2026-08-29: "some of this gray
   text is quite hard to see on the dark background. Please make it a little
   brighter." Chips, kickers and table headers keep --soft; running prose in
   this dress does not. */
.small,.srcline { font-family:var(--font-body); font-size:.92rem; font-weight:400; letter-spacing:0; text-transform:none; line-height:1.55; color:var(--body); max-width:62ch; }
.wrap,.wide { width:100%; min-width:0; }

.bar { font-family:var(--font-mono); background:transparent; color:var(--soft); padding:10px max(20px, calc((100% - 920px) / 2 + 22px)) 4px; }
.themectl { flex:none; background:var(--surface-2); border-color:var(--rule); }
.themectl button { padding:5px 9px; transition:all 220ms var(--ease); }

.screen.on { animation:none; }
.screen.on > * { animation:spbFadeUp 480ms var(--ease) both; }
.screen.on > *:nth-child(2) { animation-delay:60ms; } .screen.on > *:nth-child(3) { animation-delay:120ms; } .screen.on > *:nth-child(4) { animation-delay:180ms; } .screen.on > *:nth-child(5) { animation-delay:240ms; } .screen.on > *:nth-child(6) { animation-delay:300ms; } .screen.on > *:nth-child(7) { animation-delay:360ms; } .screen.on > *:nth-child(8) { animation-delay:420ms; }
/* scroll-margin clears the docked tab strip (~37px stuck at top:0) plus a
   breath; it was 98px when the strip sat under the old step header. */
/* 60px, not 52: the report bar grew to ~50px on 2026-08-31 (Codex catch:
   at 52 the anchored heading sat 1.6px clear of the sticky bar). */
section { padding:68px 0; scroll-margin-top:60px; }
#s3 section:nth-of-type(even) { background:color-mix(in srgb,var(--card) 30%,transparent); border-block:1px solid color-mix(in srgb,var(--rule) 55%,transparent); border-radius:20px; }

/* NO backdrop-filter ON IN-FLOW CARDS, removed 2026-08-31 on Lucas's beta
   sighting (twice): the overview's #1 hero tile rendered BLANK after a scroll
   down and back up, its translucent ground letting the page's dot texture
   show where the content should be. blur(20px) promotes every card to its own
   composited layer, and Chrome evicts those textures on scroll-away and
   intermittently fails to re-rasterize on the way back, which is exactly the
   intermittent blanking he saw and why it healed on the next repaint. The
   frosted look bought nothing here: --card is 88% opaque over a static paper,
   so the blur only softened the 12% of dot texture bleeding through. Floating
   chrome that content actually scrolls behind (.yeartog/.viewtog) keeps its
   blur: those surfaces are small and genuinely frosted. */
.q,.three>div,.plan,.mapbox,.chartbox,.tile,.mo,.sig,.td,.curow,.gate,.beta-block,.tblwrap { background:var(--card); border:1px solid var(--rule); border-radius:12px; box-shadow:var(--shade); }
.q,.plan,.mo,.sig,.td,.curow,.three>div { transition:transform 220ms var(--ease),border-color 220ms var(--ease),box-shadow 220ms var(--ease),background 220ms var(--ease); }
.q:hover,.plan:hover,.mo:hover,.sig:hover,.td:hover,.curow:hover,.three>div:hover { transform:translateY(-2px); border-color:var(--line-hover); }
.mapbox,.chartbox { border-radius:12px; }
.mapbox svg,.chartbox svg { max-width:100%; }

.btn { position:relative; overflow:hidden; isolation:isolate; border-radius:10px; padding:16px 20px; background:linear-gradient(135deg,var(--brand),var(--brand-deep)); color:#fff; font-size:13.5px; font-weight:600; letter-spacing:.02em; transition:all 220ms var(--ease); }
.btn::before { content:""; position:absolute; z-index:-1; top:0; left:-100%; width:100%; height:100%; background:linear-gradient(90deg,transparent,rgba(94,234,212,.35),transparent); transition:left 600ms var(--ease); }
.btn:hover:not(:disabled) { transform:translateY(-2px); filter:none; box-shadow:0 0 0 1px var(--neon),0 0 24px var(--neon-glow),inset 0 1px 0 rgba(255,255,255,.2); }
.btn:hover:not(:disabled)::before { left:100%; } .btn:active:not(:disabled) { transform:translateY(0); }
.btn.line { background:var(--card); color:var(--teal); box-shadow:inset 0 0 0 1px var(--rule); }

.q input[type="text"],.q input[type="email"],.q select,.gate input[type="email"],.list-filter { border:1px solid var(--rule); border-radius:8px; background:var(--surface-2); color:var(--ink); font-family:var(--font-body); transition:border-color 220ms var(--ease),box-shadow 220ms var(--ease); }
.q input:focus-visible,.q select:focus-visible,.gate input:focus-visible,.list-filter:focus-visible { outline:none; border-color:var(--focus); box-shadow:0 0 0 2px var(--neon-soft); }
.combolist { background:var(--surface); border-color:var(--rule); box-shadow:var(--shade); }

.picks label,.specialty-choice,.tile { position:relative; isolation:isolate; overflow:hidden; border-width:1px; font-weight:500; transition:all 220ms var(--ease); }
.picks label:has(input:checked),.specialty-choice[aria-pressed="true"] { border-color:var(--neon); background:var(--neon-soft); color:var(--teal); font-weight:500; box-shadow:inset 0 0 0 1px var(--neon-soft),0 0 8px var(--neon-soft); }
.picks label:hover,.specialty-choice:hover,.tile:hover { transform:translateY(-2px); border-color:var(--line-hover); }
.picks label:active,.specialty-choice:active,.tile:active { transform:translateY(0); }
.picks label::before,.specialty-choice::before,.tile::before,.cta::before { content:""; position:absolute; inset:0; z-index:-1; border-radius:inherit; padding:1px; opacity:0; pointer-events:none; background:conic-gradient(from var(--angle),transparent 35%,var(--neon),#22d3ee,transparent 65%); -webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0); -webkit-mask-composite:xor; mask-composite:exclude; transition:opacity 240ms var(--ease); }
.picks label:hover::before,.picks label:has(input:checked)::before,.specialty-choice:hover::before,.specialty-choice[aria-pressed="true"]::before,.tile:hover::before { opacity:1; animation:spbSpin 2.4s linear infinite; }
.picks label:has(input:checked)::before,.specialty-choice[aria-pressed="true"]::before { animation-duration:4s; }

.yeartog,.viewtog { border:1px solid var(--rule); border-radius:100px; backdrop-filter:blur(20px); }
.yeartog button,.viewtog button { font-weight:600; border-radius:100px; transition:all 220ms var(--ease); }
/* var(--pill-ink), NOT var(--teal): the token carries the AA-passing ink per
   theme, and light-theme teal on the neon-soft wash is a 4.46:1 near-miss. */
.yeartog button[aria-pressed="true"],.viewtog button[aria-pressed="true"] { background:var(--neon-soft); color:var(--pill-ink); }
.chip,.curchip,.sigmark { border-radius:8px; }
.dobar,.ftrack,.fit i { background:color-mix(in srgb,var(--rule) 80%,var(--soft)); }
.tblwrap { max-width:100%; overflow-x:auto; }
.ptable { background:var(--card); }
.ptable th { font-size:10px; letter-spacing:.14em; }
.ptable tr.prow:hover { background:var(--tint); }
.natfold { border-color:var(--rule); }
.natfold>summary { font-family:var(--font-mono); font-size:11px; letter-spacing:.1em; text-transform:uppercase; }

/* THE REPORT TABS, restyled 2026-08-30 on Lucas's pick: the capsule pill is
   gone, the bar is the report's header now (the step nav above it was
   removed the same night), docked at the very top as a full-width underline
   strip. The active tab wears a teal underline and full ink instead of the
   neon capsule; the profile circle (.youbtn) rides the right edge and stays
   there when the tabs overflow-scroll, because sticky works horizontally
   inside the bar's own scrollport. Positive bottom margin, never negative:
   -24px pulled the next section's kicker up underneath the bar and the two
   collided (batch 3 screenshots). */
/* Font 10px -> 12.5px and taller tabs, Lucas 2026-08-31: "increase the size
   of the header since the font is pretty small... maybe that also makes the
   header a little longer." The bar grows from ~36px to ~46px tall. */
.reportnav { position:sticky; top:0; z-index:15; margin:0 0 30px; padding:0 max(18px, calc((100% - 920px) / 2 + 22px)); display:flex; align-items:center; gap:2px; overflow-x:auto; white-space:nowrap; border-bottom:1px solid var(--rule); background:var(--paper); font-family:var(--font-mono); font-size:12.5px; letter-spacing:.08em; text-transform:uppercase; }
.reportnav .rtab { appearance:none; -webkit-appearance:none; background:none; border:0; margin:0; padding:16px 13px 14px; border-radius:0; box-shadow:inset 0 -2px 0 transparent; color:var(--body); font-family:inherit; font-size:inherit; letter-spacing:inherit; text-transform:inherit; font-weight:600; cursor:pointer; transition:all 220ms var(--ease); }
.reportnav .rtab:hover { color:var(--teal); }
.reportnav .rtab[aria-pressed="true"] { box-shadow:inset 0 -2px 0 var(--teal); color:var(--ink); }

/* The account corner: today it reopens the About-you questions, and it sits
   where the profile menu goes once logins exist. Solid card ground so the
   tabs sliding under it on a narrow screen do not show through. */
.reportnav .youbtn { appearance:none; -webkit-appearance:none; flex:none; margin-left:auto; position:sticky; right:0; width:30px; height:30px; display:inline-flex; align-items:center; justify-content:center; border:1px solid var(--rule); border-radius:50%; background:var(--card); color:var(--body); cursor:pointer; box-shadow:0 0 0 9px var(--paper); transition:color 220ms var(--ease),border-color 220ms var(--ease); }
.reportnav .youbtn svg { width:16px; height:16px; display:block; }
.reportnav .youbtn:hover { color:var(--teal); border-color:var(--teal); }
/* The strip's advising CTA rides sticky beside the profile circle, so both
   survive the strip's own sideways tab scroll on a phone. */
.reportnav .rcta { flex:none; margin-left:auto; position:sticky; right:38px; text-decoration:none; background:var(--teal); color:var(--on-accent); font-weight:650; padding:6px 11px; border-radius:30px; box-shadow:0 0 0 9px var(--paper); }
.reportnav .rcta:hover { filter:brightness(1.08); }
.reportnav .rcta + .youbtn { margin-left:8px; }

/* The coach mark is mounted only by the live intake path. The scrim is four
   plain panels around the anchor rather than a single ring with a giant
   box-shadow spread: a background fill has no raster ceiling to worry about,
   and this version's paint is pixel-verified (a white card sampled at
   [131,134,139] under the 50% scrim, 2026-08-31). The color is a literal
   dark rather than an ink token on purpose: a scrim must DARKEN the page in
   both themes, and every ink-side token flips to near-white in dark mode,
   which would have painted the page with fog and left the spotlight as the
   darker hole. */
.tourdim { position: fixed; z-index: 100; pointer-events: none; background: rgba(10, 16, 24, .5); }
.tourspot { position: fixed; z-index: 100; pointer-events: none; border: 2px solid var(--teal); border-radius: 12px; }
.tourpop { position: fixed; z-index: 101; width: min(330px, calc(100vw - 24px)); padding: 18px; border: 1px solid var(--rule); border-radius: 12px; background: var(--card); color: var(--ink); box-shadow: var(--shade); }
.tourpop p { margin: 0 0 12px; }
.tourpop .tourcount { color: var(--soft); font: 600 .78rem var(--font-mono); letter-spacing: .08em; text-transform: uppercase; }
.touractions { display: flex; align-items: center; gap: 14px; }
.tourskip { appearance: none; border: 0; padding: 6px 0; background: transparent; color: var(--teal); font: inherit; text-decoration: underline; cursor: pointer; }

/* WHICH PANE SHOWS. Hide-only rules, one per tab, so they can coexist with the
   year rules ([data-year="3"] .y4 and its mirror), which are also hide-only:
   a show rule with an id in it would out-rank the year hiding and put the
   fourth-year signals on a third-year screen. The tabs-all class is the
   audit's stacked state (and render() clears it), and print gets the whole
   report the way the single page used to lay it out, with the year rules still
   choosing the year. */
@media screen {
  #s3[data-rtab="overview"]:not(.tabs-all) [data-pane]:not([data-pane="overview"]),
  #s3[data-rtab="list"]:not(.tabs-all) [data-pane]:not([data-pane="list"]),
  #s3[data-rtab="map"]:not(.tabs-all) [data-pane]:not([data-pane="map"]),
  #s3[data-rtab="calendar"]:not(.tabs-all) [data-pane]:not([data-pane="calendar"]),
  #s3[data-rtab="signals"]:not(.tabs-all) [data-pane]:not([data-pane="signals"]),
  #s3[data-rtab="todo"]:not(.tabs-all) [data-pane]:not([data-pane="todo"]),
  #s3[data-rtab="numbers"]:not(.tabs-all) [data-pane]:not([data-pane="numbers"]) { display:none !important; }
}

/* The bottom-of-tab Next button (Lucas 2026-08-30). display:flex would defeat
   the [hidden] attribute syncNextButtons toggles, hence the explicit rule. */
/* Back sits left, Next sits right (Lucas 2026-08-31: "back should be left
   next should be right", matching the intake pager). Horizontal margins stay
   AUTO or this rule overrides the column's own centering and pins the whole
   rail to the viewport's left, which is exactly the drift he screenshotted:
   the old rule's `margin:38px 0 10px` beat `.wrap`'s `margin:0 auto`. The
   rail is `.wide` so the two buttons frame the report's widest column, the
   same span the tab bar answers at the top. Next carries its own
   margin-left:auto so it stays on the right edge even on the first pane,
   where Back is hidden and space-between would drift it left. */
.pagenav { display:flex; justify-content:space-between; gap:14px; margin:38px auto 10px; }
.pagenav .nextpane { margin-left:auto; }
.pagenav[hidden] { display:none !important; }

/* THE STANDING DISCLAIMER LINE, one copy per pane below the pager, because the
   panes are hide-only and a single copy would be visible on one screen out of
   seven. `.wide` so it spans the same column the pager and the tab bar answer,
   and a rule above it so it reads as a footer rather than as the last thing the
   pane was saying. It is deliberately quiet: it has to be present on every
   screen, and a loud banner repeated seven times is one a reader learns to skip.
   The full note it links to is #sec-limits in The numbers. */
/* THE SITE FOOTER. Outside the screens, so it survives every screen change.
   Quiet by design: it is a permanent legal rail, not a call to action, and the
   report already carries the louder version of the same claim above its pager. */
.sitefoot { max-width:var(--wide, 1180px); margin:0 auto; padding:26px 22px 40px;
  border-top:1px solid var(--rule); color:var(--soft); font-size:.9rem; }
.sitefoot p { margin:0 0 4px; }
.sitefoot a { color:var(--teal); }
@media print { .sitefoot { display:none !important; } }

.limitnote { margin:6px auto 30px; padding-top:14px; border-top:1px solid var(--rule); }
.limitnote p { max-width:78ch; margin:0; color:var(--soft); }
/* A button that reads as a link, the tourskip pattern: it changes the pane
   rather than navigating, so it cannot be an anchor. */
.linkish { appearance:none; border:0; padding:0; background:transparent; color:var(--teal);
  font:inherit; text-decoration:underline; cursor:pointer; }

/* The how-to fold above the table wears the natfold dress without its
   top-border separator, which belongs to a block that closes a section rather
   than one sitting between a lede and its table. */
.natfold.howto { margin-top:0; margin-bottom:16px; border-top:0; padding-top:0; }
.cta { position:relative; isolation:isolate; overflow:hidden; border:1px solid var(--rule); border-radius:14px; background:rgba(10,15,31,.92); box-shadow:var(--shade); }
.cta::before { z-index:0; opacity:1; animation:spbSpin 10s linear infinite; } .cta>* { position:relative; z-index:1; }

/* ------------------------------------------- beta polish, 2026-08-29 ------ */
/* Every rule in this block answers one line of Lucas's 2026-08-29 beta pass. */

/* "All the tabs need a little padding at the bottom": the visible pane's own
   68px can end flush against the viewport once its siblings hide, so the
   report container carries a floor of its own. */
#s3 { padding-bottom: 72px; }

/* "The entire header section really blends in with the rest of the page":
   the top strip becomes a solid band with a firmer line, so the chrome reads
   as chrome. */
.bar { background:var(--surface); border-bottom:1px solid var(--rule); padding:10px max(20px, calc((100% - 920px) / 2 + 22px)); }

/* "These boxes need a little padding, when you hover over one it overlaps the
   adjacent box": the hero tile sat flush on the row below it, so the -2px
   hover lift crossed the gap. The lifted tile also paints above neighbours. */
.shelf .tile.hero { margin-bottom: 14px; }
.tile:hover { z-index: 1; }

/* "Add a little hover animation to the map and the chart", REVERSED FOR THE
   MAP on Lucas's 2026-08-31 afternoon ruling: "dont make the map move up and
   down on hover". The map is an input surface (pins, drag, pinch), and a card
   that shifts under a pressing pointer moves the target mid-tap, so it keeps
   only the border highlight. The chart keeps the full lift. */
.chartbox { transition: transform 220ms var(--ease), border-color 220ms var(--ease), box-shadow 220ms var(--ease); }
.mapbox { transition: border-color 220ms var(--ease); }
.chartbox:hover { transform: translateY(-2px); }
.mapbox:hover, .chartbox:hover { border-color: var(--line-hover); }
.chartbox svg circle.dot { transform-box: fill-box; transform-origin: center; transition: transform 160ms var(--ease); }
.chartbox svg circle.dot:hover { transform: scale(1.3); }

/* The map pins are buttons now (charts.js stamps role and tabindex); the
   cursor and the grow-on-hover say so without a label. */
.mappin { cursor: pointer; transform-box: fill-box; transform-origin: center; transition: transform 180ms var(--ease); }
.mappin:hover, .mappin:focus-visible { transform: scale(1.14); }

/* "Add some vignetting to the background of the text just slightly": a soft
   page-colour stroke under the map labels, painted behind the glyphs, so a
   name crossing a state border or a leader line stays legible. */
svg .thalo { paint-order: stroke; stroke: var(--paper); stroke-width: 3.5px; stroke-opacity: .72; stroke-linejoin: round; }

/* The location list a pin click opens under the map. */
.maploc { margin-top: 18px; }
.maploc .shelfhead { margin-bottom: 12px; }

/* ------------------------------------------------------------ responsive -- */
@media (max-width: 760px) {
  body { font-size: 17px; }
  .two { grid-template-columns: 1fr; }
  .cascade .lvl { grid-template-columns: 1fr; }
  .cascade .lvl > span { text-align: left; padding-top: 0; }
  .themectl { margin-left: auto; }

  /* Five columns cannot fit a phone, so the table drops to the three that
     carry the decision. Spots and the one-line reason live in the open panel,
     which is one tap away, instead of behind a sideways scroll.
     overflow-x stays auto: dropping to `visible` let a 396px table push the
     whole page sideways on a 390px screen, which is worse than the scroll it
     was trying to avoid. */
  /* Phone keeps Program, Fit and What to do. Spots, % DO and Why go to the
     detail panel, because the two columns that answer "how strong" and "what do
     I spend" are the two worth the width. */
  .ptable, .ptable td.nm { min-width: 0; }
  .ptable th:nth-child(2), .ptable td:nth-child(2),
  .ptable th:nth-child(3), .ptable td:nth-child(3),
  .ptable th:nth-child(5), .ptable td:nth-child(5) { display: none; }
  .ptable td.rs { min-width: 0; }
  .ptable th, .ptable td { padding-inline: 8px; }
  .rowtoggle { padding-left: 8px; gap: 6px; }
  /* On a phone the column is too narrow to hold a long name on one line, so the
     desktop nowrap is released and long names break rather than overflow. */
  .rowtoggle > span { overflow-wrap: anywhere; white-space: normal; }
  .chip { font-size: 10px; padding: 6px 9px; letter-spacing: .06em; }
  /* The action chip may wrap on a phone: its label is engine data of any
     length, and a pinned label was the last 23px of sideways scroll on a
     390px screen (Lucas 2026-08-31: Your list must not scroll sideways). */
  .ptable .chip { white-space: normal; line-height: 1.3; border-radius: 14px; }
  .openmark { font-size: 10px; padding: 2px 7px; }
  .dobar { width: 34px; }
  .pct { margin-left: 5px; font-size: .8rem; }
  /* The track narrows rather than disappearing: it is the column that answers
     "are these actually different", which is worth more on a phone than on a
     desktop because the reader cannot scan a whole column at once. */
  .ftrack { width: 46px; }
  .fnum { margin-left: 6px; font-size: .86rem; }
  .dpan { padding: 16px 14px 18px 18px; }
  .dstats { gap: 18px; }
  .mapbox svg, .chartbox svg { min-width: 420px; }
  .themectl { margin-left:auto; }
  /* The envbar cannot hold title, theme control and the advising pill in one
     390px row (the pill ran off the right edge), so the title takes the first
     row alone, drops its "pre-release build" tail, and the controls wrap to a
     second row. */
  .bar { flex-wrap: wrap; row-gap: 6px; }
  #envbar > span { flex: 1 1 100%; }
  #envbar .pretag { display: none; }
  .reportnav { padding-inline:8px; }
  section { padding:50px 0; }
}

/* 761-919px: all six columns need ~870px and the wrap holds 715-860px, so
   this band sits the Why column out (the widest, min-width 224, and the one
   whose content repeats inside the tap-open row panel) and drops the 800px
   floor with it. Below 760 the phone block above already drops Spots and
   % DO as well. Lucas 2026-08-31: Your list must not scroll sideways. */
@media (min-width: 761px) and (max-width: 919px) {
  .ptable { min-width: 0; }
  .ptable th:nth-child(5), .ptable td:nth-child(5) { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior:auto; }
  *, *::before, *::after { animation-duration:.001ms !important; animation-iteration-count:1 !important; transition-duration:.001ms !important; }
  .screen.on > *, .screen.on, .dpan { animation:none !important; opacity:1; transform:none; filter:none; }
  body::before, body::after, .cta::before, .picks label::before, .specialty-choice::before, .tile::before { animation:none !important; }
}

/* ---------------------------------------------------------------- print --- */
/* The accordion has no print equivalent, so print forces every panel open and
   drops the interactive chrome. This is the report as a document, which is what
   a student will actually hand to a mentor. */
@media print {
  :root {
    --paper:#fff; --card:#fff; --rule:#CBD5D5; --ink:#0F2430; --body:#3A4E58; --soft:#66787F;
    --teal:#0A736D; --navy:#1A4568; --skip:#B03A2B; --gold:#8A6110;
    --shade: none; --invert-bg:#fff; --invert-ink:#0F2430; --tint: transparent;
  }
  body { font-size: 11.5pt; background: #fff; }
  /* `.limitnote` goes with them, and only on paper: the pane-hiding rules are
     screen-only, so print lays out every pane at once and would otherwise
     repeat the same footer line seven times. The full note it points at
     (#sec-limits) prints in place, so nothing is lost. */
  .bar, .themectl, .yeartog, .btn, .notes, .reportnav, .pagenav, .limitnote, .mapzoom, .tourdim, .tourspot, .tourpop { display: none !important; }
  .screen { display: none !important; }
  .screen#s3 { display: block !important; }
  section { padding: 14pt 0; break-inside: avoid; }
  .wrap, .wide { max-width: none; padding: 0; }
  .drow, .drow[hidden] { display: table-row !important; }
  .dpan { animation: none; }
  .chev { display: none; }
  .tblwrap, .ptable { overflow: visible; min-width: 0; box-shadow: none; }
  .card, .plan, .tile, .mo, .sig, .td, .mapbox, .chartbox, .q { box-shadow: none; border: 1px solid var(--rule); }
  .cta { border: 2px solid var(--ink); }
  h2, h3 { break-after: avoid; }
  .mapbox svg, .chartbox svg { min-width: 0; }
  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 9pt; color: var(--soft); }
}

/* THE FOLDED NATIONAL BLOCK. Lucas's ruling 2026-08-13: keep the background,
   move it behind a link. The summary reads as a link rather than as a heading,
   because a heading invites you to read what follows and this one invites you
   to decide whether to. */
.natfold { margin-top: 34px; border-top: 1px solid var(--rule); padding-top: 18px; }
.natfold > summary {
  cursor: pointer; list-style: none; color: var(--teal); font-weight: 650; font-size: .98rem;
  display: inline-flex; align-items: center; gap: 8px; padding: 4px 0;
}
.natfold > summary::-webkit-details-marker { display: none; }
.natfold > summary::before {
  content: ''; width: 7px; height: 7px; border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor; transform: rotate(-45deg); transition: transform .15s ease;
}
.natfold[open] > summary::before { transform: rotate(45deg); }
.natfold > summary:hover { text-decoration: underline; }
.natbody { margin-top: 26px; }

/* batch1: intake + landing fixes */
.beta-block {
  margin-top: 36px; padding: 24px; border-radius: 16px; background: var(--teal-lo);
  display: flex; flex-direction: column; align-items: flex-start; gap: 20px;
}
.beta-block p { color: var(--body); }
/* "WHAT IS INSIDE" IS A BAND OF FULL-WIDTH SCREENSHOTS NOW, not a scrollable
   strip. Lucas's beta ruling 2026-08-29: "shouldn't be a scrollable list just
   show it with larger pictures on a background where the screenshots
   standout." The band is a navy-lo slab, which is lighter than the page in
   dark mode and darker than the cards in light mode, so the screenshots read
   as pictures ON something in both themes. */
.peekband {
  margin-top: 46px; padding: 28px clamp(16px, 4vw, 36px) 34px;
  border-radius: 20px; background: var(--navy-lo); border: 1px solid var(--rule);
}
.peekband .peek-kicker { margin: 0 0 20px; }
.peek { display: flex; flex-direction: column; gap: 34px; }
.peek figure { margin: 0; }
.peek figcaption { font-size: .95rem; color: var(--ink); font-weight: 600; margin-bottom: 10px; }
.peek img {
  display: block; width: 100%; height: auto; border-radius: 12px;
  border: 1px solid var(--line-hover); box-shadow: var(--shade);
}
.intake-wrap { padding-top: 72px !important; }
#actions #go-report {
  flex: 1 1 320px; min-height: 62px; font-size: 1.14rem; background: var(--teal);
  color: var(--on-accent); box-shadow: var(--shade);
}
.picks label, .picks label:has(input:checked) { font-weight: 400; border-width: 1.5px; padding: 10px 17px; }
.specialty-group { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 9px; }
.specialty-choice {
  appearance: none; font: inherit; font-weight: 400; text-align: left; cursor: pointer;
  border: 1.5px solid var(--rule); border-radius: 12px; padding: 12px 14px;
  background: var(--paper); color: var(--ink);
}
.specialty-choice[aria-pressed="true"] { border-color: var(--teal); background: var(--teal-lo); color: var(--teal); }
.specialty-premium { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.specialty-premium small { color: var(--teal); font-size: .72rem; font-weight: 600; }
.specialty-gate:not(:empty) { margin-top: 18px; }
.specialty-group-label { margin: 22px 0 10px; color: var(--soft); font-size: .86rem; }
.specialty-soon { color: var(--soft); background: var(--card); cursor: pointer; }
.list-filter { margin: 0 0 12px; }
.show-all {
  appearance: none; border: 0; background: none; color: var(--teal); font: inherit;
  font-size: .9rem; padding: 0 0 12px; cursor: pointer;
}
.state-group + .state-group { margin-top: 18px; }
.state-group > p { color: var(--soft); font-size: .84rem; margin-bottom: 8px; }
.typeahead-results { display: flex; flex-direction: column; max-height: 260px; overflow-y: auto; }
.typeahead-results button {
  appearance: none; border: 0; border-bottom: 1px solid var(--rule); background: var(--paper);
  color: var(--ink); font: inherit; text-align: left; padding: 10px 12px; cursor: pointer;
}
.picked-chips { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 14px; }
.picked-chip { display: inline-flex; align-items: center; gap: 7px; border-radius: 30px; padding: 7px 10px 7px 13px; background: var(--teal-lo); color: var(--teal); }
.picked-chip button { appearance: none; border: 0; background: none; color: inherit; font: inherit; line-height: 1; padding: 1px 3px; cursor: pointer; }

/* batch2: the second safest switch, rendered beside the table so nobody
   scrolls back up to flip it (Lucas's beta ruling 2026-08-28). Same buttons,
   same delegated handler as the top one. */
.viewtog.mini { margin: 4px 0 14px; }

/* ------------------------------------------ beta polish 3, 2026-08-29 ------ */
/* Every rule in this block answers one line of Lucas's evening beta pass. */

/* "these two are too close": the plan card and the CTA panel sat 18px apart
   on the to-do tab, tighter than any other pair of slabs on the page. */
.cta { margin-top: 34px; }

/* A tile is a <button>, and a button vertically centres spare height, so a
   short card in a tall row floated its name to the middle (visible the moment
   the checklists made row heights vary). Top-aligned like any other card. */
.tile { display: flex; flex-direction: column; align-items: flex-start; }
.tile .whychk, .tile .why, .tile b, .tile em { align-self: stretch; }

/* THE TILE CHECKLIST (engine whyBits). Same visual language as the detail
   panel's tick-and-cross list, smaller: a teal disc with a tick for a driver
   that helped this row, a muted disc with a minus for one that dragged it, a
   hollow ring for a neutral fact. Spans with list roles, because the tile is
   a <button> and a real <ul> is invalid inside one. */
.whychk { display: flex; flex-direction: column; gap: 5px; margin-top: 9px; }
.whychk .wb { position: relative; display: block; padding-left: 21px; font-size: .85rem; color: var(--body); line-height: 1.4; }
.whychk .wb i { position: absolute; left: 0; top: 3px; width: 14px; height: 14px; border-radius: 50%; background: var(--rule); }
.whychk .wb.up i { background: var(--teal); }
.whychk .wb.dn i { background: color-mix(in srgb, var(--soft) 45%, transparent); }
.whychk .wb.mid i { background: none; border: 2px solid var(--soft); width: 10px; height: 10px; }
.whychk .wb i::before, .whychk .wb i::after { content: ''; position: absolute; border-radius: 1px; }
.whychk .wb.up i::before { width: 2px; height: 4px; left: 4px; top: 6.5px; transform: rotate(-45deg); background: var(--on-accent); }
.whychk .wb.up i::after { width: 2px; height: 7px; left: 7.5px; top: 3.5px; transform: rotate(35deg); background: var(--on-accent); }
.whychk .wb.dn i::before { width: 8px; height: 2px; left: 3px; top: 6px; background: var(--card); }
.tile.hero .whychk .wb { font-size: .95rem; }
/* The same checklist inside the table's Why column and the calendar month
   cards (Lucas 2026-08-29: the list and the calendar wear the checkmarks the
   overview wears). The cells set their own top spacing. */
.ptable td.rs .whychk { margin-top: 0; }
.mo .c .whychk { margin-top: 2px; }
/* On the teal hero month the generic checklist tokens vanish: --body text and
   teal discs against the teal fill. The card's own ink and an ink-ringed disc
   keep the same marks readable there. */
.mo.hi .whychk .wb { color: var(--on-accent); }
.mo.hi .whychk .wb.up i { background: color-mix(in srgb, var(--on-accent) 22%, transparent); box-shadow: inset 0 0 0 1.5px var(--on-accent); }
.mo.hi .whychk .wb.up i::before, .mo.hi .whychk .wb.up i::after { background: var(--on-accent); }
.mo.hi .whychk .wb.dn i { background: color-mix(in srgb, var(--on-accent) 30%, transparent); }
.mo.hi .whychk .wb.dn i::before { background: var(--teal); }
.mo.hi .whychk .wb.mid i { border-color: var(--on-accent); }

/* THE INTAKE PAGES. "The about you section is one massive scrollwheel can you
   paginate this as well like we did with the report": one page per taxonomy
   section, hide-only ([hidden] keeps every question in the DOM, the report
   tabs' pattern), the pills wearing the reportnav's control language. */
.itabs { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 26px; }
.itab {
  appearance: none; cursor: pointer; font-family: var(--font-mono); font-size: 11px;
  letter-spacing: .08em; text-transform: uppercase; font-weight: 600; color: var(--body);
  background: var(--card); border: 1px solid var(--rule); border-radius: 100px;
  padding: 8px 14px; transition: all 220ms var(--ease);
}
.itab:hover { color: var(--teal); border-color: var(--line-hover); }
.itab[aria-pressed="true"] { background: var(--neon-soft); color: var(--pill-ink); border-color: var(--neon); }
.ipage[hidden] { display: none; }
/* Back sits at the card's bottom-LEFT and Next at the bottom-RIGHT (Lucas
   2026-08-31, overriding the earlier bottom-right pick: "back buttons should
   be left side of the screen, forward buttons should be right side"). The
   counter sits between them; on the last page, where Next hides, it drifts
   right and Back holds the left edge. */
.ipagenav { display: flex; align-items: center; gap: 14px; margin-top: 34px; flex-wrap: wrap; justify-content: space-between; }
.ipagenav .ipagecount {
  font-family: var(--font-mono); font-size: 11px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--soft);
}
#actions[hidden] { display: none; }

/* Keep the specified brand endpoints visible while the subtle dark veil makes
   white button labels clear 4.5:1 even at the brighter end of the gradient. */
.btn, #actions #go-report {
  background:linear-gradient(rgba(6,9,18,.14),rgba(6,9,18,.14)),linear-gradient(135deg,var(--brand),var(--brand-deep));
  color:#fff;
}

/* The list-shape stats, pulled out of the rank paragraph so the numbers read
   at a glance and the prose can stay short (his 2026-08-30 over-elaboration
   flag on "How long your list ends up being"). */
.listshape { display: flex; gap: 12px; flex-wrap: wrap; margin-top: 18px; }
.listshape .ls { flex: 1 1 170px; background: var(--card); border: 1px solid var(--rule); border-radius: 10px; padding: 14px 16px; }
.listshape .ls b { display: block; font-size: 1.45rem; letter-spacing: -.01em; }
.listshape .ls span { display: block; margin-top: 4px; font-size: .85rem; color: var(--body); }
.listshape .ls i { display: block; font-style: normal; margin-top: 2px; font-size: .78rem; color: var(--soft); }
