/* ==========================================================================
   site.css — the single shared foundation for every finlingo.org page.

   WHY THIS FILE EXISTS
   Before it, index / leaderboard / privacy / 404 / competition-prep /
   advisor-dashboard / admin-dashboard / state.css / why-index each carried
   their OWN inline copy of the palette, type stack and button styles — nine
   near-identical but slowly diverging duplicates. That drift is most of what
   made the site feel assembled rather than designed. Tokens, type, buttons,
   nav, footer and the ledger components now live here and here only. Page
   files keep ONLY what is genuinely unique to that page.

   THE TYPOGRAPHIC THESIS
   DESIGN.md's north star is "The Chunky Ledger". This file makes that literal:
   every FIGURE on the site — lesson counts, XP, percentages, class codes,
   category tallies — is set in IBM Plex Mono with tabular numerals, the way a
   real ledger sets its columns. Prose is IBM Plex Sans at weight 400.
   Headlines are Fraunces, a variable serif with genuine SOFT and WONK axes,
   so the display face carries warmth without the body copy shouting.

   Baloo 2 survives in exactly one role: the logo wordmark (--f-brand), per
   DESIGN.md. The APP (app.html / popup.css / web.css) is deliberately NOT
   served by this file — it keeps Baloo 2 + Nunito and its own game furniture.

   HARD RULES ENFORCED HERE
   1. Prose is weight 400. Never 600+ for a paragraph. If copy needs emphasis
      it gets <b> at 600, not a whole paragraph at 700.
   2. Uppercase + letter-spacing is banned above headlines. The one sanctioned
      micro-label is .microlabel, for true units ("XP"). Section overlines use
      .datastamp, which is sentence-case mono and must carry a real FIGURE —
      "120 lessons · 6 units", never "FEATURES".
   3. Rest-state cards get a hairline border, not an ambient shadow. --lift is
      reserved for the two things that genuinely float. (DESIGN.md's own "No
      Soft Gray Card Rule", which the old CSS had drifted away from.)
   4. Hover is differentiated by element TYPE — buttons press, links draw an
      underline, rows grow a left rule, framed art scales inside its frame.
      There is no universal translateY(-1px) and no filter: brightness().
   5. No scroll-reveal on ordinary content. Motion is spent on the hero's one
      staged entrance plus the two animations that carry meaning (roster bars
      filling, class code stamping).
   ========================================================================== */

/* ==========================================================================
   1. TOKENS
   ========================================================================== */
:root {
  /* ---- brand accents (unchanged from DESIGN.md — these are load-bearing) --- */
  --green: #58cc02;
  --green-dark: #46a302;
  --green-deep: #3a8a00;
  --green-lit: #63dd07;          /* explicit hover shade, replaces brightness() */
  --green-tint: #eaf7db;

  --gold: #ffc800;
  --gold-dark: #e6a700;
  --gold-deep: #8f5f00;          /* darkened for AA text on gold-tint */
  --gold-lit: #ffd52e;
  --gold-tint: #fff6dd;

  --ocean: #1aa3e8;
  --ocean-dark: #1184c6;
  --ocean-deep: #0b5c8a;         /* darkened for AA as link text on white */
  --ocean-lit: #34b2f0;
  --ocean-tint: #e6f4fd;

  --purple: #a560e8;
  --purple-deep: #7233ad;
  --coral: #ff6f91;
  --coral-deep: #c53a5d;
  --red: #d93a3a;
  --red-tint: #fdeaea;

  /* ---- neutrals: a real ramp, water-cast, not a pastel wash ----
     The old palette had two neutrals doing six jobs. Headings, prose and
     captions now sit at measurably different contrasts, and there are two
     distinct paper tones (see --ledger). */
  --ink: #10344a;                /* headings — deep water. 11.4:1 on white */
  --ink-2: #274759;              /* sub-headings */
  --body: #3d5260;               /* prose — 7.8:1 on white */
  --muted: #5c7180;              /* captions — 4.9:1 on white, passes AA */
  --hair: #d8e2e8;               /* hairlines */
  --hair-2: #e9eef1;             /* faintest divider */

  /* two papers, doing different jobs: cool for marketing surfaces, WARM for
     data surfaces. This is the tertiary tone the palette was missing — it
     gives the ledger components their own material. */
  --paper: #ffffff;
  --paper-2: #f6fafb;            /* cool near-white section ground */
  --ledger: #fbfaf6;             /* warm paper — figures, tables, code stamps */
  --ledger-line: #e5e0d4;        /* warm hairline, only on --ledger surfaces */

  --panel: #0b2537;              /* dark credibility panel + footer */
  --panel-2: #11364e;
  --abyss: #051d30;              /* hero surface + nav — one continuous colour */

  /* ---- type ---- */
  --f-display: "Fraunces", Georgia, "Times New Roman", serif;
  --f-sans: "IBM Plex Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --f-mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
  --f-brand: "Baloo 2", var(--f-sans);

  /* ---- radius: varied by role, not one value everywhere ----
     Data surfaces are near-square because ledgers are; buttons and cards are
     progressively softer. This variation is what stops the "everything at the
     same radius" read. */
  --r-data: 5px;
  --r-input: 10px;
  --r-btn: 13px;
  --r-card: 20px;
  --r-pill: 999px;

  /* ---- elevation: structural only ----
     --lift is for genuinely floating objects. Rest-state cards use --hair. */
  --lift: 0 2px 4px rgba(11, 37, 55, 0.05), 0 18px 40px -16px rgba(11, 37, 55, 0.22);
  --lift-deep: 0 4px 8px rgba(2, 14, 24, 0.28), 0 40px 80px -24px rgba(2, 14, 24, 0.5);

  /* ---- motion ---- */
  --ease: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-press: cubic-bezier(0.2, 0.8, 0.3, 1);

  /* ---- measure ---- */
  --wrap: 1120px;
}

/* ==========================================================================
   2. BASE
   ========================================================================== */
* { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  /* anchor links land below the sticky nav instead of under it */
  scroll-padding-top: 84px;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  font-family: var(--f-sans);
  font-size: 16px;
  font-weight: 400;              /* RULE 1: prose is 400 */
  line-height: 1.65;
  color: var(--body);
  background: var(--paper);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
  font-variant-numeric: tabular-nums;
  /* kills the ~300ms tap delay and the default grey flash on touch, both of
     which make a tap on the chunky buttons feel unresponsive */
  touch-action: manipulation;
  -webkit-tap-highlight-color: rgba(26, 163, 232, 0.16);
}

/* `height: auto` is load-bearing, not decoration: these images carry width/
   height attributes (correctly, so the browser reserves space and the page
   doesn't shift). Without height:auto, max-width scales the WIDTH down but the
   height attribute still applies literally, so a 640x985 screenshot renders
   260x985 — stretched to nearly four times its real aspect ratio. */
img, svg, video { max-width: 100%; height: auto; display: block; }

/* ---- headings: Fraunces, with the soft/wonk axes doing the warmth ----
   optical sizing is left to the browser (font-optical-sizing: auto) so large
   headings automatically pick up the display cut's tighter spacing. */
h1, h2, h3, h4 {
  font-family: var(--f-display);
  font-optical-sizing: auto;
  font-variation-settings: "SOFT" 60, "WONK" 1;
  color: var(--ink);
  font-weight: 600;
  line-height: 1.1;
  letter-spacing: -0.02em;
  text-wrap: balance;
  margin: 0;
}
h1 { font-size: clamp(38px, 4.6vw, 62px); font-weight: 700; letter-spacing: -0.032em; }
h2 { font-size: clamp(27px, 3.4vw, 40px); letter-spacing: -0.026em; }
h3 { font-size: clamp(20px, 2.2vw, 26px); letter-spacing: -0.02em; }
h4 { font-size: 17px; }

p { margin: 0; }

/* ---- prose defaults ---- */
.lede {
  font-size: 17.5px;
  line-height: 1.7;
  font-weight: 400;
  color: var(--body);
  max-width: 62ch;
  margin: 0;
}
.fine {
  font-size: 13.5px;
  line-height: 1.6;
  font-weight: 400;
  color: var(--muted);
  margin: 0;
}
b, strong { font-weight: 600; color: var(--ink-2); }

/* ==========================================================================
   3. FIGURES — the ledger idea, made typographic
   Every number on the site goes through .fig (or .fig-xl for display figures).
   Tabular numerals mean columns of numbers actually line up.
   ========================================================================== */
.fig {
  font-family: var(--f-mono);
  font-variant-numeric: tabular-nums;
  font-feature-settings: "zero" 1;   /* slashed zero — reads as data, not prose */
  letter-spacing: -0.02em;
  color: var(--ink);
}
.fig-xl {
  font-family: var(--f-mono);
  font-variant-numeric: tabular-nums;
  font-feature-settings: "zero" 1;
  font-weight: 500;
  font-size: clamp(34px, 4vw, 46px);
  line-height: 1;
  letter-spacing: -0.045em;
  color: var(--ink);
  display: block;
}

/* .datastamp — the ONLY sanctioned section overline.
   Sentence-case mono, and it must carry a real figure. This replaces eight
   separate tracked-uppercase eyebrow treatments; a decorative category name
   ("FEATURES", "WHY US") is never an acceptable value here. */
.datastamp {
  display: block;
  font-family: var(--f-mono);
  font-size: 12.5px;
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  margin: 0 0 14px;
}
.datastamp em {
  font-style: normal;
  color: var(--ink-2);
  font-weight: 500;
}

/* .microlabel — the one place uppercase+tracking survives: true UNITS and
   table column heads, at 10–11px, never above a headline. */
.microlabel {
  font-family: var(--f-mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--muted);
}

/* ==========================================================================
   4. LAYOUT — varied measures, so not every section is the same box
   ========================================================================== */
.wrap { width: min(var(--wrap), 100% - 48px); margin-inline: auto; }
.wrap-narrow { width: min(820px, 100% - 48px); margin-inline: auto; }
.wrap-wide { width: min(1320px, 100% - 48px); margin-inline: auto; }
@media (max-width: 640px) {
  .wrap, .wrap-narrow, .wrap-wide { width: calc(100% - 36px); }
}

/* section rhythm: three deliberate steps, not one repeated value */
.section { padding: 96px 0; }
.section-tight { padding: 62px 0; }
.section-roomy { padding: 124px 0; }
@media (max-width: 720px) {
  .section { padding: 58px 0; }
  .section-tight { padding: 42px 0; }
  .section-roomy { padding: 70px 0; }
}

.sec-head { max-width: 640px; margin-bottom: 44px; }
.sec-head .lede { margin-top: 14px; }

/* ==========================================================================
   5. LINKS — hover draws an underline in; it does not move the text
   ========================================================================== */
a { color: var(--ocean-deep); }

.tlink {
  color: var(--ocean-deep);
  font-weight: 500;
  text-decoration: none;
  background-image: linear-gradient(currentColor, currentColor);
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 0% 1.5px;
  transition: background-size 0.25s var(--ease);
  padding-bottom: 1px;
}
.tlink:hover { background-size: 100% 1.5px; }

/* an arrow link: the arrow advances, the label stays put */
.alink {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  color: var(--ocean-deep);
  font-weight: 500;
  text-decoration: none;
}
.alink::after {
  content: "";
  width: 15px; height: 15px;
  flex: none;
  background: currentColor;
  /* inline arrow as a mask so it inherits colour and needs no extra markup */
  -webkit-mask: no-repeat center/100% url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h13m-6-6 6 6-6 6'/%3E%3C/svg%3E");
  mask: no-repeat center/100% url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h13m-6-6 6 6-6 6'/%3E%3C/svg%3E");
  transition: transform 0.22s var(--ease);
}
.alink:hover::after { transform: translateX(4px); }

/* ==========================================================================
   6. BUTTONS — the chunky press idiom is the brand; keep it, and make it the
   ONLY thing buttons do on interaction. A button that lifts on hover and
   presses on click is telling two contradictory physical stories, so hover
   is a colour shift and active is the press.
   ========================================================================== */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  padding: 14px 28px;
  border: 0;
  border-radius: var(--r-btn);
  font-family: var(--f-sans);
  font-weight: 600;
  font-size: 15.5px;
  letter-spacing: -0.006em;
  line-height: 1.2;
  cursor: pointer;
  text-decoration: none;
  text-align: center;
  transition: background-color 0.16s ease, box-shadow 0.12s var(--ease-press),
              transform 0.12s var(--ease-press), border-color 0.16s ease;
}
.btn:focus-visible { outline: 3px solid var(--ocean); outline-offset: 3px; }

.btn-green { background: var(--green); color: #fff; box-shadow: 0 4px 0 var(--green-dark); }
.btn-green:hover { background: var(--green-lit); }
.btn-green:active { transform: translateY(3px); box-shadow: 0 1px 0 var(--green-dark); }

.btn-ocean { background: var(--ocean); color: #fff; box-shadow: 0 4px 0 var(--ocean-dark); }
.btn-ocean:hover { background: var(--ocean-lit); }
.btn-ocean:active { transform: translateY(3px); box-shadow: 0 1px 0 var(--ocean-dark); }

.btn-gold { background: var(--gold); color: #533800; box-shadow: 0 4px 0 var(--gold-dark); }
.btn-gold:hover { background: var(--gold-lit); }
.btn-gold:active { transform: translateY(3px); box-shadow: 0 1px 0 var(--gold-dark); }

.btn-ghost {
  background: var(--paper);
  color: var(--ocean-deep);
  border: 1.5px solid var(--hair);
  box-shadow: 0 3px 0 var(--hair);
}
.btn-ghost:hover { border-color: var(--ocean); box-shadow: 0 3px 0 var(--ocean-tint); }
.btn-ghost:active { transform: translateY(2px); box-shadow: 0 1px 0 var(--hair); }

/* on dark grounds */
.btn-onDark {
  background: rgba(255, 255, 255, 0.08);
  color: #fff;
  border: 1.5px solid rgba(255, 255, 255, 0.26);
  box-shadow: 0 3px 0 rgba(255, 255, 255, 0.14);
}
.btn-onDark:hover { background: rgba(255, 255, 255, 0.14); border-color: rgba(255, 255, 255, 0.5); }
.btn-onDark:active { transform: translateY(2px); box-shadow: 0 1px 0 rgba(255, 255, 255, 0.14); }

.btn-sm { padding: 10px 18px; font-size: 14px; }
.btn-lg { padding: 17px 36px; font-size: 17px; }

/* ==========================================================================
   7. NAV — solid, one continuous colour with the hero. No blur, no shrink-on-
   scroll (that transition is identical on a thousand sites and communicates
   nothing). Below 1120px the links move into a real disclosure panel: the old
   CSS simply display:none'd them, which left phone visitors with NO route to
   Competition prep, Leaderboard, Schools or Why Finlingo at all.
   Toggle behaviour lives in nav-session.js, shared by every page.
   ========================================================================== */
.nav {
  position: sticky;
  top: 0;
  z-index: 60;
  background: var(--abyss);
  border-bottom: 1px solid rgba(255, 255, 255, 0.1);
  /* full-bleed bar: keep it clear of the notch/rounded corners in landscape */
  padding-left: env(safe-area-inset-left);
  padding-right: env(safe-area-inset-right);
}
.nav-inner {
  display: flex;
  align-items: center;
  gap: 28px;
  padding: 13px 0;
}

.brandline {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  flex: none;
  font-family: var(--f-brand);
  font-weight: 800;
  font-size: 25px;
  line-height: 1;
  color: #8ee14f;
  letter-spacing: -0.5px;
  text-decoration: none;
}
.brandline svg { flex: none; }
.brandline:focus-visible { outline: 3px solid #9fd6f2; outline-offset: 4px; border-radius: 8px; }

/* the link group sits directly after the brand and takes the slack, so the
   action group is pinned right without the brittle per-button min-widths the
   old nav needed to stop it reflowing when labels swapped */
.nav-main {
  display: flex;
  align-items: center;
  gap: 22px;
  margin-right: auto;
}
.nav-main a:not(.btn), .nav-drop summary {
  font-size: 14.5px;
  font-weight: 450;
  color: rgba(223, 238, 247, 0.86);
  text-decoration: none;
  white-space: nowrap;
}
.nav-main a:not(.btn) {
  background-image: linear-gradient(#8ee14f, #8ee14f);
  background-repeat: no-repeat;
  background-position: 0 calc(100% + 2px);
  background-size: 0% 2px;
  transition: color 0.15s ease, background-size 0.25s var(--ease);
  padding-bottom: 2px;
}
.nav-main a:not(.btn):hover { color: #fff; background-size: 100% 2px; }
.nav-main a[aria-current="page"] { color: #fff; background-size: 100% 2px; }
.nav a:focus-visible, .nav summary:focus-visible, .nav button:focus-visible {
  outline: 3px solid #9fd6f2;
  outline-offset: 3px;
  border-radius: 6px;
}

.nav-act { display: flex; align-items: center; gap: 12px; flex: none; }
.nav-act .btn { padding: 10px 18px; font-size: 14px; }
.btn-signin {
  background: transparent;
  color: #eaf5fc;
  border: 1.5px solid rgba(255, 255, 255, 0.24);
  box-shadow: 0 3px 0 rgba(255, 255, 255, 0.12);
}
.btn-signin:hover { border-color: rgba(255, 255, 255, 0.55); background: rgba(255, 255, 255, 0.06); }
.btn-signin:active { transform: translateY(2px); box-shadow: 0 1px 0 rgba(255, 255, 255, 0.12); }

/* educators dropdown */
.nav-drop { position: relative; }
.nav-drop summary {
  list-style: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  transition: color 0.15s ease;
}
.nav-drop summary::-webkit-details-marker { display: none; }
.nav-drop summary::after {
  content: "";
  width: 6px; height: 6px;
  margin-top: -3px;
  border-right: 1.8px solid currentColor;
  border-bottom: 1.8px solid currentColor;
  transform: rotate(45deg);
  transition: transform 0.18s var(--ease);
}
.nav-drop[open] summary::after { transform: rotate(-135deg); margin-top: 3px; }
.nav-drop summary:hover { color: #fff; }
.drop-menu {
  position: absolute;
  top: calc(100% + 15px);
  left: 50%;
  transform: translateX(-50%);
  min-width: 272px;
  background: var(--paper);
  border: 1px solid var(--hair);
  border-radius: var(--r-card);
  box-shadow: var(--lift-deep);
  padding: 8px;
  display: grid;
  gap: 2px;
}
/* keeps the pointer inside the details while travelling to the panel */
.drop-menu::before { content: ""; position: absolute; top: -16px; left: 0; right: 0; height: 16px; }
.drop-menu a {
  padding: 10px 12px;
  border-radius: var(--r-input);
  text-decoration: none;
  border-left: 2px solid transparent;
  transition: background-color 0.15s ease, border-color 0.15s ease;
}
.drop-menu a b { display: block; font-family: var(--f-sans); font-weight: 600; font-size: 14px; color: var(--ink); }
.drop-menu a small { display: block; font-size: 12.5px; font-weight: 400; color: var(--muted); margin-top: 2px; line-height: 1.5; }
.drop-menu a:hover { background: var(--paper-2); border-left-color: var(--green); }

/* hamburger — hidden until the links collapse */
.nav-toggle {
  display: none;
  flex: none;
  width: 42px; height: 42px;
  padding: 0;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 1.5px solid rgba(255, 255, 255, 0.24);
  border-radius: var(--r-input);
  cursor: pointer;
  color: #eaf5fc;
}
.nav-toggle:hover { border-color: rgba(255, 255, 255, 0.55); }
.nav-toggle i {
  position: relative;
  display: block;
  width: 17px; height: 1.8px;
  background: currentColor;
  border-radius: 2px;
  transition: transform 0.22s var(--ease), opacity 0.15s linear;
}
.nav-toggle i::before, .nav-toggle i::after {
  content: "";
  position: absolute;
  left: 0;
  width: 17px; height: 1.8px;
  background: currentColor;
  border-radius: 2px;
  transition: transform 0.22s var(--ease);
}
.nav-toggle i::before { top: -6px; }
.nav-toggle i::after { top: 6px; }
.nav-toggle[aria-expanded="true"] i { transform: rotate(45deg); }
.nav-toggle[aria-expanded="true"] i::before { transform: translateY(6px) rotate(-90deg); }
.nav-toggle[aria-expanded="true"] i::after { opacity: 0; }

@media (max-width: 1120px) {
  .nav-inner { gap: 14px; justify-content: space-between; }
  .nav-toggle { display: inline-flex; }
  .nav-act { margin-left: auto; }
  .nav-act .btn-signin { display: none; }   /* sign-in moves into the sheet */

  /* the links become a real panel instead of vanishing */
  .nav-main {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    margin: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: 8px 24px 20px;
    background: var(--abyss);
    border-bottom: 1px solid rgba(255, 255, 255, 0.12);
    box-shadow: 0 24px 40px -18px rgba(0, 0, 0, 0.6);
    max-height: calc(100dvh - 68px);
    overflow-y: auto;
    /* scrolling to the end of the sheet must not start scrolling the page
       behind it */
    overscroll-behavior: contain;
    padding-bottom: max(20px, env(safe-area-inset-bottom));
    display: none;
  }
  .nav-main.is-open { display: flex; }
  .nav-main a:not(.btn) {
    font-size: 16px;
    padding: 14px 2px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.09);
    background-image: none;
  }
  .nav-main a:not(.btn):hover { color: #8ee14f; }
  /* the dropdown flattens into plain rows — a nested disclosure inside a
     disclosure is a needless second tap */
  .nav-drop { border-bottom: 1px solid rgba(255, 255, 255, 0.09); }
  .nav-drop summary { display: none; }
  .drop-menu {
    position: static;
    transform: none;
    min-width: 0;
    background: transparent;
    border: 0;
    box-shadow: none;
    padding: 0;
  }
  .drop-menu::before { display: none; }
  .drop-menu a { padding: 13px 2px; border-left: 0; border-radius: 0; }
  .drop-menu a b { color: rgba(223, 238, 247, 0.9); font-size: 16px; font-weight: 450; }
  .drop-menu a small { color: rgba(223, 238, 247, 0.5); }
  .drop-menu a:hover { background: transparent; }
  .drop-menu a:hover b { color: #8ee14f; }
  .nav-sheet-signin {
    display: block;
    margin-top: 16px;
    font-size: 15px;
    font-weight: 500;
    color: #8ee14f;
    text-decoration: none;
  }
}
@media (min-width: 1121px) {
  .nav-sheet-signin { display: none; }
}

/* ==========================================================================
   8. LEDGER COMPONENTS — the shared data vocabulary.
   These replace three separate icon-card grids. A row of facts is a table,
   so it is built like one: warm paper, hairlines, dotted leaders, mono
   figures, near-square corners.
   ========================================================================== */
.ledger {
  background: var(--ledger);
  border: 1px solid var(--ledger-line);
  border-radius: var(--r-data);
  padding: 4px 20px 8px;
}
.ledger-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
  padding: 15px 2px 12px;
  border-bottom: 1px solid var(--ledger-line);
}
.ledger-head b { font-family: var(--f-sans); font-weight: 600; font-size: 14.5px; color: var(--ink); }
.ledger-rows { list-style: none; margin: 2px 0; padding: 0; }
.ledger-row {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 10px 8px;
  margin: 0 -8px;
  border-radius: var(--r-data);
  border-left: 2px solid transparent;
  transition: background-color 0.15s ease, border-color 0.15s ease;
}
.ledger-row > span:first-child { font-size: 14.5px; color: var(--body); }
.ledger-row .leader {
  flex: 1;
  min-width: 18px;
  border-bottom: 1.5px dotted #ccc4b0;
  transform: translateY(-4px);
}
.ledger-row .fig { font-weight: 500; font-size: 14px; }
/* hover: a left rule appears and the row warms — no lift, no scale */
.ledger-row:hover { background: #fff; border-left-color: var(--green); }

/* a compact stat, used in strips */
.stat { display: block; }
.stat .fig-xl { margin-bottom: 8px; }
.stat p { font-size: 14px; line-height: 1.55; color: var(--muted); }

/* ==========================================================================
   9. CARDS — hairline definition, no ambient shadow (DESIGN.md rule)
   ========================================================================== */
.card {
  background: var(--paper);
  border: 1px solid var(--hair);
  border-radius: var(--r-card);
  padding: 26px;
}
.card-float {                      /* the exception: genuinely floating */
  background: var(--paper);
  border: 1px solid var(--hair);
  border-radius: var(--r-card);
  box-shadow: var(--lift);
}

/* ==========================================================================
   10. FAQ — hairline rows, not eight bordered boxes
   ========================================================================== */
.faq-list { border-top: 1px solid var(--hair); }
.faq-item { border-bottom: 1px solid var(--hair); }
.faq-item summary {
  list-style: none;
  cursor: pointer;
  padding: 20px 4px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  font-family: var(--f-display);
  font-optical-sizing: auto;
  font-variation-settings: "SOFT" 60, "WONK" 1;
  font-weight: 600;
  font-size: 18px;
  letter-spacing: -0.015em;
  color: var(--ink);
  transition: color 0.15s ease;
}
.faq-item summary:hover { color: var(--ocean-deep); }
.faq-item summary::-webkit-details-marker { display: none; }
.faq-item summary::after {
  content: "";
  flex: none;
  width: 9px; height: 9px;
  margin-top: -4px;
  border-right: 2px solid var(--muted);
  border-bottom: 2px solid var(--muted);
  transform: rotate(45deg);
  transition: transform 0.2s var(--ease);
}
.faq-item[open] summary::after { transform: rotate(-135deg); margin-top: 4px; }
.faq-item summary:focus-visible { outline: 3px solid var(--ocean); outline-offset: -3px; border-radius: 6px; }
.faq-item p { padding: 0 4px 22px; max-width: 74ch; }

/* ==========================================================================
   11. FOOTER — two asymmetric halves, not a row of equal link columns
   ========================================================================== */
.footer {
  background: var(--panel);
  color: #bcd8e6;
  padding: 60px 0 30px;
}
.foot-top {
  display: grid;
  grid-template-columns: minmax(260px, 1.1fr) 2fr;
  gap: 56px;
  align-items: start;
}
.foot-brand .brandline { font-size: 23px; }
.foot-brand p { margin-top: 14px; font-size: 14px; line-height: 1.7; color: #9dbdcf; max-width: 32ch; }
.foot-cols { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 36px 44px; }
.foot-col { display: grid; gap: 10px; justify-items: start; align-content: start; }
.foot-col h4 {
  font-family: var(--f-mono);
  font-variation-settings: normal;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #6f9db5;
  margin-bottom: 4px;
}
.foot-col a {
  color: #d3ecf8;
  font-weight: 400;
  font-size: 14.5px;
  text-decoration: none;
  background-image: linear-gradient(#8ee14f, #8ee14f);
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 0% 1.5px;
  transition: color 0.15s ease, background-size 0.24s var(--ease);
  padding-bottom: 1px;
}
.foot-col a:hover { color: #fff; background-size: 100% 1.5px; }
.footer a:focus-visible { outline: 3px solid #9fd6f2; outline-offset: 3px; border-radius: 4px; }
.foot-fine {
  margin-top: 44px;
  padding-top: 20px;
  border-top: 1px solid rgba(255, 255, 255, 0.11);
  font-size: 13px;
  color: #7fa8bd;
  display: flex;
  flex-wrap: wrap;
  gap: 8px 20px;
  justify-content: space-between;
}
@media (max-width: 860px) {
  .foot-top { grid-template-columns: 1fr; gap: 34px; }
}
@media (max-width: 480px) {
  .foot-cols { grid-template-columns: 1fr; gap: 28px; }
}

/* ==========================================================================
   12. A11Y + MOTION
   ========================================================================== */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}
/* skip link — the nav has a lot of items before the content starts */
.skip {
  position: absolute;
  left: 12px; top: 12px;
  z-index: 100;
  /* moved with transform rather than `top` so revealing it never reflows */
  transform: translateY(-200%);
  background: var(--paper);
  color: var(--ink);
  font-weight: 600;
  font-size: 14px;
  padding: 11px 18px;
  border-radius: var(--r-input);
  box-shadow: var(--lift);
  text-decoration: none;
  transition: transform 0.18s var(--ease);
}
.skip:focus { transform: none; }

/* Every interactive element must have a visible focus ring. This is the
   backstop for anything not covered by a component rule above. */
:where(a, button, summary, input, select, textarea):focus-visible {
  outline: 3px solid var(--ocean);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

/* Legacy compatibility: competition-prep.html still drives .reveal through its
   own IntersectionObserver. Defined here so those elements are visible even
   before the observer fires, rather than being stuck at opacity 0 if the
   script fails. Do not add .reveal to new markup. */
.reveal { opacity: 1; transform: none; }

/* ==========================================================================
   13. MIGRATION SHIM
   The secondary pages (leaderboard, privacy, 404, state pages, the three
   dashboards) each carried their own copy of the old token names. Rather than
   rename several thousand usages across ~250KB of page-specific CSS — a large,
   entirely mechanical diff with a lot of room for silent breakage — the old
   names are aliased onto the new system here. Those pages therefore inherit
   the new palette and type automatically, and their own rules keep working.

   These are aliases, NOT a second palette. New CSS must use the real tokens
   from section 1. When a page's bespoke CSS is next touched, migrate its
   usages and the alias can eventually be dropped.
   ========================================================================== */
:root {
  --text: var(--body);
  --text-dim: var(--muted);
  --line: var(--hair);
  --paper-alt: var(--paper-2);
  --canvas: var(--paper-2);
  --water-1: var(--paper-2);
  --water-2: var(--ocean-tint);
  --ink-panel: var(--panel);
  --ink-panel-2: var(--panel-2);
  --font-display: var(--f-display);
  --font-body: var(--f-sans);
  --font-brand: var(--f-brand);
  --radius: var(--r-card);
  --radius-lg: var(--r-card);
  --ease-confident: var(--ease);
  /* the old ambient card shadow resolves to nothing: rest-state cards are
     defined by their hairline border now (DESIGN.md's No Soft Gray Card Rule),
     so every page that referenced it quietly stops floating */
  --shadow-card: none;
  --shadow-float: var(--lift);
  /* map-specific tokens used by the state pages */
  --map-green: var(--green-dark);
  --map-green-deep: var(--green-deep);
  --map-red: var(--red);
  --map-red-deep: #a82b2b;
}
/* Headings on shim pages must still pick up the display face and the axes. */
.s-hero h1, .s-sec h2, .s-cta h2 { font-variation-settings: "SOFT" 60, "WONK" 1; }
