/* ui.css: the Sophai design system. One section per piece, each opened by a "== <piece> ==" comment; the list of
   pieces is the index of these sections. Rules (test/ui-css-check.mjs): colours only in the token blocks (:root), weights at most 500
   (600 only on the citation chip), no !important, font-family only through the tokens, no font in data:.
   Read docs/UI.md before adding a piece. It holds the sign-in page (/login) and the whole student app (/): its shell,
   the conversation, the Curriculum Roadmap, the Bibliography, the Debug chat and the phone layout. */

/* == tokens == */
/* Light by default; dark when the system is dark and no light choice is saved, or when dark is saved. */
:root {
  color-scheme: light dark;
  --bg-page: #FAFAFB; --bg-primary: #FFFFFF; --bg-muted: #F2F2F4;
  --text-primary: #111113; --text-body: #3C3C43; --text-secondary: #646470; --text-faint: #9C9CA6;
  --accent: #7B6CF0; --link: #6A5BE0; --link-hover: #5F50D9; --on-accent: #FFFFFF;
  --soft-red-text: #C2413A;
  --hairline: rgba(17,17,19,.08); --edge-raised: rgba(17,17,19,.05);
  --font-body: 'DM Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --font-serif: 'Source Serif 4', Georgia, serif;
  --text-xs: 12px; --text-sm: 13px; --text-md: 14px; --text-base: 15px; --text-input: 16px;
  --r-sm: 8px; --r: 12px; --r-lg: 16px;
  /* glass */
  --gl-read: rgba(255,255,255,.56); --gl-edge-a: rgba(255,255,255,.70); --gl-edge-b: rgba(255,255,255,.15);
  --gl-card: rgba(255,255,255,.5); --gl-card-edge: rgba(255,255,255,.8); --gl-hover: rgba(255,255,255,.6); --gl-press: rgba(255,255,255,.85);
  --isl-sheen: rgba(255,255,255,.9); --ctl-sheen: rgba(255,255,255,.18);
  --card-shadow: inset 0 1px 0 var(--isl-sheen), inset 0 -1px 2px rgba(0,0,0,.04), 0 1px 2px rgba(17,17,19,.05), 0 12px 32px rgba(70,50,160,.12), 0 18px 44px rgba(70,50,160,.16);
  --shadow-raised: 0 1px 2px rgba(17,17,19,.06), 0 4px 12px rgba(17,17,19,.04);
  --mask: #000;
  /* field */
  --field-bg: var(--bg-primary); --field-edge: var(--edge-raised);
  /* the accent's glow on the primary button */
  --accent-glow: 0 6px 18px rgba(123,108,240,.25), 0 1px 2px rgba(123,108,240,.2);
  --accent-glow-hi: 0 8px 22px rgba(123,108,240,.30), 0 1px 2px rgba(123,108,240,.2);
  /* the app's glow (the prototype's x 0.9): the send circle */
  --accent-glow-app: 0 5px 16px rgba(123,108,240,.25), 0 1px 2px rgba(123,108,240,.2);
  /* the sign-in page's links: the darker violet keeps 4.5:1 on the glass over the aurora */
  --action-link: var(--link-hover);
  /* errors: the edge, the text (15-20 % of --text-primary keeps 4.5:1 on the glass) and the disc */
  --err-edge: var(--soft-red-text);
  --err-text: color-mix(in srgb, var(--soft-red-text) 80%, var(--text-primary));
  --err-bg: color-mix(in srgb, var(--soft-red-text) 12%, transparent);
  /* aurora (the sign-in page's strength) */
  --aurora-opacity: .52; --aur-blend: normal; --grain-opacity: .08; --dither-opacity: 0;
  --aur-1: radial-gradient(circle, rgba(124,94,232,.55) 0%, rgba(124,94,232,.36) 30%, rgba(124,94,232,.14) 55%, transparent 70%);
  --aur-2: radial-gradient(circle, rgba(128,90,178,.30) 0%, rgba(128,90,178,.2) 30%, rgba(128,90,178,.08) 55%, transparent 70%);
  --aur-3: radial-gradient(circle, rgba(80,92,190,.45) 0%, rgba(80,92,190,.3) 30%, rgba(80,92,190,.12) 55%, transparent 70%);
  --aur-dur: 90s; --aur-travel: 92vh; --br-a: 3.5; --br-t: 1.8;
  --ax: -34.6vw; --ay: 26.4vh;
  /* the dialog: its raised surface, the scrim (solid when transparency is reduced) and its shadows */
  --surface-raised: var(--bg-primary); --surface-raised-edge: var(--edge-raised);
  /* the Tutor's mark in the conversation: the Sophai symbol and the accent's halo behind it */
  --tutor-symbol: url(/assets/brand/sophai-symbol-v1.svg);
  --accent-halo: radial-gradient(circle, rgba(123,108,240,.20) 0%, rgba(123,108,240,.08) 45%, transparent 70%);
  --scrim: rgba(17,17,19,.32); --scrim-solid: rgba(17,17,19,.5);
  /* the drawer's and the sheets' dimmed background (lighter than the dialog's) */
  --scrim-soft: rgba(17,17,19,.28);
  /* the menus' top sheen and the press of their options */
  --glass-sheen: rgba(255,255,255,.7); --press: rgba(17,17,19,.08);
  /* the app's Liquid Glass (the prototype's): the islands' fill, the tablet panel's denser fill, the depth at the bottom */
  --gl-fill: rgba(255,255,255,.28); --tb-glass: rgba(250,250,251,.72); --gl-depth: rgba(0,0,0,.04);
  /* the left bar's glass, its edge and its cast shadow; the tools' tiles: their top, their shadow, the chosen one's
     halo and tint */
  --glass-panel: rgba(250,250,251,.63); --glass-border: rgba(17,17,19,.08); --rail-shadow: 7px 0 22px rgba(17,17,19,.06);
  --ic-top: var(--bg-primary); --ic-shadow: 0 1px 1px rgba(17,17,19,.06), 0 3px 7px rgba(17,17,19,.07);
  --ic-halo: radial-gradient(circle at 22% 18%, rgba(123,108,240,.12), transparent 62%); --accent-light: #F0EEFF;
  /* the action cards on the glass (Send feedback): their shadow, higher on hover; the avatar's ring */
  --gl-act-sh: 0 1px 2px rgba(17,17,19,.06), 0 4px 12px rgba(70,50,160,.08); --gl-act-sh-hi: 0 2px 4px rgba(17,17,19,.07), 0 8px 20px rgba(70,50,160,.12);
  --accent-ring: rgba(123,108,240,.35);
  /* the hover of the phone island's buttons */
  --bg-hover: #F2F2F5;
  --shadow-soft-lg: 0 16px 40px rgba(17,17,19,.09), 0 2px 4px rgba(17,17,19,.04);
  /* the left bar's labels, the raised tool tile and the dot of the chosen tool (the prototype's) */
  --shadow-soft: 0 11px 29px rgba(17,17,19,.06), 0 1px 2px rgba(17,17,19,.04);
  --ic-sheen: rgba(255,255,255,.7); --ic-shadow-up: 0 2px 2px rgba(17,17,19,.06), 0 4px 8px rgba(17,17,19,.08);
  --grad-dot: linear-gradient(135deg, #9C8FFF 0%, #6C5CE6 100%);
  --shadow-sheet: 0 -12px 40px rgba(17,17,19,.12);
  /* the student app: a quiet fill (the phone drawer), the stronger divider, the accent's soft tint, the islands' shadow,
     the code font and the Debug chat's warning */
  --bg-subtle: #F7F7F9; --border-strong: #E0E0E3; --accent-soft: rgba(123,108,240,.08);
  --isl-shadow: 0 11px 29px rgba(70,50,160,.12), 0 1px 2px rgba(17,17,19,.05);
  /* the student app's raised shadow in final values (.app-page; the sign-in page keeps --shadow-raised) */
  --shadow-raised-app: 0 1px 2px rgba(17,17,19,.06), 0 4px 11px rgba(17,17,19,.04);
  --font-mono: ui-monospace, SFMono-Regular, Menlo, monospace;
  --warning: #B45309;
  /* the violet for text and lines on a tint (the level-1 circle with activities): 4.5:1 on --accent-soft; the two ends
     of the progress ring's arc */
  --accent-text: #5B4BD6; --ring-a: #9C8FFF; --ring-b: #6C5CE6;
  /* the citation chip's fill, open and closed (on the dark theme the tint lies over the muted surface) */
  --cite-bg: var(--accent-soft); --cite-locked-bg: var(--bg-muted);
  /* the check on a filled mark (an idea explained), white in both themes */
  --on-dot: #FFFFFF;
  /* the destructive action of a window (End): its fill, pressed, and its text */
  --danger: var(--err-text); --danger-hover: #8E332E; --on-danger: #FFFFFF;
  /* the end card of a Guided Study: the accent's tint on the solid surface, with its edge */
  --ended-bg: linear-gradient(color-mix(in srgb, var(--accent) 10%, transparent), color-mix(in srgb, var(--accent) 10%, transparent)), var(--bg-primary);
  --ended-edge: color-mix(in srgb, var(--accent) 22%, transparent);
  /* the student's bubble: a light violet of the accent with a fine edge, apart from the conversation's background
     (the PO, 14/10/2026) */
  --bubble-me: #EAE7FD; --bubble-me-edge: #C9C2F9;
  /* the activity switch's command: at rest a muted violet; pressed, End's red and Start's violet a tone darker */
  --sw-cmd: color-mix(in srgb, var(--text-secondary) 70%, var(--accent));
  --sw-end-press: color-mix(in srgb, var(--soft-red-text) 80%, #000); --sw-start-press: color-mix(in srgb, var(--link) 80%, #000);
  /* the offline notice of the conversation: the accent's tint */
  --net-bg: color-mix(in srgb, var(--accent) 7%, transparent);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg-page: #0C0C0F; --bg-primary: #141417; --bg-muted: #202026;
    --text-primary: #F5F5F7; --text-body: #CDCDD5; --text-secondary: #A4A4B0; --text-faint: #5A5A64;
    --accent: #8B7CF6; --link: #8B7CF6; --link-hover: #9D90FF; --on-accent: #111113;
    --soft-red-text: #F08A84;
    --hairline: rgba(255,255,255,.08); --edge-raised: rgba(255,255,255,.07);
    --gl-read: rgba(20,20,24,.56); --gl-edge-a: rgba(255,255,255,.22); --gl-edge-b: rgba(255,255,255,.06);
    --gl-card: rgba(255,255,255,.06); --gl-card-edge: rgba(255,255,255,.1); --gl-hover: rgba(255,255,255,.08); --gl-press: rgba(255,255,255,.13);
    --isl-sheen: rgba(255,255,255,.12); --ctl-sheen: rgba(255,255,255,.14);
    --card-shadow: inset 0 1px 0 var(--isl-sheen), inset 0 -1px 2px rgba(0,0,0,.04), 0 1px 2px rgba(0,0,0,.4), 0 12px 32px rgba(0,0,0,.45);
    --shadow-raised: 0 1px 2px rgba(0,0,0,.45), 0 4px 12px rgba(0,0,0,.28);
    --field-bg: rgba(255,255,255,.06); --field-edge: rgba(255,255,255,.10);
    --accent-glow: 0 6px 20px rgba(139,124,246,.35), 0 1px 2px rgba(0,0,0,.4);
    --accent-glow-hi: 0 8px 22px rgba(139,124,246,.40), 0 1px 2px rgba(0,0,0,.4);
    --accent-glow-app: 0 5px 18px rgba(139,124,246,.35), 0 1px 2px rgba(0,0,0,.4);
    --action-link: var(--link);
    --err-bg: color-mix(in srgb, var(--soft-red-text) 16%, transparent);
    --aurora-opacity: .85; --aur-blend: screen; --grain-opacity: .10; --dither-opacity: .09;
    --surface-raised: rgba(255,255,255,.10); --surface-raised-edge: rgba(255,255,255,.14);
    --tutor-symbol: url(/assets/brand/sophai-symbol-night-v1.svg); --accent-halo: radial-gradient(circle, rgba(139,124,246,.14) 0%, rgba(139,124,246,.05) 45%, transparent 70%);
    --scrim: rgba(0,0,0,.55); --scrim-solid: rgba(0,0,0,.7); --scrim-soft: rgba(0,0,0,.5);
    --glass-sheen: rgba(255,255,255,.08); --press: rgba(255,255,255,.08); --gl-fill: rgba(20,20,24,.35); --tb-glass: rgba(15,15,19,.60);
    --glass-panel: rgba(15,15,19,.55); --glass-border: rgba(255,255,255,.10); --rail-shadow: 7px 0 22px rgba(0,0,0,.28);
    --ic-top: var(--bg-muted); --ic-shadow: 0 1px 1px rgba(0,0,0,.45), 0 3px 7px rgba(0,0,0,.5);
    --ic-halo: radial-gradient(circle at 22% 18%, rgba(139,124,246,.14), transparent 62%); --accent-light: rgba(139,124,246,.22);
    --gl-act-sh: 0 1px 2px rgba(0,0,0,.3), 0 4px 12px rgba(0,0,0,.25); --gl-act-sh-hi: 0 2px 4px rgba(0,0,0,.35), 0 8px 20px rgba(0,0,0,.35); --accent-ring: rgba(139,124,246,.45); --bg-hover: #24242B;
    --shadow-soft-lg: 0 16px 43px rgba(0,0,0,.55), 0 2px 4px rgba(0,0,0,.4);
    --shadow-soft: 0 11px 29px rgba(0,0,0,.45), 0 1px 2px rgba(0,0,0,.4);
    --ic-sheen: rgba(255,255,255,.08); --ic-shadow-up: 0 2px 2px rgba(0,0,0,.45), 0 4px 8px rgba(0,0,0,.55);
    --grad-dot: linear-gradient(135deg, #9D8EFF 0%, #6E5CE6 100%);
    --shadow-sheet: 0 -12px 40px rgba(0,0,0,.6);
    --bg-subtle: #161619; --border-strong: #34343B; --accent-soft: rgba(139,124,246,.15);
    --isl-shadow: 0 11px 29px rgba(0,0,0,.45);
    --shadow-raised-app: 0 1px 2px rgba(0,0,0,.45), 0 4px 11px rgba(0,0,0,.28);
    --accent-text: #A89CFF; --ring-a: #9D8EFF; --ring-b: #6E5CE6;
    --cite-bg: linear-gradient(var(--accent-soft), var(--accent-soft)), var(--bg-muted); --cite-locked-bg: linear-gradient(var(--accent-soft), var(--accent-soft)), var(--bg-muted);
    --danger: #B3362F; --danger-hover: #C2413A; --bubble-me: #2E2B48; --bubble-me-edge: #4F4785;  --ended-bg: color-mix(in srgb, var(--accent) 7%, transparent); --ended-edge: transparent; --net-bg: color-mix(in srgb, var(--accent) 9%, transparent);
  }
}
:root[data-theme="light"] { color-scheme: light; }
:root[data-theme="dark"] {
  color-scheme: dark;
  --bg-page: #0C0C0F; --bg-primary: #141417; --bg-muted: #202026;
  --text-primary: #F5F5F7; --text-body: #CDCDD5; --text-secondary: #A4A4B0; --text-faint: #5A5A64;
  --accent: #8B7CF6; --link: #8B7CF6; --link-hover: #9D90FF; --on-accent: #111113;
  --soft-red-text: #F08A84;
  --hairline: rgba(255,255,255,.08); --edge-raised: rgba(255,255,255,.07);
  --gl-read: rgba(20,20,24,.56); --gl-edge-a: rgba(255,255,255,.22); --gl-edge-b: rgba(255,255,255,.06);
  --gl-card: rgba(255,255,255,.06); --gl-card-edge: rgba(255,255,255,.1); --gl-hover: rgba(255,255,255,.08); --gl-press: rgba(255,255,255,.13);
  --isl-sheen: rgba(255,255,255,.12); --ctl-sheen: rgba(255,255,255,.14);
  --card-shadow: inset 0 1px 0 var(--isl-sheen), inset 0 -1px 2px rgba(0,0,0,.04), 0 1px 2px rgba(0,0,0,.4), 0 12px 32px rgba(0,0,0,.45);
  --shadow-raised: 0 1px 2px rgba(0,0,0,.45), 0 4px 12px rgba(0,0,0,.28);
  --field-bg: rgba(255,255,255,.06); --field-edge: rgba(255,255,255,.10);
  --accent-glow: 0 6px 20px rgba(139,124,246,.35), 0 1px 2px rgba(0,0,0,.4);
  --accent-glow-hi: 0 8px 22px rgba(139,124,246,.40), 0 1px 2px rgba(0,0,0,.4);
  --accent-glow-app: 0 5px 18px rgba(139,124,246,.35), 0 1px 2px rgba(0,0,0,.4);
  --action-link: var(--link);
  --err-bg: color-mix(in srgb, var(--soft-red-text) 16%, transparent);
  --aurora-opacity: .85; --aur-blend: screen; --grain-opacity: .10; --dither-opacity: .09;
  --surface-raised: rgba(255,255,255,.10); --surface-raised-edge: rgba(255,255,255,.14);
  --tutor-symbol: url(/assets/brand/sophai-symbol-night-v1.svg); --accent-halo: radial-gradient(circle, rgba(139,124,246,.14) 0%, rgba(139,124,246,.05) 45%, transparent 70%);
  --scrim: rgba(0,0,0,.55); --scrim-solid: rgba(0,0,0,.7); --scrim-soft: rgba(0,0,0,.5);
  --glass-sheen: rgba(255,255,255,.08); --press: rgba(255,255,255,.08); --gl-fill: rgba(20,20,24,.35); --tb-glass: rgba(15,15,19,.60);
    --glass-panel: rgba(15,15,19,.55); --glass-border: rgba(255,255,255,.10); --rail-shadow: 7px 0 22px rgba(0,0,0,.28);
    --ic-top: var(--bg-muted); --ic-shadow: 0 1px 1px rgba(0,0,0,.45), 0 3px 7px rgba(0,0,0,.5);
    --ic-halo: radial-gradient(circle at 22% 18%, rgba(139,124,246,.14), transparent 62%); --accent-light: rgba(139,124,246,.22);
    --gl-act-sh: 0 1px 2px rgba(0,0,0,.3), 0 4px 12px rgba(0,0,0,.25); --gl-act-sh-hi: 0 2px 4px rgba(0,0,0,.35), 0 8px 20px rgba(0,0,0,.35); --accent-ring: rgba(139,124,246,.45); --bg-hover: #24242B;
  --shadow-soft-lg: 0 16px 43px rgba(0,0,0,.55), 0 2px 4px rgba(0,0,0,.4);
  --shadow-soft: 0 11px 29px rgba(0,0,0,.45), 0 1px 2px rgba(0,0,0,.4);
  --ic-sheen: rgba(255,255,255,.08); --ic-shadow-up: 0 2px 2px rgba(0,0,0,.45), 0 4px 8px rgba(0,0,0,.55);
  --grad-dot: linear-gradient(135deg, #9D8EFF 0%, #6E5CE6 100%);
  --shadow-sheet: 0 -12px 40px rgba(0,0,0,.6);
  --bg-subtle: #161619; --border-strong: #34343B; --accent-soft: rgba(139,124,246,.15);
  --isl-shadow: 0 11px 29px rgba(0,0,0,.45);
  --shadow-raised-app: 0 1px 2px rgba(0,0,0,.45), 0 4px 11px rgba(0,0,0,.28);
  --accent-text: #A89CFF; --ring-a: #9D8EFF; --ring-b: #6E5CE6;
  --cite-bg: linear-gradient(var(--accent-soft), var(--accent-soft)), var(--bg-muted); --cite-locked-bg: linear-gradient(var(--accent-soft), var(--accent-soft)), var(--bg-muted);
  --danger: #B3362F; --danger-hover: #C2413A; --bubble-me: #2E2B48; --bubble-me-edge: #4F4785;  --ended-bg: color-mix(in srgb, var(--accent) 7%, transparent); --ended-edge: transparent; --net-bg: color-mix(in srgb, var(--accent) 9%, transparent);
}
@media (max-width: 639px) { :root { --ax: -33.5vw; --ay: 10.8vh; } }

/* == fonts == */
/* Self-hosted (OFL, from sophai-brand): no request leaves the app. A changed file gets a new -vN name.
   Declared for 400 to 600: the weights the rules allow (600 only on the citation chip). */
@font-face { font-family: 'DM Sans'; font-style: normal; font-weight: 400 600; font-display: swap; src: url(/assets/fonts/dmsans-v1.woff2) format('woff2'); }
@font-face { font-family: 'Source Serif 4'; font-style: normal; font-weight: 400 600; font-display: swap; src: url(/assets/fonts/sourceserif4-opsz-v1.woff2) format('woff2'); }

/* == base == */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body { margin: 0; min-height: 100vh; background: var(--bg-page); color: var(--text-body); font: 400 var(--text-base)/1.55 var(--font-body); -webkit-font-smoothing: antialiased; }
button, input { font: inherit; color: inherit; }
button { cursor: pointer; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
svg.i { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; flex: none; }
.sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
[hidden] { display: none; }

/* == aurora == */
/* Three colour blobs behind the content, fixed to the window, with a grain (and, in dark, a fine dither against
   banding). It drifts slowly and breathes; with prefers-reduced-motion it stands still. */
.sky-wrap { position: fixed; inset: 0; z-index: 0; overflow: hidden; pointer-events: none; }
.sky { position: absolute; inset: -10%; opacity: var(--aurora-opacity); filter: blur(46px) saturate(1.15);
  transform: translate3d(var(--ax), var(--ay), 0); animation: aur-drift var(--aur-dur) ease-in-out infinite alternate; will-change: transform; }
.sky i { position: absolute; display: block; border-radius: 50%; mix-blend-mode: var(--aur-blend); }
.sky .b1 { width: 50%; height: 62%; left: 54%; top: -14%; background: var(--aur-1); animation: br1 calc(16s * var(--br-t)) ease-in-out infinite alternate; }
.sky .b2 { width: 40%; height: 50%; left: 68%; top: 8%; background: var(--aur-2); animation: br2 calc(19s * var(--br-t)) ease-in-out infinite alternate; }
.sky .b3 { width: 46%; height: 56%; left: 44%; top: -22%; background: var(--aur-3); animation: br3 calc(17s * var(--br-t)) ease-in-out infinite alternate; }
@keyframes aur-drift { from { transform: translate3d(var(--ax), var(--ay), 0); } to { transform: translate3d(var(--ax), calc(var(--ay) + var(--aur-travel)), 0); } }
@keyframes br1 { 0% { transform: none; } 50% { transform: translate3d(calc(-6% * var(--br-a)), calc(6% * var(--br-a)), 0) scale(calc(1 + .1 * var(--br-a))); } 100% { transform: translate3d(calc(4% * var(--br-a)), calc(8% * var(--br-a)), 0) scale(calc(1 + .04 * var(--br-a))); } }
@keyframes br2 { 0% { transform: none; } 50% { transform: translate3d(calc(-8% * var(--br-a)), calc(-4% * var(--br-a)), 0) scale(calc(1 + .1 * var(--br-a))); } 100% { transform: translate3d(calc(4% * var(--br-a)), calc(-6% * var(--br-a)), 0) scale(calc(1 + .02 * var(--br-a))); } }
@keyframes br3 { 0% { transform: none; } 50% { transform: translate3d(calc(6% * var(--br-a)), calc(5% * var(--br-a)), 0) scale(calc(1 - .05 * var(--br-a))); } 100% { transform: translate3d(calc(-5% * var(--br-a)), calc(3% * var(--br-a)), 0) scale(calc(1 + .08 * var(--br-a))); } }
.sky-wrap::before { content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none; opacity: var(--dither-opacity); background-size: 96px 96px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='96' height='96'%3E%3Cfilter id='d' color-interpolation-filters='sRGB'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='1.6' numOctaves='1' stitchTiles='stitch'/%3E%3CfeColorMatrix values='.33 .33 .33 0 0  .33 .33 .33 0 0  .33 .33 .33 0 0  0 0 0 0 1'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23d)'/%3E%3C/svg%3E"); }
.sky-wrap::after { content: ""; position: absolute; inset: 0; opacity: var(--grain-opacity); background-size: 200px 200px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E"); }
/* The student app's aurora (body.app-page), as in the prototype (AUR_FIXED): the same drift (top right to bottom right
   and back in 90 s) and breathing, but it starts at the top right (14vw, -8vh) and is softer (k .6: .19 in light, .33
   in dark). The sign-in page keeps its own start and strength (the tokens above). */
.app-page { --aurora-opacity: .19; --ax: 14vw; --ay: -8vh; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .app-page { --aurora-opacity: .33; } }
:root[data-theme="dark"] .app-page { --aurora-opacity: .33; }
/* the blobs are named as specifically as their own animation rules above, or those would win */
@media (prefers-reduced-motion: reduce) { .sky, .sky .b1, .sky .b2, .sky .b3 { animation: none; } }

/* == glass card == */
/* The glass island over the aurora: a translucent fill, blur 16 with saturate 180 %, a 1 px edge fading from the
   top left, the top sheen and the island's shadow. Without transparency it turns solid. */
.glass-card { position: relative; border-radius: var(--r-lg); background: var(--gl-read);
  -webkit-backdrop-filter: blur(16px) saturate(180%); backdrop-filter: blur(16px) saturate(180%); box-shadow: var(--card-shadow); }
.glass-card::after { content: ""; position: absolute; inset: 0; border-radius: inherit; padding: 1px; pointer-events: none; background: linear-gradient(135deg, var(--gl-edge-a), var(--gl-edge-b));
  -webkit-mask: linear-gradient(var(--mask) 0 0) content-box, linear-gradient(var(--mask) 0 0); -webkit-mask-composite: xor;
  mask: linear-gradient(var(--mask) 0 0) content-box exclude, linear-gradient(var(--mask) 0 0); }
@media (prefers-reduced-transparency: reduce) { .glass-card { background: var(--bg-primary); -webkit-backdrop-filter: none; backdrop-filter: none; box-shadow: inset 0 0 0 1px var(--edge-raised); } .glass-card::after { display: none; } }
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) { .glass-card { background: var(--bg-primary); box-shadow: inset 0 0 0 1px var(--edge-raised); } .glass-card::after { display: none; } }

/* == field == */
/* A label of 13/500 above a 48 px box with the field's surface; .error gives a 2 px edge in the error colour. */
.fld { display: flex; flex-direction: column; gap: 8px; }
.fld-l { font: 500 var(--text-sm)/1.3 var(--font-body); color: var(--text-secondary); transition: color .12s ease-out; }
.fld:focus-within .fld-l { color: var(--text-primary); }
.fld-i { width: 100%; height: 48px; padding: 0 16px; border: 0; border-radius: var(--r); background: var(--field-bg); box-shadow: inset 0 0 0 1px var(--field-edge);
  font: 400 var(--text-input)/1.4 var(--font-body); color: var(--text-primary); outline: none; transition: box-shadow .12s ease-out, background-color .12s ease-out; }
.fld-i::placeholder { color: var(--text-body); opacity: .7; }
.fld-i:focus, .fld-i:focus-visible { outline: 2px solid var(--accent); outline-offset: 0; }
@media (hover: hover) { .fld-i:not(.error):hover:not(:disabled) { box-shadow: inset 0 0 0 1px var(--hairline); } }
.fld-i:disabled { opacity: .6; cursor: default; }
.fld-i.error { box-shadow: inset 0 0 0 2px var(--err-edge); }
.fld-i.error:focus, .fld-i.error:focus-visible { outline: 2px solid var(--err-edge); box-shadow: inset 0 0 0 1px var(--field-edge); }
.fld-i.code { font: 500 20px/1.2 var(--font-body); letter-spacing: .1em; font-variant-numeric: tabular-nums; }
.fld-i.code::selection { background: color-mix(in srgb, var(--accent) 25%, transparent); }

/* == buttons == */
/* Primary: 48 px, the link violet with a sheen and a glow. Secondary: the glass key. Action link: text only, a 44 px
   target on touch screens. */
.btn-pri, .btn-sec { display: flex; align-items: center; justify-content: center; width: 100%; height: 48px; margin: 0; padding: 0 16px; border: 0; border-radius: var(--r);
  font: 500 var(--text-base)/1 var(--font-body); }
.btn-pri { background: var(--link); color: var(--on-accent); box-shadow: inset 0 1px 0 var(--ctl-sheen), var(--accent-glow); transition: background-color .15s, box-shadow .15s, transform .1s; }
.btn-pri:hover:not(:disabled) { background: var(--link-hover); box-shadow: inset 0 1px 0 var(--ctl-sheen), var(--accent-glow-hi); }
.btn-pri:active:not(:disabled) { transform: translateY(1px); box-shadow: inset 0 1px 0 var(--ctl-sheen), var(--accent-glow); }
.btn-pri:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; box-shadow: 0 0 0 2px var(--bg-primary), inset 0 1px 0 var(--ctl-sheen), var(--accent-glow); }
.btn-pri:disabled { opacity: .7; cursor: default; }
.btn-sec { background: var(--gl-card); color: var(--text-body); box-shadow: inset 0 0 0 1px var(--gl-card-edge), inset 0 1px 0 var(--ctl-sheen); transition: background-color .15s, box-shadow .15s, color .15s; }
.btn-sec:hover:not(:disabled) { background: var(--gl-hover); box-shadow: inset 0 0 0 1px var(--gl-card-edge), inset 0 1px 0 var(--ctl-sheen), var(--shadow-raised); }
.btn-sec:active:not(:disabled) { background: var(--gl-press); }
.btn-sec:disabled { color: var(--text-secondary); cursor: default; }
.btn-link { align-self: center; min-height: 32px; margin: 0; padding: 0 8px; border: 0; border-radius: var(--r-sm); background: none;
  font: 500 var(--text-md)/1.3 var(--font-body); color: var(--action-link); text-decoration: none; text-underline-offset: 3px; text-decoration-thickness: 1px; transition: color .12s; }
.btn-link:hover:not(:disabled), .btn-link:focus-visible { text-decoration: underline; }
.btn-link:disabled { opacity: .5; cursor: default; }
@media (max-width: 1024px), (pointer: coarse) { .btn-link { min-height: 44px; min-width: 44px; } }

/* == error notice == */
/* A disc with the icon, the first sentence at 500 in the error colour, the rest in --text-body. Empty, it keeps no
   height but stays in the page (role="alert" must be there before the message arrives). */
.err-note { display: grid; grid-template-columns: 28px minmax(0, 1fr); align-items: center; gap: 10px; padding: 10px 14px 10px 10px; border-radius: 14px;
  background: var(--err-bg); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--err-text) 22%, transparent); }
.err-note:empty { padding: 0; background: none; box-shadow: none; }
.err-note > svg.i { box-sizing: border-box; width: 28px; height: 28px; padding: 6px; border-radius: 50%; stroke-width: 2.5; background: var(--err-bg); color: var(--err-text); }
.err-note > span { font: 400 var(--text-md)/1.4 var(--font-body); color: var(--text-body); overflow-wrap: anywhere; }
.err-note b { font-weight: 500; color: var(--err-text); }
/* its action (Try again), a raised button of 32 under the text, with a 44 target */
.err-act { grid-column: 2; justify-self: start; position: relative; display: inline-flex; align-items: center; height: 32px; margin-top: 6px; padding: 0 12px; border: 0; border-radius: 10px;
  background: var(--surface-raised); box-shadow: inset 0 0 0 1px var(--hairline), var(--shadow-raised); font: 500 14px/1.3 var(--font-body); color: var(--text-primary); transition: background-color .15s; }
.err-act:hover { background: linear-gradient(color-mix(in srgb, var(--text-primary) 5%, transparent), color-mix(in srgb, var(--text-primary) 5%, transparent)), var(--surface-raised); }
.err-act::after { content: ""; position: absolute; left: 0; right: 0; top: 50%; height: 44px; transform: translateY(-50%); }
/* a failed read of the student's activities: the same notice in every list that shows them (pieces.js) */
.err-note.read-failed > svg.i { color: var(--err-text); }

/* == login == */
/* The sign-in page: the glass card centred over the aurora, the wordmark, the two steps (email, then code). */
.lg-wrap { position: relative; z-index: 1; min-height: 100vh; min-height: 100dvh; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 24px; padding: 32px 16px; }
.lg-card { width: min(360px, 100%); padding: 32px; display: flex; flex-direction: column; gap: 32px; overflow-wrap: anywhere; animation: lg-rise .15s ease-out both; }
.lg-card > * { position: relative; z-index: 1; }
@keyframes lg-rise { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
.lg-brand { display: flex; flex-direction: column; align-items: center; text-align: center; }
.lg-wm-h { margin: 4px 0 0; line-height: 0; }
.lg-wm { display: block; width: 160px; height: auto; }
/* the wordmark follows the theme: the light file, or the night one in dark (a saved choice wins over the system) */
.lg-wm-dark { display: none; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .lg-wm-light { display: none; } :root:not([data-theme="light"]) .lg-wm-dark { display: block; } }
:root[data-theme="dark"] .lg-wm-light { display: none; }
:root[data-theme="dark"] .lg-wm-dark { display: block; }
.lg-sub { margin: 19px 0 0; font: 400 var(--text-base)/1.4 var(--font-body); color: var(--text-secondary); }
.err-note:not(:empty) { margin-bottom: 16px; }
.lg-step { display: flex; flex-direction: column; margin: 0; }
.lg-step[hidden] { display: none; }
.lg-step > * + * { margin-top: 16px; }
.lg-step > .btn-pri + .resend-row, .lg-step > .btn-link + .lg-note { margin-top: 8px; }
/* the card that says where the code went */
.lg-sent { display: grid; grid-template-columns: 18px minmax(0, 1fr); column-gap: 12px; align-items: start; padding: 12px 14px; border-radius: var(--r);
  background: color-mix(in srgb, var(--accent) 7%, transparent); }
.lg-sent > svg.i { margin-top: 2px; color: var(--accent); }
.lg-sent-txt { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.lg-to { margin: 0; font: 400 var(--text-base)/1.4 var(--font-body); color: var(--text-primary); overflow-wrap: anywhere; }
.lg-to strong { font-weight: 500; }
.lg-msg { margin: 0; font: 400 var(--text-sm)/1.4 var(--font-body); color: var(--text-body); }
/* Send a new code, with the wait's clock inside the key */
.resend-row { position: relative; }
.resend-wait { position: absolute; right: 16px; top: 50%; transform: translateY(-50%); pointer-events: none; font: 400 var(--text-base)/1 var(--font-body); font-variant-numeric: tabular-nums; color: var(--text-secondary); }
.lg-note { align-self: center; max-width: 296px; margin: 0; font: 400 var(--text-sm)/1.45 var(--font-body); color: var(--text-secondary); text-align: center; }
/* the legal line, under the card over the aurora: 12/400, links underlined lightly in the text's colour (legal links
   are exempt from the 44 px touch rule). --text-body, not --text-secondary: on the light aurora's violet the
   secondary grey gave 4.1:1, under the 4.5:1 the line needs. */
.lg-legal { max-width: 480px; margin: 0; font: 400 var(--text-xs)/1.5 var(--font-body); color: var(--text-body); text-align: center; animation: lg-rise .15s ease-out .06s both; }
.lg-legal a { color: inherit; text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 2px; }
@media (max-width: 639px) {
  .lg-wrap { padding: 12vh 16px 32px; justify-content: flex-start; }
  .lg-card { padding: 24px; gap: 24px; }
  .lg-wm { width: 128px; }
  .lg-sub { margin-top: 13px; }
}
@media (prefers-reduced-motion: reduce) { .lg-card, .lg-legal { animation: none; } .lg-card *, .lg-card *::before, .lg-card *::after { transition: none; } }

/* == dialog == */
/* A modal that asks before going on: a scrim (blurred 12) under a solid raised panel, radius 16, padding 24; the glyph
   disc of 40, the title 18/500, the text 15/1.5 in --text-secondary, then the actions on the right: 44 high, radius 10,
   the cancel outlined, the main one filled (grey while disabled). Measures in px, never the size tokens a page may
   redefine. The page makes the rest inert and decides what Escape does. On the phone (< 640) it is a sheet against the
   bottom, the disc and the texts centred, the buttons stacked at 48 with the main one on top. Opening: the scrim fades in
   and the panel rises 8 (24 on the phone); the panel itself never starts transparent, so what it says is legible from
   the first frame.
   .dlg-terms: the Terms window ("Antes de começar"), 440 wide, with no grabber (it cannot be closed); the boxes
   (checkbox) sit between the text and the actions; an error notice (error notice) goes above the boxes, at 14 px, with
   its action (.err-act). */
.dlg-scrim { position: fixed; inset: 0; z-index: 4500; background: var(--scrim); -webkit-backdrop-filter: blur(12px) saturate(120%); backdrop-filter: blur(12px) saturate(120%);
  animation: dlg-fade .15s ease-out both; }
@media (prefers-reduced-transparency: reduce) { .dlg-scrim { background: var(--scrim-solid); -webkit-backdrop-filter: none; backdrop-filter: none; } }
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) { .dlg-scrim { background: var(--scrim-solid); } }
.dlg { position: fixed; inset: 0; z-index: 4600; display: grid; place-items: center; padding: 16px; pointer-events: none; }
.dlg-scrim[hidden], .dlg[hidden] { display: none; }
.dlg-panel { pointer-events: auto; display: flex; flex-direction: column; width: min(400px, 100%); max-height: calc(100vh - 32px); overflow: auto; padding: 24px; border-radius: 16px;
  background: linear-gradient(var(--surface-raised), var(--surface-raised)), var(--bg-primary); box-shadow: var(--shadow-soft-lg), inset 0 0 0 1px var(--surface-raised-edge);
  font: 400 15px/1.5 var(--font-body); color: var(--text-body); overflow-wrap: anywhere; animation: dlg-in .15s ease-out both; }
.dlg-terms { width: min(440px, 100%); }
.dlg-panel > * { margin: 0; }
.dlg-g { display: grid; place-items: center; flex: none; width: 40px; height: 40px; margin: 0 0 16px; border-radius: 50%; background: color-mix(in srgb, var(--accent) 12%, transparent); color: var(--link-hover); }
.dlg-g > svg.i { width: 20px; height: 20px; }
.dlg-panel > .dlg-t { font: 500 18px/1.3 var(--font-body); letter-spacing: -.01em; color: var(--text-primary); text-align: left; }
.dlg-panel > .dlg-d { margin-top: 8px; font: 400 15px/1.5 var(--font-body); color: var(--text-secondary); text-align: left; }
.dlg-d a { color: var(--link); text-decoration: underline; text-underline-offset: 2px; }
.dlg-panel > .cb-row { margin-top: 24px; }
.dlg-panel > .cb-row + .cb-row { margin-top: 8px; }
/* the error notice inside the panel: 14 px (the page may redefine --text-md), and its action, a raised button of 32 */
.dlg-panel > .err-note { margin: 24px 0 0; }
.dlg-panel > .err-note:empty { margin: 0; }
.dlg-panel > .err-note > span { font-size: 14px; }
.dlg-acts { margin-top: 24px; display: flex; justify-content: flex-end; gap: 8px; }
.dlg-btn { position: relative; height: 44px; padding: 0 18px; border: 0; border-radius: 10px; font: 500 15px/1.2 var(--font-body); text-align: center;
  transition: background-color .15s, box-shadow .15s, transform .1s; }
.dlg-btn::after { content: ""; position: absolute; left: 50%; top: 50%; width: max(100%, 44px); height: 44px; transform: translate(-50%, -50%); }
.dlg-btn:active:not(:disabled) { transform: translateY(1px); }
.dlg-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.dlg-cancel { background: transparent; box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--text-primary) 16%, transparent); color: var(--text-primary); }
.dlg-cancel:hover { background: color-mix(in srgb, var(--text-primary) 5%, transparent); }
.dlg-ok { background: var(--link); color: var(--on-accent); box-shadow: inset 0 1px 0 var(--ctl-sheen), var(--accent-glow); }
.dlg-ok:hover:not(:disabled) { background: var(--link-hover); }
/* disabled: grey, its text a little darker than --text-secondary so it keeps 4.5:1 on --bg-muted */
.dlg-ok:disabled { background: var(--bg-muted); color: color-mix(in srgb, var(--text-secondary) 80%, var(--text-primary)); box-shadow: none; cursor: default; }
/* dark: the raised surface is lighter, so its links take the lighter violet */
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .dlg-d a { color: var(--link-hover); } }
:root[data-theme="dark"] .dlg-d a { color: var(--link-hover); }
/* .dlg-end: "End this Guided Study?", a destructive question: the disc in the error colours with circle-stop, End
   filled in the danger red; Cancel hovers on the hover surface; on the phone, the sheet's grabber on top. */
.dlg-grab { display: none; }
.dlg-end .dlg-g { background: var(--err-bg); color: var(--err-text); }
.dlg-end .dlg-cancel:hover { background: var(--bg-hover); box-shadow: inset 0 0 0 1px var(--hairline); }
.dlg-end .dlg-danger { background: var(--danger); color: var(--on-danger); box-shadow: inset 0 1px 0 var(--ctl-sheen); }
.dlg-end .dlg-danger:hover:not(:disabled), .dlg-end .dlg-danger:active:not(:disabled) { background: var(--danger-hover); }
.dlg-end .dlg-btn:disabled { opacity: .6; cursor: default; }
@keyframes dlg-fade { from { opacity: 0; } }
@keyframes dlg-in { from { transform: translateY(8px); } }
@keyframes dlg-up { from { transform: translateY(24px); } }
@media (max-width: 639px) {
  .dlg { place-items: end stretch; padding: 0; }
  .dlg-panel { width: 100%; max-height: 86vh; border-radius: 16px 16px 0 0; padding: 24px 24px max(24px, calc(env(safe-area-inset-bottom) + 16px));
    box-shadow: var(--shadow-sheet), inset 0 1px 0 var(--hairline); animation: dlg-up .2s ease-out both; }
  .dlg-g { margin: 0 auto 16px; }
  .dlg-panel > .dlg-t, .dlg-panel > .dlg-d { text-align: center; }
  .dlg-acts { flex-direction: column-reverse; }
  .dlg-btn { width: 100%; height: 48px; border-radius: 12px; }
  .dlg-grab { display: block; flex: none; width: 36px; height: 5px; margin: -12px auto 16px; border-radius: 3px; background: color-mix(in srgb, var(--text-primary) 18%, transparent); }
}
@media (prefers-reduced-motion: reduce) { .dlg-scrim, .dlg-panel { animation: none; } .dlg-panel *, .dlg-panel *::before, .dlg-panel *::after { transition: none; } }

/* == checkbox == */
/* A row of 56 with the field's surface: a real checkbox, visually hidden, behind a box of 20 (radius 6) that fills with
   the accent when checked, the check popping in; the text 15/1.4. The whole row is the label and carries the focus
   ring. A link inside the text opens its page and leaves the box as it was. Disabled, the box fades to half. */
.cb-row { position: relative; display: grid; grid-template-columns: 20px minmax(0, 1fr); gap: 12px; align-items: center; min-height: 56px; padding: 0 16px; border-radius: 12px;
  background: var(--field-bg); box-shadow: inset 0 0 0 1px var(--field-edge); cursor: pointer; transition: background-color .12s, box-shadow .12s; }
.cb-i { position: absolute; left: 16px; top: 50%; width: 1px; height: 1px; margin: 0; padding: 0; border: 0; opacity: 0; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; }
.cb { display: grid; place-items: center; width: 20px; height: 20px; border-radius: 6px; background: var(--bg-primary);
  box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--text-secondary) 70%, transparent); transition: background-color .15s, box-shadow .15s; }
.cb > svg.i { width: 14px; height: 14px; stroke-width: 2.5; color: var(--on-accent); opacity: 0; transform: scale(.6); transition: opacity .12s, transform .18s cubic-bezier(.3, .8, .3, 1.4); }
.cb-row:has(.cb-i:checked) { background: color-mix(in srgb, var(--accent) 7%, transparent); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 40%, transparent); }
.cb-row:has(.cb-i:checked) .cb { background: var(--accent); box-shadow: inset 0 1px 0 var(--ctl-sheen), 0 1px 2px color-mix(in srgb, var(--accent) 35%, transparent); }
.cb-row:has(.cb-i:checked) .cb > svg.i { opacity: 1; transform: none; }
@media (hover: hover) { .cb-row:not(:has(.cb-i:disabled)):not(:has(.cb-i:checked)):hover { background: linear-gradient(color-mix(in srgb, var(--text-primary) 4%, transparent), color-mix(in srgb, var(--text-primary) 4%, transparent)), var(--field-bg); } }
.cb-row:not(:has(.cb-i:disabled)):active { background: linear-gradient(color-mix(in srgb, var(--text-primary) 8%, transparent), color-mix(in srgb, var(--text-primary) 8%, transparent)), var(--field-bg); transition-duration: .1s; }
.cb-row:has(.cb-i:focus-visible) { outline: 2px solid var(--accent); outline-offset: 0; }
.cb-row:has(.cb-i:disabled) { cursor: default; }
.cb-row:has(.cb-i:disabled) .cb { opacity: .5; }
.cb-t { font: 400 15px/1.4 var(--font-body); color: var(--text-primary); }
.cb-t a { position: relative; color: var(--link); text-decoration: underline; text-underline-offset: 2px; }
.cb-t a::after { content: ""; position: absolute; left: 0; right: 0; top: 50%; height: 44px; transform: translateY(-50%); }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .cb-t a { color: var(--text-primary); text-decoration-color: var(--link-hover); } }
:root[data-theme="dark"] .cb-t a { color: var(--text-primary); text-decoration-color: var(--link-hover); }
@media (prefers-reduced-motion: reduce) { .cb-row, .cb, .cb > svg.i { transition: none; } }

/* == shell == */
/* The student app (/). .app is the root, as tall as the window (100dvh, the viewport resizes with the keyboard): a grid
   of the left bar, the main column and the right column, which holds the icon bar (64) or, from 1280 with the panel
   open, the panel too (320 + 72). The aurora sits behind it all; the island #topbar floats over the main column, the
   icon bar and the panel over the right column. On the phone (== phone ==) one column. */
.app-page { height: 100dvh; min-height: 0; overflow: hidden; }
/* The app's measures are the prototype's final values: its design x 0.9, rounded to the pixel (the 44 px targets stay;
   on the phone the conversation and the panel's sheet keep the design's values, == phone ==). The type and radius tokens
   and the raised shadow take them here, for the app only: the sign-in page keeps the tokens above. */
.app-page { --text-md: 13px; --text-base: 14px; --r-sm: 7px; --r: 11px; --r-lg: 14px; --shadow-raised: var(--shadow-raised-app); }
:where(.app-page) svg.i { width: 16px; height: 16px; }
.app { --lb-w: clamp(216px, 18vw, 270px); --rc-w: 58px;
  position: relative; isolation: isolate; display: grid; grid-template-columns: var(--lb-w) minmax(0, 1fr) var(--rc-w); grid-template-rows: minmax(0, 1fr);
  height: 100vh; height: 100dvh; overflow: hidden; }
@media (min-width: 1280px) { .app.panel-open { --rc-w: 353px; } }
.icon-btn { display: inline-grid; place-items: center; justify-content: center; align-items: center; flex: none; width: 29px; height: 29px; margin: 0; padding: 0; border: 0; border-radius: var(--r-sm);
  background: none; color: var(--text-secondary); text-decoration: none; transition: background-color .12s, color .12s; }
.icon-btn:hover { background: var(--bg-muted); color: var(--text-primary); }
.icon-btn:focus-visible { outline-offset: 0; }
/* the brand files follow the theme: the light page shows the light file, dark the night one */
.lb-wm.lb-dark, .isl-sym .lb-dark, .lb-sym { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .lb-wm.lb-light, :root:not([data-theme="light"]) .isl-sym .lb-light { display: none; }
  :root:not([data-theme="light"]) .lb-wm.lb-dark, :root:not([data-theme="light"]) .isl-sym .lb-dark { display: block; }
}
:root[data-theme="dark"] .lb-wm.lb-light, :root[data-theme="dark"] .isl-sym .lb-light { display: none; }
:root[data-theme="dark"] .lb-wm.lb-dark, :root[data-theme="dark"] .isl-sym .lb-dark { display: block; }

/* the left bar: the wordmark and Collapse menu in a row of 50, Tools, then Send feedback and the account at the bottom;
   the prototype's glass panel (.63, .55 in dark, blur 18), a 1 px edge on the right and a shadow cast on the content */
.leftbar { grid-column: 1; grid-row: 1; position: relative; z-index: 20; display: flex; flex-direction: column; min-width: 0; min-height: 0; padding: 0 14px 14px;
  background: var(--glass-panel); -webkit-backdrop-filter: blur(18px) saturate(150%); backdrop-filter: blur(18px) saturate(150%); border-right: 1px solid var(--glass-border);
  box-shadow: var(--rail-shadow); }
.lb-head { display: flex; align-items: center; justify-content: space-between; gap: 7px; flex: none; height: 50px; margin: 0 0 7px; }
.lb-brand { display: flex; align-items: center; height: 36px; margin: 0; padding: 0 7px; border: 0; border-radius: var(--r-sm); background: none; color: inherit; }
.lb-wm { display: block; width: 79px; height: auto; }
.lb-sym { width: 32px; height: 32px; }
.lb-close { display: none; }
.lb-course, .panel-grab { display: none; }
/* Tools: its title is a section head (== section head ==), a button with a chevron that folds the list (not remembered,
   as the bar's collapse), then the tools as rows of 43 */
.lb-tools { display: flex; flex-direction: column; flex: none; }
.lb-sec { align-self: flex-start; } /* the section head (== section head ==) */
.lb-tools-list { display: flex; flex-direction: column; gap: 4px; margin-top: 4px; }
.lb-item { display: flex; align-items: center; gap: 11px; width: 100%; height: 43px; margin: 0; padding: 0 7px; border: 0; border-radius: 9px; background: none;
  font: 500 var(--text-base)/1.2 var(--font-body); color: var(--text-body); text-align: left; transition: background-color .15s, box-shadow .15s, color .15s; }
.lb-item:hover { background: var(--bg-muted); color: var(--text-primary); }
.lb-item:focus-visible { outline-offset: -2px; }
.lb-item[aria-current="page"] { background: var(--bg-primary); color: var(--text-primary); box-shadow: var(--shadow-raised), inset 0 0 0 1px var(--edge-raised); }
/* only one raised at a time, as in the prototype: with an activity open (its row raised in Your Last Activities), the
   tool's item lies flat on the muted surface */
.app.on-gs:has(#acts-list .tl-row[aria-current="true"]) .lb-item[aria-current="page"] { background: var(--bg-muted); box-shadow: none; }
/* the tool's app tile, in relief like the Sophai symbol; only the chosen tool is tinted: a halo and a violet pool
   that fade in, the accent glyph, a higher shadow */
.lb-tile { position: relative; display: grid; place-items: center; flex: none; width: 29px; height: 29px; border-radius: var(--r-sm); color: var(--text-secondary);
  background: linear-gradient(to bottom, var(--ic-top), var(--bg-muted)); box-shadow: inset 0 1px 0 var(--ic-sheen), var(--ic-shadow), 0 0 0 1px var(--edge-raised);
  transition: transform .15s, box-shadow .15s, color .15s; }
.lb-tile::before { content: ""; position: absolute; inset: 0; border-radius: inherit; background: var(--ic-halo), linear-gradient(to bottom, var(--ic-top), var(--accent-light)); opacity: 0; transition: opacity .15s; }
.lb-tile > svg.i { position: relative; }
.lb-item[aria-current="page"] .lb-tile { color: var(--accent); box-shadow: inset 0 1px 0 var(--ic-sheen), var(--ic-shadow-up), 0 0 0 1px var(--edge-raised); }
.lb-item[aria-current="page"] .lb-tile::before { opacity: 1; }
.lb-item:hover .lb-tile { transform: translateY(-1px); }
.lb-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lb-foot { display: flex; flex-direction: column; gap: 7px; margin-top: auto; padding-top: 7px; }
/* Send feedback: an action card on the glass (the prototype's veil, edge and shadow), ↗ because it opens another tab;
   on hover a lighter veil, a higher shadow, 1 px up, the icon and the ↗ in the primary colour; the bottom zone stays
   calm, so its words are in the secondary colour */
.lb-feedback { align-items: center; gap: 7px; min-height: 43px; padding: 7px; border-radius: 9px; background: var(--gl-card);
  box-shadow: inset 0 0 0 1px var(--gl-card-edge), var(--gl-act-sh); color: var(--text-secondary); text-decoration: none; transition: background .15s, box-shadow .15s, transform .15s; }
.lb-feedback:hover { background: var(--gl-hover); box-shadow: inset 0 0 0 1px var(--gl-card-edge), var(--gl-act-sh-hi); transform: translateY(-1px); color: var(--text-primary); }
.lb-feedback:active { background: var(--gl-press); box-shadow: inset 0 0 0 1px var(--gl-card-edge), var(--gl-act-sh); transform: none; }
.lb-fb-text { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.feedback-label { font: 500 var(--text-base)/1.3 var(--font-body); color: var(--text-secondary); }
.feedback-sub { font: 400 var(--text-sm)/1.3 var(--font-body); color: var(--text-secondary); }
.lb-feedback > .lb-fb-go { width: 14px; height: 14px; margin-left: auto; color: var(--text-secondary); }
.lb-feedback:hover > .lb-fb-go { color: var(--text-primary); }
@media (prefers-reduced-motion: reduce) { .lb-feedback, .lb-feedback:hover { transition: none; transform: none; } }
.lb-acct { display: flex; align-items: center; gap: 4px; min-width: 0; }
.lb-acct > .account-menu { flex: 1 1 auto; min-width: 0; }
.lb-admin { width: 43px; height: 43px; border-radius: 7px; transition: background-color .15s, color .15s; }

/* the main column: the island over the screen that is open (no stacking context of its own, so the lists of the path
   and the island sit above the dimmed background of the phone's sheets and below the drawer) */
.main { grid-column: 2; grid-row: 1; position: relative; display: flex; flex-direction: column; min-width: 0; min-height: 0; }
.island { background: var(--gl-fill); -webkit-backdrop-filter: blur(14px) saturate(180%); backdrop-filter: blur(14px) saturate(180%); border-radius: var(--r-lg);
  box-shadow: inset 0 1px 0 var(--isl-sheen), inset 0 -1px 2px var(--gl-depth), var(--isl-shadow); }
/* Liquid Glass, as in the prototype: the islands (the path, the icon bar, the phone's single island) and the panel, a
   fill, a blur of 14 with saturate 180 %, the top sheen, a faint depth at the bottom, the islands' shadow, and the
   specular edge: a 1 px ring fading from the top left (the glass card's). The panel keeps a denser reading fill
   (--gl-read; on a tablet, over the conversation, --tb-glass). Without transparency: solid, a hairline and the soft
   shadow; the left bar quiet and solid; no aurora. */
.island::after, .panel::after { content: ""; position: absolute; inset: 0; z-index: 1; border-radius: inherit; padding: 1px; pointer-events: none;
  background: linear-gradient(135deg, var(--gl-edge-a), var(--gl-edge-b));
  -webkit-mask: linear-gradient(var(--mask) 0 0) content-box, linear-gradient(var(--mask) 0 0); -webkit-mask-composite: xor;
  mask: linear-gradient(var(--mask) 0 0) content-box exclude, linear-gradient(var(--mask) 0 0); }
@media (prefers-reduced-transparency: reduce) {
  .island, .panel { background: var(--bg-primary); -webkit-backdrop-filter: none; backdrop-filter: none; box-shadow: 0 0 0 1px var(--hairline), var(--shadow-soft); }
  .island::after, .panel::after { display: none; }
  .leftbar { background: var(--bg-subtle); -webkit-backdrop-filter: none; backdrop-filter: none; }
  .app-page .sky { display: none; }
}
.topbar { position: absolute; top: 7px; left: 22px; z-index: 10; display: flex; align-items: center; gap: 4px; max-width: calc(100% - 43px); min-height: 36px; padding: 4px; }
.isl-btn { display: none; place-items: center; flex: none; width: 44px; height: 44px; margin: 0; padding: 0; border: 0; border-radius: var(--r-sm); background: none; color: var(--text-primary); }
.isl-btn:hover { background: var(--bg-hover); }
.isl-btn:active { background: var(--gl-press); }
.isl-btn:focus-visible { outline-offset: 0; }
.isl-btn svg.i { width: 18px; height: 18px; }
/* the symbol after Menu: both targets stay 44, the glyphs lean towards each other (as in the prototype) */
.isl-sym { justify-items: start; margin: 0 -8px 0 -4px; }
.isl-sym img { width: 32px; height: 32px; }
.path { display: flex; align-items: center; min-width: 0; flex: 1 1 auto; }
.course-name { display: flex; align-items: center; min-width: 0; white-space: nowrap; font: 500 var(--text-base)/1.2 var(--font-body); color: var(--text-primary); }
/* the book symbol before the course's name (the prototype's .lead-ic): 14, secondary; in the plain name (one course)
   it sits where the button's padding puts it */
.course-name > .course-lead { width: 14px; height: 14px; margin: 0 7px; color: var(--text-secondary); }
/* 2 or more courses: the name is a button with the ▾ (#course-btn) that opens My courses; the topic ▾ is the same
   button. On the glass they hover as a lighter veil with its 1 px edge and press deeper; open, a raised key. */
.course-btn { display: inline-flex; align-items: center; gap: 7px; max-width: 100%; height: 29px; margin: 0; padding: 0 7px; border: 0; border-radius: var(--r); background: none;
  font: 500 var(--text-base)/1.2 var(--font-body); color: var(--text-primary); transition: background-color .15s, box-shadow .15s, color .15s; }
.course-btn:hover { background: var(--gl-hover); box-shadow: inset 0 0 0 1px var(--gl-card-edge); }
.course-btn:active { background: var(--gl-press); }
.course-btn[aria-expanded="true"] { background: var(--bg-primary); box-shadow: var(--shadow-raised), inset 0 0 0 1px var(--edge-raised); }
.course-btn:disabled { opacity: .7; cursor: default; }
.course-btn:focus-visible { outline-offset: 0; }
.course-btn svg.i { width: 14px; height: 14px; color: var(--text-secondary); }
.course-txt { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.course-btn .course-chev { margin-left: -4px; transition: transform .15s, color .15s; }
.course-btn:hover .course-chev, .course-btn[aria-expanded="true"] .course-chev { color: var(--text-primary); }
.course-btn[aria-expanded="true"] .course-chev { transform: rotate(180deg); }
/* the topic ▾ (topic.js), after the course on the Guided Study screen only: a slanted rule, then the topic open (its
   number quieter) or "Choose a topic" in the secondary colour */
.path-topic { display: flex; align-items: center; flex: 0 1 auto; min-width: 0; }
.app:not(.on-gs) .path-topic { display: none; }
.path-sep { flex: none; width: 1px; height: 14px; margin: 0 11px; background: var(--border-strong); transform: rotate(18deg); }
.topic-btn { min-width: 0; }
.topic-btn.ph .course-txt, .topic-num { color: var(--text-secondary); }
.topic-num { font-weight: 400; }
/* The lists of the path, outside the island (My courses and the topic ▾), as in the prototype: the Account menu's
   mould, a solid surface 7 under the island (shell.js places them), at least 252 wide, rising 4 px in .12 s (never
   from transparent, so its topics and their dots are legible from the first frame, as the dialog's panel); no title
   on the computer. Their options: 14/400, 32 high, radius 7, a quiet hover, a deeper press, the chosen one tinted.
   The topics: level 1 as headings with its number in a circle, its topics folded but for one section (an accordion,
   topic.js), each deeper level one step in with a line through the dots of its rows (the topic dot), number and title
   on one line, a title that does not fit on a second. On the phone both are a sheet from the bottom (== phone ==). */
.path-menu { position: fixed; top: 50px; left: 7px; z-index: 60; width: 306px; min-width: 252px; max-width: calc(100vw - 16px); max-height: min(468px, calc(100dvh - 72px)); overflow: auto;
  padding: 5px; border-radius: var(--r-lg); background: var(--bg-primary); box-shadow: inset 0 1px 0 var(--glass-sheen), var(--shadow-soft-lg), 0 0 0 1px var(--hairline); scrollbar-width: thin; }
.path-menu:not([hidden]) { animation: menu-pop .12s ease-out; }
/* the topic list is wider on the computer, 333 (the PO's decision of 13/10/2026), so most names fit one line */
@media (min-width: 640px) { .topic-menu { width: 333px; } }
@keyframes menu-pop { from { transform: translateY(4px); } to { transform: none; } }
.sheet-top, .menu-head { display: none; }
.course-opt { display: flex; align-items: center; gap: 9px; width: 100%; min-height: 32px; margin: 0; padding: 6px 9px; border: 0; border-radius: var(--r-sm); background: none;
  font: 400 var(--text-base)/1.3 var(--font-body); color: var(--text-body); text-align: left; transition: background-color .15s, color .15s; }
/* each course with the book icon before its name, as in the island (the PO's request, 13/10/2026; the prototype's list
   has the names only): 14, secondary, the prototype's .opt-ic */
.course-opt > .course-opt-ic { flex: none; width: 14px; height: 14px; color: var(--text-secondary); }
.course-opt-name { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; } /* the whole name, as in the prototype */
.course-ck, .topic-ck { display: none; flex: none; width: 16px; height: 16px; margin-left: auto; color: var(--link); }
.topic-sec { display: flex; align-items: baseline; gap: 5px; min-height: 32px; margin: 0; padding: 5px 9px; font: 500 var(--text-sm)/1.35 var(--font-body); color: var(--text-secondary); }
.topic-sec .topic-opt-num { min-width: 0; font-size: var(--text-sm); font-weight: 500; }
.topic-kids { position: relative; padding-left: 11px; }
.topic-kids::before { content: ""; position: absolute; left: 25px; top: 0; bottom: 0; width: 2px;
  background: linear-gradient(to bottom, transparent 0, var(--border-strong) 13px, var(--border-strong) calc(100% - 13px), transparent 100%); }
.topic-opt, .topic-sub { display: flex; align-items: center; gap: 7px; width: 100%; min-height: 32px; margin: 0; padding: 0 9px; border: 0; border-radius: var(--r-sm); background: none;
  font: 400 var(--text-base)/1.3 var(--font-body); color: var(--text-body); text-align: left; }
.topic-opt { transition: background-color .15s, color .15s; }
.topic-sub .topic-opt-title { color: var(--text-primary); font-weight: 500; }
/* the topic dot and the level-1 circle (== topic dot ==), on the list's surface so the line passes behind them; the
   circle on the axis of its subtopics' dots */
.topic-list :is(.topic-dot, .topic-disc) { background: var(--bg-primary); }
.topic-sec:has(> .topic-disc), .topic-opt.topic-l1 { align-items: center; gap: 9px; }
.topic-list .topic-disc { margin-left: 19px; }
/* a level-1 title, as in the prototype's list: 14/500 in the primary colour, 25 after its circle */
.topic-sec:has(> .topic-disc) > .topic-opt-title, .topic-opt.topic-l1 > .topic-opt-title { margin-left: 16px; font: 500 14px/18px var(--font-body); color: var(--text-primary); }
/* a level-1 section with topics folds them with the tree's chevron (== curriculum roadmap ==, .rm-tog), in the gutter
   left of its circle; the list's levels sit one gutter (14) further in to leave it room */
.topic-fold { position: relative; }
.topic-list > .topic-kids { padding-left: 25px; }
.topic-list > .topic-kids::before { left: 39px; top: -5px;
  background: linear-gradient(to bottom, var(--border-strong) 0, var(--border-strong) calc(100% - 13px), transparent 100%); } /* from the circle down */
.topic-opt-num { flex: none; min-width: 31px; color: var(--text-secondary); font-variant-numeric: tabular-nums; }
.topic-opt-title { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; } /* a name that does not fit wraps, never cut */
.course-opt:hover, .course-opt:focus-visible, .topic-opt:hover, .topic-opt:focus-visible { background: var(--bg-muted); color: var(--text-primary); }
.course-opt:active, .topic-opt:active { background: var(--press); transition-duration: .1s; }
.course-opt:focus-visible, .topic-opt:focus-visible { outline-offset: -2px; }
.course-opt[aria-checked="true"], .topic-opt[aria-selected="true"] { background: var(--accent-soft); color: var(--text-primary); font-weight: 500; }
.topic-opt[aria-selected="true"] .topic-opt-num { font-weight: 400; }
@media (prefers-reduced-motion: reduce) { .course-btn, .course-btn .course-chev, .course-opt, .topic-opt { transition: none; } .path-menu:not([hidden]) { animation: none; } }
/* The offline banner, the prototype's system Banner (its pieces in real px, as the kit's): the disc of 28 with the
   wifi-off glyph (16), the first sentence at 500 in the primary colour, the rest 14/400; radius 14, a hairline edge,
   a 6 % tint of the text colour over the page colour, no shadow. In the flow at the top of the content column, under
   the island: it pushes the screen down while it shows. */
.offline-banner { display: grid; grid-template-columns: 28px minmax(0, 1fr); align-items: center; column-gap: 12px; flex: none; width: calc(100% - 28px); max-width: 648px; min-height: 52px;
  margin: 65px auto 0; padding: 8px 10px 8px 12px; border-radius: 14px; box-shadow: inset 0 0 0 1px var(--hairline);
  background: linear-gradient(color-mix(in srgb, var(--text-primary) 6%, transparent), color-mix(in srgb, var(--text-primary) 6%, transparent)), var(--bg-primary);
  font: 400 14px/1.4 var(--font-body); color: var(--text-body); }
.offline-banner b { font-weight: 500; color: var(--text-primary); }
.offline-banner-g { display: grid; place-items: center; width: 28px; height: 28px; border-radius: 50%; background: color-mix(in srgb, var(--text-primary) 7%, transparent); color: var(--text-secondary); }
.offline-banner-g > svg.i { width: 16px; height: 16px; }
.main:has(> .offline-banner:not([hidden])) :is(.page, .chat) { padding-top: 16px; }
/* the screens: one shown at a time */
.screen { position: relative; display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }
.page { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 90px 0 58px; }
.page > * { width: calc(100% - 28px); max-width: 648px; margin-left: auto; margin-right: auto; }
.page-title { margin-top: 0; margin-bottom: 14px; font: 400 29px/35px var(--font-serif); letter-spacing: -.01em; color: var(--text-primary); }
.empty-placeholder { padding: 22px 11px; font: 400 var(--text-sm)/1.6 var(--font-body); color: var(--text-secondary); text-align: center; }
.empty-placeholder a { color: inherit; }

/* the icon bar and the panel (glass islands at 8 from the edge; the panel 8 to the left of the bar) */
.panel-bar { position: absolute; top: 7px; right: 7px; z-index: 15; display: flex; flex-direction: column; gap: 4px; width: 36px; padding: 4px; }
.pb-btn { display: grid; place-items: center; width: 29px; height: 29px; margin: 0; padding: 0; border: 0; border-radius: 11px; background: none; color: var(--text-secondary);
  transition: background-color .15s, color .15s, box-shadow .15s; }
/* on the glass, hover and press are a lighter glass veil with a 1 px edge (the icon bar and the panel header) */
.pb-btn:not([aria-pressed="true"]):hover, .panel-hbtn:hover { background: var(--gl-hover); box-shadow: inset 0 0 0 1px var(--gl-card-edge); color: var(--text-primary); }
.pb-btn:not([aria-pressed="true"]):active, .panel-hbtn:active { background: var(--gl-press); }
.pb-btn:focus-visible { outline-offset: 0; }
.pb-btn[aria-pressed="true"] { background: var(--bg-primary); color: var(--accent); box-shadow: var(--shadow-raised), inset 0 0 0 1px var(--edge-raised); }
.panel { position: absolute; top: 7px; right: 50px; bottom: 22px; z-index: 15; display: flex; flex-direction: column; width: 288px; min-height: 0; overflow: hidden;
  border-radius: var(--r-lg); background: var(--gl-read); -webkit-backdrop-filter: blur(14px) saturate(180%); backdrop-filter: blur(14px) saturate(180%);
  box-shadow: inset 0 1px 0 var(--isl-sheen), inset 0 -1px 2px var(--gl-depth), var(--isl-shadow); }
@media (min-width: 640px) and (max-width: 1279px) and (prefers-reduced-transparency: no-preference) { .panel { background: var(--tb-glass); } }
.panel-tabs { display: none; }
/* header E5: the tool's glyph and name on a small line, the view's title 15/500, then Expand panel and Close panel (29) */
.panel-head { display: flex; align-items: flex-start; gap: 4px; flex: none; padding: 13px 11px 7px 14px; }
.panel-head-text { flex: 1 1 auto; min-width: 0; }
.panel-eb { display: flex; align-items: center; gap: 5px; margin: 0 0 2px; font: 500 var(--text-sm)/1.2 var(--font-body); color: var(--text-secondary); }
.panel-eb > svg.i { width: 12px; height: 12px; color: var(--accent); }
.r-head-title { margin: 0; font: 500 15px/18px var(--font-body); letter-spacing: -.005em; color: var(--text-primary); }
.panel-hbtn { margin-top: -7px; border-radius: 11px; } /* on the top line, with the tool's name (the prototype's hb-top) */
.panel-hbtn svg.i { width: 14px; height: 14px; }
.panel-view { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 10px 14px 14px; }
/* the Guided Study home has no panel and no icon bar, as in the prototype: the conversation's column takes the room */
.app.on-gs:has(#chat > .welcome) { --rc-w: 0px; }
.app.on-gs:has(#chat > .welcome) :is(.panel-bar, .panel, #panel-btn) { display: none; }
.i-fill { fill: currentColor; }
.i-fill-on { fill: var(--on-accent); stroke: var(--on-accent); }
/* From 640 the panel is open by default, as in the prototype; it comes in with a fade and 7 px from the right (.15 s
   ease-out) and leaves the same way (.12 s ease-in); it stands still with prefers-reduced-motion. Its bottom sits on the
   composer's bottom edge (from 640 to 1279, 7 above its top), or 22 above the window's (shell.js). From 640 to 1279 it
   floats over the content and a tap outside it closes it (shell.js); Expand panel exists only above 1280. */
@media (min-width: 640px) {
  .panel { transition: opacity .12s ease-in, transform .12s ease-in, visibility 0s .12s, width .15s ease-out; }
  .app:not(.panel-open) .panel { visibility: hidden; opacity: 0; transform: translateX(7px); }
  .app.panel-open .panel { transition: opacity .15s ease-out, transform .15s ease-out, width .15s ease-out; }
}
@media (max-width: 1280px) { #panel-expand { display: none; } }
/* the dimmed background of the drawer, of the sheets and of the left bar over the content (640 to 1023): .28 (.5 in
   dark) with a blur of 2; beside the drawer and the bar it covers only what is on their right */
.backdrop { position: fixed; inset: 0; z-index: 40; background: var(--scrim-soft); -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px); }
@media (min-width: 640px) and (max-width: 1023px) {
  .app.lb-over { --lb-w: 58px; }
  .app.lb-over .leftbar { position: fixed; top: 0; bottom: 0; left: 0; z-index: 50; width: 252px; background: var(--bg-subtle); -webkit-backdrop-filter: none; backdrop-filter: none;
    box-shadow: var(--shadow-soft-lg); }
  .app.lb-over .backdrop { left: 252px; }
}

/* Collapse menu (computer): the left bar at 64, icons only, as in the prototype (.rail-col): Collapse menu goes, the
   head keeps only the symbol, centred (#brand, "Expand", opens the bar again: shell.js); the items lose their fill and
   only their tile lifts on hover; the chosen tool keeps its raised tile and a violet dot on the bar's edge; Send
   feedback (its glass kept, as in the prototype), the account and Admin panel become 40 x 40. */
@media (min-width: 640px) {
  .app.lb-collapsed { --lb-w: 58px; }
  .app.lb-collapsed .leftbar { padding: 0 11px 11px; }
  .app.lb-collapsed .lb-head { justify-content: center; margin-bottom: 11px; }
  .app.lb-collapsed .lb-collapse { display: none; }
  .app.lb-collapsed .lb-brand { justify-content: center; width: 36px; height: 36px; padding: 0; }
  .app.lb-collapsed .lb-brand:hover { background: none; }
  .app.lb-collapsed .leftbar .lb-wm, .app.lb-collapsed .lb-label, .app.lb-collapsed .lb-sec, .app.lb-collapsed .lb-fb-text, .app.lb-collapsed .lb-fb-go,
  .app.lb-collapsed .account-trigger-name, .app.lb-collapsed .account-role, .app.lb-collapsed .account-chevron { display: none; }
  .app.lb-collapsed .lb-brand .lb-sym.lb-light { display: block; }
  .app.lb-collapsed .lb-item { justify-content: center; padding: 0; }
  .app.lb-collapsed .lb-item, .app.lb-collapsed .lb-item:hover, .app.lb-collapsed .lb-item[aria-current="page"] { background: transparent; box-shadow: none; }
  .app.lb-collapsed .lb-item[aria-current="page"] .lb-tile { box-shadow: inset 0 1px 0 var(--ic-sheen), var(--ic-shadow-up), 0 0 0 1px var(--edge-raised); }
  .app.lb-collapsed .lb-item[aria-current="page"]::after { content: ""; position: absolute; left: -15px; top: 50%; width: 9px; height: 9px; margin-top: -5px; border-radius: 50%; background: var(--grad-dot); }
  .app.lb-collapsed .lb-foot { align-items: center; }
  .app.lb-collapsed .lb-feedback { justify-content: center; width: 36px; height: 36px; min-height: 0; padding: 0; }
  /* the PO's request (13/10/2026; the prototype puts it last): Admin panel first, above Send feedback, then the account */
  .app.lb-collapsed .lb-acct { display: contents; }
  .app.lb-collapsed .lb-admin { order: -1; }
  .app.lb-collapsed .account-trigger { justify-content: center; height: 36px; padding: 0 5px; }
  .app.lb-collapsed .lb-acct > .account-menu, .app.lb-collapsed .lb-admin { width: 36px; }
  .app.lb-collapsed .lb-admin { height: 36px; }
  :root[data-theme="dark"] .app.lb-collapsed .lb-brand .lb-sym.lb-light { display: none; }
  :root[data-theme="dark"] .app.lb-collapsed .lb-brand .lb-sym.lb-dark { display: block; }
}
@media (min-width: 640px) and (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .app.lb-collapsed .lb-brand .lb-sym.lb-light { display: none; }
  :root:not([data-theme="light"]) .app.lb-collapsed .lb-brand .lb-sym.lb-dark { display: block; }
}
@media (prefers-reduced-motion: reduce) { .lb-tile, .lb-tile::before, .lb-item, .lb-sec, .lb-sec > svg.i { transition: none; } }
/* collapsed, Tools shows its tools whatever its title says (the title is hidden) */
.app.lb-collapsed .lb-tools-list[hidden] { display: flex; }

/* == left bar labels == */
/* As in the prototype (.tt): the left bar's own labels, a .tt inside each item (aria-hidden: the item keeps its own
   name), shown only while the bar is collapsed (Admin panel always: .always), on the right of the item, 12 away, a dark
   chip with its arrow. At once on hover, with a fade and a 4 px slide of .15 s, and on the keyboard's focus; never
   with touch nor on the phone. Escape hides it until the pointer or the focus leaves the item (.tt-off, shell.js). */
.tt { display: none; }
@media (min-width: 640px) {
  .leftbar .has-tt { position: relative; }
  .app.lb-collapsed .leftbar .tt, .leftbar .tt.always { display: block; position: absolute; left: calc(100% + 11px); top: 50%; z-index: 40; padding: 5px 8px;
    border-radius: var(--r-sm); background: var(--text-primary); color: var(--bg-primary); font: 500 var(--text-sm)/1.3 var(--font-body); white-space: nowrap;
    pointer-events: none; box-shadow: var(--shadow-soft); opacity: 0; visibility: hidden; transform: translate(-4px, -50%); transition: opacity .15s, transform .15s, visibility .15s; }
  .app.lb-collapsed .leftbar .tt::before, .leftbar .tt.always::before { content: ""; position: absolute; left: -4px; top: 50%; width: 7px; height: 7px; border-radius: 1px;
    background: var(--text-primary); transform: translateY(-50%) rotate(45deg); }
  .app.lb-collapsed .leftbar .has-tt:focus-visible > .tt, .leftbar .has-tt:focus-visible > .tt.always { opacity: 1; visibility: visible; transform: translate(0, -50%); }
}
@media (min-width: 640px) and (hover: hover) {
  .app.lb-collapsed .leftbar .has-tt:hover > .tt, .leftbar .has-tt:hover > .tt.always { opacity: 1; visibility: visible; transform: translate(0, -50%); }
}
@media (min-width: 640px) {
  .app.lb-collapsed .leftbar .has-tt.tt-off > .tt, .leftbar .has-tt.tt-off > .tt.always { opacity: 0; visibility: hidden; }
}
@media (prefers-reduced-motion: reduce) { .leftbar .tt { transition: none; } }
/* Expand panel (above 1280): 45 % of the area between the left bar and the icon bar, at least 288, the conversation
   keeping 432 (shell.js sets --panel-wide); the conversation's column follows in .15 s */
@property --rc-w { syntax: '<length>'; initial-value: 58px; inherits: false; }
@media (min-width: 1281px) {
  .app { transition: --rc-w .15s ease-out; }
  .app.panel-wide .panel { width: var(--panel-wide, 288px); }
  .app.panel-open.panel-wide { --rc-w: calc(var(--panel-wide, 288px) + 65px); }
}
@media (prefers-reduced-motion: reduce) { .app, .panel, .app.panel-open .panel { transition: none; } }

/* == activity switch == */
/* At the top of the icon bar, the left bar's chosen tile stretched into one piece (29 wide, radius 11): the tool's glyph
   (16) on top, a hairline in the accent, then the command of the activity on screen, End Guided Study (circle-stop) or,
   once it has ended, Start a new Guided Study (circle-play, filled on hover). The command never takes a fill of its
   own: hover and press are the surface's (--bg-muted, --press) and the glyph's colour (red for End, the link violet for
   Start). On the Curriculum Roadmap the tile is alone (the tree), as the chosen tile; ended, the plain tile. 11 between
   it and the views. On the phone the same piece lies down in the island (end.js): the glyph, a button that opens the
   panel's sheet on Progress, the hairline, the command, two halves of 32, each a 44 target (== phone ==). */
.sw { position: relative; display: flex; flex-direction: column; align-items: stretch; flex: none; width: 29px; border-radius: 11px; color: var(--accent);
  background: linear-gradient(to bottom, var(--ic-top), var(--bg-muted)); box-shadow: inset 0 1px 0 var(--ic-sheen), var(--ic-shadow-up), 0 0 0 1px var(--edge-raised); }
.sw::before { content: ""; position: absolute; inset: 0; border-radius: inherit; background: var(--ic-halo), linear-gradient(to bottom, var(--ic-top), var(--accent-light)); transition: opacity .15s; }
.sw.ended { color: var(--text-secondary); box-shadow: inset 0 1px 0 var(--ic-sheen), var(--ic-shadow), 0 0 0 1px var(--edge-raised); }
.sw.ended::before { opacity: 0; }
.sw-v { margin-bottom: 7px; }
.sw-hd { position: relative; display: grid; place-items: center; flex: none; width: 29px; height: 29px; margin: 0; padding: 0; border: 0; border-radius: inherit; background: none; color: inherit; }
.sw-hd > svg.i { width: 16px; height: 16px; }
.app:not(.on-gs) .sw-ic-gs, .app.on-gs .sw-ic-roadmap { display: none; }
.sw-wire { position: relative; display: block; flex: none; height: 1px; margin: 0 5px; background: color-mix(in srgb, var(--accent) 24%, transparent); }
.sw:not(:has(> .sw-cmd:not([hidden]))) > .sw-wire { display: none; }
.sw-cmd { position: relative; display: grid; place-items: center; flex: none; width: 29px; height: 29px; margin: 0; padding: 0; border: 0; border-radius: 0 0 11px 11px; background: transparent;
  color: var(--sw-cmd); transition: background-color .15s, color .15s; }
.sw-cmd > svg.i { width: 16px; height: 16px; }
.sw-cmd:hover { background: var(--bg-muted); }
.sw-cmd:active:not(:disabled) { background: var(--press); transition-duration: .1s; }
.sw-cmd:focus-visible { outline: 2px solid var(--accent); outline-offset: 0; }
.sw-end:hover { color: var(--soft-red-text); }
.sw-end:active:not(:disabled) { color: var(--sw-end-press); }
.sw-start:hover { color: var(--link); }
.sw-start:active:not(:disabled) { color: var(--sw-start-press); }
.sw-cmd .sw-fill, .sw-start:hover .sw-line, .sw-start:active .sw-line { display: none; }
.sw-start:hover .sw-fill, .sw-start:active .sw-fill { display: block; }
.isl-sw { display: none; }
@media (prefers-reduced-motion: reduce) { .sw::before, .sw-cmd { transition: none; } }

/* == tooltip == */
/* One layer, #tip, outside .app: a dark chip with an arrow (13/500), beside the buttons of the icon bar and of the panel
   header, as in the prototype (the left bar has its own labels, == left bar labels ==). It only fades in (opacity), and not with
   prefers-reduced-motion. shell.js places it and picks the side: .r (right), .l (left), .b (under), .t (above); --a is
   where the arrow points. */
.tip { position: fixed; left: 0; top: 0; z-index: 1000; width: max-content; max-width: 216px; padding: 5px 8px; border-radius: var(--r-sm); background: var(--text-primary);
  font: 500 var(--text-sm)/1.3 var(--font-body); color: var(--bg-primary); white-space: normal; overflow-wrap: break-word; box-shadow: var(--shadow-soft);
  pointer-events: none; opacity: 0; transition: opacity .15s; }
.tip.on { opacity: 1; }
.tip::before { content: ""; position: absolute; width: 7px; height: 7px; border-radius: 1px; background: var(--text-primary); transform: rotate(45deg); }
.tip.r::before { left: -4px; top: calc(var(--a) - 4px); }
.tip.l::before { right: -4px; top: calc(var(--a) - 4px); }
.tip.b::before { top: -4px; left: calc(var(--a) - 4px); }
.tip.t::before { bottom: -4px; left: calc(var(--a) - 4px); }
@media (prefers-reduced-motion: reduce) { .tip { transition: none; } }

/* == account menu == */
/* The account in the left bar, as in the prototype: the avatar with its ring, the name, its role ("Student" or
   "Admin", 13, secondary) and the chevron in a box of its own at the end, primary on hover; no fill of its own while
   the menu is open. A long name gives way, cut with an ellipsis, so the role and the chevron always show (the
   prototype's name does not shrink: an improvement, review round 1). The menu opens above it, a solid raised surface. */
.account-menu { position: relative; display: flex; align-items: center; }
.account-trigger { display: flex; align-items: center; gap: 7px; width: 100%; min-width: 0; height: 43px; margin: 0; padding: 0 7px; border: 0; border-radius: 9px; background: none; overflow: hidden;
  font: 500 var(--text-base)/1.2 var(--font-body); color: var(--text-primary); text-align: left; transition: background-color .15s, color .15s; }
.account-trigger:hover { background: var(--bg-muted); }
.account-avatar { display: inline-grid; place-items: center; flex: none; width: 25px; height: 25px; border-radius: 50%; background: var(--bg-primary);
  box-shadow: 0 0 0 1px var(--accent-ring); font: 500 var(--text-sm)/1 var(--font-body); color: var(--link); }
.account-trigger-name { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.account-role { flex: none; font: 400 var(--text-sm)/1.2 var(--font-body); color: var(--text-secondary); white-space: nowrap; }
.account-role:empty { display: none; }
.account-chevron { flex: none; display: grid; place-items: center; width: 14px; height: 29px; margin-left: auto; border-radius: 7px; color: var(--text-secondary); transition: background-color .15s, color .15s; }
.account-chevron > svg.i { width: 14px; height: 14px; }
.account-trigger:hover .account-chevron { color: var(--text-primary); }
/* The menu, as in the prototype: a solid surface, the large soft shadow and a hairline ring, radius 14, padding 5; as
   wide as the bar less 12 on each side (its 1 px edge counted), 4 above the account row (collapsed: 240 wide, beside the avatar, bottoms
   aligned). It keeps the app's opening (a fade and 4 px, .15 s ease-out in, .12 s ease-in out). The name and email
   on top, a hairline, Theme, a hairline, Sign out and the legal line. */
.lb-acct { position: relative; }
.lb-acct > .account-menu { position: static; }
.account-popover { position: absolute; left: -2px; right: -3px; bottom: calc(100% + 4px); z-index: 80; padding: 5px; border-radius: var(--r-lg);
  background: var(--bg-primary); box-shadow: var(--shadow-soft-lg), 0 0 0 1px var(--hairline);
  opacity: 0; visibility: hidden; pointer-events: none; transform: translateY(4px); transition: opacity .12s ease-in, transform .12s ease-in, visibility .12s; }
@media (min-width: 640px) {
  .app.lb-collapsed .lb-acct > .account-menu { position: relative; }
  .app.lb-collapsed .account-popover { left: calc(100% + 8px); right: auto; bottom: 0; width: 240px; }
}
.account-popover-immediate { transition: none; }
.account-menu.open .account-popover { opacity: 1; visibility: visible; pointer-events: auto; transform: none; transition-timing-function: ease-out; transition-duration: .15s; }
.account-popover-head { display: flex; flex-direction: column; gap: 2px; min-width: 0; padding: 7px 9px 9px; }
.account-popover-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font: 500 var(--text-base)/1.3 var(--font-body); color: var(--text-primary); }
.account-email { overflow-wrap: anywhere; font: 400 var(--text-sm)/1.4 var(--font-body); color: var(--text-secondary); }
.account-popover-actions { margin-top: 5px; padding: 5px 0 0; border-top: 1px solid var(--hairline); }
.account-opt, .account-logout { display: flex; align-items: center; gap: 9px; width: 100%; height: 32px; margin: 0; padding: 0 9px; border: 0; border-radius: var(--r-sm); background: none;
  font: 400 var(--text-base)/1.2 var(--font-body); color: var(--text-body); text-align: left; transition: background-color .15s, color .15s; }
.account-opt:hover, .account-logout:hover, .account-opt:focus-visible, .account-logout:focus-visible { background: var(--bg-muted); color: var(--text-primary); }
.account-opt:focus-visible, .account-logout:focus-visible { outline-offset: -2px; }
.account-logout:disabled { cursor: wait; opacity: .7; }
.account-logout svg.i { width: 14px; height: 14px; }
.account-logout-status { padding: 4px 9px 0; font: 400 var(--text-sm)/1.35 var(--font-body); color: var(--err-text); }
/* Theme: a heading, then System, Light and Dark as rows, the check on the one chosen */
.account-theme { display: flex; flex-direction: column; padding: 0; border-top: 1px solid var(--hairline); }
.account-mh { margin: 5px 0 0; padding: 5px 9px 2px; font: 500 var(--text-sm)/1.3 var(--font-body); color: var(--text-secondary); }
.account-opt[aria-checked="true"] { color: var(--text-primary); font-weight: 500; }
.account-opt .account-ck { width: 14px; height: 14px; visibility: hidden; color: var(--accent); }
.account-opt[aria-checked="true"] .account-ck { visibility: visible; }
/* the legal line under Sign out: 12/400 in the secondary colour (4.5:1 on the menu's solid surface), its links
   underlined at 35 % of their colour, fully and in the primary colour on hover; its bottom as far from the menu's edge
   as the name from the top */
.account-legal { margin: 2px 0 7px; padding: 5px 9px 0; font: 400 var(--text-xs)/1.4 var(--font-body); color: var(--text-secondary); }
.account-legal a { color: inherit; text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 2px; text-decoration-color: color-mix(in srgb, currentColor 35%, transparent); }
.account-legal a:hover { color: var(--text-primary); text-decoration-color: currentColor; }
.account-menu [hidden], .account-menu[hidden] { display: none; }
@media (prefers-reduced-motion: reduce) { .account-trigger, .account-chevron, .account-popover, .account-logout, .account-opt, .lb-admin { transition: none; } }

/* == section head == */
/* The head of a section, as in the prototype: a button with the section's name only (13/500, secondary) and the
   chevron that folds its body (aria-expanded, aria-controls); the same as Tools in the left bar (.lb-sec). On the glass
   of a page it hovers as the Timeline rows. Above every section the same measure, --sec-above. */
.app-page { --sec-above: 14px; }
.sec { margin-top: var(--sec-above); }
.sec-title { display: flex; align-items: center; min-height: 29px; margin: 0; font: inherit; }
.lb-sec, .sec-h { display: inline-flex; align-items: center; gap: 4px; height: 29px; margin: 0; padding: 0 7px; border: 0; border-radius: 9px; background: none;
  font: 500 var(--text-sm)/1.55 var(--font-body); color: var(--text-secondary); transition: background-color .15s, box-shadow .15s, color .15s; }
.lb-sec:hover, .sec-h:hover { background: var(--bg-muted); color: var(--text-primary); }
.lb-sec > svg.i, .sec-h > svg.i { width: 13px; height: 13px; transition: transform .15s; }
.lb-sec[aria-expanded="true"] > svg.i, .sec-h[aria-expanded="true"] > svg.i { transform: rotate(90deg); }
.gs-body .sec-h:hover { background: var(--gl-hover); box-shadow: inset 0 0 0 1px var(--gl-card-edge), var(--gl-act-sh); }
.gs-body .sec-h:active { background: var(--gl-press); box-shadow: inset 0 0 0 1px var(--gl-card-edge); }
.sec-h:focus-visible { outline-offset: 0; }
@media (prefers-reduced-motion: reduce) { .lb-sec, .sec-h, .lb-sec > svg.i, .sec-h > svg.i { transition: none; } }

/* == info card == */
/* A card that says something, with no action: tinted with the accent, the glyph in its tile, a title (14/500, primary)
   and, when there is one, a sentence (13, secondary). The screens' intro and their empty states. */
.info-card { display: flex; align-items: center; gap: 11px; min-height: 43px; padding: 11px 13px; border-radius: 11px; color: var(--text-body);
  background: color-mix(in srgb, var(--accent) 7%, transparent); }
.info-card-ic { display: grid; place-items: center; flex: none; width: 16px; height: 16px; border-radius: 7px; color: var(--accent); }
.info-card-ic > svg.i { width: 16px; height: 16px; }
.info-card-body { display: flex; flex-direction: column; flex: 1 1 auto; min-width: 0; }
.info-card-title { margin: 0; font: 500 14px/18px var(--font-body); color: var(--text-primary); }
.info-card-text { margin: 0; font: 400 13px/17px var(--font-body); color: var(--text-secondary); }

/* == progress ring == */
/* How much of an activity is done: a track and an arc that runs clockwise from 12 o'clock (at 0 its round tip), the
   tool's glyph in the middle, in the accent. 36 (40 on the phone). The mini ring of a panel view's button is the same
   at 16. The arc's gradient lives in index.html (#ring-grad). */
.svg-defs { position: absolute; width: 0; height: 0; overflow: hidden; }
.ring-stop-a { stop-color: var(--ring-a); }
.ring-stop-b { stop-color: var(--ring-b); }
.ring { position: relative; display: grid; place-items: center; flex: none; width: 36px; height: 36px; color: var(--accent); }
.ring-svg { position: absolute; inset: 0; width: 100%; height: 100%; }
.ring-svg circle { fill: none; stroke-width: 3; }
.ring-trk, .mring-trk { stroke: var(--accent-ring); }
.ring-arc, .mring-arc { stroke: url(#ring-grad); stroke-linecap: round; }
.ring-arc.at-zero, .mring-arc.at-zero { stroke: var(--accent); }
.ring > svg.i { position: relative; width: 14px; height: 14px; }
.mring circle { fill: none; stroke-width: 2.5; }

/* == topic dot == */
/* A topic's marker: a ring, grey when neither the topic nor a topic below it has an activity, violet when one has;
   never filled (the fill is the place of mastery). Level 1 shows its number in a circle, grey or violet the same way. */
.topic-dot { position: relative; z-index: 1; display: inline-block; flex: none; width: 11px; height: 11px; border-radius: 50%; border: 1px solid var(--text-secondary); background: transparent; }
.topic-dot.on { border: 2px solid var(--accent); }
.topic-disc { position: relative; z-index: 1; display: grid; place-items: center; flex: none; width: 23px; height: 23px; border-radius: 50%; border: 1px solid var(--text-secondary);
  font: 500 13px/1 var(--font-body); color: var(--text-secondary); font-variant-numeric: tabular-nums; }
.topic-disc.on { border: 2px solid var(--accent-text); color: var(--accent-text); }

/* == timeline row == */
/* One activity in a list (the Guided Study home, the Topic Timeline, Your Last Activities): the tool's icon, with a
   violet dot while it is Active, the number and the title cut on one line, the short date of the last use. On the
   glass it hovers as a lighter veil with its edge and a shadow, and presses deeper. The whole line in the tooltip. */
.tl-rows { display: flex; flex-direction: column; gap: 4px; margin-top: 4px; }
.tl-row { position: relative; display: grid; grid-template-columns: 14px minmax(0, 1fr) auto 14px; align-items: center; column-gap: 7px; width: 100%; min-height: 29px; margin: 0; padding: 5px 7px;
  border: 0; border-radius: 9px; background: none; font: 400 14px/18px var(--font-body); color: var(--text-body); text-align: left; transition: background-color .15s, box-shadow .15s, color .15s; }
.tl-row:hover { color: var(--text-primary); background: var(--gl-hover); box-shadow: inset 0 0 0 1px var(--gl-card-edge), var(--gl-act-sh); }
.tl-row:active { color: var(--text-primary); background: var(--gl-press); box-shadow: inset 0 0 0 1px var(--gl-card-edge); }
.tl-row:focus-visible { outline: 2px solid var(--accent); outline-offset: 0; }
/* the row's chevron, as the prototype's list rows: it acts; shown on hover and focus, half-visible on a touch screen */
.tl-row::after { content: ""; width: 14px; height: 14px; background: currentColor; color: var(--text-secondary); opacity: 0; transition: opacity .15s;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m9 18 6-6-6-6'/%3E%3C/svg%3E") center / contain no-repeat; mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m9 18 6-6-6-6'/%3E%3C/svg%3E") center / contain no-repeat; }
.tl-row:hover::after, .tl-row:focus-visible::after { opacity: 1; }
@media (hover: none) { .tl-row::after { opacity: .6; } }
.tl-ic { position: relative; display: grid; place-items: center; width: 14px; height: 14px; color: var(--text-secondary); }
.tl-ic > svg.i { width: 14px; height: 14px; }
.tl-dot { position: absolute; right: -3px; top: -3px; width: 6px; height: 6px; border-radius: 50%; background: var(--accent); box-shadow: 0 0 0 2px var(--bg-page); }
.tl-title { position: relative; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tl-num { margin-right: 2px; color: var(--text-secondary); font-variant-numeric: tabular-nums; }
.tl-date { display: inline-flex; align-items: baseline; gap: 4px; font: 400 13px/18px var(--font-body); color: var(--text-secondary); white-space: nowrap; font-variant-numeric: tabular-nums; }
@media (prefers-reduced-motion: reduce) { .tl-row { transition: none; } }

/* == invite == */
/* Where a Guided Study starts: a raised card with the topic field (it opens the topic list: the topic's dot, number and
   title, or "Choose a topic") and the primary button, Start a new Guided Study or Continue Guided Study (the topic has
   an Active one), both 44. The same on the Guided Study home and in the Curriculum Roadmap's panel. */
.invite { display: grid; gap: 7px; padding: 11px 13px; border-radius: 11px; color: var(--text-body); background: var(--surface-raised);
  box-shadow: var(--shadow-raised-app), inset 0 0 0 1px var(--surface-raised-edge); }
.invite-field { display: flex; align-items: center; gap: 7px; width: 100%; min-height: 44px; margin: 0; padding: 7px 9px 7px 11px; border: 0; border-radius: 9px; background: transparent;
  box-shadow: inset 0 0 0 1px var(--field-edge); font: 400 14px/18px var(--font-body); color: var(--text-primary); text-align: left; transition: box-shadow .12s; }
@media (hover: hover) { .invite-field:hover:not(:disabled), .invite-field:active:not(:disabled) { box-shadow: inset 0 0 0 1px var(--hairline); } }
.invite-field:focus-visible { outline: 2px solid var(--accent); outline-offset: 0; }
.invite-field:disabled { opacity: .6; cursor: default; }
.invite-field > svg.i { flex: none; width: 18px; height: 18px; color: var(--text-secondary); }
.invite-v { display: flex; align-items: center; gap: 7px; flex: 1 1 auto; min-width: 0; }
.invite-ph { color: var(--text-secondary); }
.invite-num { flex: none; color: var(--text-secondary); font-variant-numeric: tabular-nums; }
.invite-topic { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; color: var(--text-primary); }
.invite-btn { display: flex; align-items: center; justify-content: center; gap: 7px; width: 100%; min-height: 44px; margin: 0; padding: 0 14px; border: 0; border-radius: 9px;
  background: var(--link); font: 500 14px/21px var(--font-body); color: var(--on-accent); transition: background-color .15s; }
.invite-btn:hover, .invite-btn:active { background: var(--link-hover); }
.invite-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; box-shadow: 0 0 0 2px var(--bg-primary); }
.invite-btn > svg.i { width: 16px; height: 16px; color: var(--on-accent); }
@media (prefers-reduced-motion: reduce) { .invite-field, .invite-btn { transition: none; } }

/* == guided study home == */
/* The Guided Study home, in the conversation's place (#chat > .welcome), laid as a page: the title, the intro card,
   the invite, then Continue (the Active Guided Studies as tiles) and Your Guided Study Timeline (Timeline rows). The
   lists sit 8 out, so a row's text lines up with the cards. A student with no course reads the sentence that says so. */
.welcome { flex: none; width: 100%; max-width: 648px; margin: 0 auto; padding-top: 0; } /* the conversation's 90 above, as a page */
.welcome-sub { margin: 0; font: 400 var(--text-sm)/1.6 var(--font-body); color: var(--text-secondary); }
.gs-invite .invite { margin-top: 11px; }
.gs-body { margin: 0 -8px; }
.gs-body .sec-body > .info-card { margin: 4px 7px 0; }
.gs-body > .err-note { margin: var(--sec-above) 8px 0; }
.gs-empty .info-card { margin-top: 11px; }
/* Continue: the Active Guided Studies as tiles, two or more a row; each a raised card with its ring, "x of y ideas
   explained", the chevron, the topic and the chip of the day it started */
.gs-tiles { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(180px, calc(50% - 4px)), 1fr)); gap: 7px; margin-top: 4px; padding: 0 7px; }
.gs-tile { display: flex; flex-direction: column; align-items: stretch; gap: 11px; min-width: 0; margin: 0; padding: 11px 13px; border: 0; border-radius: 11px; background: var(--surface-raised);
  box-shadow: var(--shadow-soft), inset 0 0 0 1px var(--surface-raised-edge); font: inherit; color: var(--text-secondary); text-align: left; transition: box-shadow .15s, transform .15s; }
.gs-tile:hover { box-shadow: var(--shadow-soft-lg), inset 0 0 0 1px var(--surface-raised-edge); transform: translateY(-1px); }
.gs-tile:active { transform: none; background-image: linear-gradient(var(--press), var(--press)); box-shadow: inset 0 0 0 1px var(--surface-raised-edge); }
.gs-tile:focus-visible { outline: 2px solid var(--accent); outline-offset: 0; }
.gs-tile-top { display: flex; align-items: center; gap: 9px; }
.gs-tile-p { flex: 1 1 auto; min-width: 0; font: 400 13px/17px var(--font-body); color: var(--text-secondary); }
.gs-tile-go { display: grid; align-self: flex-start; color: var(--text-secondary); }
.gs-tile-go > svg.i { width: 14px; height: 14px; }
.gs-tile:hover .gs-tile-go, .gs-tile:active .gs-tile-go { color: var(--text-primary); }
.gs-tile-title { font: 500 14px/18px var(--font-body); color: var(--text-primary); overflow-wrap: anywhere; }
.gs-tile-num { color: var(--text-secondary); font-variant-numeric: tabular-nums; }
.badge-date { display: inline-flex; align-items: center; align-self: flex-start; margin-top: auto; gap: 5px; height: 20px; padding: 0 7px; border-radius: 6px; background: var(--bg-muted);
  font: 500 12px/12px var(--font-body); color: var(--text-secondary); white-space: nowrap; }
@media (prefers-reduced-motion: reduce) { .gs-tile, .gs-tile:hover { transition: none; transform: none; } }

/* == conversation == */
/* The Guided Study screen: the conversation (the student's bubbles, the Tutor's replies in Markdown, the waits and
   the notices), the writing bar with the send button (Stop while a reply arrives) and the AI notice; the home when no
   Guided Study is open (== guided study home ==). The conversation and the bar keep generous side margins whatever the column. */
.chat { position: relative; z-index: 1; display: flex; flex-direction: column; gap: 14px; flex: 1 1 auto; min-height: 0; overflow-y: auto;
  padding: 90px clamp(14px, 6%, 65px) 36px; }
.msg { width: 100%; max-width: 648px; margin: 0 auto; animation: msg-in .4s cubic-bezier(.22, 1, .36, 1) both; }
/* The Tutor's message, as in the prototype: the Sophai symbol (25, on the accent's halo) on its left and the reply in a
   bubble of the raised surface with the soft shadow, its top left corner tight (4); on the phone at the design's
   size (== phone ==). */
.msg:has(> .msg-t) { position: relative; padding-left: 36px; }
.msg:has(> .msg-t)::before { content: ""; position: absolute; left: -14px; top: -14px; width: 53px; height: 53px; pointer-events: none;
  background: var(--tutor-symbol) center / 25px 25px no-repeat, var(--accent-halo); }
.msg > .msg-t { width: fit-content; max-width: min(100%, 504px); padding: 9px 13px; border-radius: 11px; border-top-left-radius: 4px; background: var(--surface-raised); box-shadow: var(--shadow-soft); }
/* on the dark theme the bubble has the raised surface's edge, as in the prototype */
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .msg > .msg-t { box-shadow: inset 0 0 0 1px var(--surface-raised-edge), var(--shadow-soft); } }
:root[data-theme="dark"] .msg > .msg-t { box-shadow: inset 0 0 0 1px var(--surface-raised-edge), var(--shadow-soft); }
@keyframes msg-in { from { opacity: 0; transform: translateY(7px); } to { opacity: 1; transform: none; } }
.msg-s { width: fit-content; max-width: 100%; margin-left: auto; padding: 11px 14px; border-radius: var(--r-lg); border-top-right-radius: var(--r-sm);
  background: var(--bubble-me); box-shadow: inset 0 0 0 1px var(--bubble-me-edge); color: var(--text-primary); white-space: pre-wrap; }
.msg-t { padding: 4px 0; color: var(--text-body); line-height: 1.55; } /* the prototype's bubble */
.msg-t > :first-child { margin-top: 0; }
.msg-t > :last-child { margin-bottom: 0; }
.msg-t p { margin: 0 0 11px; }
.msg-t strong { font-weight: 500; color: var(--text-primary); }
.msg-t em { font-style: italic; }
.msg-t del { color: var(--text-secondary); }
.msg-t a { color: var(--link); text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 2px; transition: color .1s; }
.msg-t a:hover { color: var(--link-hover); }
.msg-t h1, .msg-t h2, .msg-t h3 { margin: 18px 0 7px; font-family: var(--font-serif); font-weight: 500; line-height: 1.3; color: var(--text-primary); }
.msg-t h1 { font-size: 18px; }
.msg-t h2 { font-size: 16px; }
.msg-t h3 { font-size: 14px; }
.msg-t ul, .msg-t ol { margin: 0 0 11px; padding-left: 20px; }
.msg-t li { margin-bottom: 5px; }
.msg-t li::marker { color: var(--text-secondary); }
.msg-t li > ul, .msg-t li > ol { margin: 5px 0 4px; }
.msg-t blockquote { margin: 0 0 11px; padding: 2px 0 2px 13px; border-left: 2px solid var(--accent-soft); font-family: var(--font-serif); font-style: italic; color: var(--text-secondary); }
.msg-t code { padding: 1.5px 5px; border-radius: 4px; background: var(--bg-muted); font-family: var(--font-mono); font-size: .85em; }
.msg-t pre { overflow-x: auto; margin: 0 0 11px; padding: 11px 14px; border-radius: 5px; background: var(--bg-muted); box-shadow: inset 0 0 0 1px var(--hairline); line-height: 1.55; }
.msg-t pre code { padding: 0; background: none; font-size: 13px; }
.msg-t hr { margin: 14px 0; border: 0; border-top: 1px solid var(--hairline); }
/* the typing cursor while the reply arrives */
.msg-t .caret { display: inline-block; width: 5px; height: 1.05em; margin-left: 2px; vertical-align: -2px; border-radius: 1px; background: var(--accent); opacity: .65; animation: caret-blink 1s steps(1) infinite; }
@keyframes caret-blink { 50% { opacity: 0; } }
.msg-err { margin: 7px 0 0; font-size: var(--text-sm); color: var(--err-text); }
.msg-note { margin-top: 5px; font-size: var(--text-xs); color: var(--text-secondary); }
/* the citation chip [n]: 16 (18 on the phone), 12/600 in the violet for text on a tint; the mouse over it (or its
   focus) opens the citation card (cite-card.js), a tap too */
.cite { display: inline-flex; align-items: center; justify-content: center; min-width: 16px; height: 16px; margin: 0 1px 0 3px; padding: 0 5px; border-radius: 5px;
  background: var(--cite-bg); color: var(--accent-text); font: 600 12px/12px var(--font-body); font-variant-numeric: tabular-nums; vertical-align: 2px; /* 2 above the line, as in the prototype */
  text-decoration: none; cursor: pointer; transition: background-color .1s, color .1s; }
.msg-t a.cite { color: var(--accent-text); text-decoration: none; }
.cite:hover, .cite.hl, .msg-t a.cite:hover, .msg-t a.cite.hl { background: var(--link); color: var(--on-accent); }
.cite:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
/* a closed (copyright-protected) source: the same chip, muted, not a link */
.cite.locked, .cite.locked:hover, .cite.locked.hl { background: var(--cite-locked-bg); color: var(--text-secondary); cursor: default; }
/* the citation card: a layer outside the conversation, beside #tip, over the chip (or under it near the top): the
   material's name and page (13/20 500, the book in the link colour), then the cited excerpt (14/21); radius 11 */
.cite-card { position: fixed; left: 0; top: 0; z-index: 990; box-sizing: border-box; width: min(270px, calc(100vw - 16px)); padding: 11px 13px; border-radius: 11px;
  background: var(--bg-primary); box-shadow: var(--shadow-soft-lg), 0 0 0 1px var(--hairline); font: 400 14px/21px var(--font-body); color: var(--text-body);
  overflow-wrap: anywhere; pointer-events: none; }
.cite-card-src { display: flex; align-items: center; gap: 7px; margin-bottom: 5px; font: 500 13px/20px var(--font-body); color: var(--text-primary); }
.cite-card-src > svg.i { flex: none; width: 14px; height: 14px; color: var(--link); }
.cite-card q { color: var(--text-body); }
/* the notices of the conversation (notices.js): an info notice is a plain line; a problem is the error callout, in the
   column of the Tutor's bubbles: the disc of 28 with the glyph, the first sentence at 500 in the error colour, the rest
   14/20, on the error tint over the solid surface, radius 14 */
.app-notice { display: flex; align-items: center; gap: 5px; flex-shrink: 0; width: 100%; max-width: 630px; margin: 0 auto; padding: 5px 14px; font-size: var(--text-sm); color: var(--text-secondary); }
.app-notice.problem { display: grid; grid-template-columns: 28px minmax(0, 1fr); gap: 10px; width: min(80%, 504px); max-width: 504px; margin: 0 auto 0 calc(max(0px, (100% - 648px) / 2) + 36px); padding: 10px;
  border-radius: 14px; background: linear-gradient(var(--err-bg), var(--err-bg)), var(--bg-primary); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--err-text) 22%, transparent);
  font: 400 14px/20px var(--font-body); color: var(--text-body); }
.app-notice.problem > svg.i { box-sizing: border-box; width: 28px; height: 28px; padding: 6px; border-radius: 50%; stroke-width: 2.5; background: var(--err-bg); color: var(--err-text); }
.app-notice.problem > span { min-width: 0; overflow-wrap: anywhere; }
.app-notice.problem b { font-weight: 500; color: var(--err-text); }
/* the wait of a reply, in the place of the Tutor's bubble: the Tutor's symbol with its dot pulsing, then the stage the
   server reports (Reading your course materials, Thinking, Writing the answer; crossfading 150 ms) and three dots */
.loading { display: flex; align-items: center; gap: 11px; flex-shrink: 0; width: 100%; max-width: 648px; margin: 0 auto; font: 400 14px/21px var(--font-body); color: var(--text-body); }
.loading-sym { position: relative; flex: none; width: 25px; height: 25px; background: var(--tutor-symbol) center / contain no-repeat; }
/* the pulse: the dot grows and a ring spreads from it and fades, both by transform and opacity only (no repaint) */
.loading-sym::before, .loading-sym::after { content: ""; position: absolute; border-radius: 50%; }
.loading-sym::after { left: 15px; top: 10px; width: 5px; height: 5px; background: var(--accent); animation: sym-pulse 1.1s ease-in-out infinite; }
.loading-sym::before { left: 9px; top: 4px; width: 17px; height: 17px; background: var(--accent-ring); opacity: 0; animation: sym-ring 1.1s ease-in-out infinite; }
@keyframes sym-pulse { 50% { transform: scale(1.35); } }
@keyframes sym-ring { 0%, 100% { opacity: 1; transform: scale(.3); } 50% { opacity: 0; transform: scale(1); } }
.loading-wait { display: inline-flex; align-items: baseline; gap: 2px; font: 400 13px/20px var(--font-body); }
.loading-label { transition: opacity .15s ease-out; }
.loading-label.out { opacity: 0; }
.loading-dots { display: inline-flex; gap: 1px; }
.dot { width: 4px; height: 4px; border-radius: 50%; background: currentColor; opacity: .25; animation: think-dot 1.2s infinite; }
.dot:nth-child(2) { animation-delay: .4s; }
.dot:nth-child(3) { animation-delay: .8s; }
@keyframes think-dot { 0%, 100% { opacity: .25; } 20%, 45% { opacity: 1; } }
/* the day separator: only when the day changes between two messages (Today, Yesterday, 3 Oct), 13/17 in the
   secondary colour, centred in the column; the conversation's gap above and below it */
.day-sep { flex: none; width: 100%; max-width: 648px; margin: 7px auto; font: 400 13px/17px var(--font-body); color: var(--text-secondary); text-align: center; font-variant-numeric: tabular-nums; }
/* Jump to latest: a raised pill, 11 above the writing bar, centred, over the bottom of the conversation, while the
   reader is above its end (chat.js); 13/20 500 with the arrow (13), a hairline edge; it comes in with a fade and 7 up */
.jump-dock { position: relative; z-index: 3; flex: none; height: 0; }
.jump { position: absolute; left: 50%; bottom: 2px; transform: translateX(-50%); display: inline-flex; align-items: center; gap: 5px; height: 29px; margin: 0; padding: 0 11px; border: 0; border-radius: 999px;
  background: var(--surface-raised); box-shadow: var(--shadow-soft), 0 0 0 1px var(--hairline); font: 500 13px/20px var(--font-body); color: var(--text-primary); white-space: nowrap;
  animation: jump-in .15s ease-out; }
.jump > svg.i { width: 13px; height: 13px; }
.jump:hover { background: var(--bg-hover); }
.jump:active { background: linear-gradient(var(--press), var(--press)), var(--bg-primary); }
.jump:focus-visible { outline: 2px solid var(--accent); outline-offset: 0; }
.jump::after { content: ""; position: absolute; left: 50%; top: 50%; width: max(100%, 44px); height: 44px; transform: translate(-50%, -50%); }
@keyframes jump-in { from { opacity: 0; translate: 0 7px; } }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .jump { box-shadow: var(--shadow-soft), inset 0 0 0 1px var(--surface-raised-edge); }
  :root:not([data-theme="light"]) .jump:hover { background: linear-gradient(var(--press), var(--press)), var(--surface-raised); }
  :root:not([data-theme="light"]) .jump:active { background: linear-gradient(var(--press), var(--press)), linear-gradient(var(--press), var(--press)), var(--surface-raised); }
}
:root[data-theme="dark"] .jump { box-shadow: var(--shadow-soft), inset 0 0 0 1px var(--surface-raised-edge); }
:root[data-theme="dark"] .jump:hover { background: linear-gradient(var(--press), var(--press)), var(--surface-raised); }
:root[data-theme="dark"] .jump:active { background: linear-gradient(var(--press), var(--press)), linear-gradient(var(--press), var(--press)), var(--surface-raised); }
/* offline in the conversation: over the writing bar, in the bar's column, the accent's tint with its edge, the disc
   of 28 with the wifi-off glyph, "You're offline." at 500 in the primary colour, the rest 14/20 */
.chat-offline { position: relative; z-index: 2; display: grid; grid-template-columns: 28px minmax(0, 1fr); align-items: center; gap: 10px; flex: none;
  width: calc(100% - 2 * clamp(14px, 6%, 65px)); max-width: 648px; margin: 9px auto 0; padding: 10px; border-radius: 14px; background: var(--net-bg);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 22%, transparent); font: 400 14px/20px var(--font-body); color: var(--text-body); }
.chat-offline > svg.i { box-sizing: border-box; width: 28px; height: 28px; padding: 6px; border-radius: 50%; background: color-mix(in srgb, var(--accent) 14%, transparent); color: var(--link-hover); }
.chat-offline b { font-weight: 500; color: var(--text-primary); }
/* the writing bar: a glass field with a faint ring and a point of light circling it, the send button inside */
.input-area { position: relative; z-index: 2; flex-shrink: 0; padding: 9px clamp(14px, 6%, 65px) 0; }
@property --spin { syntax: '<angle>'; initial-value: 0deg; inherits: false; }
.input-wrap { position: relative; max-width: 648px; margin: 0 auto; border-radius: var(--r-lg); }
.input-wrap::before { content: ""; position: absolute; inset: -1.5px; padding: 1.5px; border-radius: calc(var(--r-lg) + 1.5px); pointer-events: none; opacity: .4; transition: opacity .2s;
  background: linear-gradient(135deg, color-mix(in srgb, var(--accent) 35%, transparent), color-mix(in srgb, var(--link) 20%, transparent) 50%, color-mix(in srgb, var(--accent) 35%, transparent));
  -webkit-mask: linear-gradient(var(--mask) 0 0) content-box, linear-gradient(var(--mask) 0 0); -webkit-mask-composite: xor; mask-composite: exclude; }
.input-wrap:focus-within::before { opacity: .6; }
.input-wrap::after { content: ""; position: absolute; inset: -1.5px; padding: 1.5px; border-radius: calc(var(--r-lg) + 1.5px); pointer-events: none; opacity: .8; animation: spin-border 15s linear infinite;
  background: conic-gradient(from var(--spin), color-mix(in srgb, var(--accent) 16%, transparent) 0deg, color-mix(in srgb, var(--accent) 30%, transparent) 120deg,
    color-mix(in srgb, var(--accent) 46%, transparent) 210deg, color-mix(in srgb, var(--accent) 66%, transparent) 285deg, color-mix(in srgb, var(--accent) 85%, transparent) 320deg,
    var(--accent) 338deg, color-mix(in srgb, var(--accent) 55%, transparent) 350deg, color-mix(in srgb, var(--accent) 18%, transparent) 360deg);
  -webkit-mask: linear-gradient(var(--mask) 0 0) content-box, linear-gradient(var(--mask) 0 0); -webkit-mask-composite: xor; mask-composite: exclude; }
.input-wrap:focus-within::after { opacity: 1; animation-duration: 10s; }
@keyframes spin-border { to { --spin: 360deg; } }
.input { position: relative; display: block; width: 100%; max-height: 151px; overflow-y: auto; resize: none; padding: 14px 49px 14px 14px; border: 0; border-radius: var(--r-lg); outline: none;
  background: color-mix(in srgb, var(--bg-primary) 82%, transparent); -webkit-backdrop-filter: blur(11px) saturate(1.3); backdrop-filter: blur(11px) saturate(1.3);
  font: 400 var(--text-base)/1.5 var(--font-body); color: var(--text-primary);
  box-shadow: var(--shadow-raised), 0 7px 27px color-mix(in srgb, var(--accent) 22%, transparent), 0 2px 9px color-mix(in srgb, var(--accent) 12%, transparent); transition: box-shadow .18s; }
.input::placeholder { color: var(--text-secondary); }
.input-wrap:focus-within .input { box-shadow: var(--shadow-raised), 0 11px 40px color-mix(in srgb, var(--accent) 34%, transparent), 0 2px 11px color-mix(in srgb, var(--accent) 16%, transparent); }
.input:disabled { opacity: .7; cursor: not-allowed; }
/* send, as in the prototype: a violet circle of 32 with the arrow up, faded (aria-disabled, chat.js) while the box is
   empty; Stop, while a reply is prepared, is the same circle with a filled square, never faded. Centred on the box. */
.btn-send { position: absolute; right: 8px; bottom: 9px; z-index: 2; display: grid; place-items: center; width: 32px; height: 32px; padding: 0; border: 0; border-radius: 50%;
  background: var(--link); color: var(--on-accent); box-shadow: var(--accent-glow-app); font-size: 14px; line-height: 21px; transition: transform .1s, background-color .15s, opacity .15s; }
.btn-send svg.i { position: relative; width: 16px; height: 16px; stroke-width: 1.5; }
.btn-send .stop-ic, .btn-send.stop .send-ic { display: none; }
.btn-send.stop .stop-ic { display: block; width: 14px; height: 14px; }
.i-solid { fill: currentColor; stroke: none; }
.input-wrap.multiline .btn-send { top: auto; bottom: 9px; margin: 0; }
.btn-send:hover:not([aria-disabled="true"]):not(:disabled) { background: var(--link-hover); }
.btn-send:active:not([aria-disabled="true"]):not(:disabled) { transform: translateY(1px); }
.btn-send:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; box-shadow: 0 0 0 2px var(--bg-primary), var(--accent-glow-app); }
.btn-send[aria-disabled="true"], .btn-send:disabled { opacity: .5; cursor: default; }
@media (prefers-reduced-motion: reduce) { .btn-send, .btn-send::before { transition: none; } }
/* AI notice: the one line every tool with generated content shows while a Guided Study is on the screen, open or ended,
   right under the writing bar, or under the end card once it has ended (docs/ARCHITECTURE.md). 12 px, a
   legal-note exception to the 13 px floor (docs/UI.md). Hidden on the home, the only screen with no Guided Study
   (gs-home.js mounts .welcome in #chat); no JS of its own. */
.ai-notice { position: relative; z-index: 2; flex-shrink: 0; margin: 0; padding: 7px clamp(14px, 6%, 65px) 18px; font-size: 12px; line-height: 1.4; color: var(--text-secondary); text-align: center; }
.screen:has(.welcome) .ai-notice { display: none; }
/* the end card, in the place of the writing bar once the Guided Study has ended (end.js): an info card on the
   accent's tint over the solid surface, the info glyph in its tile, "This Guided Study has ended." (14/18 500) and the
   sentence with the circle-play glyph inline (13/17); the AI notice stays under it */
.ended-area { position: relative; z-index: 2; flex-shrink: 0; padding: 9px clamp(14px, 6%, 65px) 0; }
.ended-card { display: flex; align-items: center; gap: 11px; max-width: 648px; margin: 0 auto; padding: 11px 13px; border-radius: 11px; color: var(--text-body);
  background: var(--ended-bg); box-shadow: inset 0 0 0 1px var(--ended-edge); }
.ended-card-ic { display: grid; place-items: center; flex: none; width: 16px; height: 16px; border-radius: 7px; color: var(--accent); }
.ended-card-ic > svg.i { width: 16px; height: 16px; }
.ended-card-body { display: flex; flex-direction: column; flex: 1 1 auto; min-width: 0; }
.ended-card-title { margin: 0; font: 500 14px/18px var(--font-body); color: var(--text-primary); }
.ended-card-text { margin: 0; font: 400 13px/17px var(--font-body); color: var(--text-body); }
.ic-inline { display: inline-flex; vertical-align: -2px; color: var(--accent); }
.ic-inline > svg.i { width: 13px; height: 13px; }
/* End Guided Study and Start a new Guided Study belong to the Guided Study screen only */
.app:not(.on-gs) :is(.pb-cmd, .isl-cmd, .isl-sw) { display: none; }
@media (prefers-reduced-motion: reduce) { .input-wrap::after, .msg, .msg-t .caret, .loading-sym::before, .loading-sym::after, .jump { animation: none; } .dot { animation: none; opacity: 1; } .loading-label { transition: none; } }

/* == curriculum roadmap == */
/* The Curriculum Roadmap (roadmap.js), as in the prototype: the intro card, then the course's topics as a tree, 18 under
   it. Every topic is a row of 44, a button that chooses it: level 1 with its number in a circle (23) and its title where
   the number column ends; every deeper level 22 further in, with the topic dot (11) on the circle's axis, the number (a
   column of 27) and the title; a topic with subtopics, and the chosen one, at 500 in the primary colour. A guide line
   (2, --border-strong) runs from mark to mark, 8 short of each, above the hover and the chosen tint. On the glass a row
   hovers as a lighter veil with its edge and a soft shadow and presses deeper; the chosen one is tinted; the chevron
   that says a row opens shows on hover, on focus and on the chosen one. A level-1 topic with subtopics folds them with
   its chevron, in the gutter left of the circle (25; a target of 44 with touch).
   THE DOT IS THE MASTERY SLOT: --rm-mastery (0 to 1, declared on the row, so style="--rm-mastery:.6" reaches it) fills
   it clockwise; it stays 0 until that data exists. The dot keeps an opaque disc of its own, so a value the fill cannot
   use leaves the plain ring. */
.rm-list { margin-top: 18px; padding: 0 0 14px; }
/* a course with no topics: the empty state's card, 11 under the intro card, as on the Guided Study home */
.rm-list:has(> .rm-empty) { margin-top: 11px; }
.rm-sec { position: relative; }
.rm-kids { position: relative; padding-left: 22px; }
.rm-item { --rm-mastery: 0; position: relative; display: flex; align-items: center; gap: 11px; width: 100%; min-height: 44px; margin: 0; padding: 5px 9px; border: 0; border-radius: 7px;
  background: none; font: 400 14px/18px var(--font-body); color: var(--text-body); text-align: left; transition: background-color .15s, box-shadow .15s, color .15s; }
.rm-item:hover { color: var(--text-primary); background: var(--gl-hover); box-shadow: inset 0 0 0 1px var(--gl-card-edge), var(--gl-act-sh); }
.rm-item:active { color: var(--text-primary); background: var(--gl-press); box-shadow: inset 0 0 0 1px var(--gl-card-edge); }
.rm-item:focus-visible { outline: 2px solid var(--accent); outline-offset: 0; }
.rm-item[aria-current="true"], .rm-item[aria-current="true"]:hover { color: var(--text-primary); background: var(--accent-soft); }
.rm-par .rm-topic, .rm-item[aria-current="true"] .rm-topic { font-weight: 500; color: var(--text-primary); }
.rm-num:not(.rm-disc) { flex: none; min-width: 27px; color: var(--text-secondary); font-variant-numeric: tabular-nums; }
.rm-topic { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
.rm-dot { margin: 0 3px; background-color: var(--bg-primary); background-image: conic-gradient(var(--accent) calc(clamp(0, var(--rm-mastery), 1) * 360deg), var(--bg-primary) 0); }
.rm-d1 > .rm-disc { margin-left: 19px; }
.rm-d1 > .rm-topic { margin-left: 14px; }
.rm-item > .rm-go { flex: none; width: 16px; height: 16px; color: var(--text-secondary); opacity: 0; transition: opacity .15s; }
.rm-item:hover .rm-go, .rm-item:focus-visible .rm-go, .rm-item[aria-current="true"] .rm-go { opacity: 1; }
@media (hover: none) { .rm-item > .rm-go { opacity: .6; } }
/* the guide line: above and below each row of a level (not above its first nor below its last), down the side of a
   topic's subtopics while its siblings follow, and down from a level-1 circle while its subtopics show */
.rm-kids > .rm-item::before, .rm-kids > .rm-item::after, .rm-kids > .rm-kids:not(:last-child)::before, .rm-item.rm-open::after {
  content: ""; position: absolute; z-index: 2; left: 17px; width: 2px; border-radius: 1px; background: var(--border-strong); pointer-events: none; }
.rm-kids > .rm-item::before { top: 0; height: calc(50% - 8px); }
.rm-kids > .rm-item::after { bottom: 0; height: calc(50% - 8px); }
.rm-kids > .rm-kids:not(:last-child)::before { top: 0; bottom: 0; }
.rm-item.rm-open::after { left: 39px; bottom: 0; height: calc(50% - 14px); }
.rm-kids > .rm-item:first-child::before, .rm-kids > .rm-item:last-child::after, .rm-kids > .rm-item:nth-last-child(2):has(+ .rm-kids)::after { display: none; }
.rm-list > .rm-kids > .rm-item:first-child::before { display: block; }
/* the fold of a level-1 topic: the chevron of Tools in the left bar (a quarter turn when open) */
.rm-tog { position: absolute; left: 1px; top: 50%; z-index: 3; display: grid; place-items: center; width: 25px; height: 25px; margin: -13px 0 0; padding: 0; border: 0; border-radius: 7px;
  background: none; color: var(--text-secondary); transition: background-color .15s, box-shadow .15s, color .15s; }
.rm-tog:hover { color: var(--text-primary); background: var(--gl-hover); box-shadow: inset 0 0 0 1px var(--gl-card-edge); }
.rm-tog:active { color: var(--text-primary); background: var(--gl-press); box-shadow: inset 0 0 0 1px var(--gl-card-edge); }
.rm-tog:focus-visible { outline: 2px solid var(--accent); outline-offset: 0; }
.rm-tog > svg.i { width: 13px; height: 13px; transition: transform .15s; }
.rm-tog[aria-expanded="true"] > svg.i { transform: rotate(90deg); }
@media (pointer: coarse) { .rm-tog::after { content: ""; position: absolute; left: 50%; top: 50%; width: 44px; height: 44px; transform: translate(-50%, -50%); } }
@media (prefers-reduced-motion: reduce) { .rm-item, .rm-go, .rm-tog, .rm-tog > svg.i { transition: none; } }

/* == overall progress == */
/* The Curriculum Roadmap's panel view Overall Progress (roadmap-panel.js), as in the prototype: four cards stacked at
   the panel's width, then the invite. Each card has the info card's tint. Topics Explored and Active Topics: the ring
   (Active Topics: its track, the tree's glyph and the violet dot of an Active activity), the number (the value of
   == panel stats ==, .stat-v: 22/500, a total after it at 13) and the name, then the sentence. Top 3 Explored and Top 3 Progressed: the head (the glyph, the title,
   the info button whose tooltip says what the card counts, a tap on touch), then up to three topics: number, title
   (it wraps), the count, and under them a thin bar to the largest count. The views Overall Progress and Topic Timeline
   have the prototype's body padding. */
.panel-view:is([data-panel-view="overall"], [data-panel-view="timeline"]) { padding: 10px 14px 14px; }
.overall { display: grid; grid-template-columns: minmax(0, 1fr); gap: 7px; }
.overall + .invite, .panel-view > .err-note + .invite { margin-top: 11px; }
.ov-card { display: flex; flex-direction: column; align-items: stretch; gap: 9px; min-width: 0; padding: 11px 13px; border-radius: 11px; color: var(--text-body);
  background: color-mix(in srgb, var(--accent) 7%, transparent); }
.ov-top { display: flex; align-items: center; gap: 11px; }
.ov-tx { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.ov-k { font: 500 13px/17px var(--font-body); color: var(--text-body); }
.ov-cap { font: 400 13px/17px var(--font-body); letter-spacing: -.01em; color: var(--text-secondary); } /* on one line as in the prototype: the app's DM Sans file sets this sentence 12 px wider than the prototype's */
.ov-ring .tl-ic { color: var(--accent); }
.ov-ring .tl-dot { box-shadow: 0 0 0 3px var(--bg-primary); }
.ov-card.top3 { gap: 7px; }
.top3-h { display: flex; align-items: center; justify-content: space-between; gap: 7px; }
.top3-t { display: inline-flex; align-items: center; gap: 5px; font: 500 13px/17px var(--font-body); color: var(--text-body); }
.top3-t > svg.i { flex: none; width: 12px; height: 12px; color: var(--accent); }
.top3-info { position: relative; display: grid; place-items: center; flex: none; width: 25px; height: 25px; margin: -5px -7px -5px 0; padding: 0; border: 0; border-radius: 7px;
  background: none; color: var(--text-secondary); transition: background-color .15s, box-shadow .15s, color .15s; }
.top3-info > svg.i { width: 14px; height: 14px; }
.top3-info:hover, .top3-info:active, .top3-info[aria-expanded="true"] { color: var(--text-primary); background: var(--gl-hover); box-shadow: inset 0 0 0 1px var(--gl-card-edge); }
.top3-info:focus-visible { outline: 2px solid var(--accent); outline-offset: 0; }
@media (pointer: coarse) { .top3-info::after { content: ""; position: absolute; left: 50%; top: 50%; width: 44px; height: 44px; transform: translate(-50%, -50%); } }
.top3-l { display: flex; flex-direction: column; gap: 9px; margin: 0; padding: 0; list-style: none; }
.top3-l li { display: grid; grid-template-columns: 27px minmax(0, 1fr) auto; grid-template-areas: "n t c" ". b b"; column-gap: 11px; row-gap: 5px; align-items: baseline;
  font: 400 14px/18px var(--font-body); color: var(--text-body); }
.top3-num { grid-area: n; color: var(--text-secondary); font-variant-numeric: tabular-nums; }
.top3-title { grid-area: t; min-width: 0; overflow-wrap: anywhere; }
.top3-count { grid-area: c; font-weight: 500; color: var(--text-primary); font-variant-numeric: tabular-nums; }
.top3-bar { grid-area: b; display: block; height: 4px; margin-right: 14px; border-radius: 2px; background: var(--accent-soft); overflow: hidden; }
.top3-bar > i { display: block; height: 100%; border-radius: 2px; background: var(--accent-ring); }
.top3-empty { font: 400 14px/21px var(--font-body); color: var(--text-body); }
@media (prefers-reduced-motion: reduce) { .top3-info { transition: none; } }

/* == topic timeline == */
/* The Curriculum Roadmap's panel view Topic Timeline (roadmap-panel.js): the topic chosen in its invite, 7 under the
   view's top, then the section Activities in this topic (its Timeline rows 4 apart, or its empty state). Without a
   topic chosen, only the card that says so. */
[data-panel-view="timeline"] > .invite { margin-top: 7px; }
[data-panel-view="timeline"] .tl-rows { gap: 4px; }
[data-panel-view="timeline"] .tl-row { padding: 0 7px; }
[data-panel-view="timeline"] .tl-row:hover { box-shadow: inset 0 0 0 1px var(--gl-card-edge); }
[data-panel-view="timeline"] .tl-dot { box-shadow: 0 0 0 2px var(--bg-primary); }
.tl-acts .sec-body > .info-card { margin-top: 4px; }

/* == last activities == */
/* Your Last Activities, in the left bar under Tools (last-activities.js), as in the prototype: the section head (the
   same as Tools), then the student's activities as Timeline rows, 4 apart, in a list that takes the bar's height left
   and scrolls, fading out over its last 29. In the bar the rows keep the bar's look: 29 high, a quiet fill on hover and
   press, the row of the activity on screen raised (the chosen tool's look) with its icon in the accent and its title
   at 500. "No activities yet." with none. The collapsed bar hides the section. */
.lb-acts { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; margin-top: var(--sec-above); }
.lb-acts > .lb-sec { flex: none; }
.lb-acts-list { display: flex; flex-direction: column; gap: 4px; flex: 1 1 auto; min-height: 0; overflow-y: auto; scrollbar-width: thin; margin: 4px -14px 0; padding: 0 14px 22px;
  -webkit-mask-image: linear-gradient(to bottom, var(--mask) calc(100% - 29px), transparent); mask-image: linear-gradient(to bottom, var(--mask) calc(100% - 29px), transparent); }
.lb-acts-list > * { flex: none; }
.lb-acts .tl-row { min-height: 29px; padding: 0 7px; }
.lb-acts .tl-row:hover, .lb-acts .tl-row:active { color: var(--text-primary); background: var(--bg-muted); box-shadow: none; }
.lb-acts .tl-row:focus-visible { outline-offset: -2px; }
.lb-acts .tl-row[aria-current="true"] { color: var(--text-primary); background: var(--bg-primary); box-shadow: var(--shadow-raised-app), inset 0 0 0 1px var(--edge-raised); }
.lb-acts .tl-row[aria-current="true"] .tl-title { font-weight: 500; }
.lb-acts .tl-row[aria-current="true"] .tl-ic { color: var(--accent); }
.lb-acts .tl-dot { box-shadow: 0 0 0 2px var(--bg-subtle); }
.lb-acts-empty { margin: 13px 0 0; padding: 4px 11px; font: 400 var(--text-sm)/1.4 var(--font-body); color: var(--text-secondary); }
@media (min-width: 640px) { .app.lb-collapsed .lb-acts { display: none; } }

/* == all courses == */
/* All courses (course.js), as in the prototype: the option at the top of My courses (at its bottom on the phone), with
   the grid glyph and a rule after it; the screen, titled as a page, with a card per course 18 under the title, two or
   more a row: the Action card on solid (a raised surface, the soft shadow and its edge, 64 high), the book's tile in
   relief, the name 14/500, Current course under the active one's name (its edge and tile in the accent), the chevron.
   A card hovers 1 px up with a higher shadow and presses deeper. All courses has no panel and no icon bar. */
.course-sep { height: 1px; margin: 5px 0; background: var(--hairline); }
.app.on-courses { --rc-w: 0px; }
.app.on-courses :is(.panel-bar, .panel, #panel-btn) { display: none; }
.course-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(216px, 1fr)); gap: 7px; margin-top: 18px; }
.course-card { display: flex; align-items: center; gap: 11px; min-width: 0; min-height: 64px; margin: 0; padding: 11px 13px; border: 0; border-radius: 11px; background: var(--surface-raised);
  box-shadow: var(--shadow-soft), inset 0 0 0 1px var(--surface-raised-edge); font: inherit; color: var(--text-secondary); text-align: left; transition: box-shadow .15s, transform .15s; }
.course-card:hover { box-shadow: var(--shadow-soft-lg), inset 0 0 0 1px var(--surface-raised-edge); transform: translateY(-1px); }
.course-card:active { transform: none; background-image: linear-gradient(var(--press), var(--press)); box-shadow: inset 0 0 0 1px var(--surface-raised-edge); }
.course-card[aria-current="true"] { box-shadow: var(--shadow-soft), inset 0 0 0 1px var(--accent-ring); }
.course-card[aria-current="true"]:hover { box-shadow: var(--shadow-soft-lg), inset 0 0 0 1px var(--accent-ring); }
.course-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 0; }
.course-card-ic { display: grid; place-items: center; flex: none; width: 29px; height: 29px; border-radius: 7px; color: var(--text-secondary);
  background: linear-gradient(to bottom, var(--ic-top), var(--bg-muted)); box-shadow: inset 0 1px 0 var(--ic-sheen), var(--ic-shadow), 0 0 0 1px var(--edge-raised); }
.course-card[aria-current="true"] .course-card-ic { color: var(--accent); box-shadow: inset 0 1px 0 var(--ic-sheen), var(--ic-shadow-up), 0 0 0 1px var(--edge-raised); }
.course-card-ic > svg.i { width: 16px; height: 16px; }
.course-card-text { display: flex; flex-direction: column; flex: 1 1 auto; min-width: 0; }
.course-card-name { font: 500 14px/18px var(--font-body); color: var(--text-primary); overflow-wrap: anywhere; }
.course-card-sub { font: 400 13px/17px var(--font-body); color: var(--text-secondary); }
.course-card > .course-card-go { flex: none; width: 14px; height: 14px; color: var(--text-secondary); }
.course-card:hover .course-card-go, .course-card:active .course-card-go { color: var(--text-primary); }
@media (prefers-reduced-motion: reduce) { .course-card, .course-card:hover { transition: none; transform: none; } }

/* == bibliography == */
/* The Bibliography view of the panel (bibliography.js): the cards Documents and Cited (== panel stats ==), then the
   group Cited and the group Also consulted under their section heads, a card per document, a row per excerpt the Tutor
   cited, with the same [n] as the conversation, the page and the snippet. */
.r-list { display: flex; flex-direction: column; gap: 7px; }
.r-list > .sec { margin-top: calc(var(--sec-above) - 7px); }
.bib-docs { display: flex; flex-direction: column; gap: 7px; margin-top: 4px; }
/* a document, as in the prototype's source card: the glass veil with its edge and a soft shadow, radius 11; its head (the
   file icon, the title 14/500 and the file 13, both cut on one line, the ↗ when it opens: the whole head is its link);
   inside, after a hairline from the title's column, one row per cited excerpt: the chip [n] and the page on one line
   (13), the excerpt in italics (13/1.45, two lines); an open document's row opens its page (↗ on hover). A closed
   document shows the citation, never the file. */
.doc { border-radius: 11px; font-size: 14px; line-height: 21px; background: var(--gl-card); box-shadow: inset 0 0 0 1px var(--gl-card-edge), var(--gl-act-sh); transition: background-color .15s, box-shadow .15s, transform .15s; }
.doc.open:hover { background: var(--gl-hover); box-shadow: inset 0 0 0 1px var(--gl-card-edge), var(--gl-act-sh-hi); transform: translateY(-1px); }
.doc-head { position: relative; display: grid; grid-template-columns: 15px minmax(0, 1fr) 15px; align-items: center; column-gap: 7px; min-height: 43px; padding: 7px; border-radius: 11px; color: var(--text-body); }
.doc:not(.cited) .doc-head { min-height: 40px; padding-top: 5px; padding-bottom: 5px; }
.doc-ico { display: grid; place-items: center; width: 14px; height: 14px; color: var(--text-secondary); }
.doc-ico > svg { width: 14px; height: 14px; }
.doc-main { min-width: 0; }
.doc-title { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font: 500 14px/18px var(--font-body); color: var(--text-body); text-decoration: none; }
.doc-title.o { cursor: pointer; }
.doc-title.o::after { content: ""; position: absolute; inset: 0; border-radius: inherit; }
.doc-head:has(> .doc-main > .doc-title.o:focus-visible) { outline: 2px solid var(--accent); outline-offset: -2px; }
.doc-title.o:focus-visible { outline: none; }
.doc-title.locked { display: flex; align-items: center; gap: 4px; cursor: default; }
.doc-title.locked svg { flex-shrink: 0; opacity: .7; }
.doc-sub { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font: 400 13px/17px var(--font-body); color: var(--text-secondary); }
.doc-head > svg.doc-go { width: 14px; height: 14px; color: var(--text-secondary); }
.doc-head:hover .doc-title, .doc-head:hover .doc-go { color: var(--text-primary); }
.exc-list { display: flex; flex-direction: column; gap: 2px; padding: 0 4px 4px; }
.exc-list::before { content: ""; display: block; height: 1px; margin: 0 4px 4px 25px; background: var(--hairline); }
.exc { position: relative; display: grid; grid-template-columns: 14px minmax(0, 1fr) 14px; align-items: start; column-gap: 7px; padding: 5px 4px; border-radius: 7px; color: var(--text-body);
  text-decoration: none; transition: background-color .15s, box-shadow .15s; }
/* the first column stays empty (under the document's icon), the ↗ in the last */
.exc::before { content: ""; }
.exc-main { grid-column: 2; }
a.exc::after { content: ""; grid-column: 3; width: 14px; height: 14px; margin-top: 1px; background: currentColor; color: var(--text-secondary); opacity: 0; transition: opacity .15s;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M7 7h10v10'/%3E%3Cpath d='M7 17 17 7'/%3E%3C/svg%3E") center / contain no-repeat;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M7 7h10v10'/%3E%3Cpath d='M7 17 17 7'/%3E%3C/svg%3E") center / contain no-repeat; }
a.exc:hover, .exc.hl { background: var(--gl-hover); box-shadow: inset 0 0 0 1px var(--gl-card-edge); }
a.exc:hover::after, a.exc:focus-visible::after { opacity: 1; }
a.exc:active { background: var(--gl-press); }
a.exc:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
@media (hover: none) { a.exc::after { opacity: .6; } .doc.open:hover { transform: none; background: var(--gl-card); box-shadow: inset 0 0 0 1px var(--gl-card-edge), var(--gl-act-sh); } }
.exc-main { display: flex; flex-direction: column; min-width: 0; }
.exc-line { display: flex; align-items: center; gap: 5px; font: 400 13px/17px var(--font-body); color: var(--text-secondary); font-variant-numeric: tabular-nums; }
.exc-n { display: inline-flex; align-items: center; justify-content: center; min-width: 16px; height: 16px; padding: 0 5px; border-radius: 5px; background: var(--accent-soft);
  font: 500 12px/12px var(--font-body); color: var(--accent-text); transition: background-color .15s, color .15s; }
.exc.closed .exc-n { background: var(--bg-muted); color: var(--text-secondary); }
.r-list .cite-chip { font-weight: 600; } /* the citation chip's weight, as in the conversation */
a.exc:hover .exc-n, .exc.hl .exc-n { background: var(--link); color: var(--on-accent); }
.exc-snippet { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; margin-top: 2px; font: italic 400 13px/1.45 var(--font-body); color: var(--text-secondary); }
@media (prefers-reduced-motion: reduce) { .doc, .doc.open:hover, .exc, a.exc::after, .exc-n { transition: none; transform: none; } }

/* == panel stats == */
/* The cards of a number, side by side and the same width, at the top of a panel view (Explained and To go in
   Progress, Documents and Cited in the Bibliography): the accent's 7 % tint, radius 11, the value 22/24 500 (its
   "/total" 13 in the secondary colour) over the name 13/17; Explained leads with the progress ring (36). The figures
   are hidden from screen readers; one sentence before the cards says them. */
.stat-grid { position: relative; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 7px; color: var(--text-body); }
.stat-card { display: flex; align-items: flex-start; gap: 11px; min-width: 0; padding: 11px 13px; border-radius: 11px; background: color-mix(in srgb, var(--accent) 7%, transparent); }
.stat-card:has(> .ring) { align-items: center; gap: 9px; }
.stat-tx { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.stat-v { font: 500 22px/24px var(--font-body); letter-spacing: -.02em; color: var(--text-primary); font-variant-numeric: tabular-nums; }
.stat-v small { margin-left: 1px; font: 500 13px/15px var(--font-body); letter-spacing: 0; color: var(--text-secondary); }
.stat-k { font: 400 13px/17px var(--font-body); color: var(--text-secondary); }

/* == ideas == */
/* The Progress view's group Ideas: one row per key idea of the Guided Study, its mark (a ring; filled with the dot's
   gradient and a white check once explained) and its text 14/18. */
.idea-rows { display: flex; flex-direction: column; margin-top: 4px; }
.idea-row { display: grid; grid-template-columns: 14px minmax(0, 1fr); align-items: start; column-gap: 7px; min-height: 29px; padding: 5px 7px; border-radius: 9px; font: 400 14px/18px var(--font-body); color: var(--text-body); }
.idea-ic { display: grid; place-items: center; width: 14px; height: 14px; margin-top: 2px; color: var(--text-secondary); }
.idea-dot { display: grid; place-items: center; width: 14px; height: 14px; border-radius: 50%; box-shadow: inset 0 0 0 1px var(--text-secondary); color: var(--on-dot); }
.idea-dot.done { box-shadow: none; background: var(--grad-dot); }
.idea-dot > svg.i { width: 9px; height: 9px; stroke-width: 2; }
.idea-text { min-width: 0; font: 400 14px/18px var(--font-body); overflow-wrap: anywhere; }

/* == debug chat == */
/* The block an admin with the Debug chat on sees under a Tutor reply (public/debug-render.js emits it, as in /admin):
   small, muted, collapsed; three ranks of heading, a fact list with hint marks, the prompts table. */
.msg-debug { margin-top: 8px; padding: 4px 8px; border-left: 2px solid var(--hairline); border-radius: 4px; background: color-mix(in srgb, var(--text-secondary) 5%, transparent);
  font-size: var(--text-xs); color: var(--text-secondary); }
.msg-debug > summary { display: inline-flex; align-items: center; gap: 5px; list-style: none; cursor: pointer; color: var(--text-secondary); }
.msg-debug > summary::-webkit-details-marker, .msg-debug .dbg-sys > summary::-webkit-details-marker { display: none; }
/* the disclosure triangle, right of the label, turning when open */
.msg-debug > summary::after, .msg-debug .dbg-sys > summary::after { content: ""; flex-shrink: 0; width: 0; height: 0;
  border-left: 5px solid var(--text-secondary); border-top: 4px solid transparent; border-bottom: 4px solid transparent; transition: transform .12s, border-left-color .12s; }
.msg-debug[open] > summary::after, .msg-debug .dbg-sys[open] > summary::after { transform: rotate(90deg); }
.msg-debug > summary:hover::after, .msg-debug .dbg-sys > summary:hover::after { border-left-color: var(--accent); }
.msg-debug .dbg-deeplink { margin: 4px 0 2px; }
.msg-debug .dbg-deeplink a { color: var(--text-secondary); text-decoration: underline; }
.msg-debug .dbg-sec { margin: 12px 0 0; padding-top: 10px; border-top: 1px solid var(--hairline); }
.msg-debug .dbg-sec:first-of-type { margin-top: 8px; padding-top: 0; border-top: 0; }
.msg-debug .dbg-sh { margin: 0 0 8px; padding-bottom: 4px; border-bottom: 1px solid var(--hairline); font-size: 10px; font-weight: 500; letter-spacing: .08em; text-transform: uppercase; color: var(--text-body); }
.msg-debug .dbg-sub { margin: 10px 0 10px 10px; padding-left: 10px; border-left: 2px solid var(--border-strong); }
.msg-debug .dbg-subh { margin: 0 0 6px; font-size: 10px; font-weight: 500; letter-spacing: .05em; text-transform: uppercase; color: var(--text-secondary); }
.msg-debug .dbg-plabel { margin: 8px 0 3px; font-size: var(--text-xs); font-weight: 500; color: var(--text-secondary); }
.msg-debug .dbg-facts { display: grid; grid-template-columns: max-content 1fr; gap: 6px 16px; margin: 6px 0; line-height: 1.5; }
.msg-debug .dbg-fk { white-space: nowrap; color: var(--text-faint); }
/* a fact label with data-hint: a small circled "i" marks it, and a dark box shows the hint on hover or focus */
.msg-debug .dbg-fk[data-hint] { position: relative; cursor: help; }
.msg-debug .dbg-fk[data-hint]::after { content: "i"; display: inline-flex; align-items: center; justify-content: center; width: 9px; height: 9px; margin-left: 5px; border: 1px solid var(--border-strong);
  border-radius: 50%; font-size: 7px; font-weight: 500; font-style: italic; line-height: 1; vertical-align: baseline; color: var(--text-secondary); transform: translateY(-1px); transition: color .12s, border-color .12s; }
.msg-debug .dbg-fk[data-hint]:hover::after { color: var(--accent); border-color: var(--accent); }
.msg-debug .dbg-fk[data-hint]:hover::before, .msg-debug .dbg-fk[data-hint]:focus::before { content: attr(data-hint); position: absolute; left: 0; top: calc(100% + 4px); z-index: 40;
  width: max-content; max-width: 280px; padding: 6px 9px; border-radius: 6px; background: var(--text-primary); color: var(--bg-primary); box-shadow: var(--shadow-soft-lg);
  font-size: var(--text-xs); font-weight: 400; line-height: 1.4; letter-spacing: 0; text-transform: none; white-space: normal; pointer-events: none; }
.msg-debug .dbg-fv { color: var(--text-secondary); word-break: break-word; }
.msg-debug .dbg-items { margin: 5px 0 5px 16px; padding: 0; line-height: 1.5; color: var(--text-secondary); }
.msg-debug .dbg-err { margin: 6px 0; font-size: var(--text-xs); line-height: 1.5; color: var(--err-text); }
.msg-debug .dbg-caption { margin: 3px 0 6px; font-style: italic; line-height: 1.5; color: var(--text-faint); }
/* a configuration override: an amber banner, never folded into the reasoning */
.msg-debug .dbg-banner-warn { margin: 2px 0 4px; padding: 3px 7px; border-radius: 4px; background: color-mix(in srgb, var(--warning) 14%, transparent); color: var(--warning); }
.msg-debug .dbg-prompts { width: 100%; margin: 4px 0; border-collapse: collapse; }
.msg-debug .dbg-prompts th, .msg-debug .dbg-prompts td { padding: 4px 8px 4px 0; border-bottom: 1px solid var(--hairline); text-align: left; vertical-align: top; }
.msg-debug .dbg-prompts th { font-weight: 500; color: var(--text-faint); }
.msg-debug .dbg-prompts tr.row-custom td { color: var(--warning); }
.msg-debug .dbg-hash { font-family: var(--font-mono); color: var(--text-faint); }
/* a collapsible summary is a control, not a heading: sentence case, normal weight, the triangle */
.msg-debug .dbg-sys { margin: 6px 0; }
.msg-debug .dbg-sys > summary { display: inline-flex; align-items: center; gap: 5px; margin: 6px 0 3px; list-style: none; cursor: pointer; font-weight: 500; color: var(--text-secondary); }
.msg-debug .dbg-sys > summary:hover, .msg-debug .dbg-sys[open] > summary { color: var(--text-body); }
.msg-debug .dbg-sys[open] > *:not(summary) { margin-left: 12px; }
.msg-debug .dbg-sys pre { max-height: 40vh; overflow: auto; margin: 4px 0 0; padding: 10px; border-radius: 6px; background: color-mix(in srgb, var(--text-secondary) 6%, transparent);
  box-shadow: inset 0 0 0 1px var(--hairline); font-family: var(--font-mono); font-size: var(--text-xs); white-space: pre-wrap; word-break: break-word; }

/* == phone == */
/* Below 640: one column. The island #topbar runs edge to edge at 8 (Menu, the symbol, the path, Open panel); the left
   bar is the drawer, over a dimmed background; the panel is a sheet from the bottom, half the window, with its views
   as tabs on top; the icon bar goes. Every control of the island, the drawer (the Account menu too), the sheet and
   the send button is at least 44 x 44 (the links inside the conversation and the Bibliography keep their size). */
@media (max-width: 639px) {
  .app { grid-template-columns: minmax(0, 1fr); }
  .main { grid-column: 1; }
  /* the conversation and the panel's sheet keep the design's values (the prototype's scale 1 on the phone) */
  .screen-gs, .panel { --text-md: 14px; --text-base: 15px; --r-sm: 8px; --r: 12px; --r-lg: 16px; font-size: var(--text-base); }
  .msg-s { padding: 12px 16px; }
  .msg-t p, .msg-t ul, .msg-t ol, .msg-t blockquote, .msg-t pre { margin-bottom: 12px; }
  .msg-t h1 { font-size: 20px; }
  .msg-t h2 { font-size: 18px; }
  .msg-t h3 { font-size: 16px; }
  .panel-head { padding: 0; } /* the sheet has its tabs: the computer's header text goes, the X stays in the grabber's row */
  .panel-head-text { display: none; }
  .r-head-title { font-size: 17px; line-height: 20px; }
  .leftbar { position: fixed; top: 0; bottom: 0; left: 0; z-index: 50; width: 252px; background: var(--bg-subtle); -webkit-backdrop-filter: none; backdrop-filter: none;
    box-shadow: var(--shadow-soft-lg); transform: translateX(-105%); visibility: hidden; transition: transform .2s ease, visibility 0s .2s; }
  .app.drawer-open .leftbar { transform: none; visibility: visible; transition: transform .2s ease; }
  .app.drawer-open .backdrop { left: 252px; }
  .lb-collapse { display: none; }
  .lb-close { display: inline-grid; width: 44px; height: 44px; border-radius: 9px; color: var(--text-secondary); }
  .lb-close svg.i { width: 18px; height: 18px; }
  .lb-close:hover { color: var(--text-primary); background: var(--gl-hover); box-shadow: inset 0 0 0 1px var(--gl-card-edge); }
  .lb-close:active { background: var(--gl-press); }
  /* the course in the drawer, as in the prototype: a flat row (the book symbol, the name 14/500); with two or more
     courses a button with the chevron that opens My courses, hovering as a glass veil */
  .lb-course:not([hidden]) { display: block; flex: none; margin: 0 0 7px; }
  .lb-course-row { display: flex; align-items: center; gap: 7px; width: 100%; min-height: 44px; margin: 0; padding: 5px 7px; border: 0; border-radius: 9px; background: transparent;
    font: 500 14px/1.3 var(--font-body); color: var(--text-primary); text-align: left; transition: background-color .15s, box-shadow .15s; }
  button.lb-course-row:active { background: var(--gl-press); }
  .lb-course-row > .lb-course-lead { width: 15px; height: 15px; color: var(--text-secondary); }
  .lb-course-name { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
  .lb-course-row > .lb-course-chev { width: 14px; height: 14px; margin-left: auto; color: var(--text-secondary); }
  .lb-brand { height: 44px; }
  .topbar { left: 7px; right: 7px; max-width: none; min-height: 0; gap: 0; padding: 2px; }
  .isl-btn { display: grid; }
  .path { padding: 0 4px; }
  .course-name { overflow: hidden; text-overflow: ellipsis; }
  .course-btn { height: 44px; }
  .topic-btn { height: 44px; min-width: 44px; }
  .path-sep { margin: 0 4px; }
  /* the lists of the path: a sheet from the bottom, as in the prototype (its grabber, its title 15/500 and Close menu,
     options of 44 with the check on the chosen one, the topics' titles wrapping), over the dimmed background */
  .path-menu { inset: auto 0 0 0; width: auto; min-width: 0; max-width: none; max-height: 70vh; padding: 0 11px calc(14px + env(safe-area-inset-bottom));
    border-radius: 14px 14px 0 0; box-shadow: var(--shadow-sheet); }
  /* the grabber's row on top, edge to edge, with the X at its right, as the panel's sheet (one place, one shape for
     every sheet's X); dragging the grabber down by more than 80 closes the sheet (shell.js) */
  .sheet-top { position: sticky; top: 0; z-index: 3; display: flex; justify-content: center; height: 44px; margin: 0 -11px; background: var(--bg-primary); touch-action: none; cursor: grab; }
  .sheet-grab { display: grid; place-items: start center; width: 79px; height: 44px; padding-top: 8px; } /* the bar on top; the title on the X's line */
  .sheet-grab::before { content: ""; width: 32px; height: 4px; border-radius: 2px; background: var(--border-strong); }
  .menu-head { position: sticky; top: 0; z-index: 4; display: flex; align-items: center; min-height: 44px; margin-top: -44px; padding: 10px 52px 0 9px; background: transparent;
    font: 500 15px/1.3 var(--font-body); color: var(--text-primary); pointer-events: none; } /* on the X's line, over the grabber's row */
  .menu-title { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .course-opt, .topic-opt, .topic-sub { min-height: 44px; }
  .course-opt { padding-top: 9px; padding-bottom: 9px; line-height: 1.35; }
  .course-opt-name { display: block; }
  .topic-opt { padding-top: 7px; padding-bottom: 7px; }
  .topic-list .topic-disc { margin-left: 21px; }
  .topic-list > .topic-kids { padding-left: 27px; }
  .topic-list > .topic-kids::before { left: 41px; top: -9px; }
  .course-opt[aria-checked="true"], .topic-opt[aria-selected="true"] { background: transparent; }
  .course-opt[aria-checked="true"] .course-ck, .topic-opt[aria-selected="true"] .topic-ck { display: block; } /* the check on the chosen one only */
  .offline-banner { width: calc(100% - 16px); margin-top: 58px; }
  .page { padding-top: 72px; padding-bottom: 43px; }
  .page > * { width: calc(100% - 32px); }
  .page-title { margin-bottom: 16px; font-size: 28px; line-height: 34px; }
  .chat { gap: 16px; padding: 72px 16px 16px; }
  .msg:has(> .msg-t) { padding-left: 40px; }
  .msg:has(> .msg-t)::before { width: 56px; height: 56px; background-size: 28px 28px, auto; }
  .msg > .msg-t { max-width: 100%; padding: 10px 14px; border-radius: 12px; border-top-left-radius: 4px; }
  .input-area { padding-left: 12px; padding-right: 12px; }
  .input { padding-right: 58px; font-size: var(--text-input); }
  /* on the phone the circle is 36 (the design's), in a target of 44 */
  .input-wrap .btn-send, .input-wrap.multiline .btn-send { right: 5px; bottom: 4px; width: 44px; height: 44px; background: none; box-shadow: none; }
  .btn-send::before { content: ""; position: absolute; inset: 4px; border-radius: 50%; background: var(--link); box-shadow: var(--accent-glow-app); transition: background-color .15s; }
  .btn-send:hover:not([aria-disabled="true"]):not(:disabled) { background: none; }
  .btn-send:hover:not([aria-disabled="true"]):not(:disabled)::before { background: var(--link-hover); }
  .btn-send svg.i { width: 18px; height: 18px; }
  .btn-send.stop .stop-ic { width: 16px; height: 16px; }
  .account-logout, .account-opt { height: 44px; }
  .ai-notice { padding: 8px 12px calc(20px + env(safe-area-inset-bottom)); }
  .panel-bar { display: none; }
  .panel { position: fixed; top: auto; left: 0; right: 0; bottom: 0; z-index: 50; width: auto; height: 43vh; height: 43dvh; padding-bottom: 8px; border-radius: var(--r-lg) var(--r-lg) 0 0;
    background: var(--bg-primary); -webkit-backdrop-filter: none; backdrop-filter: none; box-shadow: var(--shadow-sheet), inset 0 1px 0 var(--hairline);
    transform: translateY(105%); visibility: hidden; transition: transform .2s ease, visibility 0s .2s; }
  .panel::after { display: none; }
  .app.sheet-open .panel { transform: none; visibility: visible; transition: transform .2s ease, height .2s ease-out; }
  /* two heights, as in the prototype: the middle (43 %, how it opens) and large (86 %) */
  .app.sheet-open.sheet-large .panel { height: 86vh; height: 86dvh; }
  /* the sheet's grabber (a button, 88 x 44, the bar 36 x 4): a tap switches the two heights, a drag follows the finger
     and settles on the nearer height, or closes the sheet below a quarter of the window (shell.js); the X at the
     right of its row */
  .panel-grab { display: grid; place-items: center; flex: none; align-self: center; width: 88px; height: 44px; margin: 0; padding: 0; border: 0; background: none; touch-action: none; cursor: grab; }
  .panel-grab::before { content: ""; width: 36px; height: 4px; border-radius: 2px; background: var(--border-strong); }
  /* every sheet's X, in one place and one shape: the top right corner (4 from the edge), 44, the glyph 18 in the
     secondary colour, primary on hover with the glass veil and its edge, pressed deeper (the drawer's X too) */
  .sheet-close { position: absolute; top: 0; right: 4px; z-index: 2; width: 44px; height: 44px; border-radius: 9px; color: var(--text-secondary); }
  .sheet-close svg.i { width: 18px; height: 18px; }
  .sheet-close:hover { color: var(--text-primary); background: var(--gl-hover); box-shadow: inset 0 0 0 1px var(--gl-card-edge); }
  .sheet-close:active { background: var(--gl-press); }
  .panel-tabs { display: flex; justify-content: flex-start; gap: 4px; flex: none; padding: 0 12px; overflow-x: auto; scrollbar-width: none; }
  .panel-tabs::-webkit-scrollbar { display: none; }
  .panel-tab { display: flex; flex: 0 0 auto; flex-direction: column; align-items: center; justify-content: center; gap: 2px; min-width: 44px; height: 48px; margin: 0; padding: 0 6px; border: 0;
    border-radius: 8px; background: none; font: 500 12px/1.2 var(--font-body); color: var(--text-secondary); }
  .panel-tab:focus-visible { outline-offset: -2px; }
  .panel-tab[aria-selected="true"] { color: var(--link); }
  .panel-tab svg.i { width: 20px; height: 20px; }
  #panel-expand { display: none; }
  .panel-hbtn { width: 44px; height: 44px; margin-top: 0; }
}
@media (max-width: 639px) and (hover: hover) { button.lb-course-row:hover { background: var(--gl-hover); box-shadow: inset 0 0 0 1px var(--gl-card-edge); } }
@media (prefers-reduced-motion: reduce) { .leftbar, .panel, .lb-course-row { transition: none; } }
/* the shared pieces of the screens and the Guided Study home at the design's values (the prototype's scale 1 on the
   phone); the home as wide as a page, 16 from the window's edges */
@media (max-width: 639px) {
  .app-page { --sec-above: 16px; }
  .welcome { padding: 0; } /* the conversation's 16 from the window's edges */
  .sec-title { min-height: 44px; }
  .sec-h { height: 44px; padding: 0 8px; border-radius: 10px; }
  .info-card { gap: 12px; min-height: 48px; padding: 12px 14px; border-radius: 12px; }
  .info-card-ic, .info-card-ic > svg.i { width: 18px; height: 18px; }
  .info-card-title { font-size: 15px; line-height: 20px; }
  .ring { width: 40px; height: 40px; }
  .ring > svg.i { width: 16px; height: 16px; }
  .topic-dot { width: 12px; height: 12px; }
  .topic-disc { width: 26px; height: 26px; }
  .tl-row { grid-template-columns: 16px minmax(0, 1fr) auto 16px; column-gap: 8px; min-height: 44px; padding: 6px 8px; border-radius: 10px; font-size: 15px; line-height: 20px; }
  .tl-ic, .tl-ic > svg.i { width: 16px; height: 16px; }
  .tl-dot { width: 7px; height: 7px; }
  .invite { gap: 8px; padding: 12px 14px; border-radius: 12px; }
  .gs-invite .invite { margin-top: 12px; }
  .invite-field { gap: 8px; padding: 8px 10px 8px 12px; border-radius: 10px; font-size: 15px; line-height: 20px; }
  .invite-v { gap: 8px; }
  .invite-btn { gap: 8px; padding: 0 16px; border-radius: 10px; font-size: 15px; line-height: 23px; }
  .invite-btn > svg.i { width: 18px; height: 18px; }
  .gs-body .sec-body > .info-card { margin: 4px 8px 0; }
  .gs-empty .info-card { margin-top: 12px; }
  .rm-list:has(> .rm-empty) { margin-top: 12px; }
  .gs-tiles { grid-template-columns: repeat(auto-fill, minmax(min(200px, calc(50% - 4px)), 1fr)); gap: 8px; padding: 0 8px; }
  .gs-tile { gap: 12px; padding: 12px 14px; border-radius: 12px; }
  .gs-tile-go > svg.i { width: 16px; height: 16px; }
  .gs-tile-title { font-size: 15px; line-height: 20px; }
}
/* the Curriculum Roadmap's screens on the phone (its tree, Overall Progress, the Topic Timeline, Your Last Activities,
   All courses), at the design's values (the prototype's scale 1); the rows of Your Last Activities keep the bar's
   values, 44 high */
@media (max-width: 639px) {
  .rm-list { margin-top: 20px; }
  .rm-kids { padding-left: 24px; }
  .rm-item { gap: 12px; padding: 6px 10px; border-radius: 8px; font-size: 15px; line-height: 20px; }
  .rm-num:not(.rm-disc) { min-width: 30px; }
  .rm-dot { margin: 0 4px; }
  .rm-d1 > .rm-disc { margin-left: 21px; }
  .rm-d1 > .rm-topic { margin-left: 15px; }
  .rm-item > .rm-go { width: 18px; height: 18px; }
  .rm-kids > .rm-item::before, .rm-kids > .rm-item::after, .rm-kids > .rm-kids:not(:last-child)::before { left: 19px; }
  .rm-kids > .rm-item::before, .rm-kids > .rm-item::after { height: calc(50% - 9px); }
  .rm-item.rm-open::after { left: 43px; height: calc(50% - 16px); }
  .rm-tog { width: 28px; height: 28px; margin-top: -14px; border-radius: 8px; }
  .rm-tog > svg.i { width: 14px; height: 14px; }
  .rm-tog::after { content: ""; position: absolute; left: 50%; top: 50%; width: 44px; height: 44px; transform: translate(-50%, -50%); }
  .panel-view:is([data-panel-view="overall"], [data-panel-view="timeline"]) { padding: 8px 16px 16px; }
  .overall { gap: 8px; }
  .overall + .invite, .panel-view > .err-note + .invite { margin-top: 12px; }
  .ov-card { gap: 10px; padding: 12px 14px; border-radius: 12px; }
  .ov-card.top3 { gap: 8px; }
  .ov-top { gap: 12px; }
  .top3-h { gap: 8px; }
  .top3-t { gap: 6px; }
  .top3-t > svg.i { width: 13px; height: 13px; }
  /* the info button is a box of 44 (every control of the sheet is, nav-C10), its chip of 28 drawn inside it */
  .top3-info { width: 44px; height: 44px; margin: -14px -16px -14px -8px; border-radius: 8px; }
  .top3-info, .top3-info:hover, .top3-info:active, .top3-info[aria-expanded="true"] { background: none; box-shadow: none; }
  .top3-info::before { content: ""; position: absolute; left: 8px; top: 8px; width: 28px; height: 28px; border-radius: 8px; }
  .top3-info:hover::before, .top3-info:active::before, .top3-info[aria-expanded="true"]::before { background: var(--gl-hover); box-shadow: inset 0 0 0 1px var(--gl-card-edge); }
  .top3-info::after { display: none; }
  .top3-info > svg.i { position: relative; width: 16px; height: 16px; }
  .top3-l { gap: 10px; }
  .top3-l li { grid-template-columns: 30px minmax(0, 1fr) auto; column-gap: 12px; row-gap: 6px; font-size: 15px; line-height: 20px; }
  .top3-bar { margin-right: 16px; }
  .top3-empty { font-size: 15px; line-height: 23px; }
  [data-panel-view="timeline"] > .invite { margin-top: 8px; }
  .lb-acts { --sec-above: 14px; }
  .lb-acts .tl-row { grid-template-columns: 14px minmax(0, 1fr) auto 14px; column-gap: 7px; min-height: 44px; padding: 0 7px; border-radius: 9px; font-size: 14px; line-height: 18px; }
  .lb-acts .tl-ic, .lb-acts .tl-ic > svg.i { width: 14px; height: 14px; }
  .lb-acts .tl-dot { width: 6px; height: 6px; }
  .course-sep { margin: 6px 0; }
  .course-grid { grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 8px; margin-top: 20px; }
  .course-card { gap: 12px; padding: 12px 14px; border-radius: 12px; }
  .course-card-ic > svg.i { width: 18px; height: 18px; }
  .course-card-name { font-size: 15px; line-height: 20px; }
  .course-card > .course-card-go { width: 16px; height: 16px; }
}
/* Targets of 44 with touch, and always on the phone (the final measures put the left bar's rows at 43), as in the
   prototype (A6): the left bar's symbol, Tools' title and items, Send feedback, the account and Admin panel; on a touch tablet also the
   path's buttons (a 44 target around them) and the icon bar. */
@media (pointer: coarse), (max-width: 639px) {
  .lb-brand, .lb-sec, .lb-item, .lb-feedback, .account-trigger, .lb-admin { min-width: 44px; min-height: 44px; }
  .sec-h, .tl-row { min-height: 44px; }
}
@media (pointer: coarse) and (min-width: 640px) {
  .course-btn { position: relative; }
  .course-btn::after { content: ""; position: absolute; left: 50%; top: 50%; width: max(100%, 44px); height: 44px; transform: translate(-50%, -50%); }
  .pb-btn { height: 44px; }
}
/* the Guided Study's conversation, its end and its panel on the phone */
@media (max-width: 639px) {
  /* on the Guided Study the island's path is the topic only, as in the prototype: the course lives in the drawer */
  .app.on-gs #topbar :is(.course-name, .path-sep) { display: none; }
  .isl-sw:not([hidden]) { display: flex; flex-direction: row; width: auto; height: 32px; margin: 0 4px 0 0; align-self: center; border-radius: 12px; }
  .isl-sw .sw-hd, .isl-sw .sw-cmd { width: 32px; height: 32px; }
  .isl-sw .sw-hd { border-radius: 12px 0 0 12px; }
  .isl-sw .sw-hd:focus-visible { outline: 2px solid var(--accent); outline-offset: 0; }
  .isl-sw .sw-wire { width: 1px; height: auto; margin: 6px 0; }
  .isl-sw .sw-cmd { border-radius: 0 12px 12px 0; }
  .isl-sw :is(.sw-hd, .sw-cmd)::after { content: ""; position: absolute; left: 50%; top: 50%; width: 44px; height: 44px; transform: translate(-50%, -50%); }
  .loading { gap: 12px; }
  .loading-sym { width: 28px; height: 28px; }
  .loading-sym::after { left: 16px; top: 11px; width: 6px; height: 6px; }
  .loading-sym::before { left: 10px; top: 5px; width: 18px; height: 18px; }
  .app-notice.problem { width: auto; max-width: none; margin-left: 40px; }
  .jump { bottom: 3px; gap: 6px; height: 32px; padding: 0 12px; }
  .day-sep { margin: 8px auto; }
  .tl-row::after { width: 16px; height: 16px; }
  .jump > svg.i { width: 14px; height: 14px; }
  .cite { min-width: 18px; height: 18px; border-radius: 6px; }
  .doc, .doc-head { border-radius: 12px; }
  .panel-view { padding-left: 16px; padding-right: 16px; } /* the sheet's body, as the prototype's */
  .doc-head { grid-template-columns: 16px minmax(0, 1fr) 16px; column-gap: 8px; min-height: 48px; padding: 8px; }
  .doc:not(.cited) .doc-head { min-height: 44px; padding-top: 6px; padding-bottom: 6px; }
  .doc-ico, .doc-ico > svg, .doc-head > svg.doc-go { width: 16px; height: 16px; }
  .doc-title { font-size: 15px; line-height: 20px; }
  .exc-list::before { margin-left: 28px; }
  .exc { grid-template-columns: 16px minmax(0, 1fr) 16px; column-gap: 8px; min-height: 44px; padding: 6px 4px; border-radius: 8px; }
  a.exc::after { width: 16px; height: 16px; }
  .exc-line { gap: 6px; }
  .exc-n { min-width: 18px; height: 18px; border-radius: 6px; }
  .ended-area { padding-left: 12px; padding-right: 12px; }
  .chat-offline { width: calc(100% - 24px); }
  .ended-card { gap: 12px; padding: 12px 14px; border-radius: 12px; }
  .ended-card-ic, .ended-card-ic > svg.i { width: 18px; height: 18px; }
  .ended-card-title { font-size: 15px; line-height: 20px; }
  .ic-inline > svg.i { width: 14px; height: 14px; }
  .stat-grid { gap: 8px; }
  .stat-card { gap: 12px; padding: 12px 14px; border-radius: 12px; }
  .stat-card:has(> .ring) { gap: 10px; }
  .stat-v { font-size: 24px; line-height: 26px; }
  .stat-v small { font-size: 15px; line-height: 16px; }
  .r-list, .bib-docs { gap: 8px; }
  .r-list > .sec { margin-top: calc(var(--sec-above) - 8px); }
  .idea-row { grid-template-columns: 16px minmax(0, 1fr); column-gap: 8px; min-height: 32px; padding: 6px 8px; border-radius: 10px; }
  .idea-ic, .idea-dot { width: 16px; height: 16px; }
  .idea-dot { box-shadow: inset 0 0 0 2px var(--text-secondary); }
  .idea-text { font-size: 15px; line-height: 20px; }
}

/* hidden wins over every display above */
.app [hidden] { display: none; }
