/* ============================================================
   TutorTrack — "The Growth Ledger" marketing + auth design system
   A child's learning, hand-plotted across schoolbook graph paper.
   Scope: index, login, signup-parent, signup-tutor,
          learning-aids, privacy, terms.
   Dashboards keep /css/style.css — do not couple to this file.
   ============================================================ */


:root {
  /* ---- New palette (the real names) ---- */
  --paper: #FAF5EA;        /* warm schoolbook cream — page */
  --paper-2: #F4EDDD;      /* slightly deeper cream — bands */
  --card: #FFFDF8;         /* warm white — sheets/cards */
  --ink: #17332B;          /* deep green fountain-pen ink — text/anchor */
  --ink-soft: #3C544C;     /* softened ink — body copy */
  /* --ink-mute has to clear 4.5 on the WORST surface it lands on, not just on
     the page ground. Muted copy sits on the ruled-paper lines (--rule) and on
     alert tints, where the old value measured 4.05 light / 4.14 dark. These
     values clear 4.5 on rule, tint, paper and card in both themes. */
  --ink-mute: #516059;     /* muted ink — captions */
  --grass: #159A5B;        /* teacher's marking green — PRIMARY */
  --grass-deep: #0E7C47;
  --grass-tint: #E4F3EA;   /* pale green wash */
  --gold: #F3B72B;         /* gold star / checkpoints */
  --gold-deep: #926300;    /* gold text on gold-tint (badges/alerts) */
  --gold-soft: #E8A33D;    /* warm amber — review stars */
  --gold-tint: #FBEFCB;
  --pen: #2E63E0;          /* pen-blue — links / one subject family */
  --pen-deep: #244fc0;     /* pen text on pen-tint / btn-teal hover */
  --pen-tint: #E4EBFB;
  --coral: #E5533A;        /* red marking pen — used sparingly */
  --coral-deep: #b23a24;   /* darker coral — badge-red text */
  --coral-tint: #FBE5DF;
  --danger: #b3261e;       /* destructive action text */
  --danger-tint: #fdecea;  /* destructive action bg */
  --danger-border: #f3c0ba;/* destructive action border */
  --surface-cool: #f8fafc; /* cool near-white — table headers / consent boxes */
  --rule: #E6DFCE;         /* solid warm rule / border */
  /* Two roles the old --rule was carrying at once. --rule stays decorative
     (dividers, card edges, ~1.3:1, which is fine for those). --rule-strong is
     for borders that CARRY MEANING — the outline of an input, a select, a
     textarea — which WCAG 1.4.11 holds to 3:1. Measured on the cream card:
     --rule 1.31:1 (fail), --rule-strong 3.74:1 (pass).
     --focus-ring is its own token rather than borrowing --gold: gold on cream
     measured 1.66:1, so keyboard focus was effectively invisible in light mode
     while scoring 10.87:1 in dark. Gold stays in dark, deepened for light. */
  --rule-strong: #8E8264;  /* essential control borders — 3.74:1 on paper */
  --focus-ring: #A87400;   /* deepened gold — 3.74:1 paper, 4.00:1 card */
  --rule-soft: rgba(23,51,43,.10);
  --grid: rgba(23,51,43,.045); /* faint graph-paper line */

  /* ---- Role tokens: surfaces that must NOT invert with the palette ----
     The dark theme flips token *values*, which is right for anything whose
     role is "page" or "text". These three are the exceptions, and every one
     of them was a dark-mode contrast bug before it was a token:
     --nav-bg   the translucent ground behind the sticky nav. Was a raw
                rgba() literal of the cream, so it stayed cream in dark while
                the text on it went light — the header vanished.
     --slab     an inverted band (footer, .dark-section, video frame). It was
                painted with --ink, a TEXT token, which flips to cream in dark
                and turned the footer into a cream slab with cream text.
                A slab is dark in BOTH themes, so it needs its own token.
     --on-accent  text on a filled accent (--grass/--pen). White is only
                correct while the accent is dark; in dark mode the accents
                lighten, so this flips to near-black instead. */
  --nav-bg: rgba(250,245,234,.86);
  --slab: #17332B; --on-slab: #FAF5EA; --on-slab-mute: rgba(250,245,234,.72);
  --on-accent: #FFFFFF; --on-accent-soft: rgba(255,255,255,.6);
  /* The filled primary action needs its own token, because the brand green and
     the button fill have different jobs. White on --grass measures 3.62:1 —
     under the 4.5 a button LABEL owes — so every primary button in light mode
     was failing. --grass-deep takes white to 5.26:1 and is already in the
     palette. Light only: in dark the accent lightens and --on-accent flips to
     near-black, which already passes, so dark keeps --grass exactly as designed. */
  --action-primary: #0E7C47; --action-primary-hover: #0A5F38;
  --on-accent-mute: rgba(255,255,255,.88); /* secondary copy on an accent fill */
  /* Text on FIXED artwork (the subject-chip gradients are brand literals in
     both themes). Deliberately NOT redefined in the dark blocks — that is the
     whole point of it: --ink here put cream on a gold chip. */
  --on-bright: #17332B;

  /* ---- Compat aliases (baked into page inline styles / JS) ---- */
  --space-navy: var(--ink);
  --space-navy-light: #24463C;
  --starlight-white: var(--paper);
  --orbit-orange: var(--grass);        /* primary accent */
  --orbit-orange-hover: var(--grass-deep);
  --nebula-purple: var(--pen);
  --comet-teal: var(--pen);
  --star: var(--gold);
  --success: var(--grass);
  --moon-gray: var(--rule);
  --border-med: #D8CFB9;
  --text-main: var(--ink);
  --text-muted: var(--ink-mute);
  --text-soft: var(--ink-soft);
  --white: var(--card);
  --dash-bg: var(--paper);
  --auth-bg: var(--paper);
  /* Aliases for tokens that JS-built markup references with a light literal
     fallback — `var(--surface-2, #F4F6F9)` and friends. None of these were ever
     DEFINED, so the fallback won a permanent light colour in BOTH themes: the
     tutor dashboard's "waiting on you" panel stayed #F4F6F9 while its text went
     cream. Defining them as aliases makes every existing call site theme-aware
     without touching the JS. */
  --surface-2: var(--paper-2);
  --border: var(--rule);
  --hairline: var(--rule);
  --crit: var(--danger);
  --space-teal: #178E86;

  /* ---- Type ---- */
  --font-heading: 'Bricolage Grotesque', system-ui, sans-serif;
  --font-body: 'Hanken Grotesk', system-ui, sans-serif;
  --font-hand: 'Caveat', 'Hanken Grotesk', cursive;
  --font-mono: 'Space Mono', ui-monospace, monospace;

  /* ---- Spacing / radius / shadow ---- */
  --space-1: .25rem; --space-2: .5rem; --space-3: .75rem; --space-4: 1rem;
  --space-6: 1.5rem; --space-8: 2rem; --space-10: 2.75rem; --space-12: 3rem;
  --space-16: 4rem; --space-24: 6rem;
  --radius-sm: .5rem; --radius-md: .85rem; --radius-lg: 1.15rem; --radius-pill: 9999px;
  --shadow-sm: 0 1px 2px rgba(23,51,43,.06);
  --shadow-md: 0 10px 30px -14px rgba(23,51,43,.28);
  --shadow-lg: 0 26px 60px -22px rgba(23,51,43,.36);
  --shadow-glow: 0 12px 26px -10px rgba(21,154,91,.55);

  /* Motion. Durations and easings were written inline per rule (30 uses of a
     bare `ease`, plus .18s/.2s/.22s/.25s all meaning "a quick UI transition"),
     so nothing could be tuned centrally or slowed down consistently. */
  --dur-fast: .15s;    /* hover / focus feedback */
  --dur-base: .2s;     /* the default UI transition */
  --dur-slow: .45s;    /* larger moves — panels, reveals */
  --ease-out: cubic-bezier(.2, .8, .3, 1);   /* enters: quick then settle */
  --ease-in-out: cubic-bezier(.4, 0, .2, 1); /* moves that start and end on screen */

  /* Book surfaces, so the ledger illustration does not invert in dark mode. */
  --book-cover: #17332B; --book-page: #FAF5EA; --book-edge: #F4EDDD;
}

/* Dark theme. Two selectors deliberately:
   - the media query covers "system dark, no explicit choice", and is scoped
     with :not([data-theme="light"]) so an explicit LIGHT choice still wins
     on a dark OS;
   - [data-theme="dark"] covers an explicit dark choice on a light OS.
   Only the tokens are redefined — every component styles through them, so
   nothing else in either stylesheet needs a dark variant. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    /* Dark: the ledger by lamplight. The ground is derived from the brand's own
       deep ink-green rather than a neutral black, so it reads as the same book
       rather than a generic dark mode. The `-deep` tokens are a ROLE — readable
       accent text on a tint — so in dark they become light rather than dark. */
    --paper: #101F1A; --paper-2: #16281F; --card: #1A3128;
    --ink: #EDE7D8; --ink-soft: #C6D3CB; --ink-mute: #AFC0B7;
    --rule: #2E4C3F; --rule-soft: rgba(237,231,216,.12); --grid: rgba(237,231,216,.05);
    --rule-strong: #5C8875; --focus-ring: #F7C948;
    --action-primary: #3CCB85; --action-primary-hover: #7FE0AE;
    --grass: #3CCB85; --grass-deep: #7FE0AE; --grass-tint: #16362A;
    --gold: #F7C948; --gold-deep: #F3C765; --gold-soft: #E8A33D; --gold-tint: #3A2E14;
    --pen: #7BA5FF; --pen-deep: #A8C3FF; --pen-tint: #1B2A46;
    --coral: #FF8168; --coral-deep: #FFAA96; --coral-tint: #3D211B;
    --danger: #FF9E8C; --danger-tint: #3B1D18; --danger-border: #6B3228;
    --surface-cool: #16242B; --border-med: #3A5A4C;
  --nav-bg: rgba(16,31,26,.86);
  --slab: #0A1713; --on-slab: #EDE7D8; --on-slab-mute: rgba(237,231,216,.72);
  --on-accent: #06120D; --on-accent-soft: rgba(6,18,13,.55);
  --space-teal: #5FD3C6;
  --on-accent-mute: rgba(6,18,13,.78);
  /* Compat aliases that carry a literal colour rather than pointing at a token:
     without a dark value the sidebar, inputs and ghost buttons stayed white on
     a dark ground. Caught by rendering the dashboard, not by reading the CSS. */
  --white: #1A3128; --space-navy-light: #24463C; --starlight-white: #101F1A;
    /* The book keeps a dark cover and lighter pages in BOTH themes. Without its
       own tokens it would invert — --ink is light in dark mode, so the hardback
       cover would turn cream and the pages would go dark. */
    --book-cover: #0A1713; --book-page: #1F3A2E; --book-edge: #2E4C3F;
  }
}
:root[data-theme="dark"] {
  /* Dark: the ledger by lamplight. The ground is derived from the brand's own
     deep ink-green rather than a neutral black, so it reads as the same book
     rather than a generic dark mode. The `-deep` tokens are a ROLE — readable
     accent text on a tint — so in dark they become light rather than dark. */
  --paper: #101F1A; --paper-2: #16281F; --card: #1A3128;
  --ink: #EDE7D8; --ink-soft: #C6D3CB; --ink-mute: #AFC0B7;
  --rule: #2E4C3F; --rule-soft: rgba(237,231,216,.12); --grid: rgba(237,231,216,.05);
  --rule-strong: #5C8875; --focus-ring: #F7C948;
  --action-primary: #3CCB85; --action-primary-hover: #7FE0AE;
  --grass: #3CCB85; --grass-deep: #7FE0AE; --grass-tint: #16362A;
  --gold: #F7C948; --gold-deep: #F3C765; --gold-soft: #E8A33D; --gold-tint: #3A2E14;
  --pen: #7BA5FF; --pen-deep: #A8C3FF; --pen-tint: #1B2A46;
  --coral: #FF8168; --coral-deep: #FFAA96; --coral-tint: #3D211B;
  --danger: #FF9E8C; --danger-tint: #3B1D18; --danger-border: #6B3228;
  --surface-cool: #16242B; --border-med: #3A5A4C;
  --nav-bg: rgba(16,31,26,.86);
  --slab: #0A1713; --on-slab: #EDE7D8; --on-slab-mute: rgba(237,231,216,.72);
  --on-accent: #06120D; --on-accent-soft: rgba(6,18,13,.55);
  --space-teal: #5FD3C6;
  --on-accent-mute: rgba(6,18,13,.78);
  /* Compat aliases that carry a literal colour rather than pointing at a token:
     without a dark value the sidebar, inputs and ghost buttons stayed white on
     a dark ground. Caught by rendering the dashboard, not by reading the CSS. */
  --white: #1A3128; --space-navy-light: #24463C; --starlight-white: #101F1A;
  /* The book keeps a dark cover and lighter pages in BOTH themes. Without its
     own tokens it would invert — --ink is light in dark mode, so the hardback
     cover would turn cream and the pages would go dark. */
  --book-cover: #0A1713; --book-page: #1F3A2E; --book-edge: #2E4C3F;
}

* { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: smooth; }
body {
  overflow-x: clip;
  font-family: var(--font-body); color: var(--ink); line-height: 1.65;
  /* Hallmark redesign (atmosphere): the full-page graph-paper grid was the
     generic tell — dropped for a clean warm-paper ground so the dashboard
     carries the page. The schoolbook reference now lives in one place: the
     coral margin rule beside the hero copy (see .hero .lead-col). */
  background-color: var(--paper);
  -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility;
}
/* Hero atmosphere: clean paper + one ownable device — a coral exercise-book
   margin rule beside the copy, and a hairline baseline to ground the hero now
   that the ambient grid is gone. */
.hero { border-bottom: 1px solid var(--rule); }
.hero .lead-col { position: relative; padding-left: var(--space-6); }
.hero .lead-col::before {
  content: ""; position: absolute; left: 0; top: 6px; bottom: 6px; width: 3px;
  border-radius: 3px; background: var(--coral);
}
/* The headline is written on the sheet: faint rules pitched to the h1's own
   line-height (1.08em) so each line self-registers onto a rule at any size. */
.hero h1 {
  padding-bottom: .12em;
  background-image: repeating-linear-gradient(to bottom,
    transparent 0, transparent calc(1.08em - 1.5px),
    var(--rule) calc(1.08em - 1.5px), var(--rule) 1.08em);
}
@media (max-width: 940px){ .hero .lead-col { padding-left: var(--space-4); } }

h1,h2,h3,h4 { font-family: var(--font-heading); line-height: 1.08; color: var(--ink); font-weight: 700; letter-spacing: -.015em; }
h1 { font-size: clamp(2.6rem, 5.4vw, 4.4rem); font-weight: 800; }
h2 { font-size: clamp(2rem, 3.8vw, 3rem); }
h3 { font-size: clamp(1.3rem, 2.4vw, 1.75rem); }
a { color: inherit; text-decoration: none; }
img { max-width: 100%; display: block; }
svg { width: 1em; height: 1em; vertical-align: -0.125em; }
::selection { background: var(--gold); color: var(--ink); }

/* Wide layout: the page uses far more of a large screen rather than sitting
   in a 1180px column. Safe for readability because the text blocks carry their
   own measure caps (.hero p.lead 33rem, .sec-head 640px), so paragraphs do not
   stretch with the container — only the layout does. */
.container { max-width: 1520px; margin: 0 auto; padding: 0 var(--space-6); }
@media (min-width: 1280px) { .container { padding: 0 var(--space-12); } }
.section { padding: var(--space-24) 0; position: relative; }
.center { text-align: center; }
.muted { color: var(--ink-mute); }
.eyebrow {
  display: inline-flex; align-items: center; gap: .5rem;
  font-family: var(--font-mono); text-transform: uppercase; letter-spacing: .12em;
  font-size: .72rem; font-weight: 700; color: var(--grass-deep);
}
.eyebrow::before { content: ""; width: 1.6rem; height: 2px; background: var(--grass); border-radius: 2px; }
.mt-2{margin-top:var(--space-2)} .mt-4{margin-top:var(--space-4)} .mt-6{margin-top:var(--space-6)}
.mt-8{margin-top:var(--space-8)} .mt-10{margin-top:var(--space-10)}
.grid { display: grid; gap: var(--space-6); }
.flex { display: flex; } .items-center{align-items:center} .justify-between{justify-content:space-between}
.gap-2{gap:var(--space-2)} .gap-4{gap:var(--space-4)} .wrap{flex-wrap:wrap}
.hidden { display: none !important; }

/* ---- Buttons ---- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2);
  font-family: var(--font-heading); font-weight: 700; border-radius: var(--radius-md);
  padding: .82rem 1.5rem; cursor: pointer; border: 2px solid transparent; font-size: .98rem;
  letter-spacing: -.01em; line-height: 1;
  transition: transform var(--dur-fast) var(--ease-out), box-shadow .18s ease, background-color .18s ease, border-color .18s ease, color .18s ease;
}
.btn:focus-visible { outline: 3px solid var(--focus-ring); outline-offset: 2px; }
.btn-primary { background: var(--action-primary); color: var(--on-accent); box-shadow: var(--shadow-glow); }
.btn-primary:hover { transform: translateY(-2px); background: var(--action-primary-hover); }
.btn-secondary { background: var(--card); color: var(--ink); border-color: var(--rule); }
.btn-secondary:hover { transform: translateY(-2px); border-color: var(--ink); }
.btn-ghost { background: transparent; color: var(--ink); border-color: var(--rule); }
.btn-ghost:hover { border-color: var(--grass); color: var(--grass-deep); transform: translateY(-2px); }
.btn-teal { background: var(--pen); color: var(--on-accent); box-shadow: 0 12px 26px -12px rgba(46,99,224,.6); }
.btn-teal:hover { transform: translateY(-2px); background: var(--pen-deep); }
.btn-sm { padding: .55rem 1rem; font-size: .85rem; border-radius: var(--radius-sm); }
.btn-block { width: 100%; }
.btn:disabled { opacity: .55; cursor: not-allowed; transform: none; box-shadow: none; }

/* ---- Cards / sheets ---- */
.card {
  background: var(--card); border-radius: var(--radius-lg); padding: var(--space-8);
  box-shadow: var(--shadow-md); border: 1px solid var(--rule);
  transition: transform .22s ease, box-shadow .22s ease, border-color .22s ease;
}
.card-hover:hover { transform: translateY(-4px); box-shadow: var(--shadow-lg); border-color: var(--grass); }
.panel {
  background: var(--card); border-radius: var(--radius-lg); border: 1px solid var(--rule);
  box-shadow: var(--shadow-sm); padding: var(--space-6); margin-bottom: var(--space-6);
}
.panel h3 { margin-bottom: var(--space-4); }
/* margin-ruled sheet — the exercise-book red margin line */
.sheet { position: relative; }
.sheet::before {
  content: ""; position: absolute; top: 0; bottom: 0; left: 26px; width: 2px;
  background: var(--coral); opacity: .35;
}

/* ---- Inputs ---- */
/* .field-label is the same thing visually, for captions that are NOT labels:
   the heading over a radio/checkbox GROUP (a <label> may only point at one
   control), and captions over non-labelable elements like <video>. Using a
   real <label> there promises an association the browser cannot make. */
label, .field-label { display: block; font-weight: 600; font-size: .88rem; margin-bottom: var(--space-2); color: var(--ink); }
.input-field, select.input-field, textarea.input-field {
  width: 100%; padding: .78rem 1rem; border: 1.5px solid var(--rule-strong); border-radius: var(--radius-sm);
  font-family: var(--font-body); font-size: 1rem; color: var(--ink); background: var(--card);
  transition: border-color .18s, box-shadow .18s; font-weight: 500;
}
.input-field:focus { outline: none; border-color: var(--grass); box-shadow: 0 0 0 3px var(--grass-tint); }

/* A file input's picker button is drawn by the browser and ignores the page
   entirely, so on the dark theme it rendered as a light control sitting on a
   dark card. Styling ::file-selector-button puts it back in the design. The
   text beside it ("No file chosen") is also browser-drawn, hence the explicit
   colour on the input itself. */
.input-field[type="file"] { padding: .5rem .6rem; color: var(--ink); cursor: pointer; }
.input-field[type="file"]::file-selector-button {
  appearance: none; border: 1px solid var(--rule-strong); background: var(--paper-2);
  color: var(--ink); font-family: var(--font-heading); font-weight: 700; font-size: .85rem;
  padding: .45rem .85rem; margin-right: var(--space-3); border-radius: var(--radius-sm);
  cursor: pointer; transition: background-color .18s, border-color .18s;
}
.input-field[type="file"]::file-selector-button:hover { border-color: var(--grass); background: var(--card); }
.field { margin-bottom: var(--space-4); }
.field-help { font-size: .78rem; color: var(--ink-mute); margin-top: var(--space-2); }
.row-2 { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-4); }
@media (max-width: 560px){ .row-2 { grid-template-columns: 1fr; } }

/* Password field with a show/hide toggle (login / reset). The toggle sits
   inside the field; pad the input so typed text never runs under it. */
.pw-wrap { position: relative; }
.pw-wrap .input-field { padding-right: 2.75rem; }
.pw-toggle {
  position: absolute; top: 0; right: 0; height: 100%; width: 2.75rem;
  display: grid; place-items: center; background: transparent; border: none;
  color: var(--ink-mute); cursor: pointer; border-radius: var(--radius-sm);
}
.pw-toggle:hover { color: var(--ink); }
.pw-toggle:focus-visible { outline: 3px solid var(--focus-ring); outline-offset: 2px; }
.pw-toggle svg { width: 1.15rem; height: 1.15rem; }

/* Accessibility skip-link: off-screen until keyboard-focused, then revealed. */
.skip-link {
  position: absolute; left: var(--space-4); top: -3rem; z-index: 100;
  background: var(--ink); color: var(--card); padding: .6rem 1rem;
  border-radius: var(--radius-sm); font-weight: 700; transition: top .15s ease;
}
.skip-link:focus { top: var(--space-4); }

/* ---- Badges ---- */
.badge {
  display: inline-flex; align-items: center; gap: 6px; padding: 5px 12px; border-radius: var(--radius-pill);
  font-size: .78rem; font-weight: 700; font-family: var(--font-mono); letter-spacing: .02em;
  background: var(--grass-tint); color: var(--grass-deep);
}
.badge-orange { background: var(--gold-tint); color: var(--gold-deep); }
.badge-teal { background: var(--pen-tint); color: var(--pen-deep); }
.badge-purple { background: var(--pen-tint); color: var(--pen-deep); }
.badge-green { background: var(--grass-tint); color: var(--grass-deep); }
.badge-amber { background: var(--gold-tint); color: var(--gold-deep); }
.badge-red { background: var(--coral-tint); color: var(--coral-deep); }

/* ---- Nav ---- */
.nav { position: sticky; top: 0; z-index: 50; background: var(--nav-bg); backdrop-filter: blur(12px); border-bottom: 1px solid var(--rule); }
.nav .container { display: flex; align-items: center; justify-content: space-between; height: 72px; }
.brand { font-family: var(--font-heading); font-weight: 800; font-size: 1.4rem; color: var(--ink); display: inline-flex; align-items: center; gap: 9px; letter-spacing: -.02em; }
.brand::before {
  /* the tracked-ascent mark: a rising tick */
  content: ""; width: 20px; height: 20px; flex: none;
  background: var(--grass);
  -webkit-mask: no-repeat center/contain url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='3 17 9 11 13 15 21 5'/%3E%3Cpolyline points='15 5 21 5 21 11'/%3E%3C/svg%3E");
          mask: no-repeat center/contain url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='3 17 9 11 13 15 21 5'/%3E%3Cpolyline points='15 5 21 5 21 11'/%3E%3C/svg%3E");
}
.brand span { color: var(--grass-deep); }
.nav-links { display: flex; gap: var(--space-6); align-items: center; }
/* :not(.btn) matters more than it looks. `.nav-links a` (0,1,1) outranks
   `.btn-primary`/`.btn-ghost` (0,1,0), so without it EVERY button in the nav
   was painted --ink-soft instead of its own text colour — legible on the cream
   nav in light, but 1.07:1 once the dark theme lightened the fills. */
.nav-links a:not(.btn) { color: var(--ink-soft); font-weight: 600; font-size: .93rem; transition: color .18s; }
.nav-links a:not(.btn):hover { color: var(--grass-deep); }
@media (max-width: 900px){ .nav-links .hide-sm { display: none; } }
.nav-toggle { display: none; background: none; border: none; font-size: 1.4rem; line-height: 1; cursor: pointer; color: var(--ink); padding: 8px 10px; border-radius: var(--radius-sm); }
.nav-toggle:hover { background: var(--paper-2); }
.mobile-menu { display: none; flex-direction: column; padding: var(--space-2) var(--space-6) var(--space-4); background: var(--paper); border-bottom: 1px solid var(--rule); }
.mobile-menu a { padding: 15px 4px; color: var(--ink); font-weight: 600; border-bottom: 1px solid var(--rule); }
.mobile-menu a:last-child { border-bottom: none; }
.mobile-menu.open { display: flex; }
@media (max-width: 900px){ .nav-toggle { display: inline-flex; align-items: center; } }
@media (min-width: 901px){ .mobile-menu { display: none !important; } }
@media (pointer: coarse){
  .btn-sm { padding: .7rem 1.1rem; }
  .nav-links a.btn { min-height: 42px; }
  .mobile-menu a { padding: 17px 4px; }
}

/* ============================================================
   HERO — the progress ledger
   ============================================================ */
.hero { position: relative; overflow: hidden; padding: var(--space-16) 0 var(--space-24); }
.hero .container { position: relative; z-index: 2; display: grid; grid-template-columns: 1.02fr .98fr; gap: var(--space-16); align-items: center; }
.hero h1 { margin-top: 14px; }
.hero h1 .mark-climb { color: var(--grass-deep); position: relative; white-space: nowrap; }
.hero h1 .mark-climb::after {
  /* hand-underline the key word */
  content: ""; position: absolute; left: -2%; right: -2%; bottom: .04em; height: .32em;
  background: no-repeat center/100% 100% url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 20' preserveAspectRatio='none'%3E%3Cpath d='M2 14 C40 6 80 6 120 11 S180 14 198 8' fill='none' stroke='%23F3B72B' stroke-width='5' stroke-linecap='round'/%3E%3C/svg%3E");
  z-index: -1;
}
.hero p.lead { font-size: 1.18rem; color: var(--ink-soft); max-width: 33rem; margin-top: var(--space-6); }
.hero p.lead strong { color: var(--ink); font-weight: 700; }
.hero-cta { display: flex; gap: var(--space-3); flex-wrap: wrap; margin-top: var(--space-8); }
.hero-trust { display: flex; gap: var(--space-4); margin-top: var(--space-8); flex-wrap: wrap; color: var(--ink-mute); font-size: .86rem; font-weight: 600; }
.hero-trust span { display: inline-flex; align-items: center; gap: 7px; }
.hero-trust span::before { content: ""; width: 16px; height: 16px; flex: none; background: var(--grass); -webkit-mask: no-repeat center/contain url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E"); mask: no-repeat center/contain url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E"); }

/* the report-card sheet */
.ledger {
  position: relative; background: var(--card); border-radius: 14px;
  border: 1px solid var(--rule); box-shadow: var(--shadow-lg);
  padding: 22px 22px 18px; transform: rotate(-1.6deg);
  background-image:
    linear-gradient(var(--grid) 1px, transparent 1px),
    linear-gradient(90deg, var(--grid) 1px, transparent 1px);
  background-size: 22px 22px;
}
.ledger::before { /* pin */
  content: ""; position: absolute; top: -9px; left: 50%; width: 16px; height: 16px; transform: translateX(-50%);
  border-radius: 50%; background: radial-gradient(circle at 35% 30%, #ff8a72, var(--coral)); box-shadow: 0 3px 6px rgba(23,51,43,.35);
}
.ledger-head { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 2px; }
.ledger-head .who { font-family: var(--font-heading); font-weight: 800; font-size: 1.05rem; color: var(--ink); }
.ledger-head .term { font-family: var(--font-mono); font-size: .68rem; color: var(--ink-mute); text-transform: uppercase; letter-spacing: .1em; }
.ledger-note { font-family: var(--font-hand); font-size: 1.35rem; color: var(--coral-deep); line-height: 1.05; transform: rotate(-4deg); position: absolute; left: 24px; top: 92px; max-width: 9.5rem; text-align: left; pointer-events: none; }
.ledger svg.chart { width: 100%; height: auto; display: block; margin-top: 6px; }
.ledger-rows { margin-top: 10px; border-top: 1px dashed var(--rule); padding-top: 10px; display: grid; gap: 7px; }
.lrow { display: flex; align-items: center; gap: 9px; font-size: .84rem; }
.lrow .tick { width: 18px; height: 18px; border-radius: 5px; background: var(--grass-tint); color: var(--grass-deep); display: grid; place-items: center; flex: none; }
.lrow .tick svg { width: 12px; height: 12px; }
.lrow .subj { font-weight: 600; color: var(--ink); }
.lrow .score { margin-left: auto; font-family: var(--font-mono); font-weight: 700; color: var(--ink); font-size: .82rem; }
.lrow .score b { color: var(--grass-deep); }

/* Open ledger book: the dashboard rests on it like the current page of the
   book. The book fills the stage; padding reveals its margins (gold star +
   hand-note at the top, page-stack at the bottom). Hand-built SVG, brand tokens. */
.book-stage { position: relative; padding: 88px 18px 42px 44px; }
.book-art { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 0; filter: drop-shadow(0 26px 40px rgba(23,51,43,.24)); }
.book-stage > .proof { position: relative; z-index: 2; }
@media (max-width: 940px){ .book-stage { max-width: 540px; margin: 0 auto; } }
@media (max-width: 520px){ .book-stage { padding: 66px 10px 32px 30px; } }
/* The book illustration keeps an asymmetric inset so the drawn spine sits
   inside it. At phone widths that inset was the last thing holding
   become-a-tutor over the viewport: 286px against a 265px client width.
   Measured 286 -> 266 from this rule alone. */
@media (max-width: 400px){ .book-stage { padding-left: 14px; padding-right: 6px; } }

/* Proof dashboard — the hero signature (Option B): a crisp, upright product
   panel, not the rotated schoolbook card. */
.proof {
  position: relative; background: var(--card); border-radius: 16px;
  border: 1px solid var(--rule); box-shadow: var(--shadow-lg); padding: 18px 18px 16px;
}
.proof::before { /* pin — same tactile detail as the ledger card */
  content: ""; position: absolute; top: -9px; left: 50%; width: 16px; height: 16px; transform: translateX(-50%);
  border-radius: 50%; background: radial-gradient(circle at 35% 30%, #ff8a72, var(--coral)); box-shadow: 0 3px 6px rgba(23,51,43,.35);
}
.proof-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; }
.proof-head .who { font-family: var(--font-heading); font-weight: 800; font-size: 1.05rem; color: var(--ink); }
.proof-live { font-family: var(--font-mono); font-size: .64rem; font-weight: 700; letter-spacing: .09em; text-transform: uppercase; color: var(--coral-deep); display: inline-flex; align-items: center; gap: 6px; }
.proof-live::before { content: ""; width: 8px; height: 8px; border-radius: 50%; background: var(--coral); }
.proof-tiles { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin-bottom: 12px; }
.proof-tile { background: var(--paper-2); border-radius: 10px; padding: 10px 11px; }
.proof-tile .n { font-family: var(--font-heading); font-weight: 800; font-size: 1.3rem; line-height: 1; color: var(--ink); font-variant-numeric: tabular-nums; }
.proof-tile .n small { font-size: .62rem; font-weight: 700; color: var(--ink-mute); }
.proof-tile .l { font-family: var(--font-mono); font-size: .56rem; text-transform: uppercase; letter-spacing: .06em; color: var(--ink-mute); margin-top: 5px; }
.proof-chart { background: var(--grass-tint); border-radius: 12px; padding: 11px 12px 7px; }
.proof-chart .cap { display: flex; justify-content: space-between; font-family: var(--font-mono); font-size: .58rem; text-transform: uppercase; letter-spacing: .06em; color: var(--grass-deep); margin-bottom: 4px; }
.proof-chart svg { width: 100%; height: auto; display: block; }
.proof-rows { margin-top: 12px; border-top: 1px dashed var(--rule); padding-top: 10px; display: grid; gap: 7px; }

/* "What you see" widgets — each card previews the real dashboard data, echoing
   the hero's proof panel. */
.wcard { text-align: left; }
.wcard .wgt { background: var(--paper-2); border: 1px solid var(--rule); border-radius: 12px; padding: 12px 13px; margin-bottom: var(--space-4); min-height: 90px; display: flex; flex-direction: column; justify-content: center; gap: 9px; }
.wgt-top { display: flex; align-items: baseline; gap: 8px; }
.wgt-stat { font-family: var(--font-heading); font-weight: 800; font-size: 1.55rem; line-height: 1; color: var(--ink); font-variant-numeric: tabular-nums; }
.wgt-sub { font-family: var(--font-mono); font-size: .62rem; text-transform: uppercase; letter-spacing: .05em; color: var(--ink-mute); }
.att-days { display: flex; gap: 6px; }
.att-days .ad { flex: 1; text-align: center; font-family: var(--font-mono); font-size: .6rem; font-weight: 700; padding: 5px 0; border-radius: 6px; background: var(--grass-tint); color: var(--grass-deep); }
.wspark { width: 100%; height: 40px; display: block; }
.wgt-list { gap: 7px; }
.hwrow { display: flex; align-items: center; justify-content: space-between; gap: 8px; font-size: .8rem; font-weight: 600; color: var(--ink); }
.hwn { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pill { font-family: var(--font-mono); font-size: .56rem; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; padding: 3px 8px; border-radius: 999px; flex: none; }
.pill.pdone { background: var(--grass-tint); color: var(--grass-deep); }
.pill.psub { background: var(--pen-tint); color: var(--pen-deep); }
.pill.pset { background: var(--gold-tint); color: var(--gold-deep); }
.wgt-live { padding: 0; border: none; background: transparent; }
.lframe { position: relative; background: var(--slab); border-radius: 12px; min-height: 90px; display: grid; place-items: center; overflow: hidden; }
.lframe .proof-live { position: absolute; top: 9px; left: 10px; color: var(--on-slab); }
.lframe .lnow { position: absolute; bottom: 8px; left: 10px; font-family: var(--font-mono); font-size: .6rem; color: var(--on-slab); opacity: .85; }
.lframe .lplay { color: var(--on-slab); opacity: .9; display: grid; place-items: center; }
.lframe .lplay svg { width: 30px; height: 30px; }

/* Security status panels — the same widget shell read as a system status. */
.swgt { gap: 10px; justify-content: flex-start; }
.sstatus { align-self: flex-start; font-family: var(--font-mono); font-size: .6rem; font-weight: 700; text-transform: uppercase; letter-spacing: .08em; color: var(--grass-deep); background: var(--grass-tint); padding: 4px 10px; border-radius: 999px; display: inline-flex; align-items: center; gap: 7px; }
.sstatus .sdot { width: 8px; height: 8px; border-radius: 50%; background: var(--grass); flex: none; }
.swgt .srows { display: grid; gap: 6px; width: 100%; }
.swgt .lrow { font-size: .8rem; align-items: center; }

@media (max-width: 940px){
  .hero .container { grid-template-columns: 1fr; gap: var(--space-12); }
  .ledger { max-width: 460px; margin: 0 auto; }
}

/* ---- Section headers ---- */
.sec-head { max-width: 640px; }
.sec-head.center { margin-left: auto; margin-right: auto; }

/* ============================================================
   FEATURE CARDS (bento) — field notes
   ============================================================ */
.bento { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px,1fr)); gap: var(--space-6); }
.feature-icon { width: 50px; height: 50px; border-radius: 12px; display: grid; place-items: center; background: var(--grass-tint); color: var(--grass-deep); margin-bottom: var(--space-4); }
.feature-icon svg { width: 26px; height: 26px; }
.bento .card:nth-child(2) .feature-icon { background: var(--pen-tint); color: var(--pen-deep); }
.bento .card:nth-child(3) .feature-icon { background: var(--gold-tint); color: var(--gold-deep); }
.bento .card:nth-child(4) .feature-icon { background: var(--coral-tint); color: var(--coral-deep); }
.card h3 { font-size: 1.2rem; }

/* ---- Steps (real sequence: buy → split → schedule → track) ---- */
.steps { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px,1fr)); gap: var(--space-6); counter-reset: step; }
.step-card { position: relative; background: var(--card); border: 1px solid var(--rule); border-radius: var(--radius-lg); padding: var(--space-6); box-shadow: var(--shadow-sm); }
.step-card .step-n { font-family: var(--font-mono); font-weight: 700; font-size: .8rem; color: var(--grass-deep); background: var(--grass-tint); width: 34px; height: 34px; border-radius: 50%; display: grid; place-items: center; margin-bottom: var(--space-4); }
.step-card h3 { font-size: 1.12rem; }

/* ============================================================
   SUBJECTS — book spines
   ============================================================ */
.subjects-row { display: flex; gap: var(--space-4); flex-wrap: wrap; }
.subject-chip {
  flex: 1; min-width: 180px; padding: var(--space-6); border-radius: var(--radius-md); color:#fff;
  position: relative; overflow: hidden; box-shadow: var(--shadow-md); border: none;
}
.subject-chip h3 { color: #fff; font-size: 1.25rem; }
.subject-chip p { color: #fff; }
/* Subject chips carry white text, so the LIGHT stop of each gradient governs
   the contrast. The old light stops measured white at 2.77-3.92:1 against the
   4.5 small text owes — 18 of the student dashboard's failures were these two
   gradients alone. Stops deepened, hues kept. Coding was already dark enough;
   Yoruba is the one bright chip and carries dark text instead. */
.subject-maths   { background: linear-gradient(150deg, #12854E, #0A5F38); } /* allow-raw: the deep green must stay FIXED here. This gradient used var(--grass-deep), which lightens to #7FE0AE in dark and left the chip's white text at 1.6:1. Its sibling chips are literals for the same reason. */
.subject-english { background: linear-gradient(150deg, #3355C4, #21388C); }  /* allow-raw: fixed brand artwork — these gradients must NOT follow the theme; white text sits on them in both. */
.subject-french  { background: linear-gradient(150deg, #C23C22, #9E2F1B); }  /* allow-raw: fixed brand artwork — these gradients must NOT follow the theme; white text sits on them in both. */
.subject-coding  { background: linear-gradient(150deg, #2E463E, #14261F); }  /* allow-raw: fixed brand artwork — these gradients must NOT follow the theme; white text sits on them in both. */
.subject-yoruba  { background: linear-gradient(150deg, #F5C244, #D6900B); color: var(--on-bright); }  /* allow-raw: fixed brand artwork — these gradients must NOT follow the theme; white text sits on them in both. */
.subject-yoruba h3, .subject-yoruba p { color: var(--on-bright); }
.subject-igbo    { background: linear-gradient(150deg, #6B36C4, #4A2490); }  /* allow-raw: fixed brand artwork — these gradients must NOT follow the theme; white text sits on them in both. */
.subject-stem    { background: linear-gradient(150deg, #127389, #0C4F5E); }  /* allow-raw: fixed brand artwork — these gradients must NOT follow the theme; white text sits on them in both. */
.grade-pills { display:flex; gap: var(--space-2); flex-wrap: wrap; }
.grade-pill { padding: 9px 18px; border-radius: var(--radius-pill); background: var(--card); border: 1px solid var(--rule); font-weight: 700; font-family: var(--font-mono); font-size: .82rem; color: var(--ink); }

/* ============================================================
   PRICING — the lesson ledger
   ============================================================ */
.pricing-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--space-6); max-width: 820px; margin: 0 auto; }
@media (max-width: 1000px){ .pricing-grid { max-width: 620px; } }
@media (max-width: 520px){ .pricing-grid { grid-template-columns: 1fr; max-width: 380px; margin: 0 auto; } }
.price-card { position: relative; text-align: left; padding: var(--space-6); }
.price-card h3 { font-size: 1.1rem; }
.price-card.popular { border: 2px solid var(--grass); box-shadow: var(--shadow-lg); }
.price-card .amount { font-family: var(--font-mono); font-size: 2.4rem; font-weight: 700; color: var(--ink); letter-spacing: -.02em; }
.price-card .amount small { font-size: .9rem; font-weight: 400; color: var(--ink-mute); letter-spacing: 0; }
.price-card .per { font-family: var(--font-mono); font-size: .78rem; color: var(--grass-deep); }
.price-tag { position: absolute; top: -13px; left: var(--space-6); }
.price-list { list-style: none; text-align: left; margin: var(--space-6) 0; }
.price-list li { padding: 8px 0; display: flex; gap: 10px; color: var(--ink-soft); font-weight: 500; }
.price-list li svg { color: var(--grass); flex: none; width: 20px; height: 20px; }

/* Pricing cards — dashboard polish: mono flags, tabular price, and a lesson-
   chip row that makes "5 paid + 1 free" literal. */
.pc-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.pc-flag { font-family: var(--font-mono); font-size: .58rem; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; color: var(--ink-mute); background: var(--paper-2); padding: 4px 9px; border-radius: 999px; flex: none; }
.pc-flag.pc-save { background: var(--gold-tint); color: var(--gold-deep); }
.price-card .amount { font-variant-numeric: tabular-nums; }
.pc-chips { display: flex; gap: 5px; margin-top: var(--space-4); }
.pc-chips .lc { flex: 1; height: 12px; border-radius: 3px; }
.pc-chips .lc.paid { background: var(--grass); }
.pc-chips .lc.free { background: var(--gold); }
.pc-legend { font-family: var(--font-mono); font-size: .6rem; text-transform: uppercase; letter-spacing: .05em; color: var(--ink-mute); margin-top: 7px; }

/* ---- Recruitment band ---- */
.dark-section { background: var(--slab); position: relative; overflow: hidden;
  background-image: linear-gradient(rgba(255,255,255,.03) 1px, transparent 1px), linear-gradient(90deg, rgba(255,255,255,.03) 1px, transparent 1px);
  background-size: 26px 26px; }
.dark-section h2, .dark-section h3 { color: var(--on-slab); }
.dark-section .eyebrow { color: var(--gold); }
.dark-section .eyebrow::before { background: var(--gold); }
.dark-section .muted { color: var(--on-slab-mute); }
.dark-section .card { background: var(--card); }

/* ---- Big CTA band ---- */
/* Carries white text, so it takes the action token: white on --grass is
   3.62:1, on --action-primary 5.26:1. */
.cta-band { background: var(--action-primary); position: relative; overflow: hidden;
  background-image: linear-gradient(rgba(255,255,255,.06) 1px, transparent 1px), linear-gradient(90deg, rgba(255,255,255,.06) 1px, transparent 1px);
  background-size: 26px 26px; }
.cta-band h2, .cta-band p { color: var(--on-accent); }
.cta-band .btn-primary { background: var(--card); color: var(--grass-deep); box-shadow: 0 12px 26px -12px rgba(0,0,0,.4); }
.cta-band .btn-primary:hover { background: var(--paper-2); }
.cta-band .btn-secondary { background: transparent; color: var(--on-accent); border-color: var(--on-accent-soft); }
.cta-band .btn-secondary:hover { border-color: var(--on-accent); }

/* ---- Footer ---- */
.footer { background: var(--slab); color: var(--on-slab-mute); padding: var(--space-16) 0 var(--space-8); }
.footer .brand { color: var(--on-slab); }
.footer .brand span { color: var(--gold); }
/* WCAG 2.5.8 target size. These are navigation links stacked in their own
   column, not links inside a sentence, so the inline exception does not
   apply — and they measured 21px tall. inline-block plus block padding
   takes the hit area past 24px without moving anything visually. */
.footer a { color: var(--on-slab-mute); display: inline-block; padding-block: 4px; }
.footer a:hover { color: var(--gold); }
.footer h3 { color: var(--on-slab) !important; font-family: var(--font-heading); }
.footer-grid { display: grid; grid-template-columns: 2fr 1fr 1fr 1fr; gap: var(--space-8); }
@media (max-width:760px){ .footer-grid{ grid-template-columns: 1fr 1fr; } }
@media (max-width:460px){ .footer-grid{ grid-template-columns: 1fr; } }

/* ---- Modal ---- */
.modal-overlay { position: fixed; inset: 0; background: rgba(23,51,43,.5); backdrop-filter: blur(5px); display: none; align-items: center; justify-content: center; z-index: 100; padding: var(--space-4); }
.modal-overlay.open { display: flex; }
.modal { background: var(--card); border-radius: var(--radius-lg); padding: var(--space-8); max-width: 460px; width: 100%; box-shadow: var(--shadow-lg); animation: fadeInUp .3s ease; max-height: 92vh; overflow:auto; }

/* ============================================================
   AUTH — role tabs, alerts, avatar, camera
   ============================================================ */
.auth-wrap { position: relative; z-index: 2; min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: var(--space-6); }
.tabs { display: flex; gap: 4px; background: var(--paper-2); padding: 5px; border-radius: var(--radius-md); margin-bottom: var(--space-6); }
.tab { appearance: none; background: transparent; border: 0; flex: 1; text-align: center; padding: .55rem; border-radius: var(--radius-sm); font-weight: 700; font-family: var(--font-heading); cursor: pointer; color: var(--ink-mute); transition: background-color .18s, color .18s; font-size: .88rem; }
.tab.active { background: var(--card); color: var(--grass-deep); box-shadow: var(--shadow-sm); }
.tab:focus-visible { outline: 3px solid var(--focus-ring); outline-offset: 2px; }

/* Auth cards (.paper-sheet is only ever the sign-in / sign-up / reset / 404
   card) title themselves with an h1 because it is the page's ONLY heading —
   the level is structural, not a size. Left at the page-hero scale it rendered
   at 42px on a phone and 69px on a desktop, filling the card and wrapping to a
   different number of lines for each role tab on login.html, which moved the
   Sign in button every time the tab changed. These are the h3 metrics the
   titles had before the heading-structure fix promoted them. */
.paper-sheet h1 { font-size: clamp(1.3rem, 2.4vw, 1.75rem); font-weight: 700; }

.alert { padding: .8rem 1rem; border-radius: var(--radius-sm); font-size: .9rem; margin-bottom: var(--space-4); font-weight: 500; border: 1px solid transparent; }
.alert-error { background: var(--coral-tint); color: var(--coral-deep); border-color: #f2c4b9; }
.alert-success { background: var(--grass-tint); color: var(--grass-deep); border-color: #bfe4cd; }
.alert-info { background: var(--pen-tint); color: var(--pen-deep); border-color: #c8d5f6; }
.alert-warning { background: var(--gold-tint); color: var(--gold-deep); border-color: #f0dca0; }

.avatar-orb { width: 60px; height: 60px; border-radius: 16px; display: grid; place-items: center; background: var(--grass); box-shadow: var(--shadow-glow); flex: none; transform: rotate(-4deg); }
.avatar-orb svg { width: 30px; height: 30px; color: #fff; }
.avatar-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--space-4); }
.avatar-pick { border: 1px solid var(--rule); border-radius: var(--radius-md); padding: var(--space-3); cursor: pointer; text-align: center; background: var(--card); transition: border-color .18s, transform .18s; }
.avatar-pick:hover { transform: translateY(-3px); border-color: var(--pen); }
.avatar-pick.selected { border-color: var(--grass); box-shadow: var(--shadow-glow); }

.camera-frame { position: relative; width: min(240px, 100%); height: 240px; border-radius: 16px; overflow: hidden; margin: 0 auto var(--space-4); border: 3px dashed var(--grass); background: var(--paper-2); }
.camera-frame video, .camera-frame img, .camera-frame canvas { width: 100%; height: 100%; object-fit: cover; }

/* Auth ambient: faint ruled notebook paper — carries the hero's ruled-paper
   language onto sign-in / sign-up. Only site.css auth pages use .starfield;
   dashboards have their own (colourful) one in style.css. */
.starfield { position: absolute; inset: 0; z-index: 0; pointer-events: none; opacity: .55;
  background-image: repeating-linear-gradient(to bottom, transparent 0 31px, var(--rule) 31px 32px);
}

/* Auth card = a page of the ledger: a peeking sheet behind it + a coral
   exercise-book margin rule down the inner edge. */
.paper-sheet { position: relative;
  box-shadow: var(--shadow-lg), 9px 11px 0 -2px var(--paper), 11px 13px 0 -3px var(--rule);
}
.paper-sheet::before {
  content: ""; position: absolute; top: 18px; bottom: 18px; left: 18px; width: 2px;
  border-radius: 2px; background: var(--coral); opacity: .38;
}

/* ---- Stars ---- */
.stars { display: inline-flex; gap: 3px; }
.stars svg { width: 20px; height: 20px; }

/* ============================================================
   MOTION — the ledger draws itself
   ============================================================ */
@keyframes fadeInUp { from{ opacity:0; transform: translateY(20px);} to{ opacity:1; transform: translateY(0);} }
@keyframes drawLine { to { stroke-dashoffset: 0; } }
@keyframes popIn { 0%{ opacity:0; transform: scale(.4);} 70%{ transform: scale(1.15);} 100%{ opacity:1; transform: scale(1);} }
@keyframes twinkle { 0%,100%{ transform: scale(1); } 50%{ transform: scale(1.22); } }
@keyframes spin2 { to { transform: rotate(360deg); } }

.reveal { opacity: 1; }
.spinner { width: 42px; height: 42px; border: 4px solid var(--rule); border-top-color: var(--grass); border-radius: 50%; animation: spin2 .8s linear infinite; margin: var(--space-8) auto; }

@media (prefers-reduced-motion: no-preference) {
  .reveal { opacity: 0; animation: fadeInUp .7s ease forwards; }
  .d1{animation-delay:.08s}.d2{animation-delay:.22s}.d3{animation-delay:.36s}.d4{animation-delay:.5s}

  .ledger .plot { stroke-dasharray: 520; stroke-dashoffset: 520; animation: drawLine 1.7s ease .35s forwards; }
  .ledger .node { opacity: 0; animation: popIn .5s ease forwards; }
  .ledger .node.n1{animation-delay:.6s}.ledger .node.n2{animation-delay:.85s}
  .ledger .node.n3{animation-delay:1.1s}.ledger .node.n4{animation-delay:1.35s}
  .ledger .node.n5{animation-delay:1.6s}
  .ledger .star-node { transform-box: fill-box; transform-origin: center; opacity: 0; animation: popIn .55s ease 1.9s forwards, twinkle 2.6s ease-in-out 2.6s infinite; }
  .ledger-note { opacity: 0; animation: fadeInUp .6s ease 2.2s forwards; }

  /* Proof dashboard: bars rise from the baseline, then the live dot breathes. */
  .proof .bar { transform-box: fill-box; transform-origin: bottom; transform: scaleY(0); animation: proofRise .7s cubic-bezier(.2,.7,.3,1) forwards; }
  .proof .b1{animation-delay:.5s}.proof .b2{animation-delay:.62s}.proof .b3{animation-delay:.74s}
  .proof .b4{animation-delay:.86s}.proof .b5{animation-delay:.98s}.proof .b6{animation-delay:1.1s}
  .proof-live::before { animation: proofPulse 2s ease-in-out 1.4s infinite; }
}
@keyframes proofRise { to { transform: scaleY(1); } }
@keyframes proofPulse { 0%,100% { box-shadow: 0 0 0 0 rgba(229,83,58,.5); } 50% { box-shadow: 0 0 0 5px rgba(229,83,58,0); } }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

/* Print — marketing, auth and legal pages. Privacy/Terms are the pages people
   genuinely print, so they must come out as plain readable documents. */
@media print {
  .nav, .starfield, .hero-cta, .btn, .book-stage, .book-art, .mobile-menu,
  .skip-link, #tt-toast { display: none !important; }
  body, .card, .panel, .paper-sheet {
    background: #fff !important; color: #000 !important; box-shadow: none !important;
  }
  .paper-sheet::before, .hero .lead-col::before { display: none !important; }
  .hero h1 { background-image: none !important; }
  .container, .rc-wrap { max-width: none !important; padding: 0 !important; }
  .section { padding: var(--space-6) 0 !important; }
  .legal table { break-inside: auto; }
  tr, .card { break-inside: avoid; }
  a { text-decoration: underline; }
  .legal a[href^="http"]::after { content: " (" attr(href) ")"; font-size: .85em; word-break: break-all; }
  @page { margin: 1.5cm; }
}

/* Accessible tooltip + crash notice — mirrors style.css so the marketing and
   auth pages behave identically. Native title= is invisible to touch users and
   unreachable by keyboard; :focus-within makes this one Tab-reachable, and
   aria-describedby (set in api.js) has it announced as help text. */
[data-tip] > .tip-text {
  position: absolute; bottom: calc(100% + 8px); left: 50%; transform: translateX(-50%) translateY(3px);
  background: var(--ink); color: var(--paper); padding: 6px 10px; border-radius: var(--radius-sm);
  font-size: .78rem; font-weight: 600; line-height: 1.35; width: max-content; max-width: 240px;
  text-align: left; pointer-events: none; z-index: 60; opacity: 0;
  transition: opacity var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out);
}
[data-tip]:hover > .tip-text,
[data-tip]:focus > .tip-text,
[data-tip]:focus-within > .tip-text { opacity: 1; transform: translateX(-50%) translateY(0); }
.crash-bar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 9998;
  background: var(--danger-tint); color: var(--danger); border-top: 2px solid var(--danger-border);
  padding: var(--space-4); text-align: center; font-weight: 600;
  display: flex; gap: var(--space-4); align-items: center; justify-content: center; flex-wrap: wrap;
}
.crash-bar .btn { background: var(--danger); color: #fff; }
@media print { .crash-bar, [data-tip] > .tip-text { display: none !important; } }

/* Theme toggle. Sits in the nav (marketing) or the sidebar (dashboards); the
   glyph shows the theme it will switch TO, and aria-pressed carries the current
   state for assistive tech. */
.theme-toggle {
  background: transparent; border: 2px solid var(--rule); color: var(--ink);
  border-radius: var(--radius-pill); width: 38px; height: 38px; flex: none;
  display: inline-grid; place-items: center; cursor: pointer; font-size: 1.05rem; line-height: 1;
  transition: border-color var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}
.theme-toggle:hover { border-color: var(--grass); color: var(--grass-deep); }
.theme-toggle:focus-visible { outline: 3px solid var(--focus-ring); outline-offset: 2px; }
.sidebar .theme-toggle { margin-top: var(--space-4); }
@media print { .theme-toggle { display: none !important; } }

/* Paired with applyTheme() in api.js. Held for exactly one frame while
   data-theme flips, because a property that transitions AND reads a var()
   does not restyle when only the custom property changes — it keeps the old
   colour until a reload. Not a motion preference: this is a correctness fix. */
.theme-switching, .theme-switching *, .theme-switching *::before, .theme-switching *::after {
  transition: none !important;
}

/* Reflow, WCAG 1.4.10. Measured cause: the NAV ROW set a hard 411px floor for
   the whole page — brand + secondary button + hamburger + theme toggle, with a
   24px gap between them. Everything else that looked too wide (the hero
   columns, the book illustration) was a symptom of the body already being 411
   wide, and fixing them in isolation changed the page width by nothing.
   Verified: index went 411 -> 305 at a 320px viewport from these rules alone.

   The secondary button is hidden rather than shrunk because there is no width
   at which it, the brand and two icon buttons all fit at 320. Nothing is lost:
   the same link is in the mobile menu that the hamburger opens. The PRIMARY
   button is deliberately kept — on become-a-tutor that is the page's whole
   purpose. */
@media (max-width: 600px) {
  .container { padding: 0 var(--space-4); }
  .brand { font-size: 1.15rem; }
  .nav-links { gap: var(--space-2); }
  .nav-links > .btn-ghost { display: none; }
  /* Four role tabs cannot sit on one row at 320 without clipping their labels,
     so they are allowed to wrap. Basis auto, not 40%: a 40% basis forced two
     rows on EVERY phone, including the 390-430px widths where all four fit
     comfortably on one. */
  .tabs { flex-wrap: wrap; }
  .tab { flex: 1 1 auto; }
}

/* A table that is genuinely wider than a phone scrolls INSIDE its own region
   rather than pushing the page sideways. tabindex + role make that region
   reachable by keyboard, which a bare overflow container is not. */
.table-scroll { overflow-x: auto; }
.table-scroll:focus-visible { outline: 3px solid var(--focus-ring); outline-offset: 2px; }

/* The auth pages have no nav and no sidebar, so their toggle floats. Pinned
   top-right, clear of the card, and out of the way of the guide button which
   sits bottom-right. */
.theme-toggle-floating { position: fixed; top: 16px; right: 16px; z-index: 60; }
@media (max-width: 480px) { .theme-toggle-floating { top: 10px; right: 10px; } }

/* Icons sit on the text baseline and take their colour from it, which is the
   whole point of replacing emoji: one stroke weight, one colour source, and
   they scale with the type rather than with whatever the platform ships. */
.ic { display: inline-block; vertical-align: -0.135em; flex: none; }

/* Off-screen but still announced. Used for a page title that the visual design
   does not call for — signup-parent's visible headings are step names, not the
   page's own title. */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
