/* Pons design system, v2 (docs/build/ui/03-design-system.md; the top bar and classes: docs/build/classes/01-design.md). One file, loaded by base.html on every page.
   Package files under static/<pkg>/ add only what their pages need and never redefine anything in here.
   No inline style= anywhere (CSP style-src 'self' + nonce); every colour, size and shadow is a token on :root.

   Contents
   1. Tokens (light), dark tokens, reduced motion
   2. Font face (self-hosted Nunito variable, OFL, static/fonts/)
   3. Reset and base type
   4. Icons (inline SVG sprite, <svg class="icon"><use href="#i-name">)
   5. App shell: top bar (tablet icons only, desktop with labels), bottom tabs (phone), content column
   6. Page header, crumbs, section heads
   7. Buttons
   8. Inputs, fields, checks, toggles, segmented controls
   9. Cards and grids
  10. Chips, status, progress ring and bar
  11. Tabs (view switcher)
  12. Empty, loading, error states, skeletons, spinner
  13. Sheets and dialogs (bottom sheet on phone, centred dialog from 640)
  14. Toasts (flash)
  15. Composer (Home) and source tiles
  16. Material cards (uploads), class cards, the "tonight" strip
  17. Lesson layout: rail, document, side panel, chapter path, reader
  18. Study: options, flashcard, rate row, reveal
  19. Chat (tutor)
  20. Players (podcast, clips, full-screen)
  21. Auth pages (centred column)
  22. Utilities
*/

/* ---------------------------------------------------------------- 1. Tokens */
:root {
  /* paper and ink */
  --paper: #f4f4f1;
  --surface: #ffffff;
  --surface-2: #ecece7;
  --surface-3: #e3e3dd;
  --ink: #1f2530;
  --ink-2: #5c6470;
  --ink-3: #636b78;        /* 4.9:1 on paper, 4.5:1 on surface-2: AA for the small labels it carries */
  --line: #e0e1db;         /* card edges */
  --line-strong: #aeb1a9;  /* hover edges, dashed boxes */
  --line-control: #90938c; /* input and button borders: 3.1:1 on white (the UI floor) */
  /* the one accent: raspberry */
  --accent: #b42f62;
  --accent-hover: #9f2756;
  --accent-ink: #8e2049;
  --accent-soft: #f8e3eb;
  --accent-ring: rgba(180, 47, 98, 0.22);
  --on-accent: #ffffff;
  --on-moss: #ffffff;      /* text on a --moss fill: Got it, the rail's done check */
  --on-danger: #ffffff;    /* text on a --danger fill: Delete */
  /* one colour per kind of content (tiles, rings, chips only; never body text) */
  --honey: #b9790f;      --honey-soft: #fbefd3;     --honey-ink: #956107;     /* summary, reading */
  --cobalt: #3457d5;     --cobalt-soft: #e3e9fb;    --cobalt-ink: #3457d5;    /* flashcards, review */
  --moss: #2f7f55;       --moss-soft: #ddf1e4;      --moss-ink: #2a7049;      /* map, done, correct */
  --plum: #6e4aa3;       --plum-soft: #ece4f7;      --plum-ink: #6e4aa3;      /* podcast, tutor */
  --tangerine: #d5651f;  --tangerine-soft: #fbe6d6; --tangerine-ink: #ab4b18; /* videos */
  /* the -ink variants are the same hue dark enough to read as 13 px text on the -soft fill, white and paper (>= 4.6:1) */
  --danger: #c8322b;     --danger-soft: #f9e1df;    --danger-ink: #be2f29;    /* --danger fills and borders; -ink is the text */
  --warn-soft: #fbefd3;
  /* type */
  --font: "Nunito", "Segoe UI", system-ui, -apple-system, Roboto, sans-serif;
  --fs-0: 0.8125rem;  /* 13 */
  --fs-1: 0.875rem;   /* 14 */
  --fs-2: 1rem;       /* 16 */
  --fs-3: 1.125rem;   /* 18 */
  --fs-4: 1.375rem;   /* 22 */
  --fs-5: 1.75rem;    /* 28 */
  --fs-6: 2.25rem;    /* 36 */
  --fs-reader: 1.0625rem; /* 17 */
  --lh-tight: 1.2;
  --lh-body: 1.55;
  --lh-reader: 1.7;
  --measure: 66ch;
  /* spacing (4-based) */
  --sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px; --sp-5: 20px;
  --sp-6: 24px; --sp-7: 32px; --sp-8: 40px; --sp-9: 56px; --sp-10: 80px;
  /* radii encode hierarchy: controls 12, cards 16, panels 24 */
  --r-sm: 8px; --r-md: 12px; --r-lg: 16px; --r-xl: 24px; --r-pill: 999px;
  /* elevation: cards are flat; only floating things cast */
  --shadow-float: 0 12px 32px -8px rgba(31, 37, 48, 0.18), 0 2px 6px rgba(31, 37, 48, 0.06);
  --shadow-pop: 0 24px 64px -16px rgba(31, 37, 48, 0.28), 0 4px 12px rgba(31, 37, 48, 0.08);
  --shadow-sheet: 0 -8px 40px rgba(31, 37, 48, 0.18);
  /* motion */
  --ease: cubic-bezier(0.2, 0.7, 0.2, 1);
  --t-fast: 140ms;
  --t-med: 220ms;
  /* sizes */
  --tap: 44px;
  --tabbar-h: 64px;
  --topbar-h: 64px;
  --content-max: 1120px;
  --gutter: 16px;
  --focus: var(--accent);
  color-scheme: light dark;
}

@media (prefers-color-scheme: dark) {
  :root {
    --paper: #15181e;
    --surface: #1d2129;
    --surface-2: #262b35;
    --surface-3: #30363f;
    --ink: #ecede9;
    --ink-2: #a4abb6;
    --ink-3: #868e9a;
    --line: #2d323c;
    --line-strong: #3d434e;
    --line-control: #646c78;
    --accent: #f06e9e;
    --accent-hover: #f588ae;
    --accent-ink: #ffb3cc;
    --accent-soft: #3a1f2c;
    --accent-ring: rgba(240, 110, 158, 0.28);
    --on-accent: #1a0a11;
    --on-moss: #0f2418;
    --on-danger: #2a0f0d;
    --honey: #e2a53a;      --honey-soft: #2f2b20;     --honey-ink: #e2a53a;
    --cobalt: #7f9bff;     --cobalt-soft: #1f2846;    --cobalt-ink: #7f9bff;
    --moss: #6cc08f;       --moss-soft: #16301f;      --moss-ink: #6cc08f;
    --plum: #b596e8;       --plum-soft: #2a2140;      --plum-ink: #b596e8;
    --tangerine: #f0945a;  --tangerine-soft: #3d2516; --tangerine-ink: #f0945a;
    --danger: #f07c74;     --danger-soft: #3d1f1d;    --danger-ink: #f07c74;
    --warn-soft: #2f2b20;
    --shadow-float: 0 12px 32px -8px rgba(0, 0, 0, 0.6), 0 2px 6px rgba(0, 0, 0, 0.3);
    --shadow-pop: 0 24px 64px -16px rgba(0, 0, 0, 0.7), 0 4px 12px rgba(0, 0, 0, 0.3);
    --shadow-sheet: 0 -8px 40px rgba(0, 0, 0, 0.6);
  }
}

@media (prefers-reduced-motion: reduce) {
  :root { --t-fast: 0ms; --t-med: 0ms; }
  *, *::before, *::after { animation: none !important; transition: none !important; }
}

/* ---------------------------------------------------------------- 2. Font face */
@font-face {
  font-family: "Nunito";
  src: url("fonts/Nunito-variable.ttf") format("truetype-variations"), url("fonts/Nunito-variable.ttf") format("truetype");
  font-weight: 200 1000;
  font-style: normal;
  font-display: swap;
}

/* ---------------------------------------------------------------- 3. Reset and base type */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; height: 100%; }
body {
  margin: 0; min-height: 100dvh;
  background: var(--paper); color: var(--ink);
  font-family: var(--font); font-size: var(--fs-2); font-weight: 500; line-height: var(--lh-body);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}
h1, h2, h3, h4 { margin: 0; line-height: var(--lh-tight); font-weight: 800; letter-spacing: -0.012em; overflow-wrap: anywhere; }
h1 { font-size: var(--fs-5); }
h2 { font-size: var(--fs-4); }
h3 { font-size: var(--fs-3); }
h4 { font-size: var(--fs-2); }
p { margin: 0 0 var(--sp-3); }
p:last-child { margin-bottom: 0; }
a { color: var(--accent-ink); text-decoration: none; }
a:hover { text-decoration: underline; text-underline-offset: 0.15em; }
strong, b { font-weight: 700; }
small, .small { font-size: var(--fs-1); }
.muted { color: var(--ink-2); }
.lede { color: var(--ink-2); font-size: var(--fs-3); font-weight: 500; max-width: var(--measure); }
ul, ol { margin: 0 0 var(--sp-3); padding-left: 1.25em; }
dl { margin: 0; }
figure { margin: 0; }
img, svg, video { max-width: 100%; display: block; }
mark { background: var(--honey-soft); color: inherit; border-radius: 3px; padding: 0 2px; }
hr { border: 0; border-top: 1px solid var(--line); margin: var(--sp-6) 0; }
:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; border-radius: var(--r-sm); }
.skip-link { position: absolute; left: -9999px; }
.skip-link:focus { left: var(--sp-4); top: var(--sp-4); z-index: 100; background: var(--surface); padding: var(--sp-2) var(--sp-3); border-radius: var(--r-md); }
[hidden] { display: none !important; }

/* ---------------------------------------------------------------- 4. Icons */
.icon { width: 1.25em; height: 1.25em; flex: none; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; display: inline-block; vertical-align: -0.3em; }
.icon, .mark { max-width: none; }
.icon-sm { width: 1em; height: 1em; }
.icon-lg { width: 1.5em; height: 1.5em; }
.icon-xl { width: 2em; height: 2em; }
.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }
/* the mark: the Pons bridge, drawn in the sprite as #i-mark (fill, not stroke); .mark-inner stays for any stroked detail */
.mark { width: 32px; height: 32px; flex: none; }
.mark-outer { fill: var(--accent); }
.mark-inner { fill: none; stroke: var(--on-accent); stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }

/* ---------------------------------------------------------------- 5. App shell */
/* Markup (docs/build/classes/01-design.md § 2): body > a.skip-link + div.app(.has-nav) > (header.topbar + main#main.main
   > div.content) + nav.tabbar (phone only). .has-nav is set when the page renders its navigation (signed in).
   Phone < 640: no bar, bottom tabs. Tablet 640-1023: the sticky 64 px bar with icons only (44 px squares, title=), the
   badge on the icon's corner, Add notes as an icon button, the avatar alone. Desktop >= 1024: icons + labels. */
.app { display: grid; grid-template-columns: minmax(0, 1fr); min-height: 100dvh; }
.app.has-nav { grid-template-rows: auto minmax(0, 1fr); }
.main { min-width: 0; }
.content {
  width: 100%; max-width: var(--content-max); margin: 0 auto;
  padding: calc(env(safe-area-inset-top) + var(--sp-5)) var(--gutter) var(--sp-8);
}
.content--narrow { max-width: 760px; }
.content--reader { max-width: 880px; }
.content--wide { max-width: 1560px; }
body.signed-in .content { padding-bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom) + var(--sp-6)); }

/* the top bar: hidden on a phone, sticky from 640 */
.topbar { display: none; position: sticky; top: 0; z-index: 30; background: var(--surface); border-bottom: 1px solid var(--line); }
.topbar-inner { display: flex; align-items: center; gap: var(--sp-2); height: var(--topbar-h); padding: 0 var(--gutter); }
.topbar-brand { display: inline-flex; align-items: center; gap: 10px; margin-right: var(--sp-4); color: var(--ink); text-decoration: none; font-weight: 800; font-size: 20px; letter-spacing: -0.012em; line-height: 1; }
.topbar-brand:hover { text-decoration: none; color: var(--accent-ink); }
.topbar-brand .mark { width: 30px; height: 30px; }
.topbar-brand span { display: none; }
.topbar-nav { display: flex; align-items: center; gap: var(--sp-1); }
.topbar .nav-item { display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2); min-height: 44px; min-width: 44px; padding: 0 var(--sp-2); border-radius: var(--r-md); color: var(--ink-2); font-size: 15px; font-weight: 700; text-decoration: none; position: relative; transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease); }
.topbar .nav-item:hover { background: var(--surface-2); color: var(--ink); text-decoration: none; }
.topbar .nav-item .icon { width: 22px; height: 22px; }
.topbar .nav-item.is-active, .topbar .nav-item[aria-current="page"] { background: var(--accent-soft); color: var(--accent-ink); }
.topbar .nav-item.is-active .icon { stroke-width: 2.2; }
.topbar .nav-item > span { display: none; }
.topbar .nav-badge { position: absolute; top: 3px; right: 3px; min-width: 18px; height: 18px; padding: 0 5px; border-radius: var(--r-pill); background: var(--accent); color: var(--on-accent); font-size: 0.6875rem; font-weight: 800; line-height: 18px; text-align: center; }
.topbar-end { margin-left: auto; display: flex; align-items: center; gap: var(--sp-2); }
.topbar-add { min-height: 44px; width: 44px; padding: 0; border-radius: var(--r-md); }
.topbar-add span { display: none; }
.avatar { width: 32px; height: 32px; border-radius: 50%; background: var(--surface-3); color: var(--ink-2); display: inline-flex; align-items: center; justify-content: center; font-weight: 800; font-size: var(--fs-1); flex: none; }
/* the account menu: a <details> whose summary is the avatar (+ name on desktop) and whose body is a popover; app.js
   closes it on an outside click and Escape */
.account { position: relative; }
.account > summary { list-style: none; display: inline-flex; align-items: center; gap: var(--sp-2); min-height: 44px; padding: 0 4px; border-radius: var(--r-pill); cursor: pointer; color: var(--ink-2); font-weight: 700; font-size: 15px; }
.account > summary::-webkit-details-marker { display: none; }
.account > summary:hover { background: var(--surface-2); color: var(--ink); }
.account > summary > span:last-child { display: none; }
.account-menu { position: absolute; right: 0; top: calc(100% + 8px); min-width: 232px; padding: var(--sp-2); background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg); box-shadow: var(--shadow-pop); z-index: 31; }
.account-menu .account-name { padding: var(--sp-2) var(--sp-3); font-weight: 800; }
.account-menu form { margin: 0; }
.account-menu a, .account-menu button { display: flex; align-items: center; justify-content: flex-start; gap: var(--sp-3); width: 100%; min-height: 44px; padding: 0 var(--sp-3); border: 0; background: none; border-radius: var(--r-md); color: var(--ink); font: inherit; font-weight: 700; text-decoration: none; cursor: pointer; text-align: left; box-shadow: none; }
.account-menu a:hover, .account-menu button:hover { background: var(--surface-2); text-decoration: none; }
.account-menu a.account-quiet { color: var(--ink-2); font-weight: 500; }   /* Tell George something: there, not shouting */

/* bottom tabs: phone only. Five cells; the middle one is the raised Add button. */
.tabbar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
  display: grid; grid-template-columns: repeat(5, 1fr); align-items: start;
  height: calc(var(--tabbar-h) + env(safe-area-inset-bottom));
  padding: var(--sp-2) var(--sp-2) env(safe-area-inset-bottom);
  background: var(--surface); border-top: 1px solid var(--line);
}
.tab {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
  min-height: var(--tap); color: var(--ink-2); font-size: 0.6875rem; font-weight: 700; letter-spacing: 0.01em;
  text-decoration: none; border-radius: var(--r-md);
}
.tab:hover { text-decoration: none; }
.tab .icon, .tab-icon { width: 24px; height: 24px; }
.tab.active, .tab[aria-current="page"] { color: var(--accent-ink); }
.tab.active .icon, .tab[aria-current="page"] .icon { stroke-width: 2.2; }
.tab-upload { color: var(--accent-ink); }
.tab-upload-circle {
  display: flex; align-items: center; justify-content: center;
  width: 52px; height: 52px; margin-top: -24px; border-radius: 50%;
  background: var(--accent); color: var(--on-accent); box-shadow: var(--shadow-float);
}
.tab-upload-circle .icon, .tab-upload-circle .tab-icon { width: 26px; height: 26px; stroke-width: 2.4; }

/* tablet 640-1023: the gutter and the top padding grow with the width */
@media (min-width: 640px) {
  :root { --gutter: 24px; }
  .content { padding-top: var(--sp-6); }
}
/* The phone shell (bottom tabs with labels, no top bar) is keyed on the device, not the width alone (shakedown P35): a
   sideways phone (844 x 390) kept the tabs; it used to get the tablet bar with no labels and a bare "+". The bar takes
   over only on a fine pointer (a mouse or trackpad) or no pointer at all from 640 px, on any pointer from 1024 px
   (an iPad sideways), and never when the viewport is 500 px high or less. The three branches are one OR list so no
   `not` is needed. */
@media (min-width: 640px) and (min-height: 501px) and (pointer: fine),
       (min-width: 640px) and (min-height: 501px) and (pointer: none),
       (min-width: 1024px) and (min-height: 501px) {
  .topbar { display: block; }
  .tabbar { display: none; }
  body.signed-in .content { padding-bottom: var(--sp-8); }
}

/* desktop >= 1024: labels beside the icons, "Add notes" in words, the name beside the avatar */
@media (min-width: 1024px) {
  :root { --gutter: 40px; }
  .topbar-brand span { display: inline; }
  .topbar .nav-item { padding: 0 var(--sp-3); }
  .topbar .nav-item > span { display: inline; }
  .topbar .nav-badge { position: static; margin-left: 2px; }
  .topbar-add { width: auto; padding: 0 var(--sp-4); gap: var(--sp-2); }
  .topbar-add span { display: inline; }
  .account > summary { padding-right: var(--sp-3); }
  .account > summary > span:last-child { display: inline; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 160px; }
  .content { padding-top: var(--sp-7); }
}

/* ---------------------------------------------------------------- 6. Page header, crumbs, section heads */
.page-head { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--sp-3) var(--sp-5); margin-bottom: var(--sp-6); }
.page-head > .page-title-wrap { flex: 1 1 320px; min-width: 0; }
.page-title { font-size: var(--fs-5); }
.page-lede { color: var(--ink-2); margin-top: var(--sp-1); max-width: var(--measure); }
.page-actions { display: flex; flex-wrap: wrap; gap: var(--sp-2); align-items: center; }
.crumb { display: inline-flex; align-items: center; gap: var(--sp-1); min-height: 32px; color: var(--ink-2); font-size: var(--fs-1); font-weight: 700; text-decoration: none; }
.crumb:hover { color: var(--ink); text-decoration: none; }
.crumb .icon { width: 18px; height: 18px; }
.kicker { color: var(--ink-2); font-size: var(--fs-1); font-weight: 700; margin-bottom: var(--sp-1); }
.section-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-3); margin: var(--sp-7) 0 var(--sp-4); }
.section-head h2 { font-size: var(--fs-4); }
.section-head .muted { font-size: var(--fs-1); font-weight: 700; }
@media (min-width: 1024px) {
  .page-title { font-size: var(--fs-6); }
  .page-head { margin-bottom: var(--sp-7); }
}

/* ---------------------------------------------------------------- 7. Buttons */
.button, button, input[type="submit"] {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2);
  min-height: var(--tap); padding: 0 var(--sp-5);
  border: 1px solid var(--line-control); border-radius: var(--r-md);
  background: var(--surface); color: var(--ink);
  font: inherit; font-weight: 700; line-height: 1.2; text-decoration: none; cursor: pointer; white-space: nowrap;
  -webkit-tap-highlight-color: transparent; touch-action: manipulation;
  transition: background var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease), transform var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
.button:hover, button:hover { background: var(--surface-2); text-decoration: none; }
.button:active, button:active { transform: translateY(1px); }
.button.primary, button.primary, a.primary {
  background: var(--accent); border-color: var(--accent); color: var(--on-accent);
  box-shadow: inset 0 -3px 0 rgba(0, 0, 0, 0.14);
}
.button.primary:hover, button.primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); }
.button.secondary, button.secondary { background: var(--accent-soft); border-color: transparent; color: var(--accent-ink); }
.button.secondary:hover, button.secondary:hover { background: var(--accent-soft); filter: brightness(0.97); }
.button.quiet, button.quiet { background: transparent; border-color: transparent; color: var(--accent-ink); }
.button.quiet:hover, button.quiet:hover { background: var(--accent-soft); }
.button.danger, button.danger { background: var(--danger); border-color: var(--danger); color: var(--on-danger); }
.button.danger-quiet, button.danger-quiet { background: transparent; border-color: transparent; color: var(--danger-ink); }
.button.danger-quiet:hover { background: var(--danger-soft); }
.button.big, button.big { min-height: 56px; font-size: var(--fs-3); padding: 0 var(--sp-6); border-radius: var(--r-lg); }
.button.small, button.small { min-height: 36px; padding: 0 var(--sp-3); font-size: var(--fs-1); border-radius: var(--r-sm); }
.button.block { width: 100%; }
.button.icon-button, button.icon-button { width: var(--tap); padding: 0; }
.button.icon-button.small { width: 36px; }
/* on a phone every small button and the crumb is a 44 px target (media Retry/Download, auth Remove, lesson Fit, study) */
@media (max-width: 639px) {
  .button.small, button.small, .crumb { min-height: var(--tap); }
  .button.small, button.small { min-width: var(--tap); }   /* Star under a card was 44x32 (review-phone r2) */
  .button.icon-button.small { width: var(--tap); }
}
.button .icon, button .icon { width: 20px; height: 20px; }
button.link, .link { display: inline; background: none; border: 0; padding: 0; min-height: 0; color: var(--accent-ink); font: inherit; font-weight: 700; text-decoration: underline; text-underline-offset: 0.15em; cursor: pointer; }
button[disabled], .button[aria-disabled="true"], .button.is-disabled { opacity: 0.45; cursor: default; pointer-events: none; }
.button-row { display: flex; flex-wrap: wrap; gap: var(--sp-2); align-items: center; }
.button-row.end { justify-content: flex-end; }
.button-row.split { justify-content: space-between; }
@media (max-width: 639px) { .button.big { width: 100%; } }

/* ---------------------------------------------------------------- 8. Inputs */
input, textarea, select {
  width: 100%; min-height: 48px; padding: var(--sp-2) var(--sp-4);
  border: 1px solid var(--line-control); border-radius: var(--r-md);
  background: var(--surface); color: var(--ink); font: inherit; font-size: 16px; font-weight: 500;
  transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
input:focus, textarea:focus, select:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 4px var(--accent-ring); }
input::placeholder, textarea::placeholder { color: var(--ink-3); }
textarea { min-height: 140px; resize: vertical; line-height: var(--lh-body); }
select {
  appearance: none; -webkit-appearance: none; padding-right: 44px; cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235c6470' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 14px center; background-size: 20px;
}
@media (prefers-color-scheme: dark) {
  select { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23a4abb6' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E"); }
}
label { font-weight: 700; }
.field { display: flex; flex-direction: column; gap: var(--sp-2); }
.field-label { font-size: var(--fs-1); font-weight: 700; color: var(--ink); }
.field-hint { font-size: var(--fs-1); color: var(--ink-2); font-weight: 500; }
.field-row { display: grid; gap: var(--sp-3); }
@media (min-width: 640px) { .field-row { grid-template-columns: 1fr 1fr; } }
/* settings row: label + hint left, control right */
.setting-row { display: grid; grid-template-columns: 1fr; gap: var(--sp-2); padding: var(--sp-4) 0; border-top: 1px solid var(--line); }
.setting-row:first-child { border-top: 0; }
.setting-row .field-hint { margin-top: 2px; }
@media (min-width: 640px) { .setting-row { grid-template-columns: 1fr 300px; align-items: center; gap: var(--sp-5); } }
/* a box to tick: 24 px inside a 44 px row */
.check-row { display: flex; align-items: center; gap: var(--sp-3); min-height: var(--tap); cursor: pointer; font-weight: 700; }
.check-row input[type="checkbox"] { width: 22px; height: 22px; min-height: 0; padding: 0; margin: 0; flex: none; accent-color: var(--accent); border-radius: 6px; }
/* switch: label.switch > input + span */
.switch { position: relative; display: inline-flex; align-items: center; gap: var(--sp-3); min-height: var(--tap); cursor: pointer; font-weight: 700; }
.switch input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.switch span::before { content: ""; display: inline-block; width: 44px; height: 26px; border-radius: var(--r-pill); background: var(--surface-3); vertical-align: middle; margin-right: var(--sp-2); box-shadow: inset 3px 0 0 3px var(--surface-3), inset 0 0 0 3px var(--surface-3), inset -21px 0 0 var(--surface); transition: background var(--t-med) var(--ease), box-shadow var(--t-med) var(--ease); }
.switch input:checked + span::before { background: var(--accent); box-shadow: inset -3px 0 0 3px var(--accent), inset 0 0 0 3px var(--accent), inset 21px 0 0 var(--on-accent); }
.switch input:focus-visible + span::before { outline: 3px solid var(--focus); outline-offset: 2px; }
/* segmented control: fieldset.segmented > legend + label > input + span. The legend reads as a label above the track
   (design § 4 Inputs): absolutely positioned (so it is not the fieldset's rendered legend inside the border) and the
   fieldset leaves a line of room for it. */
.segmented, .confidence { position: relative; display: flex; border: 1px solid var(--line-control); border-radius: var(--r-md); padding: 3px; background: var(--surface); margin: 0; gap: 2px; }
.segmented:has(> legend), .confidence:has(> legend) { margin-top: 30px; }
.segmented legend, .confidence legend { position: absolute; left: 0; top: -30px; width: 100%; padding: 0; margin: 0; line-height: 22px; font-size: var(--fs-1); font-weight: 700; color: var(--ink-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.segmented label, .confidence label { flex: 1; cursor: pointer; }
.segmented input, .confidence input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.segmented span, .confidence span { display: flex; align-items: center; justify-content: center; min-height: 38px; padding: 0 var(--sp-3); border-radius: calc(var(--r-md) - 3px); font-size: var(--fs-1); font-weight: 700; color: var(--ink-2); transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease); }
@media (max-width: 639px) { .segmented span, .confidence span { min-height: var(--tap); } }   /* the whole row is a tap target on a phone (review-phone r2); 38 px with a mouse */
.segmented input:checked + span, .confidence input:checked + span { background: var(--ink); color: var(--paper); }
.segmented input:focus-visible + span, .confidence input:focus-visible + span { outline: 3px solid var(--focus); outline-offset: -3px; }
/* toggle list rows (learn/test setup) */
.toggles { display: grid; gap: var(--sp-2); margin: 0; padding: 0; border: 0; }
.toggle { display: flex; align-items: center; gap: var(--sp-3); min-height: var(--tap); padding: 0 var(--sp-3); border: 1px solid var(--line); border-radius: var(--r-md); background: var(--surface); cursor: pointer; font-weight: 700; }
.toggle input { width: 22px; height: 22px; min-height: 0; padding: 0; margin: 0; flex: none; accent-color: var(--accent); }
.toggle:has(input:checked) { border-color: var(--accent); background: var(--accent-soft); }

/* ---------------------------------------------------------------- 9. Cards and grids */
.card {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg);
  padding: var(--sp-5); margin: 0;
}
.card + .card, .stack > .card + .card { margin-top: var(--sp-3); }
.card-grid > .card + .card, .library > .card + .card, .tonight > .card + .card { margin-top: 0; }
.card-link { display: block; color: inherit; text-decoration: none; }
.card-link:hover { text-decoration: none; }
a.card:hover, .card:has(> .card-link:hover), .card.is-link:hover { border-color: var(--line-strong); }
.card-title { font-size: var(--fs-3); font-weight: 800; margin-bottom: var(--sp-1); }
.card-meta { color: var(--ink-2); font-size: var(--fs-1); font-weight: 700; }
.card-tint { padding: var(--sp-5); border-radius: var(--r-lg); border: 0; }
.card-tint.honey { background: var(--honey-soft); }
.card-tint.cobalt { background: var(--cobalt-soft); }
.card-tint.moss { background: var(--moss-soft); }
.card-tint.plum { background: var(--plum-soft); }
.card-tint.tangerine { background: var(--tangerine-soft); }
.card-tint.accent { background: var(--accent-soft); }
.panel { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-xl); padding: var(--sp-6); }
.card-grid { display: grid; gap: var(--sp-4); grid-template-columns: 1fr; }
@media (min-width: 640px) { .card-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1200px) { .card-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.card-grid--2 { grid-template-columns: 1fr; }
@media (min-width: 800px) { .card-grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
/* kind tile: a coloured rounded square holding one icon */
.kind { display: inline-flex; align-items: center; justify-content: center; width: 40px; height: 40px; border-radius: var(--r-md); flex: none; }
.kind .icon { width: 22px; height: 22px; stroke-width: 2; }
.kind.honey { background: var(--honey-soft); color: var(--honey-ink); }
.kind.cobalt { background: var(--cobalt-soft); color: var(--cobalt-ink); }
.kind.moss { background: var(--moss-soft); color: var(--moss-ink); }
.kind.plum { background: var(--plum-soft); color: var(--plum-ink); }
.kind.tangerine { background: var(--tangerine-soft); color: var(--tangerine-ink); }
.kind.accent { background: var(--accent-soft); color: var(--accent-ink); }
.kind.big { width: 56px; height: 56px; border-radius: var(--r-lg); }
.kind.big .icon { width: 28px; height: 28px; }
/* a row with a tile left and text right */
.tile-row { display: flex; align-items: center; gap: var(--sp-4); min-height: var(--tap); color: inherit; text-decoration: none; }
.tile-row:hover { text-decoration: none; }
.tile-row-text { min-width: 0; flex: 1; display: flex; flex-direction: column; }
.tile-row-title { font-weight: 800; display: block; }
.tile-row-meta { color: var(--ink-2); font-size: var(--fs-1); font-weight: 700; display: block; }
.tile-row .chevron { color: var(--ink-3); width: 20px; height: 20px; }
.list { list-style: none; margin: 0; padding: 0; }
.list > li + li { border-top: 1px solid var(--line); }
.list > li { padding: var(--sp-3) 0; }

/* ---------------------------------------------------------------- 10. Chips, status, progress */
.chip {
  display: inline-flex; align-items: center; gap: 4px; min-height: 26px; padding: 0 var(--sp-2);
  border-radius: var(--r-pill); font-size: var(--fs-0); font-weight: 700; text-decoration: none;
  background: var(--surface-2); color: var(--ink-2); vertical-align: baseline; white-space: nowrap;
}
.chip .icon { width: 14px; height: 14px; }
.chip-text { background: var(--accent-soft); color: var(--accent-ink); }
.chip-background { background: var(--warn-soft); color: var(--honey-ink); }
.chip-derived { background: var(--surface-2); color: var(--ink-2); }
.chip-unknown { background: var(--danger-soft); color: var(--danger-ink); }
.chip.honey { background: var(--honey-soft); color: var(--honey-ink); }
.chip.cobalt { background: var(--cobalt-soft); color: var(--cobalt-ink); }
.chip.moss { background: var(--moss-soft); color: var(--moss-ink); }
.chip.plum { background: var(--plum-soft); color: var(--plum-ink); }
.chip.tangerine { background: var(--tangerine-soft); color: var(--tangerine-ink); }
/* a chip that goes somewhere (the Study guide on a class card, a due-by-class chip): no underline, an edge on hover;
   a 44 px tap band above and below the 26 px pill without changing its look (phone r2 minor) */
a.chip { position: relative; }
a.chip::before { content: ""; position: absolute; inset: -9px 0; }
a.chip:hover { text-decoration: none; box-shadow: inset 0 0 0 1.5px var(--line-strong); }
/* a material nobody chose a kind for (0005 kind_set = 0): the chip asks, dashed in the accent, and opens Move */
.chip.is-unset { background: transparent; border: 1.5px dashed var(--accent); color: var(--accent-ink); }
.chip.is-unset:hover { box-shadow: none; background: var(--accent-soft); }
details.chip { display: inline-block; padding: 2px var(--sp-2); }
details.chip summary { cursor: pointer; list-style: none; }
details.chip summary::-webkit-details-marker { display: none; }
.chip-legend { display: block; font-weight: 500; padding: var(--sp-1) 0; white-space: normal; }
.chip-row { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
/* status: a dot and a word */
.status { display: inline-flex; align-items: center; gap: 6px; font-size: var(--fs-1); font-weight: 700; color: var(--ink-2); }
.status::before { content: ""; width: 8px; height: 8px; border-radius: 50%; background: var(--ink-3); flex: none; }
.status.ok::before { background: var(--moss); }
.status.working::before { background: var(--honey); animation: pulse 1.4s ease-in-out infinite; }
.status.failed { color: var(--danger-ink); }
.status.failed::before { background: var(--danger); }
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }
/* ring: svg.ring > circle.ring-track + circle.ring-fill (+ text.ring-text); fill via stroke-dasharray from the server */
.ring { width: 44px; height: 44px; transform: rotate(-90deg); flex: none; }
.ring-track { fill: none; stroke: var(--surface-3); stroke-width: 4; }
.ring-fill { fill: none; stroke: var(--accent); stroke-width: 4; stroke-linecap: round; transition: stroke-dasharray var(--t-med) var(--ease); }
.ring.moss .ring-fill { stroke: var(--moss); }
.ring.is-zero .ring-fill { display: none; }  /* a round cap on a zero dash would still draw a dot */
.ring.is-zero .ring-text { display: none; }  /* an empty ring says "not started"; a column of 0% says nothing */
.upload-card .ring.is-zero { display: none; }  /* the library card: no ring at all until she has studied (Progress keeps its track) */
.ring.cobalt .ring-fill { stroke: var(--cobalt); }
.ring-text { transform: rotate(90deg); transform-origin: center; fill: var(--ink); font-weight: 800; font-size: 11px; text-anchor: middle; dominant-baseline: central; font-family: var(--font); }
.ring.big { width: 96px; height: 96px; }
.ring.big .ring-track, .ring.big .ring-fill { stroke-width: 3; }
.ring.big .ring-text { font-size: 9px; }
/* bar */
/* bar: <progress class="bar" value="43" max="100"> (no inline style under the CSP) */
.bar { display: block; width: 100%; height: 6px; border: 0; border-radius: var(--r-pill); background: var(--surface-3); overflow: hidden; appearance: none; -webkit-appearance: none; }
.bar::-webkit-progress-bar { background: transparent; }
.bar::-webkit-progress-value { background: var(--accent); border-radius: var(--r-pill); transition: width var(--t-med) var(--ease); }
.bar::-moz-progress-bar { background: var(--accent); border-radius: var(--r-pill); }
.bar.moss::-webkit-progress-value { background: var(--moss); }
.bar.moss::-moz-progress-bar { background: var(--moss); }
.bar-line { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); font-size: var(--fs-1); font-weight: 700; color: var(--ink-2); margin-bottom: var(--sp-2); }
/* counter pill (question 3 of 8) */
.counter { display: inline-flex; align-items: center; min-height: 28px; padding: 0 var(--sp-3); border-radius: var(--r-pill); background: var(--accent-soft); color: var(--accent-ink); font-size: var(--fs-1); font-weight: 800; }

/* ---------------------------------------------------------------- 11. Tabs */
.tabs, .lesson-tabs { display: flex; gap: var(--sp-1); padding: 4px; border-radius: var(--r-md); background: var(--surface-2); overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch; }
.tabs::-webkit-scrollbar, .lesson-tabs::-webkit-scrollbar { display: none; }
.tab-link, .lesson-tab-link {
  display: inline-flex; align-items: center; gap: var(--sp-2); min-height: 40px; padding: 0 14px; flex: none;
  border-radius: calc(var(--r-md) - 4px); color: var(--ink-2); font-size: var(--fs-1); font-weight: 700; text-decoration: none; white-space: nowrap;
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.tab-link:hover, .lesson-tab-link:hover { color: var(--ink); text-decoration: none; }
.tab-link .icon { width: 18px; height: 18px; }
.tab-link.is-active, .tab-link.active, .tab-link[aria-current="page"], .lesson-tab-link.active, .lesson-tab-link[aria-current="page"] { background: var(--surface); color: var(--ink); box-shadow: 0 1px 2px rgba(31, 37, 48, 0.08); }
@media (min-width: 640px) { .tabs, .lesson-tabs { display: inline-flex; } }
/* scroll cue on phone: fade at the right edge (not for the chapter strip, whose five tabs fit: .lesson-tabs below) */
.tabs-wrap { position: relative; }
@media (max-width: 639px) {
  .tabs-wrap:not(:has(.lesson-tabs))::after { content: ""; position: absolute; top: 0; right: 0; bottom: 0; width: 32px; border-radius: 0 var(--r-md) var(--r-md) 0; background: linear-gradient(to right, transparent, var(--surface-2)); pointer-events: none; }
  .lesson-tabs { overflow: hidden; gap: 2px; padding: 2px; }
  /* a 44 px pill (ui review r2: 40 was under the tap rule); the strip's padding shrinks to 2 so the row stays 48 */
  .lesson-tab-link { flex: 1 1 0; min-width: 0; justify-content: center; padding: 0 4px; font-size: var(--fs-0); letter-spacing: -0.01em; min-height: var(--tap); }
}

/* ---------------------------------------------------------------- 12. Empty, loading, error states */
.empty { text-align: center; color: var(--ink-2); padding: var(--sp-8) var(--sp-5); border: 1px dashed var(--line-strong); border-radius: var(--r-lg); }
.empty .kind { margin: 0 auto var(--sp-4); }
.empty h3 { color: var(--ink); margin-bottom: var(--sp-2); }
.empty p { max-width: 44ch; margin-left: auto; margin-right: auto; }
.empty .button { margin-top: var(--sp-4); }
/* beside the top bar's "Add notes" the empty state's button is a second copy of the same action, so it reads as
   secondary there (the phone keeps the primary; tests read the anchor's text and attributes, never its colour) */
@media (min-width: 1024px) {
  .app.has-nav .empty .button.primary { background: var(--accent-soft); border-color: transparent; color: var(--accent-ink); box-shadow: none; }
  .app.has-nav .empty .button.primary:hover { background: var(--accent-soft); filter: brightness(0.97); }
}
.status-line { color: var(--ink-2); margin: 0; font-weight: 700; }
.error-line { color: var(--danger-ink); margin: 0; font-weight: 700; }
.elapsed { color: var(--ink-3); white-space: nowrap; font-weight: 700; }
.skeleton { background: linear-gradient(90deg, var(--surface-2) 25%, var(--surface-3) 50%, var(--surface-2) 75%); background-size: 200% 100%; animation: shimmer 1.4s linear infinite; border-radius: var(--r-sm); color: transparent; min-height: 1em; }
.skeleton.line { height: 14px; margin: 8px 0; }
.skeleton.line.short { width: 55%; }
.skeleton-lines { padding: var(--sp-1) 0; }
@keyframes shimmer { to { background-position: -200% 0; } }
.spinner { display: inline-block; vertical-align: middle; width: 18px; height: 18px; border: 2.5px solid var(--surface-3); border-top-color: var(--accent); border-radius: 50%; animation: spin 0.8s linear infinite; flex: none; }
@keyframes spin { to { transform: rotate(360deg); } }
.htmx-indicator { opacity: 0; transition: opacity 200ms ease-in; }
.htmx-request .htmx-indicator, .htmx-request.htmx-indicator { opacity: 1; }
.notice { display: flex; gap: var(--sp-3); align-items: flex-start; padding: var(--sp-3) var(--sp-4); border-radius: var(--r-md); background: var(--surface-2); font-weight: 500; }
.notice.warn { background: var(--warn-soft); }
.notice.danger { background: var(--danger-soft); color: var(--danger-ink); }
.notice .icon { margin-top: 2px; }

/* ---------------------------------------------------------------- 13. Sheets and dialogs */
dialog.sheet, dialog.study-sheet {
  width: 100%; max-width: 100%; max-height: 92dvh; margin: auto auto 0; padding: 0; border: 0;
  border-radius: var(--r-xl) var(--r-xl) 0 0; background: var(--surface); color: var(--ink);
  box-shadow: var(--shadow-sheet); overflow: auto; overscroll-behavior: contain;
}
dialog.sheet::backdrop, dialog.study-sheet::backdrop { background: rgba(31, 37, 48, 0.45); backdrop-filter: blur(2px); }
dialog.sheet[open], dialog.study-sheet[open] { animation: sheet-up var(--t-med) var(--ease); }
@keyframes sheet-up { from { transform: translateY(24px); opacity: 0; } to { transform: none; opacity: 1; } }
.sheet-body, .study-sheet-body { padding: var(--sp-3) var(--sp-5) calc(var(--sp-6) + env(safe-area-inset-bottom)); }
/* a page pulled into a sheet with hx-select="#main > *" brings its div.content along: no second gutter inside */
.sheet-body > .content, .study-sheet-body > .content { padding: 0; max-width: none; }
.sheet-head { position: sticky; top: 0; z-index: 2; display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); padding: var(--sp-5) 0 var(--sp-3); background: var(--surface); }
.sheet-head h2 { font-size: var(--fs-4); }
.sheet-head::before { content: ""; position: absolute; top: 8px; left: 50%; width: 40px; height: 4px; margin-left: -20px; border-radius: var(--r-pill); background: var(--surface-3); }
dialog.sheet { position: fixed; }
/* a page pulled into the study sheet (the source passage): no crumb, a smaller title */
.study-sheet-body .page-head { margin-bottom: var(--sp-4); }
.study-sheet-body .page-head .crumb { display: none; }
.study-sheet-body .page-title { font-size: var(--fs-4); }
.sheet-section h3 { margin: var(--sp-4) 0 var(--sp-2); }
.sheet-row { display: flex; align-items: center; gap: var(--sp-4); min-height: 60px; padding: var(--sp-2) var(--sp-2); border-radius: var(--r-md); cursor: pointer; color: inherit; text-decoration: none; }
.sheet-row:hover, .sheet-row:focus-within { background: var(--surface-2); }
.sheet-row-button { all: unset; display: flex; align-items: center; gap: var(--sp-4); width: 100%; min-height: 60px; cursor: pointer; }
.sheet-icon { display: inline-flex; align-items: center; justify-content: center; width: 44px; height: 44px; border-radius: var(--r-md); background: var(--accent-soft); color: var(--accent-ink); flex: none; }
.sheet-icon svg, .sheet-icon .icon { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.record-icon { background: var(--danger-soft); color: var(--danger-ink); }
.sheet-text { display: flex; flex-direction: column; min-width: 0; }
.sheet-label { font-weight: 800; }
.sheet-hint { color: var(--ink-2); font-size: var(--fs-1); font-weight: 500; }
.sheet-foot { text-align: center; margin: var(--sp-4) 0 0; }
.sheet-close { position: absolute; top: var(--sp-3); right: var(--sp-3); }
@media (min-width: 640px) {
  dialog.sheet, dialog.study-sheet {
    max-width: 560px; max-height: 86vh; margin: auto; border-radius: var(--r-xl); box-shadow: var(--shadow-pop);
  }
  dialog.sheet[open], dialog.study-sheet[open] { animation: dialog-in var(--t-med) var(--ease); }
  @keyframes dialog-in { from { transform: scale(0.98); opacity: 0; } to { transform: none; opacity: 1; } }
  .sheet-head::before { display: none; }
  .sheet-head { padding-top: var(--sp-2); }
  .sheet-body, .study-sheet-body { padding: var(--sp-5) var(--sp-7) var(--sp-7); }
  .sheet-rows { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-2); }
}

/* ---------------------------------------------------------------- 14. Toasts */
.flash {
  position: fixed; left: var(--sp-4); right: var(--sp-4); z-index: 60;
  bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom) + var(--sp-3));
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-5); border-radius: var(--r-md);
  background: var(--ink); color: var(--paper); font-weight: 700; box-shadow: var(--shadow-float);
}
.flash.flash-error { background: var(--danger); color: var(--on-danger); }
.flash-error .link, .flash-error button.link { color: var(--on-danger); text-decoration: underline; }
.card .flash, form .flash { position: static; margin-top: var(--sp-3); box-shadow: none; }
.inline-flash { margin-bottom: var(--sp-4); }
/* a Problem answered as a page (_partials/problem.html): the sentence sits in the card, not pinned at the bottom */
.problem-card .flash { position: static; justify-content: center; box-shadow: none; background: var(--danger-soft); color: var(--danger-ink); }
@media (min-width: 640px) {
  .flash { left: auto; right: var(--sp-6); bottom: var(--sp-6); max-width: 420px; }
}

/* ---------------------------------------------------------------- 15. Composer and source tiles */
/* The one bold element on Home: a panel that says what to drop in. On the phone it is a card with four tiles; on
   desktop it is a drop zone with the same four tiles. Markup: section.composer > (div.composer-head) + div.composer-sources */
.composer {
  position: relative; background: var(--surface); border: 1.5px solid var(--accent); border-radius: var(--r-xl);
  padding: var(--sp-5); box-shadow: 0 0 0 5px var(--accent-ring), var(--shadow-float);
}
.composer.is-dragover { background: var(--accent-soft); }
/* the halo is for the empty Home, where the composer is the whole page; under a tonight strip her next step is a card */
.tonight + .composer { box-shadow: none; }
.composer-head { display: flex; align-items: center; gap: var(--sp-3); margin-bottom: var(--sp-4); }
.composer-head .mark { width: 36px; height: 36px; }
.composer-title { font-size: var(--fs-4); font-weight: 800; letter-spacing: -0.01em; }
.composer-hint { color: var(--ink-2); font-size: var(--fs-1); font-weight: 500; }
.composer-hint:empty { display: none; }
.composer-sources { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-2); }
.composer-sources > .source-tile:last-child:nth-child(odd) { grid-column: 1 / -1; }  /* 3 or 5 tiles: the odd one spans the row */
.source-tile {
  display: flex; align-items: center; gap: var(--sp-3); min-height: 60px; padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--line); border-radius: var(--r-lg); background: var(--surface); color: inherit; text-decoration: none; cursor: pointer; text-align: left; white-space: normal;
  transition: border-color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.source-tile:hover { background: var(--surface-2); border-color: var(--line-strong); text-decoration: none; }
.source-tile .kind { width: 40px; height: 40px; }
.source-tile-text { display: flex; flex-direction: column; min-width: 0; overflow-wrap: anywhere; }
.source-tile-label { font-weight: 800; font-size: var(--fs-1); }
.source-tile-hint { color: var(--ink-2); font-size: var(--fs-0); font-weight: 500; }
.composer-foot { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); margin-top: var(--sp-4); font-size: var(--fs-1); color: var(--ink-2); font-weight: 500; }
@media (min-width: 640px) {
  .composer { padding: var(--sp-7); }
  .composer-head .mark { width: 44px; height: 44px; }
  .composer-title { font-size: var(--fs-5); }
  .composer-sources { grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); }  /* 3, 4 or 5 tiles in one row */
  .composer-sources > .source-tile:last-child:nth-child(odd) { grid-column: auto; }
  .source-tile { flex-direction: column; align-items: flex-start; gap: var(--sp-3); min-height: 112px; padding: var(--sp-4); }
}
/* a returning Home on a phone: the tiles in one row, icon over label, no hints (the empty Home keeps the full tiles) */
@media (max-width: 639px) {
  .tonight + .composer .composer-head { margin-bottom: var(--sp-3); }
  .tonight + .composer .composer-sources { display: flex; gap: var(--sp-1); }
  .tonight + .composer .source-tile { flex: 1 1 0; flex-direction: column; justify-content: flex-start; gap: var(--sp-1); min-height: 0; min-width: 0; padding: var(--sp-1) 0; border: 0; background: transparent; text-align: center; }
  .tonight + .composer .source-tile .kind { width: 56px; height: 56px; border-radius: var(--r-lg); }
  .tonight + .composer .source-tile .kind .icon { width: 26px; height: 26px; }
  .tonight + .composer .source-tile-text { align-items: center; }
  .tonight + .composer .source-tile-label { font-size: 0.6875rem; line-height: 1.2; }
  .tonight + .composer .source-tile-hint { display: none; }
}
/* attached-file chip inside the composer while uploading */
.attach { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3) var(--sp-4); border-radius: var(--r-md); background: var(--surface-2); }
.attach .status { margin-left: auto; }

/* ---------------------------------------------------------------- 16. Library cards and "tonight" */
.tonight { display: grid; gap: var(--sp-3); grid-template-columns: minmax(0, 1fr); margin-bottom: var(--sp-7); }
.tonight:empty { display: none; }
@media (min-width: 800px) { .tonight { grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: var(--sp-4); } }
.tonight-card { display: flex; flex-direction: column; gap: var(--sp-3); }
.tonight-card .tile-row { min-height: 0; }
.tonight-card .button { align-self: flex-start; }
.tonight-card.card-tint .button.primary { box-shadow: inset 0 -3px 0 rgba(0, 0, 0, 0.14); }
.tonight-number { font-size: var(--fs-5); font-weight: 800; letter-spacing: -0.02em; line-height: 1; }

.library { display: grid; gap: var(--sp-4); grid-template-columns: 1fr; }
@media (min-width: 640px) { .library { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1200px) { .library { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.upload-card { display: flex; flex-direction: column; gap: var(--sp-3); }
.upload-card .card-link { display: flex; gap: var(--sp-4); align-items: flex-start; }
.upload-card .card-title { font-size: var(--fs-3); margin-bottom: 2px; }
.upload-card .card-title { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.upload-card .ring { margin-left: auto; }
.upload-card .card-open { color: var(--ink-3); width: 22px; height: 22px; margin-top: 2px; flex: none; transition: color var(--t-fast) var(--ease), transform var(--t-fast) var(--ease); }
.upload-card .ring + .card-open { margin-left: var(--sp-1); }
.upload-card:has(> .card-link:hover) { border-color: var(--line-strong); box-shadow: var(--shadow-float); }
.upload-card .card-link:hover .card-title { color: var(--accent-ink); }
.upload-card .card-link:hover .card-open { color: var(--accent-ink); transform: translateX(2px); }
.upload-card .chip-row { margin-top: auto; }
.library-empty { color: var(--ink-2); text-align: center; padding: var(--sp-5) 0; font-weight: 700; }
.library-page .upload-list { margin-top: var(--sp-2); }
.upload-card.state-failed { border-color: var(--danger); }
.upload-card .modes { margin-top: var(--sp-1); }
/* mode row: Learn · Test · Match · Cards */
.modes { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--sp-2); }
.modes.three { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.mode {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2); min-height: var(--tap);
  border-radius: var(--r-md); background: var(--surface-2); color: var(--ink); font-weight: 700; font-size: var(--fs-1); text-decoration: none;
  transition: background var(--t-fast) var(--ease);
}
.mode:hover { background: var(--surface-3); text-decoration: none; }
.mode .icon { width: 18px; height: 18px; }
@media (min-width: 640px) { .modes.compact .mode { min-height: 40px; } }  /* 44 px on a phone: every tap target */
.modes.large .mode { min-height: 64px; flex-direction: column; gap: 4px; font-size: var(--fs-1); }
.modes.large .mode .icon { width: 22px; height: 22px; }

/* classes on Home and /classes (docs/build/classes/01-design.md § 1.2): the dot, the grid, the class card, the per-class
   due chips on the Review card, the "Working on" strip, the section heads. The class page's own rules (the classroom
   columns, the picker, the Study panel, the guide and tutor cards) are static/classes/classes.css. */
.class-dot { display: inline-block; width: 12px; height: 12px; border-radius: 50%; flex: none; background: var(--ink-3); }
.class-dot.raspberry { background: var(--accent); } .class-dot.honey { background: var(--honey); } .class-dot.cobalt { background: var(--cobalt); }
.class-dot.moss { background: var(--moss); } .class-dot.plum { background: var(--plum); } .class-dot.tangerine { background: var(--tangerine); }
.class-dot.slate { background: var(--ink-3); } .class-dot.ink { background: var(--ink); }
.crumb .class-dot { margin-right: 2px; }
.class-head .page-title { display: flex; align-items: center; gap: var(--sp-3); }
.class-head .page-title .class-dot { width: 14px; height: 14px; }
.class-grid { display: grid; gap: var(--sp-4); grid-template-columns: 1fr; }
@media (min-width: 640px) { .class-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1200px) { .class-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.class-grid > .card + .card { margin-top: 0; }
.class-card { display: flex; flex-direction: column; gap: var(--sp-3); }
.class-card .card-link { display: flex; align-items: flex-start; gap: var(--sp-3); }
.class-card .class-dot { margin-top: 7px; }
.class-card .card-title { margin-bottom: 2px; }
.class-card .card-open { color: var(--ink-3); width: 22px; height: 22px; margin-left: auto; margin-top: 2px; flex: none; }
.class-card:has(> .card-link:hover) { border-color: var(--line-strong); box-shadow: var(--shadow-float); }
.class-card .card-link:hover .card-title { color: var(--accent-ink); }
.class-card .chip-row { margin-top: auto; }
.class-card.is-new { border-style: dashed; border-color: var(--line-strong); background: transparent; justify-content: center; align-items: center; min-height: 132px; text-align: center; gap: var(--sp-2); color: var(--ink-2); font-weight: 700; text-decoration: none; }
.class-card.is-new:hover { background: var(--surface); color: var(--accent-ink); text-decoration: none; }
.due-by-class { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.chip.danger { background: var(--danger-soft); color: var(--danger-ink); }
.chip.class-chip { color: var(--ink-2); text-decoration: none; }
.chip.class-chip:hover { color: var(--ink); text-decoration: none; }
.upload-card .where-row:empty { display: none; }
.working-on .library { grid-template-columns: 1fr; }
@media (min-width: 640px) { .working-on .library { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
/* the strip sits on top of Home (shakedown P12): the head hugs the lede, the strip keeps the today strip's distance below;
   the Ready cards (one per lesson finished since her last visit) share the today strip's grid */
.working-on:has(.card) { margin: 0 0 var(--sp-7); }
.working-on > .section-head:first-child { margin-top: 0; }
.working-on .ready-list { margin-bottom: var(--sp-4); }
.working-on .ready-list:last-child { margin-bottom: 0; }
.working-on .library + .section-head { margin-top: var(--sp-5); }
.working-on .ready-card .tile-row-meta { overflow-wrap: anywhere; }
.working-on .upload-card .elapsed { font-weight: 500; }
.materials-section + .materials-section { margin-top: var(--sp-6); }
.materials-section .section-head { margin: 0 0 var(--sp-3); }
.materials-section .section-head h3 { font-size: var(--fs-3); }

/* ---------------------------------------------------------------- 17. Lesson layout */
/* div.lesson > aside.lesson-rail + article.lesson-doc + div.lesson-scrim + aside.lesson-side. Rail from 1024. The tutor
   panel is inline from 1600 (220 | 1fr | 320 with .content--wide at 1560: the document keeps its 66ch at every width,
   ui review r2 M2) and a right drawer 1024-1599 (fixed, 360 px, slid in by .lesson.is-ask-open over the scrim; the
   page-head button toggles it, tutor.js: M1). Below 1024 the page-head button posts to a new thread page; the floating
   pill is gone (phone review r2 #1: it covered the Match tile and the running text). */
.lesson { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--sp-6); align-items: start; }
.lesson-rail, .lesson-side, .lesson-scrim { display: none; }
.lesson-doc { min-width: 0; }
@media (min-width: 1024px) {
  .lesson { grid-template-columns: 220px minmax(0, 1fr); gap: var(--sp-7); }
  .lesson-rail { display: block; position: sticky; top: calc(var(--topbar-h) + var(--sp-5)); max-height: calc(100dvh - var(--topbar-h) - var(--sp-8)); overflow: auto; }
}
@media (min-width: 1024px) and (max-width: 1599px) {
  .lesson-side {
    display: block; position: fixed; top: 0; right: 0; bottom: 0; width: 360px; max-width: 100%; z-index: 45;
    transform: translateX(100%); visibility: hidden;
    transition: transform var(--t-med) var(--ease), visibility 0s linear var(--t-med);
  }
  .lesson.is-ask-open .lesson-side { transform: none; visibility: visible; transition: transform var(--t-med) var(--ease); }
  .lesson-scrim { display: block; position: fixed; inset: 0; z-index: 44; background: rgba(31, 37, 48, 0.45); opacity: 0; pointer-events: none; transition: opacity var(--t-med) var(--ease); }
  .lesson.is-ask-open .lesson-scrim { opacity: 1; pointer-events: auto; }
}
@media (min-width: 1600px) {
  .lesson { grid-template-columns: 220px minmax(0, 1fr) 320px; gap: var(--sp-6); }
  .lesson-side { display: block; position: sticky; top: calc(var(--topbar-h) + var(--sp-5)); max-height: calc(100dvh - var(--topbar-h) - var(--sp-8)); }
}
/* the chapter path (rail): ol.path > li.path-item(.is-done|.is-current|.is-pending) > a */
.path { list-style: none; margin: 0; padding: 0; }
.path-item a {
  display: grid; grid-template-columns: 28px 1fr; gap: var(--sp-3); align-items: center;
  min-height: var(--tap); padding: var(--sp-2) var(--sp-3); border-radius: var(--r-md); color: var(--ink-2); font-weight: 700; font-size: var(--fs-1); text-decoration: none;
}
.path-item a:hover { background: var(--surface-2); color: var(--ink); text-decoration: none; }
.path-num { display: inline-flex; align-items: center; justify-content: center; width: 26px; height: 26px; border-radius: 50%; border: 1.5px solid var(--line-strong); font-size: var(--fs-0); font-weight: 800; color: var(--ink-2); }
.path-item.is-done .path-num { background: var(--moss); border-color: var(--moss); color: var(--on-moss); }
.path-item.is-done .path-num .icon { width: 14px; height: 14px; stroke-width: 3; }
.path-item.is-current a { background: var(--accent-soft); color: var(--accent-ink); }
.path-item.is-current .path-num { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
.path-item.is-pending a { color: var(--ink-3); }
.path-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* the chapter rail wraps a long title onto two lines instead of cutting it (ui review r2); the number stays on the first line */
.lesson-rail .path-title { white-space: normal; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; line-height: 1.35; }
.lesson-rail .path-item a { align-items: start; }
.lesson-rail .path-num { margin-top: -3px; }
/* the chapter list on the upload page (lesson/_chapter_card.html inside ol.path.chapter-path): full-size rows with a card
   edge, a ring and a chevron at the right (ui fix r2: a row she can open says so before hover). The number and the
   title are the fixed columns; the ring (hidden at 0 %) and the chevron flow into auto columns after them. */
.chapter-list .path-item a {
  font-size: var(--fs-2); color: var(--ink); grid-template-columns: 28px 1fr; grid-auto-flow: column; grid-auto-columns: auto;
  min-height: 56px; padding: var(--sp-3) var(--sp-4); border: 1px solid var(--line); border-radius: var(--r-lg); background: var(--surface);
}
.chapter-list .path-item a:hover { background: var(--surface); border-color: var(--line-strong); }
.chapter-list .path-item a[aria-disabled="true"] { cursor: default; border-style: dashed; background: transparent; }
.chapter-list .path-item a[aria-disabled="true"]:hover { background: transparent; border-color: var(--line); }
.chapter-list .path-item.is-pending a { color: var(--ink-2); }
.chapter-list .path-item.is-failed a { border-style: solid; border-color: var(--danger); }
.chapter-list .path-item.is-failed .path-num { border-color: var(--danger); color: var(--danger-ink); }
.chapter-list .path-item .ring { width: 36px; height: 36px; }
.chapter-list .chevron { color: var(--ink-3); width: 20px; height: 20px; transition: color var(--t-fast) var(--ease), transform var(--t-fast) var(--ease); }
.chapter-list .path-item a:hover .chevron { color: var(--accent-ink); transform: translateX(2px); }
.lesson-covers { color: var(--ink-2); font-size: var(--fs-1); font-weight: 500; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.lesson-chapter-card.is-pending { opacity: 0.7; }
.lesson-chapter-card.is-failed { border-color: var(--danger); }
.rail-head { padding: 0 var(--sp-3) var(--sp-3); }
.rail-head .card-title { font-size: var(--fs-2); }
.rail-section { margin-top: var(--sp-5); padding: 0 var(--sp-3); }
.rail-section h4 { color: var(--ink-2); font-size: var(--fs-1); margin-bottom: var(--sp-2); }
/* document */
.lesson-head { margin-bottom: var(--sp-5); }
.lesson-head .crumb { margin-bottom: var(--sp-2); }
.lesson-title { font-size: var(--fs-5); }
.lesson-chapter-n { display: block; color: var(--ink-2); font-size: var(--fs-1); font-weight: 700; margin-bottom: var(--sp-1); letter-spacing: 0; }
.lesson-tabs { margin: var(--sp-4) 0 var(--sp-6); }
.lesson-tab-body { min-height: 200px; }
@media (min-width: 1024px) { .lesson-title { font-size: var(--fs-6); } }
/* reader: 17 px, 1.7, 66ch, bold lead-ins, soft h2 */
.reader { font-size: var(--fs-reader); line-height: var(--lh-reader); max-width: var(--measure); font-weight: 500; }
.reader p { margin-bottom: 1em; }
.reader h2 { font-size: var(--fs-4); margin: 1.6em 0 0.6em; }
.reader h3 { font-size: var(--fs-3); margin: 1.4em 0 0.5em; }
.reader ul, .reader ol { padding-left: 1.3em; margin-bottom: 1em; }
.reader li { margin-bottom: 0.35em; }
.reader li::marker { color: var(--accent); }
.reader b, .reader strong, .reader .term { font-weight: 700; color: var(--ink); }
.reader .term { border-bottom: 2px solid var(--honey-soft); }
.reader blockquote { margin: 1em 0; padding: var(--sp-3) var(--sp-4); border-left: 3px solid var(--honey); background: var(--honey-soft); border-radius: 0 var(--r-md) var(--r-md) 0; }
.reader table { border-collapse: collapse; width: 100%; font-size: var(--fs-1); margin: 1em 0; }
.reader th, .reader td { text-align: left; padding: var(--sp-2) var(--sp-3); border-bottom: 1px solid var(--line); vertical-align: top; }
.reader th { background: var(--surface-2); font-weight: 800; }
@media (max-width: 639px) { .reader table { display: block; overflow-x: auto; max-width: 100%; } }
/* study row under a chapter; hidden while a quiz stage is on the page, so the question is alone */
.lesson-modes { margin-top: var(--sp-7); padding-top: var(--sp-5); border-top: 1px solid var(--line); }
.lesson:has(#stage) .lesson-modes, .lesson:has(#stage) .lesson-chapter-nav { display: none; }
.lesson-modes h3 { margin-bottom: var(--sp-3); }
.lesson-chapter-nav { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--sp-3); margin-top: var(--sp-6); }
@media (min-width: 640px) { .lesson-chapter-nav { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); } }
.lesson-chapter-nav .button { justify-content: flex-start; min-height: 56px; padding: var(--sp-2) var(--sp-4); text-align: left; white-space: normal; min-width: 0; }
.lesson-chapter-nav .button > span { min-width: 0; overflow-wrap: break-word; }
.lesson-chapter-nav .button:last-child:not(:only-child) { justify-content: flex-end; text-align: right; }
@media (min-width: 640px) { .lesson-chapter-nav .button:only-child { grid-column: 2; justify-content: flex-end; } }
.lesson-chapter-nav .button small { display: block; color: var(--ink-2); font-weight: 700; }
.lesson-chapter-nav .button > span { display: flex; flex-direction: column; }
/* terms list */
.lesson-term-list { display: grid; gap: var(--sp-2); }
.lesson-term { display: grid; gap: 2px; padding: var(--sp-3) var(--sp-4); border: 1px solid var(--line); border-radius: var(--r-md); background: var(--surface); }
.lesson-term dt { font-weight: 800; }
.lesson-term dd { margin: 0; color: var(--ink-2); font-weight: 500; }
@media (min-width: 800px) { .lesson-term { grid-template-columns: 220px 1fr; gap: var(--sp-4); align-items: baseline; } }
/* tutor side panel (the thread and composer live in lesson.css) */
.lesson-side .panel { display: flex; flex-direction: column; gap: var(--sp-4); padding: var(--sp-5); max-height: calc(100dvh - var(--sp-8)); }
/* as the drawer (1024-1599) the panel fills the aside's full height, flush to the window's right edge */
@media (min-width: 1024px) and (max-width: 1599px) {
  .lesson-side .panel { height: 100%; max-height: none; border-radius: 0; border-width: 0 0 0 1px; box-shadow: var(--shadow-pop); }
}
.side-head { display: flex; align-items: center; gap: var(--sp-3); }
.side-head h3 { flex: 1 1 auto; min-width: 0; }
.side-head h3 { font-size: var(--fs-2); }
.side-head .kind { width: 32px; height: 32px; border-radius: var(--r-sm); }
.side-head .kind .icon { width: 18px; height: 18px; }

/* ---------------------------------------------------------------- 18. Study */
.study-stage { display: flex; flex-direction: column; gap: var(--sp-5); }
.stage-head { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); }
.progress-line { color: var(--ink-2); font-size: var(--fs-1); font-weight: 700; }
.question, .prompt { font-size: var(--fs-4); font-weight: 800; line-height: 1.3; max-width: var(--measure); }
.statement { padding: var(--sp-4) var(--sp-5); border-radius: var(--r-lg); background: var(--surface-2); font-weight: 700; font-size: var(--fs-3); }
.options { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-2); }
.option {
  display: flex; align-items: center; gap: var(--sp-3); width: 100%; min-height: 56px; padding: var(--sp-3) var(--sp-4);
  border: 1.5px solid var(--line-control); border-radius: var(--r-lg); background: var(--surface); color: var(--ink);
  font-weight: 500; text-align: left; white-space: normal; line-height: 1.35; justify-content: flex-start;
}
.option:hover { border-color: var(--accent); background: var(--surface); }
.option .pair-letter { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; border-radius: 50%; background: var(--surface-2); font-size: var(--fs-0); font-weight: 800; color: var(--ink-2); flex: none; }
.options.locked .option { pointer-events: none; }
.options.locked .option.key { border-color: var(--moss); background: var(--moss-soft); }
.options.locked .option.picked:not(.key) { border-color: var(--danger); background: var(--danger-soft); }
.options.locked .option.key .pair-letter { background: var(--moss); color: var(--on-moss); }
.options.locked .option.picked:not(.key) .pair-letter { background: var(--danger); color: var(--on-danger); }
.options.plain { padding-left: 1.2em; list-style: disc; }
.options.plain li { color: var(--ink-2); }
@media (min-width: 800px) { .options.grid-2 { grid-template-columns: 1fr 1fr; } }
.tf-row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-3); }
.tf-row .option { justify-content: center; font-size: var(--fs-3); min-height: 64px; }
.dont-know { align-self: center; color: var(--ink-2); font-weight: 700; }
.thumb { display: flex; flex-direction: column; gap: var(--sp-3); }
.thumb .button.big { width: 100%; }
@media (min-width: 640px) { .thumb { flex-direction: row; justify-content: flex-end; } .thumb .button.big { width: auto; min-width: 200px; } }
.verdict { font-size: var(--fs-4); font-weight: 800; }
.verdict-correct .verdict { color: var(--moss-ink); }
.verdict-wrong .verdict, .verdict-partial .verdict { color: var(--danger-ink); }
.explanation, .right-answer, .her-answer, .reason { max-width: var(--measure); }
.source { padding: var(--sp-4); border-radius: var(--r-lg); background: var(--honey-soft); border-left: 3px solid var(--honey); }
.source figcaption { font-size: var(--fs-1); font-weight: 700; margin-bottom: var(--sp-2); display: flex; gap: var(--sp-2); align-items: center; }
.source blockquote { margin: 0; font-style: normal; }
.reveal-tools { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
/* flashcard: one object in the middle */
.flashcard { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-xl); padding: var(--sp-7) var(--sp-6); min-height: 280px; display: flex; flex-direction: column; justify-content: center; text-align: center; box-shadow: var(--shadow-float); }
.flashcard .front, .lesson-card-front { font-size: var(--fs-4); font-weight: 800; line-height: 1.3; }
.flashcard .back, .lesson-card-back { margin-top: var(--sp-5); padding-top: var(--sp-5); border-top: 1px dashed var(--line-strong); font-size: var(--fs-3); font-weight: 500; }
.card-meta.context, .lesson-card-context { color: var(--ink-2); font-size: var(--fs-1); margin-top: var(--sp-3); }
.flip summary, .lesson-flip summary { list-style: none; cursor: pointer; }
.flip summary::-webkit-details-marker, .lesson-flip summary::-webkit-details-marker { display: none; }
.flip-hint, .lesson-flip-hint { display: block; margin-top: var(--sp-4); color: var(--ink-3); font-size: var(--fs-1); font-weight: 700; }
.flip[open] .flip-hint, .lesson-flip[open] .lesson-flip-hint { display: none; }
.lesson-card-count { text-align: center; color: var(--ink-2); font-size: var(--fs-1); font-weight: 700; margin-bottom: var(--sp-3); }
.lesson-card-nav, .browse-nav { display: grid; grid-template-columns: 1fr auto 1fr; gap: var(--sp-3); margin-top: var(--sp-5); align-items: center; }
.lesson-card-nav .button:last-child { justify-self: end; }
.lesson-star.is-on, .mark.on { color: var(--honey); }
@media (min-width: 640px) { .flashcard { min-height: 340px; padding: var(--sp-9) var(--sp-8); max-width: 720px; margin: 0 auto; } .lesson-card-nav, .browse-nav { width: 100%; max-width: 720px; margin-left: auto; margin-right: auto; } }
/* rating row: Forgot | Got it, 64 px; Hard / Easy revealed */
.rate-row, .rate-more { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-3); }
.rate { min-height: 64px; font-size: var(--fs-3); border-radius: var(--r-lg); }
.rate.forgot { background: var(--danger-soft); border-color: transparent; color: var(--danger-ink); }
.rate.gotit { background: var(--moss); border-color: var(--moss); color: var(--on-moss); box-shadow: inset 0 -3px 0 rgba(0, 0, 0, 0.14); }
.rate.hard { background: var(--warn-soft); border-color: transparent; color: var(--honey-ink); }
.rate.easy { background: var(--cobalt-soft); border-color: transparent; color: var(--cobalt-ink); }
.rate-hint { text-align: center; color: var(--ink-3); font-size: var(--fs-1); font-weight: 500; }
@media (min-width: 640px) { .rate-row, .rate-more { width: 100%; max-width: 720px; margin-left: auto; margin-right: auto; } }
/* predict pills */
.pills { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.pill { min-height: 48px; padding: 0 var(--sp-5); border-radius: var(--r-pill); font-weight: 800; }
.pill:hover { border-color: var(--accent); color: var(--accent-ink); }
/* test dots */
.dots { display: flex; flex-wrap: wrap; gap: 5px; list-style: none; margin: 0; padding: 0; }
.dot { width: 10px; height: 10px; border-radius: 50%; background: var(--surface-3); }
.dot.done { background: var(--ink-3); }
.dot.current { background: var(--accent); }
.test-timer { font-weight: 800; color: var(--ink-2); font-variant-numeric: tabular-nums; }
.test-timer.low { color: var(--danger-ink); }
/* match board */
.match-board .tiles { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-2); }   /* two columns under 640 (TILE_LEN 80, review-phone r2); four from 640 */
.tile { min-height: 96px; padding: var(--sp-2); border-radius: var(--r-lg); white-space: normal; font-size: var(--fs-1); font-weight: 700; line-height: 1.3; overflow-wrap: anywhere; }  /* a term wraps at a word, never a hyphen mid-word; the tile grows */
.tile.sel { border-color: var(--accent); background: var(--accent-soft); color: var(--accent-ink); }
.tile.done { visibility: hidden; }
.match-board.missed .tiles { animation: shake 240ms var(--ease); }
@keyframes shake { 25% { transform: translateX(-4px); } 75% { transform: translateX(4px); } }
.match-timer { font-weight: 800; font-size: var(--fs-4); font-variant-numeric: tabular-nums; }
@media (min-width: 640px) { .match-board .tiles { grid-template-columns: repeat(4, minmax(0, 1fr)); max-width: 820px; } .tile { min-height: 110px; font-size: var(--fs-2); } }
/* results */
.result-head { font-size: var(--fs-4); font-weight: 800; }
.result-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-2); }
.result-list > li { display: flex; gap: var(--sp-3); padding: var(--sp-3) var(--sp-4); border: 1px solid var(--line); border-radius: var(--r-md); background: var(--surface); }  /* > li: the nested ul.pair-review rows are the Matching block's own */
.r-mark { display: inline-flex; align-items: center; justify-content: center; width: 26px; height: 26px; border-radius: 50%; flex: none; font-weight: 800; font-size: var(--fs-0); }
.r-mark.ok { background: var(--moss-soft); color: var(--moss-ink); }
.r-mark.miss { background: var(--danger-soft); color: var(--danger-ink); }
/* progress page */
.buckets { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-3); }
.buckets > div { padding: var(--sp-4); border: 1px solid var(--line); border-radius: var(--r-lg); background: var(--surface); }
.buckets dt { color: var(--ink-2); font-size: var(--fs-1); font-weight: 700; }
.buckets dd { margin: 0; font-size: var(--fs-5); font-weight: 800; letter-spacing: -0.02em; }
@media (min-width: 800px) { .buckets { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.progress-overall { display: flex; align-items: center; gap: var(--sp-5); }
.progress-upload { display: flex; align-items: center; gap: var(--sp-4); }
/* due banner (home, phone only; desktop uses .tonight) */
.due-banner { margin-bottom: var(--sp-4); }
.due-banner.loading { min-height: 56px; border-radius: var(--r-lg); }
.due-none { color: var(--ink-2); font-weight: 700; }

/* ---------------------------------------------------------------- 19. Chat */
.chat, .lesson-chat { display: flex; flex-direction: column; gap: var(--sp-3); }
.bubble { max-width: 44rem; padding: var(--sp-3) var(--sp-4); border-radius: var(--r-lg); line-height: 1.5; }
.bubble p { margin-bottom: var(--sp-2); }
.bubble-user { align-self: flex-end; background: var(--accent-soft); color: var(--ink); border-bottom-right-radius: var(--r-sm); }
.bubble-tutor { align-self: flex-start; background: var(--surface); border: 1px solid var(--line); border-bottom-left-radius: var(--r-sm); }
.bubble-tutor .nowrap { white-space: nowrap; }
.bubble.is-streaming p::after { content: "▍"; color: var(--accent); animation: pulse 1s ease-in-out infinite; }
.bubble.is-error { background: var(--danger-soft); color: var(--danger-ink); border-color: transparent; }
.chat-input, .lesson-ask-bar { display: flex; gap: var(--sp-2); align-items: flex-end; padding: var(--sp-2); border: 1px solid var(--line-control); border-radius: var(--r-lg); background: var(--surface); }
.chat-input:focus-within, .lesson-ask-bar:focus-within { border-color: var(--accent); box-shadow: 0 0 0 4px var(--accent-ring); }
.chat-input textarea, .lesson-ask-bar textarea { border: 0; min-height: 40px; max-height: 160px; padding: var(--sp-2) var(--sp-3); background: transparent; resize: none; }
.chat-input textarea:focus, .lesson-ask-bar textarea:focus { box-shadow: none; }
.chat-input .button, .lesson-ask-bar .button { flex: none; }
.chat-starters, .lesson-starters { display: flex; flex-direction: column; gap: var(--sp-2); }
.lesson-starter, .starter { justify-content: flex-start; text-align: left; white-space: normal; min-height: var(--tap); padding: var(--sp-2) var(--sp-4); font-weight: 500; line-height: 1.3; }
.lesson-starters-intro { color: var(--ink-2); font-size: var(--fs-1); font-weight: 700; }
.lesson-show-full { align-self: center; }
.lesson-shown { color: var(--ink-3); font-size: var(--fs-0); font-weight: 700; margin-top: var(--sp-1); }
.lesson-threads .card { margin-bottom: var(--sp-2); }
.chat-thread { flex: 1; overflow: auto; min-height: 120px; display: flex; flex-direction: column; gap: var(--sp-3); }
/* tutor page: fixed bar on phone, inline on desktop */
@media (max-width: 639px) {
  /* the tab bar's Upload circle rises 24 px above the bar, so the pinned bar sits 30 px above it */
  .lesson-ask-bar.is-fixed { position: fixed; left: var(--sp-3); right: var(--sp-3); bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom) + 30px); z-index: 30; box-shadow: var(--shadow-float); }
  .lesson-ask-spacer { height: 120px; }
}

/* ---------------------------------------------------------------- 20. Players */
/* podcast card: div.player > (div.player-head: kind + title + meta) + div.player-controls + div.player-scrub */
.player { display: flex; flex-direction: column; gap: var(--sp-4); }
.player-head { display: flex; align-items: center; gap: var(--sp-3); }
.player-controls { display: flex; align-items: center; gap: var(--sp-3); }
.player-play { width: 56px; height: 56px; padding: 0; border-radius: 50%; background: var(--plum); border-color: var(--plum); color: #fff; flex: none; }
.player-play .icon { width: 26px; height: 26px; }
.player-scrub { flex: 1; display: flex; align-items: center; gap: var(--sp-3); font-size: var(--fs-1); font-weight: 700; color: var(--ink-2); font-variant-numeric: tabular-nums; }
.player-scrub .bar { flex: 1; height: 6px; }
.podcast-audio { width: 100%; margin-top: var(--sp-2); }
.hosts { font-weight: 700; }
/* clips */
.clip-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--sp-3); }
@media (min-width: 640px) { .clip-grid { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); } }
.media-figure { position: relative; }
.media-open { position: relative; display: block; width: 100%; padding: 0; border: 0; border-radius: var(--r-lg); overflow: hidden; background: var(--ink); aspect-ratio: 9 / 16; }
.media-figure:not(.portrait) .media-open { aspect-ratio: 16 / 9; }
.media-poster { width: 100%; height: 100%; object-fit: cover; opacity: 0.92; }
.media-blank { width: 100%; height: 100%; background: linear-gradient(160deg, var(--plum) 0%, var(--ink) 100%); }
.media-play { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; color: #fff; }
.media-play .icon { width: 44px; height: 44px; filter: drop-shadow(0 2px 6px rgba(0, 0, 0, 0.4)); }
.media-length { position: absolute; right: 8px; bottom: 8px; padding: 2px 8px; border-radius: var(--r-pill); background: rgba(0, 0, 0, 0.55); color: #fff; font-size: var(--fs-0); font-weight: 800; }
.media-figure figcaption { margin-top: var(--sp-2); font-size: var(--fs-1); font-weight: 700; }
.media-title { display: block; }
.length { color: var(--ink-2); font-weight: 700; }
.media-actions { display: flex; gap: var(--sp-2); flex-wrap: wrap; margin-top: var(--sp-3); }
.render-wait { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--sp-3); border: 1px dashed var(--line-strong); border-radius: var(--r-lg); padding: var(--sp-5); color: var(--ink-2); text-align: center; min-height: 120px; }
.render-wait.portrait { aspect-ratio: 9 / 16; }
.render-tile.state-failed { border-color: var(--danger); }
/* full-screen player */
html.player-open, html.player-open body { overflow: hidden; }
.media-player { position: fixed; inset: 0; z-index: 80; background: #000; display: flex; flex-direction: column; }
.player-stage { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; min-height: 0; }
.player-video { max-height: 100%; max-width: 100%; width: 100%; height: 100%; object-fit: contain; }
.player-top { position: absolute; top: 0; left: 0; right: 0; display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); padding: calc(env(safe-area-inset-top) + var(--sp-3)) var(--sp-4) var(--sp-3); background: linear-gradient(rgba(0, 0, 0, 0.6), transparent); color: #fff; }
.player-button { background: rgba(255, 255, 255, 0.14); border-color: transparent; color: #fff; min-height: var(--tap); min-width: 72px; padding: 0 var(--sp-4); font-weight: 700; border-radius: var(--r-pill); }
.player-button:hover { background: rgba(255, 255, 255, 0.24); }
.player-count { font-weight: 800; }
/* the paused mark hugs the bottom edge, like the top bar hugs the top: the caption band in the middle stays clear */
.player-paused { position: absolute; left: 0; right: 0; bottom: calc(env(safe-area-inset-bottom, 0px) + var(--sp-5)); display: flex; align-items: center; justify-content: center; color: #fff; pointer-events: none; }
.player-paused .icon { width: 48px; height: 48px; }
.player-progress { position: absolute; left: 0; right: 0; bottom: env(safe-area-inset-bottom); width: 100%; height: 4px; appearance: none; border: 0; background: rgba(255, 255, 255, 0.25); }
.player-progress::-webkit-progress-bar { background: transparent; }
.player-progress::-webkit-progress-value { background: var(--accent); }
.player-progress::-moz-progress-bar { background: var(--accent); }
.media-player.is-review .player-paused, .media-player.is-review .player-progress { display: none; }
/* pickers (voice, background) */
.media-picker > summary { list-style: none; cursor: pointer; display: inline-flex; align-items: center; gap: var(--sp-2); min-height: var(--tap); color: var(--accent-ink); font-weight: 700; }
.media-picker > summary::-webkit-details-marker { display: none; }
.media-form { display: grid; gap: var(--sp-4); margin-top: var(--sp-3); }
.bg-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); gap: var(--sp-3); }
.bg-option { display: block; cursor: pointer; text-align: center; font-size: var(--fs-0); font-weight: 700; color: var(--ink-2); }
.bg-option input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.bg-option img, .bg-blank { aspect-ratio: 9 / 16; width: 100%; object-fit: cover; border-radius: var(--r-md); border: 2px solid transparent; background: var(--surface-3); }
.bg-option input:checked + img, .bg-option input:checked + .bg-blank { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-ring); }
.bg-option input:focus-visible + img, .bg-option input:focus-visible + .bg-blank { outline: 3px solid var(--focus); outline-offset: 2px; }

/* ---------------------------------------------------------------- 21. Auth pages */
.auth { min-height: calc(100dvh - 180px); display: flex; flex-direction: column; align-items: center; justify-content: center; padding: var(--sp-6) 0; }
.auth-card .field { text-align: left; }
.auth-card { width: 100%; max-width: 420px; display: flex; flex-direction: column; gap: var(--sp-4); text-align: center; }
.auth-card .mark { width: 56px; height: 56px; margin: 0 auto var(--sp-2); }
.auth-card h1 { font-size: var(--fs-5); }
.auth-card .lede { font-size: var(--fs-2); margin: 0 auto; }
.auth-card .button { width: 100%; }
.auth-foot { color: var(--ink-3); font-size: var(--fs-1); font-weight: 500; margin-top: var(--sp-4); }
body.bare .content { text-align: center; }

/* ---------------------------------------------------------------- 22. Utilities */
.visually-hidden { position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }
.stack { display: flex; flex-direction: column; gap: var(--sp-3); }
.stack-lg { display: flex; flex-direction: column; gap: var(--sp-6); }
.row { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; }
.row.between { justify-content: space-between; }
.grow { flex: 1; min-width: 0; }
.nowrap { white-space: nowrap; }
.text-right { text-align: right; }
.center { text-align: center; }
.hide-phone { display: none; }
@media (min-width: 640px) { .hide-phone { display: initial; } .hide-tablet-up { display: none !important; } }
/* the home-screen hint card (phone only: it carries .hide-tablet-up; app.js shows the iOS or the Android line) */
.hint-card { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3); background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--r-lg); padding: var(--sp-3) var(--sp-4); margin: var(--sp-5) 0 0; font-weight: 500; font-size: var(--fs-1); color: var(--ink-2); }
.hint-card p { flex: 1; margin: 0; }
.job-card { padding: var(--sp-3) 0; }
.upload-list { list-style: none; padding: 0; margin: var(--sp-2) 0 0; }
