/* CollegePath — design system (Sprint 0). Light, clean, organized.
   © 2026 ENVS Holdings LLC. */
:root{
  --bg:#f5f7fb; --surface:#ffffff; --surface-2:#fbfcfe;
  --ink:#16202e; --muted:#5c6b80; --line:#e5e9f1;
  --brand:#14274e; --brand-700:#22366b; --accent:#c8a44d;
  /*  (WCAG 2.1 AA 1.4.3): status text colors darkened to reach >=4.5:1
     on both their tint backgrounds and white. -bg tints unchanged (backgrounds only). */
  --good:#0f7a4e; --good-bg:#e7f6ee; --warn:#8a6212; --warn-bg:#fbf3e2;
  --bad:#b83b2b; --bad-bg:#fceae7; --info-bg:#eaf0fb;
  --radius:14px; --radius-sm:9px; --shadow:0 1px 2px rgba(16,32,54,.06),0 8px 24px rgba(16,32,54,.07);
  --maxw:1180px;
  /* form-field type scale: a field's label and the value typed into it must read as
     one deliberate hierarchy, not accidental browser defaults. Used by every label+input/select grid
     (.pf-grid, .fin-grid) so they can't drift apart from each other again. */
  --fs-field-label:var(--fs-200); --fs-field-value:var(--fs-400);
  /* feed/reality card type scale: the eyebrow label ("What it is", "Why it matters to you", "In your
     feed", etc.) and the explanation text beneath it must read as one legible size -- distinguished by
     weight/case/color, not by shrinking the label to near-illegibility. Shared by .fvr-lbl and its
     sibling body text so the two can't drift apart from each other again. */
  --fs-card-text:var(--fs-200);

  /* Type scale. 32 distinct font-size values were in use, ten of them on no scale at all
     (10px, 10.5, 14.5, 15.5, 16.5, 18, 22, 24, 30, 46). Every feature invented its own size
     because there was no scale to add to. These eleven steps are the whole vocabulary. */
  --fs-100:11px;   /* badges, the smallest text that ships */
  --fs-200:12px;   /* fine print, chip labels */
  --fs-300:13px;   /* captions, hints, table text */
  --fs-400:14px;   /* secondary body */
  --fs-500:15px;   /* body. matches the base set on <body> */
  --fs-600:17px;   /* lead-in, small headings */
  --fs-700:19px;   /* card and section headings */
  --fs-800:21px;   /* view headings */
  --fs-900:24px;   /* page headings */
  --fs-1000:30px;  /* display */
  --fs-1100:46px;
  /* Surfaces and emphasis. 0156 left these as literals because no token meant the same thing.
     They are named here rather than left loose, so a component never invents its own again. */
  --brand-900:#0f1d3a;      /* the darkest brand stop, header gradient only */
  --brand-600:#1f3a68;      /* mid brand, was the best-fit gradient's second stop */
  --ink-2:#3f4c5e;          /* the smallest text; darkened to clear AA contrast */
  --accent-bg:#fbf6e8;      /* tinted surface for an emphasised card */
  --accent-line:#e6d5a8;    /* its border */
  /* hero only */
}
*{box-sizing:border-box}
html,body{margin:0}
body{background:var(--bg);color:var(--ink);
  font:15px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;}
a{color:var(--brand);text-decoration:none}
a:hover{text-decoration:underline}
.wrap{max-width:var(--maxw);margin:0 auto;padding:0 20px}

/*  — WCAG 2.1 AA accessibility baseline
   2.4.7 Focus Visible: a strong, consistent keyboard focus ring on every
   interactive control. The 2px offset leaves a light gap so the navy ring
   stays visible on both light surfaces and navy buttons. */
:focus-visible{outline:3px solid var(--brand);outline-offset:2px;border-radius:3px}
/* keep mouse users clean, keyboard users clearly focused (no :focus-visible => hide the default only where a stronger ring exists) */

/* 2.4.1 Bypass Blocks: skip-to-content link, visible on keyboard focus */
.skip-link{position:absolute;left:8px;top:-56px;z-index:100;background:var(--brand);color:#fff;
  padding:10px 16px;border-radius:0 0 8px 8px;font-weight:700;box-shadow:var(--shadow);transition:top .15s}
.skip-link:focus{top:0;text-decoration:none}
:target{scroll-margin-top:64px}
[tabindex="-1"]:focus{outline:none}

/* 2.3.3 / respects reduced motion preference */
@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{animation-duration:.001ms!important;animation-iteration-count:1!important;transition-duration:.001ms!important;scroll-behavior:auto!important}
}

/* header */
.top{background:linear-gradient(135deg,var(--brand) 0%,var(--brand-700) 70%,var(--brand-900) 100%);color:#fff;border-bottom:3px solid var(--accent)}
.top .wrap{display:flex;align-items:center;gap:16px;padding:16px 20px;flex-wrap:wrap}
.brand-link{display:inline-block;color:inherit;text-decoration:none}
.brand-link:hover{text-decoration:none}
.brand-link:focus-visible{outline-color:#fff}
/* On the light Analysis header the white ring above would be invisible; keep keyboard focus visible there. */
/* The Analysis page header had no layout rule at all: the wordmark and Sign out stacked unstyled. */
.hdr{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap;padding:12px 16px;border-bottom:1px solid var(--line)}
.hdr-actions{display:flex;align-items:center;gap:10px}
.hdr .brand-link:focus-visible{outline-color:var(--brand)}
.an-back{margin:0 0 12px}
.brand{display:flex;flex-direction:column;line-height:1.15}
.brand b{font-size:var(--fs-800);letter-spacing:.2px}
.brand span{font-size:var(--fs-200);opacity:.85}
/* min-width:0 is the whole fix and it is not decoration. .prof is a flex ITEM of .top .wrap, and a
   flex item's default min-width is auto -- it refuses to shrink below its content. flex-wrap was
   already on, so the row wrapped, but a single chip wider than the viewport could not shrink and
   pushed the document past 375px: scrollWidth 456 against clientWidth 375, offenders div.prof and
   span.pchip. The overflow is profile-dependent, so it appeared in some scenario draws and not
   others and read as flakiness.
   The chip needs three things together or the truncation does nothing: inline-block (text-overflow
   does not apply to an inline box), a max-width to truncate against, and the overflow rule itself.
   white-space:nowrap stays -- a chip that wraps mid-value is harder to read than one that elides. */
.prof{margin-left:auto;display:flex;gap:8px;flex-wrap:wrap;justify-content:flex-end;min-width:0;max-width:100%;
  /* RESERVE THE CHIP'S HEIGHT. #prof ships empty in app.html and is filled after boot with the
     profile chip. On a phone .prof wraps onto its own line inside .top .wrap, so going from empty to
     one 22px chip grew the header 103 -> 125 and pushed the entire document down 22px -- a single
     layout shift measured at CLS 0.2501, landing at ~1.44s, almost exactly when the app becomes
     usable and a finger is most likely already on the way down.
     The height is derived, not guessed: the chip is one line of --fs-200 with 4px padding and a 1px
     border top and bottom, so the reservation tracks text scaling instead of pinning a magic 22px.
     On desktop .prof sits inline beside a 52px brand block, so this is a no-op there. */
  min-height:calc(var(--fs-200) + 10px)}
.pchip{background:rgba(255,255,255,.14);border:1px solid rgba(255,255,255,.22);
  border-radius:999px;padding:4px 11px;font-size:var(--fs-200);white-space:nowrap;
  display:inline-block;min-width:0;max-width:100%;overflow:hidden;text-overflow:ellipsis}
.pchip b{font-weight:700}

/* stepper */
.steps{display:flex;gap:8px;background:var(--surface);border-bottom:1px solid var(--line);position:sticky;top:0;z-index:20}
/* CSS-only "scroll shadow": a fade at whichever edge(s) currently have more tabs scrolled off-screen,
   so overflow-x:auto (which gives no visual cue on its own) doesn't read as "the rest are missing".
   Paired cover/shadow gradients per edge -- the cover layer scrolls WITH the content
   (background-attachment:local) and exactly hides the shadow layer, which stays fixed to the viewport
   (background-attachment:scroll), except at whichever edge the content has actually scrolled away
   from. No JS, no rect/ratio state to keep in sync with itself -- it's correct by construction at any
   scroll position, zoom level, or display-scaling factor.
   Notes: the cover gradient's transparent endpoint derives from var(--surface) via color-mix(), not a
   hardcoded rgba(255,255,255,0) -- a themed --surface stays correct instead of visibly fading through
   white first. No background-color on .wrap -- .steps (its direct parent, one rule up) already paints
   the identical var(--surface) right behind it. -webkit-overflow-scrolling:touch was dropped -- it's
   vestigial on any iOS version this app targets (native since iOS 13) and WebKit has a known history
   of not compositing background-attachment:local cleanly alongside it during momentum scroll. */
/* THE LAST TAB WAS UNREACHABLE ON A PHONE. A horizontally scrolling flex container does not
   include its trailing padding in the scrollable overflow area, so scrollLeft maxed out with the
   final tabs still sitting behind that 20px inset: measured at 390px, five tabs were clipped and
   two of them stayed clipped at maximum scroll. Leading padding is honoured, so only the trailing
   side moves -- to a flex spacer, which DOES extend scrollWidth. Same visual inset at both ends,
   and the end of the strip can now actually be scrolled to. Scoped to .steps .wrap; the other
   .wrap users (.top, .tray, .utilbar) are untouched. */
.steps .wrap{display:flex;gap:6px;padding:0 0 0 20px;overflow-x:auto;
  background-image:
    linear-gradient(to right, var(--surface) 30%, color-mix(in srgb, var(--surface) 0%, transparent)),
    linear-gradient(to left, var(--surface) 30%, color-mix(in srgb, var(--surface) 0%, transparent)),
    linear-gradient(to right, rgba(20,39,78,.15), rgba(20,39,78,0)),
    linear-gradient(to left, rgba(20,39,78,.15), rgba(20,39,78,0));
  background-repeat:no-repeat;
  background-size:40px 100%, 40px 100%, 14px 100%, 14px 100%;
  background-position:left, right, left, right;
  background-attachment:local, local, scroll, scroll}
.steps .wrap::after{content:"";flex:0 0 20px;align-self:stretch}
.step{appearance:none;background:none;border:none;cursor:pointer;color:var(--muted);flex-shrink:0;
  font-weight:600;font-size:var(--fs-300);line-height:1;font-family:inherit;padding:15px 14px;border-bottom:3px solid transparent;display:flex;align-items:center;gap:8px}
.step .n{display:inline-grid;place-items:center;width:20px;height:20px;border-radius:999px;background:var(--line);color:var(--muted);font-size:var(--fs-100)}
.step.active{color:var(--brand);border-bottom-color:var(--brand)}
.step.active .n{background:var(--brand);color:#fff}
.step:hover{color:var(--ink)}

main{padding:22px 0 120px}
.view{display:none}
.view:not(.hidden){display:block}
.h{font-size:var(--fs-800);margin:0 0 4px}
.sub{color:var(--muted);margin:0 0 18px;font-size:var(--fs-300)}

/* finder */
.finder{display:grid;grid-template-columns:1fr;gap:16px}
.qcard{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);padding:16px 18px;box-shadow:var(--shadow)}
.qcard h3{margin:0 0 3px;font-size:var(--fs-400)}
.qcard p.hint{margin:0 0 12px;color:var(--muted);font-size:var(--fs-200)}
.chips{display:flex;flex-wrap:wrap;gap:8px}
.chip{appearance:none;cursor:pointer;border:1px solid var(--line);background:var(--surface-2);
  color:var(--ink);border-radius:999px;padding:7px 13px;font-weight:600;font-size:var(--fs-300);line-height:1;font-family:inherit;transition:.12s}
.chip:hover{border-color:var(--brand)}
.chip.sel{background:var(--brand);border-color:var(--brand);color:#fff}
.chip.star.sel{background:var(--accent);border-color:var(--accent)}
.qgrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:16px}
/* THE ACTION BAR IS STICKY TO THE BOTTOM OF THE SCROLLPORT, WHICH IS WHERE THE TRAY LIVES.
   This is the mechanism behind the "Show matches" hit-test failure, and it is why reserving space
   at the end of the document does not touch it: a sticky element positions against the viewport,
   not the document, so no amount of trailing padding moves it out from under a fixed overlay. It
   has to be told about the tray. --tray-h is 0px whenever the tray is hidden, so the bar sits at
   its designed 16px in the ordinary case and lifts by exactly the tray's measured height when the
   tray is up -- at every viewport, because the number is measured rather than assumed.
   Observed before the fix, desktop 1440x900: the button at y 846-884, topmost element
   div#tray-picked. */
.finder-actions{position:sticky;bottom:calc(16px + var(--tray-h,0px));display:flex;gap:12px;align-items:center;justify-content:center;margin-top:6px}
.btn{appearance:none;cursor:pointer;border:1px solid var(--brand);background:var(--brand);color:#fff;
  border-radius:10px;padding:11px 20px;font-weight:700;font-size:var(--fs-400);line-height:1;font-family:inherit;box-shadow:var(--shadow)}
.btn:hover{background:var(--brand-700)}
.btn.ghost{background:var(--surface);color:var(--brand)}
.btn.sm{padding:7px 12px;font-size:var(--fs-200);border-radius:8px}
.btn:disabled{opacity:.5;cursor:not-allowed}

/* results */
.rbar{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:14px}
.rbar .count{color:var(--muted);font-size:var(--fs-300)}
.rbar input[type=search]{flex:1;min-width:180px;border:1px solid var(--line);border-radius:9px;padding:9px 12px;font:inherit;background:var(--surface)}
.cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:14px}
.card{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);padding:15px 16px;box-shadow:var(--shadow);display:flex;flex-direction:column;gap:9px;position:relative}
.card .name{font-weight:700;font-size:var(--fs-500);padding-right:54px}
.card .loc{color:var(--muted);font-size:var(--fs-200)}
.match{position:absolute;top:13px;right:14px;font-weight:700;font-size:var(--fs-300);color:var(--brand);background:var(--info-bg);border-radius:8px;padding:3px 8px}
.tags{display:flex;flex-wrap:wrap;gap:6px}
.tag{font-size:var(--fs-100);padding:3px 8px;border-radius:6px;background:var(--surface-2);border:1px solid var(--line);color:var(--muted)}
.tag.good{background:var(--good-bg);color:var(--good);border-color:transparent}
.tag.warn{background:var(--warn-bg);color:var(--warn);border-color:transparent}
.tag.bad{background:var(--bad-bg);color:var(--bad);border-color:transparent}
.tag.brand{background:var(--info-bg);color:var(--brand);border-color:transparent}
.tag.wrest{background:#efe9ff;color:#6a4bd1;border-color:transparent}
.card .row{display:flex;justify-content:space-between;align-items:center;gap:8px;margin-top:auto}
.locked-dot{display:inline-block;width:7px;height:7px;border-radius:999px;background:var(--accent);margin-right:5px;vertical-align:middle}
.empty{background:var(--surface);border:1px dashed var(--line);border-radius:var(--radius);padding:40px;text-align:center;color:var(--muted)}
/* WCAG 1.4.1: links sitting inside running prose are marked only by colour, because the global
   a{text-decoration:none} strips the underline and :hover puts it back too late to help. Scoped to
   the same domain the rule actually covers -- links inside a text block -- rather than to the ids
   that happened to be on screen when the gate ran. Measured across every view before widening it:
   7 links match, 5 are footer links already underlined, and the only 2 that change are the two
   defective ones. Nav, cards and control-styled links are untouched. */
.empty a,p a,li a{text-decoration:underline}

/* compare */
.cmp-wrap{overflow:auto;border:1px solid var(--line);border-radius:var(--radius);box-shadow:var(--shadow);background:var(--surface)}
table.cmp{border-collapse:collapse;width:100%;min-width:680px}
table.cmp th,table.cmp td{padding:11px 13px;border-bottom:1px solid var(--line);text-align:left;vertical-align:top;font-size:var(--fs-300)}
table.cmp thead th{position:sticky;top:0;background:var(--brand);color:#fff;font-size:var(--fs-200);z-index:1}
table.cmp tbody th{background:var(--surface-2);font-weight:600;color:var(--muted);white-space:nowrap;position:sticky;left:0}
table.cmp td .pill{display:inline-block;border-radius:6px;padding:2px 8px;font-size:var(--fs-200);font-weight:600}
.pill.good{background:var(--good-bg);color:var(--good)} .pill.warn{background:var(--warn-bg);color:var(--warn)} .pill.bad{background:var(--bad-bg);color:var(--bad)} .pill.info{background:var(--info-bg);color:var(--brand)}
/*  (WCAG 1.4.3): "remove" sits in the navy sticky header (thead th, bg=var(--brand)
   var(--brand)). --bad var(--bad) on navy was 2.59:1 — fail. Light error tint #ffb4ab on navy = 8.68:1. */
.rm{cursor:pointer;color:#ffb4ab;background:none;border:none;font-size:var(--fs-200)}

/* scholarships */
.scards{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px}
.scards>p.hint{grid-column:1/-1;margin:0 0 4px;color:var(--muted,#6b7280);font-size:var(--fs-200)}
.scard{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);padding:13px 15px;box-shadow:var(--shadow)}
.scard .nm{font-weight:700;font-size:var(--fs-400);margin-bottom:3px}
.scard .amt{font-weight:700;color:var(--brand)}
.scard .meta{color:var(--muted);font-size:var(--fs-200);margin-top:6px}
.scard-v2 .tag{margin-left:4px}
.sc-gates{list-style:none;margin:8px 0 0;padding:0;display:flex;flex-direction:column;gap:6px}
.sc-gate{font-size:var(--fs-200);padding:6px 8px;border-radius:6px;background:var(--bg,#f7f8fa);border:1px solid var(--line)}
.sc-gate .meta{margin-top:2px}
.sc-gate-ico{display:inline-block;width:14px;text-align:center;font-weight:700}
.sc-gate-good .sc-gate-ico{color:var(--good,#1c8a4b)}
.sc-gate-warn .sc-gate-ico{color:var(--gold,var(--accent))}
.sc-gate-info .sc-gate-ico{color:var(--muted,#6b7280)}

/* sticky compare bar
   THE TRAY IS AN OVERLAY AND THE PAGE HAS TO MAKE ROOM FOR IT. position:fixed takes the tray out of
   flow, so once a school was added it slid up over whatever occupied the bottom of the viewport --
   including the "Show matches" button, which a real hit test (elementFromPoint at the button's own
   centre) reported as covered by div#tray-picked. This is NOT phone-only: one of the eight observed
   failures was desktop 1440x900, so a mobile-breakpoint fix would not have cleared it.
   --tray-h is written by tray() in app.js from the tray's own measured height, because the tray
   wraps and its height depends on how many schools are picked and how long their names are; a
   hardcoded padding would be right at one tray size and wrong at every other. It is 0 while the
   tray is hidden, so nothing reserves space that nothing occupies. */
.tray{position:fixed;left:0;right:0;bottom:0;background:var(--surface);border-top:1px solid var(--line);
  box-shadow:0 -6px 20px rgba(16,32,54,.08);transform:translateY(110%);transition:.2s;z-index:30}
.tray.show{transform:none}
body{padding-bottom:var(--tray-h,0px)}
@media print{body{padding-bottom:0!important}}
.tray .wrap{display:flex;align-items:center;gap:12px;padding:12px 20px;flex-wrap:wrap}
.tray .picked{display:flex;gap:6px;flex-wrap:wrap;flex:1}
.tray .pk{background:var(--info-bg);border-radius:999px;padding:4px 10px;font-size:var(--fs-200);display:flex;gap:6px;align-items:center}
.tray .pk b{font-weight:600}
.tray .pk button{border:none;background:none;color:var(--muted);cursor:pointer;font-size:var(--fs-300);line-height:1;
  /* THE HIT AREA IS BIGGER THAN THE GLYPH. This rendered 20x15 -- under the 44x44 WCAG 2.5.5 target
     and under even the 24x24 WCAG 2.2 AA floor -- and it is how a parent drops a school on a phone.
     The overlay below grows the touch target to 44x44 without changing the visual chip at all:
     position:relative plus an absolutely centred ::after costs no layout space, so the tray keeps
     its compact appearance and nothing reflows. Chips carry a real gap, so neighbouring targets do
     not collide. */
  position:relative}
.tray .pk button::after{content:"";position:absolute;left:50%;top:50%;
  width:44px;height:44px;transform:translate(-50%,-50%)}
.tray .pk button:focus-visible{outline:3px solid var(--brand);outline-offset:2px;border-radius:999px}
/* A 44x44 target cannot sit inside a 22px chip in a WRAPPED list without colliding with the chip on
   the row below -- measured: 5 overlapping pairs. So on touch pointers the chip itself becomes a
   real touch row. This is gated on `pointer:coarse`, a capability query, NOT a viewport width and
   NOT user-agent sniffing: a mouse user keeps the compact 22px tray exactly as designed, and anyone
   driving the page with a finger gets a row their finger can actually hit. */
@media (pointer:coarse){
  #tray-picked{display:flex;flex-wrap:wrap;gap:8px}
  .tray .pk{min-height:44px}
}
.note{font-size:var(--fs-100);color:var(--muted);margin-top:14px;line-height:1.45}
.foot{border-top:1px solid var(--line);color:var(--muted);font-size:var(--fs-100);padding:16px 0;margin-top:30px}
@media print{.top,.steps,.tray,.finder-actions,.rbar,.btn{display:none!important}.view:not(.hidden){display:block!important}}


/* profile editor */
.pchip-cta{cursor:pointer;border:1px dashed rgba(255,255,255,.55);background:rgba(255,255,255,.10);color:#fff;font-weight:600;font-size:var(--fs-200);line-height:1;font-family:inherit}
.pchip-cta:hover{background:rgba(255,255,255,.2)}
/* `safe center`: centre the card, but never centre it OFF the viewport. At 200% zoom the card is taller
   than the viewport and plain centring pushed its top (and the close control) above the screen; the
   overlay scrolls instead. The plain value stays first as the fallback for engines without `safe`. */
.pmodal{position:fixed;inset:0;background:rgba(16,32,54,.45);display:grid;place-items:center;place-items:safe center;overflow:auto;z-index:40}
.pmodal.hidden{display:none}

/*  — lean card headline stat + click-to-expand school detail */
/*  (WCAG 4.1.2 nested-interactive): the whole card is no longer clickable
   (that nested a button + a link inside a role="button"). Keep the hover-lift affordance,
   but drop cursor:pointer so the card no longer signals a non-existent whole-card action —
   detail now opens from the real .viewmore <button> below. */
.card.clickable{transition:box-shadow .15s,transform .15s}
.card.clickable:hover{box-shadow:0 8px 22px rgba(16,32,54,.12);transform:translateY(-1px)}
.admitline{font-size:var(--fs-300);color:var(--ink)}
.admitline b{color:var(--brand);}
.trend{font-size:var(--fs-200);font-weight:700;white-space:nowrap}
.trend.down{color:var(--good)}.trend.up{color:var(--bad)}.trend.flat{color:var(--muted);font-weight:400}
.prov{color:var(--muted);cursor:help;font-size:var(--fs-100)}
/* : .viewmore is now a real <button> (keyboard-focusable); reset the button
   chrome so it keeps the original inline text-link look. The :focus-visible ring (top of file) applies. */
.viewmore{appearance:none;background:none;border:none;padding:0;cursor:pointer;color:var(--brand);font-weight:600;font-size:var(--fs-200);line-height:1;font-family:inherit;text-align:left}
.viewmore:hover{text-decoration:underline}
.sd-card{max-width:560px;width:92%;max-height:88vh;overflow:auto;text-align:left;position:relative;padding:20px}
.sd-close{position:absolute;top:10px;right:12px;border:none;background:transparent;font-size:var(--fs-600);color:var(--muted);cursor:pointer;line-height:1}
.sd-head h3{margin:0 40px 2px 0;font-size:var(--fs-700)}
.sd-loc{color:var(--muted);font-size:var(--fs-300)}
.sd-sec{margin-top:16px}
.sd-sec h4{margin:0 0 8px;font-size:var(--fs-100);text-transform:uppercase;letter-spacing:.05em;color:var(--muted)}
.sd-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px}
.sd-stat{background:var(--surface-2);border:1px solid var(--line);border-radius:8px;padding:9px 11px}
.sd-k{font-size:var(--fs-100);color:var(--muted);margin-bottom:2px}
.sd-v{font-size:var(--fs-500);color:var(--ink)}.sd-v b{color:var(--brand)}
.sd-note{font-size:var(--fs-100);color:var(--muted);font-weight:400}
.sd-stale{color:var(--warn)}
.sd-prov{margin-top:14px;font-size:var(--fs-100);color:var(--muted);line-height:1.5}
.sd-actions{display:flex;gap:8px;justify-content:flex-end;margin-top:18px}
/* : "what this school weighed most" — C7 factor weights grouped by importance */
.sd-c7row{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin-bottom:8px}
.sd-c7lvl{font-size:var(--fs-100);font-weight:700;text-transform:uppercase;letter-spacing:.04em;padding:2px 8px;border-radius:999px;white-space:nowrap}
.sd-c7lvl.vi{background:var(--brand);color:#fff}
.sd-c7lvl.imp{background:var(--brand);color:#fff;opacity:.72}
.sd-c7lvl.con{background:var(--surface-2);color:var(--muted);border:1px solid var(--line)}
.sd-c7lvl.not{background:transparent;color:var(--muted);border:1px dashed var(--line)}
.sd-c7f{font-size:var(--fs-200);color:var(--ink);background:var(--surface-2);border:1px solid var(--line);border-radius:6px;padding:2px 8px}
@media(max-width:480px){.sd-grid{grid-template-columns:1fr}}
/*  (S4): Admissions trend + plain-language inferences (per-school detail) */
.sd-tbars{display:flex;flex-direction:column;gap:6px;margin:2px 0 10px}
.sd-tbar{display:grid;grid-template-columns:52px 1fr 46px;align-items:center;gap:8px}
.sd-tyr{font-size:var(--fs-100);color:var(--muted);text-align:right}
.sd-ttrack{height:10px;background:var(--surface-2);border:1px solid var(--line);border-radius:999px;overflow:hidden}
.sd-tfill{display:block;height:100%;background:var(--line)}
.sd-tfill.last{background:var(--brand)}
.sd-tval{font-size:var(--fs-200);font-weight:700;color:var(--ink)}
.sd-infer{font-size:var(--fs-200);line-height:1.5;color:var(--ink);background:var(--surface-2);border:1px solid var(--line);border-left:3px solid var(--line);border-radius:8px;padding:8px 10px;margin-top:6px}
.sd-infer.good{border-left-color:var(--good)}
.sd-infer.info{border-left-color:var(--brand)}
.sd-infer-lab{font-weight:700;color:var(--brand)}
.sd-infer.good .sd-infer-lab{color:var(--good)}

/* /0070 — finance UX: Chapter 35, loan planner, Parent PLUS info bubble (room, not crammed) */
.ch35-opt{display:flex;align-items:center;gap:8px;margin:10px 0 4px}
.ch35-grid{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin:6px 0}
.ch35-grid label{font-size:var(--fs-200);color:var(--muted)}
.nc-plan{margin-top:14px;padding:13px 14px;background:var(--surface-2);border:1px solid var(--line);border-radius:10px}
.nc-plan-hd{display:flex;justify-content:space-between;align-items:baseline;font-weight:600;font-size:var(--fs-300);margin-bottom:8px}
.nc-plan-net{color:var(--brand);font-size:var(--fs-300)}
.nc-plan .nc-line{padding:5px 0}
.nc-plan .nc-line small{color:var(--muted);font-weight:400}
.nc-plan-out{margin-top:9px;border-top:1px solid var(--line);padding-top:9px;font-size:var(--fs-300)}
.nc-gap-bad{color:var(--bad);margin-top:4px}
.nc-atmax{color:var(--muted);font-size:var(--fs-200);margin-top:4px}
.nc-cap{font-size:var(--fs-100);color:var(--warn);margin:-2px 0 4px}
.cmp-next{display:flex;flex-direction:column;align-items:center;gap:8px;margin:20px 0 6px;text-align:center}
.cmp-next-lab{font-size:var(--fs-300);color:var(--muted)}
.cmp-next .btn{font-size:var(--fs-500);padding:10px 22px}
/* paired back+forward buttons at the bottom of a step, matching each other's
   reachability -- without this, a forward CTA at scroll-bottom left the back link stranded at the top. */
.cmp-next-btns{display:flex;gap:10px;flex-wrap:wrap;justify-content:center}
.nc-gi{margin-top:14px;padding:13px 14px;background:var(--info-bg);border:1px solid var(--line);border-radius:10px}
.nc-gi-hd{display:flex;justify-content:space-between;flex-wrap:wrap;gap:6px;font-weight:600;font-size:var(--fs-300);margin-bottom:8px}
.nc-gi .nc-line{padding:4px 0}
.nc-gi .nc-line small{color:var(--muted);font-weight:400}
.nc-gi-tot{display:flex;justify-content:space-between;border-top:1px solid var(--line);margin-top:6px;padding-top:6px;font-size:var(--fs-400)}
.nc-gi-tot b{color:var(--brand)}
.gi-yes{font-size:var(--fs-100);color:var(--good);font-weight:600}
.gi-no{font-size:var(--fs-100);color:var(--muted)}
.nc-gi-gap span:last-child{color:var(--warn)}
.va-pick{margin:6px 0 8px}
.va-pick-q{font-size:var(--fs-300);font-weight:600;margin-bottom:6px}
.va-opt{display:flex;align-items:flex-start;gap:8px;padding:6px 0;font-size:var(--fs-300);line-height:1.4}
.va-opt input{margin-top:3px;flex:none}
/* .va-opt is a flex row, so a bare <b> plus its following text became TWO flex items and the 8px
   gap opened up in the middle of the sentence, detaching the colon: "Chapter 33) : as a service".
   The label is wrapped in a span so it is one item. */
.va-opt>span{flex:1}
.nc-gap-ok{color:var(--good);margin-top:4px}
.pp-info{display:inline-block;margin-left:2px}
.pp-info summary{cursor:pointer;color:var(--brand);font-size:var(--fs-100);list-style:none;display:inline}
.pp-info summary::-webkit-details-marker{display:none}
.pp-info .pp-body{margin-top:6px;padding:9px 11px;background:var(--info-bg);border:1px solid var(--line);border-radius:8px;font-size:var(--fs-100);color:var(--ink);line-height:1.55;font-weight:400}
/* position:relative on the shared base class (not just .sd-card, smodal's own
   subclass) so #pf-close's position:absolute anchors to the card, not the full-screen overlay. */
.pmodal-card{position:relative;background:var(--surface);border-radius:var(--radius);box-shadow:var(--shadow);padding:20px 22px;width:min(560px,92vw);max-height:88vh;overflow:auto}
.pmodal-card h3{margin:0 0 3px;font-size:var(--fs-500)}
.pf-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px 14px;margin:14px 0}
.pf-grid label,.fin-grid label{display:flex;flex-direction:column;font-size:var(--fs-field-label);color:var(--muted);gap:4px;min-width:0}
.pf-grid input,.pf-grid select,.fin-grid input,.fin-grid select{border:1px solid var(--line);border-radius:8px;padding:8px 10px;font-size:var(--fs-field-value);font-family:inherit;color:var(--ink);background:#fff;width:100%;min-width:0}
.pf-actions{display:flex;gap:10px;justify-content:flex-end}
@media(max-width:560px){.pf-grid{grid-template-columns:1fr}}

.help{display:inline-grid;place-items:center;width:15px;height:15px;border-radius:999px;background:var(--line);color:var(--muted);font-size:var(--fs-100);font-weight:700;cursor:help}
.help:hover{background:var(--brand);color:#fff}


/* ENVS family branding + legal footer */
.brand .gold{color:var(--accent)}
.brand .prop{display:inline-block;margin-left:10px;padding-left:10px;border-left:1px solid rgba(255,255,255,.28);font-size:var(--fs-100);font-weight:700;letter-spacing:.5px;text-transform:uppercase;color:var(--accent);white-space:nowrap}
.rp{margin-left:12px;align-self:center;font-size:var(--fs-100);font-weight:700;letter-spacing:.5px;text-transform:uppercase;color:var(--accent);border:1px solid rgba(255,255,255,.32);border-radius:999px;padding:3px 9px;white-space:nowrap}
.foot .disclaimer{font-size:var(--fs-100);color:var(--muted);line-height:1.5;margin:0 0 8px}
.foot .meta{font-size:var(--fs-100);color:var(--muted);margin:0 0 6px}
.foot .copyr{font-size:var(--fs-100);color:var(--muted);font-weight:600;margin:0}
.foot .footlinks{font-size:var(--fs-100);margin:8px 0 0}
.foot .footlinks a{color:var(--brand);text-decoration:underline;
  /* These measured 13px tall. Padding lifts each link to a 24px minimum target and puts real space
     between neighbours, which matters more here than raw height: they sit inline separated by
     middots, so without spacing two adjacent 44px areas would overlap and a thumb could activate
     the wrong policy page. inline-block is required for vertical padding to apply at all. */
  display:inline-block;min-height:24px;padding:6px 4px;margin:0 2px}
.foot .footlinks a:focus-visible{outline:3px solid var(--brand);outline-offset:2px}


/* Sprint 2: utility bar, field help, finances */
.utilbar{background:var(--surface-2);border-bottom:1px solid var(--line)}
.utilbar .wrap{display:flex;align-items:center;gap:12px;padding:8px 20px;flex-wrap:wrap}
.utilbar .priv{font-size:var(--fs-100);color:var(--muted)}
.utilbar .session-actions{margin-left:auto;display:flex;gap:8px}
.help{cursor:pointer}
.fieldhint{display:block;margin-top:5px;font-size:var(--fs-100);color:var(--brand);background:var(--info-bg);border-radius:6px;padding:6px 9px;line-height:1.45}
.fin-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px 14px;margin-top:10px}
table.cmp.fin td{vertical-align:middle}
.npc-pre{color:var(--muted);margin-right:3px}
.npc-in{width:150px;border:1px solid var(--line);border-radius:8px;padding:7px 9px;font:inherit;background:#fff}
@media(max-width:560px){.fin-grid{grid-template-columns:1fr}}

/* Finances v1 — "Your numbers" + per-school net-price cards */
.fin-pell{margin-top:12px;padding:9px 11px;background:var(--info-bg);border-radius:8px;font-size:var(--fs-200);color:var(--brand)}
.fin-pell .fin-pellval b{font-weight:700}
.fin-pell .fin-pellnote{color:var(--muted)}
.fin-pell .fin-pellhint{color:var(--muted)}
.nc-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(330px,1fr));gap:14px;margin-top:16px}
.nc-card{display:flex;flex-direction:column;gap:0;padding:15px 17px}
.nc-head{display:flex;align-items:center;justify-content:space-between;gap:10px}
.nc-name{font-weight:700;font-size:var(--fs-500);color:var(--ink)}
.nc-head .pill{display:inline-block;border-radius:6px;padding:3px 9px;font-size:var(--fs-100);font-weight:700;white-space:nowrap}
.nc-loc{color:var(--muted);font-size:var(--fs-200);margin:3px 0 12px}
.nc-flow{border-top:1px solid var(--line);padding-top:8px}
.nc-line{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:6px 0;font-size:var(--fs-300)}
.nc-line.nc-sub{color:var(--muted)}
.nc-line.nc-total{border-top:1px solid var(--line);margin-top:4px;padding-top:10px;font-weight:700;color:var(--brand);font-size:var(--fs-500)}
.nc-line.nc-total small{font-weight:400;color:var(--muted);font-size:var(--fs-200)}
.nc-na{color:var(--muted);font-size:var(--fs-200)}
.nc-inwrap{display:inline-flex;align-items:center}
.nc-in{width:140px;border:1px solid var(--line);border-radius:8px;padding:6px 8px;font:inherit;background:#fff;text-align:right}
.nc-in:focus{border-color:var(--brand)} /* : outline:none removed so keyboard focus stays visible (2.4.7); :focus-visible ring above applies */
/* Where the figures come from: our estimate, the school's calculator, or an aid offer. */
.nc-src{margin:0 0 12px;background:var(--surface-2);border:1px dashed var(--line);border-radius:9px;padding:10px 12px;min-width:0}
.nc-src legend{font-size:var(--fs-200);font-weight:600;color:var(--ink);padding:0 4px}
.nc-src-opts{display:flex;flex-wrap:wrap;gap:6px 14px}
.nc-src-opt{display:inline-flex;align-items:center;gap:6px;font-size:var(--fs-200);color:var(--ink);cursor:pointer}
.nc-schfig{margin-top:8px;border-top:1px solid var(--line);padding-top:4px}
.nc-schfig .nc-line label,.nc-flow .nc-line label{font-size:var(--fs-300);color:inherit}
.rep-sub{padding-left:12px;color:var(--muted)}
/* A money figure never breaks between its sign and its digits. */
.nc-flow .nc-line>span:last-child,.rep-water .nc-line>span:last-child{white-space:nowrap}
/* The value column is a figure and never wraps; the label column carries any explanation and must be
   free to wrap, or a long label pushes the figure off the page. */
.rep-water .nc-line>span:first-child{min-width:0;overflow-wrap:anywhere}
.rep-plan{border-top:1px solid var(--line)}
.nc-verdict{margin-top:12px;border-radius:9px;padding:9px 12px;font-size:var(--fs-200);line-height:1.4}
.nc-verdict b{font-weight:700}
.nc-verdict.good{background:var(--good-bg);color:var(--good)}
.nc-verdict.warn{background:var(--warn-bg);color:var(--warn)}
.nc-verdict.bad{background:var(--bad-bg);color:var(--bad)}
.nc-verdict.info{background:var(--info-bg);color:var(--brand)}
.nc-who{margin-top:10px;font-size:var(--fs-200);color:var(--muted);line-height:1.6}
.nc-who b{color:var(--ink);font-weight:700}
.nc-wlab{font-weight:700;color:var(--ink)}
.nc-loan{margin-top:2px}
.nc-foot{margin-top:12px}
.nc-link{font-size:var(--fs-200);font-weight:600}
.nc-disc{margin-top:18px;background:var(--surface-2);border:1px solid var(--line);border-radius:9px;padding:11px 13px}
.nc-disc b{color:var(--brand)}
@media(max-width:560px){.nc-in{width:110px}}

/* ---------- Trends surface (social-feed theme prevalence) ---------- */
.tcards{display:flex;flex-direction:column;gap:10px;margin-top:14px}
.tcard{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius-sm);
  box-shadow:var(--shadow);padding:12px 14px}
.tc-head{display:flex;align-items:baseline;justify-content:space-between;gap:12px}
.tc-topic{font-weight:700;color:var(--brand);font-size:var(--fs-500)}
.tc-posts{color:var(--muted);font-size:var(--fs-200);white-space:nowrap}
.tc-bar{height:8px;background:var(--info-bg);border-radius:999px;margin:8px 0 6px;overflow:hidden}
.tc-bar>span{display:block;height:100%;background:linear-gradient(90deg,var(--brand),var(--accent));border-radius:999px}
.tc-claim{color:var(--ink);font-size:var(--fs-300);line-height:1.45}
#trends-meta{margin:6px 0 2px}
#trends-foot{margin-top:14px;color:var(--muted);font-size:var(--fs-200)}
.tc-sub{color:var(--muted);font-size:var(--fs-200);margin-top:6px}
.tc-posts b{color:var(--ink)}
.cmp-empty{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);
  box-shadow:var(--shadow);padding:22px;max-width:620px}
.cmp-empty h3{margin:0 0 8px;color:var(--brand);font-size:var(--fs-600)}
.cmp-empty p{margin:0 0 12px;color:var(--ink)}
.cmp-steps{margin:0 0 16px;padding-left:20px;color:var(--ink);line-height:1.7}
.cmp-steps b{color:var(--brand)}

/* ---------- majors multi-select dropdown (max 3) + federal-law note ---------- */
.msel{position:relative}
.msel-btn{width:100%;display:flex;align-items:center;justify-content:space-between;gap:8px;
  background:var(--surface);border:1px solid var(--line);border-radius:var(--radius-sm);
  padding:10px 12px;cursor:pointer;color:var(--muted);font:inherit;text-align:left}
.msel-btn.has{color:var(--ink);border-color:var(--brand-700)}
.msel-lab{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.msel-caret{color:var(--muted);font-size:var(--fs-200)}
.msel-panel{position:absolute;z-index:30;left:0;right:0;margin-top:6px;background:var(--surface);
  border:1px solid var(--line);border-radius:var(--radius-sm);box-shadow:var(--shadow);
  padding:6px;max-height:280px;overflow:auto}
.msel-panel.hidden{display:none}
.msel-opt{width:100%;display:flex;align-items:center;gap:8px;background:none;border:none;cursor:pointer;
  padding:8px 10px;border-radius:7px;font:inherit;color:var(--ink);text-align:left}
.msel-opt:hover{background:var(--surface-2)}
.msel-opt.on{color:var(--brand);font-weight:600}
.msel-opt.dis{color:var(--muted);cursor:not-allowed;opacity:.55}
.msel-check{display:inline-grid;place-items:center;width:18px;height:18px;border-radius:5px;
  border:1px solid var(--line);color:#fff;font-size:var(--fs-100);background:var(--surface)}
.msel-opt.on .msel-check{background:var(--brand);border-color:var(--brand)}
.msel-foot{color:var(--muted);font-size:var(--fs-200);padding:6px 10px 2px;border-top:1px solid var(--line);margin-top:4px}
.lawnote{margin:10px 0 0;font-size:var(--fs-200);line-height:1.5;color:var(--muted);
  background:var(--info-bg);border-radius:8px;padding:9px 11px}
.lawnote b{color:var(--brand)}

/*  — Finances COA worksheet (Sprint 3) */
.nc-coahd{font-weight:600;border-top:1px solid var(--line,#e6e8ee);padding-top:8px;margin-top:6px}
.nc-coatot{font-weight:700}
.nc-coanote{font-size:var(--fs-100);color:var(--muted,#6b7280);margin:2px 0 6px;line-height:1.4}
.nc-comp span:first-child{color:var(--muted,#6b7280);font-size:var(--fs-300)}
.nc-comp .nc-in{max-width:120px}

.sch-h{grid-column:1/-1;font-size:var(--fs-300);font-weight:700;color:var(--brand,var(--brand));margin:16px 0 6px;border-bottom:1px solid var(--line,#e6e8ee);padding-bottom:3px}
.sch-h:first-child{margin-top:0}

/*  — veteran aid + ED/school-reported panel (Sprint 4) */
.fin-vatog{display:flex;align-items:center;gap:8px;margin:8px 0;font-size:var(--fs-field-value);font-weight:600;cursor:pointer}
.fin-va{margin-top:6px}
.nc-ed{display:flex;align-items:center;gap:8px;margin-top:10px}
.nc-edlab{font-size:var(--fs-300);color:var(--muted,#6b7280)}
.fin-ed{padding:4px 6px}
.nc-cds{margin-top:6px;padding:8px 10px;border:1px solid var(--line,#e6e8ee);border-radius:8px;background:rgba(20,39,78,.04);font-size:var(--fs-300)}
.nc-cdsmeta{font-size:var(--fs-100);color:var(--muted,#6b7280);margin-top:3px}
.nc-cdsverify{background:rgba(200,164,77,.10);border-color:var(--gold,var(--accent))}
.nc-aidreal{margin-top:6px;padding:8px 10px;border:1px solid var(--line,#e6e8ee);border-radius:8px;background:rgba(20,39,78,.04);font-size:var(--fs-300)}
.nc-aidreal>b{display:block;margin-bottom:4px}
.nc-aid-hd{font-weight:600}

/* ----------  Trends redesign: provenance banner + toggle + feed-vs-reality cards ---------- */
.pv-banner{display:flex;gap:10px;flex-wrap:wrap;margin:14px 0 16px}
.pv-tile{flex:1;min-width:150px;background:var(--card,#f6f6f8);border:1px solid var(--line,#e6e8ee);border-radius:10px;padding:12px 14px}
.pv-n{font-size:var(--fs-900);font-weight:700;letter-spacing:-.02em}
.pv-l{font-size:var(--fs-100);color:var(--muted,#6b6b70);margin-top:2px}
.tg{display:flex;gap:6px;margin:0 0 16px;flex-wrap:wrap}
.tg-pill{padding:6px 13px;border-radius:16px;font-size:var(--fs-200);border:1px solid var(--line,#e6e8ee);background:var(--card,#f1f1f4);color:var(--muted,#6b6b70);cursor:pointer}
/*  (WCAG 1.4.3): active lens pill was white on gold (--accent var(--accent)) = 2.37:1 — fail.
   Keep the gold "active" tint; use navy text (var(--brand) var(--brand)) instead = 6.22:1. */
.tg-pill.on{background:var(--accent,var(--accent));color:var(--brand);border-color:transparent;font-weight:600}
.tg-pill.tg-off{opacity:.45;cursor:not-allowed}
.fvr-wrap{display:flex;flex-direction:column;gap:11px}
.fvr{border:1px solid var(--line,#e6e8ee);border-radius:11px;overflow:hidden}
.fvr-head{display:flex;align-items:center;gap:8px;padding:10px 14px;background:var(--card,#f6f6f8)}
.fvr-t{font-size:var(--fs-400);font-weight:700}
.fvr-pct{margin-left:auto;font-size:var(--fs-200);font-weight:600;color:var(--muted,#6b6b70);border:1px solid var(--line,#e6e8ee);border-radius:20px;padding:2px 9px;background:var(--bg,#fff)}
.fvr-cols{display:grid;grid-template-columns:1fr 1fr}
.fvr-c{padding:12px 14px}
.fvr-feed{border-right:1px solid var(--line,#e6e8ee)}
.fvr-lbl{font-size:var(--fs-card-text);font-weight:700;text-transform:uppercase;letter-spacing:.04em;margin-bottom:5px}
/*  (WCAG 1.4.3): feed/reality labels sit on the ~white trends bg (var(--bg)).
   var(--bad) was 3.72:1 and var(--good) was 3.14:1 — fail. Reuse the  darkened tokens:
   --bad var(--bad) = 5.30:1, --good var(--good) = 5.00:1. */
.fvr-feed .fvr-lbl{color:var(--bad)}
.fvr-real .fvr-lbl{color:var(--good)}
.fvr-c>div:last-child{font-size:var(--fs-card-text);line-height:1.5}
.dot{width:10px;height:10px;border-radius:50%;display:inline-block;flex:none}
.dot-green{background:var(--good)}.dot-amber{background:var(--warn)}.dot-red{background:var(--bad)}
.lg{font-size:var(--fs-100);color:var(--muted,#6b6b70);margin-right:14px;display:inline-flex;align-items:center;gap:5px}
@media(max-width:560px){.fvr-cols{grid-template-columns:1fr}.fvr-feed{border-right:none;border-bottom:1px solid var(--line,#e6e8ee)}}

/* ----------  Academic Fit (opt-in + per-card fit chip) ---------- */
.acad-opt{display:flex;align-items:center;gap:8px;cursor:pointer;font-size:var(--fs-400)}
.acad-opt input{width:16px;height:16px}
.acad-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:10px;margin-top:10px}
.acad-f{display:flex;flex-direction:column;gap:4px;font-size:var(--fs-200);color:var(--muted,#6b6b70)}
.acad-f input{padding:8px 10px;border:1px solid var(--line,#e6e8ee);border-radius:8px;font-size:var(--fs-400);color:var(--text,#1c1c1e)}
.fit{margin:8px 0 2px;padding:8px 11px;border-radius:9px;font-size:var(--fs-200);line-height:1.5;border:1px solid var(--line,#e6e8ee);background:var(--card,#f6f6f8)}
.fit-band{font-weight:700;text-transform:uppercase;letter-spacing:.03em;font-size:var(--fs-100);padding:2px 8px;border-radius:20px;margin-right:6px;color:#fff}
.fit-like .fit-band{background:var(--good)}.fit-match .fit-band{background:var(--warn)}.fit-reach .fit-band{background:var(--bad)}.fit-unlikely .fit-band{background:var(--ink)}
.fit-like{border-color:#bfe6d3}.fit-match{border-color:#f0dcb0}.fit-reach{border-color:#f0c4bf}.fit-unlikely{border-color:#c9ccd2}
.fit-cav{color:var(--muted,#6b6b70);font-style:italic}
.fit-na{color:var(--muted,#6b6b70)}
/* The fit block reads at two lengths and is ONE component at both. On a results card it is a band,
   one sentence and the caveat, because a family there is comparing schools rather than reading one.
   In the school detail and the printed report the same component opens out into labelled rows.
   No new callout, no new colour, and deliberately NO NEW FONT SIZE anywhere below: the block still
   spends exactly the two type steps it always spent (.fit and .fit-band), which is what keeps a
   card inside the four-size ceiling the design gate enforces while gaining structure. */
.fit-more{color:var(--muted,#6b6b70)}
.fit-rows{margin:8px 0 0;padding:0}
.fit-rows>div{display:grid;grid-template-columns:minmax(0,9.5rem) minmax(0,1fr);gap:2px 12px;
  padding:6px 0;border-top:1px solid var(--line,#e6e8ee)}
.fit-rows dt{font-weight:600;color:var(--muted,#6b6b70)}
.fit-rows dd{margin:0}
.fit-list{margin:0;padding-left:1.05rem}
.fit-list>li{margin:.14rem 0}
.fit-note{display:block;color:var(--muted,#6b6b70);margin-top:3px}
/* One column on a phone: a 9.5rem label column beside a value leaves too little for either. */
@media(max-width:560px){.fit-rows>div{grid-template-columns:1fr;gap:1px}}
/* Inside the report the fit read sits within .rep-card, which already spends its four type steps on
   the money. It joins the report's own body step rather than importing two more of its own. */
.rep-sch .fit{font-size:var(--fs-300)}
.rep-sch .fit .fit-band{font-size:inherit}
@media(max-width:480px){.acad-grid{grid-template-columns:1fr}}

/* press/college lens cards (named, cited) */
.fvr-src .fvr-c{padding:11px 14px}
.fvr-heads{margin:2px 0 0;padding-left:18px}
.fvr-heads li{font-size:var(--fs-200);line-height:1.55;margin-bottom:3px}
.fvr-heads a{color:var(--accent,#2f6fed);text-decoration:none}
.fvr-heads a:hover{text-decoration:underline}
.fvr-out{font-size:var(--fs-100);color:var(--muted,#6b6b70);margin-top:7px}

/*  — school card campus image (Wikimedia → R2) */
.card-img{position:relative;width:calc(100% + 32px);aspect-ratio:16/9;margin:-16px -16px 12px;border-radius:12px 12px 0 0;overflow:hidden;background:#e6e8ec}
.card-img img{width:100%;height:100%;object-fit:cover;display:block}
.card-img-fallback{display:flex;flex-direction:column;align-items:center;justify-content:center;background:linear-gradient(135deg,var(--brand),var(--accent))}
.card-img-fallback .ci-init{font-size:var(--fs-1100);font-weight:700;color:#fff;line-height:1}
.card-img-fallback .ci-name{font-size:var(--fs-300);font-weight:600;color:#fff;opacity:.96;margin-top:6px;padding:0 14px;text-align:center;line-height:1.25}
.card-credit{position:absolute;left:0;right:0;bottom:0;padding:3px 8px;font-size:var(--fs-100);color:#fff;background:rgba(0,0,0,.45)}
.card-credit a{color:#fff;text-decoration:none}

/*  — make the current admit-rate year explicit (was misread as '2018 data') */
.admityr{font-size:var(--fs-200);color:var(--muted,#6b6b70);font-weight:600;text-transform:uppercase;letter-spacing:.02em}

/*  — Money Summary (report view) */
.rep-actions{display:flex;gap:10px;flex-wrap:wrap;margin:6px 0 14px}
.rep-card{background:var(--surface,#fff);border:1px solid var(--line,#e6e8ee);border-radius:12px;padding:16px 18px;margin:14px 0}
.rep-card h3{margin:0 0 10px;font-size:var(--fs-500)}
.rep-table th,.rep-table td{vertical-align:top}
.rep-table small{color:var(--muted,#6b6b70);font-weight:400}
.rep-loc{color:var(--muted,#6b6b70);font-size:var(--fs-200)}
/* The best-fit result SHOULD stand out: it is the answer the family came for. It was standing out
   by changing four things at once - size, weight, colour and a gradient banner - so it read as if
   it came from a different product than the cards around it.
   ONE device now carries the emphasis: a tinted surface with an accent rail. The school name is
   left at exactly the size, weight and colour it has in every other card, so a name looks like a
   name wherever it appears. */
.rep-best{background:var(--accent-bg);border:1px solid var(--accent-line);
  border-left:4px solid var(--accent);border-radius:var(--radius);padding:16px 18px;margin:14px 0;
  color:var(--ink)}
.rep-best-warn{background:var(--warn-bg);border-color:var(--warn);border-left-color:var(--warn)}
.rep-best-tag{font-size:var(--fs-100);text-transform:uppercase;letter-spacing:.05em;
  font-weight:700;color:var(--muted)}
.rep-best-name{font-size:var(--fs-700);font-weight:700;color:var(--brand);margin:2px 0 6px}
.rep-best p{margin:0;font-size:var(--fs-300);line-height:1.6;color:var(--ink)}
.rep-best b{color:var(--brand)}
.rep-sch{border-top:1px solid var(--line,#e6e8ee);padding:14px 0}
.rep-sch:first-of-type{border-top:0}
.rep-sch-hd{display:flex;justify-content:space-between;align-items:baseline;gap:10px}
/* .rep-sch-name is now a real <button> (matches .viewmore's reset-chrome-keep-look
   convention), not a bare span -- opens the school's detail modal, matching Results cards' behavior. */
.rep-sch-name{appearance:none;background:none;border:none;padding:0;cursor:pointer;text-align:left;
  font-weight:700;font-size:var(--fs-700);line-height:1.25;font-family:inherit;color:var(--brand);
  letter-spacing:-.15px}
.rep-sch-name:hover{text-decoration:underline}
/* The school name heads the card. It was rendering at the browser's unstyled button default,
   13.33px weight 400, because the font shorthand it was given was invalid and discarded, so the
   dollar figures inside the card outranked the name of the school the card is about. */
@media(max-width:560px){.rep-sch-name{font-size:var(--fs-600)}}
.rep-4y{display:flex;flex-wrap:wrap;gap:16px;margin:10px 0}
.rep-4y-yrs{display:flex;gap:8px;flex-wrap:wrap}
.rep-yr{display:flex;flex-direction:column;min-width:78px;padding:8px 10px;background:var(--surface-2,#f4f6fb);border:1px solid var(--line,#e6e8ee);border-radius:9px;font-weight:700;font-size:var(--fs-300)}
.rep-yr small{color:var(--muted,#6b6b70);font-weight:600;font-size:var(--fs-200);margin-bottom:2px}
.rep-4y-tot{flex:1;min-width:230px}
.rep-4y-line{display:flex;justify-content:space-between;gap:12px;padding:3px 0;font-size:var(--fs-300)}
.rep-4y-big{font-size:var(--fs-500);font-weight:700;border-bottom:1px solid var(--line,#e6e8ee);padding-bottom:6px}
/* The line is already at 700, and the browser's default b{font-weight:bolder} compounds off it
   to 900, which is a fourth weight the contract does not have. The <b> is markup for the total,
   not a second level of emphasis. */
.rep-4y-big b{font-weight:inherit}
.rep-4y-naive span,.rep-4y-prem span{color:var(--muted,#6b6b70)}
.rep-loans{font-size:var(--fs-200);line-height:1.6;background:var(--surface-2,#f4f6fb);border-radius:9px;padding:9px 12px}
.rep-analysis{font-size:var(--fs-300);line-height:1.6;margin:9px 0 0}
.rep-reapply ul{margin:4px 0 0;padding-left:20px}
.rep-reapply li{font-size:var(--fs-300);line-height:1.6;margin-bottom:4px}
.rep-steps{margin:4px 0 12px;padding-left:20px}
.rep-steps li{font-size:var(--fs-300);line-height:1.6;margin-bottom:5px}
.rep-ctas{display:flex;gap:10px;flex-wrap:wrap}
@media(max-width:560px){.rep-4y{flex-direction:column;gap:10px}.rep-yr{min-width:64px}}
/* The report as a document, not a printed screen. Everything below is placement and colour only:
   the per-school section spends the four type steps the report already spent and introduces no new
   size. The two overrides exist because .nc-cdsmeta and .sd-note declare --fs-100 for the Finances
   card, and importing an 11px step into a reading surface would spend a step the block does not
   have. Same pattern already established at .rep-sch .fit. */
.rep-sch>h4{margin:14px 0 4px}
.rep-why,.rep-weighs{font-size:var(--fs-300);line-height:1.6;margin:0 0 8px;max-width:74ch}
.rep-flag{font-size:var(--fs-300);line-height:1.6;margin:8px 0;padding:8px 11px;max-width:74ch;
  border-radius:9px;background:var(--surface-2,#f4f6fb);border-left:3px solid var(--line,#e6e8ee)}
.rep-confirm{margin:4px 0 0;padding-left:20px}
.rep-confirm>li{font-size:var(--fs-300);line-height:1.6;margin-bottom:6px;max-width:74ch}
/* On paper the bracketed key IS the link, so it must survive at a glance without pulling the eye
   off the figure it qualifies. */
.rep-key{color:var(--muted,#6b6b70);font-weight:600;white-space:nowrap}
.rep-check{color:var(--bad);font-weight:600}
.rep-band{margin-top:8px}
.rep-water{margin:6px 0 2px}
.rep-doc>.hint{max-width:74ch}
.rep-sch .fit-rows,.rep-sources .fit-rows{font-size:var(--fs-300)}
.rep-sch .nc-cdsmeta,.rep-sch .sd-note{font-size:var(--fs-300)}
.rep-srclist dt{white-space:nowrap}

/* ---- TWO READERS, ONE PAGE -------------------------------------------------------------------
   A school section used to be one column of everything, in which the verdict, its caveats, the
   evidence and the money all carried the same weight, and the actions sat at the bottom under all
   of it. Two people use this document and they do different jobs: the student is deciding where to
   apply and whether they want to be there, the family is deciding what it costs and whether it can
   be paid. Two lanes, each opening with the jobs that reader performs. */
.rep-two{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:24px;margin:12px 0 0}
@media(max-width:860px){.rep-two{grid-template-columns:1fr;gap:18px}}
.rep-lane{min-width:0}
.rep-lane-tag{font-size:var(--fs-100);text-transform:uppercase;letter-spacing:.05em;font-weight:700;
  color:var(--muted);margin:0 0 8px;padding-bottom:6px;border-bottom:1px solid var(--line)}
.rep-lane>h4:first-of-type{margin-top:0}
/* The argument, one finding to a line. It was a single paragraph opening with the same sentence at
   every school, and a reader who has read it once skips the four that follow. */
.rep-why{padding-left:20px}
.rep-why>li{margin-bottom:5px}
/* A caveat is not a finding. It keeps its own words and travels to the foot of the page as a
   numbered note, attached by a marker to the line it qualifies. */
.rep-fnm{font-size:var(--fs-100);font-weight:700;color:var(--muted);vertical-align:super;
  line-height:0;margin-left:2px}
.rep-fn{margin:14px 0 0;padding:10px 0 0 20px;border-top:1px solid var(--line)}
.rep-fn>li{margin:0 0 6px}
.rep-fn .rep-flag{background:none;border:0;border-radius:0;padding:0;margin:0;font-size:var(--fs-200)}

/* ---- THE SPREAD: cost against fit ------------------------------------------------------------
   Fit was on one page and cost was several pages later, so the trade between them existed only in
   the reader's head. The plot states no new fact: the band, the net price and the budget are three
   columns of the ranked table above it, read as one picture instead of one column at a time. */
.rep-spread .sp{display:block;width:100%;height:auto;margin:10px 0 0;overflow:visible}
.sp-grid{stroke:var(--line);stroke-width:1}
.sp-axis{stroke:var(--muted);stroke-width:1}
.sp-ylab{fill:var(--muted);font-size:var(--fs-100);font-weight:700;text-anchor:end;letter-spacing:.05em}
.sp-xlab{fill:var(--muted);font-size:var(--fs-100);text-anchor:middle}
.sp-budget{stroke:var(--accent);stroke-width:1.5;stroke-dasharray:4 3}
.sp-budlab{fill:var(--warn);font-size:var(--fs-100);font-weight:700}
.sp-dot{fill:var(--brand)}
.sp-dotlab{fill:var(--ink);font-size:var(--fs-200);font-weight:600}
.sp-end{text-anchor:end}

/* scoped print — only the report prints when launched from its Print button */
@media print{body.printing-report .view:not(#view-report){display:none!important}
  body.printing-report #view-report{display:block!important}
  /* Controls are not content. The depth checkbox printed as a hollow box beside its own label on
     page one of every report, which reads as a form the family is supposed to fill in on paper. */
  body.printing-report .rep-actions,body.printing-report .rep-ctas,
  body.printing-report .rep-depth{display:none!important}
  /* The ranked table scrolls sideways on screen and a sheet of paper does not scroll, so the last
     column was being cut off the right edge of page one. On paper it lays out to the page width. */
  body.printing-report .cmp-wrap{overflow:visible!important}
  body.printing-report table.rep-table{table-layout:auto;width:100%}
  body.printing-report table.rep-table thead th{position:static}
  /* .rep-sch no longer asks to stay whole. A per-school section is now a multi-page document
     section rather than a card, and an unbreakable block taller than the page is a block the
     browser breaks anyway, in the worst place it can find. The parts that DO fit on a page keep the
     rule. */
  body.printing-report .rep-best,body.printing-report .rep-4y,
  body.printing-report table.rep-table tr{break-inside:avoid;page-break-inside:avoid}
  body.printing-report .rep-sch{break-before:auto;page-break-before:auto}
  body.printing-report .rep-card h3,body.printing-report .rep-sch h4{break-after:avoid;page-break-after:avoid}
  body.printing-report .rep-flag,body.printing-report .rep-confirm>li,
  body.printing-report .rep-srclist>div{break-inside:avoid;page-break-inside:avoid}}

/* HS finder combobox */
.pf-hs{position:relative}
.hs-list{position:absolute;z-index:40;left:0;right:0;top:100%;background:#fff;border:1px solid var(--line,#d8dee6);border-radius:8px;box-shadow:0 6px 18px rgba(0,0,0,.12);max-height:260px;overflow:auto}
.hs-opt{padding:8px 10px;cursor:pointer;font-size:var(--fs-400)}
.hs-opt.active,.hs-opt:hover{background:#eef3f8}
.hs-loc{color:#5b6b7c;font-size:var(--fs-300)}
.hs-none{padding:8px 10px;color:#5b6b7c;font-size:var(--fs-400)}

/* Profile sections + radios (PDR DR-1/DR-2) */
.pf-sec{border:1px solid var(--line,#d8dee6);border-radius:10px;padding:10px 12px;margin:10px 0}
.pf-sec>legend{font-weight:600;padding:0 6px;font-size:var(--fs-400)}
.pf-radios{border:none;padding:4px 0 0;margin:6px 0 0}
.pf-radios>legend{font-weight:600;font-size:var(--fs-400);padding:0}
.pf-radios .radio{display:flex;align-items:center;gap:8px;padding:4px 0;font-size:var(--fs-400);cursor:pointer}
.pf-errors{background:#fdf2f2;border:1px solid #e0b4b4;border-radius:8px;padding:10px 12px;margin:8px 0;color:#8a2424;font-size:var(--fs-400)}
.hs-wrap{position:relative;display:block}
#pf-hsName{width:100%;border:1px solid var(--line,#d8dee6);border-radius:8px;padding:8px 30px 8px 10px;font:inherit;color:var(--ink,var(--ink));background:#fff}
.hs-clear{position:absolute;right:6px;top:50%;transform:translateY(-50%);border:none;background:none;font-size:var(--fs-600);cursor:pointer;color:#5b6b7c}
/* Round segmented control (DR-4) */
.rv-seg{display:inline-flex;border:1px solid var(--line,#d8dee6);border-radius:8px;overflow:hidden;margin:6px 0 10px}
.rv-btn{border:none;background:#fff;padding:7px 14px;font-size:var(--fs-400);cursor:pointer}
.rv-btn.on{background:var(--primary,#1c3d5a);color:#fff;font-weight:600}
.rv-btn:focus-visible{outline:2px solid var(--accent,#c7892c);outline-offset:-2px}

/* moved off inline style= attributes so style-src can drop 'unsafe-inline' (security headers hardening) */
.gap-row{margin-bottom:12px;display:flex;gap:10px;flex-wrap:wrap}
.muted-note{color:var(--muted);font-size:var(--fs-300);margin:0}

/* moved off <style> blocks in index.html/accessibility.html -- CSP is style-src 'self' with no
   'unsafe-inline', so inline <style> tags render as unstyled text. External stylesheet only. */
.lp{max-width:920px;margin:0 auto;padding:8px 20px 60px}
.lp section{margin:34px 0}
.lp .hero{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);box-shadow:var(--shadow);padding:34px 30px;margin:22px 0 34px}
.lp .hero h1{font-size:var(--fs-1000);line-height:1.25;margin:0 0 10px}
.lp .hero .lede{color:var(--muted);font-size:var(--fs-600);margin:0 0 22px;max-width:640px}
.lp .privacy-pledge{color:var(--good);font-weight:700;font-size:var(--fs-300);margin:0 0 18px}
.lp .cta-primary{display:inline-block;background:var(--brand);color:#fff;padding:13px 22px;border-radius:var(--radius-sm);font-weight:700;font-size:var(--fs-500);border:none;cursor:pointer}
.lp .cta-primary:hover{background:var(--brand-700);text-decoration:none}
.lp .cta-secondary{display:inline-block;margin-left:14px;padding:13px 2px;color:var(--brand);font-weight:600}
.lp .tier .cta-secondary{margin:6px 0 0;padding:8px 0}
.lp .lp-fold-note{margin:16px 0 0}
.lp h2{font-size:var(--fs-800);margin:0 0 16px}
.lp .lp-steps{display:grid;grid-template-columns:repeat(3,1fr);gap:16px}
@media (max-width:760px){.lp .lp-steps{grid-template-columns:1fr}}
.lp .lp-step{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);padding:18px 20px;box-shadow:var(--shadow)}
.lp .lp-step .n{display:inline-block;width:26px;height:26px;border-radius:50%;background:var(--info-bg);color:var(--brand);font-weight:700;font-size:var(--fs-300);text-align:center;line-height:26px;margin-bottom:10px}
.lp .lp-step h3{font-size:var(--fs-500);margin:0 0 6px}
.lp .lp-step p{font-size:var(--fs-300);color:var(--muted);margin:0}
.lp .tiers{display:grid;grid-template-columns:1fr 1fr;gap:16px}
@media (max-width:700px){.lp .tiers{grid-template-columns:1fr}}
.lp .tier{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);padding:20px 22px;box-shadow:var(--shadow)}
.lp .tier h3{margin:0 0 6px;font-size:var(--fs-600)}
.lp .tier .price{font-size:var(--fs-900);font-weight:700;color:var(--brand);margin:0 0 4px}
.lp .tier .price small{font-weight:600;color:var(--muted);font-size:var(--fs-200)}
.lp .tier ul{margin:12px 0 0;padding-left:20px;font-size:var(--fs-300)}
.lp .tier li{margin:6px 0;color:var(--ink)}
.lp .tier.pass{border-color:var(--brand)}
.lp .btn.buy{background:var(--brand);color:#fff;border:none;border-radius:var(--radius-sm);padding:12px 20px;font-weight:700;font-size:var(--fs-500);cursor:pointer;margin-top:14px}
.lp .btn.buy:hover{background:var(--brand-700)}
#buy-msg{margin-top:10px;font-size:var(--fs-300);color:var(--muted)}
.lp .honesty{background:var(--surface-2);border:1px solid var(--line);border-radius:var(--radius);padding:22px 24px}
.lp .honesty ul{margin:10px 0 0;padding-left:20px;font-size:var(--fs-400);color:var(--ink)}
.lp .honesty li{margin:8px 0}
.lp .cta-repeat{text-align:center;padding:30px 0}
.lp footer{border-top:1px solid var(--line);padding-top:20px;margin-top:44px;font-size:var(--fs-200);color:var(--muted);line-height:1.7}
.lp footer a{color:var(--muted);text-decoration:underline}

.a11y-wrap{max-width:820px;margin:0 auto;padding:0 20px}
.a11y-doc{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);
  box-shadow:var(--shadow);padding:26px 30px;margin:24px 0 60px}
.a11y-doc h1{font-size:var(--fs-900);margin:0 0 6px;color:var(--brand)}
.a11y-doc h2{font-size:var(--fs-500);margin:26px 0 8px;color:var(--brand)}
.a11y-doc p,.a11y-doc li{font-size:var(--fs-400);line-height:1.65;color:var(--ink)}
.a11y-doc ul{padding-left:22px}
.a11y-doc a{color:var(--brand);text-decoration:underline}
.a11y-meta{font-size:var(--fs-200);color:var(--muted);margin-top:4px}
.a11y-back{display:inline-block;margin-top:8px}

.kd-wrap{max-width:960px;margin:0 auto;padding:0 20px}
.kd-doc{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);
  box-shadow:var(--shadow);padding:26px 30px;margin:24px 0 60px}
.kd-doc h1{font-size:var(--fs-900);margin:0 0 6px;color:var(--brand)}
.kd-doc h2{font-size:var(--fs-500);margin:26px 0 8px;color:var(--brand)}
.kd-doc p,.kd-doc li,.kd-doc td,.kd-doc th{font-size:var(--fs-400);line-height:1.6;color:var(--ink)}
.kd-doc ul{padding-left:22px}
.kd-doc a{color:var(--brand);text-decoration:underline}
.kd-meta{font-size:var(--fs-200);color:var(--muted);margin-top:4px}
.kd-caveat{background:var(--surface);border:1px solid var(--line);border-left:4px solid var(--brand);
  border-radius:8px;padding:12px 16px;margin:16px 0}
.kd-table-wrap{overflow-x:auto;margin:14px 0}
table.kd{width:100%;border-collapse:collapse;min-width:640px}
table.kd caption{text-align:left;font-size:var(--fs-200);color:var(--muted);padding:0 0 8px}
table.kd th,table.kd td{border:1px solid var(--line);padding:9px 11px;text-align:left;vertical-align:top}
table.kd thead th{background:var(--brand);color:#fff;font-weight:600}
table.kd tbody th{background:var(--surface);font-weight:600;white-space:nowrap}
.kd-when{white-space:nowrap;font-weight:600}
.kd-sources li{margin:4px 0}
.kd-back{display:inline-block;margin-top:8px}

/* index.html landing banner -- conditional state on the single landing page (e.g. arrived here via
   the paywall gate's no-entitlement redirect), instead of a duplicate page. */
.landing-banner{background:var(--info-bg);color:var(--brand);border-bottom:1px solid var(--line);
  padding:10px 20px;text-align:center;font-size:var(--fs-400);font-weight:600}
.landing-banner.hidden{display:none}

/* success.html / cancel.html — the checkout-return pages */
.checkout-page{max-width:640px;padding:40px 20px}
.checkout-page h1{font-size:var(--fs-900)}
.checkout-page .lede{color:var(--muted);font-size:var(--fs-500);margin:0 0 12px;max-width:none}
.checkout-page .btn{display:inline-block}
.checkout-page #continue.hidden{display:none}

/* Profile test-score groups. Fields follow the order a score report prints them:
   SAT total then Reading and Writing then Math; ACT composite then Math, Science,
   English, Reading. Matching the report means a student can copy straight down. */
.pf-sections{margin:.5rem 0;border:1px solid var(--line,#d7d7d7);border-radius:6px;padding:.5rem .75rem}
.pf-sections>summary{cursor:pointer;font-weight:600}
.pf-premium{font-size:var(--fs-200);font-weight:600;letter-spacing:.02em;text-transform:uppercase;
  border:1px solid currentColor;border-radius:3px;padding:0 .3rem;margin-left:.4rem;vertical-align:middle}
.pf-test{border:0;border-top:1px solid var(--line,#e3e3e3);margin:.6rem 0 0;padding:.5rem 0 0}
.pf-test>legend{font-weight:600;padding:0 .4rem 0 0}

/* Premium per-school profile report. Collapsed by default: the four-year cost is the headline,
   this is the "why" underneath it. */
.rep-prof{margin:.6rem 0 0;border-top:1px solid var(--line,#e3e3e3);padding-top:.5rem}
.rep-prof>summary{cursor:pointer;font-weight:600}
.rep-prof-sec{margin:.7rem 0 0}
.rep-prof-sec>h4{margin:0 0 .3rem;font-size:var(--fs-400)}
/* The list carried margins but no size, so its items fell through to the 15px body while their own
   h4 above and the source note below are both 13px: the content was LARGER than the heading that
   introduced it. Same defect class as the undefined .hint. The list is body copy inside a report
   card, so it takes the card body step. */
.rep-prof-list{margin:.2rem 0 .3rem;padding-left:1.1rem;font-size:var(--fs-300)}
.rep-prof-list>li{margin:.18rem 0}

/* Report depth toggle and the prepared-for line.
   Uses the existing tokens only; no new colours enter the system here. */
.rep-prepared{margin:-2px 0 10px;color:var(--brand-700);font-weight:700;font-size:var(--fs-400)}
.rep-depth{display:flex;gap:10px;align-items:flex-start;margin:0 0 16px;padding:12px 14px;
  background:var(--surface-2);border:1px solid var(--line);border-radius:var(--radius-sm);
  cursor:pointer;max-width:640px}
.rep-depth input{margin:2px 0 0;flex:0 0 auto;width:16px;height:16px;cursor:pointer}
.rep-depth span{display:block}
.rep-depth b{display:block;font-size:var(--fs-300)}
.rep-depth small{display:block;color:var(--muted);font-size:var(--fs-200);margin-top:2px;line-height:1.45}
.rep-depth:focus-within{outline:2px solid var(--brand-700);outline-offset:2px}

/* The print question, added by an earlier change request alongside the report's second mode. It
   borrows .rep-depth's panel entirely -- same surface, same line, same radius, same 640px measure --
   because it is the same kind of thing sitting in the same place, and a second panel treatment
   would be a twelfth callout style for no reason. The radios are the existing .pf-check control
   row. Nothing new enters the token system here. */
.rep-choose{margin:0 0 16px;padding:12px 14px;background:var(--surface-2);
  border:1px solid var(--line);border-radius:var(--radius-sm);max-width:640px}
.rep-choose[hidden]{display:none}
.rep-choose-q{margin:0 0 8px;font-weight:700;font-size:var(--fs-300)}
.rep-choose-sch{display:flex;align-items:center;gap:8px;margin:2px 0 0 26px;
  font-size:var(--fs-300);flex-wrap:wrap}
.rep-choose-sch select{border:1px solid var(--line);border-radius:8px;padding:8px 10px;
  font-size:var(--fs-field-value);font-family:inherit;color:var(--ink);background:#fff;max-width:100%}
.rep-choose-go{display:flex;gap:10px;margin-top:12px;flex-wrap:wrap}
/* The toggle is a control, not content: it must not appear in the printed report. The chooser is
   the same, and it is hidden for EVERY print path rather than only the report's own, because the
   panel is open at the moment the dialog appears. */
@media print{.rep-depth{display:none}
  .rep-choose{display:none!important}
  .rep-prepared{color:var(--brand)}}

/* AA contrast. var(--muted) on var(--line) measures 4.46 against a required 4.5, at 11px
   and 10px. These two carry the smallest text in the interface, so the foreground is darkened
   here rather than changing --muted globally (which is legible at the larger sizes it is used at). */
.step .n{color:var(--ink-2)}
.help{color:var(--ink-2)}

/* WCAG 2.5.5 touch targets. A 16px checkbox and a 20px step badge are below the 44px target.
   The CONTROL keeps its visual size; the hit area is enlarged around it so the design does not
   change while the target does. */
.step{min-height:44px}

/* The brand block names the product, so the product name is the page h1. The heading carries no
   box of its own: the surrounding .brand keeps the layout it always had. */
.brand h1{margin:0;font:inherit;display:inline}

/* 23 controls rendered in Arial at the browser default because nothing told them otherwise:
   a control does NOT inherit font from its parent unless asked. button#pf-close was showing
   visible text at 18px Arial on a page set in the system stack. */
input,select,textarea,button{font-family:inherit}

/* ONE control row. .pf-check, .acad-opt, .pf-radios .radio and .rep-depth were four patterns for
   the same thing, each added at a different time. They share the row, the gap, the target size and
   the focus treatment; only .rep-depth adds a description line beneath its label. */
.pf-check,.acad-opt,.pf-radios .radio,.rep-depth{
  display:flex;align-items:center;gap:10px;min-height:44px;margin:0;
  font-size:var(--fs-400);font-weight:400;cursor:pointer}
.pf-check>input,.acad-opt input,.pf-radios .radio input,.rep-depth input{
  width:20px;height:20px;margin:0;flex:0 0 auto;accent-color:var(--brand)}
.pf-check:focus-within,.acad-opt:focus-within,.pf-radios .radio:focus-within,.rep-depth:focus-within{
  outline:2px solid var(--brand-700);outline-offset:2px;border-radius:var(--radius-sm)}
/* .rep-depth is the one variant: it carries a description under its label, so it aligns to the top */
.rep-depth{align-items:flex-start;padding:12px 14px;background:var(--surface-2);
  border:1px solid var(--line);border-radius:var(--radius-sm);max-width:640px;margin:0 0 16px}
.rep-depth input{margin-top:2px}

/* A control row inside .pf-grid was losing to `.pf-grid label` on specificity (0,1,1 beats 0,1,0),
   so seven checkboxes kept the grid's field-label size and 4px gap while every other control row
   used 14px and 10px. Match the specificity rather than reaching for !important. */
.pf-grid .pf-check,.fin-grid .pf-check,
.pf-grid .acad-opt,.pf-grid .radio{
  font-size:var(--fs-400);gap:10px;display:flex;align-items:center;min-height:44px}

/* <small> and bare form controls carry browser defaults (0.8em, 13.33px) unless told otherwise.
   These were the last two off-scale sizes rendering on the page. */
small{font-size:var(--fs-100)}
input,select,textarea,button{font-size:var(--fs-400)}

/* Profile layout. 43 controls in seven stacked fieldsets ran to 1.6 screens on a large desktop
   while the page capped content at 1180px and left 332px of viewport unused.
   The core stays open; everything optional sits behind a disclosure that says what it buys. */
.pf-group{border:1px solid var(--line);border-radius:var(--radius-sm);margin:10px 0;
  background:var(--surface)}
.pf-group>summary{cursor:pointer;padding:12px 14px;min-height:44px;display:flex;
  flex-direction:column;justify-content:center;gap:2px;border-radius:var(--radius-sm)}
.pf-group>summary b{font-size:var(--fs-400);color:var(--ink)}
.pf-group>summary small{color:var(--muted);font-size:var(--fs-200);line-height:1.45}
.pf-group>summary:focus-visible{outline:2px solid var(--brand-700);outline-offset:2px}
.pf-group[open]>summary{border-bottom:1px solid var(--line);border-radius:var(--radius-sm) var(--radius-sm) 0 0}
/* a wrapped fieldset keeps its own fields but drops the doubled frame */
.pf-group>.pf-sec{border:0;margin:0;padding:12px 14px}
.pf-group>.pf-sec>legend{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}

/* The profile is a MODAL, and .pmodal-card is width:min(560px,92vw) with internal scrolling.
   45 controls in a 560px column is the actual reason it scrolls; the page's 1180px cap was never
   the constraint. Widen the PROFILE modal only - #smodal (school details) shares the class and
   reads better narrow. */
#pmodal>.pmodal-card{width:min(920px,94vw)}
/* Column count follows the CONTAINER, not the viewport. A viewport media query is wrong here:
   the modal has its own width, so at 1512px viewport with a 366px modal the fields were still
   being laid out in three 89px columns.
   auto-FILL, not auto-fit: auto-fit collapses empty tracks, and this grid holds full-width
   sections alongside its fields, so the single remaining field stretched to 850px. */
#pmodal .pf-grid{grid-template-columns:repeat(auto-fill,minmax(210px,1fr))}

/* .fieldhint{display:block} silently beat the browser's [hidden]{display:none}, so all 21 help
   texts rendered permanently and the "?" toggle that is supposed to reveal them did nothing.
   They accounted for 1065px of the profile's 1132px height: the form was long because every hint
   was expanded, not because it has too many fields. */
.fieldhint[hidden],.hint[hidden],[hidden]{display:none}

/* The two Premium blocks are children of .pf-grid, so each was landing in ONE 274px cell beside
   Class year and GPA: misaligned with the fields around them, and forced into a narrow column that
   stacked their contents into a 585px and 858px scroll. They are sections, not fields. */
#pmodal .pf-sections{grid-column:1/-1;margin:6px 0}
#pmodal .pf-sections>summary{min-height:44px;display:flex;align-items:center;gap:8px}

/* Opened, their contents use the width of the section rather than a single column. */
/* The checkboxes are direct children of the <details>, with no wrapper, so the DETAILS is the
   grid container. Its summary and intro span every column; when closed only the summary renders,
   so the grid costs nothing. */
/* The GRID goes on a real wrapper, never on <details> itself. Chrome inserts an anonymous
   ::details-content box around a details' contents, so a grid set on <details> has exactly ONE
   item and everything inside it stacks - which is why seven checkboxes rendered in one column
   while the container correctly reported three. */
#pmodal .pf-checks{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));
  gap:2px 18px;align-items:start}
#pmodal .pf-sections[open]>fieldset.pf-test .pf-grid{grid-template-columns:repeat(auto-fit,minmax(150px,1fr))}

/* A control label is something to read and act on, not a hint. .pf-grid label paints every label
   --muted, which is the SECONDARY text colour; on a checkbox row that made the choices read as
   greyed out. Checkbox and radio labels take --ink; the field captions above inputs stay muted. */
#pmodal .pf-check,#pmodal .acad-opt,#pmodal .pf-radios .radio{color:var(--ink)}

/* ONE locked state, for every premium surface: the profile blocks, the per-school report and
   Trends. A gated feed 403s and its global stays empty, so without this a premium section renders
   blank and reads as "we have no data for your school". That is the one thing it must never say:
   absence is ours and temporary, and a paywall is neither.
   The badge and the state are one component; "Premium" as a bare label on an empty section tells
   a family nothing about why it is empty. */
.is-locked{position:relative;border:1px dashed var(--accent-line);background:var(--accent-bg);
  border-radius:var(--radius-sm);padding:14px 16px;color:var(--ink)}
.is-locked>.locked-title{display:flex;align-items:center;gap:8px;font-size:var(--fs-400);
  font-weight:700;margin:0 0 4px}
.is-locked>.locked-body{margin:0;font-size:var(--fs-300);color:var(--ink);line-height:1.5;max-width:62ch}
.locked-badge{display:inline-block;background:var(--brand);color:#fff;border-radius:999px;
  padding:2px 9px;font-size:var(--fs-100);font-weight:700;letter-spacing:.04em;text-transform:uppercase}

/* The locked PREVIEW: one contained proposition — badge + headline, the description, the action row.
   A flex column with one gap gives the three parts a rhythm instead of three ad-hoc margins. */
.is-locked.pass-preview{display:flex;flex-direction:column;gap:10px}
.is-locked.pass-preview>.locked-title,.is-locked.pass-preview>.locked-body{margin:0}
/* The action row. Button and price are siblings in a wrapping flex row: side by side when both fit,
   the price under the button when they do not. The button may wrap its label but never spills over the
   price, and it is never wider than the card. Below 480px the two always stack, full width, in reading
   order (button, then the term it is sold on). No pixel widths tied to one viewport. */
.pass-cta{display:flex;flex-wrap:wrap;align-items:center;gap:10px 14px;max-width:none}
.pass-cta .btn{white-space:normal;text-align:center;max-width:100%;flex:0 1 auto;line-height:1.3;text-decoration:none}
.pass-cta .pass-price{flex:0 1 auto;white-space:nowrap}
@media(max-width:480px){.pass-cta{flex-direction:column;align-items:stretch;gap:8px}.pass-cta .btn{display:block}.pass-cta .pass-price{text-align:center;white-space:normal}}

/* The Premium badge appeared at two sizes and two weights across the section. One definition. */
.pf-premium,.locked-badge{font-size:var(--fs-100);font-weight:700;letter-spacing:.04em;
  text-transform:uppercase}

/* Label colour, stated once for the whole section:
   a caption ABOVE an input is secondary text and stays --muted;
   a label a family reads and ACTS ON (checkbox, radio) is primary text and takes --ink.
   This was inconsistent by accident of which rule won, not by decision. */
#pmodal .pf-grid>label{color:var(--muted)}
#pmodal .pf-check,#pmodal .acad-opt,#pmodal .pf-radios .radio,
#pmodal .pf-group>summary b,#pmodal .pf-sections>summary{color:var(--ink)}

/* Nothing in the field grid may be a section. A grouping that lands in a field cell inherits a
   field's width and stacks its contents into a column. */
#pmodal .pf-grid>details,#pmodal .pf-grid>fieldset{grid-column:1/-1}
/* The course-load group reuses .vet-q, THE two-column intake row, rather than inventing a second
   layout for the same need: question and its why-prose left, the control right, one column below
   640px. Two things need saying inside the modal. The row heading is a control label here, so it
   carries the ? affordance and its disclosure inside itself, and the disclosure is prose rather
   than emphasis, so it does not inherit the heading's weight. */
#pmodal .vet-q-t>.fieldhint{font-weight:400}
#pmodal #pf-courseload .vet-q:first-of-type{border-top:0;margin-top:6px}
#pmodal #pf-courseload .pf-checks{grid-template-columns:1fr;gap:2px}
/* `.pf-grid label` turns every label inside the modal grid into a flex COLUMN, which stacked the ?
   affordance under its own question and the tick box above its own word. `.pf-grid .pf-check`
   already re-matched that specificity for the size and the gap but never reset the direction, so
   both are set explicitly here for the rows this group owns. */
#pmodal #pf-courseload label.vet-q-t{display:block}
#pmodal #pf-courseload .pf-check{flex-direction:row}

/* Veteran services reuses .rep-prof-sec / .rep-prof-list, the pattern every other subsection of
   the profile block already uses. No new callout: reduced eleven of those to one.
   The only addition is a semantic modifier for a genuine warning, drawn from the warn tokens. */
.rep-prof-list>li.is-warn{list-style:none;margin-left:-1.1rem;padding:6px 10px;
  background:var(--warn-bg);color:var(--warn);border-radius:var(--radius-sm);font-weight:600}
.rep-prof-list>li.is-muted{color:var(--muted)}
/* Yellow Ribbon has three states. "Not confirmed" is not "not offered" - it means we could not
   verify this school against the VA's records, and must not read as a denial. */
.gi-unk{color:var(--muted)}

/* The veteran step is hidden until a family says it applies to them. `.hidden` is scoped per
   component in this sheet rather than global, so the step needs its own rule - without one the
   class is inert and the step shows to everybody. */
.steps .step.hidden{display:none}

/* `.hint` is the fine print under a control, used 48 times across the app - and until now it was
   only DEFINED inside .qcard and .scards. Everywhere else it inherited the 15px body size and full
   --ink, which made the explanation larger and louder than the label it explains. Secondary text is
   smaller and quieter than what it qualifies; that is the whole job. The two scoped rules above
   deliberately go one step further down in dense cards and still win on specificity. */
.hint{font-size:var(--fs-300);color:var(--muted);line-height:1.5}
.hint b{color:var(--ink)}

/* ---------- veteran benefits, its own view -------------------------------------------------
   No new colour, no new size: the panel is the card surface every other view uses, the money lines
   are the same .nc-line the net-price cards use, and status colour comes from the good/warn/muted
   tokens. The only genuinely new component is an agreement row, because a Yellow Ribbon agreement
   carries three facts at once — a division, a contribution, and a cap — and no existing row does. */
.vet-panel{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);
  box-shadow:var(--shadow);padding:15px 17px;margin-top:16px}
.vet-panel>h3{margin:0 0 .5rem;font-size:var(--fs-700);color:var(--brand)}
/* One size for the action labels in this panel. The tick-box and the two benefit radios are the
   same KIND of thing - a control a family reads and acts on - and were arriving at 14px and 13px
   because each came from a different component. */
.vet-panel .va-opt{font-size:var(--fs-400)}
.vet-panel .hint{max-width:74ch}
.vet-radios{margin:.5rem 0}

/* THE two-column intake pattern for question panels. One row per question: the
   question text and the prose that explains it sit in the LEFT column, the control the student
   acts on sits in the RIGHT column, so a long panel spends its width instead of its height. Any
   question panel that stacks questions gets THIS row, .vet-q; do not invent a second layout for
   the same need. Rows separate with a subtle var(--line) rule and fold to a single column below
   640px, question above control. */
.vet-q{display:grid;grid-template-columns:minmax(0,1.2fr) minmax(0,1fr);gap:8px 24px;
  align-items:start;padding:12px 0;border-top:1px solid var(--line);margin-top:12px}
.vet-q+.vet-q{margin-top:0}
.vet-q.vet-q-full{grid-template-columns:minmax(0,1fr)}
.vet-q-t{display:block;font-size:var(--fs-400);font-weight:600;color:var(--ink)}
.vet-q-l>.hint{margin:4px 0 0}
.vet-q-c{min-width:0}
/* Bare controls in the row: same field treatment as .fin-grid inputs, capped so a lone select
   does not stretch to the column edge past comfortable reach. */
.vet-q-c>select,.vet-q-c>input:not([type=checkbox]){border:1px solid var(--line);border-radius:8px;
  padding:8px 10px;font-size:var(--fs-field-value);font-family:inherit;color:var(--ink);
  background:#fff;width:100%;max-width:22rem;min-width:0}
.vet-q-c .pf-radios{margin:0;padding:0}
.vet-q-c .pf-check{margin:0}
@media (max-width:640px){.vet-q{grid-template-columns:1fr;gap:6px}}

/* auto-FIT with a ceiling, not auto-fill. This page is dense explanatory prose, not a row of
   summary tiles: with auto-fill a single school sat in one narrow column with the rest of the row
   empty, squeezing the money lines and the coverage sentences. The ceiling stops one card
   stretching to the full 1180px, which is past comfortable reading width for a figure list. */
/* The cards must share the panel's right edge. The 540px ceiling left the row ~46px short of the
   entitlement panel above it, which read as misalignment (operator report). Columns now fill the
   row; the ceiling survives only for a lone card, where full container width is past comfortable
   reading width for a figure list. */
.vet-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(340px,1fr));gap:14px;margin-top:16px}
.vet-grid .vet-card:only-child{max-width:560px}
.vet-card{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);
  box-shadow:var(--shadow);padding:15px 17px}
.vet-card>h3{margin:0 0 .6rem;font-size:var(--fs-600);color:var(--ink);line-height:1.3}
.vet-card>h3>small{display:block;font-weight:400;font-size:var(--fs-300);color:var(--muted);margin-top:2px}
.vet-money{margin-bottom:.4rem}

/* ONE ANATOMY, SIX SLOTS, ALIGNED ACROSS THE ROW.
   Every card renders the same six slots in the same order and no slot ever collapses (app.js,
   vetSchoolCard). The spacing between them is stated once, here, so the slots are the only thing
   that decides the rhythm of the card.
   The alignment mechanism is subgrid: each card spans a run of the grid's own row tracks and
   adopts them, so cards sitting side by side share every slot boundary. The estimated total, the Yellow
   Ribbon heading, the services heading and the footer then sit at ONE height per row instead of
   wherever each school's data happened to leave them, and a sparse card's whitespace sits inside
   the slot it belongs to, beside the content it is the absence of, rather than pooling as several
   hundred pixels of empty card bottom. Cards in a row also come out the same height by
   construction, so nothing stretches. Every card carries the same padding, so the padding-inset
   row tracks still line up across the row. */
.vet-card>.vet-slot{margin:0;min-width:0}
.vet-card>.vet-slot+.vet-slot{margin-top:12px}
@supports (grid-template-rows: subgrid){
  /* Ten tracks, not six: the money slot spends five of them, one per figure, so the five lines
     align individually and the total starts at one height per row however much explanation a
     school needs. Its hints ride in the fifth track with the total rather than in tracks of their
     own, which is why the total's own line is the thing that aligns and not the block's foot. */
  .vet-card{display:grid;grid-template-rows:subgrid;grid-row:span 10;row-gap:12px}
  .vet-card>.vet-slot+.vet-slot{margin-top:0}
  .vet-card>.vet-money{display:grid;grid-template-rows:subgrid;grid-row:span 5;row-gap:0}
}
/* Without subgrid the cards keep normal flow. The anatomy alone still fixes the line order and
   holds slots 1 to 3 to a constant height, so the money block aligns everywhere and only slots 4
   and 5 drift. Nothing above depends on the feature being present. */

/* SLOT 2, the verdict: the one line that answers the question the card exists to answer. It is set
   apart by weight and colour and NOT by a new type step. The card gets three sizes; the design
   gate's ceiling of four is a ratchet, not headroom to spend. */
.vet-verdict{font-size:var(--fs-300);font-weight:600;line-height:1.5;color:var(--ink-2)}
.vet-verdict.is-good{color:var(--good)}
.vet-verdict.is-warn{color:var(--warn)}

/* SLOT 6, the return path, identical on every card. A plain inline link, because a button in prose
   is a design-gate failure and this is a road back into the main flow, not a primary action. */
.vet-foot{border-top:1px solid var(--line);padding-top:10px}

/* One agreement. The division is the heading because it is the condition the money depends on;
   the amount is secondary to knowing whether it applies to you at all. */
.vet-ags{list-style:none;margin:.4rem 0 0;padding:0;display:flex;flex-direction:column;gap:10px}
.vet-ag{border:1px solid var(--line);border-radius:var(--radius-sm);padding:10px 12px;
  background:var(--surface-2)}
.vet-ag-hd{display:flex;align-items:baseline;justify-content:space-between;gap:10px;
  font-size:var(--fs-400);color:var(--ink)}
.vet-ag-amt{white-space:nowrap;font-weight:700;color:var(--brand);font-size:var(--fs-400)}
.vet-ag-amt>small{display:block;font-weight:400;font-size:var(--fs-100);color:var(--muted);text-align:right}
.vet-ag-cov{margin:.35rem 0 0;font-size:var(--fs-300);line-height:1.5;color:var(--ink-2)}
.vet-ag-cov.is-good{color:var(--good);font-weight:600}
.vet-ag-cov.is-warn{color:var(--warn);font-weight:600}
.vet-ag-cov.is-muted{color:var(--muted)}
.vet-ag-cap{margin:.35rem 0 0}
/* A cap is the fact families most often read as a promise, so it is set as a fact, not a footnote. */
.vet-cap{display:inline-block;background:var(--info-bg);color:var(--ink);border-radius:999px;
  padding:2px 9px;font-size:var(--fs-100);font-weight:700}
.vet-cap.is-unk{background:transparent;color:var(--muted);padding:0;font-weight:400}

.vet-links{margin:.4rem 0 0;padding-left:1.1rem;display:flex;flex-direction:column;gap:5px}
.vet-links a{font-size:var(--fs-300)}

@media (max-width:640px){
  .vet-grid{grid-template-columns:1fr}
  .vet-ag-hd{flex-direction:column;gap:2px}
  .vet-ag-amt{text-align:left}
  .vet-ag-amt>small{text-align:left}
}

/* What the veteran view produced, echoed on Finances. A definition list because that is what it is:
   a set of terms and the answers given. It is deliberately read-only - one value, one place to set
   it, and this shows the money where its inputs came from. */
/* A 9rem label column made sense for four rows and looked broken for one, stranding "not chosen
   yet" a third of the way across the panel. The label column now sizes to its content with a floor,
   so one row reads as a sentence and several still line up. */
.va-sum{margin:.5rem 0 .75rem;display:grid;grid-template-columns:auto 1fr;gap:4px 10px;
  align-items:baseline;width:fit-content;max-width:100%}
.va-sum>div{display:contents}
.va-sum dt{color:var(--muted);font-size:var(--fs-300);white-space:nowrap}
.va-sum dt::after{content:":"}
.va-sum dd{margin:0;color:var(--ink);font-weight:600;font-size:var(--fs-300)}
.va-sum .is-unset{color:var(--muted);font-weight:400;font-style:normal}

/* The step rail carries two kinds of destination and now says so. Numbered steps are a sequence;
   reference sections are entered in any order and take no ordinal. The rule is one marker system per
   control row - the previous rail mixed ordinals with six unrelated dingbats. */
.steps-sep{align-self:center;width:1px;height:20px;background:var(--line);flex:none;margin:0 4px}
.steps .step.ref{color:var(--muted)}
.steps .step.ref:hover{color:var(--ink)}
.steps .step.ref.active{color:var(--brand)}

/* Target size, stated once and honestly. WCAG 2.2 AA (2.5.8) requires 24x24 CSS px, which every
   control here already clears; 44x44 is 2.5.5 at AAA and is the right target for a finger, not a
   mouse. So the desktop sizes stand and the AAA size is applied where it actually matters - on a
   coarse pointer. Inline links in running prose are exempt from target size under both.
   This replaces the flat "44px targets" claim, which was never true of the 32 chips. */
@media (pointer:coarse){
  .btn,.chip,.step,.tg-pill,
  select,input[type="text"],input[type="number"],input:not([type]),textarea{min-height:44px}
  .chip{padding-top:0;padding-bottom:0;display:inline-flex;align-items:center}
}

/* CARD COMPOSITION, stated once for the whole site.
   A card gets three type steps, two apart: title, body, meta. The site was using contiguous runs
   (11,12,13,14,15) inside a single card - five steps a pixel apart, which cannot read as hierarchy
   and instead reads as several unrelated fonts. That is the drift people SEE, and it passed every
   token check because each value was individually legal. Conformance is not coherence.
   This collapses the 11/12 pair onto one meta step wherever it appears inside a card. */
:is(.qcard,.card,.rep-card,.nc-card,.vet-card,.scard,.tcard)
  :is(small,.pill,.tag,.prov,.nc-rec,.nc-coanote,.pp-body,.pf-premium,.admityr,.trend,summary){
  font-size:var(--fs-200)}
/* A sub-heading one step under the body text is not a level, it is noise. */
:is(.rep-card,.nc-card,.vet-card) h4{font-size:var(--fs-300)}
/* Last of the contiguous-run collapse: these sat one step off the card body or meta and so read as
   another font rather than another level. */
.gi-yes,.gi-no,.gi-unk,.vet-cap{font-size:var(--fs-200)}
.vet-ag-hd,.vet-ag-amt{font-size:var(--fs-300)}
:is(.qcard,.nc-card) h3{font-size:var(--fs-500)}
.nc-gi-hd{font-size:var(--fs-300)}
/* The veteran card's total line carried its emphasis with a size step as well as weight and colour,
   which put a fourth and fifth level into a card that needs three. Weight and colour already say it. */
.vet-card :is(.nc-gi-tot,.nc-line.nc-total){font-size:var(--fs-300)}

/* Target size, the AA floor. WCAG 2.2 2.5.8 requires 24x24 CSS px for any control that is not an
   inline link inside running prose. Three real controls sat under it: "View details" at 12px high,
   the compare tray's "remove" at 16, and the report's school-name button at the boundary. These are
   the controls a family uses most, so they were the worst three to have missed. The 44px goal for a
   finger is applied separately under (pointer:coarse). */
.viewmore,.rm{min-height:24px;display:inline-flex;align-items:center}
.rep-sch-name{min-height:26px}

/* Landing page hero photo + collapsible sections. Appended block, index.html only.
   Grids stay on wrappers INSIDE <details> (.lp-fold-body children), never on <details> itself:
   Chrome wraps details content in one anonymous box, so a grid set directly on it breaks. */
/* cover with the default centre crop trimmed the top of the frame and cut the models' heads off
   (operator report). The faces sit in the upper band of the 2.35:1 source, so the crop window is
   biased upward; 30% keeps every head with a little air while still trimming mostly lawn. */
.lp .hero-img{display:block;width:100%;max-width:100%;height:auto;max-height:280px;object-fit:cover;object-position:50% 30%;border-radius:var(--radius-sm);border:1px solid var(--line);margin:0 0 22px}
/* An absolutely-positioned overlay label used to sit on the hero and was withdrawn; attribution
   belongs in the image asset, which is unchanged. The wrapper survives it deliberately: it owns the
   hero's bottom margin and zeroes the image's own, so deleting it would move the hero and shift the
   fold. `position:relative` is kept as the containing block for anything anchored to the hero later. */
.lp .hero-wrap{position:relative;margin:0 0 22px}
.lp .hero-wrap .hero-img{margin:0}
.lp .lp-fold{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);box-shadow:var(--shadow);margin:20px 0}
.lp .lp-fold summary{cursor:pointer;list-style:none;display:flex;align-items:center;justify-content:space-between;gap:12px;padding:18px 22px}
.lp .lp-fold summary::-webkit-details-marker{display:none}
.lp .lp-fold summary h2{margin:0;font-size:var(--fs-700)}
.lp .lp-fold summary::after{content:"";flex:none;width:9px;height:9px;border-right:2px solid var(--brand);border-bottom:2px solid var(--brand);transform:rotate(45deg);transition:transform .12s;margin-top:-3px}
.lp .lp-fold[open] summary::after{transform:rotate(225deg);margin-top:3px}
.lp .lp-fold .lp-fold-body{padding:0 22px 22px}
.lp .lp-fold .honesty{background:transparent;border:none;border-radius:0;padding:0}
.lp .lp-fold .lp-step,.lp .lp-fold .tier{box-shadow:none}

/* CSP: style-src 'self' forbids parsed style attributes, and production was silently dropping all
   fourteen of app.js's inline styles (the local harness serves no _headers, so it never showed).
   These utilities replace them one for one; dynamic bar widths apply via CSSOM (applyBarWidths). */
.u-block{display:block}
.u-gap{margin-top:8px}
.u-gap6{margin-top:6px}
.u-mut{color:var(--muted)}
.u-rule-top{border-top:1px solid var(--line)}
.u-sub{margin:6px 0 0;padding-left:18px}

/* ================================================================================================
   THE PRINTED REPORT IS A DOCUMENT, NOT A PRINTED SCREEN.

   WHAT WAS WRONG. Printing was a media query that hid the header, the step nav and the buttons and
   then sent the screen to the printer. Everything it did not name went with it. Page one opened
   with "Private. Your entries stay in this browser tab", which is a browser fact printed on paper.
   The ranked table kept the min-width it carries so it can scroll sideways on screen, so on a sheet
   that does not scroll the Budget column ran off the right edge and the scroll container's edge
   printed beside it as a rule. Every block was a rounded card on a tinted panel with screen padding
   and the screen's pixel type scale. Seventeen sheets, and nothing about any one of them said it
   was a document.

   WHAT THIS IS. A print stylesheet that sets a page instead of suppressing a screen: page geometry
   from @page, its own type scale in points, a cover sheet, rules and whitespace where the screen
   uses boxes and tint, and break control that keeps a heading with what it introduces.

   WHAT IT IS NOT. There is no running header, no folio and no contents list, because this engine
   family implements neither counter(page) nor target-counter() in a form Chrome and Safari both
   honour, and faking a page number from script would be a number that is right until the reader
   changes the paper size. That gap is known and is left open rather than papered over.

   SCOPE. Not one sentence, figure, provenance marker or flag is touched, and the six-block order of
   a school section is exactly as it was. Everything here is inside @media print except the single
   line that hides the cover sheet from the screen. The screen is unchanged.
   ============================================================================================== */

/* The cover sheet is paper furniture. It exists in the DOM so the print engine can see it, and a
   screen never shows it. */
.rep-cover{display:none}

@media print{
  /* THE PRINT TYPE SCALE, stated once, and this is the whole vocabulary the printed document has.
     Paper is read at arm's length in reflected light and cannot be zoomed, so it takes its own
     scale in points rather than importing the screen's eleven pixel steps.
     TWO FAMILIES, and the split is not decoration: prose is set in a serif because it is read in
     long passages, and every table, figure and money column is set in the sans because a column of
     digits is scanned and has to line up. */
  :root{
    --pp-fine:7pt;      /* source keys, provenance, notes: the smallest thing that prints */
    --pp-small:7.5pt;   /* table body, fine print */
    --pp-body:8pt;      /* body copy. Two columns at an 87mm measure take about 41 characters to
                           the line at this size, which is the measure the layout is set for. */
    --pp-lead:10.5pt;   /* the statement that opens the document or a section */
    --pp-h4:8pt;        /* a block heading inside a school section */
    --pp-h3:12.5pt;     /* a section heading */
    --pp-h2:15pt;       /* a school; the document's top-level headings */
    --pp-title:32pt;    /* the cover */
    --pp-serif:Georgia,"Times New Roman",Times,serif;
    --pp-sans:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
    --pp-ink:#111;
    --pp-soft:#4a4a4a;
    --pp-hair:#bcbcbc;
  }

  /* Page geometry. A margin, not padding: the sheet's own white edge, a little wider at the head
     than the foot so the text block sits where the eye expects it. Letter at 96dpi is 816 x 1056px,
     so 14mm and 12mm leave a 725px measure and a 963px column. The measure is set by what a school
     has to hold: two lanes and a gutter, at a size a parent reads without effort. */
  @page{size:Letter;margin:14mm 12mm 12mm}

  /* ---- the sheet ------------------------------------------------------------------------------ */
  body.printing-report{background:#fff;color:var(--pp-ink);
    font-family:var(--pp-serif);font-size:var(--pp-body);line-height:1.45}
  /* SCREEN CHROME IS NOT CONTENT. The utility bar was never in the generic hide list, so its privacy
     line, which is true only of a browser tab, opened the printed report. A control, a hint that
     explains a control, and an affordance that does nothing on paper all go with it. */
  body.printing-report .utilbar,body.printing-report .top,body.printing-report .steps,
  body.printing-report .tray,body.printing-report .skip-link,body.printing-report .pmodal,
  body.printing-report .rep-actions,body.printing-report .rep-ctas,body.printing-report .rep-depth,
  body.printing-report .rep-prepared,body.printing-report .empty,
  body.printing-report .footlinks,body.printing-report #foot{display:none!important}
  /* The site footer's disclaimers DO print: they are the legal statement a document that travels
     has to carry. Its navigation links and its build stamp do not, and on their own they were
     taking a twelfth sheet to say "Accessibility Statement". */
  body.printing-report .foot{margin-top:6mm;padding-top:3mm;border-top:.5pt solid var(--pp-hair)}
  body.printing-report .foot .disclaimer,body.printing-report .foot .copyr{
    font-family:var(--pp-serif);font-size:var(--pp-fine);line-height:1.35;color:var(--pp-soft);
    margin:0 0 1.6mm;max-width:none}
  /* Screen padding is not a margin. @page sets the edge; the text block fills what is left. */
  body.printing-report main.wrap,body.printing-report #view-report{
    max-width:none;width:auto;margin:0;padding:0}
  /* A link on paper is not a link. The bracketed source key is what carries the reference, and the
     Sources appendix at the back is what it resolves against. */
  body.printing-report a{color:inherit;text-decoration:none}

  /* ---- the cover sheet ------------------------------------------------------------------------ */
  body.printing-report .rep-cover{display:block;padding-top:34mm;
    break-after:page;page-break-after:always}
  .rep-cover-org{font-family:var(--pp-sans);font-size:var(--pp-fine);letter-spacing:.22em;
    text-transform:uppercase;color:var(--pp-soft);margin:0 0 46mm}
  .rep-cover-title{font-family:var(--pp-serif);font-size:var(--pp-title);font-weight:400;
    line-height:1.08;letter-spacing:-.01em;margin:0 0 6mm;color:var(--pp-ink)}
  .rep-cover-lede{font-size:var(--pp-lead);line-height:1.5;margin:0 0 12mm;max-width:118mm}
  .rep-cover-meta{margin:0;padding:5mm 0 0;border-top:.75pt solid var(--pp-ink);max-width:118mm}
  .rep-cover-meta>div{display:flex;gap:8mm;padding:1.6mm 0;align-items:baseline}
  .rep-cover-meta dt{flex:0 0 34mm;font-family:var(--pp-sans);font-size:var(--pp-fine);
    letter-spacing:.12em;text-transform:uppercase;color:var(--pp-soft)}
  .rep-cover-meta dd{margin:0;font-size:var(--pp-body);line-height:1.5}
  .rep-cover-meta dd ol{margin:0;padding:0;list-style:none}
  .rep-cover-meta dd li{margin:0 0 .8mm}
  .rep-cover-foot{margin:16mm 0 0;padding-top:3mm;border-top:.5pt solid var(--pp-hair);
    font-size:var(--pp-small);line-height:1.5;color:var(--pp-soft);max-width:118mm}

  /* ---- the document body ----------------------------------------------------------------------
     Every card loses its box. A rounded container on a tinted panel with a shadow is a screen
     affordance for a surface that scrolls; on paper the same job is done by a rule and by space. */
  body.printing-report .rep-card,body.printing-report .rep-best,body.printing-report .cmp-wrap,
  body.printing-report .rep-flag,body.printing-report .rep-loans,body.printing-report .rep-yr,
  body.printing-report .fit,body.printing-report .rep-prof,body.printing-report .pf-sections{
    background:none!important;border:0!important;border-radius:0!important;box-shadow:none!important;
    padding:0!important;margin:0}
  body.printing-report .rep-card{margin:0 0 7mm}
  body.printing-report .cmp-wrap{overflow:visible!important}

  /* Headings: one family, one scale, a rule instead of a coloured bar. */
  body.printing-report #view-report>h2.h,body.printing-report .rep-card>h3{
    font-family:var(--pp-serif);font-weight:400;color:var(--pp-ink);
    border-bottom:.75pt solid var(--pp-ink);padding-bottom:2mm;margin:0 0 4mm}
  body.printing-report #view-report>h2.h{font-size:var(--pp-h2)}
  body.printing-report .rep-card>h3{font-size:var(--pp-h3)}
  body.printing-report #view-report>p.sub{font-size:var(--pp-lead);line-height:1.5;
    color:var(--pp-ink);margin:0 0 7mm;max-width:132mm}
  body.printing-report .rep-sch h4{font-family:var(--pp-sans);font-size:var(--pp-h4);font-weight:700;
    letter-spacing:.1em;text-transform:uppercase;color:var(--pp-soft);margin:5mm 0 1.6mm;
    border:0;padding:0}

  /* Body copy: one measure and one leading, wherever the sentence came from. */
  body.printing-report .hint,body.printing-report .rep-why,body.printing-report .rep-weighs,
  body.printing-report .rep-analysis,body.printing-report .rep-flag,body.printing-report .rep-loans,
  body.printing-report .rep-confirm>li,body.printing-report .rep-steps li,
  body.printing-report .rep-reapply li,body.printing-report .rep-best p{
    font-family:var(--pp-serif);font-size:var(--pp-body);line-height:1.5;color:var(--pp-ink);
    max-width:none}
  body.printing-report .hint b,body.printing-report .rep-why b{color:var(--pp-ink)}
  body.printing-report .hint,body.printing-report .rep-why,body.printing-report .rep-weighs,
  body.printing-report .rep-analysis{margin:0 0 2.6mm}
  /* A callout keeps its emphasis without a tinted panel: a rule down the left and an indent. */
  body.printing-report .rep-flag{border-left:1.5pt solid var(--pp-ink)!important;
    padding:.2mm 0 .2mm 3mm!important;margin:2mm 0}
  body.printing-report .rep-loans{border-left:.5pt solid var(--pp-hair)!important;
    padding:.2mm 0 .2mm 3mm!important;margin:2mm 0;font-size:var(--pp-small)}

  /* ---- the ranked table -----------------------------------------------------------------------
     THE CLIPPING, AND WHY THE LAST FIX DID NOT TAKE. table.cmp carries min-width:680px so it can
     scroll sideways inside .cmp-wrap on screen. Paper does not scroll: 680px of table plus the
     card's padding plus the page wrapper's padding is wider than the 695px measure, so the Budget
     column fell off the right edge of sheet one. The previous pass set width:100% and left the
     minimum in place, and a minimum wins over a width. The minimum is removed here, and the six
     columns are given fixed shares of the measure so the table cannot outgrow the page whatever
     lands in it. */
  body.printing-report table.cmp,body.printing-report table.rep-table{
    min-width:0!important;width:100%!important;table-layout:fixed;
    font-family:var(--pp-sans);font-size:var(--pp-small);border-collapse:collapse}
  body.printing-report table.rep-table thead th{position:static!important;background:none!important;
    color:var(--pp-ink)!important;font-size:var(--pp-fine);text-transform:uppercase;
    letter-spacing:.09em;font-weight:700;border-bottom:.75pt solid var(--pp-ink);
    padding:0 3mm 1.6mm 0;vertical-align:bottom}
  body.printing-report table.rep-table tbody td{border-bottom:.5pt solid var(--pp-hair);
    padding:2.2mm 3mm 2.2mm 0;vertical-align:top;line-height:1.35;overflow-wrap:break-word}
  body.printing-report table.rep-table th:last-child,
  body.printing-report table.rep-table td:last-child{padding-right:0}
  body.printing-report table.rep-table th:nth-child(1){width:5%}
  body.printing-report table.rep-table th:nth-child(2){width:29%}
  body.printing-report table.rep-table th:nth-child(3){width:13%}
  body.printing-report table.rep-table th:nth-child(4){width:19%}
  body.printing-report table.rep-table th:nth-child(5){width:17%}
  body.printing-report table.rep-table th:nth-child(6){width:17%}
  body.printing-report table.rep-table{margin:0 0 2.6mm}
  body.printing-report .rep-loc{font-family:var(--pp-sans);font-size:var(--pp-fine);color:var(--pp-soft)}
  /* A pill is a screen chip. On paper the same word is a word. */
  body.printing-report .pill{display:inline!important;background:none!important;
    color:var(--pp-ink)!important;border:0!important;border-radius:0!important;padding:0!important;
    font-size:inherit;font-weight:700}

  /* ---- the best-fit statement -----------------------------------------------------------------
     A tinted card with an accent rail becomes a rule above and a rule below, which is the same
     emphasis without the furniture. */
  body.printing-report .rep-best{border-top:.75pt solid var(--pp-ink)!important;
    border-bottom:.75pt solid var(--pp-ink)!important;padding:3.5mm 0!important;margin:0 0 7mm}
  body.printing-report .rep-best-tag{font-family:var(--pp-sans);font-size:var(--pp-fine);
    letter-spacing:.14em;color:var(--pp-soft)}
  body.printing-report .rep-best-name{font-family:var(--pp-serif);font-size:var(--pp-h3);
    font-weight:400;color:var(--pp-ink);margin:1mm 0 1.6mm}

  /* ---- one school, one fresh page -------------------------------------------------------------
     Sections vary in length, which is exactly what pagination is for. Starting each school on its
     own sheet is what makes the variation harmless: a section can run to one page or to three and
     the next school still opens at the top of a sheet, so no heading is ever stranded and a family
     can hand a counsellor the two pages about one school. */
  body.printing-report .rep-sch{border:0!important;padding:0!important;margin:0;
    break-before:page;page-break-before:always}
  /* The band verdict rides on the same line as the name, at the right edge, rather than taking a
     line of its own under it. A school has one page and the head of it is not where to spend one. */
  body.printing-report .rep-sch-hd{display:flex;align-items:baseline;justify-content:space-between;
    gap:6mm;margin:0}
  body.printing-report .rep-sch-name{display:block;font-family:var(--pp-serif);
    font-size:var(--pp-h2);font-weight:400;letter-spacing:-.01em;color:var(--pp-ink);
    text-decoration:none;padding:0;margin:0;line-height:1.1}
  body.printing-report .rep-sch .rep-sch-hd .pill{display:inline-block!important;flex:0 0 auto;
    font-family:var(--pp-sans);font-size:var(--pp-fine);letter-spacing:.14em;text-transform:uppercase;
    color:var(--pp-soft)!important;font-weight:700;white-space:nowrap;margin:0}
  body.printing-report .rep-sch>.rep-loc{margin:.2mm 0 1mm;padding-bottom:1mm;
    border-bottom:.75pt solid var(--pp-ink)}
  /* The band and its caveat read as the first line of the argument, not as a coloured badge. */
  body.printing-report .rep-sch .fit{margin:0 0 3mm!important;font-family:var(--pp-serif);
    font-size:var(--pp-body);line-height:1.5}
  body.printing-report .fit-band{display:inline!important;background:none!important;
    color:var(--pp-ink)!important;padding:0!important;border-radius:0!important;
    font-size:inherit;font-weight:700;letter-spacing:.02em}
  body.printing-report .fit-cav{color:var(--pp-soft)}

  /* ---- the evidence rows ----------------------------------------------------------------------- */
  body.printing-report .fit-rows{margin:1.6mm 0 0;font-family:var(--pp-sans);font-size:var(--pp-small)}
  body.printing-report .fit-rows>div{display:grid;grid-template-columns:44mm minmax(0,1fr);
    gap:0 5mm;padding:1.6mm 0;border-bottom:.5pt solid var(--pp-hair)}
  body.printing-report .fit-rows dt{font-weight:700;color:var(--pp-soft)}
  body.printing-report .fit-rows dd{margin:0;line-height:1.4}
  body.printing-report .rep-sch .nc-cdsmeta,body.printing-report .rep-sch .sd-note,
  body.printing-report .prov,body.printing-report .nc-cdsmeta,body.printing-report .sd-note{
    font-size:var(--pp-fine);color:var(--pp-soft)}
  body.printing-report .rep-key{color:var(--pp-soft);font-family:var(--pp-sans);font-size:var(--pp-fine)}
  body.printing-report .rep-check{color:var(--pp-ink);font-weight:700}

  /* ---- the money block ------------------------------------------------------------------------- */
  body.printing-report .rep-4y{display:flex;gap:6mm;margin:2.6mm 0;font-family:var(--pp-sans)}
  body.printing-report .rep-yr{border:0!important;background:none!important;
    padding:0 4mm 0 0!important;min-width:0;font-size:var(--pp-small);font-weight:700}
  body.printing-report .rep-yr small{font-family:var(--pp-sans);font-size:var(--pp-fine);
    color:var(--pp-soft);font-weight:400}
  body.printing-report .rep-4y-line{font-family:var(--pp-sans);font-size:var(--pp-small);padding:1mm 0}
  body.printing-report .rep-4y-big{font-size:var(--pp-body);border-bottom:.75pt solid var(--pp-ink)}

  /* ---- confirmation steps, next steps, sources ------------------------------------------------- */
  body.printing-report .rep-confirm,body.printing-report .rep-steps,
  body.printing-report .rep-reapply ul{margin:1.6mm 0 0;padding-left:6mm}
  body.printing-report .rep-confirm>li,body.printing-report .rep-steps li,
  body.printing-report .rep-reapply li{margin:0 0 1.6mm}
  body.printing-report .rep-reapply,body.printing-report .rep-sources,
  body.printing-report .rep-notes{break-before:page;page-break-before:always}
  body.printing-report .rep-notes .rep-fn{margin:0;padding:2mm 0 0 5mm;border-top:0}
  body.printing-report .rep-srclist{font-family:var(--pp-sans);font-size:var(--pp-small)}
  body.printing-report .rep-srclist>div{display:grid;grid-template-columns:24mm minmax(0,1fr);
    gap:0 5mm;padding:1.6mm 0;border-bottom:.5pt solid var(--pp-hair)}
  body.printing-report .rep-srclist dt{white-space:nowrap;font-weight:700;color:var(--pp-soft)}
  body.printing-report .rep-srclist dd{margin:0;line-height:1.4;overflow-wrap:break-word}
  body.printing-report .nc-disc,body.printing-report .note{font-family:var(--pp-serif);
    font-size:var(--pp-small);color:var(--pp-soft);line-height:1.5;margin:6mm 0 0;padding-top:3mm;
    border-top:.5pt solid var(--pp-hair)}

  /* ---- one ink, in two values ------------------------------------------------------------------
     The screen separates things with colour: brand navy on the figure that matters, a muted
     grey-blue on provenance, a warn tint behind a caution row, a faint navy wash behind the aid
     panel. A black and white printer flattens all four to the same grey, and a colour one prints
     what is plainly a screenshot. On paper those separations are already carried by the two
     families, the scale and the rules set above, so the document runs on one ink at two values:
     the text, and everything that qualifies the text. */
  body.printing-report .rep-best b,body.printing-report .hint a,
  body.printing-report .rep-confirm a,body.printing-report .rep-srclist a{color:var(--pp-ink)}
  body.printing-report small,body.printing-report .fit-note,body.printing-report .is-muted,
  body.printing-report .rep-4y-naive span,body.printing-report .rep-4y-prem span,
  body.printing-report .nc-na{color:var(--pp-soft)}
  body.printing-report .rep-card :is(small,.prov,.nc-rec,.nc-coanote,.admityr,.trend){
    font-size:var(--pp-fine)}
  body.printing-report .rep-prof-list>li.is-warn{color:var(--pp-ink);background:none!important;
    border:0!important;border-radius:0!important;padding:0!important}
  body.printing-report .nc-aidreal{background:none!important;border:0!important;border-radius:0!important;
    border-left:.5pt solid var(--pp-hair)!important;padding:.4mm 0 .4mm 4mm!important;
    font-family:var(--pp-serif);font-size:var(--pp-body);line-height:1.5;margin:3mm 0}
  body.printing-report .note,body.printing-report .nc-disc,body.printing-report .rep-prof{
    background:none!important;border:0!important}

  /* ---- the two lanes, the footnotes and the spread, on paper ------------------------------------
     Two columns is not decoration here: a school has to fit on one sheet so both readers see both
     halves at once, and half the measure is also the right measure for the size this text is set
     at. The footnotes run two-up at the foot in the smallest step the document has. */
  /* NOT TWO EQUAL COLUMNS. The student's half of a school carries the reading and its evidence and
     the family's half carries a money block of fixed length, so an even split leaves the family
     column short while the student column runs off the foot of the sheet. The measure is split in
     the proportion the content actually takes, which is what balances the two lanes and is what
     lets the page close. */
  body.printing-report .rep-two{display:grid;grid-template-columns:1fr 1fr;gap:5.5mm;margin:1.2mm 0 0}
  body.printing-report .rep-lane{min-width:0}
  body.printing-report .rep-lane-tag{font-family:var(--pp-sans);font-size:var(--pp-fine);
    letter-spacing:.14em;text-transform:uppercase;color:var(--pp-soft);font-weight:700;
    margin:0 0 1mm;padding-bottom:.8mm;border-bottom:.5pt solid var(--pp-hair)}
  body.printing-report .rep-lane>h4:first-of-type{margin-top:0}
  body.printing-report .rep-lane .rep-why{margin:0 0 1.8mm}
  body.printing-report .rep-lane .fit-rows{margin:1mm 0 0}
  /* The notes that govern the whole document run in the same two columns the school pages use.
     Set across the full measure at this size they were 110 characters to the line, which is twice
     a readable one. */
  body.printing-report .rep-genl{columns:2;column-gap:6mm;margin:0 0 3mm}
  body.printing-report .rep-genl>p{break-inside:avoid;page-break-inside:avoid;margin:0 0 2mm;
    line-height:1.3}
  body.printing-report .rep-why{padding-left:4mm;margin:0 0 2.6mm}
  body.printing-report .rep-why>li{margin:0 0 .8mm}
  body.printing-report .rep-fnm{font-family:var(--pp-sans);font-size:var(--pp-fine);
    color:var(--pp-ink);font-weight:700}
  body.printing-report .rep-fn{margin:3mm 0 0;padding:2mm 0 0 4.5mm;
    border-top:.5pt solid var(--pp-hair);columns:2;column-gap:7mm;font-size:var(--pp-fine)}
  body.printing-report .rep-fn>li{margin:0 0 1.6mm;break-inside:avoid;page-break-inside:avoid}
  body.printing-report .rep-fn .rep-flag,body.printing-report .rep-fn p{
    border:0!important;padding:0!important;margin:0!important;font-family:var(--pp-serif);
    font-size:var(--pp-fine)!important;line-height:1.28;color:var(--pp-ink)}
  body.printing-report .rep-4y{display:block;margin:1.8mm 0}
  body.printing-report .rep-4y-yrs{display:flex;flex-wrap:wrap;gap:0}
  body.printing-report .rep-4y-tot{margin-top:1.6mm}
  /* A closed disclosure control prints as a heading with nothing under it, which on paper reads as
     a section the printer dropped. It is a control: it does not print. */
  body.printing-report details.rep-prof:not([open]){display:none!important}
  body.printing-report .rep-prof-sec>h4{margin-top:3mm}

  body.printing-report .rep-spread{break-before:page;page-break-before:always}
  body.printing-report .rep-spread .sp{width:100%;height:auto;margin:4mm 0 0}
  body.printing-report .sp-grid{stroke:var(--pp-hair);stroke-width:.75}
  body.printing-report .sp-axis{stroke:var(--pp-ink);stroke-width:1}
  body.printing-report .sp-ylab,body.printing-report .sp-xlab{fill:var(--pp-soft);
    font-family:var(--pp-sans);font-size:10px}
  body.printing-report .sp-budget{stroke:var(--pp-ink);stroke-width:1;stroke-dasharray:5 3}
  body.printing-report .sp-budlab{fill:var(--pp-ink);font-family:var(--pp-sans);font-size:10px;font-weight:700}
  body.printing-report .sp-dot{fill:var(--pp-ink)}
  body.printing-report .sp-dotlab{fill:var(--pp-ink);font-family:var(--pp-serif);font-size:12px}

  /* ---- fitting a school on one sheet -------------------------------------------------------------
     A school is one page or it is not one page, and both readers have to see both halves at once.
     Three things bought the room, and none of them cuts a sentence.

     ONE. The evidence rows were a two column grid, and half a page measure is not wide enough for
     a 44mm label column: every value wrapped four or five lines deep and the block ran to 816px on
     its own. In a lane the rows run in, label and value on the same line, and the source note that
     qualifies the row sits under it in the smallest step.
     TWO. Leading. Paper set at 9.75pt does not need 1.5 line spacing at half measure; the natural
     measure for this column is nearer 1.35, and it reads better as well as shorter.
     THREE. The waterfall, the money lines and the list items lose the padding they carry on screen
     for a finger, which is not a paper quantity. */
  body.printing-report .rep-lane{line-height:1.25}
  body.printing-report .rep-lane .rep-why,body.printing-report .rep-lane .rep-weighs,
  body.printing-report .rep-lane .hint,body.printing-report .rep-lane .rep-confirm>li,
  body.printing-report .rep-lane .rep-analysis,body.printing-report .rep-lane .rep-flag,
  body.printing-report .rep-lane .fit,body.printing-report .rep-lane .rep-loans,
  body.printing-report .rep-lane p{line-height:1.25}
  body.printing-report .rep-lane .fit-rows>div{display:block;padding:.6mm 0}
  body.printing-report .rep-lane .fit-rows dt{display:inline;font-weight:700;color:var(--pp-ink);
    padding-right:1.6mm}
  body.printing-report .rep-lane .fit-rows dd{display:inline;margin:0}
  body.printing-report .rep-lane .fit-rows .fit-note{display:block;font-size:var(--pp-fine);
    line-height:1.3;margin-top:.4mm}
  body.printing-report .rep-lane .rep-confirm,body.printing-report .rep-lane .rep-prof-list{
    padding-left:4.5mm;margin:.8mm 0 0}
  body.printing-report .rep-lane .rep-prof-list{font-family:var(--pp-serif);font-size:var(--pp-body);
    line-height:1.25}
  body.printing-report .rep-lane .rep-prof-list>li{margin:0 0 .6mm}
  body.printing-report .rep-lane .rep-confirm>li{margin:0 0 .8mm}
  body.printing-report .rep-lane .nc-line{padding:.6mm 0;gap:3mm;font-size:var(--pp-small)}
  body.printing-report .rep-lane .nc-line.nc-total{padding-top:1.4mm;margin-top:.6mm;
    font-size:var(--pp-body);color:var(--pp-ink)}
  body.printing-report .rep-lane .rep-4y-line{padding:.6mm 0}
  body.printing-report .rep-lane h4{margin:1.5mm 0 .5mm}
  body.printing-report .rep-lane>h4:first-of-type{margin-top:2mm}
  body.printing-report .rep-lane .rep-prof-sec{margin:1.8mm 0 0}
  body.printing-report .rep-lane .nc-aidreal{margin:1.8mm 0 0}
  body.printing-report .rep-water{margin:1.2mm 0 0}

  /* ---- break control ---------------------------------------------------------------------------
     Keep-with-next where it earns a better page and nowhere else. A block that cannot fit on a page
     and still asks to stay whole is a block the engine breaks anyway, at the worst line it can
     find, which is why neither .rep-sch nor .rep-card asks. */
  body.printing-report .rep-cover,body.printing-report .rep-best,body.printing-report .rep-4y,
  body.printing-report .fit-rows>div,body.printing-report .rep-srclist>div,
  body.printing-report .rep-flag,body.printing-report .rep-confirm>li,
  body.printing-report table.rep-table tr{break-inside:avoid;page-break-inside:avoid}
  body.printing-report .rep-sch-hd,body.printing-report .rep-sch>.rep-loc,
  body.printing-report .rep-sch h4,body.printing-report .rep-card>h3,
  body.printing-report #view-report>h2.h,body.printing-report .rep-best-tag,
  body.printing-report .rep-best-name{break-after:avoid;page-break-after:avoid}
  body.printing-report p,body.printing-report li{orphans:2;widows:2}
}

/* ---------- Governed Decision Intelligence sections ------------------------------------------- */
/* Additive. No existing rule is modified. The four states are visually distinct on purpose: a
   locked section must never be mistaken for an empty one, and a suppressed figure must never be
   mistaken for one the college failed to report. */
.di-host{margin-top:1rem}
.di-sec{border-top:1px solid var(--line,#e5e7eb);padding:.85rem 0}
.di-h{margin:0 0 .5rem;font-size:.95rem;font-weight:600}
.di-rows{margin:0;display:grid;gap:.35rem}
.di-rows>div{display:flex;justify-content:space-between;gap:1rem;align-items:baseline}
.di-rows dt{margin:0;color:var(--muted,#6b7280)}
.di-rows dd{margin:0;font-variant-numeric:tabular-nums;text-align:right}
.di-src{color:var(--muted,#6b7280);font-size:.8em;font-weight:400}
.di-note{margin:.5rem 0 0;color:var(--muted,#6b7280);font-size:.85em}
/* LOCKED — an offer, not an absence. */
.di-locked{margin:0;color:var(--muted,#6b7280);font-style:italic}
/* MISSING — the college did not report it. */
.di-missing{margin:0;color:var(--muted,#6b7280)}
/* ERROR — ours, and retryable per section. */
.di-error{margin:0;color:var(--bad,#b91c1c)}
.di-retry{background:none;border:0;padding:0;color:inherit;text-decoration:underline;cursor:pointer;font:inherit}
.di-skel{margin:0;color:var(--muted,#9ca3af)}
.di-open{font:inherit;cursor:pointer;padding:.35rem .7rem;border:1px solid var(--line,#e5e7eb);
         border-radius:.4rem;background:none}
.di-progs{list-style:none;margin:0;padding:0;display:grid;gap:.6rem}
.di-obs{list-style:none;margin:.2rem 0 0;padding:0;color:var(--muted,#6b7280);font-size:.9em}

/* ================================================================================================
   CollegePath Analysis — the premium surface.
   ------------------------------------------------------------------------------------------------
   These classes existed in analysis.html and analysis.js with NO rules behind them, so the one page
   a family pays for rendered as unstyled browser defaults: stacked headings, bare bullet lists, no
   cards. It looked like a debug dump, and paired with a "records loaded" line it read like one.
   The rules below reuse the same tokens as the rest of the site so the page belongs to it, and add
   nothing new to the palette.
   ================================================================================================ */
.an-panel{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);
  padding:16px 18px;box-shadow:var(--shadow);margin:0 0 14px}
.an-panel h3{margin:0 0 8px;font-size:var(--fs-500);line-height:1.25}
.an-panel p{margin:0 0 8px;color:var(--ink-2)}
.an-panel p:last-child{margin-bottom:0}
.an-panel .an-note{color:var(--muted);font-size:var(--fs-200)}
.an-list{margin:10px 0 0;padding:0 0 0 18px}
.an-list li{margin:0 0 8px;color:var(--ink-2);line-height:1.45}
.an-list li b{color:var(--ink)}

/* ---------- Admitted: the family's own statement, and the segment it drives ----------------------
   Built from the tokens the rest of the app already uses -- --surface-2, --line, --brand-700,
   --muted, --radius-sm -- so this reads as part of myCollegePath rather than as something added
   afterwards. The segment panel borrows .rep-depth entirely, the way the print chooser already does:
   same surface, same line, same radius, same measure. */

/* The per-school control. .pf-check's inline shape: the label wraps the input so the whole row is
   the hit target, and the input is a real checkbox so the checked state is native rather than
   simulated. Nothing here communicates state by colour alone -- the box itself carries it. */
.adm-check{display:inline-flex;align-items:center;gap:8px;cursor:pointer;
  font-size:var(--fs-200);color:var(--ink);line-height:1.3;padding:4px 2px;border-radius:var(--radius-sm)}
.adm-check input{width:16px;height:16px;flex:0 0 auto;cursor:pointer;margin:0}
.adm-check:focus-within{outline:2px solid var(--brand-700);outline-offset:2px}
.adm-check:hover{background:var(--surface-2)}
.adm-lbl{white-space:nowrap}
/* The school name is in the accessible name but not in the visual label: seven visible copies of the
   school name in one table column is noise, and seven identical "Admitted" labels announced to a
   screen reader is worse. This is how both readers get what they need. */
.u-sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0 0 0 0);white-space:nowrap;border:0}

/* Financial card: the control sits under the head, aligned with the card's own padding.
   THE TOP MARGIN IS NOT DECORATIVE. It was -4px, which tightened the head group and left no room for
   the control's own focus ring: on keyboard focus the 2px outline at 2px offset expanded upward into
   the descenders of the school name and read as striking through it. A focus indicator that collides
   with adjacent text is a worse indicator than a plain one. 6px clears a 4px ring with room to
   spare. Found in UAT capture, not by axe, which checks that an indicator exists and contrasts but
   not that it lands clear of its neighbours. */
.nc-adm{margin:6px 0 10px;padding:0 2px}

/* Summary table column. */
.adm-col{white-space:nowrap;vertical-align:middle}

/* The segment panel. Inherits .rep-depth for surface and measure; only the internals differ. */
.rep-depth.adm-seg{display:block;padding:12px 14px;border:1px solid var(--line);
  background:var(--surface-2);border-radius:var(--radius-sm);max-width:640px;margin:0 0 16px;cursor:default}
.adm-seg-lg{padding:0;display:block}
.adm-seg-lg b{display:block;font-size:var(--fs-300)}
.adm-seg-lg small{display:block;color:var(--muted);font-size:var(--fs-200);margin-top:2px;line-height:1.45}
.adm-seg-opts{display:flex;flex-wrap:wrap;gap:8px 18px;margin-top:10px}
.adm-seg-opt{display:inline-flex;align-items:center;gap:8px;cursor:pointer;font-size:var(--fs-300);
  padding:4px 2px;border-radius:var(--radius-sm)}
.adm-seg-opt input{width:16px;height:16px;flex:0 0 auto;cursor:pointer;margin:0}
.adm-seg-opt:focus-within{outline:2px solid var(--brand-700);outline-offset:2px}
/* The count is text, so the active segment and its size are legible without relying on hue. */
.adm-seg-n{color:var(--muted);font-variant-numeric:tabular-nums}

/* The printed status line. Text, not a pill: it has to survive print, and a colour is not a claim. */
.rep-adm{font-size:var(--fs-200);color:var(--ink);margin:2px 0 0}
.rep-adm-src{color:var(--muted)}
.rep-sub2{font-size:var(--fs-300);color:var(--muted);margin:2px 0 12px;letter-spacing:.01em}

/* Responsive. At narrow widths the table column and the radio row are the two things that break, so
   they are the two things handled: the options stack, and the column keeps its own tap target. */
@media (max-width:720px){
  .adm-seg-opts{flex-direction:column;gap:10px}
  .adm-check{padding:6px 2px}
  .adm-check input,.adm-seg-opt input{width:18px;height:18px}   /* comfortable touch target */
}
@media (max-width:520px){
  .adm-lbl{font-size:var(--fs-100)}
  .rep-adm-src{display:block}
}

/* PRINT. The controls are interactive and do not belong in a PDF; the segment panel follows the same
   rule .rep-depth already sets for itself. What survives is the STATUS, as text, with its provenance
   marker -- so a printed report still says which schools the family told us they were admitted to,
   and says who said it. */
@media print{
  .adm-check,.adm-col,.rep-depth.adm-seg{display:none!important}
  .rep-adm{display:block!important;color:#000}
}
body.printing-report .adm-check,
body.printing-report .adm-col,
body.printing-report .rep-depth.adm-seg{display:none!important}
body.printing-report .rep-adm{display:block!important}

/* Account link in the page header, and the purchase outcome banner in the app. The banner is hidden
   until a checkout outcome needs saying, so it adds nothing to the first paint. */
.top .acct{margin-left:auto;color:#fff;font-weight:600;text-decoration:underline;text-underline-offset:3px;white-space:nowrap;padding:6px 2px}
.top .acct:focus-visible{outline:2px solid #fff;outline-offset:2px}
.purchase-status{margin:12px 0;padding:12px 16px;border:1px solid var(--accent);border-left-width:4px;border-radius:8px;background:var(--accent-bg);color:inherit}
.purchase-status .pass-go{margin-left:8px}
