/* 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 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;
}
@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);
    --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;
  }
}
: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);
  --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;
}
@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); }
@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; }
}
@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); }
/* 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.on-roadmap .path-topic, .app.on-roadmap .topic-menu { 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, each deeper level one step in with a line through the
   dots of its rows (the topic dot), number and title on one line. 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; }
@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: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
.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; margin: 0; padding: 9px 9px 2px; font: 500 var(--text-sm)/1.35 var(--font-body); color: var(--text-secondary); }
.topic-sec:first-child { padding-top: 4px; }
.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: 5px; }
.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: hidden; text-overflow: ellipsis; white-space: nowrap; }
.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: 79px 14px 29px; }
.page > * { max-width: 648px; margin-left: auto; margin-right: auto; }
.page-title { margin-top: 0; margin-bottom: 14px; font: 400 25px/1.2 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 { border-radius: 11px; }
.panel-hbtn svg.i { width: 14px; height: 14px; }
.panel-view { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 4px 11px 11px 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; }
/* the command of the Guided Study on screen at the top of the icon bar (End, or Start a new one); Start fills its
   circle on hover */
.pb-cmd .pb-fill, .pb-cmd:hover .pb-line { display: none; }
.pb-cmd:hover .pb-fill { display: block; }
.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; } }

/* == 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; margin-top: 4px; }
.tl-row { position: relative; display: grid; grid-template-columns: 14px minmax(0, 1fr) auto; 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; }
.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: 14px; }
.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; 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: 22px; flex: 1 1 auto; min-height: 0; overflow-y: auto;
  padding: 65px 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); }
@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(--bg-muted); color: var(--text-primary); white-space: pre-wrap; }
.msg-t { padding: 4px 0; color: var(--text-body); line-height: 1.65; }
.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]: the same in the conversation and in the Bibliography's rows */
.cite { display: inline-flex; align-items: center; justify-content: center; min-width: 16px; height: 16px; margin: 0 1px; padding: 0 4px; border-radius: 5px;
  background: var(--accent-soft); color: var(--link); font: 600 var(--text-xs)/1 var(--font-body); font-variant-numeric: tabular-nums; vertical-align: super;
  text-decoration: none; cursor: pointer; transition: background-color .1s, color .1s; }
.cite:hover, .cite.hl { background: var(--link); color: var(--on-accent); }
/* a closed (copyright-protected) source: the same chip, muted, not a link */
.cite.locked, .cite.locked:hover, .cite.locked.hl { background: var(--bg-muted); color: var(--text-secondary); cursor: default; }
/* the waits and the notices of the conversation (notices.js) */
.loading, .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 { color: var(--err-text); }
.dot { width: 3px; height: 3px; border-radius: 50%; background: var(--accent); opacity: .4; animation: dot-pulse 1.4s ease-in-out infinite; }
.dot:nth-child(2) { animation-delay: .2s; }
.dot:nth-child(3) { animation-delay: .4s; }
@keyframes dot-pulse { 0%, 100% { opacity: .15; } 50% { opacity: .8; } }
/* 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; }
.btn-send { position: absolute; right: 7px; bottom: 9px; z-index: 2; display: flex; align-items: center; justify-content: center; width: 31px; height: 31px; padding: 0; border: 0; border-radius: 8px;
  background: var(--link); color: var(--on-accent); box-shadow: inset 0 1px 0 var(--ctl-sheen), var(--shadow-raised); transition: transform .14s, background-color .14s; }
.btn-send svg.i { width: 14px; height: 14px; stroke-width: 2; }
.input-wrap.multiline .btn-send { top: auto; bottom: 9px; margin: 0; }
.btn-send:hover { transform: translateY(-1px); background: var(--link-hover); }
.btn-send:active { transform: none; }
.btn-send:disabled { background: var(--text-faint); cursor: not-allowed; transform: none; }
/* Stop, while the reply arrives: discreet, a square */
.btn-send.stop { background: var(--text-secondary); }
.btn-send.stop:hover { background: var(--text-body); transform: none; }
.btn-send.stop svg { display: none; }
.btn-send.stop::after { content: ""; width: 8px; height: 8px; border-radius: 2px; background: var(--bg-primary); }
/* 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 conversation when there is no bar (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; }
@media (prefers-reduced-motion: reduce) { .input-wrap::after, .msg, .msg-t .caret, .dot { animation: none; } }

/* == curriculum roadmap == */
/* The course syllabus (roadmap.js): a section heading per depth-1 node, then every level as one block, a line with a
   marker on each topic, one indent step in per level. A row with no subtopics is a button that opens a Guided Study. */
.rm-list { padding: 0 0 14px; }
.rm-sec { display: flex; gap: 7px; align-items: baseline; padding: 14px 7px 5px; }
.rm-sec:first-child { padding-top: 5px; }
.rm-sec-num { flex-shrink: 0; font-size: var(--text-sm); font-weight: 500; letter-spacing: .02em; color: var(--accent); }
.rm-sec-title { font-size: var(--text-sm); font-weight: 500; line-height: 1.35; letter-spacing: .04em; text-transform: uppercase; color: var(--text-secondary); }
/* THE MARKER IS THE MASTERY SLOT. --rm-mastery (0 to 1) fills the disc clockwise, so how well a student knows a topic is
   read off the same mark at every level. It is declared on the row, so a per-row value (style="--rm-mastery:.6")
   reaches the marker by inheritance. It stays 0 until that data exists: the plain empty ring. */
.rm-item { --rm-mastery: 0; display: flex; gap: 9px; padding: 8px 7px; border-radius: var(--r-sm); }
.rm-leaf { cursor: pointer; }
.rm-leaf:hover { background: var(--bg-muted); }
.rm-leaf:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
/* positioned so it paints over the level's line, which runs behind it; the colour and the fill set apart, so a value
   the fill cannot use leaves the plain disc */
.rm-dot { position: relative; z-index: 1; display: flex; align-items: center; justify-content: center; flex-shrink: 0; width: 16px; height: 16px; margin-top: 2px; border-radius: 50%;
  border: 2px solid var(--border-strong); color: var(--text-faint); background-color: var(--bg-primary);
  background-image: conic-gradient(var(--accent) calc(clamp(0, var(--rm-mastery), 1) * 360deg), var(--bg-primary) 0); }
.rm-body { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.rm-num { font-size: var(--text-xs); font-weight: 500; line-height: 1.3; letter-spacing: .02em; color: var(--text-secondary); }
.rm-topic { font-size: var(--text-md); line-height: 1.35; color: var(--text-body); word-break: break-word; }
/* one level: its rows, one indent step in; the line runs the whole block through the centre of the markers and fades
   at both ends over the height of one marker */
.rm-kids { --rm-indent: 18px; position: relative; padding-left: var(--rm-indent); }
.rm-kids::before { content: ""; position: absolute; left: calc(var(--rm-indent) + 14px); top: 0; bottom: 0; width: 2px;
  background: linear-gradient(to bottom, transparent 0, var(--border-strong) 18px, var(--border-strong) calc(100% - 18px), transparent 100%); }

/* == bibliography == */
/* The Bibliography view of the panel (bibliography.js): 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; }
.doc { overflow: hidden; border-radius: var(--r); background: var(--bg-primary); box-shadow: inset 0 0 0 1px var(--hairline), var(--shadow-raised); transition: box-shadow .16s; }
.doc:hover { box-shadow: inset 0 0 0 1px var(--border-strong), var(--shadow-raised); }
.doc-head { display: flex; align-items: flex-start; gap: 6px; padding: 9px 9px 7px; }
.doc-ico { flex-shrink: 0; margin-top: 2px; color: var(--text-secondary); }
.doc-main { min-width: 0; }
.doc-title.o { display: block; font-size: var(--text-sm); font-weight: 500; line-height: 1.35; color: var(--link); text-decoration: none; cursor: pointer; }
.doc-title.o:hover { text-decoration: underline; }
.doc-title.locked { display: flex; align-items: center; gap: 4px; font-size: var(--text-sm); font-weight: 500; line-height: 1.35; color: var(--text-secondary); cursor: default; }
.doc-title.locked svg { flex-shrink: 0; opacity: .7; }
.doc-sub { margin-top: 1px; font-size: var(--text-xs); line-height: 1.4; color: var(--text-secondary); word-break: break-word; }
/* the excerpt row: the whole row is the target (it opens the PDF at its page); cited in the latest reply: a bar on the left */
.exc { position: relative; display: flex; align-items: flex-start; gap: 6px; padding: 7px 9px; border-top: 1px solid var(--hairline); text-decoration: none; transition: background-color .1s; }
a.exc:hover, .exc.hl { background: var(--accent-soft); }
.exc-n { flex-shrink: 0; margin-top: 2px; padding: 1px 4px; border-radius: 4px; background: var(--accent-soft); font-size: var(--text-xs); font-weight: 500; color: var(--link); }
.exc-main { min-width: 0; }
.exc-page { font-size: var(--text-xs); font-weight: 500; line-height: 1.4; color: var(--link); }
.exc.closed .exc-page { color: var(--text-secondary); }
.exc-snippet { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; margin-top: 2px;
  font-family: var(--font-serif); font-style: italic; font-size: var(--text-xs); line-height: 1.5; color: var(--text-secondary); }
.exc.new::before { content: ""; position: absolute; left: 0; top: 5px; bottom: 5px; width: 2px; border-radius: 2px; background: var(--accent); }

/* == 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: 14px 12px 8px 16px; }
  .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: center; width: 79px; height: 44px; }
  .sheet-grab::before { content: ""; width: 32px; height: 4px; border-radius: 2px; background: var(--border-strong); }
  .menu-head { position: sticky; top: 44px; z-index: 2; display: flex; align-items: center; min-height: 28px; padding: 0 0 4px 9px; background: var(--bg-primary); font: 500 15px/1.3 var(--font-body); color: var(--text-primary); }
  .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-opt-title { white-space: normal; overflow: visible; overflow-wrap: anywhere; }
  .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: 65px; }
  .chat { gap: 24px; padding: 72px 12px 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); }
  .input-wrap .btn-send, .input-wrap.multiline .btn-send { right: 5px; bottom: 4px; width: 44px; height: 44px; border-radius: 12px; }
  .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; gap: 4px; flex: none; padding: 0 8px; }
  .panel-tab { display: flex; flex: 1 1 auto; flex-direction: column; align-items: center; justify-content: center; gap: 2px; min-width: 44px; height: 48px; margin: 0; padding: 0 4px; 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; }
}
@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 4px; }
  .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; 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; }
  .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) */
/* 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 */

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