/* ==========================================================================
   JTS SAT Platform — Design System (core.css)
   Light theme by default; dark theme via [data-theme="dark"] on <html>.
   No frameworks, no build step. Works from file://
   ========================================================================== */

/* ----- 1. Tokens ---------------------------------------------------------- */
:root {
  /* Brand. Purple is the product's colour, not an accent on a neutral chrome:
     the header, the hero, the page ground, the eyebrows and every interactive
     state come from this one ramp. */
  --brand-950: #170D2E;
  --brand-900: #221445;
  --brand-800: #3A1F7A;
  --brand-700: #6F31E8;      /* text and hover on light grounds */
  --brand-600: #874BF8;      /* primary action */
  --brand-500: #9A68FA;
  --brand-400: #B08CFB;
  --brand-300: #CBB5FD;
  --brand-200: #DDD0FE;
  --brand-100: #EDE4FF;
  --brand-050: #F3EFFA;
  --eyebrow:   #874BF8;
  --eyebrow-on-dark: #CBB5FD;
  --dark-grad-a: #221445;
  --dark-grad-b: #3A1F7A;

  /* Neutrals, tinted towards the brand so nothing on screen reads as grey. */
  --bg:        #F7F5FB;
  --surface:   #FFFFFF;
  --surface-2: #F3EFFA;
  --border:    #E5DEEF;
  --border-strong: #D3C7E8;
  --ink:       #211934;
  --ink-2:     #3D3452;
  --muted:     #716A81;      /* 5.2:1 on #FFF */

  /* Semantic */
  --ok:        #17764E;
  --ok-bg:     #E7F5EC;
  --warn:      #96690A;      /* 4.6:1 on #FFF */
  --warn-bg:   #FDF3DF;
  --danger:    #C42B30;      /* 5.6:1 on #FFF */
  --danger-bg: #FCEAEB;
  --info:      #1B62C4;
  --info-bg:   #E8F0FD;

  /* Mastery scale */
  --m-nodata:  #D5D4E2;
  --m-learning:#E8797D;
  --m-developing:#EFB750;
  --m-mastered:#4FBF8B;

  /* Shape & motion: white cards with soft corners and a soft shadow, pill
     buttons, on a pale lavender ground. */
  --r-sm: 10px;
  --r-md: 12px;
  --r-lg: 18px;
  --r-xl: 22px;
  --r-pill: 999px;
  --sp-1: 4px;  --sp-2: 8px;  --sp-3: 12px; --sp-4: 16px;
  --sp-5: 24px; --sp-6: 32px; --sp-7: 48px; --sp-8: 64px;
  --shadow-1: 0 6px 22px rgba(53,34,85,.04);
  --shadow-2: 0 8px 26px rgba(53,34,85,.08);
  --shadow-3: 0 18px 48px rgba(33,25,52,.22);
  --font: Manrope, "Segoe UI", -apple-system, BlinkMacSystemFont, Roboto, Arial, "Noto Sans", sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
  --sidebar-w: 248px;
  --topbar-h: 60px;
  --header-h: var(--topbar-h);   /* what the question screen sticks itself under */
  --tabbar-h: 56px;
}

html[data-theme="dark"] {
  /* The dark theme is the same purple pushed to the bottom of the ramp, not a
     neutral dark with a purple button. */
  --bg:        #0C0920;
  --surface:   #171232;
  --surface-2: #1E1840;
  --border:    #302759;
  --border-strong: #4B3F80;
  --ink:       #F2F0FB;
  --ink-2:     #D8D3EE;
  --muted:     #A8A2C6;      /* 7.2:1 on #171232 */
  --brand-200: #3A2F6E;
  --brand-100: #2A2257;
  --brand-050: #1F1945;
  --brand-600: #9B6BFF;
  --brand-500: #AC85FF;
  --brand-700: #C3A6FF;
  --brand-800: #1F1945;
  --brand-900: #171232;
  --eyebrow:   #C3A6FF;
  --eyebrow-on-dark: #C0B6FA;
  --dark-grad-a: #171232;
  --dark-grad-b: #241C4E;
  --ok:        #4FD19A;  --ok-bg:     #10301F;
  --warn:      #F0B84B;  --warn-bg:   #332809;
  --danger:    #F2787C;  --danger-bg: #3A1520;
  --info:      #79AEF7;  --info-bg:   #101F4A;
  --m-nodata:  #332B55;
  --shadow-1: none;
  --shadow-2: 0 2px 0 rgba(0,0,0,.5);
  --shadow-3: 0 18px 48px rgba(0,0,0,.65);
}

/* ----- 2. Reset ----------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
html, body { height: 100%; }
body {
  margin: 0;
  font-family: var(--font);
  font-size: 15px;
  line-height: 1.5;
  color: var(--ink);
  background: var(--bg);
  -webkit-text-size-adjust: 100%;
}
h1,h2,h3,h4,p,figure,ul,ol { margin: 0; }
ul,ol { padding: 0; list-style: none; }
/* The reset kills markers everywhere, which is right for nav and card lists
   and wrong for prose. Numbered and bulleted content opts back in. */
ol.list-num { list-style: decimal; padding-inline-start: 22px; }
ul.list-dot { list-style: disc; padding-inline-start: 22px; }
ol.list-num li, ul.list-dot li { margin-block: 2px; }
img { max-width: 100%; display: block; }
button, input, select, textarea { font: inherit; color: inherit; }
a { color: var(--brand-600); text-decoration: none; }
a:hover { text-decoration: underline; }
[hidden] { display: none !important; }

/* SAT Math: keep text + inline math on the same line */
.sat-source-render .sat-source-line {
  display: inline;
}

.sat-source-render .sat-source-line + .sat-source-line::before {
  content: " ";
}

.sat-question-text {
  display: block;
  line-height: 1.65;
  margin: 0;
}

.question-text img {
  width: auto !important;
  height: 1.5em !important;
  vertical-align: middle;
}

.answer-option img {
  width: auto !important;
  max-width: 300px !important;
  max-height: 110px !important;
}

.question-visual img,
img.question-visual {
  width: 100%;
  max-width: 520px;
  height: auto;
}

.sat-question-text .sat-inline-math {
  display: inline-block !important;
  vertical-align: -0.22em;
  margin: 0 0.08em;
}

/* Small math images must behave like characters inside a sentence */
.sat-inline-math,
.sat-source-render img.m {
  display: inline-block !important;
  width: auto;
  max-width: none;
  vertical-align: -0.22em;
  margin: 0 0.08em;
}

/* Don't let wrappers force line breaks */
.sat-source-render p {
  display: inline;
  margin: 0;
}

.sat-display-math,
.sat-question-visual,
.sat-source-render .fig {
  display: block !important;
  margin: 10px 0 16px;
}

:focus-visible {
  outline: 2px solid var(--brand-600);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}

.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;
}

/* ----- 3. Typography ------------------------------------------------------ */
.h1 { font-size: 26px; line-height: 1.2; font-weight: 700; letter-spacing: -.01em; }
.h2 { font-size: 20px; line-height: 1.25; font-weight: 650; letter-spacing: -.005em; }
.h3 { font-size: 16px; line-height: 1.3; font-weight: 650; }
.eyebrow {
  font-size: 11px; font-weight: 700; letter-spacing: .09em;
  text-transform: uppercase; color: var(--eyebrow);
}
.muted { color: var(--muted); }
.small { font-size: 13px; }
.xsmall { font-size: 12px; }
.num { font-variant-numeric: tabular-nums; }
.mono { font-family: var(--mono); }
.center { text-align: center; }
.nowrap { white-space: nowrap; }

/* Math without MathJax: fractions and helpers */
.frac {
  display: inline-flex; flex-direction: column; vertical-align: -0.45em;
  text-align: center; line-height: 1.06; font-size: .92em; margin: 0 .12em;
}
.frac > span:first-child { border-bottom: 1.2px solid currentColor; padding: 0 .3em; }
.frac > span:last-child { padding: 0 .3em; }
.sqrt::before { content: "\221A"; }
sup, sub { line-height: 0; font-size: .75em; }

/* ----- 4. Layout ---------------------------------------------------------- */
.app-shell { min-height: 100%; }
/* The sidebar is fixed rather than sticky: sticky gives it the height of one
   screenful, so on any page taller than the window the column beside the
   content runs out of sidebar and shows the page ground underneath. */
.app-body { min-width: 0; display: flex; flex-direction: column; margin-left: var(--sidebar-w); }
.app-sidebar[hidden] + .app-body { margin-left: 0; }
/* With no sidebar there is nothing for the column to sit beside, so it centres
   itself instead of hugging the left edge of the window. */
.app-sidebar[hidden] + .app-body .container { margin-inline: auto; }
/* Screens are measured from the left edge of the content column, not from the
   middle of the window: with a fixed sidebar a centred container drifts right
   and leaves a gutter that belongs to nothing. */
.container { width: 100%; max-width: 1360px; margin: 0; padding-inline: 28px; }
.container-wide { max-width: 1560px; }
/* Prose does not get wider just because the page does: a 1300px line is not
   readable. Screens that are mostly text cap their own paragraphs instead. */
.prose { max-width: 78ch; }
.screen { padding-block: 24px 48px; }
.stack > * + * { margin-top: var(--sp-4); }
.stack-sm > * + * { margin-top: var(--sp-2); }
.stack-lg > * + * { margin-top: var(--sp-5); }
.row { display: flex; align-items: center; gap: var(--sp-3); }
.row-wrap { flex-wrap: wrap; }
.row-between { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); }
.row-top { align-items: flex-start; }
.spacer { flex: 1 1 auto; }
.grid { display: grid; gap: var(--sp-4); }
.grid-2 { grid-template-columns: repeat(2, minmax(0,1fr)); }
.grid-3 { grid-template-columns: repeat(3, minmax(0,1fr)); }
.grid-4 { grid-template-columns: repeat(4, minmax(0,1fr)); }
.grid-auto { grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); }

/* ----- 5. Sidebar, top bar & navigation ----------------------------------- */
.app-sidebar {
  position: fixed; top: 0; left: 0; bottom: 0; z-index: 40;
  /* Nothing in the sidebar scrolls — not the bar, and not the navigation
     inside it. On a short window the nav used to grow a scrollbar of its own,
     so the page had two, and a destination could be below the fold of a menu
     nobody expects to have a fold. Instead the chrome tightens as the window
     gets shorter (the blocks at the end of this section): the rows give up
     padding, then type size, and all nine destinations stay on screen. */
  width: var(--sidebar-w); overflow: hidden;
  display: flex; flex-direction: column; gap: 10px;
  padding: var(--sp-4) var(--sp-3);
  background: var(--brand-900); color: #fff;
  border-right: 3px solid var(--brand-600);
}

.sb-brand { display: flex; align-items: center; gap: 10px; color: #fff; text-decoration: none; padding: 4px; }
.sb-brand:hover { text-decoration: none; }
.brand-mark {
  width: 34px; height: 34px; flex: 0 0 34px;
  background: var(--brand-600);
  display: grid; place-items: center;
  font-weight: 800; font-size: 13px; letter-spacing: .02em; color: #fff;
}
.brand-text { display: flex; flex-direction: column; line-height: 1.15; min-width: 0; }
.brand-text b { font-size: 15px; font-weight: 700; }
.brand-text span {
  font-size: 10px; font-weight: 700; letter-spacing: .09em; text-transform: uppercase;
  color: var(--eyebrow-on-dark);
}

.sb-goal {
  display: flex; flex-direction: column; gap: 1px;
  padding: 10px 12px; text-decoration: none; color: #fff;
  background: var(--brand-800); border-left: 3px solid var(--brand-500);
}
.sb-goal:hover { background: var(--brand-700); text-decoration: none; }
.sb-goal-label { font-size: 10px; font-weight: 700; letter-spacing: .09em; text-transform: uppercase; color: var(--eyebrow-on-dark); }
.sb-goal-value { font-size: 22px; font-weight: 750; letter-spacing: -.02em; line-height: 1.1; font-variant-numeric: tabular-nums; }
.sb-goal-meta { font-size: 11px; color: rgba(255,255,255,.66); }

/* Fixed: it neither takes the spare space (the spacer below it does that, so
   the account block stays pinned to the bottom) nor scrolls. Its height is
   what the rows need, and the height-based rules below are what make the rows
   need less. */
.sb-nav {
  display: flex; flex-direction: column; gap: 6px;
  flex: 0 0 auto;
}
.sb-nav a {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 12px; font-size: 14px; font-weight: 600;
  color: rgba(255,255,255,.76); text-decoration: none;
  border-left: 3px solid transparent;
}
.sb-nav a em { font-style: normal; font-size: 15px; width: 18px; text-align: center; flex: 0 0 18px; opacity: .85; }
.sb-nav a:hover { background: var(--brand-800); color: #fff; text-decoration: none; }
.sb-nav a[aria-current="page"] {
  background: var(--brand-600); color: #fff; border-left-color: var(--brand-300);
}
.sb-nav a[aria-current="page"] em { opacity: 1; }

/* Four controls have to share 248px minus padding, so this row does not wrap:
   the language switch gives up the slack instead of the gear falling to a
   second line. */
.sb-tools { display: flex; align-items: center; gap: 5px; }
.sb-tools .lang-switch { flex: 1 1 auto; min-width: 0; }
.sb-tools .lang-switch button { flex: 1 1 auto; padding-inline: 6px; }
.sb-tools .icon-btn { flex: 0 0 32px; width: 32px; height: 32px; font-size: 14px; }
.sb-user {
  display: flex; align-items: center; gap: 9px;
  padding: 9px 10px; background: var(--brand-800); min-width: 0;
}
.sb-avatar {
  width: 32px; height: 32px; flex: 0 0 32px; display: grid; place-items: center;
  background: var(--brand-600); color: #fff; font-size: 12px; font-weight: 750; letter-spacing: .02em;
}
.sb-user-text { display: flex; flex-direction: column; line-height: 1.2; min-width: 0; flex: 1; }
.sb-user-text b { font-size: 13px; font-weight: 650; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sb-user-text span { font-size: 11px; color: rgba(255,255,255,.6); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sb-out { flex: 0 0 30px; width: 30px; height: 30px; font-size: 14px; }

.icon-btn {
  display: inline-grid; place-items: center; width: 34px; height: 34px;
  border: 1px solid var(--brand-700); background: var(--brand-800);
  color: #fff; cursor: pointer; font-size: 15px; text-decoration: none;
}
.icon-btn:hover { background: var(--brand-600); border-color: var(--brand-600); text-decoration: none; }

.lang-switch { display: inline-flex; border: 1px solid var(--brand-700); }
.lang-switch button {
  border: 0; background: transparent; color: rgba(255,255,255,.72);
  font-size: 11px; font-weight: 700; letter-spacing: .04em;
  padding: 6px 9px; cursor: pointer;
}
.lang-switch button:hover { background: var(--brand-800); color: #fff; }
.lang-switch button[aria-pressed="true"] { background: var(--brand-600); color: #fff; }

/* Nine destinations, a brand, a goal, a tools row and an account block are
   about 700px of sidebar at full size. Below that the bar tightens rather
   than scrolling: first the space between things, then the padding inside the
   rows, then the type. Each step is small enough that the one before it has
   to be exhausted first, which keeps a 1080p window looking exactly as it
   did. */
@media (max-height: 880px) {
  .app-sidebar { gap: 7px; padding-block: var(--sp-3); }
  .sb-goal { padding: 8px 12px; }
  .sb-goal-value { font-size: 19px; }
  .sb-nav { gap: 4px; }
  .sb-nav a { padding: 8px 12px; }
}
@media (max-height: 800px) {
  .sb-nav { gap: 2px; }
  .sb-nav a { padding: 6px 12px; }
}
@media (max-height: 700px) {
  .app-sidebar { gap: 5px; }
  .sb-nav { gap: 1px; }
  .sb-goal { padding: 6px 12px; }
  .sb-goal-value { font-size: 17px; }
  .sb-nav a { padding: 4px 12px; }
  .sb-user { padding: 6px 10px; }
  .sb-avatar { width: 28px; height: 28px; flex: 0 0 28px; }
}
@media (max-height: 620px) {
  .app-sidebar { gap: 4px; padding-block: 10px; }
  .sb-nav { gap: 0; }
  .brand-mark { width: 28px; height: 28px; flex: 0 0 28px; font-size: 11px; }
  /* The goal is a number the student steers by; at this height it keeps the
     number and gives up the exam date, which is also in Settings. */
  .sb-goal-meta { display: none; }
  .sb-nav a { padding: 3px 12px; font-size: 13px; }
  .sb-tools .icon-btn { flex: 0 0 28px; width: 28px; height: 28px; }
  .sb-user { padding: 4px 8px; }
}
/* Under about 470px there is not enough glass for nine destinations and an
   account block however tight the rows get, and clipping the sign-out button
   out of existence is worse than a scrollbar. So the bar scrolls as a last
   resort — the navigation still does not, and no laptop window is this
   short. */
@media (max-height: 470px) {
  .app-sidebar { overflow-y: auto; }
}

/* ----- 5b. Top bar -------------------------------------------------------- */
.app-topbar {
  position: sticky; top: 0; z-index: 30;
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4);
  min-height: var(--topbar-h); padding: 10px 28px;
  background: var(--surface); border-bottom: 1px solid var(--border);
}
.tb-left { display: flex; align-items: baseline; gap: var(--sp-3); min-width: 0; }
.tb-title { font-size: 22px; line-height: 1.2; font-weight: 700; letter-spacing: -.01em; margin: 0; }
.tb-date { font-size: 12px; color: var(--muted); white-space: nowrap; }
.tb-actions { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; justify-content: flex-end; }
.tb-actions:empty { display: none; }
.tb-menu { display: none; }

/* The tab bar is a phone-only mirror of the sidebar. */
.tabbar { display: none; }

/* ----- 6. Buttons --------------------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  padding: 9px 16px; min-height: 38px;
  border-radius: var(--r-md); border: 1px solid var(--border-strong);
  background: var(--surface); color: var(--ink);
  font-size: 14px; font-weight: 600; cursor: pointer; text-decoration: none;
  transition: background .12s ease, border-color .12s ease, transform .06s ease;
}
.btn:hover { background: var(--brand-050); border-color: var(--brand-500); color: var(--brand-700); text-decoration: none; }
.btn:active { transform: translateY(1px); }
.btn[disabled], .btn[aria-disabled="true"] { opacity: .5; cursor: not-allowed; pointer-events: none; }
.btn-primary { background: var(--brand-600); border-color: var(--brand-600); color: #fff; }
/* .btn:hover sets color too, and a bare class loses to a class + pseudo-class,
   so without restating it here a hovered primary button painted brand-700 text
   on a brand-700 fill — an invisible label on every primary button in the app. */
.btn-primary:hover { background: var(--brand-700); border-color: var(--brand-700); color: #fff; }
.btn-ghost { background: transparent; border-color: transparent; color: var(--ink-2); }
.btn-ghost:hover { background: var(--brand-050); color: var(--brand-700); }
.btn-danger { background: var(--surface); border-color: var(--danger); color: var(--danger); }
.btn-danger:hover { background: var(--danger-bg); color: var(--danger); }
.btn-lg { min-height: 48px; padding: 13px 24px; font-size: 15px; }
.btn-sm { min-height: 30px; padding: 5px 10px; font-size: 13px; border-radius: var(--r-sm); }
.btn-block { width: 100%; }
.btn-group { display: inline-flex; gap: 6px; flex-wrap: wrap; }

/* ----- 7. Cards & surfaces ------------------------------------------------ */
.card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-lg); padding: var(--sp-5); box-shadow: var(--shadow-1);
}
.card-sm { padding: var(--sp-4); border-radius: var(--r-md); }
.card-flat { box-shadow: none; }
.card-accent { border-left: 4px solid var(--brand-600); }
.card-brand { background: var(--brand-050); border-color: var(--brand-200); }
.card-head { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); margin-bottom: var(--sp-4); }
.card-hero {
  background: linear-gradient(135deg, var(--brand-800) 0%, var(--brand-600) 100%);
  color: #fff; border: 0;
}
.card-hero .muted, .card-hero .small.muted { color: rgba(255,255,255,.76); }
.card-hero .eyebrow { color: var(--eyebrow-on-dark); }
/* .stat-label carries its own muted colour, so the generic .card-hero .muted
   rule never reached it and the labels sat near-invisible on the gradient. */
.card-hero .stat-label { color: rgba(255,255,255,.76); }
.card-hero .badge { background: rgba(255,255,255,.14); border-color: rgba(255,255,255,.28); color: #fff; }
/* An empty bar in brand-100 on a purple hero reads as a full one. */
.card-hero .bar { background: rgba(255,255,255,.22); }
.card-hero .bar > i { background: #fff; }
.divider { height: 1px; background: var(--border); border: 0; margin-block: var(--sp-4); }

.stat { display: flex; flex-direction: column; gap: 2px; }
.stat-value { font-size: 28px; font-weight: 750; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.stat-label { font-size: 12px; color: var(--muted); font-weight: 600; letter-spacing: .02em; }

/* ----- 8. Badges & pills -------------------------------------------------- */
.badge {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 9px;
  font-size: 12px; font-weight: 650; line-height: 1.5;
  background: var(--brand-100); color: var(--brand-700);
  border: 1px solid var(--brand-200); white-space: nowrap;
}
.badge-ok     { background: var(--ok-bg); color: var(--ok); }
.badge-warn   { background: var(--warn-bg); color: var(--warn); }
.badge-danger { background: var(--danger-bg); color: var(--danger); }
.badge-info   { background: var(--info-bg); color: var(--info); }
.badge-muted  { background: var(--bg); color: var(--muted); border-color: var(--border); }
.badge-dot::before { content: ""; width: 7px; height: 7px; background: currentColor; }

.chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 13px; cursor: pointer;
  border: 1px solid var(--border-strong); background: var(--surface);
  font-size: 13px; font-weight: 600; color: var(--ink-2);
}
.chip:hover { border-color: var(--brand-500); background: var(--brand-050); color: var(--brand-700); }
.chip[aria-pressed="true"] { background: var(--brand-600); border-color: var(--brand-600); color: #fff; }

/* ----- 9. Forms ----------------------------------------------------------- */
.field { display: flex; flex-direction: column; gap: 6px; }
.label { font-size: 13px; font-weight: 650; color: var(--ink-2); }
.hint { font-size: 12px; color: var(--muted); }
.error-text { font-size: 12px; color: var(--danger); font-weight: 600; }
.input, .select, .textarea {
  width: 100%; padding: 9px 12px; min-height: 40px;
  border: 1px solid var(--border-strong); border-radius: var(--r-md);
  background: var(--surface); color: var(--ink); outline: none;
}
.input:focus, .select:focus, .textarea:focus {
  border-color: var(--brand-600); box-shadow: 0 0 0 3px var(--brand-100);
}
.input[aria-invalid="true"] { border-color: var(--danger); }
.textarea { min-height: 120px; resize: vertical; line-height: 1.5; font-family: var(--mono); font-size: 13px; }
.select { appearance: none; padding-right: 34px;
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%), linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: calc(100% - 17px) 17px, calc(100% - 12px) 17px;
  background-size: 5px 5px, 5px 5px; background-repeat: no-repeat;
}
.input-affix { position: relative; display: flex; }
.input-affix .input { padding-right: 60px; }
.input-affix button {
  position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
  border: 0; background: transparent; color: var(--brand-600);
  font-size: 12px; font-weight: 700; cursor: pointer; padding: 6px;
}
.check { display: flex; align-items: flex-start; gap: 9px; cursor: pointer; font-size: 14px; }
.check input { width: 17px; height: 17px; margin: 2px 0 0; accent-color: var(--brand-600); flex: 0 0 17px; }
.check-card {
  border: 1px solid var(--border-strong); border-radius: var(--r-md);
  padding: 11px 13px; background: var(--surface);
}
.check-card:hover { border-color: var(--brand-500); }
.check-card:has(input:checked) { border-color: var(--brand-600); background: var(--brand-050); }
/* A check-card driven by a button rather than a checkbox says so with
   aria-pressed; selection should not need an inline style at every call site. */
.check-card[aria-pressed="true"] { border-color: var(--brand-600); background: var(--brand-050); }

/* ----- 10. Progress ------------------------------------------------------- */
.bar { height: 8px; background: var(--brand-100); overflow: hidden; }
.bar > i { display: block; height: 100%; background: var(--brand-600); transition: width .3s ease; }
.bar-ok > i { background: var(--ok); }
.bar-warn > i { background: var(--warn); }
.bar-thin { height: 5px; }

.steps { display: flex; gap: 6px; }
.steps > li { flex: 1; height: 5px; background: var(--brand-100); }
.steps > li.done { background: var(--brand-600); }
.steps > li.current { background: var(--brand-500); }

/* Six readable stage labels cannot fit 390px, so the track scrolls inside its
   own container rather than pushing the whole page sideways. */
.phase-track { display: flex; gap: 4px; overflow-x: auto; scrollbar-width: thin; }
.phase-track > div {
  flex: 1; padding: 9px 6px; text-align: center; font-size: 11px; font-weight: 650;
  background: var(--bg); color: var(--muted); border: 1px solid var(--border);
}
.phase-track > div + div { border-left: 0; }
.phase-track > div.done    { background: var(--ok-bg); color: var(--ok); border-color: transparent; }
.phase-track > div.current { background: var(--brand-600); color: #fff; border-color: transparent; }

/* ----- 11. Tabs ----------------------------------------------------------- */
.tabs { display: flex; gap: 2px; border-bottom: 1px solid var(--border); overflow-x: auto; }
.tabs button {
  border: 0; background: transparent; cursor: pointer; white-space: nowrap;
  padding: 10px 14px; font-size: 14px; font-weight: 600; color: var(--muted);
  border-bottom: 2px solid transparent; margin-bottom: -1px;
}
.tabs button:hover { color: var(--ink); }
.tabs button[aria-selected="true"] { color: var(--brand-700); border-bottom-color: var(--brand-600); border-bottom-width: 3px; }

/* ----- 12. Accordion ------------------------------------------------------ */
.acc { border: 1px solid var(--border); border-radius: var(--r-md); overflow: hidden; background: var(--surface); }
.acc + .acc { margin-top: var(--sp-2); }
.acc-head {
  width: 100%; display: flex; align-items: center; gap: var(--sp-3);
  padding: 12px 14px; border: 0; background: var(--surface-2); cursor: pointer; text-align: left;
}
.acc-head:hover { background: var(--brand-100); }
.acc-head .caret { transition: transform .15s ease; color: var(--muted); font-size: 12px; }
.acc[open] .acc-head .caret, .acc.open .acc-head .caret { transform: rotate(90deg); }
.acc-body { padding: 6px 14px 12px; border-top: 1px solid var(--border); }
.skill-row {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: 9px 4px; border-bottom: 1px dashed var(--border);
}
.skill-row:last-child { border-bottom: 0; }
.skill-row .name { flex: 1; min-width: 0; font-size: 14px; }

/* ----- 13. Modal & toast -------------------------------------------------- */
.modal-backdrop {
  position: fixed; inset: 0; z-index: 100; display: grid; place-items: center;
  background: rgba(20,18,31,.55); padding: 16px; overflow-y: auto;
}
.modal {
  background: var(--surface); border-radius: var(--r-lg); box-shadow: var(--shadow-3);
  width: 100%; max-width: 560px; max-height: calc(100vh - 32px);
  display: flex; flex-direction: column; border: 1px solid var(--border);
}
.modal-lg { max-width: 860px; }
.modal-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 16px 20px; border-bottom: 1px solid var(--border); }
.modal-body { padding: 20px; overflow-y: auto; }
.modal-foot { padding: 14px 20px; border-top: 1px solid var(--border); display: flex; justify-content: flex-end; gap: 8px; }

#toast-root { position: fixed; z-index: 200; left: 50%; bottom: 24px; transform: translateX(-50%); display: flex; flex-direction: column; gap: 8px; align-items: center; pointer-events: none; }
.toast {
  background: var(--brand-900); color: #fff; padding: 12px 20px;
  border-left: 4px solid var(--brand-500);
  font-size: 14px; font-weight: 600; box-shadow: var(--shadow-3); max-width: 90vw;
}
/* The base toast carries a brand rule; a semantic toast keeps its own colour
   on both the fill and the rule so the edge does not read as a stray purple. */
.toast-ok { background: var(--ok); border-left-color: #0C6B47; }
.toast-err { background: var(--danger); border-left-color: #8E1F23; }

/* ----- 14. Tables --------------------------------------------------------- */
.table-wrap { overflow-x: auto; }
table.table { width: 100%; border-collapse: collapse; font-size: 14px; }
table.table th, table.table td { padding: 9px 12px; text-align: left; border-bottom: 1px solid var(--border); }
table.table th {
  font-size: 12px; font-weight: 700; color: var(--brand-700);
  text-transform: uppercase; letter-spacing: .04em;
  background: var(--brand-050); border-bottom-color: var(--brand-200);
}
table.table tbody tr:hover { background: var(--brand-050); }
table.table td.num, table.table th.num { text-align: right; font-variant-numeric: tabular-nums; }

/* ----- 15. Empty / notice ------------------------------------------------- */
.empty { text-align: center; padding: var(--sp-7) var(--sp-4); color: var(--muted); }
.empty .h2 { color: var(--ink); margin-bottom: 6px; }
/* The unqualified notice is brand-coloured; notice-ok / -warn / -danger keep
   their semantic colours, because green and red mean correct and wrong here
   and recolouring them purple would delete that meaning. */
.notice {
  display: flex; gap: 10px; padding: 12px 14px;
  background: var(--brand-050); color: var(--ink-2); font-size: 13px;
  border: 1px solid var(--brand-200); border-left-width: 4px;
}
.notice-warn, .notice-danger, .notice-ok { border-color: transparent; }
.notice-warn { background: var(--warn-bg); }
.notice-danger { background: var(--danger-bg); }
.notice-ok { background: var(--ok-bg); }
.notice b { color: var(--ink); }

/* ----- 16. Skill mastery visuals ----------------------------------------- */
.m-dot { width: 11px; height: 11px; display: inline-block; flex: 0 0 11px; }
.m-nodata     { background: var(--m-nodata); }
.m-learning   { background: var(--m-learning); }
.m-developing { background: var(--m-developing); }
.m-mastered   { background: var(--m-mastered); }
.heatmap { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 6px; }
.heat-cell {
  border-radius: var(--r-sm); padding: 9px 10px; cursor: pointer; border: 1px solid var(--border);
  background: var(--surface); display: flex; flex-direction: column; gap: 3px; text-align: left; font: inherit;
}
.heat-cell:hover { border-color: var(--brand-500); }
.heat-cell .hc-name { font-size: 12.5px; font-weight: 600; line-height: 1.25; }
.heat-cell .hc-meta { font-size: 11px; color: var(--muted); }
.heat-cell.m-bg-nodata     { background: color-mix(in srgb, var(--m-nodata) 26%, var(--surface)); }
.heat-cell.m-bg-learning   { background: color-mix(in srgb, var(--m-learning) 26%, var(--surface)); }
.heat-cell.m-bg-developing { background: color-mix(in srgb, var(--m-developing) 26%, var(--surface)); }
.heat-cell.m-bg-mastered   { background: color-mix(in srgb, var(--m-mastered) 26%, var(--surface)); }

/* Columns are weeks. Without an explicit auto-column width the grid stretches
   the 13 columns across the card and the calendar stops reading as a calendar. */
.cal-heat {
  display: grid; grid-template-rows: repeat(7, 12px); grid-auto-flow: column;
  grid-auto-columns: 12px; justify-content: start;
  gap: 3px; overflow-x: auto; padding-bottom: 4px;
}
.cal-heat i { width: 12px; height: 12px; background: var(--brand-100); display: block; }
.cal-heat i[data-lv="1"] { background: color-mix(in srgb, var(--brand-600) 30%, var(--border)); }
.cal-heat i[data-lv="2"] { background: color-mix(in srgb, var(--brand-600) 58%, var(--border)); }
.cal-heat i[data-lv="3"] { background: var(--brand-600); }

/* ----- 17. Question screen ------------------------------------------------ */
/* The question screen fills what is left of the window, so it has to measure
   the chrome that is actually on screen. During onboarding and the diagnostic
   there is no app header and no tab bar, and assuming them left a 60px band of
   nothing above the toolbar, the first lines of the passage underneath it, and
   the footer floating clear of the bottom of the window. */
.q-shell {
  --q-top: var(--header-h); --q-bottom: 0px;
  display: flex; flex-direction: column; background: var(--surface);
  min-height: calc(100vh - var(--q-top) - var(--q-bottom));
}
body.no-frame .q-shell { --q-top: 0px; }
.q-topbar {
  display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap;
  padding: 10px 16px; border-bottom: 1px solid var(--border); background: var(--surface-2);
  position: sticky; top: var(--q-top); z-index: 20;
}
.q-timer { font-variant-numeric: tabular-nums; font-size: 18px; font-weight: 700; letter-spacing: .02em; }
.q-timer.low { color: var(--danger); }
.q-tools { display: flex; gap: 6px; margin-left: auto; flex-wrap: wrap; }
.q-note { font-size: 12px; color: var(--muted); max-width: 30ch; line-height: 1.3; }
.q-tool {
  display: inline-flex; align-items: center; gap: 6px; padding: 6px 10px;
  border: 1px solid var(--border-strong); border-radius: var(--r-sm); background: var(--surface);
  font-size: 13px; font-weight: 600; cursor: pointer; color: var(--ink-2);
}
.q-tool:hover { border-color: var(--brand-500); color: var(--brand-700); }
.q-tool[aria-pressed="true"] { background: var(--brand-600); border-color: var(--brand-600); color: #fff; }

.q-main { flex: 1; display: grid; grid-template-columns: minmax(0,1fr); gap: 0; }
.q-main.with-side { grid-template-columns: minmax(0,1fr) minmax(380px, 34vw); }
/* The 100px that used to sit under the content was there to clear a fixed
   footer. The footer is sticky and in flow, so it was 100px of nothing. */
.q-content { padding: 18px 16px 28px; max-width: 980px; margin: 0 auto; width: 100%; }
/* A question with no passage is a column of text and four choices; at 980px
   the choices become stripes and the eye has to travel the whole width. */
.q-content.is-single { max-width: 720px; padding-top: 28px; }
/* Alone on the page the stem is the thing being read, so it is set like one. */
.q-content.is-single .q-stem { font-size: 17px; font-weight: 600; line-height: 1.5; }
.q-head { align-items: center; gap: 10px; margin-bottom: 4px; }
.q-count { font-size: 13px; color: var(--muted); font-weight: 600; }
/* Only the passage and the stem can be highlighted, so only they can be
   selected. Dragging across the toolbar used to leave the browser's blue
   selection lying over half the screen with nothing to clear it. */
.q-shell { user-select: none; -webkit-user-select: none; }
.q-passage, .q-stem { user-select: text; -webkit-user-select: text; }
.q-split { display: grid; grid-template-columns: minmax(0,1fr) minmax(0,1fr); gap: var(--sp-5); align-items: start; }
.q-passage {
  font-size: 15px; line-height: 1.65; padding-right: var(--sp-4);
  border-right: 1px solid var(--border);
}
.q-passage p + p { margin-top: .8em; }
.q-num {
  display: inline-grid; place-items: center; width: 28px; height: 28px;
  background: var(--brand-600); color: #fff; font-size: 13px; font-weight: 700;
}
.q-stem { font-size: 15.5px; line-height: 1.6; margin-block: var(--sp-3) var(--sp-4); }

.opt-list { display: flex; flex-direction: column; gap: 9px; }
.opt {
  display: flex; align-items: center; gap: 12px; width: 100%; text-align: left;
  padding: 13px 16px; border: 1.5px solid var(--border-strong); border-radius: 14px;
  background: var(--surface); cursor: pointer; font-size: 14.5px; line-height: 1.5;
}
.opt:hover { border-color: var(--brand-500); }
/* Round, like the letter on an answer sheet. */
.opt .key {
  flex: 0 0 26px; width: 26px; height: 26px; display: grid; place-items: center;
  border: 1.5px solid var(--border-strong); border-radius: 50%;
  font-size: 13px; font-weight: 700; color: var(--ink-2);
}
.opt[aria-pressed="true"] { border-color: var(--brand-600); background: var(--brand-050); }
.opt[aria-pressed="true"] .key { background: var(--brand-600); border-color: var(--brand-600); color: #fff; }
.opt.is-correct { border-color: var(--ok); background: var(--ok-bg); }
.opt.is-correct .key { background: var(--ok); border-color: var(--ok); color: #fff; }
.opt.is-wrong { border-color: var(--danger); background: var(--danger-bg); }
.opt.is-wrong .key { background: var(--danger); border-color: var(--danger); color: #fff; }
.opt.struck .opt-text { text-decoration: line-through; opacity: .45; }
/* Crossing a choice out is the pencil move, so the control is the letter
   again, outside the pill, and it wears the line it puts through the choice. */
.opt-strike {
  margin-left: auto; flex: 0 0 26px; width: 26px; height: 26px;
  display: grid; place-items: center;
  border: 1px solid var(--border); border-radius: 50%; background: transparent;
  cursor: pointer; color: var(--muted); font-size: 12px; font-weight: 700;
}
.opt-strike:hover { border-color: var(--ink-2); color: var(--ink); }
.opt-strike.is-struck { text-decoration: line-through; border-color: var(--ink-2); color: var(--ink-2); }
.opt-text { flex: 1; min-width: 0; }

.spr-box { max-width: 320px; }
.spr-preview { font-family: var(--mono); font-size: 15px; padding: 8px 12px; border-radius: var(--r-sm); background: var(--bg); }

mark.hl { background: #FFE27A; color: var(--brand-950); padding: 0 1px; }
html[data-theme="dark"] mark.hl { background: #8C7415; color: #FFF7DA; }

.q-footer {
  position: sticky; bottom: var(--q-bottom); z-index: 25;
  display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap;
  padding: 10px 16px; border-top: 1px solid var(--border); background: var(--surface);
  box-shadow: 0 -2px 0 var(--border);
}
.q-jump {
  flex: none; border: 1px solid transparent; border-radius: var(--r-md);
  background: transparent; color: var(--muted);
  padding: 7px 10px; font-size: 13.5px; font-weight: 650; cursor: pointer;
  font-variant-numeric: tabular-nums;
}
.q-jump:hover { border-color: var(--border-strong); color: var(--ink); }

/* The set, numbered, in the middle of the bar: where you are and how much is
   left, without opening anything. It takes the spare width and scrolls inside
   itself on a phone rather than pushing the buttons off the bar. */
.q-rail {
  flex: 1 1 auto; min-width: 0;
  display: flex; justify-content: center; gap: 6px;
  overflow-x: auto; scrollbar-width: none; padding: 2px;
}
.q-rail::-webkit-scrollbar { display: none; }
.q-step {
  flex: 0 0 34px; width: 34px; height: 34px; display: grid; place-items: center;
  border: 1px solid var(--border); border-radius: var(--r-sm); background: var(--surface);
  font: inherit; font-size: 13px; font-weight: 700; color: var(--ink-2);
  font-variant-numeric: tabular-nums; cursor: pointer; position: relative;
}
.q-step:hover { border-color: var(--brand-500); color: var(--brand-700); background: var(--brand-050); }
.q-step.is-answered { border-color: var(--brand-400); background: var(--brand-050); color: var(--brand-700); }
.q-step.is-here {
  background: var(--brand-600); border-color: var(--brand-600); color: #fff; cursor: default;
}
.q-step.is-marked::after {
  content: "\2691"; position: absolute; top: -5px; right: -3px; font-size: 11px; color: var(--warn);
}
@media (max-width: 760px) {
  /* A rail and five controls do not fit one phone row, and shrinking either
     makes both unusable. The rail takes a row of its own above them and
     scrolls inside it; the controls keep their size and wrap. */
  .q-rail { order: -1; flex: 1 1 100%; justify-content: flex-start; }
  .q-footer { gap: 8px; padding-inline: 10px; }
  .q-step { flex: 0 0 30px; width: 30px; height: 30px; }
}
.q-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(42px,1fr)); gap: 7px; }
.q-grid button {
  aspect-ratio: 1/1; border-radius: var(--r-sm); border: 1.5px solid var(--border-strong);
  background: var(--surface); font-size: 13px; font-weight: 700; cursor: pointer; position: relative;
}
.q-grid button.answered { background: var(--brand-600); border-color: var(--brand-600); color: #fff; }
.q-grid button.current { outline: 2px solid var(--ink); outline-offset: 1px; }
.q-grid button.marked::after {
  content: "\2691"; position: absolute; top: -6px; right: -4px; font-size: 12px; color: var(--warn);
}

.q-side {
  border-left: 1px solid var(--border); background: var(--surface-2);
  display: flex; flex-direction: column; max-height: calc(100vh - var(--header-h));
  position: sticky; top: var(--header-h);
}
.q-side-body { overflow-y: auto; padding: 14px 16px 24px; flex: 1; }
.ai-msg { border-radius: var(--r-md); padding: 11px 13px; font-size: 14px; line-height: 1.55; background: var(--surface); border: 1px solid var(--border); }
.ai-msg + .ai-msg { margin-top: 10px; }
.ai-msg.from-user { background: var(--brand-050); border-color: var(--brand-100); }
.ai-actions { display: flex; gap: 6px; margin-top: 8px; }

.ref-table { width: 100%; border-collapse: collapse; font-size: 13.5px; }
.ref-table td { padding: 7px 9px; border-bottom: 1px solid var(--border); vertical-align: middle; }
.ref-table td:first-child { color: var(--muted); width: 45%; }

/* ----- 18. Desmos panel --------------------------------------------------- */
/* The closed panel is display:none rather than parked off-screen: a
   transformed fixed element still extends the document's scrollable width,
   which put a horizontal scrollbar on every page at phone width. Toggling
   display does not reload the iframe — only removing or reparenting it does. */
#desmos-panel {
  position: fixed; top: var(--header-h); right: 0; bottom: 0; width: min(560px, 92vw);
  z-index: 60; background: var(--surface); border-left: 1px solid var(--border);
  box-shadow: var(--shadow-3); display: none; flex-direction: column;
}
#desmos-panel.open { display: flex; animation: dp-in .22s ease; }
@keyframes dp-in { from { transform: translateX(100%); } to { transform: translateX(0); } }
/* The panel is fixed, so without this the question footer sits underneath it
   and Next becomes unclickable while the calculator is open. */
@media (min-width: 1024px) {
  body.desmos-open .q-shell { margin-right: min(560px, 92vw); }
}
#desmos-panel .dp-head {
  display: flex; align-items: center; gap: 10px; padding: 9px 12px;
  border-bottom: 1px solid var(--border); cursor: move; user-select: none;
  touch-action: none;
}
.dp-grip { color: var(--muted); font-size: 13px; }
/* Dragged out of the dock, the calculator becomes a window: placed by the
   student, resized from its own corner, floating over the question rather than
   beside it — which is how the calculator behaves in the real test. */
#desmos-panel.floating {
  top: auto; right: auto; bottom: auto; border: 1px solid var(--border);
  overflow: hidden; resize: both; min-width: 300px; min-height: 240px;
  max-width: 100vw; max-height: 100vh; animation: none;
}
/* Without this the iframe eats the pointer the instant the cursor crosses it. */
#desmos-panel.dragging iframe { pointer-events: none; }
#desmos-panel iframe { flex: 1; width: 100%; border: 0; background: #fff; }
#desmos-fallback { padding: 20px; }
.desmos-embed { width: 100%; height: 420px; border: 1px solid var(--border); border-radius: var(--r-md); background: #fff; }

/* ----- 19. Plan / calendar ------------------------------------------------ */
.week-grid { display: grid; grid-template-columns: repeat(7, minmax(0,1fr)); gap: 8px; }
.day-col { border: 1px solid var(--border); border-radius: var(--r-md); background: var(--surface); padding: 10px 9px; min-height: 120px; }
.day-col.today { border-color: var(--brand-600); box-shadow: 0 0 0 2px var(--brand-100); }
.day-name { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; color: var(--muted); }
.day-date { font-size: 17px; font-weight: 700; margin-bottom: 6px; }
/* The chips inside a day column are the calendar's own (section 25): the week
   and the month are one calendar, so an entry looks the same in both. */
.day-col .cal-tag + .cal-tag { margin-top: 5px; }

/* ----- 20. Flashcards ----------------------------------------------------- */
/* The card is a <button> so it is reachable by keyboard, which means undoing
   the UA button chrome: otherwise its grey background shows through the 3D
   perspective box and `margin: 0 auto` cannot centre an inline-block. */
.flash {
  display: block; border: 0; background: none; padding: 0; font: inherit; color: inherit;
  perspective: 1200px; width: 100%; max-width: 520px; height: 260px; margin: 0 auto; cursor: pointer;
}
.flash-inner { position: relative; width: 100%; height: 100%; transition: transform .5s; transform-style: preserve-3d; }
.flash.flipped .flash-inner { transform: rotateY(180deg); }
/* A white face on a white card with neither a corner nor a shadow to separate
   them needs the border to do the work, so it is 2px and brand-tinted. */
.flash-face {
  position: absolute; inset: 0; backface-visibility: hidden; -webkit-backface-visibility: hidden;
  border: 2px solid var(--brand-300); background: var(--surface);
  padding: 24px; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 10px; text-align: center; overflow-y: auto;
}
.flash-back { transform: rotateY(180deg); background: var(--brand-050); }
.vocab-stage { max-width: 680px; margin: 0 auto; display: flex; flex-direction: column; gap: var(--sp-4); }
.vocab-stage .row, .vocab-stage .row-between { width: 100%; }
.vocab-grades { display: grid; grid-template-columns: minmax(0,1fr); gap: 6px; }

/* ----- 20a. Vocabulary hub ------------------------------------------------
   The vocabulary screen opens on what a student can do with the deck rather
   than on one exercise with the rest behind a tab strip. Each card is an
   address of its own. */
.ex-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 12px; }
.ex-card {
  display: flex; align-items: flex-start; gap: 12px; padding: 14px;
  border: 1px solid var(--border-strong); background: var(--surface);
  color: var(--ink); text-decoration: none;
}
.ex-card:hover { border-color: var(--brand-500); background: var(--brand-050); text-decoration: none; }
.ex-icon {
  flex: 0 0 38px; width: 38px; height: 38px; display: grid; place-items: center;
  background: var(--brand-100); color: var(--brand-700); font-size: 17px;
}
.ex-text { display: flex; flex-direction: column; gap: 3px; min-width: 0; flex: 1; }
.ex-text b { font-size: 15px; line-height: 1.25; }
.ex-stat { font-size: 11.5px; font-weight: 700; color: var(--brand-700); margin-top: 2px; }
.ex-go { color: var(--muted); }
.ex-card:hover .ex-go { color: var(--brand-600); }

/* ----- 20b. Vocabulary games ---------------------------------------------
   Match is two columns of tiles; the quizzes reuse the question screen's own
   option list, because a student should meet one shape of answer button in
   this platform and not three. */
.mg-board { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr); gap: 10px; }
.mg-col { display: flex; flex-direction: column; gap: 8px; }
.mg-tile {
  border: 1.5px solid var(--border-strong); background: var(--surface); color: var(--ink);
  font: inherit; font-size: 14px; line-height: 1.35; text-align: start;
  padding: 10px 12px; cursor: pointer; min-height: 46px;
}
.mg-word { font-weight: 750; }
.mg-def { font-size: 13px; color: var(--ink-2); }
.mg-tile:hover:not(:disabled) { border-color: var(--brand-500); background: var(--brand-050); }
.mg-tile.sel { border-color: var(--brand-600); background: var(--brand-050); box-shadow: inset 0 0 0 1px var(--brand-600); }
.mg-tile.done { opacity: .45; border-style: dashed; cursor: default; background: var(--ok-bg); border-color: var(--ok); }
.mg-tile.miss { border-color: var(--danger); background: var(--danger-bg); animation: mg-shake .32s; }
@keyframes mg-shake {
  0%, 100% { transform: translateX(0); }
  25% { transform: translateX(-4px); }
  75% { transform: translateX(4px); }
}
@media (max-width: 560px) { .mg-board { grid-template-columns: minmax(0, 1fr); } }

.quiz-prompt { font-size: 16px; line-height: 1.7; }
/* The blank is a rule of fixed width, so the sentence does not reflow when the
   answer is revealed — and nothing about its length hints at the word. */
.quiz-blank {
  display: inline-block; width: 96px; border-bottom: 2px solid var(--brand-600);
  margin-inline: 3px; vertical-align: baseline;
}

/* ----- 21. Misc ----------------------------------------------------------- */
.video-slot {
  border: 2px dashed var(--border-strong); border-radius: var(--r-md);
  padding: 26px; text-align: center; color: var(--muted); background: var(--surface-2);
}
/* With a video in it the slot IS the video: the dashed box is the empty
   state's styling and has no business framing a player.

   Two elements, not one. 16:9 comes from padding-bottom rather than
   aspect-ratio so the height is right in whatever browser a student turns up
   with — but a percentage padding resolves against the PARENT's width, so the
   cap has to live on a wrapper. With both on one element the slot read
   820px wide and 602px tall, which is 56.25% of the card, not of the video. */
/* The lesson number sits before the title, not after it: it is part of the
   name of the section, not a label on it. */
.dg-lesson { flex: none; margin-inline-end: 2px; }
/* A lesson: the video on the left, the calculator open on the right. */
.dg-pair { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--sp-4); align-items: start; }
.dg-pair .video-wrap { max-width: none; }
.dg-calc { min-width: 0; }
.dg-calc .desmos-embed { display: block; height: clamp(360px, 62vh, 640px); }
@media (max-width: 1100px) { .dg-pair { grid-template-columns: minmax(0, 1fr); } }

.video-wrap { width: 100%; max-width: 820px; margin-inline: auto; }
.video-slot.has-video {
  position: relative; height: 0; padding: 0 0 56.25% 0; width: 100%;
  border: 1px solid var(--border-strong); background: #000;
}
.video-slot.has-video iframe {
  position: absolute; inset: 0; width: 100%; height: 100%; border: 0;
}
/* The one floating control in the app: add a word, from anywhere. */
.fab {
  position: fixed; right: 20px; bottom: 20px; z-index: 50;
  width: 54px; height: 54px; border: 0; cursor: pointer;
  background: var(--brand-600); color: #fff; font-size: 26px; line-height: 1;
  box-shadow: var(--shadow-3);
}
.fab:hover { background: var(--brand-700); }
@media (max-width: 1023px) {
  /* Clear of the tab bar, which owns the bottom of a phone screen. */
  .fab { bottom: calc(var(--tabbar-h) + 12px); right: 14px; }
}

.chart-wrap { width: 100%; overflow-x: auto; }
svg.chart { display: block; max-width: 100%; height: auto; }
.legend { display: flex; gap: 14px; flex-wrap: wrap; font-size: 12px; color: var(--muted); }
.legend span { display: inline-flex; align-items: center; gap: 5px; }

.countdown { display: flex; gap: var(--sp-5); flex-wrap: wrap; }
.countdown .cd-num { font-size: 38px; font-weight: 750; line-height: 1; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.countdown .cd-lab { font-size: 11px; text-transform: uppercase; letter-spacing: .08em; opacity: .75; }

.desktop-only-note { display: none; }

/* The break clock is one big number, not the onboarding countdown's row of
   day/hour/minute tiles — different widget, different class. */
.break-clock {
  font-size: 54px; font-weight: 750; line-height: 1; letter-spacing: -.02em;
  font-variant-numeric: tabular-nums; color: var(--ink);
}
@media (max-width: 560px) {
  /* "1 of 24" already says where the student is, so the long form goes and the
     footer stays one row instead of wrapping Next onto a line of its own. */
  .q-footer > .small { display: none; }
}
@media (max-width: 760px) { .break-clock { font-size: 40px; } }

/* ----- 22. Responsive ----------------------------------------------------- */
@media (max-width: 1023px) {
  /* Below a laptop the sidebar is a drawer. It parks to the LEFT, which cannot
     widen the document the way a right-hand transform can, so this does not
     reintroduce the horizontal scrollbar the Desmos panel once caused. */
  .app-sidebar {
    z-index: 60;
    transform: translateX(-100%); transition: transform .2s ease;
    box-shadow: var(--shadow-3);
  }
  .app-body, .app-sidebar[hidden] + .app-body { margin-left: 0; }
  body.sb-open .app-sidebar { transform: translateX(0); }
  body.sb-open::after {
    content: ""; position: fixed; inset: 0; z-index: 55;
    background: rgba(18,14,48,.55);
  }
  .tb-menu {
    display: inline-grid; place-items: center; width: 34px; height: 34px;
    border: 1px solid var(--border-strong); background: var(--surface);
    color: var(--ink); font-size: 18px; cursor: pointer; align-self: center;
  }
  .tb-menu:hover { border-color: var(--brand-600); color: var(--brand-700); }
  .app-topbar { padding-inline: 16px; }
  .container { padding-inline: 16px; }

  .q-main.with-side { grid-template-columns: minmax(0,1fr); }
  .q-side { position: fixed; inset: var(--header-h) 0 0 auto; width: min(420px,100%); z-index: 55; border-left: 1px solid var(--border); max-height: none; }
  .q-split { grid-template-columns: minmax(0,1fr); }
  .q-passage { border-right: 0; border-bottom: 1px solid var(--border); padding-right: 0; padding-bottom: var(--sp-4); }
  .grid-4 { grid-template-columns: repeat(2, minmax(0,1fr)); }
  .desktop-only-note { display: block; }
}

@media (max-width: 760px) {
  body { font-size: 15px; padding-bottom: var(--tabbar-h); }
  .phase-track > div { flex: 0 0 auto; padding-inline: 12px; }
  .tb-title { font-size: 19px; }
  .tb-date { display: none; }
  .grid-2, .grid-3, .grid-4 { grid-template-columns: minmax(0,1fr); }
  .card { padding: var(--sp-4); border-radius: var(--r-md); }
  .h1 { font-size: 22px; }
  .week-grid { grid-template-columns: repeat(2, minmax(0,1fr)); }
  .tabbar {
    display: flex; position: fixed; left: 0; right: 0; bottom: 0; z-index: 45;
    height: var(--tabbar-h); background: var(--surface); border-top: 1px solid var(--border);
    padding-bottom: env(safe-area-inset-bottom);
  }
  .tabbar a {
    flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
    font-size: 10.5px; font-weight: 650; color: var(--muted); text-decoration: none;
  }
  .tabbar a em { font-style: normal; font-size: 17px; line-height: 1; }
  .tabbar a[aria-current="page"] { color: var(--brand-700); box-shadow: inset 0 3px 0 var(--brand-600); }
  #desmos-panel { top: 0; width: 100%; }
  /* A floating window inside a phone screen is just a smaller phone screen. */
  #desmos-panel.floating {
    left: 0 !important; top: 0 !important; right: 0; bottom: 0;
    width: 100% !important; height: auto !important; resize: none;
  }
  .q-shell { --q-bottom: var(--tabbar-h); }
  body.no-frame .q-shell { --q-bottom: 0px; }
  .countdown { gap: var(--sp-4); }
  .countdown .cd-num { font-size: 30px; }
}

/* ----- 23. Sign-in landing ------------------------------------------------
   The header is hidden while signed out, so this screen is the whole window
   and is the only place the brand gets to speak at full volume. */
.auth-page {
  min-height: 100vh;
  background:
    linear-gradient(155deg, var(--brand-950) 0%, var(--brand-800) 52%, var(--brand-600) 100%);
  display: flex; align-items: center; justify-content: center;
  padding: 40px 16px;
}
.auth-panel { width: 100%; max-width: 440px; }
.auth-head { text-align: center; color: #fff; margin-bottom: var(--sp-5); }
.auth-head .brand-mark {
  width: 56px; height: 56px; font-size: 18px; margin: 0 auto var(--sp-4);
  background: #fff; color: var(--brand-700);
}
.auth-head .auth-title { font-size: 30px; font-weight: 750; letter-spacing: -.02em; line-height: 1.15; }
.auth-head .eyebrow { color: var(--eyebrow-on-dark); margin-top: 6px; }
.auth-page .card { border-color: transparent; box-shadow: var(--shadow-3); }
/* Rules and dividers inside a white card sitting on saturated purple read
   better one step up the ramp than the page-level border colour. */
.auth-page .card .divider { background: var(--brand-100); }
.auth-foot { text-align: center; color: rgba(255,255,255,.66); font-size: 12px; margin-top: var(--sp-4); }
@media (max-width: 760px) {
  .auth-head .auth-title { font-size: 25px; }
}

/* ----- 23a. Goal step: the target, and where it lands ---------------------
   Two columns, because the two halves answer each other: the score on the
   left, and what that score reaches on the right, recomputed as it is typed. */
.goal-split {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr);
  gap: var(--sp-6); align-items: start;
}
.goal-unis { min-width: 0; }
.uni-list {
  display: flex; flex-direction: column; gap: 8px;
  max-height: 520px; overflow-y: auto;
  /* A frame, so the cut-off row at the bottom reads as a list that scrolls
     rather than as a card that failed to render. */
  border: 1px solid var(--border); padding: 8px; background: var(--bg);
  scrollbar-gutter: stable;
}
.uni-row {
  width: 100%; text-align: start; cursor: pointer;
  display: flex; flex-direction: column; gap: 5px;
  border-inline-start-width: 3px;
}
.uni-fit {
  font-size: 10.5px; font-weight: 750; text-transform: uppercase; letter-spacing: .05em;
  white-space: nowrap;
}
/* The band is carried by the edge of the row as well as by its label, so the
   list can be read by shape before it is read by word. */
.uni-row.fit-above { border-inline-start-color: var(--ok); }
.uni-row.fit-inside { border-inline-start-color: var(--brand-600); }
.uni-row.fit-near { border-inline-start-color: var(--warn); }
.uni-row.fit-below { border-inline-start-color: var(--border); }
.fit-above .uni-fit { color: var(--ok); }
.fit-inside .uni-fit { color: var(--brand-700); }
.fit-near .uni-fit { color: var(--warn); }
.fit-below .uni-fit { color: var(--muted); }
@media (max-width: 900px) {
  .goal-split { grid-template-columns: minmax(0, 1fr); }
  .uni-list { max-height: none; }
}

/* ----- 23b. Setup header --------------------------------------------------
   Onboarding and the diagnostic run before there is anywhere to navigate to,
   so the sidebar, the top bar and the tab bar are not built at all. These two
   screens carry the brand and the controls that still mean something. */
.setup-bar {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-4); flex-wrap: wrap; margin-bottom: var(--sp-5);
}
.setup-brand { display: flex; align-items: center; gap: 10px; }
.setup-brand .brand-mark { width: 36px; height: 36px; font-size: 12px; }
.setup-brand .brand-text b { display: block; font-size: 15px; line-height: 1.1; }
.setup-brand .brand-text span {
  display: block; font-size: 10px; font-weight: 700; letter-spacing: .09em;
  text-transform: uppercase; color: var(--muted);
}
.setup-bar .sb-tools { display: flex; align-items: center; gap: 6px; }
/* Both controls were drawn for the dark sidebar; on a light page their own
   colours have to be restated or the inactive languages are white on white. */
.setup-bar .lang-switch { border-color: var(--border-strong); }
.setup-bar .lang-switch button { color: var(--muted); }
.setup-bar .lang-switch button:hover { background: var(--brand-050); color: var(--brand-700); }
.setup-bar .lang-switch button[aria-pressed="true"] { background: var(--brand-600); color: #fff; }
.setup-bar .icon-btn {
  width: 32px; height: 32px; font-size: 14px;
  border-color: var(--border-strong); background: var(--surface); color: var(--ink-2);
}
.setup-bar .icon-btn:hover { background: var(--brand-050); border-color: var(--brand-500); color: var(--brand-700); }
.setup-brand .brand-mark { background: var(--brand-600); color: #fff; }

/* ----- 23c. Onboarding ----------------------------------------------------
   The way forward never leaves the screen, and a score is never typed when it
   can be pressed. */
.onb-foot {
  position: sticky; bottom: 0; z-index: 5;
  /* Pulled out to the card's edges so the rule reads as the card's own base. */
  margin: 4px calc(var(--sp-5) * -1) calc(var(--sp-5) * -1);
  padding: 12px var(--sp-5);
  background: var(--surface); border-top: 1px solid var(--border);
}
.onb-count { flex: 0 0 auto; }
@media (max-width: 1023px) {
  .onb-foot {
    bottom: var(--tabbar-h, 0px);
    margin: 4px calc(var(--sp-4) * -1) calc(var(--sp-4) * -1);
    padding: 12px var(--sp-4);
  }
}
@media (max-width: 420px) { .onb-count { display: none; } }

.score-row { display: flex; align-items: stretch; gap: 0; }
.score-row .input { text-align: center; border-radius: 0; min-width: 0; }
.score-step {
  flex: 0 0 42px; border: 1px solid var(--border-strong); background: var(--surface);
  color: var(--brand-700); font: inherit; font-size: 18px; line-height: 1; cursor: pointer;
}
.score-step:first-child { border-inline-end: 0; }
.score-step:last-child { border-inline-start: 0; }
.score-step:hover { background: var(--brand-050); border-color: var(--brand-500); }
/* The browser's own spinner duplicates the two buttons either side of it. */
.score-in::-webkit-outer-spin-button, .score-in::-webkit-inner-spin-button {
  -webkit-appearance: none; margin: 0;
}
.score-in { -moz-appearance: textfield; appearance: textfield; }

/* ----- 23d. Exam dates ----------------------------------------------------
   Each administration as a tear-off from a calendar: the month on the band,
   the day under it, and one line saying what to do about it. A date, two
   deadlines and a region run together in a sentence is how a beginner misses
   a registration. */
.date-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(232px, 1fr)); gap: 10px; }
.date-card {
  display: flex; gap: 12px; align-items: flex-start; cursor: pointer;
  border: 1px solid var(--border-strong); background: var(--surface); padding: 11px 12px;
}
.date-card:hover { border-color: var(--brand-500); }
.date-card:has(input:checked) {
  border-color: var(--brand-600); background: var(--brand-050);
  box-shadow: inset 0 0 0 1px var(--brand-600);
}
.date-card:focus-within { outline: 2px solid var(--brand-500); outline-offset: 2px; }
.date-tear {
  flex: 0 0 54px; width: 54px; text-align: center; overflow: hidden;
  border: 1px solid var(--border); background: var(--surface);
}
.date-tear b {
  display: block; background: var(--brand-600); color: #fff;
  font-size: 10px; font-weight: 750; letter-spacing: .08em; text-transform: uppercase; padding: 3px 0;
}
.date-tear span { display: block; font-size: 23px; font-weight: 800; line-height: 1.1; padding-top: 5px; }
.date-tear i { display: block; font-style: normal; font-size: 10px; color: var(--muted); padding-bottom: 5px; }
.date-card.is-late .date-tear b { background: var(--warn); }
.date-card.is-closed .date-tear b { background: var(--muted); }
.date-card.is-closed .date-tear span { color: var(--muted); }
.date-main { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.date-when { font-size: 14px; font-weight: 750; text-transform: capitalize; }
.date-away { font-size: 12px; color: var(--brand-700); font-weight: 650; }
.date-left { font-size: 11.5px; font-weight: 650; color: var(--ok); }
.date-line { font-size: 11px; color: var(--muted); line-height: 1.35; }
.date-main .badge { align-self: flex-start; margin-block: 2px; }

/* ----- 24. Roadmap -------------------------------------------------------- */
/* A level map: one road from the diagnostic at the bottom to exam day at the
   top, a numbered stop per phase, a ring for how far through that phase you
   are, stars for the same thing at a glance. The whole screen is sized to the
   window — the road is meant to be seen at once, so nothing here is allowed to
   grow the page. That is also why the step you are reading sits in a column
   beside the map and not under it: stacked, either the road or the reading
   would have to be off screen. */
.rm-screen {
  display: flex; flex-direction: column; gap: var(--sp-4);
  padding-block: 20px 56px; max-width: 1560px;
  /* Room under the map, so it does not end on the window's edge.
     Everything but the top bar and this screen's own padding. */
  height: calc(100vh - var(--topbar-h) - 40px);
}
.rm-top { display: flex; align-items: flex-end; justify-content: space-between; gap: var(--sp-4); flex-wrap: wrap; }
.rm-top .h2 { margin: 0; }
.rm-top-who { min-width: 0; }

/* How far along the whole road, on one rule under the header. */
.rm-total { flex: 1 0 100%; display: flex; align-items: center; gap: var(--sp-3); }
.rm-total .bar { flex: 1; min-width: 0; }
.rm-total-lab, .rm-total-n {
  font-size: 11px; font-weight: 750; text-transform: uppercase; letter-spacing: .05em;
  color: var(--muted); white-space: nowrap;
}
.rm-total-n { color: var(--brand-700); }

.rm-body {
  flex: 1; min-height: 0;
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(330px, 420px);
  gap: var(--sp-4);
}
.rm-left { min-width: 0; min-height: 0; display: flex; flex-direction: column; gap: 10px; }
.rm-map { flex: 1; min-height: 0; display: flex; align-items: center; justify-content: center; }

.rm-stage {
  /* Sized in JS to the smaller of the column's two axes, because the stops are
     placed as percentages of a square drawing space and CSS cannot clamp on
     "whichever of width and height is smaller". These are the fallback, used
     for the one frame before the measurement lands. */
  --rm-h: min(clamp(240px, calc(100vh - 340px), 660px), calc(100vw - 40px));
  position: relative;
  height: var(--rm-h);
  width: var(--rm-h);
  flex: none;
  overflow: hidden;
  background:
    radial-gradient(120% 70% at 50% 108%, rgba(109, 90, 230, .18), transparent 62%),
    linear-gradient(180deg, var(--brand-050), var(--brand-100) 58%, var(--brand-200));
  border: 1px solid var(--border);
}
/* A faint grid, so the map has ground under it rather than a flat wash. */
.rm-stage::before {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background-image:
    linear-gradient(to right, rgba(74, 58, 184, .055) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(74, 58, 184, .055) 1px, transparent 1px);
  background-size: 7.5% 7.5%;
}
.rm-road { position: absolute; inset: 0; }
.rm-road svg { width: 100%; height: 100%; display: block; overflow: visible; }
.rm-road-edge, .rm-road-line, .rm-road-dash, .rm-road-done {
  fill: none; stroke-linecap: round; stroke-linejoin: round;
}
.rm-road-edge { stroke: rgba(43, 34, 112, .16); stroke-width: 36; }
.rm-road-line { stroke: #fff; stroke-width: 28; }
/* The road ahead keeps its centre dashes; the stretch already walked is
   painted over them in solid brand, so "done" is legible at a glance. Both
   were a shade too pale against a lavender stage to read as two states. */
.rm-road-dash {
  stroke: var(--brand-400); stroke-width: 3.5; stroke-dasharray: 3 15; opacity: 1;
}
.rm-road-done {
  stroke: var(--brand-600); stroke-width: 28;
  transition: stroke-dashoffset 1.1s cubic-bezier(.22, .61, .36, 1) .15s;
}
.rm-nodes { position: absolute; inset: 0; }

/* Each stop is a point, not a box: everything hangs off its centre, so the pin
   always sits exactly on the road however long the phase's name is. */
.rm-stop { position: absolute; width: 0; height: 0; }
.rm-in .rm-stop { animation: rm-pop .34s cubic-bezier(.2, 1.3, .5, 1) backwards; animation-delay: calc(var(--i, 0) * 55ms + 120ms); }
@keyframes rm-pop { from { opacity: 0; transform: scale(.4); } to { opacity: 1; transform: none; } }

/* The ring behind the pin is that phase's own progress: a conic sweep with the
   pin sitting on top of it, so only the rim shows. */
.rm-ring {
  position: absolute; left: 0; top: 0; transform: translate(-50%, -50%);
  width: 56px; height: 56px; border-radius: 50%;
  background: conic-gradient(var(--brand-600) calc(var(--p, 0) * 1%), rgba(255, 255, 255, .72) 0);
}
.rm-pin {
  position: absolute; left: 0; top: 0; transform: translate(-50%, -50%);
  width: 44px; height: 44px; border-radius: 50%; display: grid; place-items: center;
  font: inherit; font-size: 16px; font-weight: 800;
  border: 3px solid #fff; background: var(--brand-200); color: var(--brand-800);
  box-shadow: 0 3px 0 rgba(28, 22, 72, .18);
  padding: 0; transition: transform .14s ease, box-shadow .14s ease;
}
button.rm-pin { cursor: pointer; }
.rm-done .rm-pin { background: var(--brand-600); color: #fff; }
.rm-current .rm-pin { background: var(--brand-800); color: #fff; }
/* A gate is the one stop you can be stopped at, so it is the one stop drawn in
   a different colour rather than only a different glyph. */
.rm-gate .rm-pin { background: #ffeec2; color: #7a4a00; }
.rm-gate.rm-done .rm-pin { background: #e0a020; color: #fff; }
.rm-gate.rm-current .rm-pin { background: #a56a00; color: #fff; }
.rm-sel .rm-pin { box-shadow: 0 0 0 4px var(--brand-700), 0 3px 0 rgba(28, 22, 72, .18); }
.rm-sel .rm-pin, button.rm-pin:hover { transform: translate(-50%, -50%) scale(1.1); }
button.rm-pin:focus-visible {
  outline: none;
  box-shadow: 0 0 0 4px var(--brand-700), 0 0 0 7px var(--brand-200), 0 3px 0 rgba(28, 22, 72, .18);
}
/* The stop you are standing on breathes, so the eye finds it without reading. */
.rm-current .rm-ring { animation: rm-beat 2.6s ease-in-out infinite; }
@keyframes rm-beat {
  0%, 100% { box-shadow: 0 0 0 0 rgba(109, 90, 230, .42); }
  55%      { box-shadow: 0 0 0 11px rgba(109, 90, 230, 0); }
}

/* What kind of stop this is, above the pin where the stars used to sit. The
   stars were three greyed glyphs over an unstarted stop, which reads as a
   rating of the student rather than as progress — and the ring around the pin
   was already saying the same thing, accurately. */
.rm-kind {
  position: absolute; left: 0; top: 0; transform: translate(-32px, -24px);
  width: 20px; height: 20px; border-radius: 50%; display: grid; place-items: center;
  font-size: 11px; line-height: 1;
  background: #fff; color: var(--brand-700); border: 1px solid var(--brand-300);
}
.rm-gate .rm-kind { background: #fff7e6; color: #9a6400; border-color: #e6b053; }
.rm-done .rm-kind { background: var(--brand-600); color: #fff; border-color: var(--brand-600); }

/* A walked stop keeps its number and wears the tick on its shoulder, so the
   road still counts 1 to 6 all the way along. */
.rm-tick {
  position: absolute; left: 0; top: 0; transform: translate(10px, 10px);
  width: 20px; height: 20px; border-radius: 50%; display: grid; place-items: center;
  font-size: 11px; font-weight: 800; color: #fff;
  background: var(--ok); border: 2px solid #fff;
}

/* Every stop is named, always. The map folds back on itself so two names can
   come close; the pill background and a fixed width keep them readable where
   they do, and it is still far better than six numbers you must click to
   identify. */
.rm-name {
  position: absolute; left: 0; top: 26px; transform: translateX(-50%);
  width: 104px; text-align: center;
  font-size: 11px; line-height: 1.25; font-weight: 750; color: var(--ink-2);
  background: rgba(255, 255, 255, .88); border-radius: 9px; padding: 2px 4px;
}
/* Near an edge the label hangs inward from the pin rather than straddling it,
   so it stays on the stage at any size. */
.rm-edge-l .rm-name { transform: none; left: -14px; text-align: left; }
.rm-edge-r .rm-name { transform: translateX(-100%); left: 14px; text-align: right; }
.rm-ahead .rm-name { color: var(--muted); }
.rm-sel .rm-name, .rm-current .rm-name {
  color: #fff; background: var(--brand-800); z-index: 3;
}

/* The prize at the end of the road, square where the stops are round. */
.rm-gift {
  position: absolute; left: 0; top: 0; transform: translate(-50%, -50%);
  width: 50px; height: 50px; display: grid; place-items: center; font-size: 22px;
  background: linear-gradient(160deg, #ffd86b, #f0a92b); color: #7a4a00;
  border: 3px solid #fff; box-shadow: 0 3px 0 rgba(28, 22, 72, .18);
  padding: 0; font-family: inherit; cursor: pointer;
  transition: transform .14s ease;
}
.rm-gift:hover { transform: translate(-50%, -50%) scale(1.08) rotate(-4deg); }
.rm-gift:focus-visible { outline: none; box-shadow: 0 0 0 4px var(--brand-700), 0 3px 0 rgba(28, 22, 72, .18); }
.rm-goal .rm-name { top: 30px; }

/* You, standing on the stop you are on. Inner side, so it never covers a name. */
.rm-here {
  position: absolute; left: 0; top: 0;
  width: 26px; height: 26px; border-radius: 50%; display: grid; place-items: center;
  font-size: 10px; font-weight: 800; color: #fff;
  background: var(--brand-600); border: 2px solid #fff;
}
.rm-here { transform: translate(14px, -26px); z-index: 4; }

/* The step you are reading. Its own scroller, so a long phase cannot push the
   road off the screen. */
/* The panel has the column to itself and takes all of it, so the longest
   phase in the wordiest language still reads without a scrollbar. */
.rm-panel-host { min-width: 0; min-height: 0; display: flex; }
.rm-panel {
  /* As tall as its own content, up to the column. Stretching it to the full
     height left half a card of white under the button on a short stop. */
  flex: 1 1 auto; align-self: flex-start;
  min-width: 0; max-height: 100%; overflow-y: auto;
  display: flex; flex-direction: column; gap: var(--sp-3);
  border-top: 3px solid var(--border-strong);
  animation: rm-enter .26s ease-out;
}
.rm-panel.is-current { border-top-color: var(--brand-600); }
.rm-panel.is-done { border-top-color: var(--ok); }
@keyframes rm-enter { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

.rm-panel-head { display: flex; align-items: center; gap: var(--sp-3); }
.rm-panel-n {
  flex: none; width: 42px; height: 42px; display: grid; place-items: center;
  font-size: 18px; font-weight: 800;
  background: var(--brand-100); color: var(--brand-700);
}
.rm-panel.is-current .rm-panel-n { background: var(--brand-600); color: #fff; }
.rm-panel.is-done .rm-panel-n { background: var(--ok-bg); color: var(--ok); }
.rm-panel-title { min-width: 0; }
.rm-panel-title .h2 { margin: 0; }
.rm-panel-desc { margin: 0; }
.rm-panel-bar { display: flex; flex-direction: column; gap: 4px; }
.rm-panel-foot {
  padding-top: var(--sp-3); border-top: 1px solid var(--border);
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-3); flex-wrap: wrap;
}

.rm-stepno {
  text-transform: uppercase; letter-spacing: .06em; font-weight: 750; color: var(--brand-600);
}
/* "What you do" / "By the end": a label and a sentence, on one line where
   there is room and stacked where there is not. */
.rm-fact { display: flex; gap: 8px; font-size: 13px; line-height: 1.45; }
.rm-fact-lab {
  flex: 0 0 90px; font-size: 11px; font-weight: 750; text-transform: uppercase;
  letter-spacing: .05em; color: var(--muted); padding-top: 2px;
}

/* Under about 1040px the two columns stop being two columns: the panel would
   be narrower than its own sentences. The road goes back on top and the page
   is allowed to scroll, which on a phone is what a thumb expects anyway. */
@media (max-width: 1040px) {
  .rm-screen { height: auto; }
  .rm-body { grid-template-columns: minmax(0, 1fr); }
  .rm-stage { --rm-h: min(62vh, 560px, calc(100vw - 40px)); }
  .rm-panel { max-height: none; overflow: visible; }
  .rm-panel-foot { margin-top: 0; }
}
@media (max-width: 560px) {
  .rm-fact { flex-direction: column; gap: 1px; }
  .rm-fact-lab { flex: none; }
  .rm-stage { --rm-h: min(52vh, 420px, calc(100vw - 32px)); }
  .rm-panel-tags .badge { font-size: 10.5px; }
}
/* Asked not to be moved, not moved. */
@media (prefers-reduced-motion: reduce) {
  .rm-road-done, .rm-pin, .rm-gift { transition: none; }
  .rm-in .rm-stop, .rm-current .rm-ring, .rm-panel { animation: none; }
}

/* The three moves, for someone reading about the SAT for the first time. */
.rm-how {
  border: 1px solid var(--border); background: var(--surface); padding: 12px;
  display: flex; flex-direction: column; gap: 4px;
}
.rm-how-n {
  width: 24px; height: 24px; display: grid; place-items: center;
  background: var(--brand-600); color: #fff; font-size: 12px; font-weight: 750;
}

/* ----- 24a. Daily check ---------------------------------------------------- */
/* The fortnight as a strip. Squares and not a chart: the question it answers
   is "did I turn up", which is a yes or a no per day. */
.dc-strip { display: flex; gap: 3px; }
.dc-day {
  flex: 1 1 0; min-width: 0; height: 22px;
  background: var(--bg); border: 1px solid var(--border);
}
.dc-day.is-done { background: var(--brand-300); border-color: var(--brand-400); }
.dc-day.is-perfect { background: var(--ok); border-color: var(--ok); }
.dc-day.is-today { box-shadow: inset 0 0 0 2px var(--brand-700); }
.dc-stats { display: flex; gap: var(--sp-5); }
.dc-stat { display: flex; flex-direction: column; line-height: 1.15; }
.dc-stat b { font-size: 20px; font-weight: 750; font-variant-numeric: tabular-nums; }
.dc-stat span {
  font-size: 10.5px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .06em; color: var(--muted);
}

/* ----- 24b. First-visit tour ----------------------------------------------- */
/* A dimmed page with one control cut out of the dimming. The cut-out is four
   panels around the target rather than a ring with a huge shadow, because the
   shadow cannot be clicked through and the panels can simply not be drawn
   where the control is. */
.tour { position: fixed; inset: 0; z-index: 90; }
.tour-mask { position: fixed; background: rgba(18, 14, 48, .62); }
.tour-ring {
  position: fixed; pointer-events: none;
  border: 2px solid var(--brand-400); box-shadow: 0 0 0 2px rgba(255, 255, 255, .5);
}
.tour-bubble {
  position: fixed; z-index: 91; width: min(320px, calc(100vw - 24px));
  background: var(--surface); border: 1px solid var(--border-strong);
  border-top: 3px solid var(--brand-600);
  padding: var(--sp-4); box-shadow: 0 10px 30px rgba(18, 14, 48, .28);
  display: flex; flex-direction: column; gap: 6px;
}
.tour-count {
  font-size: 10.5px; font-weight: 750; text-transform: uppercase;
  letter-spacing: .06em; color: var(--brand-600);
}
.tour-title { font-size: 15px; font-weight: 750; color: var(--ink); }
.tour-body { margin: 0; font-size: 13px; line-height: 1.5; color: var(--ink-2); }
.tour-foot {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-2); margin-top: 4px;
}
.tour-foot .row { gap: var(--sp-2); }
/* Nothing behind the overlay is reachable while it is up, including the
   sticky top bar, which would otherwise sit over the dimming. */
body.tour-open { overflow: hidden; }
body.tour-open .app-topbar, body.tour-open #add-word { z-index: 1; }

/* ----- 24c. The programme ------------------------------------------------- */
/* Forty-five lessons in order, cut into weeks. A row is a number, a code and a
   name; the code chips are the same everywhere the programme is shown, so a
   lesson is recognisable before it is read. */
.pg-stage-head { display: flex; align-items: flex-end; justify-content: space-between; gap: var(--sp-3); flex-wrap: wrap; }
.pg-stage-head .h3 { margin: 0; }
.pg-lessons { display: flex; flex-direction: column; }
.pg-lesson {
  display: grid; grid-template-columns: 30px minmax(0, 1fr) auto;
  align-items: start; gap: 10px;
  padding: 7px 0; border-top: 1px solid var(--border);
}
.pg-lesson:first-child { border-top: 0; }
.pg-lesson.is-gate { background: var(--warn-bg); margin-inline: -6px; padding-inline: 6px; }
.pg-n {
  width: 26px; height: 22px; display: grid; place-items: center;
  font-size: 11.5px; font-weight: 800; color: var(--muted); background: var(--bg);
}
.pg-lesson.is-gate .pg-n { background: var(--warn); color: #fff; }
.pg-body { min-width: 0; }
.pg-name { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; font-size: 13px; }
.pg-practice {
  font-size: 10.5px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .04em; color: var(--muted);
}
.pg-topics { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; margin-top: 2px; }
.pg-topic-text { font-size: 12px; color: var(--muted); }
.pg-from-log { font-style: italic; }

/* A tag chip. The border carries the level, so hard topics are visible in a
   list of forty without reading a word of it. */
.pg-tag {
  display: inline-block; padding: 1px 5px;
  font-size: 10.5px; font-weight: 800; font-variant-numeric: tabular-nums;
  background: var(--brand-050); color: var(--brand-700);
  border: 1px solid var(--brand-200);
}
.pg-tag.lv-core { border-color: var(--brand-400); }
.pg-tag.lv-hard { background: var(--warn-bg); color: var(--warn); border-color: var(--warn); }
.pg-level {
  display: inline-block; margin-inline-end: 4px; padding: 0 5px;
  font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
  background: var(--bg); color: var(--muted); border: 1px solid var(--border);
}
.pg-level.lv-hard { background: var(--warn-bg); color: var(--warn); border-color: var(--warn); }
.pg-table td { vertical-align: top; }
.pg-table td:first-child { white-space: nowrap; }

.pg-zero { border-left: 3px solid var(--brand-600); }

/* A week's heading inside a phase: which week it is, and the practice test
   that closes it. The test is the gate's currency, so it is never implied. */
.pg-week {
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
  padding: 10px 6px 4px; margin-inline: -6px; border-top: 1px solid var(--border);
}
.pg-lessons > .pg-week:first-child { border-top: 0; }
.pg-week-n {
  font-size: 11px; font-weight: 800; text-transform: uppercase; letter-spacing: .06em;
  color: var(--ink-2);
}
.pg-week-test { font-size: 11px; font-weight: 650; color: var(--muted); }
.pg-lesson { border-top: 0; }
.pg-lessons > .pg-lesson + .pg-lesson { border-top: 1px solid var(--border); }

/* What follows every lesson, and the one thing that follows every week. */
.pg-hw { display: flex; flex-direction: column; gap: 10px; }
.pg-hw-item { display: flex; gap: 10px; align-items: flex-start; }
.pg-hw-n {
  flex: none; width: 22px; height: 22px; display: grid; place-items: center;
  background: var(--brand-600); color: #fff; font-size: 11px; font-weight: 750;
}
.pg-mins {
  margin-inline-start: 8px; font-size: 10.5px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .04em; color: var(--muted);
}

/* The weekly practice test is not homework like the others: it belongs to the
   week, so its marker is not a number in the sequence. */
.pg-hw-item.is-weekly .pg-hw-n { background: var(--warn); }

/* A gate is a checkpoint, not a stretch of road: its pin is marked out from
   the phases either side of it. */
.rm-stop.rm-gate .rm-pin { border-color: var(--warn); }
.rm-stop.rm-gate.rm-current .rm-pin, .rm-stop.rm-gate.rm-done .rm-pin { background: var(--warn); border-color: var(--warn); }
.rm-panel.is-current .rm-panel-n { background: var(--brand-600); }

/* The codes in a stretch, each a link into its own unit. */
.rm-codes { display: flex; flex-wrap: wrap; gap: 4px; }
/* A stop's topics by name, one row each, opening the unit. */
.rm-topics { display: flex; flex-direction: column; }
/* The panel still scrolls when a stop has more topics than fit, but without
   a scrollbar drawn down its side. */
.rm-panel { scrollbar-width: none; }
.rm-panel::-webkit-scrollbar { display: none; }

.rm-topics[hidden] { display: none; }
.rm-topic { padding: 7px 0; font-size: 13.5px; line-height: 1.35; color: var(--ink); }
.rm-topic + .rm-topic { border-top: 1px solid var(--border); }
/* The arrow that opens and closes the list. */
.rm-fold {
  display: flex; align-items: center; justify-content: space-between; gap: 10px; width: 100%;
  padding: 6px 0; background: none; border: 0; color: inherit; font: inherit; cursor: pointer; text-align: left;
}
.rm-fold-arrow { flex: none; font-size: 16px; line-height: 1; color: var(--muted); }
.rm-fold:hover .rm-fold-arrow { color: var(--brand-700); }
.rm-codes .pg-tag { text-decoration: none; }
.rm-codes .pg-tag:hover { background: var(--brand-200); text-decoration: none; }

/* The course under the roadmap. The map half is sized to the window; with the
   course below it the screen is a page again and has to be allowed to scroll. */
.rm-screen.has-course { height: auto; }
.rm-screen.has-course .rm-body { min-height: min(72vh, 680px); }
.rm-course { display: flex; flex-direction: column; gap: var(--sp-4); }

.gl-item { border-left: 2px solid var(--border-strong); padding-inline-start: 10px; }

/* The day's own detail, inside the modal the day opens. */
.pg-day-topic { display: flex; align-items: baseline; gap: 8px; font-size: 13px; line-height: 1.45; }
.pg-day-topic .pg-tag { flex: none; }

/* ----- 25. The calendar ---------------------------------------------------- */
/* One card holds the whole calendar: a toolbar, a legend of what the colours
   mean, and whichever of the three views is open. The colour of an entry says
   what kind of thing it is (a session, a checkpoint, a deadline, the exam);
   its state — done, skipped, moved — is said in the chip itself. */
.cal { padding: 0; overflow: hidden; }

.cal-bar {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-3) var(--sp-4); flex-wrap: wrap;
  padding: 12px var(--sp-4); border-bottom: 1px solid var(--border);
}
.cal-nav { display: flex; align-items: center; gap: 8px; min-width: 0; }
.cal-title-box { display: flex; flex-direction: column; line-height: 1.2; }
.cal-title { margin: 0 4px; white-space: nowrap; }
.cal-arrow {
  width: 30px; height: 30px; font-size: 17px; line-height: 1;
  background: var(--surface); border-color: var(--border); color: var(--ink-2);
}
.cal-arrow:hover { background: var(--brand-050); border-color: var(--brand-500); color: var(--brand-700); }
.cal-arrow.is-off { opacity: .4; pointer-events: none; }
.cal-bar-right { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

/* The view switch. Three links styled as one control, because that is what
   they are: the same plan, seen three ways. */
.cal-seg { display: inline-flex; border: 1px solid var(--border); background: var(--surface); }
.cal-seg a {
  padding: 6px 14px; font-size: 13px; font-weight: 650;
  color: var(--ink-2); text-decoration: none; border-inline-end: 1px solid var(--border);
}
.cal-seg a:last-child { border-inline-end: 0; }
.cal-seg a:hover { background: var(--brand-050); color: var(--brand-700); text-decoration: none; }
.cal-seg a[aria-pressed="true"] { background: var(--brand-600); color: #fff; }
.cal-filter {
  border: 1px solid var(--border); background: var(--surface); color: var(--ink);
  font: inherit; font-size: 13px; font-weight: 600; padding: 6px 10px;
}

/* The legend doubles as the filter: press a kind to see only it. */
.cal-legend {
  display: flex; align-items: center; gap: 6px 16px; flex-wrap: wrap;
  padding: 9px var(--sp-4); border-bottom: 1px solid var(--border);
  background: var(--surface-2);
}
.cal-key {
  display: inline-flex; align-items: center; gap: 7px;
  border: 0; background: none; cursor: pointer; padding: 2px 0;
  font: inherit; font-size: 12px; font-weight: 600; color: var(--muted);
}
.cal-key:hover { color: var(--ink); }
.cal-key[aria-pressed="true"] { color: var(--ink); text-decoration: underline; text-underline-offset: 3px; }

/* The dot carries the kind, in the legend and on every chip alike. */
.cal-dot {
  width: 7px; height: 7px; flex: 0 0 7px; border-radius: 50%;
  background: var(--brand-600); display: inline-block;
}
[data-type="test"] .cal-dot, .cal-key[data-type="test"] .cal-dot { background: var(--warn); }
[data-type="deadline"] .cal-dot, .cal-key[data-type="deadline"] .cal-dot { background: var(--danger); }
[data-type="exam"] .cal-dot, .cal-key[data-type="exam"] .cal-dot { background: var(--ok); }

/* ----- the month ----------------------------------------------------------- */
/* Header band and grid share one set of columns, and the grid lines are the
   gaps: cells sit on a background the width of a hairline rather than each
   carrying its own border. */
.cal-head, .cal-month { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); }
.cal-head { background: var(--surface-2); border-bottom: 1px solid var(--border); }
.cal-dow {
  font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em;
  color: var(--muted); padding: 8px 10px;
}
.cal-month { gap: 1px; background: var(--border); }
.cal-cell {
  min-height: 104px; background: var(--surface);
  padding: 6px 7px 8px; display: flex; flex-direction: column; gap: 4px;
}
.cal-evs { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.cal-out { background: var(--bg); }
.cal-out .cal-num { color: var(--muted); opacity: .7; }
.cal-out .cal-tag { opacity: .55; }
.cal-num {
  font-size: 12.5px; font-weight: 700; color: var(--ink-2);
  width: 22px; height: 22px; display: grid; place-items: center;
}
/* Today is a filled marker on the date itself, the way a calendar marks it,
   rather than a box around the whole square. */
.cal-today .cal-num { background: var(--brand-600); color: #fff; }
.cal-exam { background: var(--brand-050); }

.cal-tag {
  display: flex; align-items: center; gap: 6px; width: 100%; min-width: 0;
  text-align: left; border: 0; font: inherit; font-size: 11px; line-height: 1.3;
  font-weight: 600; padding: 3px 6px;
  background: var(--surface-2); color: var(--ink-2);
}
.cal-tag-text { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
/* A month square now carries the topic rather than "Lesson 7", and a topic is
   a sentence fragment, not three words. The square has the height to spare, so
   it wraps to three lines and clips after that; the dot stays at the top so a
   two-line chip does not push it into the middle of nowhere. */
.cal-month .cal-tag { align-items: flex-start; }
.cal-month .cal-dot { margin-top: 4px; }
.cal-month .cal-tag-text {
  white-space: normal; text-overflow: clip;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3;
}
/* The week's chips carry the skills as well as the label, so they are two
   lines and sit against the top of the dot rather than beside its middle. */
.cal-tag.is-rich { align-items: flex-start; padding: 7px 9px; font-size: 12px; }
.cal-tag.is-rich .cal-dot { margin-top: 5px; }
.cal-tag-body { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.cal-tag-body b { font-weight: 700; line-height: 1.3; }
.cal-tag-body span { font-size: 11px; font-weight: 600; opacity: .8; }
button.cal-tag { cursor: pointer; }
button.cal-tag:hover { background: var(--brand-100); color: var(--brand-700); }
.cal-tag[data-type="deadline"] { background: var(--danger-bg); color: var(--danger); }
.cal-tag[data-type="test"] { background: var(--warn-bg); color: var(--warn); }
.cal-tag-exam { background: var(--brand-600); color: #fff; }
.cal-tag-exam .cal-dot { background: #fff; }
.cal-tag.done { color: var(--ok); background: var(--ok-bg); }
.cal-tag.done .cal-dot { background: var(--ok); }
.cal-tag.skipped { color: var(--muted); text-decoration: line-through; }
.cal-tag.skipped .cal-dot { background: var(--border-strong); }
.cal-tag.moved { color: var(--warn); }
.cal-tag.moved .cal-dot { background: var(--warn); }

/* A day in the month is pressable, and says so on hover and on focus. */
.cal-cell.is-tappable { cursor: pointer; }
.cal-cell.is-tappable:hover { background: var(--brand-050); }
.cal-cell.is-tappable:focus-visible { outline: 2px solid var(--brand-700); outline-offset: -2px; }

/* ----- the list ------------------------------------------------------------ */
.cal-agenda { display: flex; flex-direction: column; }
.cal-ag-row {
  display: flex; gap: var(--sp-4); align-items: flex-start;
  padding: 10px var(--sp-4); border-bottom: 1px solid var(--border);
}
.cal-ag-row:last-child { border-bottom: 0; }
.cal-ag-row.is-today { background: var(--brand-050); }
.cal-ag-date {
  flex: 0 0 52px; display: flex; flex-direction: column; align-items: center;
  line-height: 1.15;
}
.cal-ag-date b { font-size: 19px; font-weight: 750; letter-spacing: -.02em; }
.cal-ag-date span {
  font-size: 10px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .06em; color: var(--muted);
}
.cal-ag-evs { display: flex; flex-direction: column; gap: 4px; flex: 1; min-width: 0; }
.cal-ag-evs .cal-tag { font-size: 12.5px; padding: 5px 9px; }

/* The week grid and the empty state sit inside the same card. */
.cal-body > .week-grid, .cal-body > .empty { padding: var(--sp-4); }


@media (max-width: 760px) {
  /* Seven columns of readable chips do not fit a phone, so the month becomes a
     scrolling strip rather than seven unreadable slivers. The header band
     scrolls with it, which is why both live in the same box. */
  .cal-month-wrap { overflow-x: auto; }
  .cal-head, .cal-month { min-width: 620px; }
  .cal-bar, .cal-legend { padding-inline: var(--sp-3); }
  .cal-bar { gap: 10px; }
}

/* ----- 26. Materials ------------------------------------------------------- */
/* One subtopic, one unit. There is no folder between the student and the
   topic: the card IS the topic, and its state is carried by the left edge and
   the mark rather than by a colour wash over the whole row. */
.mat-units { display: flex; flex-direction: column; gap: 8px; }
.mat-unit {
  display: flex; align-items: center; gap: 12px;
  border: 1px solid var(--border); border-left: 3px solid var(--border-strong);
  background: var(--surface); padding: 13px 14px;
  color: inherit; text-decoration: none;
}
.mat-unit:hover { background: var(--brand-050); text-decoration: none; }
.mat-unit:focus-visible { outline: 2px solid var(--brand-700); outline-offset: -2px; }
.mat-unit.is-done { border-left-color: var(--ok); }
.mat-unit.is-current { border-left-color: var(--brand-600); background: var(--brand-050); }
.mat-unit.is-current:hover { background: var(--brand-100); }

.mat-state {
  flex: 0 0 22px; width: 22px; height: 22px; display: grid; place-items: center;
  font-size: 12px; font-weight: 700; color: var(--muted);
  border: 1px solid var(--border-strong);
}
.mat-unit.is-done .mat-state { color: var(--ok); border-color: var(--ok); }
.mat-unit.is-current .mat-state { color: #fff; background: var(--brand-600); border-color: var(--brand-600); }
.mat-unit-text { display: flex; flex-direction: column; gap: 2px; flex: 1; min-width: 0; }
.mat-unit-text b { font-size: 15px; font-weight: 650; line-height: 1.3; }
.mat-go { color: var(--border-strong); font-size: 11px; }
.mat-unit:hover .mat-go { color: var(--brand-700); }

@media (max-width: 560px) {
  .mat-unit { padding: 11px 12px; gap: 10px; }
  .mat-unit .pg-tag { display: none; }
}

/* ----- 27. One lesson ------------------------------------------------------ */
/* The rule and the trap are the whole explanation, so they are set apart from
   each other: one is what is true, the other is how the test uses it. */
.lesson-rule { border-left: 3px solid var(--brand-600); padding-inline-start: 12px; }
.lesson-trap { border-left: 3px solid var(--warn); padding-inline-start: 12px; }
.lesson-rule p, .lesson-trap p { margin: 2px 0 0; }
#lesson-nav { gap: 10px; }


/* ----- 28. The dashboard hero ---------------------------------------------- */
/* The clock the whole course runs on, and the two things a student does with
   this screen. Days, hours, minutes and seconds: a countdown that only counts
   days is a number you can ignore for twenty-three hours. */
.today-hero {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-5) var(--sp-6); flex-wrap: wrap;
  padding: var(--sp-5) var(--sp-5);
  background: linear-gradient(135deg, var(--brand-700), var(--brand-500));
  border-color: transparent; color: #fff;
}
.hero-left { flex: 1 1 320px; min-width: 0; display: flex; flex-direction: column; gap: 10px; }
.hero-title { font-size: 26px; font-weight: 750; letter-spacing: -.02em; line-height: 1.15; }
.hero-lead { margin: 0; font-size: 14px; color: rgba(255,255,255,.82); max-width: 46ch; }
.hero-actions { gap: 10px; }
.hero-btn {
  background: rgba(0,0,0,.24); border-color: rgba(255,255,255,.28); color: #fff;
  font-weight: 650;
}
.hero-btn:hover { background: rgba(0,0,0,.36); border-color: #fff; color: #fff; }
.hero-streak {
  display: inline-flex; align-items: center; padding: 7px 12px;
  border: 1px solid rgba(255,255,255,.28); border-radius: 999px;
  font-size: 12.5px; font-weight: 700; color: #fff;
}

.hero-clock { display: flex; flex-direction: column; align-items: center; gap: 8px; }
.hero-exam {
  font-size: 11px; font-weight: 800; letter-spacing: .22em; text-transform: uppercase;
  color: rgba(255,255,255,.72);
}
.cd-flip { display: flex; align-items: flex-start; gap: 14px; }
.cd-group { display: flex; flex-direction: column; align-items: center; gap: 6px; }
.cd-tiles { display: flex; gap: 4px; }
.cd-tile {
  width: 40px; height: 54px; display: grid; place-items: center;
  background: rgba(0,0,0,.26); border: 1px solid rgba(255,255,255,.16);
  font-size: 30px; font-weight: 750; font-variant-numeric: tabular-nums;
  line-height: 1;
}
.cd-group .cd-lab {
  font-size: 10px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase;
  color: rgba(255,255,255,.66);
}
.hero-date { font-size: 12px; font-weight: 650; color: rgba(255,255,255,.86); }
.hero-change { font-size: 12px; color: rgba(255,255,255,.72); text-decoration: underline; }
.hero-change:hover { color: #fff; }

@media (max-width: 720px) {
  .today-hero { padding: var(--sp-4); }
  .hero-title { font-size: 21px; }
  .cd-flip { gap: 9px; }
  .cd-tile { width: 30px; height: 42px; font-size: 22px; }
}

/* ----- 28a. This week's test and the targets ------------------------------- */
.wk-card {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4);
  color: inherit; text-decoration: none;
}
.wk-card:hover { background: var(--brand-050); text-decoration: none; }
.wk-go { color: var(--border-strong); font-size: 12px; }
.wk-card:hover .wk-go { color: var(--brand-700); }
.wk-status { font-size: 15px; font-weight: 700; }
.wk-status.is-open { color: var(--brand-700); }
.wk-status.is-late { color: var(--danger); }
.wk-status.is-done { color: var(--ok); }
.wk-chips { gap: 8px; margin-top: 2px; }
.wk-chip {
  display: inline-flex; align-items: center; gap: 6px;
  border: 1px solid var(--border); border-radius: 999px; padding: 3px 11px;
  font-size: 12px; font-weight: 650; color: var(--muted);
}
.wk-chip.is-done { border-color: var(--ok); color: var(--ok); background: var(--ok-bg); }

.tg-row { display: flex; justify-content: space-between; align-items: flex-end; gap: var(--sp-4); }
.tg-goal { text-align: right; align-items: flex-end; }
.tg-goal .tg-num { color: var(--brand-700); }
.tg-card { justify-content: space-between; }
.tg-foot { margin-top: auto; }

/* ----- Dashboard layout ---------------------------------------------------
   This week's test with the targets beside it; the statistics as a grid of
   tiles and a row of panels. Cards in a row are the same height. */
.dash-row { display: grid; grid-template-columns: minmax(0, 2fr) minmax(280px, 1fr); gap: var(--sp-4); align-items: stretch; }
.dash-row.is-single { grid-template-columns: minmax(0, 1fr); }
.dash-row > .card { display: flex; flex-direction: column; margin: 0; }
.dash-stats { gap: var(--sp-3); margin-top: var(--sp-4); }
.dash-kpis .ps-kpi { background: var(--surface); padding: 16px 18px; }
.dash-panels { display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr) minmax(0, 1.2fr); gap: var(--sp-4); align-items: stretch; }
.dash-panels.is-two { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
.dash-panel { margin: 0; gap: var(--sp-3); }
.dash-panel .ps-week { height: 150px; }
.dash-stats > .grid-4 > .card { margin: 0; }
.dash-map { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--sp-5, 24px); align-items: start; }
.dash-map-sec { display: inline-flex; align-items: center; gap: 8px; font-size: 13px; font-weight: 700; color: var(--res-c); }
.dash-map .heatmap { grid-template-columns: repeat(auto-fill, minmax(128px, 1fr)); }
.dash-map .eyebrow { font-size: 10.5px; color: var(--muted); }
.dash-two { display: grid; grid-template-columns: minmax(0, 1.6fr) minmax(280px, 1fr); gap: var(--sp-4); align-items: stretch; }
.dash-badge { display: flex; align-items: center; gap: 12px; opacity: .5; }
.dash-badge.is-got { opacity: 1; }
.dash-badge-ico { flex: none; width: 36px; height: 36px; display: grid; place-items: center; border-radius: 10px; background: var(--surface-2); font-size: 18px; color: var(--brand-700); }
@media (max-width: 1180px) { .dash-map, .dash-two { grid-template-columns: minmax(0, 1fr); } }
@media (max-width: 1180px) {
  .dash-row, .dash-panels, .dash-panels.is-two { grid-template-columns: minmax(0, 1fr); }
}
.tg-cell { display: flex; flex-direction: column; gap: 2px; }
.tg-num { font-size: 28px; font-weight: 750; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.tg-edit { width: 30px; height: 30px; font-size: 13px; background: var(--surface); border-color: var(--border); color: var(--ink-2); }
.tg-edit:hover { background: var(--brand-050); border-color: var(--brand-500); color: var(--brand-700); }

/* ----- 29. The error log --------------------------------------------------- */
/* The breakdown that answers "what kind of mistakes am I making". Each tile is
   a filter, so it is a button and has to lose the UA button chrome. */
.err-kinds {
  display: grid; gap: 10px;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
}
/* ----- Error log: a summary column and the mistakes as cards -------------- */
.el-layout { display: grid; grid-template-columns: 320px minmax(0, 1fr); gap: var(--sp-4); align-items: start; }
.el-side { display: flex; flex-direction: column; gap: var(--sp-4); position: sticky; top: calc(var(--topbar-h) + 16px); }
.el-side > .card { margin: 0; }
.el-summary { display: flex; flex-direction: column; align-items: center; gap: var(--sp-4); }
.el-ring {
  --p: 0; width: 148px; height: 148px; border-radius: 50%; display: grid; place-items: center; align-content: center;
  background: radial-gradient(closest-side, var(--surface) 80%, transparent 81%),
    conic-gradient(var(--brand-600) calc(var(--p) * 1%), var(--surface-2) 0);
}
.el-ring b { font-family: var(--display); font-size: 32px; line-height: 1; letter-spacing: -.02em; }
.el-ring span { font-size: 11px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); margin-top: 6px; }
.el-counts { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); width: 100%; text-align: center; }
.el-counts > div { display: flex; flex-direction: column; gap: 2px; padding: 0 6px; }
.el-counts > div + div { border-left: 1px solid var(--border); }
.el-counts b { font-family: var(--display); font-size: 20px; font-variant-numeric: tabular-nums; }
.el-counts span { font-size: 11px; color: var(--muted); }
.el-kinds { display: flex; flex-direction: column; gap: 2px; }
.el-kind {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 6px 10px; align-items: baseline; text-align: left;
  font: inherit; color: inherit; cursor: pointer; padding: 9px 10px; margin-inline: -10px;
  background: none; border: 1px solid transparent; border-radius: 10px;
}
.el-kind:hover { background: var(--surface-2); }
.el-kind.is-on { border-color: var(--brand-600); background: color-mix(in srgb, var(--brand-600) 10%, transparent); }
.el-kind.is-zero { opacity: .55; }
.el-kind-name { font-size: 13.5px; font-weight: 600; }
.el-kind-n { font-variant-numeric: tabular-nums; }
.el-kind-bar { grid-column: 1 / -1; height: 4px; border-radius: 4px; background: var(--surface-2); overflow: hidden; }
.el-kind-bar i { display: block; height: 100%; border-radius: 4px; background: var(--brand-600); }
.el-kind.is-none .el-kind-bar i { background: var(--warn); }
.el-main .err-bar { padding: 12px; border: 1px solid var(--border); border-radius: var(--r-lg); background: var(--surface); }
/* One mistake to a row, the full width of the column. */
.el-list { display: flex; flex-direction: column; gap: 10px; }
.el-foot { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.el-pages { display: flex; flex-wrap: wrap; gap: 6px; }
.el-page {
  min-width: 34px; height: 34px; padding: 0 8px; font: inherit; font-weight: 700; font-variant-numeric: tabular-nums;
  cursor: pointer; color: var(--ink); background: var(--surface); border: 1px solid var(--border); border-radius: 10px;
}
.el-page:hover { border-color: var(--brand-500); }
.el-page.is-on { background: var(--brand-600); border-color: var(--brand-600); color: #111; }
.el-item {
  display: flex; flex-direction: column; gap: 10px; padding: 16px 18px; cursor: pointer;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-lg);
  box-shadow: inset 3px 0 0 var(--res-c, var(--border-strong));
}
.el-item:hover, .el-item:focus-visible { border-color: var(--brand-500); outline: none; }
.el-item.is-done { opacity: .62; }
.el-item-top, .el-item-foot { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.el-topic { display: inline-flex; align-items: center; gap: 8px; min-width: 0; font-size: 12.5px; font-weight: 700; color: var(--ink-2); }
.el-topic > span:last-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.el-title { font-size: 14.5px; line-height: 1.5; font-weight: 600; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.el-note { font-size: 13px; line-height: 1.45; color: var(--muted); padding-left: 10px; border-left: 2px solid var(--border-strong); }
.el-item-foot { margin-top: auto; }
.el-check { gap: 6px; font-size: 12px; margin: 0; align-items: center; }
.el-check input { margin: 0; }
@media (max-width: 1100px) {
  .el-layout { grid-template-columns: minmax(0, 1fr); }
  .el-side { position: static; }
}

/* The head of the log: what it is for, and the one action. */
.err-top { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-5, 24px); }
.err-top > .stack-sm { max-width: 760px; min-width: 0; }
.err-top .btn { flex: none; }
#err-kpis .ps-num { font-size: 22px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@media (max-width: 720px) { .err-top { flex-direction: column; align-items: stretch; } }
.err-kind {
  display: flex; flex-direction: column; gap: 6px; text-align: left;
  font: inherit; cursor: pointer; padding: 11px 13px;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-md);
}
.err-kind:hover { border-color: var(--brand-300); background: var(--brand-050); }
.err-kind.is-on { border-color: var(--brand-600); background: var(--brand-050); }
.err-kind.is-none .bar > i { background: var(--warn); }
.err-kind-top { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.err-kind-name { font-size: 13px; font-weight: 600; color: var(--ink-2); }
.err-kind-n { font-size: 20px; font-variant-numeric: tabular-nums; }
.err-kind-pct { font-size: 11.5px; color: var(--muted); font-variant-numeric: tabular-nums; }

.err-bar { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.err-search { flex: 1 1 220px; min-width: 0; }

/* The table reads as a spreadsheet on purpose: this is the screen a student
   and a tutor sit in front of together, and the thing they already know how to
   read is a grid. Hence ruled columns, a frozen header and tabular numerals —
   and an Export that opens in the real one. */
.xl-wrap { max-height: 62vh; overflow: auto; border: 1px solid var(--border); border-radius: var(--r-md);
  scrollbar-width: thin; scrollbar-color: var(--border-strong) transparent; }
.xl-wrap::-webkit-scrollbar { width: 8px; height: 8px; }
.xl-wrap::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 8px; }
.xl-wrap::-webkit-scrollbar-track { background: transparent; }
table.table.xl { font-size: 13px; border-collapse: separate; border-spacing: 0; }
table.table.xl th, table.table.xl td {
  border-right: 1px solid var(--border); border-bottom: 1px solid var(--border);
  padding: 7px 10px; vertical-align: top;
}
table.table.xl th:last-child, table.table.xl td:last-child { border-right: 0; }
table.table.xl thead th {
  position: sticky; top: 0; z-index: 2; padding: 0;
  background: var(--surface-2); white-space: nowrap;
}
table.table.xl thead th.is-sorted { background: var(--brand-050); }
.xl-sort {
  width: 100%; text-align: inherit; font: inherit; font-weight: 700; font-size: 12px;
  color: var(--ink-2); background: none; border: 0; cursor: pointer; padding: 8px 10px;
}
.xl-sort:hover { color: var(--brand-700); }
table.table.xl tbody tr:nth-child(even) { background: var(--bg); }
table.table.xl tbody tr.xl-row { cursor: pointer; }
table.table.xl tbody tr.xl-row:hover, table.table.xl tbody tr.xl-row:focus-visible {
  background: var(--brand-050); outline: none;
}
.xl-n { color: var(--muted); width: 1%; }
.xl-nowrap { white-space: nowrap; }
/* The stem is the one column allowed to be long; it gets the leftover width
   and clips at two lines so a row stays a row. */
.xl-stem { max-width: 330px; }
/* The topic cell carries a code chip and a name; on a narrow column the name
   drops under the chip rather than squeezing both. */
.xl-topic { display: block; margin-top: 3px; }
/* The note a student added sits under their own sentence, quieter than it. */
.xl-note {
  display: block; margin-top: 3px; font-size: 11.5px; color: var(--muted);
  overflow: hidden; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 1;
}
.xl-tick { white-space: nowrap; }
.xl-tick .check { gap: 6px; font-size: 12px; margin: 0; cursor: pointer; }
/* A reviewed row steps back without disappearing: it is still the record. */
table.table.xl tbody tr.is-done .xl-clip, table.table.xl tbody tr.is-done .xl-topic {
  color: var(--muted);
}
/* The clamp lives on a span: a <td> cannot be a -webkit-box without giving up
   being a table cell, which takes the column widths with it. */
.xl-clip {
  overflow: hidden; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
}

.err-stem { font-size: 15px; line-height: 1.55; }
.err-pick { display: flex; flex-wrap: wrap; gap: 6px; }
.err-pick-opt.is-on {
  border-color: var(--brand-600); background: var(--brand-050); color: var(--brand-700);
  font-weight: 700;
}
.err-opt {
  display: flex; align-items: baseline; gap: 8px; padding: 7px 10px;
  border: 1px solid var(--border); border-radius: var(--r-sm); font-size: 14px;
}
.err-opt.is-right { border-color: var(--ok); background: var(--ok-bg); }
.err-opt.is-picked { border-color: var(--warn); background: var(--warn-bg); }

@media (max-width: 700px) {
  /* A nine-column grid does not fit a phone, so it scrolls sideways inside its
     own box rather than shrinking every column past reading. */
  .xl-wrap { max-height: 70vh; }
  table.table.xl { min-width: 720px; }
  .xl-stem { max-width: 220px; }
}

@media print {
  .app-sidebar, .app-topbar, .tabbar, .q-footer, #desmos-panel { display: none !important; }
  .container { max-width: none; padding-inline: 0; }
}

/* ------------------------------------------------------------------------
   Class page: the written lesson, Desmos and the whiteboard
   ------------------------------------------------------------------------ */
.lesson-written { line-height: 1.6; }
.lesson-written > :first-child { margin-top: 0; }
.lesson-written h4 {
  margin: 22px 0 6px; font-size: 16px; padding-top: 14px;
  border-top: 1px solid var(--border);
}
.lesson-written .lw-mins { font-weight: 400; font-size: 12px; color: var(--muted); margin-inline-start: 6px; }
.lesson-written p { margin: 8px 0; }
.lesson-written ul, .lesson-written ol { margin: 8px 0; padding-inline-start: 22px; }
.lesson-written ul { list-style: disc; }
.lesson-written ol { list-style: decimal; }
.lesson-written li > ul { list-style: circle; }
.lesson-written li { margin: 4px 0; }
.lesson-written li > ul { margin: 4px 0; }
.lesson-written blockquote {
  margin: 12px 0; padding: 10px 14px; background: var(--info-bg);
  border-left: 3px solid var(--info); color: var(--ink);
}
.lesson-written blockquote p { margin: 4px 0; }
.lesson-written table {
  width: 100%; border-collapse: collapse; font-size: 14px; margin: 10px 0;
  display: block; overflow-x: auto;
}
.lesson-written th, .lesson-written td {
  padding: 7px 10px; text-align: left; border-bottom: 1px solid var(--border); vertical-align: top;
}
.lesson-written th { color: var(--muted); font-weight: 600; font-size: 13px; }

.wb { display: flex; flex-direction: column; gap: 8px; outline: none; }
.wb-tools { display: flex; flex-wrap: wrap; gap: 8px 14px; align-items: center; }
.wb-group { display: flex; flex-wrap: wrap; gap: 4px; align-items: center; }
.wb-tool[aria-pressed="true"], .wb-size[aria-pressed="true"] {
  background: var(--ink); color: var(--surface); border-color: var(--ink);
}
.wb-swatch {
  width: 26px; height: 26px; border: 2px solid var(--surface); border-radius: 50%;
  box-shadow: 0 0 0 1px var(--border-strong); cursor: pointer; padding: 0;
}
.wb-swatch[aria-pressed="true"] { box-shadow: 0 0 0 2px var(--ink); }
.wb-size { min-width: 34px; justify-content: center; }
.wb-dot { display: inline-block; border-radius: 50%; background: currentColor; }
.wb-stage {
  position: relative; width: 100%; aspect-ratio: 16 / 9;
  display: flex; align-items: flex-start; justify-content: center;
  background: #ffffff; border: 1px solid var(--border-strong); overflow: hidden;
}
.wb-canvas {
  display: block; touch-action: none; cursor: crosshair;
  background-color: #ffffff;
  background-image: radial-gradient(#d9d6e8 1px, transparent 1px);
  background-size: 24px 24px;
}
.wb-canvas[data-tool="text"] { cursor: text; }
.wb-text-input {
  position: absolute; z-index: 2; min-width: 160px; padding: 2px 4px; margin: 0;
  font-weight: 600; font-family: system-ui, -apple-system, "Segoe UI", sans-serif; line-height: 1.25;
  background: rgba(255, 255, 255, .92); border: 1px dashed #8f86b8; resize: both; outline: none;
}
.wb:fullscreen, .wb.wb-max {
  background: var(--surface); padding: 12px; gap: 10px;
}
.wb.wb-max { position: fixed; inset: 0; z-index: 1000; }
.wb:fullscreen .wb-stage, .wb.wb-max .wb-stage { flex: 1; aspect-ratio: auto; min-height: 0; }

/* Unit page: the unit on the left, the side panel on the right. */
.lesson-page { display: grid; grid-template-columns: minmax(0, 1fr) 52px; gap: 16px; align-items: start; }
.lesson-main { min-width: 0; }
/* The tool rail: icon buttons, kept in view while the lesson scrolls. */
.lesson-side {
  position: sticky; top: calc(var(--topbar-h) + 16px);
  display: flex; flex-direction: column; gap: 8px;
}
.lesson-tool {
  width: 52px; height: 52px; display: grid; place-items: center; cursor: pointer;
  border: 1px solid var(--border-strong); background: var(--surface); color: var(--ink);
}
.lesson-tool:hover { border-color: var(--brand-500); color: var(--brand-700); }
.lesson-tool[aria-pressed="true"] { background: var(--brand-600); border-color: var(--brand-600); color: #fff; }
.lesson-tool:focus-visible { outline: 2px solid var(--brand-600); outline-offset: 2px; }
/* With Desmos docked there is less room: the rail runs along the top. */
body.desmos-open .lesson-page { grid-template-columns: minmax(0, 1fr); margin-right: min(560px, 92vw); max-width: none; }
body.desmos-open .lesson-side { order: -1; flex-direction: row; top: var(--topbar-h); z-index: 5; }
@media (max-width: 700px) {
  .lesson-page { grid-template-columns: minmax(0, 1fr); }
  .lesson-side { order: -1; flex-direction: row; top: var(--topbar-h); z-index: 5; }
  .lesson-tool { width: 44px; height: 44px; }
}

/* A unit takes the whole window: the app's menu and top bar step aside. */
body.unit-focus { --topbar-h: 0px; --header-h: 0px; }
body.unit-focus .app-sidebar, body.unit-focus .app-topbar, body.unit-focus .tabbar { display: none !important; }
body.unit-focus .app-body { margin-left: 0; }
body.unit-focus .lesson-page { max-width: none; padding-inline: 20px; }
body.unit-focus .lesson-side { top: 16px; max-height: calc(100vh - 32px); }

/* The whiteboard in a window of its own: moved by its title bar, resized
   from its corner. */
.wb-window {
  position: fixed; z-index: 70; display: flex; flex-direction: column;
  background: var(--surface); border: 1px solid var(--border-strong); box-shadow: var(--shadow-3);
  overflow: hidden; resize: both; min-width: 360px; min-height: 280px;
  max-width: 100vw; max-height: 100vh;
}
.wb-win-head {
  display: flex; align-items: center; gap: 10px; padding: 8px 12px;
  border-bottom: 1px solid var(--border); cursor: move; user-select: none; touch-action: none;
}
.wb-window .wb { flex: 1; min-height: 0; padding: 10px; }
.wb-window .wb-stage { flex: 1; aspect-ratio: auto; min-height: 0; }
.wb-window.dragging canvas { pointer-events: none; }
/* The canvas must not hold its box open: let the stage shrink with the
   window, and the board refits itself to the new size. */
.wb, .wb-stage { min-width: 0; }
.wb-canvas { max-width: 100%; max-height: 100%; }

/* Practice: the skills inside a domain, as rows you press to pick. */
.sk-group .acc-head { padding-block: 14px; }
.sk-group.open .acc-head { background: var(--brand-050); }
.sk-list { padding: 10px; display: flex; flex-direction: column; gap: 6px; }
.sk-row {
  position: relative; display: flex; align-items: center; gap: 14px;
  padding: 12px 14px; border: 1px solid var(--border); background: var(--surface);
  cursor: pointer; transition: border-color .12s ease, background .12s ease;
}
.sk-row:hover { border-color: var(--brand-500); background: var(--brand-050); }
.sk-row.is-on { border-color: var(--brand-600); background: var(--brand-050); box-shadow: inset 3px 0 0 var(--brand-600); }
.sk-check { position: absolute; opacity: 0; width: 1px; height: 1px; pointer-events: none; }
.sk-box {
  flex: none; width: 22px; height: 22px; border: 2px solid var(--border-strong); background: var(--surface);
  display: grid; place-items: center; transition: all .12s ease;
}
.sk-row.is-on .sk-box { background: var(--brand-600); border-color: var(--brand-600); }
.sk-row.is-on .sk-box::after { content: '✓'; color: #fff; font-size: 14px; font-weight: 700; line-height: 1; }
.sk-check:focus-visible + .sk-box { outline: 2px solid var(--brand-600); outline-offset: 2px; }
.sk-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.sk-name { font-weight: 600; color: var(--ink); }
.sk-meta { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--muted); }
.sk-dot { width: 8px; height: 8px; border-radius: 50%; flex: none; background: var(--m-nodata); }
.sk-dot.st-learning { background: var(--m-learning); }
.sk-dot.st-developing { background: var(--m-developing); }
.sk-dot.st-mastered { background: var(--m-mastered); }
.sk-count {
  flex: none; font-size: 12px; font-weight: 600; color: var(--muted);
  padding: 4px 10px; border: 1px solid var(--border); background: var(--bg); white-space: nowrap;
}
.sk-go { flex: none; min-width: 40px; justify-content: center; }
@media (max-width: 640px) {
  .sk-count { display: none; }
}

/* An official Bluebook practice test, as its own card in the course list. */
.pg-official { border-left: 4px solid var(--warn); background: var(--warn-bg); }
.pg-official .eyebrow { color: var(--warn); }
.pg-official .h3 { margin: 0; }

/* ---------------------------------------------------------- study time (practice top bar) */
.pomo-wrap { position: relative; }
.pomo-btn { font-variant-numeric: tabular-nums; }
.pomo-btn.is-running { border-color: var(--brand-600); color: var(--brand-700); }
.pomo-btn.is-running.is-rest { border-color: #1a9a6c; color: #157a56; }
.pomo-panel {
  position: absolute; top: calc(100% + 8px); right: 0; z-index: 60;
  width: 320px; max-width: calc(100vw - 32px);
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--border); border-radius: var(--r-md);
  box-shadow: var(--shadow-3); padding: 16px;
  display: flex; flex-direction: column; gap: 12px;
}
.pomo-head strong { font-size: 17px; }
.pomo-tabs { display: grid; grid-template-columns: 1fr 1fr; gap: 4px; padding: 4px; border-radius: var(--r-md); background: var(--surface-2); }
.pomo-tab, .pomo-phase {
  border: 0; background: transparent; color: var(--muted); font: inherit; font-size: 14px; font-weight: 600;
  padding: 8px 10px; border-radius: var(--r-md); cursor: pointer;
}
.pomo-tab[aria-pressed="true"], .pomo-phase[aria-pressed="true"] { background: var(--surface); color: var(--ink); box-shadow: 0 1px 3px rgba(24, 18, 49, .12); }
.pomo-timer { background: var(--surface-2); border-radius: var(--r-md); padding: 14px; display: flex; flex-direction: column; align-items: center; gap: 10px; }
.pomo-phases { display: flex; gap: 4px; }
.pomo-clock { font-size: 56px; font-weight: 700; line-height: 1; font-variant-numeric: tabular-nums; letter-spacing: -.02em; }
.pomo-timer.is-rest .pomo-clock { color: #157a56; }
.pomo-tag, .pomo-row { display: flex; align-items: center; gap: 8px; font-size: 14px; }
.pomo-dot { width: 9px; height: 9px; border-radius: 50%; flex: none; }
.pomo-dot.rw { background: #0c8a7a; }
.pomo-dot.math { background: var(--brand-600); }
.pomo-actions { display: flex; gap: 8px; width: 100%; }
.pomo-go { flex: 1; justify-content: center; }
.pomo-hint { margin: 0; font-size: 12px; color: var(--muted); text-align: center; line-height: 1.4; }
.pomo-stats { display: flex; flex-direction: column; gap: 10px; }
.pomo-total { display: flex; justify-content: space-between; align-items: baseline; }
.pomo-total strong { font-size: 18px; }
.pomo-bar { display: flex; height: 8px; border-radius: 99px; overflow: hidden; background: var(--surface-2); }
.pomo-bar .rw { background: #0c8a7a; }
.pomo-bar .math { background: var(--brand-600); }
.pomo-row strong { margin-left: auto; font-variant-numeric: tabular-nums; }
.pomo-stats .pomo-hint { text-align: left; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .pomo-btn.is-running.is-rest,
  :root:not([data-theme="light"]) .pomo-timer.is-rest .pomo-clock { color: #5fd0a3; }
}
:root[data-theme="dark"] .pomo-btn.is-running.is-rest,
:root[data-theme="dark"] .pomo-timer.is-rest .pomo-clock { color: #5fd0a3; }
@media (max-width: 600px) {
  .pomo-panel { position: fixed; top: 120px; left: 16px; right: 16px; width: auto; max-width: none; }
}

/* ---------------------------------------------------------- Math reference sheet */
.ref-sheet { color: var(--ink); }
.ref-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px 24px; }
.ref-item { margin: 0; display: flex; flex-direction: column; align-items: center; gap: 6px; text-align: center; }
.ref-fig { width: 100%; max-width: 180px; height: auto; }
.ref-item figcaption { display: flex; flex-direction: column; gap: 2px; }
.ref-formula { font-family: Georgia, 'Times New Roman', serif; font-size: 18px; }
.ref-name { font-size: 12px; color: var(--muted); }
.ref-facts { margin-top: 20px; padding-top: 14px; border-top: 1px solid var(--border); font-family: Georgia, 'Times New Roman', serif; font-size: 15px; }
.ref-facts p { margin: 6px 0; }
@media (max-width: 420px) { .ref-grid { gap: 14px 12px; } .ref-formula { font-size: 16px; } }
.ref-formula .frac { font-size: .9em; vertical-align: middle; margin: 0 .1em; line-height: 1.15; }

/* ---------------------------------------------------------- explanation, step by step */
.xp { gap: 18px; font-size: 15px; line-height: 1.6; }
.xp-verdict { border: 1px solid var(--border); background: var(--surface); padding: 12px 14px; display: flex; flex-direction: column; gap: 8px; }
.xp-verdict.is-right { border-color: #1a9a6c; }
.xp-verdict.is-wrong { border-color: var(--danger); }
.xp-verdict-title { font-size: 17px; font-weight: 700; }
.xp-verdict.is-right .xp-verdict-title { color: #157a56; }
.xp-verdict.is-wrong .xp-verdict-title { color: var(--danger); }
.xp-verdict-row { display: flex; flex-wrap: wrap; gap: 8px; }
.xp-pill { font-size: 13px; font-weight: 700; padding: 4px 10px; border: 1px solid; }
.xp-pill.is-right { color: #157a56; border-color: #1a9a6c; background: rgba(26,154,108,.08); }
.xp-pill.is-wrong { color: var(--danger); border-color: var(--danger); background: rgba(220,53,69,.06); }
.xp-block { display: flex; flex-direction: column; gap: 10px; }
.xp-h { margin: 0; font-size: 13px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: var(--muted); }
.xp-text p { margin: 0 0 8px; }
.xp-steps { margin: 0; padding-left: 0; list-style: none; counter-reset: xp; display: flex; flex-direction: column; gap: 8px; }
.xp-steps li { counter-increment: xp; position: relative; padding-left: 34px; }
.xp-steps li::before {
  content: counter(xp); position: absolute; left: 0; top: 1px; width: 24px; height: 24px;
  display: grid; place-items: center; font-size: 12px; font-weight: 700;
  background: var(--brand-600); color: #fff;
}
.xp-choice { display: flex; gap: 10px; align-items: flex-start; padding: 10px 12px; border: 1px solid var(--border); background: var(--surface); }
.xp-choice.is-right { border-color: #1a9a6c; background: rgba(26,154,108,.07); }
.xp-choice.is-mine { border-color: var(--danger); }
.xp-key { flex: 0 0 26px; width: 26px; height: 26px; display: grid; place-items: center; font-size: 13px; font-weight: 700; border: 1.5px solid var(--border-strong); }
.xp-choice.is-right .xp-key { background: #1a9a6c; border-color: #1a9a6c; color: #fff; }
.xp-choice.is-mine .xp-key { border-color: var(--danger); color: var(--danger); }
.xp-choice-body { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.xp-choice-text { font-weight: 600; }
.xp-tag { align-self: flex-start; font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; color: var(--danger); }
.xp-reason { font-size: 14px; color: var(--ink-2); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .xp-verdict.is-right .xp-verdict-title,
  :root:not([data-theme="light"]) .xp-pill.is-right { color: #5fd0a3; }
}
:root[data-theme="dark"] .xp-verdict.is-right .xp-verdict-title,
:root[data-theme="dark"] .xp-pill.is-right { color: #5fd0a3; }

/* ---------------------------------------------------------- the lesson, part by part */
.lw-parts { display: flex; flex-direction: column; gap: 16px; }
.lw-lead { font-size: 16px; color: var(--ink-2); }
.lw-steps { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 6px; }
.lw-step {
  display: inline-flex; align-items: center; gap: 8px; padding: 7px 12px 7px 7px; cursor: pointer;
  border: 1px solid var(--border-strong); background: var(--surface); color: var(--ink-2);
  font: inherit; font-size: 13.5px; font-weight: 600;
}
.lw-step:hover { border-color: var(--brand-500); color: var(--brand-700); }
.lw-step-n {
  width: 24px; height: 24px; display: grid; place-items: center; flex: none;
  font-size: 12px; font-weight: 700; border: 1px solid var(--border-strong); color: var(--muted);
}
.lw-step.is-done .lw-step-n { background: var(--brand-100); border-color: var(--brand-300); color: var(--brand-700); }
.lw-step.is-on { background: var(--brand-600); border-color: var(--brand-600); color: #fff; }
.lw-step.is-on .lw-step-n { background: #fff; border-color: #fff; color: var(--brand-700); }
.lw-part { border: 1px solid var(--border); background: var(--surface-2); padding: 22px clamp(16px, 3vw, 32px) 18px; }
.lw-part-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 14px; margin-bottom: 14px; padding-bottom: 12px; border-bottom: 2px solid var(--brand-600); }
.lw-part-n { flex-basis: 100%; font-size: 12px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--brand-700); }
.lw-part-title { margin: 0; font-size: 24px; line-height: 1.25; }
.lw-part-mins { font-size: 13px; color: var(--muted); }
.lw-part .lesson-written { font-size: 17px; line-height: 1.7; }
.lw-part .lesson-written p { margin: 0 0 14px; }
.lw-part .lesson-written li { margin: 6px 0; }
.lw-part .lesson-written blockquote { margin: 16px 0; padding: 14px 18px; background: var(--surface); border: 1px solid var(--border); border-left: 4px solid var(--info); }
.lw-part-nav { display: flex; justify-content: space-between; gap: 10px; flex-wrap: wrap; margin-top: 20px; padding-top: 16px; border-top: 1px solid var(--border); }
/* Worked examples: the choices one per line, the working line by line. */
.lw-opts { list-style: none !important; margin: 10px 0 0 !important; padding: 0 !important; display: grid; gap: 6px; }
.lw-opts li { margin: 0 !important; display: flex; gap: 10px; align-items: center; padding: 6px 10px; border: 1px solid var(--border); background: var(--surface-2); }
.lw-opts b { width: 24px; height: 24px; display: grid; place-items: center; flex: none; font-size: 12px; border: 1.5px solid var(--border-strong); }
.lw-work { margin-top: 10px; display: flex; flex-direction: column; gap: 4px; font-variant-numeric: tabular-nums; }
.lw-work > div { padding: 4px 10px; background: var(--surface-2); border-left: 3px solid var(--brand-300); }
/* Tip and common-mistake boxes. */
.lesson-written .lw-note { padding: 12px 16px; border: 1px solid; border-left-width: 4px; margin: 14px 0; }
.lw-note.lw-tip { background: rgba(26,154,108,.08); border-color: #1a9a6c; }
.lw-note.lw-tip > b:first-child { color: #157a56; }
.lw-note.lw-mistake { background: rgba(196,43,48,.06); border-color: var(--danger); }
.lw-note.lw-mistake > b:first-child { color: var(--danger); }
.lw-note.lw-info { background: var(--info-bg); border-color: var(--info); }
.lw-table { overflow-x: auto; margin: 12px 0; }
.lw-part .lesson-written table { font-size: 15px; display: table; }
.lw-part .lesson-written th { background: var(--surface); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .lw-note.lw-tip > b:first-child { color: #5fd0a3; }
}
:root[data-theme="dark"] .lw-note.lw-tip > b:first-child { color: #5fd0a3; }
@media (max-width: 600px) {
  .lw-step-t { display: none; }
  .lw-step { padding: 5px; }
  .lw-part-title { font-size: 20px; }
  .lw-part .lesson-written { font-size: 16px; }
}
/* A long practice set (more than 20) scrolls its numbered rail from the start. */
.q-rail.is-long { justify-content: flex-start; }

/* ---------------------------------------------------------- practice bottom bar */
.q-footer.q-footer-practice {
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 12px;
  padding: 12px clamp(12px, 4vw, 48px);
}
.qf-side { display: flex; align-items: center; gap: 8px; min-width: 0; }
.qf-right { justify-content: flex-end; flex-wrap: wrap; }
.qf-mid { display: flex; flex-direction: column; align-items: center; gap: 8px; }
.qf-progress {
  font-size: 12.5px; font-weight: 600; color: var(--brand-700); white-space: nowrap;
  padding: 4px 10px; border: 1px solid var(--brand-200); background: var(--brand-050);
}
.qf-where {
  font: inherit; font-size: 15px; font-weight: 700; color: var(--ink); cursor: pointer;
  padding: 8px 18px; border: 2px solid var(--ink); background: var(--surface);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.qf-where:hover { border-color: var(--brand-600); color: var(--brand-700); }
.qf-check:not(:disabled) { background: var(--ink); border-color: var(--ink); color: var(--surface); }
.qf-check:disabled { opacity: .55; }
@media (max-width: 760px) {
  .q-footer.q-footer-practice { grid-template-columns: 1fr 1fr; }
  .qf-mid { grid-column: 1 / -1; order: -1; }
}
.qf-where { display: inline-flex; align-items: center; gap: 10px; }
.qf-chev { display: inline-grid; place-items: center; transition: transform .15s; }
.qf-where:hover .qf-chev { transform: translateY(-2px); }
@media (prefers-reduced-motion: reduce) { .qf-chev { transition: none; } }
/* "Log error" once the mistake is logged: it shows the kind, quietly. */
.q-tool.is-logged { border-color: var(--brand-300); color: var(--brand-700); background: var(--brand-050); }

/* ---------------------------------------------------------- practice: larger questions */
.q-shell.is-practice .q-content { max-width: 1240px; padding-top: 24px; }
.q-shell.is-practice .q-content.is-single { max-width: 860px; }
.q-shell.is-practice .q-passage { font-size: 17.5px; line-height: 1.7; }
.q-shell.is-practice .q-stem { font-size: 18px; line-height: 1.6; }
.q-shell.is-practice .q-content.is-single .q-stem { font-size: 19.5px; }
.q-shell.is-practice .opt { font-size: 17px; padding: 15px 18px; }
.q-shell.is-practice .opt .key { flex-basis: 30px; width: 30px; height: 30px; font-size: 14px; }
/* Pictures never run wider than the question, and keep their own shape.
   Equations set inside a sentence carry their own height, and their width
   follows from it. Only stand-alone figures (tables, graphs, diagrams)
   are widened to the full column. */
.q-shell.is-practice .q-passage img,
.q-shell.is-practice .q-stem img,
.q-shell.is-practice .opt-text img { max-width: 100%; width: auto; }
.q-shell.is-practice .sat-source-visual img,
.q-shell.is-practice img.sat-question-visual,
.q-shell.is-practice .q-passage > img:only-child,
.q-shell.is-practice .q-passage > p > img:only-child { display: block; width: 100%; height: auto; }
.q-shell.is-practice .q-passage table { font-size: 16px; }
.practice-resume { border-color: var(--brand-300); background: var(--brand-050); }
/* The passage side gets the larger share, so tables and graphs read at size. */
.q-shell.is-practice .q-split { grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr); }
@media (max-width: 900px) { .q-shell.is-practice .q-split { grid-template-columns: minmax(0, 1fr); } }

/* ---------------------------------------------------------- practice: a fixed frame
   The practice screen fills the window exactly. The top bar and the bottom
   bar stay where they are; the question and the explanation panel each
   scroll in their own column, so neither slides under a bar and the page
   itself never scrolls. */
body.unit-focus .q-shell.is-practice {
  height: 100vh; height: 100dvh; min-height: 0; overflow: hidden;
}
body.unit-focus .q-shell.is-practice .q-topbar,
body.unit-focus .q-shell.is-practice .q-footer { position: static; flex: none; }
body.unit-focus .q-shell.is-practice .q-main { flex: 1 1 auto; min-height: 0; overflow: hidden; }
body.unit-focus .q-shell.is-practice .q-content {
  height: 100%; overflow-y: auto; max-width: none; margin: 0;
  padding-inline: max(16px, calc((100% - 1240px) / 2));
}
body.unit-focus .q-shell.is-practice .q-content.is-single { padding-inline: max(16px, calc((100% - 860px) / 2)); }
body.unit-focus .q-shell.is-practice .q-side {
  position: static; max-height: none; min-height: 0; height: 100%; overflow: hidden;
}
@media (max-width: 1000px) {
  body.unit-focus .q-shell.is-practice .q-side { position: fixed; inset: 0 0 0 auto; height: auto; }
}

/* ---------------------------------------------------------- the rounded look
   Buttons, chips and tool buttons are pills; the question choices and the
   inputs keep a soft corner. */
.btn, .chip, .q-tool, .lw-step, .qf-where, .qf-progress, .pomo-tab, .pomo-phase,
.lesson-tool, .xp-pill, .badge { border-radius: var(--r-pill); }
.opt, .input, .select, .textarea, .xp-choice, .xp-verdict, .lw-part, .lw-note,
.lw-opts li, .lw-work > div, .pomo-panel, .pomo-timer, .q-grid button { border-radius: var(--r-md); }
.card { box-shadow: var(--shadow-1); }
.lesson-tool { border-radius: var(--r-md); }

/* ---------------------------------------------------------- light sidebar
   The sidebar is light like the rest of the page: white, with the current
   page as a violet pill. */
.app-sidebar { background: var(--surface); color: var(--ink); border-right: 1px solid var(--border); }
.sb-brand { color: var(--ink); }
.brand-mark { border-radius: var(--r-sm); }
.brand-text span { color: var(--brand-600); }
.sb-goal {
  background: var(--brand-050); color: var(--ink); border-left: 0;
  border-radius: var(--r-md); border: 1px solid var(--border);
}
.sb-goal:hover { background: var(--brand-100); }
.sb-goal-label { color: var(--brand-600); }
.sb-goal-meta { color: var(--muted); }
.sb-nav a { color: var(--ink-2); border-left: 0; border-radius: var(--r-pill); }
.sb-nav a:hover { background: var(--brand-050); color: var(--brand-700); }
.sb-nav a[aria-current="page"] { background: var(--brand-100); color: var(--brand-700); font-weight: 700; }
.sb-user { background: var(--surface-2); border-radius: var(--r-md); }
.sb-user-text span { color: var(--muted); }
.sb-avatar { border-radius: 50%; }
.icon-btn { border: 1px solid var(--border); background: var(--surface); color: var(--ink-2); border-radius: var(--r-pill); }
.icon-btn:hover { background: var(--brand-600); border-color: var(--brand-600); color: #fff; }
.lang-switch { border: 1px solid var(--border); border-radius: var(--r-pill); overflow: hidden; background: var(--surface); }
.lang-switch button { color: var(--ink-2); }
.lang-switch button:hover { background: var(--brand-050); color: var(--brand-700); }
.lang-switch button[aria-pressed="true"] { background: var(--brand-600); color: #fff; }

/* ---------------------------------------------------------- vocabulary, new look */
.ex-card {
  border: 1px solid var(--border); border-radius: var(--r-lg); padding: 18px;
  box-shadow: var(--shadow-1); transition: transform .14s ease, box-shadow .14s ease, border-color .14s ease;
}
.ex-card:hover { background: var(--surface); border-color: var(--brand-300); box-shadow: var(--shadow-2); transform: translateY(-2px); }
.ex-icon { border-radius: var(--r-md); background: var(--brand-100); color: var(--brand-600); }
.ex-stat { color: var(--brand-600); }
.flash-face {
  border: 1px solid var(--border); border-radius: var(--r-xl);
  box-shadow: var(--shadow-2);
}
.flash-back { background: var(--brand-050); border-color: var(--brand-200); }
.mg-tile { border: 1px solid var(--border); border-radius: var(--r-md); box-shadow: var(--shadow-1); }
.mg-tile.sel { border-color: var(--brand-600); box-shadow: 0 0 0 3px var(--brand-100); }
@media (prefers-reduced-motion: reduce) { .ex-card, .ex-card:hover { transition: none; transform: none; } }

/* ---------------------------------------------------------- roadmap, new look
   The map is a white card with a soft violet glow instead of a gridded board;
   stops are white discs that fill with violet as they are done, the tests
   along the way are violet too, and the course list below uses pills. */
.rm-stage {
  background:
    radial-gradient(90% 60% at 50% 105%, rgba(135, 75, 248, .12), transparent 65%),
    linear-gradient(180deg, var(--surface), var(--brand-050));
  border: 1px solid var(--border); border-radius: var(--r-lg); box-shadow: var(--shadow-1);
}
.rm-stage::before { display: none; }
.rm-road-edge { stroke: rgba(135, 75, 248, .12); }
.rm-road-dash { stroke: var(--brand-300); }
.rm-pin {
  background: var(--surface); color: var(--brand-700); border: 3px solid var(--brand-200);
  box-shadow: 0 4px 12px rgba(53, 34, 85, .12);
}
.rm-done .rm-pin { background: var(--brand-600); border-color: var(--surface); color: #fff; }
.rm-current .rm-pin { background: var(--brand-700); border-color: var(--surface); color: #fff; box-shadow: 0 0 0 6px rgba(135, 75, 248, .18); }
.rm-gate .rm-pin, .rm-stop.rm-gate .rm-pin { background: var(--surface); color: var(--brand-700); border-color: var(--brand-400); }
.rm-gate.rm-done .rm-pin, .rm-stop.rm-gate.rm-done .rm-pin { background: var(--brand-600); border-color: var(--surface); color: #fff; }
.rm-gate.rm-current .rm-pin, .rm-stop.rm-gate.rm-current .rm-pin { background: var(--brand-700); border-color: var(--surface); color: #fff; }
.rm-sel .rm-pin { box-shadow: 0 0 0 5px var(--brand-300), 0 4px 12px rgba(53, 34, 85, .12); }
.rm-kind, .rm-gate .rm-kind { background: var(--surface); color: var(--brand-600); border-color: var(--brand-200); }
.rm-gift {
  background: linear-gradient(160deg, var(--brand-500), var(--brand-700)); color: #fff;
  border-radius: var(--r-md); box-shadow: 0 6px 16px rgba(111, 49, 232, .3);
}
.rm-name { border-radius: var(--r-pill); background: var(--surface); box-shadow: 0 2px 8px rgba(53, 34, 85, .08); padding: 2px 8px; }
.rm-sel .rm-name, .rm-current .rm-name { background: var(--brand-600); color: #fff; }
.rm-panel { border-top: 1px solid var(--border); }
.rm-panel.is-current, .rm-panel.is-done { border-top-color: var(--border); }
.rm-panel-n { border-radius: 50%; }
.rm-how { border-radius: var(--r-md); box-shadow: var(--shadow-1); }
.rm-how-n { border-radius: 50%; }
.pg-tag { border-radius: var(--r-pill); padding: 1px 8px; }
.pg-tag.lv-hard, .pg-level.lv-hard { background: var(--brand-100); color: var(--brand-700); border-color: var(--brand-300); }
.pg-level { border-radius: var(--r-pill); }
.pg-n { border-radius: 50%; width: 24px; height: 24px; background: var(--brand-050); color: var(--brand-700); }
.pg-lesson.is-gate { background: var(--brand-050); border-radius: var(--r-md); }
.pg-lesson.is-gate .pg-n { background: var(--brand-600); }
.pg-week-n { color: var(--brand-600); }
.pg-zero { border-left: 0; background: var(--brand-050); }
.pg-official {
  border-left: 0; color: #fff;
  background: linear-gradient(135deg, var(--brand-600), var(--brand-700));
  box-shadow: 0 10px 28px rgba(111, 49, 232, .25);
}
.pg-official .eyebrow { color: rgba(255, 255, 255, .8); }
.pg-official .muted, .pg-official p, .pg-official .small { color: rgba(255, 255, 255, .88); }
.pg-official .badge { background: rgba(255, 255, 255, .18); color: #fff; border-color: transparent; }
.pg-hw-item.is-weekly .pg-hw-n { background: var(--brand-600); }
.rm-screen .notice-warn, .rm-course .notice-warn {
  background: var(--brand-050); border-color: var(--brand-200); color: var(--ink-2); border-radius: var(--r-md);
}

/* Equation pictures inside a sentence (class "m" in the question files) sit
   on the line like a word; their height and baseline come from the file.
   Stand-alone figures (class "fig") keep a line of their own. */
img.m { display: inline-block; max-width: none; margin: 0 .08em; }
img.fig { display: block; max-width: 100%; height: auto; margin: 8px 0 12px; }

/* ---------------------------------------------------------- explanation panel, white
   A white sheet beside the question: a quiet header, the verdict as a
   tinted card, numbered steps in violet circles, and the answer choices as
   soft cards, the right one green and the student's own pick red. */
.q-side {
  background: var(--surface); border-left: 1px solid var(--border);
  box-shadow: -10px 0 30px rgba(53, 34, 85, .06);
}
.q-side > .q-topbar {
  background: var(--surface); border-bottom: 1px solid var(--border);
  padding: 14px 22px; min-height: 62px;
}
.q-side > .q-topbar strong { font-size: 17px; font-weight: 800; letter-spacing: -.01em; }
.q-side > .q-topbar .btn { border-radius: var(--r-pill); }
.q-side-body { padding: 20px 22px 32px; }

.xp { gap: 22px; }
.xp-verdict { border: 0; border-radius: var(--r-lg); padding: 16px 18px; gap: 10px; background: var(--surface-2); }
.xp-verdict.is-wrong { background: var(--danger-bg); }
.xp-verdict.is-right { background: var(--ok-bg); }
.xp-verdict-title { font-size: 18px; font-weight: 800; }
.xp-pill { border-radius: var(--r-pill); background: var(--surface); padding: 5px 12px; border-width: 1px; }

.xp-h {
  display: flex; align-items: center; gap: 10px;
  font-size: 12px; font-weight: 800; letter-spacing: .08em; color: var(--brand-600);
}
.xp-h::after { content: ''; flex: 1; height: 1px; background: var(--border); }

.xp-steps { gap: 12px; }
.xp-steps li { padding-left: 38px; line-height: 1.65; }
.xp-steps li::before {
  width: 26px; height: 26px; border-radius: 50%; top: 0;
  background: var(--brand-100); color: var(--brand-700); font-weight: 800;
}

.xp-choice {
  border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--surface); padding: 12px 14px; box-shadow: var(--shadow-1);
}
.xp-choice.is-right { background: var(--ok-bg); border-color: transparent; box-shadow: none; }
.xp-choice.is-mine { background: var(--danger-bg); border-color: transparent; box-shadow: none; }
.xp-key { border-radius: 50%; border-width: 1.5px; }
.xp-choice.is-right .xp-key { background: var(--ok); border-color: var(--ok); }
.xp-choice.is-mine .xp-key { background: var(--danger); border-color: var(--danger); color: #fff; }
.xp-tag { color: var(--danger); }
.xp-reason { color: var(--ink-2); line-height: 1.6; }
.xp-text { line-height: 1.7; }

/* Answer-choice pictures: sized by fitChoiceImages() in question.js; here
   they only keep their shape and sit on the line beside the letter. */
.opt-text .fig.sat-natural-option, .opt-text .fig.sat-display-math, .opt-text .figw { margin: 0; }
.opt-text img.opt-img { width: auto; max-width: 100%; height: auto; margin: 0; object-fit: contain; vertical-align: middle; }
.opt-text img.opt-img.fig { display: block; }

/* Weekly practice test card (js/modules/weekly-test.js) */
.wt-past { gap: 6px; }
.wt-chip { font-size: 12px; font-weight: 600; padding: 4px 10px; border-radius: var(--r-pill);
  background: var(--brand-050); color: var(--brand-700); border: 1px solid var(--brand-100, var(--border)); }

/* Weekly test result: rows that open to the question and its explanation */
.wt-row { padding: 0; overflow: hidden; scroll-margin-top: 90px; }
.wt-head { all: unset; box-sizing: border-box; width: 100%; cursor: pointer; display: flex; align-items: center;
  justify-content: space-between; gap: 12px; padding: 14px 18px; }
.wt-head:hover { background: var(--brand-050); }
.wt-head:focus-visible { outline: 2px solid var(--brand-600); outline-offset: -2px; }
.wt-caret { font-size: 18px; line-height: 1; color: var(--muted); transition: transform .15s ease; }
.wt-row.is-open .wt-caret { transform: rotate(180deg); }
.wt-body { border-top: 1px solid var(--border); padding: 16px 18px 20px; display: flex; flex-direction: column; gap: 14px; }
.wt-body[hidden] { display: none; }
.wt-passage { background: var(--surface-2); border-radius: var(--r-md); padding: 12px 14px; }
.wt-stem { font-weight: 600; }
.wt-body img { max-width: 100%; height: auto; }
.wt-opts { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.wt-opts li { display: flex; gap: 10px; align-items: flex-start; padding: 8px 12px; border: 1px solid var(--border); border-radius: var(--r-md); }
.wt-opts li.is-right { border-color: var(--ok); background: var(--ok-bg); }
.wt-opts li.is-wrong { border-color: var(--danger, #d33); background: var(--danger-bg, #fdecec); }
.wt-key { font-weight: 700; min-width: 1.2em; }

/* Challenge classes: each question is one picture; shown a little smaller
   than the column so it reads at text size. */
.q-shell.is-challenge .q-stem img { max-width: min(100%, 600px) !important; width: auto !important; height: auto !important; }

/* A completed unit: its box is filled and ticked. */
.mat-unit.is-done .mat-state { background: var(--ok); border-color: var(--ok); color: #fff; font-weight: 800; }
.q-shell.is-challenge .q-stem img.is-wide { max-width: 100% !important; }

/* A full test's modules on its class page */
.lw-module { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
.lw-module > .stack-sm { flex: 1 1 260px; min-width: 0; }
.lw-module.is-done { border-color: var(--ok); }

/* A passage set inside a question (JSON tasks): set off from the question. */
.lw-passage { background: var(--surface-2); border-left: 3px solid var(--brand-300, var(--border)); border-radius: var(--r-md); padding: 12px 14px; margin-bottom: 12px; }

/* Letters only (the choices are in the picture): A B C D in one row. */
.opt-list.is-letters { flex-direction: row; flex-wrap: wrap; gap: 12px; }
.opt-list.is-letters .opt { flex: 0 0 auto; width: 72px; min-height: 0; height: 64px; padding: 0; justify-content: center; }
.opt-list.is-letters .opt .opt-text,
.opt-list.is-letters .opt .opt-strike { display: none; }
.opt-list.is-letters .opt .key { width: 40px; height: 40px; flex-basis: 40px; font-size: 18px; margin: 0; }

/* Exam footer: the rail takes what is left and scrolls inside itself, so a
   27-question rail no longer pushes Next onto a second line. */
.q-footer > .q-rail { flex: 1 1 0; }
.q-nav { display: flex; gap: 8px; flex: none; margin-left: auto; }
.q-nav .btn { min-width: 88px; }
@media (max-width: 760px) { .q-footer > .q-rail { flex: 1 1 100%; } }

/* Mock tests: the last paper, analysed */
.pa-tiles { gap: 12px; }
.pa-tile { border: 1px solid var(--border); border-radius: var(--r-md); padding: 14px 16px; display: flex; flex-direction: column; gap: 4px; }
.pa-tile.is-total { background: var(--brand-050); border-color: var(--brand-300, var(--border)); }
.pa-big { font-size: 26px; font-weight: 800; letter-spacing: -.01em; font-variant-numeric: tabular-nums; }
.pa-mod { border: 1px solid var(--border); border-radius: var(--r-md); padding: 12px 14px; display: flex; flex-direction: column; gap: 8px; }
.pa-mod-head { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; }
.pa-chips { gap: 6px; }

/* Mock tests: recent tests, each opening with its arrow */
.rt-item { border: 1px solid var(--border); border-radius: var(--r-md); overflow: hidden; }
.rt-head { all: unset; box-sizing: border-box; width: 100%; cursor: pointer; display: flex; align-items: center; gap: 14px; padding: 14px 16px; }
.rt-head:hover { background: var(--brand-050); }
.rt-head:focus-visible { outline: 2px solid var(--brand-600); outline-offset: -2px; }
.rt-arrow { font-size: 22px; line-height: 1; color: var(--brand-600); transition: transform .15s ease; width: 14px; text-align: center; }
.rt-item.is-open .rt-arrow { transform: rotate(90deg); }
.rt-title, .rt-score { display: flex; flex-direction: column; gap: 2px; }
.rt-title { flex: 1; min-width: 0; }
.rt-score { text-align: right; align-items: flex-end; }
.rt-body { border-top: 1px solid var(--border); padding: 16px; }
.rt-body[hidden] { display: none; }

/* ----- Result of a simulation or a past paper ----------------------------- */
.res-head { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4); flex-wrap: wrap; }
.res-meta { gap: 8px; align-items: center; }
.res-grid { display: grid; grid-template-columns: minmax(0, 1.75fr) minmax(300px, 1fr); gap: var(--sp-4); align-items: stretch; }
.res-grid.is-single { grid-template-columns: minmax(0, 1fr); }
.res-grid > .card { margin: 0; }
.res-secs { display: grid; grid-template-rows: 1fr 1fr; gap: var(--sp-4); min-width: 0; }
.res-secs > .card { margin: 0; justify-content: space-between; }
.res-total { display: flex; flex-direction: column; justify-content: space-between; gap: var(--sp-4); padding: 26px 28px; }
.res-big { font-family: var(--display); font-size: clamp(40px, 5.2vw, 68px); font-weight: 800; line-height: 1; letter-spacing: -.03em; font-variant-numeric: tabular-nums; }
.res-scale-wrap { max-width: 640px; }
.res-scale { position: relative; height: 8px; border-radius: 8px; background: var(--surface-2); border: 1px solid var(--border); }
.res-scale-range { position: absolute; top: -4px; height: 14px; border-radius: 8px; background: var(--brand-600); }
.res-scale-goal { position: absolute; top: -9px; width: 2px; height: 24px; margin-left: -1px; background: var(--ink); border-radius: 2px; }
.res-ticks { position: relative; height: 34px; margin-top: 10px; font-size: 11px; color: var(--muted); font-variant-numeric: tabular-nums; }
.res-ticks span { position: absolute; transform: translateX(-50%); white-space: nowrap; }
.res-ticks span:first-child { transform: none; }
.res-ticks span:nth-child(4) { transform: translateX(-100%); }
.res-ticks .res-tick-goal { top: 17px; color: var(--ink); font-weight: 700; }
.res-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: var(--res-c, var(--brand-600)); flex: none; }
.is-rw { --res-c: #4C8DFF; }
.is-math { --res-c: #FF5FA8; }
.res-sec-name, .res-mod-name, .res-lost-name { display: inline-flex; align-items: center; gap: 8px; min-width: 0; }
.res-sec-name { font-weight: 650; }
.res-sec-nums { display: flex; align-items: flex-end; gap: var(--sp-5, 24px); }
.res-sec-nums > div { display: flex; flex-direction: column; gap: 2px; }
.res-raw, .res-est { font-family: var(--display); font-size: 26px; font-weight: 750; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.res-est { color: var(--res-c); }
.res-sec .bar > i { background: var(--res-c); }
.res-route { background: color-mix(in srgb, var(--brand-600) 16%, transparent); color: var(--brand-700); border-color: transparent; }
.res-mods { display: flex; flex-direction: column; }
/* Every row is its own grid, so the columns are fixed widths and each cell is
   placed by name: a row with no route badge must not pull the others along. */
.res-mod { display: grid; grid-template-columns: minmax(0, 1fr) 190px 130px 70px; gap: 12px; align-items: center; padding: 13px 0; }
.res-mod-name { grid-column: 1; }
.res-mod-spec { grid-column: 2; }
.res-mod > .badge { grid-column: 3; justify-self: start; }
.res-mod + .res-mod { border-top: 1px solid var(--border); }
.res-mod-score { text-align: right; font-variant-numeric: tabular-nums; grid-column: 4; }
.res-lost { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 11px 14px; border-radius: 12px; background: var(--surface-2); font-size: 14px; font-weight: 600; }
.res-lost-name span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.res-lost-n { flex: none; font-size: 12px; font-weight: 700; color: var(--danger); }
.res-build { width: 100%; justify-content: center; background: color-mix(in srgb, var(--brand-600) 14%, transparent); color: var(--brand-700); border-color: transparent; }
.res-build:hover { background: color-mix(in srgb, var(--brand-600) 24%, transparent); }
@media (max-width: 1100px) {
  .res-grid { grid-template-columns: minmax(0, 1fr); }
  .res-mod { grid-template-columns: minmax(0, 1fr) 110px 60px; }
  .res-mod-spec { display: none; }
  .res-mod > .badge { grid-column: 2; }
  .res-mod-score { grid-column: 3; }
}

/* Mock tests: the simulation with the trajectory beside it */
.mk-top { display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr); gap: var(--sp-5, 24px); align-items: start; }
@media (max-width: 1180px) { .mk-top { grid-template-columns: minmax(0, 1fr); } }

/* Past papers: tiles in a row, wrapping onto the next line */
.pp-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 12px; }
.pp-tile { border: 1px solid var(--border); border-radius: var(--r-lg); padding: 16px; display: flex; flex-direction: column; justify-content: space-between; gap: 14px; background: var(--surface); }
.pp-tile:hover { border-color: var(--brand-300, var(--border-strong)); }
.pp-tile .btn { align-self: flex-start; }

/* Challenge Math pictured as one wide line: shown at full size. */
.q-shell.is-challenge .q-content.has-wide-math,
body.unit-focus .q-shell.is-practice.is-challenge .q-content.is-single.has-wide-math {
  max-width: 1440px; padding-inline: max(16px, calc((100% - 1400px) / 2));
}
.q-shell.is-challenge .q-content.has-wide-math .q-stem img.is-wide { width: auto !important; max-width: 100% !important; }
/* The two full simulations are screenshots of whole questions: their
   pictures are shown at their own size, not held to text size. */
.q-shell.is-full-sim .q-stem img { max-width: 100% !important; width: auto !important; }

/* ==========================================================================
   TeenTech SAT look (2026-10)
   Near-black ground, dark cards with a hairline border, one yellow accent.
   The current page is a yellow pill with black text; section labels are
   small, spaced capitals; page titles are set heavy. Dark is the default
   theme, and the light theme keeps the same yellow on white.
   This block sits last so it wins over everything above it.
   ========================================================================== */
:root, html[data-theme="light"] {
  --brand-950: #1A1500;
  --brand-900: #2B2300;
  --brand-800: #4A3C00;
  --brand-700: #7A5F00;      /* yellow text on light grounds */
  --brand-600: #FFD400;      /* the accent: buttons, current page */
  --brand-500: #FFDB2E;
  --brand-400: #FFE15C;
  --brand-300: #FFE98A;
  --brand-200: #FFF0B3;
  --brand-100: #FFF6D1;
  --brand-050: #FFFAE6;
  --eyebrow:   #8A6B00;
  --eyebrow-on-dark: #FFD400;
  --on-brand:  #0B0B0B;      /* text on the yellow */
  --bg:        #F5F5F2;
  --surface:   #FFFFFF;
  --surface-2: #F2F2EE;
  --border:    #E4E4DE;
  --border-strong: #CFCFC7;
  --ink:       #111111;
  --ink-2:     #2E2E2E;
  --muted:     #6B6B66;
  --r-sm: 10px; --r-md: 12px; --r-lg: 18px; --r-xl: 22px;
  --shadow-1: none;
  --shadow-2: 0 10px 30px rgba(0,0,0,.08);
  --shadow-3: 0 24px 60px rgba(0,0,0,.25);
  --display: Unbounded, Manrope, "Segoe UI", sans-serif;
}
html[data-theme="dark"] {
  --brand-950: #FFF3B0;
  --brand-900: #FFE97A;
  --brand-800: #2A250D;
  --brand-700: #FFE15C;      /* yellow text on dark grounds */
  --brand-600: #FFD400;
  --brand-500: #FFDB2E;
  --brand-400: #D9B500;
  --brand-300: #6B5A10;
  --brand-200: #3D3510;
  --brand-100: #29240C;
  --brand-050: #1C190B;
  --eyebrow:   #FFD400;
  --eyebrow-on-dark: #FFD400;
  --on-brand:  #0B0B0B;
  --bg:        #0A0A0A;
  --surface:   #141414;
  --surface-2: #1B1B1B;
  --border:    #262626;
  --border-strong: #3A3A3A;
  --ink:       #F4F4F2;
  --ink-2:     #D6D6D2;
  --muted:     #9A9A94;
  --ok:        #4ADE80;  --ok-bg:     #10261A;
  --warn:      #FBBF24;  --warn-bg:   #2A2108;
  --danger:    #F87171;  --danger-bg: #2E1214;
  --info:      #60A5FA;  --info-bg:   #0F1C33;
  --m-nodata:  #2A2A2A;
  --dark-grad-a: #141414;
  --dark-grad-b: #1B1B1B;
  --shadow-1: none;
  --shadow-2: 0 2px 0 rgba(0,0,0,.5);
  --shadow-3: 0 24px 60px rgba(0,0,0,.7);
}

body { background: var(--bg); color: var(--ink); }
::selection { background: var(--brand-600); color: var(--on-brand); }
a { color: var(--brand-700); }

/* ----- type: heavy titles, spaced capitals ------------------------------- */
.h1, .ph-title, .hero-title {
  font-family: var(--display); font-weight: 800; letter-spacing: -.01em;
}
.h2 { font-family: var(--display); font-weight: 700; font-size: 19px; letter-spacing: 0; }
.h3 { font-weight: 800; }
.eyebrow, .stat-label, .sb-goal-label, .ph-eyebrow, .sb-group {
  font-weight: 800; letter-spacing: .16em; text-transform: uppercase;
}
.eyebrow { color: var(--eyebrow); font-size: 11.5px; }

/* ----- sidebar ----------------------------------------------------------- */
.app-sidebar {
  background: var(--bg); color: var(--ink);
  border-right: 1px solid var(--border); padding: 18px 14px;
}
html[data-theme="light"] .app-sidebar { background: #FFFFFF; }
.sb-brand { color: var(--ink); gap: 12px; padding: 4px 6px 12px; border-bottom: 1px solid var(--border); margin-bottom: 4px; }
.brand-mark {
  width: 44px; height: 44px; flex: 0 0 44px; display: grid; place-items: center;
  background: var(--brand-600); color: var(--on-brand); border-radius: 12px;
}
.brand-mark svg { display: block; }
.brand-text b { font-family: var(--display); font-size: 15px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase; }
.brand-text span { color: var(--muted); font-size: 10px; font-weight: 700; letter-spacing: .22em; text-transform: uppercase; }
.sb-goal {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-md);
  color: var(--ink);
}
.sb-goal:hover { background: var(--surface-2); border-color: var(--border-strong); }
.sb-goal-label { color: var(--brand-700); font-size: 10px; }
.sb-goal-value { font-family: var(--display); font-weight: 800; }
.sb-goal-meta { color: var(--muted); }
.sb-nav { gap: 4px; }
.sb-group {
  font-size: 10.5px; color: var(--muted); padding: 14px 12px 6px;
}
.sb-group:first-child { padding-top: 6px; }
.sb-nav a {
  display: flex; align-items: center; gap: 12px;
  padding: 11px 14px; border-radius: var(--r-md); border: 0;
  color: var(--ink-2); font-weight: 650; font-size: 15px;
}
.sb-nav a em { width: 20px; flex: 0 0 20px; display: grid; place-items: center; opacity: .9; }
.sb-nav a em svg { display: block; }
.sb-nav a:hover { background: var(--surface-2); color: var(--ink); }
.sb-nav a[aria-current="page"] {
  background: var(--brand-600); color: var(--on-brand); font-weight: 800;
}
.sb-nav a[aria-current="page"] em { opacity: 1; }
.sb-user { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-md); }
.sb-avatar { background: var(--brand-600); color: var(--on-brand); }
.sb-user-text b { color: var(--ink); }
.sb-user-text span { color: var(--muted); }

/* ----- small controls: icon buttons, language switch -------------------- */
.icon-btn {
  background: var(--surface); border: 1px solid var(--border); color: var(--ink-2);
  border-radius: var(--r-md);
}
.icon-btn:hover { background: var(--surface-2); border-color: var(--border-strong); color: var(--ink); }
.lang-switch { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-md); }
.lang-switch button { color: var(--muted); font-weight: 700; }
.lang-switch button:hover { background: var(--surface-2); color: var(--ink); }
.lang-switch button[aria-pressed="true"] { background: var(--ink); color: var(--bg); }

/* ----- top bar: a breadcrumb --------------------------------------------- */
.app-topbar {
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--border); min-height: 64px;
}
.tb-left { align-items: center; }
.tb-crumbs {
  display: flex; align-items: center; gap: 10px;
  font-size: 12px; font-weight: 700; letter-spacing: .2em; text-transform: uppercase;
  color: var(--muted); white-space: nowrap; overflow: hidden;
}
.tb-crumbs a { color: var(--muted); text-decoration: none; }
.tb-crumbs a:hover { color: var(--ink); }
.tb-crumbs b { color: var(--ink); font-weight: 800; overflow: hidden; text-overflow: ellipsis; }
.tb-sep { opacity: .6; }
.tb-menu { border-radius: var(--r-md); background: var(--surface); border-color: var(--border); color: var(--ink); }

/* ----- the page's own title --------------------------------------------- */
.page-head { padding-top: 30px; padding-bottom: 4px; }
.page-head[hidden] { display: none; }
.ph-eyebrow { font-size: 12px; color: var(--eyebrow); }
.ph-title { margin: 6px 0 0; font-size: clamp(28px, 3.2vw, 40px); line-height: 1.12; color: var(--ink); }
.page-head:not([hidden]) + main .screen { padding-top: 18px; }
body.unit-focus .page-head { display: none !important; }

/* ----- cards ------------------------------------------------------------- */
.card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-lg); box-shadow: none;
}
.card-sm { border-radius: var(--r-md); }
.card-brand { background: var(--brand-050); border-color: var(--brand-300); }
.card-accent { border-left: 1px solid var(--border); box-shadow: inset 4px 0 0 var(--brand-600); }
.card-hero, .today-hero {
  background:
    radial-gradient(120% 140% at 100% 0%, rgba(255, 212, 0, .16), transparent 55%),
    #141414;
  border: 1px solid #262626; color: #F4F4F2;
}
.card-hero .eyebrow, .today-hero .eyebrow { color: #FFD400; }
.hero-lead { color: rgba(244,244,242,.72); }
.hero-btn {
  background: #1F1F1F; border: 1px solid #333; color: #F4F4F2; border-radius: var(--r-md);
}
.hero-btn:hover { background: #FFD400; border-color: #FFD400; color: #0B0B0B; }
.hero-exam { color: #FFD400; }
.cd-tile { background: #0A0A0A; border: 1px solid #2E2E2E; color: #F4F4F2; border-radius: 10px; }
.cd-lab { color: rgba(244,244,242,.6); }
.hero-date { color: rgba(244,244,242,.85); }
.hero-change { color: rgba(244,244,242,.6); }

/* ----- buttons ----------------------------------------------------------- */
.btn {
  border-radius: var(--r-md); border: 1px solid var(--border-strong);
  background: var(--surface); color: var(--ink); font-weight: 700;
}
.btn:hover { background: var(--surface-2); border-color: var(--ink-2); color: var(--ink); }
.btn-primary, .btn-primary:hover {
  background: var(--brand-600); border-color: var(--brand-600); color: var(--on-brand); font-weight: 800;
}
.btn-primary:hover { filter: brightness(1.06); }
.btn-ghost { background: transparent; border-color: transparent; }
.btn-ghost:hover { background: var(--surface-2); }

/* ----- chips, tabs, badges ---------------------------------------------- */
.chip {
  border-radius: var(--r-md); background: var(--surface); border: 1px solid var(--border);
  color: var(--ink-2); font-weight: 700;
}
.chip:hover { background: var(--surface-2); border-color: var(--border-strong); color: var(--ink); }
.chip[aria-pressed="true"] { background: var(--ink); border-color: var(--ink); color: var(--bg); }
.tabs { border-bottom: 1px solid var(--border); }
.tabs button { color: var(--muted); font-weight: 700; }
.tabs button:hover { color: var(--ink); }
.tabs button[aria-selected="true"] { color: var(--ink); border-bottom-color: var(--brand-600); }
.badge {
  border-radius: 8px; font-weight: 700; background: var(--surface-2);
  border: 1px solid var(--border); color: var(--ink-2);
}
.badge-ok     { background: var(--ok-bg); border-color: transparent; color: var(--ok); }
.badge-warn   { background: var(--warn-bg); border-color: transparent; color: var(--warn); }
.badge-danger { background: var(--danger-bg); border-color: transparent; color: var(--danger); }
.badge-muted  { background: var(--surface-2); color: var(--muted); }

/* ----- form fields ------------------------------------------------------- */
.input, .select, .textarea {
  background: var(--surface-2); border: 1px solid var(--border); color: var(--ink);
  border-radius: var(--r-md);
}
.input:focus, .select:focus, .textarea:focus {
  border-color: var(--brand-600); box-shadow: 0 0 0 3px rgba(255, 212, 0, .22); outline: none;
}
.input::placeholder, .textarea::placeholder { color: var(--muted); }

/* ----- notices ----------------------------------------------------------- */
.notice { background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--r-md); color: var(--ink-2); }
.notice-warn { background: var(--warn-bg); border-color: transparent; color: var(--warn); }

/* ----- bars and meters --------------------------------------------------- */
.bar { background: var(--surface-2); border-radius: 999px; overflow: hidden; }
.bar > i { background: var(--brand-600); }
.bar-ok > i { background: var(--ok); }

/* ----- every yellow fill gets black text --------------------------------- */
.phase-track > div.current, .q-tool[aria-pressed="true"], .opt[aria-pressed="true"] .key,
.q-step.is-here, .q-grid button.answered, .fab, .fab:hover,
.setup-bar .lang-switch button[aria-pressed="true"], .setup-brand .brand-mark,
.rm-done .rm-pin, .rm-done .rm-kind, .rm-panel.is-current .rm-panel-n,
.cal-seg a[aria-pressed="true"], .cal-today .cal-num, .cal-tag-exam,
.mat-unit.is-current .mat-state, .lesson-tool[aria-pressed="true"],
.lw-step.is-on, .rm-current .rm-pin, .rm-gate.rm-done .rm-pin, .rm-stop.rm-gate.rm-done .rm-pin,
.rm-gate.rm-current .rm-pin, .rm-stop.rm-gate.rm-current .rm-pin,
.rm-sel .rm-name, .rm-current .rm-name, .pomo-btn.is-running {
  color: var(--on-brand) !important;
}
.lw-step.is-on .lw-step-n { background: var(--on-brand); border-color: var(--on-brand); color: var(--brand-600); }
.fab { border-radius: 16px; }
.q-step.is-here { background: var(--brand-600); border-color: var(--brand-600); }
.q-step.is-answered { background: var(--brand-050); border-color: var(--brand-300); color: var(--ink); }
.opt[aria-pressed="true"] { border-color: var(--brand-600); box-shadow: 0 0 0 1px var(--brand-600) inset; }
.mat-unit.is-done .mat-state { background: var(--ok); border-color: var(--ok); color: #0B0B0B; }
.sk-row.is-on .sk-box { color: var(--on-brand); }

/* ----- question screen and practice frame -------------------------------- */
.q-topbar, .q-footer { background: var(--bg); border-color: var(--border); }
.q-footer { box-shadow: none; }
.q-tool { background: var(--surface); border: 1px solid var(--border); color: var(--ink-2); border-radius: var(--r-md); }
.q-tool:hover { background: var(--surface-2); color: var(--ink); }
.opt { background: var(--surface); border: 1px solid var(--border); }
.opt:hover { border-color: var(--border-strong); background: var(--surface-2); }
.opt .key { border-color: var(--border-strong); color: var(--ink); }
.qf-where { border-color: var(--ink); color: var(--ink); background: var(--surface); }
.qf-progress { background: var(--brand-050); color: var(--brand-700); border-color: var(--brand-300); }

/* ----- the rest of the purple, turned yellow ----------------------------- */
.rm-current .rm-pin { box-shadow: 0 0 0 6px rgba(255, 212, 0, .18); }
.rm-stage {
  background:
    radial-gradient(90% 60% at 50% 105%, rgba(255, 212, 0, .10), transparent 65%),
    linear-gradient(180deg, var(--surface), var(--surface-2));
}

/* ----- pictures of questions on dark ground ------------------------------
   Question pictures are black text on white; on the dark theme they sit on
   a white plate so they stay readable. */
html[data-theme="dark"] .q-stem img:not(.m),
html[data-theme="dark"] .q-passage img:not(.m),
html[data-theme="dark"] .opt-text img,
html[data-theme="dark"] .lesson-written img,
html[data-theme="dark"] .wt-body img,
html[data-theme="dark"] .xp img {
  background: #FFFFFF; border-radius: 8px; padding: 6px;
}
html[data-theme="dark"] img.m { background: #FFFFFF; border-radius: 4px; padding: 0 2px; }
html[data-theme="dark"] .lw-passage { background: var(--surface-2); border-left-color: var(--brand-600); }

/* ----- phone tab bar ----------------------------------------------------- */
.tabbar { background: var(--bg); border-top: 1px solid var(--border); }
.tabbar a { color: var(--muted); }
.tabbar a em svg { display: block; margin: 0 auto; }
.tabbar a[aria-current="page"] { color: var(--brand-600); }

/* Sign-in and setup screens: a black logo tile with the yellow cap, on the
   near-black ground with a yellow glow. */
.auth-page {
  background:
    radial-gradient(70% 55% at 50% 0%, rgba(255, 212, 0, .14), transparent 70%),
    #0A0A0A;
}
.auth-head { color: #F4F4F2; }
.auth-head .auth-title { font-family: var(--display); font-weight: 800; letter-spacing: .02em; }
.auth-head .eyebrow { color: #FFD400; }
.auth-head .brand-mark, .setup-brand .brand-mark {
  background: #0B0B0B; color: #FFD400 !important; border: 1px solid #2E2E2E;
  display: grid; place-items: center;
}
.auth-head .brand-mark { width: 64px; height: 64px; border-radius: 18px; }
.auth-head .brand-mark svg { width: 30px; height: 30px; }
.setup-brand .brand-mark { border-radius: 10px; }
.setup-brand .brand-mark svg { width: 20px; height: 20px; }

/* Sidebar on shorter windows: the bottom controls (language, theme,
   settings, the account) always stay on screen. The rows tighten as the
   window gets shorter, and only if that is still not enough does the menu
   itself scroll, never the account under it. */
.sb-nav { flex: 0 1 auto; min-height: 0; overflow-y: auto; scrollbar-width: thin; }
.sb-tools, .sb-user, .sb-brand, .sb-goal { flex-shrink: 0; }
.sb-nav a { padding: 10px 14px; }
@media (max-height: 920px) {
  .app-sidebar { padding-block: 12px; gap: 8px; }
  .sb-brand { padding-bottom: 10px; }
  .brand-mark { width: 38px; height: 38px; flex-basis: 38px; }
  .sb-goal { padding: 8px 12px; }
  .sb-goal-value { font-size: 18px; }
  .sb-group { padding: 8px 12px 3px; }
  .sb-nav { gap: 2px; }
  .sb-nav a { padding: 8px 12px; font-size: 14.5px; }
}
@media (max-height: 780px) {
  .sb-goal-meta { display: none; }
  .sb-nav a { padding: 6px 12px; font-size: 14px; }
  .sb-group { padding: 6px 12px 2px; font-size: 10px; }
  .sb-user { padding: 6px 8px; }
}

/* No scrollbar in the sidebar menu: on shorter windows it tightens further
   instead, dropping the target-score card's date and then the card itself
   (the target is also on Today), so every destination fits. */
.sb-nav { overflow-y: auto; scrollbar-width: none; }
.sb-nav::-webkit-scrollbar { display: none; }
@media (max-height: 860px) {
  .sb-goal-meta { display: none; }
  .sb-group { padding: 6px 12px 2px; }
  .sb-nav a { padding: 7px 12px; }
}
@media (max-height: 760px) {
  .sb-goal { display: none; }
  .brand-text span { display: none; }
  .sb-brand { padding-bottom: 8px; }
  .sb-nav a { padding: 5px 12px; font-size: 13.5px; }
  .sb-nav a em svg { width: 18px; height: 18px; }
  .sb-group { padding: 4px 12px 1px; font-size: 9.5px; }
  .sb-user { padding: 4px 8px; }
  .sb-tools .icon-btn, .lang-switch button { height: 28px; }
}
@media (max-height: 640px) {
  .sb-user-text span { display: none; }
  .sb-nav a { padding: 3px 12px; font-size: 13px; }
}

/* A little wider sidebar. */
:root, html[data-theme="light"], html[data-theme="dark"] { --sidebar-w: 276px; }

/* ---------------------------------------------------------- practice: no scrollbar
   The question area shows no scrollbar. Choices sit tighter so a passage and
   its four answers fit on one screen; a longer question still scrolls with
   the wheel or a swipe, just without the bar. */
body.unit-focus .q-shell.is-practice .q-content { padding-top: 16px; padding-bottom: 16px; scrollbar-width: none; }
body.unit-focus .q-shell.is-practice .q-content::-webkit-scrollbar { display: none; }
.q-shell.is-practice .opt-list { gap: 8px; }
.q-shell.is-practice .opt { font-size: 16px; line-height: 1.45; padding: 10px 16px; }
.q-shell.is-practice .q-passage { font-size: 17px; line-height: 1.6; }

/* ---------------------------------------------------------- practice statistics
   The result of a finished practice set (top of #/practice) and the running
   totals card on the dashboard. */
.ps-kpis { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; flex: 1; min-width: 0; }
.ps-kpi { display: flex; flex-direction: column; gap: 4px; padding: 14px 16px; border: 1px solid var(--border); border-radius: 14px; background: var(--surface-2); min-width: 0; }
.ps-num { font-family: var(--display); font-size: 24px; font-weight: 700; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.ps-hero { display: flex; align-items: center; gap: 24px; }
.ps-ring {
  --p: 0; flex: none; width: 116px; height: 116px; border-radius: 50%; display: grid; place-items: center;
  background: conic-gradient(var(--brand-600) calc(var(--p) * 1%), var(--surface-2) 0);
}
.ps-ring::before { content: ""; grid-area: 1 / 1; width: 88px; height: 88px; border-radius: 50%; background: var(--surface); }
.ps-ring b { grid-area: 1 / 1; position: relative; font-family: var(--display); font-size: 24px; }
.ps-result { border-color: var(--brand-600); }
.ps-bar-row { display: flex; flex-direction: column; gap: 6px; }
.ps-cols { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 24px; align-items: start; }
.ps-week { display: grid; grid-template-columns: repeat(7, 1fr); gap: 8px; align-items: end; height: 120px; }
.ps-day { display: flex; flex-direction: column; align-items: center; gap: 4px; height: 100%; }
.ps-day-n { font-size: 11px; font-weight: 700; min-height: 14px; }
.ps-day-bar { flex: 1; width: 100%; max-width: 28px; display: flex; align-items: flex-end; background: var(--surface-2); border-radius: 8px; overflow: hidden; }
.ps-day-bar i { display: block; width: 100%; min-height: 0; background: var(--brand-600); border-radius: 8px; }
.ps-day-lab { font-size: 11px; color: var(--muted); text-transform: capitalize; }
.ps-topics { display: flex; flex-direction: column; gap: 6px; }
.ps-topic { display: grid; grid-template-columns: minmax(0, 1fr) auto 56px; gap: 12px; align-items: center; padding: 8px 12px; border: 1px solid var(--border); border-radius: 12px; }
.ps-topic-name { font-size: 14px; font-weight: 600; color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
a.ps-topic-name:hover { color: var(--brand-600); }
.ps-topic .xsmall { text-align: right; }
.ps-chip { font-size: 12px; font-weight: 700; padding: 3px 10px; border-radius: 999px; background: var(--surface-2); color: var(--ink); }
.ps-chip.is-ok { background: var(--ok-bg); color: var(--ok); }
.ps-chip.is-low { background: var(--danger-bg); color: var(--danger); }
@media (max-width: 760px) {
  .ps-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ps-hero { flex-direction: column; align-items: stretch; }
  .ps-ring { align-self: center; }
  .ps-cols { grid-template-columns: 1fr; }
}
/* Visible before the question bank finishes loading and the router starts. */
.boot-loading {
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  padding: 24px;
  text-align: center;
}

.boot-loading strong { font-size: 24px; }
.boot-loading p { margin: 12px 0 0; }
