/* brainlag.css v2 - the Brainlag design system (shared by every page).
   Pages link this BEFORE their own <style>, so page rules win.
   Tokens: paper/surface/sunk/ink/ink-2/ink-3/rule + roles (study = teal, play = violet, ok, warn, bad).
   Legacy names (--bg --card --text --muted --accent --accent-text --ink-rgb --text-2 --dk-panel)
   stay as aliases: the 20 study tools are written against them. */

/* ---- Fonts (self-hosted, OFL; see /assets/fonts/OFL-*.txt) ---- */
@font-face{font-family:"BL Body";src:url(/assets/fonts/bl-onest.woff2) format("woff2");font-weight:400 700;font-style:normal;font-display:swap}
@font-face{font-family:"BL Display";src:url(/assets/fonts/bl-display2.woff2) format("woff2");font-weight:500 700;font-style:normal;font-display:swap}

/* ---- Tokens (see scratchpad bl-redesign/PALETTE.md; shared roles with code.brainlag.space) ---- */
:root{
  --f-body:"BL Body",system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
  --f-display:"BL Display","BL Body",system-ui,sans-serif;
  --f-mono:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  --paper:#f4f9ff; --surface:#ffffff; --sunk:#e6f1fc;
  --track:var(--sunk);   /* an empty progress track: light, the sunk tone already reads on the page (1.08:1) */
  --ink:#15365a; --ink-2:#2c4a6b; --ink-3:#536b88;
  --ink-rgb:21,54,90;
  --rule:rgba(var(--ink-rgb),.12); --rule-2:rgba(var(--ink-rgb),.22);
  --study:#0d9aa7; --study-ink:#08707a; --study-tint:#dcf3f2;
  /* primary buttons (owner, 9 Oct: "White text - why not?"): white on a deeper teal, 4.76:1 (navy on --study was
     3.95, white on it 3.39); hover and pressed a step deeper, the lip deeper still. The same in the dark theme (the
     fill is 3.8:1 against the dark page). --study stays for accents, progress and icons. */
  --study-btn:#0a7f8a; --study-btn-hover:#097883; --study-btn-press:#09737e; --study-btn-lip:#065a62; --on-study-btn:#ffffff;
  --btn-off-edge:#7a8fa8;   /* a disabled button's edge: 3.1:1 on the page, so its shape still reads */
  /* secondary buttons (owner, 9 Oct: in dark mode they were darker than the page, holes not buttons): always a tone
     ABOVE the page and cards, an edge of 3:1 or more against both, the same raised lip as the answer cards */
  --btn-2:#ffffff; --btn-2-hover:#eef5fd; --btn-2-press:#e2edf9; --btn-2-edge:#7a8fa8; --btn-2-lip:#c3d2e3;
  /* a speech bubble's outline: one solid colour, so the tail and the body join without a seam */
  --say-edge:color-mix(in srgb,var(--ink) 24%,var(--surface));
  --blue:#3a9be8; --blue-ink:#1f6fb5; --blue-tint:#e3f0fc;
  --play:#6a4bc4; --play-ink:#5536ad; --play-tint:#eee8fb;
  --pink:#e0559a; --pink-ink:#b8326f; --pink-tint:#fde8f1;
  /* Music (owner, 10 Oct: pink, "cream looks boring", over the 9 Oct brass; tokens.json palette.subjects.music). --music-2
     is the deeper rose partner for gradients; --music-glow and --music-row are the dark part glow and the active row */
  --music:#e0559a; --music-ink:#b8326f; --music-tint:#fde8f1; --music-2:#c84283; --music-2-tint:#fadbea; --music-glow:#fde8f1; --music-row:#fde8f1;
  --gold:#ffc23d; --gold-ink:#8a5d00; --gold-tint:#fff2cc;
  --navy:#15365a; --on-navy:#ffffff; --on-navy-2:#b9cde3;
  --ok:#13804f; --warn-ink:#8a4b00; --warn-bg:#ffe9c2; --bad:#c0362c;
  --code-bg:#0b1626; --code-ink:#e6eef7;
  --shadow:0 1px 2px rgba(21,54,90,.06),0 6px 18px rgba(21,54,90,.07);
  --r1:14px; --r2:18px; --r3:26px; --pill:10px; --chip:4px;   /* no pills (brand/identity/LAYOUT.md, COLOUR.md #13): --pill is a key's 10 px corner now; label chips 0.12 x their height */
  --wrap:1200px;
  --bg:var(--paper); --card:var(--surface); --text:var(--ink); --muted:var(--ink-3); --text-2:var(--ink-2);
  --accent:var(--study); --accent-text:var(--study-ink); --accent2:var(--play); --br:var(--r2);
  --hdr-bg:var(--surface);
  /* motion (docs/research/MOTION_DESIGN_DEVONHOUSE.md, T1 and T5): the house curves, and durations by size and
     importance. Enter with out, leave with in (and faster); spring only on small things that are touched. A list
     staggers 35ms an item, capped at 6 (the rest arrive with the sixth). Reduced motion: the end state at once. */
  --ease-out:cubic-bezier(.22,1,.36,1); --ease-in:cubic-bezier(.55,0,1,.45); --ease-io:cubic-bezier(.45,0,.55,1);
  --ease-spring:cubic-bezier(.34,1.56,.64,1); --ease-soft:cubic-bezier(.3,1.3,.6,1);
  --dur-press:75ms; --dur-hover:175ms; --dur-enter:220ms; --dur-leave:160ms; --dur-panel:300ms;
  --dur-page-out:140ms; --dur-page-in:240ms; --dur-reward:1s; --stagger:35ms; --stagger-max:6;
  color-scheme:light;
}
:root[data-theme="dark"]{
  --paper:#0b1626; --surface:#12233a; --sunk:#081120;
  --track:#1a2c44;   /* dark: lighter than the page (1.29:1), since a track darker than #0b1626 (sunk, 1.04:1) vanishes */
  --ink:#ffffff; --ink-2:#c8d7e8; --ink-3:#9db3c9;
  --ink-rgb:200,215,232;
  --rule:rgba(157,179,201,.18); --rule-2:rgba(157,179,201,.32);
  --study:#0d9aa7; --study-ink:#2cc6d1; --study-tint:#0f3438;
  --btn-off-edge:#5d7591;   /* 3.8:1 on the dark page */
  --btn-2:#22385a; --btn-2-hover:#2a4368; --btn-2-press:#1b2f4b; --btn-2-edge:#6b829d; --btn-2-lip:#07101c;   /* edge 4.6:1 on the page, 4.0:1 on a card */
  --blue:#5aaff0; --blue-ink:#7cc0f5; --blue-tint:#13304f;
  --play:#8f74e8; --play-ink:#b6a1ff; --play-tint:#241d45;
  --pink:#f07ab5; --pink-ink:#f59cc8; --pink-tint:#3a1a33;
  --music:#f07ab5; --music-ink:#f59cc8; --music-tint:#3a1a33; --music-2:#e169a5; --music-2-tint:#4a2242; --music-glow:#5a2a50; --music-row:#3d1d37;
  --gold:#ffc23d; --gold-ink:#ffd877; --gold-tint:#33280f;
  --navy:#102a44; --on-navy-2:#a9c1da;
  --ok:#3fd59a; --warn-ink:#ffc23d; --warn-bg:#33280f; --bad:#ff8a80;
  --code-bg:#071020;
  --shadow:0 1px 2px rgba(0,0,0,.3),0 8px 22px rgba(0,0,0,.25);
  --accent:var(--study); --accent-text:var(--study-ink);
  --dk-panel:#16304d; --danger:#ff8a80; --warn:#ffc23d;
  color-scheme:dark;
}

/* ---- Base ---- */
*{box-sizing:border-box}
[hidden]{display:none!important}
html{-webkit-text-size-adjust:100%;text-size-adjust:100%}
html,body{margin:0;padding:0;background:var(--paper);color:var(--ink);font:400 17px/1.55 var(--f-body)}
body{min-height:100vh;display:flex;flex-direction:column}
body > main{flex:1 0 auto}
a{color:inherit;text-decoration:none}
img{max-width:100%}
h1,h2,h3{font-family:var(--f-display);font-weight:600;letter-spacing:-.01em;line-height:1.15;color:var(--ink);text-wrap:balance}
/* no orphan lines (owner, 10 Oct: a line never ends with one or two words on it): headings balance, running text is
   pretty (the browser looks ahead so the last line is not a lone word); browsers without it wrap as before */
h4,h5,h6{text-wrap:balance}
p,li,dd,dt,figcaption,blockquote,summary,label,td,th{text-wrap:pretty}
h1{font-size:clamp(28px,4.2vw,40px);margin:0 0 8px}
h2{font-size:clamp(21px,2.4vw,26px);margin:0 0 12px}
h3{font-size:18px;margin:0 0 6px}
p{margin:0 0 12px}
:focus-visible{outline:2px solid var(--study-ink);outline-offset:2px}
/* Simplified Chinese (/zh/, <html lang="zh-Hans">) and Hindi (/hi/, <html lang="hi">): the site fonts carry no CJK or
   Devanagari glyphs, so Latin keeps them and the script falls back to Noto Sans SC / Noto Sans Devanagari (Google Fonts,
   unicode-range slices, display swap, linked by header.php on those languages only), then the system face.
   Chinese wraps between any two characters; strict line-break keeps ，。：？ off the start of a line; a long Latin run
   (a URL, an email) may break anywhere. Headings get more leading and no negative tracking. No faux italics on Han.
   Devanagari needs taller lines for its matras and the headline bar; text-wrap balance and pretty stay where supported. */
:root:lang(zh){--f-body:"BL Body","Noto Sans SC","PingFang SC","Hiragino Sans GB","Microsoft YaHei",system-ui,sans-serif;
  --f-display:"BL Display","BL Body","Noto Sans SC","PingFang SC","Hiragino Sans GB","Microsoft YaHei",system-ui,sans-serif}
:lang(zh) body{line-break:strict;word-break:normal;overflow-wrap:anywhere;font-kerning:none}
:lang(zh) h1,:lang(zh) h2,:lang(zh) h3{letter-spacing:0;line-height:1.3;hyphens:manual;-webkit-hyphens:manual}
:lang(zh) p,:lang(zh) li{line-height:1.7}
:lang(zh) em,:lang(zh) i,:lang(zh) cite{font-style:normal}
:lang(zh) em{font-weight:600}
:root:lang(hi){--f-body:"BL Body","Noto Sans Devanagari","Kohinoor Devanagari","Nirmala UI",system-ui,sans-serif;
  --f-display:"BL Display","BL Body","Noto Sans Devanagari","Kohinoor Devanagari","Nirmala UI",system-ui,sans-serif}
:lang(hi) body{line-height:1.6;overflow-wrap:break-word}
:lang(hi) h1,:lang(hi) h2,:lang(hi) h3{letter-spacing:0;line-height:1.35}
:lang(hi) p,:lang(hi) li{line-height:1.75}
:lang(hi) em,:lang(hi) i,:lang(hi) cite{font-style:normal}
:lang(hi) em{font-weight:600}
/* Arabic (/ar/, <html lang="ar" dir="rtl">): Noto Sans Arabic (Google Fonts, /ar/ only), taller lines for the script's
   ascenders and dots, no letter-spacing (it breaks joined letters), no faux italics. Layout follows dir through logical
   properties (margin-inline, inset-inline, text-align:start); maths, code, formulae and music stay left to right. */
:root:lang(ar){--f-body:"BL Body","Noto Sans Arabic","Geeza Pro","Segoe UI",system-ui,sans-serif;
  --f-display:"BL Display","BL Body","Noto Sans Arabic","Geeza Pro","Segoe UI",system-ui,sans-serif}
:lang(ar) body{line-height:1.65}
:lang(ar) h1,:lang(ar) h2,:lang(ar) h3{letter-spacing:0;line-height:1.4}
:lang(ar) p,:lang(ar) li{line-height:1.8}
:lang(ar) *{letter-spacing:0}
:lang(ar) em,:lang(ar) i,:lang(ar) cite{font-style:normal}
:lang(ar) em{font-weight:600}
[dir="rtl"] :is(code,pre,kbd,samp,var,math,.fml,.mono,.katex,.stave,input[type="number"],input[type="email"],input[type="url"]){direction:ltr;unicode-bidi:isolate}
[dir="rtl"] :is(.ic-dir,.chev,.arrow,.bl-chev,.crumb-sep,.hm-inside-go){scale:-1 1}   /* the individual property: it composes with any transform the icon already has */
[dir="rtl"] .hm-phone{direction:ltr}   /* the home hero's phone plays an English lesson: it stays left to right */
main:focus{outline:none}
.wrap{width:100%;max-width:var(--wrap);margin:0 auto;padding:0 24px}
@media (min-width:1680px){:root{--wrap:1480px}}
@media (max-width:640px){.wrap{padding:0 16px}}
.muted{color:var(--ink-3)}
.mono,.tnum{font-variant-numeric:tabular-nums}
.mono{font-family:var(--f-mono)}
.vh{position:absolute!important;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}

/* ---- Buttons: pill, chunky ---- */
.b{display:inline-flex;align-items:center;justify-content:center;gap:8px;min-height:46px;padding:0 22px;border-radius:var(--pill);
  font:700 16px/1.1 var(--f-body);border:2px solid transparent;cursor:pointer;text-decoration:none;white-space:nowrap;
  transition:background-color .15s cubic-bezier(.22,1,.36,1),border-color .15s cubic-bezier(.22,1,.36,1),color .15s cubic-bezier(.22,1,.36,1),transform .1s cubic-bezier(.22,1,.36,1)}
.b:active{transform:translateY(1px)}
.b svg{flex:none}
.b-study,:root[data-theme="dark"] .b-study{background:var(--study-btn);color:var(--on-study-btn);box-shadow:0 3px 0 var(--study-btn-lip)}
.b-study:hover{background:var(--study-btn-hover)}
.b-study:active{background:var(--study-btn-press)}
.b-play{background:var(--play);color:#fff;box-shadow:0 3px 0 #4a3299}
.b-play:hover{background:#5d3fb5}
:root[data-theme="dark"] .b-play{color:#120c24;box-shadow:0 3px 0 #5a46a8}
.b-quiet{background:var(--btn-2);color:var(--ink);border-color:var(--btn-2-edge);box-shadow:0 3px 0 var(--btn-2-lip)}
.b-quiet:hover{background:var(--btn-2-hover);border-color:var(--btn-2-edge)}
.b-quiet:active{background:var(--btn-2-press)}
.b-text{background:none;border:0;padding:0;min-height:0;color:var(--study-ink);font-weight:700;box-shadow:none}
.b-text:hover{text-decoration:underline;text-underline-offset:3px}
.b-lg{min-height:54px;padding:0 28px;font-size:17px}
.b-sm{min-height:38px;padding:0 14px;font-size:14px}
/* a long label (a German one, say) wraps to two balanced lines on a phone instead of running out of its button; a word
   never splits (owner, 9 Oct). .nw keeps a short run (a URL's last part) on one line. */
@media (max-width:520px){.b{white-space:normal;text-wrap:balance;text-align:center;line-height:1.2;padding-top:8px;padding-bottom:8px}}
.nw{white-space:nowrap}
@media (pointer:coarse){.b-sm{min-height:44px}}
@media (prefers-reduced-motion:reduce){.b:active{transform:none}}
button.cta,.btn.primary{background:var(--study-btn);color:var(--on-study-btn);font-weight:700;border:none;border-radius:var(--pill);padding:12px 20px;cursor:pointer}

/* ---- Text links ---- */
.tlink{color:var(--study-ink);font-weight:700}
.tlink:hover{text-decoration:underline;text-underline-offset:3px}
.prose a,.lnk{color:var(--blue-ink);text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:3px}

/* ---- Section head ---- */
.shead{display:flex;align-items:center;justify-content:space-between;gap:12px 20px;flex-wrap:wrap;margin:0 0 16px}
.shead h2{margin:0}
.shead .sub{color:var(--ink-3);font-size:15px;margin:4px 0 0;flex-basis:100%}
.shead a.more{display:inline-flex;align-items:center;min-height:38px;padding:0 14px;border-radius:var(--pill);background:var(--blue-tint);color:var(--blue-ink);font-weight:700;font-size:15px}
.shead a.more:hover{background:var(--blue);color:#fff}

/* ---- Tile lists (replaces hairline-ruled rows): rounded white tiles with a tinted icon tile ---- */
.rows{list-style:none;margin:0;padding:0;display:grid;gap:10px}
.rows > li{margin:0}
.rows a.row{display:flex;align-items:center;gap:14px;padding:12px 16px 12px 12px;min-height:68px;color:var(--ink);background:var(--surface);
  border-radius:var(--r2);box-shadow:var(--shadow);border:2px solid transparent;transition:border-color .15s cubic-bezier(.22,1,.36,1),transform .15s cubic-bezier(.22,1,.36,1)}
.rows a.row:hover{border-color:var(--blue)}
.row .ri{flex:none;width:46px;height:46px;display:grid;place-items:center;border-radius:14px;background:var(--blue-tint);color:var(--blue-ink)}
.row[data-tone="teal"] .ri{background:var(--study-tint);color:var(--study-ink)}
.row[data-tone="violet"] .ri{background:var(--play-tint);color:var(--play-ink)}
.row[data-tone="pink"] .ri{background:var(--pink-tint);color:var(--pink-ink)}
.row[data-tone="gold"] .ri{background:var(--gold-tint);color:var(--gold-ink)}
.row .rb{min-width:0;flex:1}
.row .rt{display:block;font-weight:700;font-size:16.5px;line-height:1.3}
.row .rd{display:block;color:var(--ink-3);font-size:14.5px;line-height:1.4;margin-top:2px}
.row .rx{flex:none;color:var(--ink-3);font-size:14px;font-variant-numeric:tabular-nums}

/* ---- Game tiles: a white bubble with the art inside ---- */
.tiles{display:grid;gap:18px;grid-template-columns:repeat(auto-fill,minmax(min(100%,230px),1fr))}
@media (max-width:700px){.tiles{grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}}
.tile{display:block;min-width:0;color:var(--ink);background:var(--surface);border-radius:var(--r2);padding:8px 8px 12px;box-shadow:var(--shadow);
  border:2px solid transparent;transition:border-color .15s cubic-bezier(.22,1,.36,1),transform .15s cubic-bezier(.22,1,.36,1)}
.tile:hover{border-color:var(--play);transform:translateY(-2px)}
.tile .ti{display:block;position:relative;aspect-ratio:16/9;border-radius:12px;overflow:hidden;background:var(--sunk)}
.tile .ti img{display:block;width:100%;height:100%;object-fit:cover}
.tile .tt{display:block;font:600 17px/1.25 var(--f-display);margin:10px 6px 0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tile .tl{display:block;color:var(--ink-2);font-size:14.5px;line-height:1.35;margin:3px 6px 0;overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}
.tile .tm{display:block;color:var(--ink-3);font-size:13.5px;margin:5px 6px 0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.tile:focus-visible{outline-offset:3px}
@media (max-width:700px){.tile{padding:6px 6px 10px}.tile .tt{font-size:15.5px;margin:8px 4px 0}.tile .tl{font-size:13.5px;margin:2px 4px 0}.tile .tm{font-size:12.5px;margin:4px 4px 0}}
@media (prefers-reduced-motion:reduce){.tile:hover{transform:none}}
.mk{position:absolute;inset-inline-start:8px;top:8px;display:inline-flex;align-items:center;gap:5px;padding:4px 10px 4px 8px;border-radius:var(--chip);
  background:#ffe9c2;color:#6a3a00;font-size:12px;font-weight:700;line-height:1.2;box-shadow:0 1px 3px rgba(0,0,0,.25)}
.mk svg{flex:none}
.mk-desk{inset-inline-start:auto;inset-inline-end:8px;top:auto;bottom:8px;display:none;background:var(--navy);color:#fff}
@media (max-width:820px) and (pointer:coarse){.mk-desk{display:inline-flex}}

/* ---- Lens chips (game filters): coloured pills ---- */
.lenses{display:flex;gap:8px;overflow-x:auto;scrollbar-width:none;margin:0;padding:2px 2px 6px}
.lenses::-webkit-scrollbar{display:none}
.lenses a,.lenses .lens-more{flex:none;display:inline-flex;align-items:center;min-height:42px;padding:0 16px;font:700 15px/1 var(--f-body);color:var(--ink-2);
  background:var(--surface);border:2px solid var(--rule);border-radius:var(--pill);white-space:nowrap;cursor:pointer}
.lenses a:hover,.lenses .lens-more:hover{border-color:var(--blue)}
.lenses a[data-c="study"]{--c:var(--study);--ct:var(--study-tint);--ci:var(--study-ink)}
.lenses a[data-c="blue"]{--c:var(--blue);--ct:var(--blue-tint);--ci:var(--blue-ink)}
.lenses a[data-c="violet"]{--c:var(--play);--ct:var(--play-tint);--ci:var(--play-ink)}
.lenses a[data-c="pink"]{--c:var(--pink);--ct:var(--pink-tint);--ci:var(--pink-ink)}
.lenses a[data-c="gold"]{--c:var(--gold);--ct:var(--gold-tint);--ci:var(--gold-ink)}
.lenses a[data-c]{background:var(--ct);border-color:transparent;color:var(--ci)}
.lenses a[aria-current="page"]{background:var(--navy);border-color:var(--navy);color:#fff}
.lenses a[data-c][aria-current="page"]{background:var(--c);border-color:var(--c);color:#fff}
:root[data-theme="dark"] .lenses a[aria-current="page"]{background:#fff;color:#0b1626;border-color:#fff}
:root[data-theme="dark"] .lenses a[data-c][aria-current="page"]{color:#0b1626}

/* ---- Switch ---- */
.sw{display:inline-flex;align-items:center;gap:10px;cursor:pointer;font-size:15px;font-weight:600;color:var(--ink-2);min-height:44px;user-select:none}
.sw input{appearance:none;-webkit-appearance:none;margin:0;width:44px;height:26px;border-radius:13px;background:var(--rule-2);position:relative;cursor:pointer;flex:none;transition:background-color .15s cubic-bezier(.22,1,.36,1)}
.sw input::after{content:"";position:absolute;inset-inline-start:3px;top:3px;width:20px;height:20px;border-radius:50%;background:#fff;box-shadow:0 1px 2px rgba(0,0,0,.25);transition:transform .15s cubic-bezier(.22,1,.36,1)}
.sw input:checked{background:var(--study)}
.sw input:checked::after{transform:translateX(18px)}
.sw input:focus-visible{outline:2px solid var(--study-ink);outline-offset:2px}

/* ---- Content label (game page) ---- */
.clabel{display:inline-flex;align-items:flex-start;gap:8px;font-size:15px;color:var(--ink-2);margin:10px 0 0;padding:8px 14px;border-radius:var(--r1);background:var(--blue-tint)}
.clabel.mature{background:var(--warn-bg)}
.clabel svg{flex:none;margin-top:3px}
.clabel b{color:var(--ink)}
.clabel.mature b{color:var(--warn-ink)}
.clabel a{color:var(--blue-ink);font-weight:700;white-space:nowrap}

.note{background:var(--blue-tint);padding:12px 16px;border-radius:var(--r1);color:var(--ink-2);font-size:15px}

/* ---- Breadcrumbs ---- */
.crumbs{font-size:14px;color:var(--ink-3);margin:18px 0 0;display:flex;flex-wrap:wrap;align-items:center;gap:6px}
.crumbs a{color:var(--ink-3)}
.crumbs a:hover{color:var(--blue-ink);text-decoration:underline}
.crumbs .sep{opacity:.6}
@media (pointer:coarse){.crumbs{gap:0 6px}.crumbs a{display:inline-flex;align-items:center;min-height:40px}}

/* ---- Related links: soft chips ---- */
.related{margin:28px 0 0}
.related h2{font-size:19px;margin:0 0 10px}
/* Related guides and games under a tool: plain links with a small icon, not pills. */
.related ul{list-style:none;padding:0;margin:0;display:flex;flex-wrap:wrap;gap:0 26px}
.related a{display:inline-flex;align-items:center;gap:8px;min-height:40px;color:var(--blue-ink);font-weight:700;font-size:15.5px}
.related a svg{flex:none;color:var(--ink-3)}
.related a:hover{text-decoration:underline;text-underline-offset:3px}

/* ---- Forms ---- */
/* Typed numbers use proportional digits. Onest's tabular figures are all 672 units wide (its "1" is 363),
   so tabular-nums in a field made "123123123" read as "1 2 3 1 2 3". Keep tabular-nums for aligned columns
   and ticking timers only. */
input,textarea,select,output{font-variant-numeric:normal;font-feature-settings:normal;letter-spacing:normal}
/* Form controls take the page's font (browsers give them a system font of their own). Line height stays the
   browser's on one-line controls, so no button grows taller than it was. */
button,input,select,textarea{font:inherit}
button,input,select{line-height:normal}
/* Every select: no native arrow, one chevron (12 x 8, 2 px stroke, the text colour), 16 px from the right edge, and
   room for it so long text never runs underneath. !important because components set the background shorthand. */
select:not([multiple]):not([size]){-webkit-appearance:none;appearance:none;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5l5 5 5-5' fill='none' stroke='%2315365a' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E")!important;
  background-repeat:no-repeat!important;background-position:right 16px center!important;background-size:12px 8px!important;
  padding-inline-end:44px!important;text-overflow:ellipsis}
/* right to left (ar): the chevron sits at the inline end too, where the padding already leaves room for it */
[dir="rtl"] select:not([multiple]):not([size]){background-position:left 16px center!important}
:root[data-theme="dark"] select:not([multiple]):not([size]){
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5l5 5 5-5' fill='none' stroke='%23c8d7e8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E")!important}
select::-ms-expand{display:none}
select:focus-visible{outline:2px solid var(--study-ink)!important;outline-offset:2px}
select:disabled{opacity:.55;cursor:not-allowed}
.input,.select{background:var(--surface);border:2px solid var(--rule-2);border-radius:var(--r1);padding:11px 14px;color:var(--ink);font:inherit;outline:none}
.input:focus,.select:focus{border-color:var(--blue)}

/* ---- Segmented control: the one style for tab pairs and option switches (account sign-in tabs,
   theme picker in the phone menu and on the account page, calculator modes). A soft track, no outline,
   and the chosen option filled with the study colour in both themes. ---- */
:root{--seg-track:var(--sunk)}
:root[data-theme="dark"]{--seg-track:rgba(157,179,201,.12)}
.segc{display:grid;grid-auto-flow:column;grid-auto-columns:minmax(0,1fr);gap:4px;padding:4px;margin:0;border:0;border-radius:12px;background:var(--seg-track)}
.segc > button{min-height:40px;padding:0 12px;border:0;border-radius:9px;background:transparent;color:var(--ink-2);
  font:700 15px/1.15 var(--f-body);cursor:pointer;box-shadow:none;-webkit-tap-highlight-color:transparent}
.segc > button:hover{color:var(--ink);background:rgba(var(--ink-rgb),.07)}
.segc > button[aria-selected="true"],.segc > button[aria-checked="true"],.segc > button[aria-pressed="true"]{background:var(--study-btn);color:var(--on-study-btn)}
:root[data-theme="dark"] .segc > button[aria-selected="true"],:root[data-theme="dark"] .segc > button[aria-checked="true"],:root[data-theme="dark"] .segc > button[aria-pressed="true"]{color:#04161c}
.segc > button:focus-visible{outline:2px solid var(--study-ink);outline-offset:2px}
.segc.many{display:flex;flex-wrap:wrap;border-radius:12px}
.segc.many > button{flex:1 1 auto;border-radius:9px}
@media (pointer:coarse){.segc > button{min-height:44px}}
@media (prefers-reduced-motion:reduce){.segc > button{transition:none}}

/* ---- Legacy card ---- */
.grid{display:grid;gap:18px;grid-template-columns:repeat(4,1fr)}
@media (max-width:1100px){.grid{grid-template-columns:repeat(3,1fr)}}
@media (max-width:720px){.grid{grid-template-columns:repeat(2,1fr)}}
.card{background:var(--surface);border-radius:var(--r2);box-shadow:var(--shadow);overflow:hidden;display:flex;flex-direction:column}
.thumb{aspect-ratio:16/9;overflow:hidden;position:relative}
.thumb img{width:100%;height:100%;object-fit:cover;display:block}
.content{padding:12px 14px 14px;display:flex;flex-direction:column;gap:6px}
.gtitle{font-weight:700;font-size:16px}
.desc{color:var(--ink-3);font-size:14px}
.chip{padding:6px 12px;border-radius:var(--chip);background:var(--blue-tint);font-size:14px}
footer{color:var(--ink-3)}
:root[data-theme="dark"] .fc-back{background:#1b2f4b}
:root[data-theme="dark"] .ntoast button{color:#08707a}
:root[data-theme="dark"] .reveal-card{background:#1b2f4b}
:root[data-theme="dark"] .prose p{color:var(--ink-2)}
:root[data-theme="dark"] #editor mark{color:#15365a}

/* ---- Guide covers (home shelf + guides index) ---- */
.gshelf{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:16px}
@media (max-width:1000px){.gshelf{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (max-width:560px){.gshelf{display:flex;overflow-x:auto;scroll-snap-type:x mandatory;padding:4px 2px 10px;margin:0 -16px;padding-inline-start:16px;scrollbar-width:none}
  .gshelf::-webkit-scrollbar{display:none}.gshelf .gcov{flex:0 0 76%;scroll-snap-align:start}}
.gcov{display:flex;flex-direction:column;background:var(--surface);border-radius:var(--r2);padding:8px 8px 16px;box-shadow:var(--shadow);color:var(--ink);
  border:2px solid transparent;transition:border-color .15s cubic-bezier(.22,1,.36,1),transform .15s cubic-bezier(.22,1,.36,1)}
.gcov:hover{border-color:var(--blue);transform:translateY(-2px)}
.gcov .gc-art{position:relative;display:flex;align-items:flex-end;justify-content:flex-end;height:132px;border-radius:12px;background:var(--blue-tint);overflow:hidden;padding:0 14px}
.gcov .gc-art img{width:104px;height:auto;margin-bottom:-6px}
.gcov .gc-art.is-hero{height:auto;aspect-ratio:8/5;padding:0}
.gcov .gc-art.is-hero img{width:100%;height:100%;object-fit:cover;margin:0}
.gcov[data-tone="teal"] .gc-art{background:var(--study-tint)}
.gcov[data-tone="violet"] .gc-art{background:var(--play-tint)}
.gcov[data-tone="pink"] .gc-art{background:var(--pink-tint)}
.gcov[data-tone="gold"] .gc-art{background:var(--gold-tint)}
.gcov .gc-min{position:absolute;inset-inline-start:12px;top:12px;background:var(--surface);color:var(--ink-2);font-size:12.5px;font-weight:700;padding:4px 10px;border-radius:var(--chip)}
.gcov .gc-t{display:block;font:600 18px/1.25 var(--f-display);margin:12px 8px 0}
.gcov .gc-l{display:block;color:var(--ink-3);font-size:14.5px;line-height:1.45;margin:6px 8px 0}
@media (prefers-reduced-motion:reduce){.gcov:hover{transform:none}}

/* ---- Ad slots (components/ad-slots.php): reserved IAB sizes, house promo until a zone code is set ---- */
.adslot{display:flex;flex-direction:column;align-items:center;margin:0 auto;width:100%;max-width:100%;min-width:0}
.adslot .adl{font-size:11.5px;font-weight:600;letter-spacing:.04em;color:var(--ink-3);margin:0 0 4px}
.adslot .adbox{position:relative;width:var(--aw);height:var(--ah);max-width:100%;border-radius:12px;overflow:hidden;background:var(--sunk);contain:strict}
.ad-leader{--aw:320px;--ah:100px}
@media (min-width:760px){.ad-leader{--aw:728px;--ah:90px}}
@media (min-width:1100px){.ad-leader{--aw:970px;--ah:90px}}
.ad-rect{--aw:300px;--ah:250px}
/* A house promo is ours, not a fixed-size ad: it spans its column so it lines up with the content. */
.adslot[data-ad-state="house"].ad-leader .adbox{width:100%}
.ad-sky{--aw:160px;--ah:600px}
.ad-tall{--aw:300px;--ah:250px}
@media (min-width:1100px){.ad-tall{--aw:300px;--ah:600px}}
.house{display:flex;align-items:center;gap:14px;width:100%;height:100%;padding:10px 18px;color:#fff;text-decoration:none;background:var(--navy)}
.house > span:first-child{min-width:0}
.house .hm{display:block;font:600 12.5px/1 var(--f-mono);color:#7ad7de;margin-bottom:4px}
.house b{font:600 18px/1.15 var(--f-display);display:block}
.house span.hs{font-size:13.5px;color:#c7d8ea;display:block;line-height:1.3;margin-top:2px}
.house .hb{margin-inline-start:auto;flex:none;background:var(--gold);color:#3a2700;font-weight:700;font-size:14px;border-radius:var(--pill);padding:8px 16px}
.house.study{background:#0d9aa7}
.house.study .hm{color:#e3fbfb;font-family:var(--f-body);font-variant-numeric:tabular-nums}
.house.study span.hs{color:#e3fbfb}
.house.tall{flex-direction:column;justify-content:center;text-align:center;padding:20px 16px;gap:16px}
.house.tall .hb{margin:0}
.house.tall b{font-size:22px}
.ad-leader:not(.x) .house span.hs{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
@media (max-width:759px){.ad-leader .house{padding:8px 12px;gap:10px}.ad-leader .house b{font-size:16px}.ad-leader .house span.hs{font-size:12.5px}.ad-leader .house .hb{padding:6px 12px;font-size:13px}}
:root[data-theme="dark"] .house{background:#13304f}
:root[data-theme="dark"] .house.study{background:#0b7680}

/* ---- Play page (dark immersive variant kept for compatibility) ---- */
body.theme-dark{--paper:#0b1626;--surface:#12233a;--ink:#fff;--ink-3:#9db3c9;background:var(--paper);color:var(--ink)}

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important;scroll-behavior:auto!important}
}
/* Touch: tapping or long-pressing a control never selects text or opens the iOS callout. Results, working, notes and
   every input stay selectable, so answers can still be copied. Tools add their own surfaces with [data-press]. */
button,.btn,.segc,[role="tab"],[role="radio"],[role="button"],[role="switch"],summary,.sw,canvas,label:has(> input[type="checkbox"]),label:has(> input[type="radio"]),
.blk-key,.blk-tile,.fc-card,.fp-learn-card,.pt-cell,.tt-kb,.tt-keyline,.evblock,.gc-dot,.simtile,[data-press]{-webkit-user-select:none;user-select:none;-webkit-touch-callout:none}
a,button,.btn,label,summary,canvas,[role="tab"],[role="radio"],[role="button"],[data-press]{-webkit-tap-highlight-color:transparent}
input,textarea,select,[contenteditable="true"],[contenteditable=""]{-webkit-user-select:text;user-select:text;-webkit-touch-callout:default}
/* Keyboard-shortcut hints are noise on a touch-only device. tools/_shell.php sets html.bl-touch when the device has
   no hover and a coarse pointer, and takes it off again the first time a hardware keyboard is used (an iPad with a
   keyboard keeps its hints). Mark a hint with .kbd-only; .kbd key caps and .kbd-row/.kbd-hint lines go too. */
html.bl-touch .kbd-only,html.bl-touch .kbd,html.bl-touch .kbd-row,html.bl-touch .kbd-hint{display:none!important}
/* Game music switch (includes/components/game-audio.php, assets/js/bl-audio.js): printed only when a game has a track. */
.bl-music[aria-pressed="true"]{border-color:var(--study);color:var(--study-ink)}

/* Coming up: signed-in homepage and account page (includes/components/coming-up.php). A plain list, no cards. */
.cu{margin:28px 0 40px;max-width:780px}
.cu h2{font-size:20px;margin:0 0 8px}
.cu-list{list-style:none;margin:0;padding:0;border-top:1px solid var(--rule)}
.cu-list a{display:grid;grid-template-columns:7.5em minmax(0,1fr) auto;gap:2px 16px;align-items:baseline;padding:11px 2px;border-bottom:1px solid var(--rule);color:var(--ink);text-decoration:none}
.cu-list a:hover .cu-what{text-decoration:underline;text-underline-offset:3px}
.cu-when{font-weight:700;color:var(--ink-2);font-size:15px;font-variant-numeric:tabular-nums}
.cu-when small,.cu-what small{display:block;font-weight:500;color:var(--ink-3);font-size:13.5px;margin-top:1px}
.cu-what{font-weight:600;font-size:16px}
.cu-kind{color:var(--ink-3);font-size:13.5px;font-weight:600;text-align:end}
.cu-list li.od .cu-when,.cu-list li.od .cu-kind{color:var(--bad)}
.cu.cu-acc{max-width:none;margin:22px 0 0;padding-top:18px;border-top:1px solid var(--rule);text-align:start}
.cu.cu-acc h2{font-size:18px}
.cu.cu-acc .cu-list{border-top:0}
.cu.cu-acc .cu-list li:last-child a{border-bottom:0}
@media (max-width:520px){.cu-list a{grid-template-columns:6.2em minmax(0,1fr)}.cu-kind{grid-column:2;text-align:start}}

/* ---- Courses page (includes/courses.php): hero, level control, course cards with covers, how courses work ----
   Each card takes its subject's colour from the role tokens (--c base, --ci ink, --ct tint), so the cover art and
   markers follow the light and dark themes; the Code tracks keep their own colours (brand/identity/tokens.json). */
.cs{padding-top:28px;padding-bottom:40px}
.cs-hero{display:flex;align-items:flex-end;justify-content:space-between;gap:24px}
.cs-hero h1{margin:0 0 10px;font-weight:600}
.cs .lead{font-size:19px;color:var(--ink-2);max-width:62ch;margin:0;line-height:1.55}
.cs .cs-note{color:var(--ink-3);font-size:15px;margin:10px 0 0;max-width:70ch}
.cs-hero-nd{flex:none;width:120px;height:auto;margin-bottom:-6px}
@media (max-width:640px){.cs-hero-nd{display:none}}
.cs-lvnav{display:flex;gap:4px;margin:26px 0 0;padding:4px;background:var(--sunk);border-radius:14px;width:max-content;max-width:100%;overflow-x:auto;scrollbar-width:none}
.cs-lvnav::-webkit-scrollbar{display:none}
.cs-lvnav a{flex:none;padding:9px 16px;border-radius:10px;color:var(--ink-2);font-weight:700;font-size:15px;line-height:1.2;transition:background-color .15s cubic-bezier(.22,1,.36,1),color .15s cubic-bezier(.22,1,.36,1)}
.cs-lvnav a:hover{color:var(--ink)}
.cs-lvnav a[aria-current="true"]{background:var(--surface);color:var(--ink);box-shadow:var(--shadow)}
@media (max-width:600px){.cs-lvnav{width:100%}.cs-lvnav a{flex:1 0 auto;text-align:center;padding:9px 10px}}
.cs-sec{scroll-margin-top:84px}
.cs-sec[hidden]{display:none}
.cs h2{margin:44px 0 6px}
.cs .sec-p{color:var(--ink-2);max-width:70ch;margin:0;line-height:1.55}
.cs a.tl{color:var(--study-ink);font-weight:700;text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:3px}
.cs-more{margin:18px 0 0}
.cs-ucas{margin:18px 0 0;color:var(--ink-2);max-width:70ch;line-height:1.55}
.cs-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:18px;margin-top:18px}
.cs-grid.is-4{grid-template-columns:repeat(4,minmax(0,1fr))}
@media (max-width:1100px){.cs-grid.is-4{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (max-width:900px){.cs-grid{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (max-width:600px){.cs-grid,.cs-grid.is-4{grid-template-columns:1fr}}
.crs{--c:var(--blue);--ci:var(--blue-ink);--ct:var(--blue-tint);display:flex;flex-direction:column;background:var(--surface);border-radius:var(--r2);padding:8px;
  box-shadow:var(--shadow);color:var(--ink);border:2px solid transparent;transition:transform .2s cubic-bezier(.22,1,.36,1),border-color .15s cubic-bezier(.22,1,.36,1),box-shadow .2s cubic-bezier(.22,1,.36,1)}
a.crs:hover{transform:translateY(-3px);border-color:var(--c);box-shadow:0 2px 4px rgba(21,54,90,.07),0 12px 26px rgba(21,54,90,.11)}
a.crs:active{transform:translateY(-1px);box-shadow:var(--shadow);transition-duration:.09s}
a.crs:focus-visible{outline:3px solid var(--study-ink);outline-offset:2px}
.crs.is-soon{background:transparent;box-shadow:none;border-color:var(--rule-2)}
.crs[data-s="science"]{--c:var(--study);--ci:var(--study-ink);--ct:var(--study-tint)}
.crs[data-s="cs"]{--c:var(--play);--ci:var(--play-ink);--ct:var(--play-tint)}
.crs[data-s="music"]{--c:var(--music);--ci:var(--music-ink);--ct:var(--music-tint)}
.crs[data-s="python"]{--c:#ffc83d;--ci:#7f5b00;--ct:#fcecc0}
.crs[data-s="web"]{--c:#ff7a3d;--ci:#a8420f;--ct:#fdd9c4}
.crs[data-s="sql"]{--c:#3a9be8;--ci:#1b65a6;--ct:#cfe3f4}
.crs[data-s="c"]{--c:#f0567e;--ci:#b8204b;--ct:#f9d3db}
:root[data-theme="dark"] .crs[data-s="python"]{--ci:#ffcf5c;--ct:#2a2614}
:root[data-theme="dark"] .crs[data-s="web"]{--ci:#ff9a66;--ct:#2c1d18}
:root[data-theme="dark"] .crs[data-s="sql"]{--ci:#74b9f2;--ct:#13304f}
:root[data-theme="dark"] .crs[data-s="c"]{--ci:#ff819f;--ct:#2e1726}
:root[data-theme="dark"] a.crs:hover{box-shadow:0 12px 26px rgba(0,0,0,.35)}
/* the thumbnail (brand/mascot/course-thumbs.cjs): a 400 x 250 scene per course, light and dark; the box keeps its
   ratio so nothing shifts while it loads */
.crs-cov{position:relative;display:block;aspect-ratio:8/5;border-radius:12px;background:var(--ct);overflow:hidden}
.crs-th{display:block;width:100%;height:100%}
.crs-th.th-dark,:root[data-theme="dark"] .crs-th.th-light{display:none}
:root[data-theme="dark"] .crs-th.th-dark{display:block}
.crs-art{position:absolute;inset-inline-end:8px;top:5px;width:calc(100% - 96px);max-width:230px;height:140px}
.crs-art .l{fill:none;stroke:var(--ci);stroke-width:3.5;stroke-linecap:round;stroke-linejoin:round}
.crs-art .g{fill:none;stroke:var(--ci);stroke-width:2;stroke-linecap:round;opacity:.3}
.crs-art .a{fill:none;stroke:var(--c);stroke-width:6;stroke-linecap:round;stroke-linejoin:round}
.crs-art .f{fill:var(--c)}
.crs-art .s{stroke:var(--ci);stroke-width:2.5}
.crs-art .p{fill:var(--surface)}
.crs-art .k{fill:var(--ci)}
.crs-art .t{fill:var(--ci);font:700 19px/1 var(--f-body)}
.crs-art .t.big{font:700 38px/1 var(--f-mono)}
.crs-b{display:flex;flex-direction:column;gap:6px;flex:1;padding:14px 10px 8px}
.crs-t{font:600 19px/1.25 var(--f-display)}
.crs-d{color:var(--ink-2);font-size:15.5px;line-height:1.5}
.crs-n{color:var(--ink);font-size:14.5px;font-weight:700}
.crs-mk{display:flex;flex-wrap:wrap;gap:4px 16px;margin:2px 0 10px;color:var(--ink-3);font-size:14px}
.crs-mk span{display:inline-flex;align-items:center;gap:5px}
.crs-mk svg{width:16px;height:16px;fill:none;stroke:var(--ci);stroke-width:2.4;stroke-linecap:round;stroke-linejoin:round}
.crs-go{margin-top:auto;align-self:flex-start;background:var(--study-btn);color:var(--on-study-btn);font-weight:700;font-size:15.5px;line-height:1.2;padding:10px 16px;border-radius:12px;transition:background-color .15s cubic-bezier(.22,1,.36,1)}
a.crs:hover .crs-go{background:var(--study-btn-hover)}
.crs-soon{margin-top:auto;color:var(--ink-3);font-weight:700;font-size:15px;line-height:1.2;padding:10px 0}
.cs-how{margin-top:56px;padding:36px 0;background:var(--sunk);border-radius:0;box-shadow:0 0 0 100vmax var(--sunk);clip-path:inset(0 -100vmax)}   /* a square full-bleed band (owner, 10 Oct) */
.cs-how h2{margin:0 0 18px}
.cs-how ul{list-style:none;margin:0;padding:0;display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:22px}
@media (max-width:900px){.cs-how ul{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (max-width:480px){.cs-how{padding:26px 0}.cs-how ul{grid-template-columns:1fr;gap:18px}}
.cs-how li{display:flex;flex-direction:column;gap:4px}
.cs-how li svg{width:26px;height:26px;margin-bottom:4px;fill:none;stroke:var(--study-ink);stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
.cs-how li span{color:var(--ink-2);font-size:15.5px;line-height:1.5}
.cs-onward{display:flex;flex-wrap:wrap;gap:10px 28px;margin:24px 0 0}
@media (prefers-reduced-motion:reduce){.crs,.crs-go,.cs-lvnav a{transition:none}a.crs:hover,a.crs:active{transform:none}}

/* motion: the list stagger (T8, T10). Give a list .bl-stagger and its items arrive 35ms apart, capped at the sixth;
   transform and opacity only, content visible at rest, nothing under reduced motion */
@keyframes bl-stag-in{from{opacity:0;transform:translateY(6px)}}
.bl-stagger>*{animation:bl-stag-in var(--dur-enter) var(--ease-out) both}
.bl-stagger>:nth-child(2){animation-delay:calc(var(--stagger)*1)}.bl-stagger>:nth-child(3){animation-delay:calc(var(--stagger)*2)}
.bl-stagger>:nth-child(4){animation-delay:calc(var(--stagger)*3)}.bl-stagger>:nth-child(5){animation-delay:calc(var(--stagger)*4)}
.bl-stagger>:nth-child(n+6){animation-delay:calc(var(--stagger)*5)}
@media (prefers-reduced-motion:reduce){.bl-stagger>*{animation:none}}
:root[data-motion=off] .bl-stagger>*{animation:none}

/* Focus ring on lipped (3D) buttons (owner, 9 Oct: "the shadow is part of the button too"). An outline can only
   circle the face, so the lip hung below the ring. The ring is a pseudo-element that wraps the face and the lip:
   --lip is the lip's height (0 while pressed, when the lip collapses), --ring-r the ring's corner (the face's radius
   plus the 5 px gap), --ring its colour (study ink: 5.5:1 on the light page, 9:1 on the dark; Highlight in forced
   colours). .ibtn uses ::before: its ::after is the tooltip. */
:where(.lp-btn,.lq-tile,.lp-key,.plc-save,.plc-btn,.lr-go,.cp-go,.pm a.pm-cta,.pm-mini a.pm-cta,.b.spk-cta,.fp-th-b,.ct-big,.mt-key,.pr-btn.primary,
  .blm .blm-yes,.b-study,.b-play,.codeband .b-code,.ibtn.play,.keys button.eq,.deck-bar .btn,.btn.primary):focus-visible{position:relative}
:is(.lp-btn,.lq-tile,.lp-key,.plc-save,.plc-btn,.lr-go,.cp-go,.pm a.pm-cta,.pm-mini a.pm-cta,.b.spk-cta,.fp-th-b,.ct-big,.mt-key,.pr-btn.primary,
  .blm .blm-yes,.b-study,.b-play,.codeband .b-code,.ibtn.play,.keys button.eq,.deck-bar .btn,.btn.primary):focus-visible{outline:none}
:is(.lp-btn,.lq-tile,.lp-key,.plc-save,.plc-btn,.lr-go,.cp-go,.pm a.pm-cta,.pm-mini a.pm-cta,.b.spk-cta,.fp-th-b,.ct-big,.mt-key,.pr-btn.primary,
  .blm .blm-yes,.b-study,.b-play,.codeband .b-code,.keys button.eq,.deck-bar .btn,.btn.primary):focus-visible::after,
.ibtn.play:focus-visible::before{content:"";position:absolute;inset:-5px -5px calc(-5px - var(--lip,4px)) -5px;border:3px solid var(--ring,var(--study-ink));
  border-radius:var(--ring-r,inherit);pointer-events:none;z-index:1}
.lp-btn,.lq-tile,.plc-save,.plc-btn,.lr-go,.cp-go,.pm a.pm-cta,.pm-mini a.pm-cta,.mt-key{--lip:4px}
.lp-key,.b-study,.b-play,.codeband .b-code,.b.spk-cta,.pr-btn.primary,.blm .blm-yes,.keys button.eq,.deck-bar .btn,.btn.primary{--lip:3px}
.ct-big,.ibtn.play{--lip:5px}
.fp-th-b{--lip:4px;--ring-r:27px}
.lp-btn,.lq-tile,.pm a.pm-cta,.pm-mini a.pm-cta{--ring-r:21px}
.plc-save,.plc-btn,.lr-go,.cp-go,.mt-key,.b.spk-cta{--ring-r:19px}
.lp-key{--ring-r:17px}
.blm .blm-yes,.btn.primary,.b-study,.b-play,.codeband .b-code{--ring-r:999px}
.lp-btn.danger{--ring:var(--ln-leave,#c0362c)}
.pm a.pm-cta,.pm-mini a.pm-cta{--ring:#fff}
:is(.lp-btn,.lq-tile,.lp-key,.plc-save,.plc-btn,.lr-go,.cp-go,.pm-cta,.spk-cta,.fp-th-b,.mt-key,.pr-btn,.blm-yes,.b-study,.b-play,.b-code,.keys button,.deck-bar .btn,.btn.primary):active{--lip:0px}
.ct-big:active,.ibtn.play:active{--lip:2px}
@media (forced-colors:active){
  :is(.lp-btn,.lq-tile,.lp-key,.plc-save,.plc-btn,.lr-go,.cp-go,.pm-cta,.spk-cta,.fp-th-b,.ct-big,.mt-key,.pr-btn,.blm-yes,.b-study,.b-play,.b-code,.keys button,.deck-bar .btn,.btn.primary):focus-visible::after,
  .ibtn.play:focus-visible::before{border-color:Highlight}
}

/* ---- Motion (shared; owner, 11 Oct: "Find areas on the website to also improve the motion like the homepage"). The
   homepage's language for every page, from the same tokens (docs/plans/HOMEPAGE_REDESIGN.md, Motion rules): one
   easing with no bounce, 180 and 320 ms, 8 / 12 / 16 px, a lean of 6 degrees at most; transform and opacity only, so
   nothing moves the layout (CLS 0); nothing loops; reduced motion turns it all off. assets/js/bl-mo-cards.js picks the
   cards and blocks (one selector list) and sets .is-mo-in, --mo-i and the lean's --mx / --my. */
:root{--m-ease:cubic-bezier(.22,1,.36,1);--m-t1:180ms;--m-t2:320ms;--m-step:60ms;--m-d1:8px;--m-d2:12px;--m-d3:16px;--m-tilt:6deg;--m-enter:200ms;--m-enter-step:40ms;--m-enter-d:12px}
@media (pointer:coarse){:root{--m-enter-d:8px}}
/* entrances: drawn complete at rest; a block that was below the fold rises 12 px and fades in as it arrives, its row
   neighbours a step later */
/* Fast scrollers (owner, 11 Oct: "Consider fast scrollers on mobile"): an entrance is short (--m-enter, 200 ms, row
   neighbours 40 ms apart, at most 3 steps), starts 200 px before the block is on screen, rises 8 px on touch screens,
   and is skipped (the block is simply there) when the page is moving fast or more than 3 blocks arrive at once. */
.is-mo-in{animation:bl-mo-in var(--m-enter) var(--m-ease) both;animation-delay:calc(var(--mo-i,0) * var(--m-enter-step))}
@keyframes bl-mo-in{from{opacity:0;translate:0 var(--m-enter-d)}}
/* empty states arrive the same way whenever they are shown */
:is(.bt-empty,.cp-empty,.fc-empty,.lib-empty,.my-empty,.pp-empty,.mk-empty,.lr-empty-t):not([hidden]){animation:bl-mo-in var(--m-t2) var(--m-ease) both}
/* cards: one hover timing everywhere; with a mouse, on wide screens, a card leans toward the pointer and lifts */
:is(a.crs,a.tile,a.gk,a.rv-link,.pl-card,.acd-card){transition:transform var(--m-t2) var(--m-ease),box-shadow var(--m-t2) var(--m-ease),border-color var(--m-t1) var(--m-ease)}
@media (hover:hover) and (pointer:fine) and (min-width:1024px){
  [data-mo-tilt]{transform:perspective(900px) rotateX(calc(var(--my,0) * -3deg)) rotateY(calc(var(--mx,0) * var(--m-tilt))) translateY(var(--mo-lift,0px))}
  [data-mo-tilt]:hover{--mo-lift:-3px}
  [data-mo-tilt].is-mo-tilt{transition:transform 90ms linear,box-shadow var(--m-t2) var(--m-ease),border-color var(--m-t1) var(--m-ease)}
}
@media (prefers-reduced-motion:reduce){.is-mo-in,:is(.bt-empty,.cp-empty,.fc-empty,.lib-empty,.my-empty,.pp-empty,.mk-empty,.lr-empty-t){animation:none!important}[data-mo-tilt]{transform:none!important}}
html[data-motion="off"] :is(.is-mo-in,.bt-empty,.cp-empty,.fc-empty,.lib-empty,.my-empty,.pp-empty,.mk-empty,.lr-empty-t){animation:none!important}
html[data-motion="off"] [data-mo-tilt]{transform:none!important}

/* ---- Plus prompts (components/plus-nudge.php; owner, 11 Oct): one calm card, value first, the price, one teal action.
   At most one per page; none for members. */
.bl-pn{display:flex;align-items:center;gap:14px;margin:20px 0;padding:14px 16px;border-radius:var(--r2,16px);background:var(--study-tint);color:var(--ink)}
.bl-pn-mk{flex:none;display:grid;place-items:center}
.bl-pn-tx{flex:1 1 auto;min-width:0}
.bl-pn-tx h3{margin:0 0 2px;font:700 16.5px/1.3 var(--f-display)}
.bl-pn-tx p{margin:0;font-size:15px;line-height:1.5;color:var(--ink-2)}
.bl-pn-pr{white-space:nowrap;font-weight:650;color:var(--ink)}
.bl-pn-go{flex:none;display:inline-flex;align-items:center;min-height:44px;padding:0 16px;border-radius:var(--pill);background:var(--study-btn,var(--study));color:var(--on-study-btn,#fff);font:700 15px/1 var(--f-body);text-decoration:none;white-space:nowrap}
.bl-pn-go:hover{background:var(--study-btn-hover,var(--study))}
.bl-pn-go:focus-visible{outline:2px solid var(--blue);outline-offset:2px}
@media (max-width:560px){.bl-pn{flex-wrap:wrap}.bl-pn-tx{flex-basis:calc(100% - 40px)}.bl-pn-go{width:100%;justify-content:center}.bl-pn-pr{white-space:normal}}
.shop-plus-pr{margin:6px 0 12px;font-weight:650;color:var(--ink)}
/* the quiet card beside a Buy button (a pack's or a bundle's page): the same card, See plans as a text link */
.bl-pn.bl-pn-q{margin:10px 0;padding:12px 14px;gap:12px;flex-wrap:wrap}
.bl-pn.bl-pn-q .bl-pn-tx{flex-basis:calc(100% - 40px)}
.bl-pn.bl-pn-q .bl-pn-go{min-height:auto;padding:0;margin-inline-start:34px;background:none;box-shadow:none;color:var(--study-ink);text-decoration:underline;text-underline-offset:3px;font-size:14.5px}
.bl-pn.bl-pn-q .bl-pn-pr{white-space:normal}
@media (max-width:560px){.bl-pn.bl-pn-q .bl-pn-go{width:auto;max-width:calc(100% - 34px);min-width:0;white-space:normal}}   /* the quiet card's link is never wider than its row (it overflowed by its 34 px indent at 320 and 390) */
.bl-pn.bl-pn-q.lp-pn{text-align:start}.bl-pn.bl-pn-q.lp-pn .bl-pn-tx{flex-basis:100%}.bl-pn.bl-pn-q.lp-pn .bl-pn-go{margin:4px auto 0 0}   /* the lesson's end (learn.js): no mark, so the link lines up with the text */
.bl-pn-tx h3{color:var(--ink)}

/* the lesson's end (owner, 11 Oct; the player's own learn.css is another agent's open file): every secondary step a
   small quiet button, left-aligned (Next lesson in the bar stays the one main action); no single word left alone */
.lp-btn.lp-btn-s{display:inline-flex;align-items:center;justify-content:center;min-height:44px;padding:0 18px;font-size:15.5px;text-decoration:none;width:auto}
.lp-done-body .lr-after{margin:16px 0 0;text-align:start}
.lp-done-body .bl-pn.lp-pn{flex-direction:column;align-items:flex-start;gap:10px;text-align:start}
.lp-done-body .bl-pn.lp-pn .bl-pn-tx p{color:var(--ink-2)}
.lp-done-body :is(p,li,h2,h3),.lh-card :is(p,li,span){text-wrap:pretty}
.lp-done h1,.lp-done-body h2,.lh-card h2{text-wrap:balance}

/* course pages (owner, 11 Oct: "make it more clear that the first lesson is free"; the player's course.css is another
   agent's open file, so these sit here, prefixed to outrank it): a teal Free pill on a free lesson among locked ones,
   and its Up next label reads "Free lesson" */
.lsr-free{display:inline-flex;align-items:center;margin-inline-start:8px;padding:2px 9px;border-radius:999px;background:var(--study-tint);color:var(--study-ink);font:700 12.5px/1.35 var(--f-body);vertical-align:2px;white-space:nowrap}
:root[data-theme="dark"] .lsr-free{background:color-mix(in srgb,var(--study) 30%,var(--surface));color:#bff3f0}
.cp .lsr.is-next[data-free] .lsr-t::before,.ln-page .lsr.is-next[data-free] .lsr-t::before{content:"Free lesson"}
.cp .cp-facts a{color:inherit;font-weight:700}
.lsr.is-next .lsr-free{display:none}   /* its label already says Free lesson, and its button Start free */
@media (max-width:480px){   /* phones: compact unit cards, every toggle a 44 px target */
  .cp .cp-units{gap:10px}
  .cp .cp-u .cp-uh{padding:10px 12px;gap:10px}
  .cp .cp-u .cp-tog{min-height:44px;margin:-6px 0 -8px}
}
@media (max-width:380px){   /* the grade switcher on one row: the "Grade" label takes only its width (it grew to 92 px and pushed the last grade onto a line alone) */
  .cp .cp-sw.is-grades{flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none}
  .cp .cp-sw.is-grades .cp-sw-k{flex:none;width:auto}
}
/* the lesson player (owner, 11 Oct): no row under the top bar; its line holds the course name as plain context */
.lp-unavrow{display:none}
.lp-loc{white-space:nowrap;max-width:100%;flex-shrink:1;min-width:0}
span.lp-loc{display:inline-flex}
.lp-loc-c{overflow:hidden;text-overflow:ellipsis;min-width:0}
.lp-loc-w{flex:none}
/* the course hero (owner, 11 Oct, "best design?"): a one-line Start free lesson, then the facts, then a small muted plan line */
.cp .cp-go.is-one{align-items:center;align-content:center;grid-template-rows:auto;min-height:66px}   /* the two-line button's height: a returning learner's Continue (course.js) moves nothing below */
.cp .cp-go.is-one > span{grid-row:1;align-self:center}
.cp .cp-go.is-one > svg{grid-row:1;align-self:center}
.cp .cp-plus-l{margin:4px 0 0;color:var(--ink-3);font-size:14px;line-height:1.45}
.cp .cp-plus-l a{color:inherit;font-weight:650;text-decoration:underline;text-underline-offset:2px}
.cp .cp-promise{text-wrap:pretty}
/* the question's answer area (owner, 11 Oct: "feels unlevel"; learn.css is another agent's open file): one toolbar of
   tools, Calculator, Show a hint and Review the lesson, each 44 px, centred on one line; and the content always clears
   the sticky bottom bar by 16 px (--lp-foot-h, set by learn.js) */
body.ln-play .lq-aids{align-items:center;gap:10px}
body.ln-play .lq-aids > :is(.lq-aid,.lq-calcbtn){box-sizing:border-box;height:44px;min-height:44px;display:inline-flex;align-items:center;gap:8px;padding:0 14px;margin:0;font-size:15px;line-height:1}
body.ln-play .lq-aids > .lq-calcbtn{border-radius:12px}
body.ln-play .lp-stage{padding-bottom:calc(var(--lp-foot-h, 96px) + 16px)}
body.ln-play .lp-foot .lp-actions{max-width:var(--lp-col-w, 900px)}   /* Check ends at the content's edge (learn.js sets the stage's width) */
@media (max-width:600px){
  span.lp-loc{flex-wrap:wrap}
  .lp-loc-c{flex-shrink:0;overflow:visible}   /* on a phone the line has its own row: the course name whole, never "GCSE..." */
}
@media (max-width:480px){   /* the tools on a phone (owner, 11 Oct): one row of equal buttons, the icon over a short label, 44 px tall */
  body.ln-play .lq-aids{flex-wrap:nowrap;gap:8px}
  body.ln-play .lq-aids > :is(.lq-aid,.lq-calcbtn){flex:1 1 0;min-width:0;flex-direction:column;justify-content:center;gap:2px;padding:0 4px;font-size:12.5px;line-height:1.1}
  body.ln-play .lq-aids > :is(.lq-aid,.lq-calcbtn)[data-short] > :is(.t, span:not([aria-hidden])){display:none}
  body.ln-play .lq-aids > :is(.lq-aid,.lq-calcbtn)[data-short]::after{content:attr(data-short);white-space:nowrap}
  body.ln-play .lq-aids > :is(.lq-aid,.lq-calcbtn) svg{width:18px;height:18px;flex:none}
  /* the symbol pads fill their rows evenly: six columns; the Working pad's More takes two (10 keys and More: two rows of 6) */
  body.ln-play .lq-syms{display:grid;grid-template-columns:repeat(6,minmax(0,1fr));gap:6px}
  body.ln-play .lq-syms > .lq-sym{min-width:0;width:100%;padding:0}
  body.ln-play .lq-syms > .lq-symmore{grid-column:span 2}
}
/* the course page's Practise strip (owner, 11 Oct: "the Flashcards card is too tall for no reason"): on a wide screen
   the three cards are as tall as the tallest one's real content, with no reserved space (the cards' reserve stays on a
   phone, where the cards stack and filling the count would otherwise move the page) */
@media (min-width:701px){
  .cp .lr-panel.pp-strip .pp-cards,.cp .lr-panel.pp-strip .pp-cards.has-3{align-items:stretch}
  .cp .lr-panel.pp-strip.pp-rsv-cd [data-part="cards"] .pp-foot{min-height:0}
}

/* the question screen (owner, 11 Oct): the title, marks and timer stay at the top, under the bar; only the question's
   body (the stem, the answer and Hint) is centred in the room left above the bottom bar, and a body taller than that
   room simply starts under the header. The loading shape does the same, so nothing moves when the question arrives. */
.lp-stage:has(> #lpDyn > .lp-q.is-on)::before,.lp-stage:has(> #lpDyn > .lp-q.is-on)::after{content:none}
.lp-stage > #lpDyn:has(> .lp-q.is-on){flex:1 0 auto;display:flex;flex-direction:column}
#lpDyn > .lp-q.is-on{flex:1 0 auto;display:flex;flex-direction:column}
.lp-q.is-on > .lp-skel{flex:1 0 auto;grid-template-rows:auto auto 1fr}
.lp-q.is-on > .lp-skel > .lp-skel-b{align-self:center}
.lp-q.is-on > .lq-ctx{flex:none}
.lp-top > .lp-loc{flex-wrap:nowrap;box-sizing:border-box;min-width:0;max-width:100%;overflow:hidden}   /* one line, inside the column: only the course name shortens ("…") */
.lp-top > .lp-loc > .lp-loc-c{flex:0 1 auto;min-width:0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}
.lp-top > .lp-loc > .lp-loc-w{flex:none}
@media (max-width:359px){.lp-top > .lp-loc > .lp-loc-c{display:none}}   /* under 360 px: "Unit 10, Lesson 2 of 3" alone */
.lp-q.is-on > .lq{flex:1 0 auto;display:flex;flex-direction:column;position:relative}
.lp-q.is-on > .lq > *{flex:none}
.lp-q.is-on > .lq > .ls-read{position:absolute;top:6px;right:-6px;margin:0}
.lp-q.is-on > .lq:has(> .ls-read) > .lq-title{padding-inline-end:46px}
/* Quick recall: its header row holds only the pill, "1 of 3" and Skip, on one centre line */
.lp-q.is-on > .lq.lr-q > .lr-top{min-height:44px;margin-top:0;align-items:center}
@media (max-width:420px){.lp-q.is-on > .lq.lr-q > .lr-top{gap:6px}}
/* read aloud on a question (owner, 11 Oct): one place on every question type, the top right of Noodle's bubble (or of
   the shared stem), a 44 px target, floated so a long stem does not lose a column; the bubble redraws when it joins */
/* a 44 x 44 button (the icon its usual size) floated at the start of the text; negative margins let it hang into the
   bubble's padding, so the text makes room for only about 30 x 26 and at most the first line moves */
.lq .ls-read.ls-inq{float:right;position:relative;width:44px;height:44px;margin:-10px -14px -8px 2px;z-index:1}
.lq > .lq-stem .ls-read.ls-inq,.lq > .lq-part > .lq-prompt .ls-read.ls-inq{margin:-10px -10px -8px 4px}
.lp-q.is-on > .lq > :is(.ls-read,.lq-title,.lq-upnote,.lq-mkh,.lq-pace,.lr-top) + :not(.ls-read,.lq-title,.lq-upnote,.lq-mkh,.lq-pace,.lr-top){margin-top:auto}
.lp-q.is-on > .lq::after{content:'';flex:none;margin-top:auto}
/* the header and the body are two groups (owner, 11 Oct): a larger gap after the header than between the body's blocks */
.lp-q.is-on > .lq{--lq-head-gap:22px}
.lp-q.is-on > .lq > :is(.lq-title,.lq-upnote,.lq-mkh,.lq-pace,.lr-top):not(:has(~ :is(.lq-title,.lq-upnote,.lq-mkh,.lq-pace,.lr-top))){margin-bottom:var(--lq-head-gap)}
/* where a question with a figure is two columns, the columns keep their own layout, top-aligned */
@media (min-width:1000px){.lp-q.is-on > .lq.has-vis{display:grid;flex:none}.lp-q.is-on > .lq.has-vis > .ls-read{position:static;margin:6px 0 0}.lp-q.is-on > .lq.has-vis::after{content:none}}
/* Mixed review (owner, 11 Oct): the top bar stays one row (close, progress, the small icons); the review's label is
   one quiet line over the question's title, shortened with an ellipsis when it is long */
.lp-top .lr-meta{display:none}
.lq-ctx{margin:8px 0 -4px;color:var(--ink-3);font-size:14px;font-weight:650;line-height:1.35;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0}
/* the lesson's line under the bar on a phone starts where the bar starts (owner, 11 Oct), one line */
@media (max-width:560px){.lp-top > .lp-loc{padding-inline-start:58px;justify-content:flex-start}}
@media (max-width:440px){.lp-top > .lp-loc{padding-inline-start:46px}}
@media (max-width:359px){.lp-top > .lp-loc{padding-inline-start:44px}}
/* the question's body (owner, 11 Oct: "feels unlevel"): the bubble row, Working, the answer and the tools share the
   column's two edges, and one gap sits between each of them. The answer box grows to the right edge beside its label. */
body.ln-play .lq-part{--lq-gap:12px}
body.ln-play .lq-part > .lq-say{margin-bottom:0}
body.ln-play .lq-part > :is(.lq-work,.lq-in,.lq-aids){margin-top:var(--lq-gap)}
body.ln-play .lq-part > .lq-work{margin-bottom:0}
body.ln-play .lq-part > :is(.lq-work,.lq-in,.lq-aids) > :first-child{margin-top:0}   /* no inner margin adds to the gap (a drawn answer's grid had 14 px) */
body.ln-play .lq-line > .lq-fu{flex:1 1 0;max-width:none;min-width:min(100%,160px)}
body.ln-play .lq-line > .lq-fu > .lq-field,body.ln-play .lq-line > .lq-field{flex:1 1 auto;width:auto;min-width:0}
body.ln-play .lq-in .lq-read:empty{display:none}   /* the "reads as" line takes room only when it says something, so the gaps stay even */
/* the player's top bar (owner, 11 Oct: "misuse of space"): the progress bar takes the room between the close button
   (and the lesson's line) and the right-hand icons, up to 1100 px on very wide screens, centred there; the icons
   (settings, Sparks, sound) sit together with one even gap, and the Sparks counter is only as wide as its number.
   On a locked lesson, where no Sparks counter comes, no empty slot is kept for it. */
.lp-top > .lp-bar{flex:1 1 auto;min-width:48px}
@media (min-width:1600px){.lp-top > .lp-bar{max-width:1100px;margin-inline:auto}}
.lp-top > .lh-topcount{width:auto;min-width:44px;padding:0 8px}
.lp-top > :is(.lh-topcount,.lp-snd){margin-inline-start:-6px}   /* settings (order 10) leads the group; Sparks (11) and sound (12) follow it closely */
.lp-top:not(:has(> .lh-topcount))::after{width:44px;margin-inline-start:-6px}
@media (min-width:561px){.lp-top > .lp-loc{max-width:34%}}
body:has(.lp-lock.is-on) .lp-top::after{display:none}
/* the progress bar's empty track (owner, 11 Oct: at the start of a lesson the dark track read as a blank gap) */
.lp-top > .lp-bar{background:var(--track)}
