/* ───────── tokens ───────── */
:root{
  color-scheme:light;
  --bg:#f4f4f2; --surface:#fcfcfb; --surface-2:#f0efec; --line:#e2e1dc; --line-2:#cfcdc6;
  --ink:#0b0b0b; --ink-2:#52514e; --ink-3:#7a7974;
  --accent:#2a78d6; --accent-ink:#ffffff; --accent-soft:#e3eefb; --accent-2:#1c5cab;
  --good:#0ca30c; --good-soft:#e6f5e6; --bad:#d03b3b; --bad-soft:#fbe7e7; --warn:#8a5a00; --warn-soft:#fff4dc;
  --d1:#2a78d6; --d2:#eb6834; --d3:#1baf7a; --d4:#eda100; --d5:#e87ba4;
  --seq-1:#cde2fb; --seq-2:#9ec5f4; --seq-3:#6da7ec; --seq-4:#3987e5; --seq-5:#256abf; --seq-6:#184f95;
  --shadow:0 1px 2px rgba(0,0,0,.05),0 4px 14px rgba(0,0,0,.05);
  --r:12px; --r-sm:8px;
  --mono:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
}
:root[data-theme="dark"]{
  color-scheme:dark;
  --bg:#141413; --surface:#1a1a19; --surface-2:#232322; --line:#2e2e2c; --line-2:#3d3d3a;
  --ink:#f3f2ee; --ink-2:#c3c2b7; --ink-3:#8f8e86;
  --accent:#3987e5; --accent-ink:#0b0b0b; --accent-soft:#14284a; --accent-2:#6da7ec;
  --good:#3fbf3f; --good-soft:#12301a; --bad:#e66767; --bad-soft:#3a1717; --warn:#e0b25a; --warn-soft:#332a14;
  --d1:#3987e5; --d2:#d95926; --d3:#199e70; --d4:#c98500; --d5:#d55181;
  --seq-1:#184f95; --seq-2:#1c5cab; --seq-3:#256abf; --seq-4:#3987e5; --seq-5:#6da7ec; --seq-6:#9ec5f4;
  --shadow:0 1px 2px rgba(0,0,0,.4),0 4px 14px rgba(0,0,0,.35);
}
@media (prefers-color-scheme:dark){
  :root:not([data-theme="light"]){
    color-scheme:dark;
    --bg:#141413; --surface:#1a1a19; --surface-2:#232322; --line:#2e2e2c; --line-2:#3d3d3a;
    --ink:#f3f2ee; --ink-2:#c3c2b7; --ink-3:#8f8e86;
    --accent:#3987e5; --accent-ink:#0b0b0b; --accent-soft:#14284a; --accent-2:#6da7ec;
    --good:#3fbf3f; --good-soft:#12301a; --bad:#e66767; --bad-soft:#3a1717; --warn:#e0b25a; --warn-soft:#332a14;
    --d1:#3987e5; --d2:#d95926; --d3:#199e70; --d4:#c98500; --d5:#d55181;
    --seq-1:#184f95; --seq-2:#1c5cab; --seq-3:#256abf; --seq-4:#3987e5; --seq-5:#6da7ec; --seq-6:#9ec5f4;
    --shadow:0 1px 2px rgba(0,0,0,.4),0 4px 14px rgba(0,0,0,.35);
  }
}
/* ───────── base ───────── */
*{box-sizing:border-box}
html,body{margin:0;background:var(--bg);color:var(--ink);font:15px/1.5 system-ui,-apple-system,"Segoe UI",Roboto,Inter,Arial,sans-serif;-webkit-font-smoothing:antialiased}
button,input,select{font:inherit;color:inherit}
a{color:var(--accent-2)}
h1,h2,h3{margin:0;line-height:1.25;letter-spacing:-.01em}
h1{font-size:1.5rem;font-weight:700} h2{font-size:1.2rem;font-weight:700} h3{font-size:1rem;font-weight:650}
.hidden{display:none!important}
.muted{color:var(--ink-2)} .faint{color:var(--ink-3)} .small{font-size:.87rem} .mono{font-family:var(--mono)}
kbd{font-family:var(--mono);font-size:.78em;padding:1px 6px;border:1px solid var(--line-2);border-bottom-width:2px;border-radius:5px;background:var(--surface-2);color:var(--ink-2)}
/* ───────── shell ───────── */
.top{position:sticky;top:0;z-index:20;background:var(--surface);border-bottom:1px solid var(--line)}
.top .in{max-width:1140px;margin:0 auto;padding:10px 20px;display:flex;align-items:center;gap:18px}
.brand{font-weight:750;letter-spacing:-.01em;white-space:nowrap} .brand span{color:var(--ink-3);font-weight:500}
nav.main{display:flex;gap:4px;flex:1}
nav.main a{text-decoration:none;color:var(--ink-2);padding:7px 12px;border-radius:var(--r-sm);font-weight:600;font-size:.92rem}
nav.main a:hover{background:var(--surface-2);color:var(--ink)} nav.main a.on{background:var(--accent-soft);color:var(--accent-2)}
.top .tools{display:flex;gap:6px;align-items:center}
main{max-width:1140px;margin:0 auto;padding:22px 20px 60px}
footer{max-width:1140px;margin:0 auto;padding:0 20px 30px;color:var(--ink-3);font-size:.8rem}
/* ───────── components ───────── */
.card{background:var(--surface);border:1px solid var(--line);border-radius:var(--r);padding:20px;box-shadow:var(--shadow)}
.card+.card{margin-top:16px}
.grid{display:grid;gap:16px} .g2{grid-template-columns:1fr 1fr} .g3{grid-template-columns:repeat(3,1fr)} .g-side{grid-template-columns:1fr 280px}
@media(max-width:900px){.g2,.g3,.g-side{grid-template-columns:1fr}}
.row{display:flex;gap:10px;align-items:center;flex-wrap:wrap} .row.between{justify-content:space-between} .row.end{justify-content:flex-end}
.stack{display:flex;flex-direction:column;gap:10px}
.btn{border:1px solid var(--line-2);background:var(--surface);border-radius:var(--r-sm);padding:9px 14px;cursor:pointer;font-weight:600;font-size:.92rem;color:var(--ink);transition:background .12s,border-color .12s}
.btn:hover{background:var(--surface-2)} .btn:disabled{opacity:.45;cursor:not-allowed}
.btn.primary{background:var(--accent);border-color:var(--accent);color:var(--accent-ink)} .btn.primary:hover{filter:brightness(1.06)}
.btn.danger{color:var(--bad);border-color:var(--bad)} .btn.sm{padding:5px 10px;font-size:.84rem} .btn.ghost{border-color:transparent;background:transparent}
.pill{display:inline-flex;align-items:center;gap:6px;background:var(--surface-2);border-radius:999px;padding:4px 10px;font-size:.82rem;color:var(--ink-2);font-weight:600}
.pill.accent{background:var(--accent-soft);color:var(--accent-2)} .pill.good{background:var(--good-soft);color:var(--good)} .pill.bad{background:var(--bad-soft);color:var(--bad)} .pill.warn{background:var(--warn-soft);color:var(--warn)}
.kicker{font-size:.76rem;text-transform:uppercase;letter-spacing:.08em;font-weight:700;color:var(--ink-3)}
.field{display:flex;flex-direction:column;gap:6px} .field label{font-size:.85rem;font-weight:600;color:var(--ink-2)}
.input,select.input{border:1px solid var(--line-2);border-radius:var(--r-sm);padding:9px 11px;background:var(--surface);min-width:0;width:100%}
.input:focus{outline:2px solid var(--accent);outline-offset:1px;border-color:var(--accent)}
.check{display:flex;gap:10px;align-items:center;cursor:pointer} .check input{width:18px;height:18px;accent-color:var(--accent)}
.notice{border-left:3px solid var(--accent);background:var(--accent-soft);padding:10px 14px;border-radius:0 var(--r-sm) var(--r-sm) 0;font-size:.92rem}
.notice.warn{border-color:var(--warn);background:var(--warn-soft)}
.table{width:100%;border-collapse:collapse;font-size:.9rem} .table th,.table td{text-align:left;padding:8px 10px;border-bottom:1px solid var(--line);vertical-align:top}
.table th{font-size:.78rem;text-transform:uppercase;letter-spacing:.05em;color:var(--ink-3);font-weight:700} .table td.num,.table th.num{text-align:right;font-variant-numeric:tabular-nums}
.tablewrap{overflow-x:auto}
.stat{background:var(--surface-2);border-radius:var(--r-sm);padding:12px 14px} .stat .v{font-size:1.6rem;font-weight:750;letter-spacing:-.02em;font-variant-numeric:tabular-nums;display:block} .stat .l{font-size:.78rem;color:var(--ink-2)}
.hero{font-size:3.2rem;font-weight:800;letter-spacing:-.03em;line-height:1;font-variant-numeric:tabular-nums}
.progress{height:8px;background:var(--surface-2);border-radius:99px;overflow:hidden} .progress>div{height:100%;background:var(--accent);border-radius:99px;transition:width .2s}
.toast{position:fixed;bottom:22px;left:50%;transform:translateX(-50%);background:var(--ink);color:var(--bg);padding:10px 16px;border-radius:var(--r-sm);font-size:.9rem;box-shadow:var(--shadow);z-index:50;opacity:0;transition:opacity .2s;pointer-events:none} .toast.on{opacity:1}
/* ───────── dashboard viz (dataviz rules: thin marks, direct labels, recessive chrome) ───────── */
.bars{display:grid;gap:10px}
.bar{display:grid;grid-template-columns:230px 1fr 56px;gap:12px;align-items:center;font-size:.9rem}
.bar .lab{display:flex;gap:8px;align-items:center;color:var(--ink);font-weight:600} .bar .sw{width:10px;height:10px;border-radius:3px;flex:none}
.bar .track{height:14px;background:var(--surface-2);border-radius:4px;position:relative;overflow:hidden}
.bar .track>i{position:absolute;left:0;top:0;bottom:0;border-radius:0 4px 4px 0;min-width:2px}
.bar .val{text-align:right;font-variant-numeric:tabular-nums;color:var(--ink-2);font-weight:600}
.heat{display:grid;grid-template-columns:repeat(6,1fr);gap:6px}
.heat .cell{border-radius:6px;padding:8px 9px;min-height:64px;display:flex;flex-direction:column;justify-content:space-between;cursor:pointer;border:1px solid transparent;transition:transform .1s}
.heat .cell:hover{transform:translateY(-1px);border-color:var(--ink-3)} .heat .cell b{font-size:.95rem} .heat .cell span{font-size:.75rem;opacity:.9}
.heat .cell.l0{background:var(--surface-2);color:var(--ink-2)} .heat .cell.l1{background:var(--seq-1);color:#0b0b0b} .heat .cell.l2{background:var(--seq-2);color:#0b0b0b} .heat .cell.l3{background:var(--seq-3);color:#0b0b0b} .heat .cell.l4{background:var(--seq-4);color:#fff} .heat .cell.l5{background:var(--seq-5);color:#fff} .heat .cell.l6{background:var(--seq-6);color:#fff}
:root[data-theme="dark"] .heat .cell.l1,:root[data-theme="dark"] .heat .cell.l2,:root[data-theme="dark"] .heat .cell.l3{color:#f3f2ee}
@media (prefers-color-scheme:dark){:root:not([data-theme="light"]) .heat .cell.l1,:root:not([data-theme="light"]) .heat .cell.l2,:root:not([data-theme="light"]) .heat .cell.l3{color:#f3f2ee}}
.legend{display:flex;gap:14px;flex-wrap:wrap;font-size:.8rem;color:var(--ink-2);margin-top:8px} .legend i{display:inline-block;width:10px;height:10px;border-radius:3px;margin-right:5px;vertical-align:-1px}
.check-list{list-style:none;margin:0;padding:0;display:grid;gap:8px} .check-list li{display:grid;grid-template-columns:22px 1fr;gap:10px;align-items:start} .check-list .ic{font-weight:800} .check-list .ok .ic{color:var(--good)} .check-list .no .ic{color:var(--ink-3)}
/* ───────── question runner ───────── */
.qhead{display:flex;gap:10px;align-items:center;flex-wrap:wrap;margin:10px 0 14px}
.qtext{font-size:1.12rem;line-height:1.55;margin:6px 0 16px}
.choice{display:grid;grid-template-columns:34px 1fr;gap:10px;align-items:start;width:100%;text-align:left;border:1.5px solid var(--line);background:var(--surface);border-radius:10px;padding:12px 14px;margin:8px 0;cursor:pointer;line-height:1.4;transition:border-color .12s,background .12s}
.choice:hover{border-color:var(--accent);background:var(--surface-2)}
.choice .k{font-family:var(--mono);font-size:.8rem;color:var(--ink-3);border:1px solid var(--line-2);border-radius:6px;padding:2px 0;text-align:center;width:28px;margin-top:1px}
.choice.selected{border-color:var(--accent);background:var(--accent-soft)} .choice.selected .k{border-color:var(--accent);color:var(--accent-2)}
.choice.correct{border-color:var(--good);background:var(--good-soft)} .choice.wrong{border-color:var(--bad);background:var(--bad-soft)}
.choice.locked{cursor:default}
.feedback{margin-top:14px;border-radius:10px;padding:14px 16px;border:1px solid var(--line)} .feedback.good{background:var(--good-soft);border-color:var(--good)} .feedback.bad{background:var(--bad-soft);border-color:var(--bad)}
.feedback h3{margin-bottom:6px}
/* .why is the per-choice rationale list in feedback. The next-step card and lesson intros reuse
   the class for prose, where a grid would put every <b>/<i>/<code> on its own row — so they reset it. */
.why{margin-top:12px;display:grid;gap:8px} .next .why,.lesson .why{display:block} .why .item{display:grid;grid-template-columns:22px 1fr;gap:8px;font-size:.9rem;padding:8px 10px;border-radius:8px;background:var(--surface)} .why .item .m{font-weight:800} .why .item.yes .m{color:var(--good)} .why .item.no .m{color:var(--bad)}
.tipbox{margin-top:10px;font-size:.9rem;color:var(--ink-2)} .tipbox b{color:var(--ink)}
.conf{display:inline-flex;border:1px solid var(--line-2);border-radius:var(--r-sm);overflow:hidden} .conf button{border:0;background:transparent;padding:7px 12px;cursor:pointer;font-weight:600;font-size:.86rem;color:var(--ink-2)} .conf button.on{background:var(--accent);color:var(--accent-ink)}
.navgrid{display:grid;grid-template-columns:repeat(9,1fr);gap:5px} .navgrid button{border:1px solid var(--line);background:var(--surface);border-radius:6px;padding:5px 0;font-size:.78rem;cursor:pointer;font-variant-numeric:tabular-nums;color:var(--ink-2)}
.navgrid button.answered{background:var(--accent-soft);border-color:var(--accent);color:var(--accent-2)} .navgrid button.current{outline:2px solid var(--accent);outline-offset:1px} .navgrid button.flag{border-color:var(--warn);color:var(--warn)} .navgrid button.miss{background:var(--bad-soft);border-color:var(--bad);color:var(--bad)} .navgrid button.hit{background:var(--good-soft);border-color:var(--good);color:var(--good)}
.timer{font-family:var(--mono);font-weight:700;font-size:1.05rem;font-variant-numeric:tabular-nums} .timer.low{color:var(--bad)}
.side{position:sticky;top:76px;align-self:start}
.visual{margin:10px 0 14px;border:1px solid var(--line);border-radius:10px;padding:12px 14px;background:var(--surface-2)} .visual .vt{font-weight:700;font-size:.92rem} .visual .vs{font-size:.84rem;color:var(--ink-2);margin-bottom:6px} .visual svg{width:100%;height:auto;display:block}
.chart-label{font-size:11px;fill:var(--ink-2)} .chart-axis{stroke:var(--ink-3);stroke-width:1} .chart-grid{stroke:var(--line);stroke-width:1} .chart-mark{stroke:var(--accent-2);stroke-width:2;fill:none} .chart-mark.s2{stroke:var(--d2)} .chart-fill{fill:var(--seq-3);stroke:none} .chart-fill.s2{fill:var(--d2)} .chart-fill.s3{fill:var(--d3)} .chart-total{fill:var(--surface);stroke:var(--ink-2);stroke-width:2} .chart-dot{fill:var(--accent);stroke:var(--surface);stroke-width:2} .heat-cell{stroke:var(--surface);stroke-width:2;fill:var(--accent)} .chart-shade{fill:var(--accent);opacity:.25} .chart-neg{fill:var(--d2)}
.chart-table{width:100%;border-collapse:collapse;font-size:.88rem} .chart-table th,.chart-table td{border:1px solid var(--line);padding:6px 8px;text-align:left} .chart-table th{background:var(--surface)}
.chart-legend{display:flex;gap:10px 16px;flex-wrap:wrap;margin-top:8px;font-size:.8rem;color:var(--ink-2)} .legend-item{display:inline-flex;gap:6px;align-items:center} .legend-swatch{width:14px;height:10px;border-radius:2px;background:var(--seq-3);display:inline-block} .legend-swatch.legend-line{height:2px;background:var(--accent-2);border-radius:0} .legend-swatch.legend-dashed{height:0;border-top:2px dashed var(--d2);background:none} .legend-swatch.legend-dot{width:10px;height:10px;border-radius:50%;background:var(--accent)} .legend-swatch.legend-fill2{background:var(--d2)} .legend-swatch.legend-fill3{background:var(--d3)} .legend-swatch.legend-neg{background:var(--d2)} .legend-swatch.legend-total{background:var(--surface);border:2px solid var(--ink-2)} .legend-swatch.legend-shade{background:var(--accent);opacity:.3}
.pbq-exhibit{margin:10px 0 14px} .pbq-code{white-space:pre-wrap;background:var(--surface-2);border:1px solid var(--line);border-radius:10px;padding:12px;overflow-x:auto;font-family:var(--mono);font-size:.86rem;line-height:1.45;margin:0} .pbq-exhibit table{width:100%;border-collapse:collapse;font-size:.9rem} .pbq-exhibit th,.pbq-exhibit td{border:1px solid var(--line);padding:6px 9px;text-align:left;vertical-align:top} .pbq-exhibit th{background:var(--surface-2)}
.task{border:1px solid var(--line);border-radius:10px;padding:14px 16px;margin:12px 0;background:var(--surface)} .task .tn{font-weight:700;margin-bottom:6px} .task .choice{margin:6px 0;padding:9px 12px}
.beyond{font-size:.78rem;color:var(--warn);font-weight:700}
.help-overlay{position:fixed;inset:0;background:rgba(0,0,0,.45);z-index:60;display:flex;align-items:center;justify-content:center;padding:20px} .help-overlay .card{max-width:560px;width:100%}
.help-overlay table td{padding:5px 8px} .help-overlay table td:first-child{width:130px}
.two{display:grid;grid-template-columns:1fr 1fr;gap:6px 20px} @media(max-width:700px){.two{grid-template-columns:1fr}}
/* ───────── v1.1: next step, welcome, lessons, practice, progress, guide ───────── */
.next{border:1px solid var(--accent);background:linear-gradient(135deg,var(--accent-soft),var(--surface));display:grid;grid-template-columns:1fr auto;gap:16px;align-items:center}
.next .kicker{color:var(--accent-2)} .next h2{font-size:1.35rem;margin:4px 0 6px} .next .why{color:var(--ink-2);font-size:.92rem}
@media(max-width:700px){.next{grid-template-columns:1fr}}
.welcome{border-left:3px solid var(--accent)} .welcome .row{margin-top:10px}
.tools .btn{text-decoration:none;display:inline-flex;align-items:center}
.lesson-list .dom{margin-top:18px} .lesson-list .dom:first-child{margin-top:0}
.lrow{display:grid;grid-template-columns:52px 1fr auto auto auto;gap:12px;align-items:center;padding:12px 14px;border:1px solid var(--line);border-radius:10px;background:var(--surface);margin:8px 0;text-decoration:none;color:inherit;transition:border-color .12s}
.lrow:hover{border-color:var(--accent)} .lrow .id{font-family:var(--mono);font-weight:700;color:var(--accent-2)} .lrow .t{font-weight:600} .lrow .m{font-size:.82rem;color:var(--ink-2);white-space:nowrap}
.lrow .read{font-size:.78rem;font-weight:700;color:var(--good)} .lrow .unread{font-size:.78rem;color:var(--ink-3)}
@media(max-width:760px){.lrow{grid-template-columns:52px 1fr;} .lrow .m,.lrow .mast{display:none}}
.lesson{max-width:820px} .lesson .why{font-size:1.02rem;line-height:1.6;color:var(--ink-2);border-left:3px solid var(--line-2);padding-left:14px;margin:14px 0 22px}
.lesson .lsec{margin:26px 0} .lesson .lsec h2{font-size:1.15rem;margin-bottom:10px} .lesson p{line-height:1.65;margin:0 0 12px}
.lesson .example{background:var(--surface-2);border-radius:10px;padding:12px 16px;margin:12px 0;line-height:1.55} .lesson .example b{color:var(--ink-2);font-size:.78rem;text-transform:uppercase;letter-spacing:.06em;display:block;margin-bottom:4px}
.lesson .hook{border:1.5px solid var(--accent);border-radius:10px;padding:12px 16px;margin:12px 0;font-weight:600;line-height:1.5;background:var(--accent-soft)} .lesson .hook b{color:var(--accent-2);font-size:.78rem;text-transform:uppercase;letter-spacing:.06em;display:block;margin-bottom:4px;font-weight:700}
.lesson .traps li{margin:6px 0;line-height:1.5} .lesson code{font-family:var(--mono);font-size:.9em;background:var(--surface-2);padding:1px 5px;border-radius:4px}
.lesson .vocab td:first-child{font-weight:600;width:34%}
.lesson-nav{display:flex;justify-content:space-between;gap:10px;margin-top:22px;flex-wrap:wrap}
.lesson-actions{position:sticky;bottom:0;background:var(--surface);border-top:1px solid var(--line);margin:24px -20px -20px;padding:14px 20px;border-radius:0 0 var(--r) var(--r);display:flex;gap:10px;justify-content:flex-end;flex-wrap:wrap}
.practice .card h2{margin-bottom:6px}
.guide h2{margin:22px 0 8px} .guide p,.guide li{line-height:1.6} .guide ol li{margin:6px 0} .guide .tabs dt{font-weight:700;margin-top:10px} .guide .tabs dd{margin:2px 0 0;color:var(--ink-2)}

/* ═════════ phone layout (v1.3) ═════════
   Everything below is inside a max-width query, so the laptop view is untouched.
   The five tabs become a fixed bottom bar; a running session hides that bar and
   pins its own action bar in its place, with the question navigator as a sheet. */
/* The tab icons and phone-only controls exist in the markup at every width but render only
   inside the phone layout below, so the laptop view is byte-for-byte what it was. */
.phone-only{display:none} nav.main a .ti{display:none}
@media (max-width:760px){
  :root{ --tabbar:60px; --safe-b:env(safe-area-inset-bottom,0px); }

  /* ── shell: brand + tools on top, tabs on the bottom ── */
  .top .in{padding:8px 14px;gap:10px;justify-content:space-between}
  .top .tools{gap:4px}
  #counts,#who{display:none}                /* informational; the space is worth more */
  .brand{font-size:.98rem}
  main{padding:16px 14px calc(var(--tabbar) + var(--safe-b) + 26px)}
  footer{padding:0 14px calc(var(--tabbar) + var(--safe-b) + 20px);font-size:.74rem}

  nav.main{
    position:fixed;left:0;right:0;bottom:0;z-index:40;flex:none;gap:0;
    display:grid;grid-template-columns:repeat(5,1fr);
    background:var(--surface);border-top:1px solid var(--line);
    padding-bottom:var(--safe-b);
    box-shadow:0 -1px 12px rgba(0,0,0,.06);
  }
  nav.main a{
    display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;
    padding:9px 2px 8px;border-radius:0;min-height:var(--tabbar);
    font-size:.68rem;font-weight:650;letter-spacing:-.01em;color:var(--ink-3);
  }
  nav.main a .ti{display:block;width:22px;height:22px;fill:none;stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}
  nav.main a:hover{background:transparent;color:var(--ink-3)}
  nav.main a.on{background:transparent;color:var(--accent-2)}
  nav.main a.on .ti{stroke-width:2.1}

  /* ── the running session owns the bottom of the screen ── */
  body.running nav.main{display:none}
  body.running main{padding-bottom:calc(var(--safe-b) + 132px)}
  .phone-only{display:inline-flex}
  .qactions{
    position:fixed;left:0;right:0;bottom:0;z-index:45;margin:0!important;
    background:var(--surface);border-top:1px solid var(--line);
    padding:9px 12px calc(9px + var(--safe-b));
    gap:8px;flex-wrap:nowrap;align-items:center;
    box-shadow:0 -1px 12px rgba(0,0,0,.08);
  }
  /* Seven controls will not fit one phone row, so the bar becomes two: secondary controls and
     the clock above, the confidence toggle and the primary action below. Pause and Finish move
     into the navigator sheet, which the ⊞ button opens. */
  .qactions{flex-wrap:wrap;row-gap:8px}
  .qactions>.row{flex:1 1 100%;gap:6px;flex-wrap:nowrap;min-width:0}
  .qactions>.row:last-child{justify-content:flex-end}
  .qactions .btn{padding:11px 12px;font-size:.88rem;white-space:nowrap;min-height:44px}
  .qactions .btn.primary{flex:1 1 auto;justify-content:center;max-width:60%}
  .qactions .lbl,.hide-phone{display:none}
  .qactions .timer{font-size:1rem;margin-left:auto;padding-right:2px}
  .conf{flex:0 0 auto} .conf button{padding:11px 13px;font-size:.84rem}

  /* the sidebar becomes the "jump to question" sheet */
  .side{
    position:fixed;left:0;right:0;bottom:0;top:auto;z-index:46;   /* top:auto — the desktop rule sets top:76px, and top+bottom together would win over bottom */
    max-height:72vh;overflow-y:auto;border-radius:14px 14px 0 0;
    padding-bottom:calc(20px + var(--safe-b));
    /* visibility, not just the transform: a translated-off-screen box can still swallow taps
       meant for the action bar underneath it, depending on how the viewport is measured. */
    transform:translateY(101%);visibility:hidden;pointer-events:none;
    transition:transform .22s ease,visibility .22s;
    box-shadow:0 -8px 30px rgba(0,0,0,.22);
  }
  body.sheet-open .side{transform:none;visibility:visible;pointer-events:auto}
  body.sheet-open::after{content:"";position:fixed;inset:0;background:rgba(0,0,0,.4);z-index:44}
  .navgrid{grid-template-columns:repeat(6,1fr);gap:7px}
  .navgrid button{padding:11px 0;font-size:.86rem}

  /* ── question ergonomics ── */
  .qhead{gap:6px;margin:8px 0 12px} .qhead .pill{font-size:.75rem;padding:4px 8px}
  .qtext{font-size:1.06rem}
  .choice{padding:14px 13px;margin:9px 0;grid-template-columns:30px 1fr;gap:9px}
  .task{padding:13px 12px}
  .task .choice{padding:12px 11px}

  /* ── tap targets: 44px is Apple's minimum ── */
  /* Standalone navigation links ("Full history →", "← All lessons") get a real touch area;
     links inside a sentence stay inline, since every one of them has a tab of its own. */
  a.small{display:inline-block;padding:12px 0;min-height:46px;line-height:1.5}
  .btn{padding:11px 14px;min-height:44px}
  .btn.sm{padding:8px 11px;min-height:38px}
  .tools .btn{min-height:44px;padding:10px 11px}
  .check{min-height:44px} .check input{width:22px;height:22px}
  .input,select.input{font-size:16px;min-height:44px}   /* 16px stops iOS zooming on focus */
  .heat .cell{min-height:58px}

  /* ── content reflow ── */
  /* Flex and grid children default to min-width:auto, so one wide table refuses to shrink and
     drags every sibling card past the screen edge. Let them shrink and scroll in their own box. */
  .grid>*,.stack>*,.bar>*,.row>*{min-width:0}
  .tablewrap{max-width:100%}
  h1{font-size:1.3rem} .card{padding:16px 14px} .card+.card{margin-top:12px}
  .hero{font-size:2.4rem} .grid{gap:12px}
  .g3{grid-template-columns:1fr 1fr}
  .heat{grid-template-columns:repeat(3,1fr)}
  .lesson-actions{position:sticky;bottom:calc(var(--tabbar) + var(--safe-b));margin:20px -14px -16px;padding:12px 14px;justify-content:stretch;flex-direction:column}
  body.running .lesson-actions{bottom:0}
  .lesson-actions .btn{width:100%;justify-content:center;display:inline-flex;align-items:center}
  .lesson-nav{flex-direction:column} .lesson-nav .btn{width:100%;text-align:center}
  .lesson .vocab td:first-child{width:40%}
  .lesson{max-width:none}
  .help-overlay{padding:12px;align-items:flex-end} .help-overlay .card{max-height:80vh;overflow-y:auto}
  .toast{bottom:calc(var(--tabbar) + var(--safe-b) + 14px);width:calc(100% - 28px);text-align:center}
  body.running .toast{bottom:calc(var(--safe-b) + 126px)}

  /* charts keep legible text by scrolling in their own box rather than shrinking */
  .visual{overflow-x:auto;padding:10px} .visual svg{min-width:520px}
  .chart-label{font-size:12px}
  .bars .lab{font-size:.82rem}
  .bar{grid-template-columns:1fr 48px;grid-template-areas:"lab val" "track track";gap:4px 10px;row-gap:6px}
  .bar .lab{grid-area:lab} .bar .val{grid-area:val} .bar .track{grid-area:track}
  .check-list li{grid-template-columns:20px 1fr}
}
@media (max-width:420px){
  /* The exam code in the brand is the first thing worth losing: on a 360px screen it pushed
     the header past the viewport, which stretched the fixed tab bar and every card with it. */
  .brand span{display:none}
  .top .in{gap:8px} .top .tools{gap:3px} .tools .btn{padding:10px 9px}
  nav.main a{font-size:.63rem} nav.main a .ti{width:20px;height:20px}
  .qactions .btn{padding:10px 9px;font-size:.82rem}
  .g3{grid-template-columns:1fr}
}

/* ── Inline glossary ───────────────────────────────────────────────────────────
   A term is underlined the first time it appears in a question or a lesson. Tap or hover it for
   the one-line definition. Never present during a timed exam. */
.gl{border-bottom:1px dotted var(--ink-3);cursor:help;text-underline-offset:2px}
.gl:hover,.gl:focus{border-bottom-color:var(--accent);color:var(--accent-2)}
.glpop{position:fixed;z-index:60;display:none;max-width:min(340px,calc(100vw - 24px));
  background:var(--surface);color:var(--ink);border:1px solid var(--line-2);border-radius:var(--r-sm);
  padding:10px 12px;font-size:.87rem;line-height:1.45;box-shadow:0 8px 26px rgba(0,0,0,.18)}
.glpop.on{display:block}
.glpop b{color:var(--accent-2)}
@media (max-width:760px){
  .gl{border-bottom-width:1.5px;padding:2px 0}
  /* Phone: a bar above whatever owns the bottom of the screen — the tab bar, or a
     question's own action bar while a session is running. Matches .toast exactly. */
  .glpop{left:14px;right:14px;top:auto!important;width:auto!important;
    bottom:calc(var(--tabbar) + var(--safe-b) + 14px);max-width:none}
  body.running .glpop{bottom:calc(var(--safe-b) + 126px)}
}

/* ── Accounts: the pairing gate and the sync pill ─────────────────────────────
   The gate is the whole app until a code is entered, so it hides the chrome behind it. */
body.gated nav.main,body.gated .tools .btn,body.gated #counts,body.gated #who,body.gated #syncPill,body.gated footer{display:none}
.gate{max-width:440px;margin:8vh auto 0}
.gate h1{margin:6px 0 8px}
.gate p.muted{margin:0 0 18px}
.gate form{display:flex;gap:8px;flex-wrap:wrap}
.gate input{flex:1 1 200px;min-width:0;font-family:var(--mono,ui-monospace,monospace);font-size:17px;font-weight:600;line-height:1.2;letter-spacing:.06em;
  padding:12px 14px;border:1px solid var(--line-2);border-radius:var(--r-sm);background:var(--surface);color:var(--ink);text-transform:uppercase}
.gate input:focus{outline:2px solid var(--accent);outline-offset:1px;border-color:var(--accent)}
.gate .btn{padding:12px 20px}
.gate-msg{min-height:1.2em;margin:12px 0 0;color:var(--ink-2)}
.gate-msg.bad{color:var(--bad,#b3261e);font-weight:600}

.pill.sync{font-size:.72rem;padding:3px 8px;white-space:nowrap}
.pill.sync:empty{display:none}
.pill.sync.synced{color:var(--ink-3);background:transparent;border:1px solid var(--line)}
.pill.sync.saving{color:var(--ink-2)}
.pill.sync.offline,.pill.sync.queued{color:var(--warn,#7E5C30);border:1px solid currentColor;background:transparent}
.pill.sync.unpaired{color:var(--bad,#b3261e);border:1px solid currentColor;background:transparent}
@media (max-width:760px){
  .gate{margin-top:4vh} .gate form{flex-direction:column} .gate .btn{width:100%}
  /* The header row has no spare width on a phone — v1.3 fixed exactly this overflow. The pill
     becomes a dot, and disappears entirely when there is nothing to say. */
  .pill.sync{font-size:0;line-height:0;padding:0;border:0;background:none;width:10px;height:10px;
    border-radius:50%;display:inline-block;flex:0 0 auto}
  .pill.sync.synced{display:none}
  .pill.sync.saving{background:var(--ink-3)}
  .pill.sync.offline,.pill.sync.queued{background:var(--warn,#7E5C30)}
  .pill.sync.unpaired{background:var(--bad,#b3261e)}
}
