/* App layout & components — design tokens live in assets/tokens.css */
*{box-sizing:border-box;margin:0;padding:0}
html{scroll-behavior:smooth;font-size:16px}

body{
  background:var(--main-bg);
  color:var(--ink);
  font-family:var(--sans);
  min-height:100vh;
  overflow-x:hidden;
  transition:background 0.4s, color 0.4s;
}

body::before{
  content:'';position:fixed;inset:0;
  background-image:
    radial-gradient(ellipse 80% 50% at 50% 0%,rgba(var(--accent-rgb),0.06) 0%,transparent 60%),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='400' height='400'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='400' height='400' filter='url(%23n)' opacity='0.025'/%3E%3C/svg%3E");
  pointer-events:none;z-index:0;
}

/* ═══════════════════════════════════════════
   LAYOUT
═══════════════════════════════════════════ */
.app{display:flex;min-height:100vh;position:relative;z-index:1}

/* ═══════════════════════════════════════════
   SIDEBAR
═══════════════════════════════════════════ */
.sidebar{
  width:var(--sidebar-w);min-width:var(--sidebar-w);
  background:var(--ink2) !important;
  display:flex;flex-direction:column;
  position:sticky;top:0;height:100vh;
  overflow-y:auto;overflow-x:hidden;
  border-right:1px solid rgba(255,255,255,0.06);
  transition:transform 0.35s cubic-bezier(0.4,0,0.2,1);
}
[data-theme="dark"] .sidebar{background:#0a0906 !important}
.sidebar::-webkit-scrollbar{width:3px}
.sidebar::-webkit-scrollbar-thumb{background:rgba(255,255,255,0.15);border-radius:2px}

.sidebar-logo{
  padding:32px 24px 24px;
  border-bottom:1px solid rgba(255,255,255,0.08);
  position:relative;overflow:hidden;
}
/* The watermark is the module's own numeral, and it used to be the string
   'CH₄'. Two things were wrong with that. It is Module 1 chemistry hard-coded
   into the shell that every module shares, so Module 2 — Analytical Chemistry —
   was carrying a methane mark for no reason. And it was drawn at right:-10px
   bottom:-20px inside `overflow:hidden`, which cut through its own letterforms
   and sliced the subscript off: a watermark reads as texture, half a watermark
   reads as a rendering fault, and that is what it looked like.

   `line-height` under 1 makes the box hug the glyph, so the numeral sits whole
   inside the block instead of hanging out of it. */
.sidebar-logo::after{
  content:attr(data-mark);
  position:absolute;right:20px;bottom:10px;
  font-family:var(--serif);font-size:92px;font-weight:900;line-height:.72;
  color:rgba(255,255,255,0.045);pointer-events:none;user-select:none;
}
.logo-eyebrow{font-family:var(--mono);font-size:11px;color:var(--gold-on-dark);
  letter-spacing:0.16em;text-transform:uppercase;margin-bottom:10px;line-height:1.55}
/* A line each, so a long module name cannot strand its own number. `block` on
   the spans rather than flex on the parent: this file already has a bug from
   making a flex item of every child (the mind map's subscripts, CLAUDE.md
   12.7), and two stacked blocks need nothing that flex provides. */
.logo-eyebrow-name,.logo-eyebrow-num{display:block}
/* The name carries the module's accent; the number is the quieter half.
   `--ink-on-dark` is the sidebar-calibrated token — the page tokens are
   measured against cream and read far too low here. */
.logo-eyebrow-num{color:var(--ink-on-dark);letter-spacing:0.19em}
.logo-main{font-family:var(--serif);font-weight:900;font-size:1.42rem;color:#f5f0e8;
  line-height:1.12;letter-spacing:-.005em}
.logo-sub{font-family:var(--mono);font-size:10.5px;color:rgba(245,240,232,0.66);
  letter-spacing:0.14em;margin-top:9px}

/* Top controls row in sidebar */
.sidebar-controls{
  display:grid;grid-template-columns:repeat(3,1fr);gap:6px;
  padding:12px 20px;
  border-bottom:1px solid rgba(255,255,255,0.06);
}
.ctrl-btn{
  background:rgba(255,255,255,0.05);border:1px solid rgba(255,255,255,0.09);
  color:rgba(245,240,232,0.8);padding:7px 8px;border-radius:7px;
  font-family:var(--mono);font-size:11px;letter-spacing:.04em;cursor:pointer;
  display:flex;align-items:center;justify-content:center;gap:5px;
  transition:var(--trans);
}
.ctrl-btn:hover{background:rgba(255,255,255,0.12);color:#f5f0e8}
.ctrl-btn.active{background:rgba(var(--accent-rgb),0.2);border-color:rgba(var(--accent-rgb),0.4);color:var(--gold2)}

/* Progress */
.progress-section{padding:20px 24px;border-bottom:1px solid rgba(255,255,255,0.06)}
.prog-row{display:flex;justify-content:space-between;align-items:center;margin-bottom:10px}
.prog-label{font-family:var(--mono);font-size:var(--fs-xs);color:rgba(245,240,232,0.72);letter-spacing:0.1em;text-transform:uppercase}
.prog-pct{font-family:var(--mono);font-size:var(--fs-sm);color:var(--gold-on-dark);font-weight:500}
.prog-track{height:5px;background:rgba(255,255,255,0.07);border-radius:3px;overflow:hidden}
.prog-fill{height:100%;background:linear-gradient(90deg,var(--gold),var(--gold3));border-radius:2px;width:0%;transition:width 0.8s cubic-bezier(0.4,0,0.2,1)}

/* Search */
.search-wrap{padding:16px 20px;border-bottom:1px solid rgba(255,255,255,0.06);position:relative}
.search-box{
  display:flex;align-items:center;gap:8px;
  background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.1);
  border-radius:8px;padding:8px 12px;cursor:text;
  transition:border-color 0.2s;
}
.search-box:focus-within{border-color:rgba(var(--accent-rgb),0.4)}
.search-box input{background:transparent;border:none;outline:none;color:#f5f0e8;font-family:var(--sans);font-size:var(--fs-sm);width:100%}
.search-box input::placeholder{color:rgba(245,240,232,0.62)}
.search-icon{color:rgba(245,240,232,0.66);font-size:var(--fs-sm);flex-shrink:0}
.search-results{
  position:absolute;top:calc(100% - 16px);left:20px;right:20px;
  background:#1a1814;border:1px solid rgba(255,255,255,0.12);
  border-radius:0 0 10px 10px;z-index:100;
  max-height:220px;overflow-y:auto;display:none;
  box-shadow:0 8px 24px rgba(0,0,0,0.3);
}
.search-result-item{
  padding:10px 16px;cursor:pointer;font-size:var(--fs-sm);
  color:rgba(245,240,232,0.88);border-bottom:1px solid rgba(255,255,255,0.05);
  transition:background 0.15s;display:flex;align-items:center;gap:8px;
}
.search-result-item:hover{background:rgba(var(--accent-rgb),0.15);color:#f5f0e8}
.sr-tag{font-family:var(--mono);font-size:var(--fs-xs);color:var(--gold2);background:rgba(var(--accent-rgb),0.15);padding:2px 7px;border-radius:3px;flex-shrink:0}
mark{background:rgba(var(--accent-rgb),0.3);color:var(--gold3);padding:0 2px;border-radius:2px}

/* Nav */
.nav-group-label{padding:16px 24px 6px;font-family:var(--mono);font-size:var(--fs-xs);color:rgba(245,240,232,0.62);text-transform:uppercase;letter-spacing:0.18em}
.nav-item{
  display:flex;align-items:center;margin:2px 12px;border-radius:8px;
  cursor:pointer;transition:var(--trans);overflow:hidden;
  border:1px solid transparent;position:relative;
}
.nav-item:hover{background:rgba(255,255,255,0.06);border-color:rgba(255,255,255,0.08)}
.nav-item.active{background:rgba(14,12,10,0.45);border-color:rgba(var(--accent-rgb),0.22)}
.nav-item.active::before{
  content:'';position:absolute;left:0;top:6px;bottom:6px;width:3px;
  background:var(--gold-on-dark);border-radius:0 3px 3px 0;
}
.nav-num{
  font-family:var(--mono);font-size:var(--fs-xs);background:rgba(255,255,255,0.06);
  color:rgba(245,240,232,0.88);padding:3px 7px;margin:10px 0 10px 12px;
  border-radius:4px;min-width:26px;text-align:center;flex-shrink:0;
}
.nav-item.active .nav-num{background:rgba(var(--accent-rgb),0.2);color:var(--gold-on-dark)}
.nav-text{flex:1;padding:10px 10px 10px 8px;font-size:var(--fs-base);font-weight:400;color:rgba(245,240,232,0.78);transition:color 0.2s}
.nav-item.active .nav-text{color:#f5f0e8;font-weight:500}
.nav-check{
  width:18px;height:18px;border-radius:50%;border:1.5px solid rgba(255,255,255,0.15);
  display:flex;align-items:center;justify-content:center;
  font-size:8px;color:transparent;transition:var(--trans);margin-right:12px;flex-shrink:0;
}
.nav-item.done .nav-check{background:var(--emerald);border-color:var(--emerald);color:#f5f0e8}
.nav-score{font-family:var(--mono);font-size:var(--fs-xs);padding:2px 7px;border-radius:4px;margin-right:8px;flex-shrink:0}

/* Bookmarks panel */
.bm-panel{padding:16px 20px;border-top:1px solid rgba(255,255,255,0.06)}
.bm-panel-label{font-family:var(--mono);font-size:var(--fs-xs);color:rgba(245,240,232,0.62);margin-bottom:10px;letter-spacing:0.1em;text-transform:uppercase}
.bm-item{padding:6px 0;cursor:pointer;border-bottom:1px solid rgba(255,255,255,0.05);color:rgba(245,240,232,0.78);font-size:var(--fs-sm);transition:color 0.2s;display:flex;align-items:center;gap:6px}
.bm-item:hover{color:var(--gold2)}
.bm-empty{font-size:var(--fs-sm);color:rgba(245,240,232,0.55);font-style:italic;font-family:var(--body)}

/* ═══════════════════════════════════════════
   MAIN AREA
═══════════════════════════════════════════ */
.main{flex:1;overflow-y:auto;position:relative;background:var(--main-bg);transition:background 0.4s}
.main::-webkit-scrollbar{width:6px}
.main::-webkit-scrollbar-thumb{background:var(--cream3);border-radius:3px}

/* ── Reading (focus) mode ──
   Collapses the sidebar to an icon rail. The controls row MUST stay visible,
   otherwise the Focus toggle hides itself and the only way out is a reload. */
body.reading-mode .sidebar{width:var(--rail-w);min-width:var(--rail-w)}
body.reading-mode .sidebar .logo-eyebrow,
body.reading-mode .sidebar .logo-main,
body.reading-mode .sidebar .logo-sub,
body.reading-mode .sidebar .progress-section,
body.reading-mode .sidebar .search-wrap,
body.reading-mode .sidebar .nav-group-label,
body.reading-mode .sidebar .nav-text,
body.reading-mode .sidebar .nav-check,
body.reading-mode .sidebar .nav-score,
body.reading-mode .sidebar .bm-panel{display:none}

/* Keep the controls reachable: stack them, and show only the Focus toggle
   (labelled with a compact glyph) so the user can always get back out. */
body.reading-mode .sidebar .sidebar-controls{
  flex-direction:column;gap:8px;padding:12px 8px;
}
body.reading-mode .sidebar .ctrl-btn{width:100%;justify-content:center;padding:8px 4px}
body.reading-mode .sidebar .ctrl-btn .ctrl-label{display:none}
body.reading-mode .sidebar .ctrl-btn::after{
  content:attr(data-short);font-family:var(--mono);font-size:var(--fs-xs);
}
body.reading-mode .sidebar .nav-item{margin:2px 8px;justify-content:center}
body.reading-mode .sidebar .nav-num{margin:10px auto}
body.reading-mode .sidebar .sidebar-logo{padding:18px 8px;text-align:center}
body.reading-mode .sidebar .sidebar-logo::after{display:none}
/* Collapsed to a rail, the block has room for one mark. It was 'CH' — which
   tells a reader nothing, and tells a Module 2 reader something false. The
   number says which module they are standing in, which is the only thing a
   rail this narrow has space to say. */
body.reading-mode .sidebar .sidebar-logo::before{
  content:attr(data-mark);font-family:var(--serif);font-weight:900;
  font-size:1.25rem;color:var(--gold-on-dark);letter-spacing:0.02em;
}

/* ═══════════════════════════════════════════
   PAGES
═══════════════════════════════════════════ */
.page{display:none;animation:pgIn 0.4s ease}
.page.active{display:block}
@keyframes pgIn{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}

/* ═══════════════════════════════════════════
   HERO
═══════════════════════════════════════════ */
.page-hero{
  position:relative;overflow:hidden;
  padding:60px 64px 48px;
  border-bottom:1px solid var(--line);
  background:var(--hero-bg);
  transition:background 0.4s;
}
.page-hero::before{
  content:'';position:absolute;right:-40px;top:-40px;
  width:300px;height:300px;border-radius:50%;
  background:radial-gradient(ellipse,rgba(var(--accent-rgb),0.07) 0%,transparent 70%);
  pointer-events:none;
}
.hero-molecule{position:absolute;right:64px;top:50%;transform:translateY(-50%);opacity:0.07;pointer-events:none}
.page-eyebrow{
  font-family:var(--mono);font-size:var(--fs-xs);color:var(--gold);letter-spacing:0.2em;
  text-transform:uppercase;margin-bottom:14px;display:flex;align-items:center;gap:10px;
}
.page-eyebrow::before{content:'';width:24px;height:1px;background:var(--gold)}
.page-title{font-family:var(--serif);font-weight:900;font-size:3.2rem;color:var(--ink);line-height:1.05;max-width:600px}
.page-title em{color:var(--gold);font-style:italic}
.page-summary{
  margin-top:20px;max-width:640px;font-family:var(--body);font-size:var(--fs-base);
  line-height:1.8;color:var(--ink3);font-style:italic;
  padding-left:18px;border-left:3px solid var(--gold3);
}
.hero-actions{margin-top:20px;display:flex;gap:10px;align-items:center;flex-wrap:wrap}

/* ═══════════════════════════════════════════
   CONTENT BODY
═══════════════════════════════════════════ */
.content-body{padding:48px 64px}

/* ═══════════════════════════════════════════
   MIND MAP
═══════════════════════════════════════════ */
/* THE MIND MAP IS A THIRD PERMANENTLY-DARK SURFACE, and it was carrying the
   page's tokens like the other two did before they were fixed. Measured in the
   LIGHT theme before this change: the "MIND MAP" header was 2.47:1 in Module 1,
   1.53:1 in Module 2 and 1.66:1 in Module 3, because `--gold` is the accent
   calibrated for the cream page and this panel is not the cream page. The
   centre node was 4.2 / 4.68 / 4.4 — two of the three under the floor.

   It takes the sidebar's on-dark tokens now, for the same reason the formula
   box does: the surface decides the calibration, not the page. */
/* THE MIND MAP IS A THIRD PERMANENTLY-DARK SURFACE, and it was carrying the
   page's tokens like the other two did before they were fixed. Measured in the
   LIGHT theme before this change: the "MIND MAP" header was 2.47:1 in Module 1,
   1.53:1 in Module 2 and 1.66:1 in Module 3, because `--gold` is the accent
   calibrated for the cream page and this panel is not the cream page. The
   centre node was 4.2 / 4.68 / 4.4 — two of the three under the floor.

   It takes the sidebar's on-dark tokens now, for the same reason the formula
   box does: the surface decides the calibration, not the page. */
.mindmap{
  margin-bottom:40px;padding:30px 34px 32px;
  border:1px solid var(--line);border-radius:16px;
  background:var(--ink2);position:relative;overflow:hidden;
  /* A hairline of light along the top edge. It is the cheapest rule in this
     block and does most of the work of making the panel read as a surface with
     a thickness rather than a flat rectangle. */
  box-shadow:inset 0 1px 0 rgba(255,255,255,0.07), var(--shadow2);
  --mm-line:rgba(245,240,232,0.44);
}
[data-theme="dark"] .mindmap{background:#0a0906}

/* Two washes, not one: a cool lift from the top-left and the accent pooling at
   the bottom. A single flat ground is what made this read as a container
   rather than a plate of its own. */
.mindmap::before{
  content:'';position:absolute;inset:0;pointer-events:none;
  background:
    radial-gradient(ellipse 70% 55% at 50% 108%,rgba(var(--accent-rgb),0.13),transparent),
    radial-gradient(ellipse 60% 50% at 0% -10%,rgba(245,240,232,0.055),transparent);
}
/* An inner frame, inside the padding. A printed diagram sits on a plate. */
.mindmap::after{
  content:'';position:absolute;inset:9px;border-radius:11px;pointer-events:none;
  border:1px solid rgba(245,240,232,0.05);
}
.mindmap > *{position:relative;z-index:1}

.mm-header{font-family:var(--mono);font-size:var(--fs-xs);color:var(--gold-on-dark);letter-spacing:0.22em;text-transform:uppercase;margin-bottom:20px;display:flex;align-items:center;gap:11px}
.mm-header::before{content:'';width:20px;height:1px;background:var(--gold-on-dark);flex-shrink:0}
.mm-header::after{content:'';flex:1;height:1px;background:linear-gradient(90deg,rgba(245,240,232,0.14),transparent)}

.mm-center-node{
  display:inline-flex;align-items:center;gap:10px;
  background:rgba(var(--accent-rgb),0.16);
  border:1px solid rgba(var(--accent-rgb),0.42);
  color:var(--gold-on-dark);
  font-family:var(--serif);font-weight:700;font-size:1.14rem;letter-spacing:-.01em;
  padding:12px 26px;border-radius:50px;margin-bottom:4px;
  box-shadow:0 0 0 6px rgba(var(--accent-rgb),0.06), inset 0 1px 0 rgba(255,255,255,0.08);
}

/* ── the tree ──────────────────────────────────────────────────────────
   A trunk with branches hanging off it, drawn ENTIRELY IN CSS. No SVG and no
   measurement: a connector positioned from getBoundingClientRect breaks on
   resize, and one drawn in a frame callback is missing altogether on a page
   opened in a background tab. These are borders and pseudo-elements, so they
   are part of the layout and cannot be absent.

   The trunk is drawn per branch — each segment spans the gap above its own
   node — rather than as one line down the whole tree. That is what makes it
   stop at the last node instead of running past it, with no mask and no
   measured height. */
.mm-tree{position:relative;padding-left:34px;display:flex;flex-direction:column;gap:22px;margin-top:18px}
.mm-branch{position:relative}
.mm-branch::before{content:'';position:absolute;left:-26px;top:-22px;width:1px;height:33px;background:var(--mm-line)}
.mm-branch:first-child::before{top:-26px;height:37px}

/* The node on the trunk: a filled core with a halo of its own colour. A plain
   dot reads as a bullet; the halo reads as a junction. */
.mm-branch::after{
  content:'';position:absolute;left:-29px;top:7px;width:7px;height:7px;border-radius:50%;
  background:var(--mm-hue);box-shadow:0 0 0 3.5px rgba(var(--accent-rgb),0.13);
}

/* ── the branch header ────────────────────────────────────────────────
   A set numeral, the name in the display face, and a rule that runs to the
   right edge and fades out. The rule is what turns four stacked lists into
   four titled bands — the single declaration here doing the most work. */
.mm-branch-head{display:flex;align-items:center;gap:11px;margin-bottom:11px}
.mm-branch-head::before{content:'';position:absolute;left:-20px;top:10px;width:14px;height:1px;background:var(--mm-hue)}
.mm-num{font-family:var(--mono);font-size:11px;letter-spacing:.1em;color:var(--mm-hue);flex-shrink:0}
.mm-branch-name{font-family:var(--serif);font-size:1.02rem;font-weight:700;letter-spacing:-.005em;color:rgba(245,240,232,0.94);min-width:0}
.mm-rule{flex:1;height:1px;min-width:18px;background:linear-gradient(90deg,var(--mm-hue),transparent);opacity:.5}
.mm-count{font-family:var(--mono);font-size:9.5px;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-on-dark);flex-shrink:0}

.mm-leaves{display:flex;flex-wrap:wrap;gap:8px}

/* A leaf is a button now, because it goes somewhere. The dot is drawn from the
   branch's own colour rather than written into the markup, so it cannot end up
   disagreeing with the branch it sits under — which is what the old cycling
   `style="background:var(--rust)"` dots did: four colours in rotation, by
   position, meaning nothing.

   NOT inline-flex with a gap. That is what the old tag used, and a flex
   container makes a flex item of every child — so `K<sub>a</sub> and
   K<sub>b</sub>` became four items with the gap applied between each, which is
   why the subscripts read as "K a and K b" with the spacing pulled apart. The
   dot is positioned instead, and the label is left as ordinary inline text
   where subscripts behave. */
.mm-tag{
  position:relative;display:inline-block;text-align:left;line-height:1.45;
  font-size:var(--fs-sm);font-family:var(--sans);
  color:rgba(245,240,232,0.74);
  padding:6px 15px 6px 26px;border-radius:50px;cursor:pointer;
  background:linear-gradient(180deg,rgba(245,240,232,0.085),rgba(245,240,232,0.045));
  border:1px solid rgba(245,240,232,0.11);
  box-shadow:inset 0 1px 0 rgba(255,255,255,0.045);
  transition:var(--trans);
}
.mm-tag::before{content:'';position:absolute;left:13px;top:50%;margin-top:-2.5px;width:5px;height:5px;border-radius:50%;background:var(--mm-hue)}
.mm-tag:hover{
  background:linear-gradient(180deg,rgba(245,240,232,0.15),rgba(245,240,232,0.08));
  color:#f5f0e8;border-color:var(--mm-hue);transform:translateY(-1px);
  box-shadow:inset 0 1px 0 rgba(255,255,255,0.07), 0 3px 10px rgba(0,0,0,0.22);
}
.mm-tag:active{transform:translateY(0)}
.mm-tag:focus-visible{outline:2px solid var(--gold-on-dark);outline-offset:2px}
.mm-tag sub{font-size:.72em}

/* Kept so an un-migrated lecture body still renders while the rest are
   converted. Remove once every mind map is a tree. */
.mm-branches{display:flex;flex-wrap:wrap;gap:8px;margin-top:14px}
.mm-dot{width:5px;height:5px;border-radius:50%;flex-shrink:0}

/* On a phone the branch header has room for a numeral and a name and nothing
   else. The count was being clipped by the panel's own overflow:hidden — which
   hides the symptom and keeps the bug, so it comes off deliberately instead and
   the rule takes the space. Counting four pills on a narrow screen was never
   the hard part. */
@media (max-width:560px){
  .mindmap{padding:24px 20px 26px}
  .mindmap::after{inset:7px}
  .mm-tree{padding-left:28px;gap:20px}
  .mm-branch::before{left:-22px}
  .mm-branch::after{left:-25px}
  .mm-branch-head::before{left:-17px;width:11px}
  .mm-count{display:none}
  .mm-branch-name{font-size:0.96rem}
}

/* ═══════════════════════════════════════════
   SECTIONS
═══════════════════════════════════════════ */
.section{border:1px solid var(--line);border-radius:12px;overflow:hidden;margin-bottom:16px;background:var(--section-bg);box-shadow:var(--shadow);transition:box-shadow 0.2s,background 0.4s,border-color 0.4s}
.section:hover{box-shadow:var(--shadow2)}
.section-header{padding:18px 24px;display:flex;align-items:center;justify-content:space-between;cursor:pointer;user-select:none;transition:background 0.2s}
.section-header:hover{background:rgba(var(--accent-rgb),0.04)}
.section.open .section-header{background:rgba(var(--accent-rgb),0.04)}
.section-left{display:flex;align-items:center;gap:14px}
.section-icon{width:34px;height:34px;border-radius:8px;display:flex;align-items:center;justify-content:center;font-size:var(--fs-md);flex-shrink:0;border:1px solid var(--line);background:var(--hero-bg)}
.section-title-text{font-family:var(--serif);font-weight:700;font-size:1rem;color:var(--ink)}
.section-toggle{width:26px;height:26px;border-radius:50%;background:var(--hero-bg);border:1px solid var(--line);display:flex;align-items:center;justify-content:center;font-size:var(--fs-xs);color:var(--ink3);transition:transform 0.35s,background 0.2s;flex-shrink:0}
/* The glyph is --paper, not #fff, because --gold flips lightness between the
   themes: it is a DARK accent on the light page and a RAISED LIGHT one at
   night. A hard-set white therefore sat on a light-green disc after dark —
   measured 1.91:1 in Module 1, 2.26:1 in Module 2, 2.14:1 in Module 3, against
   the 3:1 floor WCAG 1.4.11 sets for a non-text indicator. --paper flips with
   it, so the glyph is always the opposite of its own disc: 4.80 / 7.03 / 6.36
   in light and 9.83 / 8.36 / 8.87 in dark. */
.section.open .section-toggle{transform:rotate(180deg);background:var(--gold);color:var(--paper);border-color:var(--gold)}
.section-body{max-height:0;overflow:hidden;transition:max-height 0.5s cubic-bezier(0.4,0,0.2,1)}
.section.open .section-body{max-height:10000px}
.section-content{padding:24px;border-top:1px solid var(--line)}
@keyframes searchFlash{0%{background:rgba(var(--accent-rgb),0.28);box-shadow:0 0 0 3px rgba(var(--accent-rgb),0.35)}100%{background:transparent;box-shadow:0 0 0 0 rgba(var(--accent-rgb),0)}}
.search-flash{animation:searchFlash 2.2s ease-out;border-radius:8px}
@media (prefers-reduced-motion:reduce){.search-flash{animation-duration:0.01ms}}

/* ═══════════════════════════════════════════
   FLIP CARDS
═══════════════════════════════════════════ */
.flip-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(190px,1fr));gap:12px;margin:16px 0}
.flip-card{height:150px;perspective:900px;cursor:pointer}
.flip-inner{position:relative;width:100%;height:100%;transform-style:preserve-3d;transition:transform 0.6s cubic-bezier(0.4,0,0.2,1)}
.flip-card.flipped .flip-inner{transform:rotateY(180deg)}
.flip-front,.flip-back{position:absolute;inset:0;backface-visibility:hidden;border-radius:10px;padding:18px;display:flex;flex-direction:column;justify-content:center;align-items:center;text-align:center}
.flip-front{background:var(--hero-bg);border:1px solid var(--line);font-family:var(--serif);font-weight:700;font-size:0.9rem;color:var(--ink)}
.flip-front .card-ico{font-size:1.6rem;margin-bottom:10px}
.flip-front .hint{font-family:var(--mono);font-size:var(--fs-xs);color:var(--ink3);margin-top:8px;letter-spacing:0.05em}
.flip-back{background:var(--ink2);border:1px solid rgba(var(--accent-rgb),0.3);transform:rotateY(180deg);font-size:var(--fs-sm);line-height:1.65;color:rgba(245,240,232,0.8);text-align:left;align-items:flex-start;justify-content:flex-start;overflow-y:auto}
.flip-back::-webkit-scrollbar{display:none}
.flip-back strong{color:var(--gold3);display:block;margin-bottom:5px;font-size:var(--fs-sm);font-family:var(--mono);letter-spacing:0.05em;text-transform:uppercase}

/* ═══════════════════════════════════════════
   TABLES
═══════════════════════════════════════════ */
.tbl-wrap{overflow-x:auto;margin:16px 0;border-radius:10px;border:1px solid var(--line)}
table{width:100%;border-collapse:collapse;font-size:var(--fs-base)}
thead tr{background:var(--hero-bg)}
th{padding:11px 16px;text-align:left;font-family:var(--mono);font-size:var(--fs-xs);color:var(--ink3);text-transform:uppercase;letter-spacing:0.1em;border-bottom:1px solid var(--line);white-space:nowrap}
td{padding:10px 16px;border-bottom:1px solid var(--line2);color:var(--ink2);vertical-align:top;font-size:var(--fs-base);line-height:1.6}
tr:last-child td{border-bottom:none}
tr:hover td{background:rgba(var(--accent-rgb),0.04)}

/* ═══════════════════════════════════════════
   INFO BOXES
═══════════════════════════════════════════ */
.info-box{border-radius:8px;padding:14px 18px;margin:12px 0;font-size:var(--fs-base);line-height:1.75;border-left:3px solid var(--gold);background:rgba(var(--accent-rgb),0.06)}
.info-box.warn{border-left-color:var(--rust);background:rgba(139,58,42,0.07)}
.info-box.tip{border-left-color:var(--teal);background:rgba(42,107,107,0.07)}
.info-box.formula{font-family:var(--mono);font-size:var(--fs-base);background:var(--ink2);border:1px solid rgba(var(--accent-rgb),0.25);border-left:3px solid var(--gold);color:var(--gold-on-dark);text-align:center;padding:16px;letter-spacing:0.04em;border-radius:8px}
[data-theme="dark"] .info-box.formula{background:#0a0906}
.info-box h4{font-family:var(--mono);font-size:var(--fs-xs);color:var(--gold);margin-bottom:6px;letter-spacing:0.12em;text-transform:uppercase}
.info-box.warn h4{color:var(--rust)}
.info-box.tip h4{color:var(--teal2)}

/* THE FORMULA BOX IS A DARK PANEL IN BOTH THEMES, AND THE PAGE'S TOKENS ARE THE
   WRONG CALIBRATION FOR IT.
   Its ground is `--ink2` in the light theme and #0a0906 in the dark one — which
   are exactly the sidebar's two grounds, so it takes the sidebar's two tokens.
   This is the same trap that file documents: a colour is calibrated for a
   surface, and every other rule here is calibrated for the cream page.

   Without these, anything an author puts inside carries a light-page colour on
   to a dark panel. Measured before the fix: `.body-text` landed on exactly the
   background at 1.00:1 — invisible — a bare <li> the same, <strong> at 1.84:1,
   and `.info-box h4` at 1.53:1 in Module 2, which has shipped 39 of these boxes.

   After: 5.77 / 5.00 / 5.23:1 in light and 9.22 / 8.79 / 9.38:1 in dark, for
   modules 1, 2 and 3. Inheriting is what makes it safe for the next author too
   — the box decides its own colour and nothing inside re-asserts one. */
.info-box.formula p,
.info-box.formula li,
.info-box.formula span,
.info-box.formula strong,
.info-box.formula em,
.info-box.formula .body-text,
.info-box.formula .chem-list,
/* TABLE CELLS TOO — bug #26, second occurrence.
   The list above was written when no formula box contained a table, so `td`
   was not on it. Module 4's octane-rating table is inside one, and its cells
   took `--ink2` from the general table rule — which is EXACTLY this panel's
   background in the light theme. Contrast 1.00: the text was not faint, it was
   invisible, and a <strong> inside a cell inherited the same nothing.
   Anything that can hold text inside this box has to inherit. */
.info-box.formula table,
.info-box.formula thead,
.info-box.formula tbody,
.info-box.formula tr,
.info-box.formula th,
.info-box.formula td{color:inherit}
.info-box.formula h4{color:var(--ink-on-dark)}
/* The rules between rows would be page-calibrated too, and vanish or glare. */
.info-box.formula th,
.info-box.formula td{border-color:rgba(var(--accent-rgb),0.28)}
/* AND THE HEADER ROW'S BACKGROUND — bug #26, third occurrence.
   The guard above fixed every COLOUR inside this box and left one surface
   behind: `thead tr{background:var(--hero-bg)}` and, after dark,
   `[data-theme="dark"] th{background:var(--cream2)}`. Both are page
   backgrounds, asserted inside a panel that is dark in BOTH themes — so the
   cell text correctly inherited `--gold-on-dark` and then sat on a light band.
   Measured at 1.84:1 on Lecture 15's directing-groups and boiling-point
   tables, and on Lecture 13's octane-rating table, which has been shipped in
   that state since the table was added.
   The header still reads as a header without a fill: it already has uppercase
   mono type, letter-spacing, and the rule underneath it from the line above. */
.info-box.formula thead tr,
.info-box.formula th,
[data-theme="dark"] .info-box.formula thead tr,
[data-theme="dark"] .info-box.formula th{background:transparent}

/* ═══════════════════════════════════════════
   LISTS
═══════════════════════════════════════════ */
ul.chem-list{padding:0;list-style:none;margin:10px 0}
ul.chem-list li{padding:7px 0 7px 22px;position:relative;font-size:var(--fs-base);line-height:1.65;border-bottom:1px solid var(--line2);font-family:var(--body);color:var(--ink2)}
ul.chem-list li:last-child{border-bottom:none}
ul.chem-list li::before{content:'→';position:absolute;left:0;color:var(--gold);font-size:var(--fs-sm);top:9px;font-family:var(--mono)}
ul.chem-list li strong{color:var(--teal);font-family:var(--sans)}

/* ═══════════════════════════════════════════
   BADGES
═══════════════════════════════════════════ */
.badge{display:inline-flex;align-items:center;font-family:var(--mono);font-size:var(--fs-xs);padding:2px 8px;border-radius:4px;margin:2px;font-weight:400}
.badge.default{background:rgba(var(--accent-rgb),0.12);color:var(--gold);border:1px solid rgba(var(--accent-rgb),0.25)}
.badge.teal{background:rgba(42,107,107,0.1);color:var(--teal);border:1px solid rgba(42,107,107,0.2)}
.badge.rust{background:rgba(139,58,42,0.1);color:var(--rust);border:1px solid rgba(139,58,42,0.2)}
.badge.emerald{background:rgba(45,90,61,0.1);color:var(--emerald);border:1px solid rgba(45,90,61,0.2)}

/* ═══════════════════════════════════════════
   COMPARE GRID
═══════════════════════════════════════════ */
.compare-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin:12px 0}
.compare-card{background:var(--hero-bg);border:1px solid var(--line);border-radius:10px;padding:16px}
.compare-card h4{font-family:var(--serif);font-weight:700;font-size:0.85rem;color:var(--ink);margin-bottom:10px}
.compare-card ul{list-style:none;padding:0}
.compare-card ul li{font-size:var(--fs-base);padding:4px 0;border-bottom:1px solid var(--line2);color:var(--ink2)}
.compare-card ul li:last-child{border-bottom:none}
.compare-card ul li::before{content:'· ';color:var(--gold)}

/* ═══════════════════════════════════════════
   SUBSECTIONS
═══════════════════════════════════════════ */
.sub-section{margin-bottom:22px}
.sub-title{font-family:var(--serif);font-weight:700;font-size:0.88rem;color:var(--ink);margin-bottom:12px;padding-bottom:7px;border-bottom:1px solid var(--line);display:flex;align-items:center;gap:8px}
.sub-title::before{content:'';width:18px;height:2px;background:var(--gold);flex-shrink:0}
p.body-text{font-size:var(--fs-base);line-height:1.8;color:var(--ink2);margin:10px 0;font-family:var(--body)}
p.body-text strong{color:var(--teal);font-family:var(--sans)}

/* ═══════════════════════════════════════════
   FLOW DIAGRAM
═══════════════════════════════════════════ */
.diagram{background:var(--hero-bg);border-radius:12px;padding:24px;margin:16px 0;border:1px solid var(--line)}
.diagram-label{font-family:var(--mono);font-size:var(--fs-xs);color:var(--gold);text-transform:uppercase;letter-spacing:0.15em;margin-bottom:16px;display:flex;align-items:center;gap:8px}
.diagram-label::before{content:'';width:16px;height:1px;background:var(--gold)}
.flow-wrap{display:flex;flex-direction:column;align-items:center}
.flow-step{background:var(--section-bg);border:1px solid var(--line);border-radius:8px;padding:10px 28px;font-size:var(--fs-base);text-align:center;width:100%;max-width:360px;opacity:0;transform:translateX(-16px);transition:opacity 0.4s,transform 0.4s;color:var(--ink2)}
.flow-step.show{opacity:1;transform:translateX(0)}
/* --gold, not --gold3. Every theme file describes --gold3 as decorative and
   names its contrast — 2.51:1 in Module 4, and it measured 1.77:1 here in
   Module 1's light theme. An arrow between two steps is a glyph a reader has
   to see, so it takes the text-safe half of the pair. */
.flow-arrow{color:var(--gold);font-size:16px;margin:3px 0;opacity:0;transition:opacity 0.3s}
.flow-arrow.show{opacity:1}
.btn-animate{background:transparent;border:1px solid var(--line);color:var(--gold);padding:7px 18px;border-radius:6px;font-size:var(--fs-sm);cursor:pointer;margin-bottom:14px;font-family:var(--mono);transition:var(--trans);letter-spacing:0.05em}
.btn-animate:hover{background:var(--gold);color:var(--paper)}

/* ═══════════════════════════════════════════
   BUTTONS
═══════════════════════════════════════════ */
.print-btn{background:transparent;border:1px solid var(--line);color:var(--ink3);padding:6px 14px;border-radius:6px;font-family:var(--mono);font-size:var(--fs-xs);cursor:pointer;transition:var(--trans);display:inline-flex;align-items:center;gap:6px}
.print-btn:hover{border-color:var(--teal);color:var(--teal)}
.bm-btn{background:transparent;border:1px solid var(--line);color:var(--ink3);padding:5px 12px;border-radius:6px;font-family:var(--mono);font-size:var(--fs-xs);cursor:pointer;display:flex;align-items:center;gap:6px;transition:var(--trans)}
.bm-btn:hover{border-color:var(--gold);color:var(--gold);background:rgba(var(--accent-rgb),0.05)}
.bm-btn.saved{border-color:var(--gold);color:var(--gold);background:rgba(var(--accent-rgb),0.08)}

/* ═══════════════════════════════════════════
   QUIZ
═══════════════════════════════════════════ */
.quiz-wrap{margin-top:48px;background:var(--quiz-bg);border-radius:14px;overflow:hidden;border:1px solid rgba(var(--accent-rgb),0.2);transition:background 0.4s}
.quiz-hero{padding:28px 32px 20px;border-bottom:1px solid rgba(255,255,255,0.08);display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:10px}
.quiz-title{font-family:var(--serif);font-weight:900;font-size:1.1rem;color:#f5f0e8;display:flex;align-items:center;gap:12px;flex-wrap:wrap}
.quiz-pill{font-family:var(--mono);font-size:var(--fs-xs);background:rgba(var(--accent-rgb),0.2);color:var(--gold2);padding:3px 12px;border-radius:20px;border:1px solid rgba(var(--accent-rgb),0.3)}
.quiz-timer-display{font-family:var(--mono);font-size:var(--fs-base);color:rgba(245,240,232,0.78);display:flex;align-items:center;gap:6px}
.quiz-timer-display.warning{color:#f87171;animation:pulse 0.8s infinite}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:0.5}}
.timer-toggle{background:rgba(255,255,255,0.08);border:1px solid rgba(255,255,255,0.12);color:rgba(245,240,232,0.78);font-family:var(--mono);font-size:var(--fs-xs);letter-spacing:0.1em;padding:3px 10px;border-radius:4px;cursor:pointer;transition:var(--trans)}
.timer-toggle:hover{background:rgba(255,255,255,0.14);color:#f5f0e8}
.q-block{display:none}
.q-block.active{display:block;animation:pgIn 0.3s ease}
.q-body{padding:28px 32px}
.q-meta{font-family:var(--mono);font-size:var(--fs-xs);color:rgba(245,240,232,0.62);margin-bottom:12px;display:flex;align-items:center;gap:8px}
.q-progress-dots{display:flex;gap:4px}
.q-dot{width:6px;height:6px;border-radius:50%;background:rgba(255,255,255,0.15);transition:background 0.3s}
.q-dot.done{background:var(--gold2)}
.q-dot.current{background:rgba(245,240,232,0.7)}
.q-text{font-family:var(--body);font-size:var(--fs-md);line-height:1.75;color:#f5f0e8;margin-bottom:22px;font-style:italic}
.options{display:flex;flex-direction:column;gap:8px}
.opt{background:rgba(255,255,255,0.05);border:1px solid rgba(255,255,255,0.1);border-radius:8px;padding:12px 18px;font-size:var(--fs-base);cursor:pointer;text-align:left;color:rgba(245,240,232,0.88);transition:var(--trans);display:flex;align-items:center;gap:12px;font-family:var(--sans);width:100%}
.opt-letter{width:22px;height:22px;border-radius:50%;border:1.5px solid rgba(255,255,255,0.2);display:flex;align-items:center;justify-content:center;font-family:var(--mono);font-size:var(--fs-xs);color:rgba(245,240,232,0.78);flex-shrink:0;transition:var(--trans)}
.opt:hover:not(:disabled){background:rgba(255,255,255,0.09);border-color:rgba(var(--accent-rgb),0.4);color:#f5f0e8;transform:translateX(3px)}
.opt:hover:not(:disabled) .opt-letter{border-color:var(--gold2);color:var(--gold2)}
.opt.correct{background:rgba(45,90,61,0.25);border-color:rgba(45,90,61,0.5);color:#a7f3d0;animation:correctPop 0.4s ease}
.opt.correct .opt-letter{background:var(--emerald);border-color:var(--emerald);color:#fff}
.opt.wrong{background:rgba(139,58,42,0.2);border-color:rgba(139,58,42,0.4);color:#fca5a5}
.opt.wrong .opt-letter{background:var(--rust);border-color:var(--rust);color:#fff}
.opt:disabled{cursor:default;pointer-events:none}
@keyframes correctPop{0%{transform:scale(1)}50%{transform:scale(1.02)}100%{transform:scale(1)}}

/* Quiz explanation box */
.q-explain{
  margin-top:12px;padding:12px 16px;border-radius:8px;
  background:rgba(var(--accent-rgb),0.1);border:1px solid rgba(var(--accent-rgb),0.25);
  font-size:var(--fs-base);line-height:1.7;color:rgba(245,240,232,0.75);
  display:none;
  animation:pgIn 0.3s ease;
}
.q-explain.show{display:block}
.q-explain strong{color:var(--gold3);font-family:var(--mono);font-size:var(--fs-xs);display:block;margin-bottom:5px;letter-spacing:0.08em;text-transform:uppercase}

.quiz-footer{padding:16px 32px 24px;display:flex;align-items:center;justify-content:space-between}
/* --paper on --gold, NEVER --ink on --gold.

   --ink and --gold both flip with the theme and both flip the SAME way: at
   night --gold is raised to stay visible on a dark ground and --ink is raised
   to near-white. Put them together and you get light text on a light button —
   measured at 1.64:1 in Module 1 and 1.96:1 in Module 4, against a 4.5 floor,
   on the primary action of every lecture. It has been live.

   --paper is the half that flips the OTHER way, so --paper on --gold stays a
   real pairing in both themes. Same rule the module 3 labs arrived at from the
   other direction, where --paper had been put on --gold-ui and measured 3.45. */
.btn-next{background:var(--gold);color:var(--paper);border:none;padding:10px 26px;border-radius:8px;font-size:var(--fs-sm);cursor:pointer;font-weight:500;font-family:var(--mono);letter-spacing:0.06em;transition:var(--trans)}
.btn-next:hover{background:var(--gold2);transform:translateY(-1px)}
.score-display{font-family:var(--mono);font-size:var(--fs-sm);color:rgba(245,240,232,0.88)}

/* ═══════════════════════════════════════════
   SCORE DASHBOARD
═══════════════════════════════════════════ */
.dashboard-wrap{padding:48px 64px;border-top:1px solid var(--line);background:linear-gradient(180deg,var(--main-bg),rgba(var(--accent-rgb),0.03));transition:background 0.4s}
.dash-heading{font-family:var(--serif);font-weight:900;font-size:1.8rem;color:var(--ink);margin-bottom:8px}
.dash-sub{font-family:var(--body);font-size:var(--fs-base);color:var(--ink3);font-style:italic;margin-bottom:32px}
.dash-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:16px;margin-bottom:32px}
.dash-card{background:var(--section-bg);border:1px solid var(--line);border-radius:12px;padding:20px;position:relative;overflow:hidden;transition:var(--trans)}
.dash-card:hover{box-shadow:var(--shadow2);transform:translateY(-2px)}
.dash-card::before{content:'';position:absolute;top:0;left:0;right:0;height:3px}
.dash-card.card-gold::before{background:linear-gradient(90deg,var(--gold),var(--gold3))}
.dash-card.card-teal::before{background:linear-gradient(90deg,var(--teal),var(--teal2))}
.dash-card.card-emerald::before{background:linear-gradient(90deg,var(--emerald),#3d8b5e)}
.dash-card.card-rust::before{background:linear-gradient(90deg,var(--rust),#c0644a)}
.dash-lecture{font-family:var(--mono);font-size:var(--fs-xs);color:var(--ink3);letter-spacing:0.12em;text-transform:uppercase;margin-bottom:8px}
.dash-name{font-family:var(--serif);font-weight:700;font-size:0.88rem;color:var(--ink);margin-bottom:16px}
.dash-score-big{font-family:var(--serif);font-weight:900;font-size:2.4rem;color:var(--ink);line-height:1}
.dash-denom{font-size:1rem;color:var(--ink3);font-weight:400}
.dash-bar-wrap{margin-top:12px;height:4px;background:var(--cream3);border-radius:2px;overflow:hidden}
.dash-bar{height:100%;border-radius:2px;transition:width 1s cubic-bezier(0.4,0,0.2,1)}
.dash-bar.gold{background:linear-gradient(90deg,var(--gold),var(--gold3))}
.dash-bar.teal{background:linear-gradient(90deg,var(--teal),var(--teal2))}
.dash-bar.emerald{background:linear-gradient(90deg,var(--emerald),#3d8b5e)}
.dash-bar.rust{background:linear-gradient(90deg,var(--rust),#c0644a)}
.dash-pct{font-family:var(--mono);font-size:var(--fs-xs);color:var(--ink3);margin-top:6px}
.dash-overall{background:var(--quiz-bg);border-radius:12px;padding:24px 28px;display:flex;align-items:center;justify-content:space-between;border:1px solid rgba(var(--accent-rgb),0.2)}
.dash-overall-left h3{font-family:var(--serif);font-weight:900;font-size:1rem;color:#f5f0e8;margin-bottom:4px}
.dash-overall-left p{font-family:var(--body);font-size:var(--fs-sm);color:rgba(245,240,232,0.72);font-style:italic}
.dash-grade{font-family:var(--serif);font-weight:900;font-size:3rem;color:var(--gold2)}

/* ═══════════════════════════════════════════
   MOBILE HAMBURGER
═══════════════════════════════════════════ */
/* ── Menu button ──
   Anchored left, matching the side the drawer slides in from. Morphs into a
   close (X) while the drawer is open so its meaning is never ambiguous. */
.hamburger{
  display:none;position:fixed;top:14px;left:14px;z-index:1000;
  width:44px;height:44px;border-radius:12px;
  background:var(--quiz-bg);border:1px solid rgba(255,255,255,0.14);
  flex-direction:column;align-items:center;justify-content:center;gap:4px;
  cursor:pointer;box-shadow:var(--shadow);
  transition:background 0.24s var(--ease), border-color 0.24s var(--ease);
}
.hamburger:hover{border-color:var(--gold-ui)}
.hamburger span{
  display:block;width:18px;height:1.5px;background:var(--cream);border-radius:1px;
  transition:transform 0.3s var(--ease-out), opacity 0.2s var(--ease);
}
body.nav-open .hamburger span:nth-child(1){transform:translateY(5.5px) rotate(45deg)}
body.nav-open .hamburger span:nth-child(2){opacity:0}
body.nav-open .hamburger span:nth-child(3){transform:translateY(-5.5px) rotate(-45deg)}

.sidebar-overlay{
  position:fixed;inset:0;background:rgba(14,12,10,0.55);
  z-index:98;backdrop-filter:blur(2px);
  opacity:0;visibility:hidden;transition:opacity 0.3s var(--ease), visibility 0.3s;
}
.sidebar-overlay.open{opacity:1;visibility:visible}

/* Toast notification.

   Its text is hard-set cream, so its background has to be dark in BOTH themes
   — exactly like the sidebar two hundred lines up, and for the same reason.
   It was `var(--ink2)` with no dark override, so at night the surface flipped
   to #cdc5b8 and cream sat on cream at 1.45:1: unreadable, and only in the
   theme where a toast is most likely to be the brightest thing on screen. */
.toast{
  position:fixed;top:24px;left:50%;transform:translateX(-50%) translateY(-80px);
  background:var(--ink2);border:1px solid rgba(var(--accent-rgb),0.3);
  color:rgba(245,240,232,0.9);padding:10px 20px;border-radius:8px;
  font-family:var(--mono);font-size:var(--fs-sm);z-index:1000;
  transition:transform 0.4s cubic-bezier(0.4,0,0.2,1);
  white-space:nowrap;letter-spacing:0.05em;
  box-shadow:0 4px 20px rgba(0,0,0,0.3);
}
[data-theme="dark"] .toast{background:#0a0906}
.toast.show{transform:translateX(-50%) translateY(0)}

/* Keyboard shortcut tooltip */
.kbd{display:inline-flex;align-items:center;background:rgba(255,255,255,0.08);border:1px solid rgba(255,255,255,0.15);border-radius:4px;padding:1px 6px;font-family:var(--mono);font-size:var(--fs-xs);color:rgba(245,240,232,0.78)}

/* ═══════════════════════════════════════════
   RESPONSIVE
═══════════════════════════════════════════ */
/* ── Laptop / small desktop ── */
@media(max-width:1180px){
  :root{--sidebar-w:256px}
  .page-hero{padding:52px 44px 38px}
  .content-body{padding:38px 44px}
  .dashboard-wrap{padding:38px 44px}
}

/* ── Tablet (iPad portrait and below): drawer navigation ──
   1024px covers iPad Air/Pro portrait, which the old 768px breakpoint left
   in a cramped two-column layout. */
@media(max-width:1024px){
  .sidebar{
    position:fixed;left:0;top:0;bottom:0;z-index:99;
    width:min(320px,86vw);min-width:0;
    transform:translateX(-100%);
    box-shadow:none;
  }
  .sidebar.open{transform:translateX(0);box-shadow:4px 0 32px rgba(0,0,0,0.4)}
  .hamburger{display:flex}
  /* Reading mode must not collapse the drawer on touch layouts. */
  body.reading-mode .sidebar{width:min(320px,86vw);min-width:0}
  body.reading-mode .sidebar .logo-eyebrow,
  body.reading-mode .sidebar .logo-main,
  body.reading-mode .sidebar .logo-sub,
  body.reading-mode .sidebar .progress-section,
  body.reading-mode .sidebar .search-wrap,
  body.reading-mode .sidebar .nav-group-label,
  body.reading-mode .sidebar .nav-text,
  body.reading-mode .sidebar .nav-check,
  body.reading-mode .sidebar .nav-score,
  body.reading-mode .sidebar .bm-panel{display:revert}
  body.reading-mode .sidebar .sidebar-controls{flex-direction:row;padding:12px 20px}
  body.reading-mode .sidebar .ctrl-btn{width:auto;padding:7px 12px}
  body.reading-mode .sidebar .ctrl-btn .ctrl-label{display:inline}
  body.reading-mode .sidebar .ctrl-btn::after{content:none}
  body.reading-mode .sidebar .nav-item{justify-content:flex-start}
  body.reading-mode .sidebar .sidebar-logo::before{content:none}
  body.reading-mode .sidebar .sidebar-logo{padding:32px 24px 24px;text-align:left}

  /* Leave room for the fixed menu button. */
  .page-hero{padding:76px 40px 36px}
  .content-body{padding:34px 36px}
  .dashboard-wrap{padding:34px 36px}
}

/* ── Large phone / small tablet ── */
@media(max-width:720px){
  .page-hero{padding:72px 22px 30px}
  .content-body{padding:26px 20px}
  .dashboard-wrap{padding:26px 20px}
  .compare-grid{grid-template-columns:1fr}
  .flip-grid{grid-template-columns:1fr}
  .dash-grid{grid-template-columns:1fr}
  .q-body{padding:20px 18px}
  .quiz-hero{padding:20px 18px 16px}
  .quiz-footer{padding:14px 18px 20px}
  .tbl-wrap{margin-inline:-20px;padding-inline:20px}
  .section-header{padding:16px 18px}
  .section-content{padding:20px 18px}
  .hero-actions{gap:8px}
}

/* ── Phone ── */
@media(max-width:480px){
  .page-hero{padding:70px 18px 26px}
  .content-body{padding:22px 16px}
  .dashboard-wrap{padding:22px 16px}
  .hero-molecule{display:none}
  .section-header{padding:14px 16px}
  .section-content{padding:18px 16px}
  .tbl-wrap{margin-inline:-16px;padding-inline:16px}
  .toast{left:12px;right:12px;transform:translateY(-100px);white-space:normal;text-align:center}
  .toast.show{transform:translateY(0)}
}

/* Touch targets: pointer-coarse devices need ≥44px hit areas. */
@media(pointer:coarse){
  .nav-item{min-height:48px}
  .ctrl-btn{min-height:40px}
  .opt{min-height:48px}
  .section-header{min-height:56px}
}

/* Tables scroll horizontally rather than breaking the page width. */
.tbl-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch}

/* ═══════════════════════════════════════════
   PRINT
═══════════════════════════════════════════ */
@media print{
  .sidebar,.hamburger,.quiz-wrap,.btn-animate,.print-btn,.toast{display:none!important}
  .main{overflow:visible}
  .page{display:block!important}
  body{background:#fff!important;color:#000!important}
  body::before{display:none}
  .section-body{max-height:none!important}
  .page-hero{background:#fff!important;border-bottom:2px solid #000!important;padding:32px!important}
  .page-title{color:#000!important;font-size:2rem!important}
  .page-title em{color:#b8903a!important}
  .content-body{padding:24px 32px!important}
  .section{break-inside:avoid;border:1px solid #ccc!important;background:#fff!important}
  .section-body{max-height:none!important;display:block!important}
  .section-content{display:block!important}
  .section-toggle,.bm-btn,.diagram button{display:none!important}
  table{break-inside:avoid}
  .info-box{background:#f9f5ee!important;border-left:3px solid #b8903a!important}
  .info-box.formula{background:#1a1814!important;color:#f0c97a!important}
  .flip-grid{display:none!important}
  .mindmap{background:#1a1814!important}
  .compare-grid{grid-template-columns:1fr 1fr!important}
  .dashboard-wrap{display:none!important}
  a::after{content:" ("attr(href)")"!important}
  @page{margin:1.5cm;size:A4}
}

/* ─── Additions from the refactor ─── */

/* Accessible visually-hidden helper (for the search <label>). */
.visually-hidden{position:absolute!important;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}

/* Nav score badge colored via data-tier (replaces the old JS-injected
   style.cssText). Base spacing/typography still lives in .nav-score. */
.nav-score[data-tier="high"]{background:rgba(45,90,61,0.2);color:#6ee7b7;border:1px solid rgba(45,90,61,0.3)}
.nav-score[data-tier="mid"]{background:rgba(var(--accent-rgb),0.15);color:var(--gold2);border:1px solid rgba(var(--accent-rgb),0.25)}
.nav-score[data-tier="low"]{background:rgba(139,58,42,0.15);color:#fca5a5;border:1px solid rgba(139,58,42,0.25)}

/* Overall grade color via tier (was inline style before). */
.dash-grade[data-tier="high"]{color:var(--emerald)}
.dash-grade[data-tier="mid"]{color:var(--gold2)}
.dash-grade[data-tier="low"]{color:var(--rust)}

/* Bookmark star (was inline <span style>). */
.bm-star{color:var(--gold2);font-size:var(--fs-xs)}

/* Quiz-complete screen (was a giant inline-styled block in nextQ()). */
.quiz-complete{text-align:center;padding:40px 24px}
.quiz-complete .qc-emoji{font-size:3rem;margin-bottom:16px}
.quiz-complete .qc-title{font-family:var(--serif);font-size:1.4rem;font-weight:900;color:#f5f0e8;margin-bottom:6px}
.quiz-complete .qc-msg{font-family:var(--body);font-size:var(--fs-base);color:rgba(245,240,232,0.78);font-style:italic;margin-bottom:20px}
.quiz-complete .qc-grade{font-family:var(--mono);font-size:2.5rem;color:var(--gold2);margin-bottom:4px}
.quiz-complete .qc-score{font-family:var(--mono);font-size:1rem;color:rgba(245,240,232,0.78);margin-bottom:4px}
.quiz-complete .qc-pct{font-family:var(--mono);font-size:var(--fs-sm);color:var(--gold);margin-bottom:28px}
.quiz-complete .qc-actions{display:flex;gap:12px;justify-content:center;flex-wrap:wrap}
.quiz-complete .qc-retry{background:transparent;border:1px solid rgba(var(--accent-rgb),0.4);color:var(--gold);padding:10px 22px;border-radius:8px;cursor:pointer;font-family:var(--mono);font-size:var(--fs-sm);letter-spacing:0.06em;transition:background 0.2s}
.quiz-complete .qc-retry:hover{background:rgba(var(--accent-rgb),0.15)}

/* ═══════════════════════════════════════════
   REFINEMENT LAYER
   Typography scale, icon sizing, and dark-surface
   corrections applied on top of the base rules.
═══════════════════════════════════════════ */

/* Base rhythm — body copy is set for sustained reading, not glanceability. */
body{font-size:var(--fs-base);line-height:var(--lh-body);-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}
.body-text{font-family:var(--body);font-size:var(--fs-base);line-height:var(--lh-body);color:var(--ink2);margin-bottom:1.1em}
.body-text:last-child{margin-bottom:0}

/* Headings hold a clear step above body text. */
.page-title{font-size:var(--fs-2xl);line-height:var(--lh-tight);letter-spacing:-0.015em}
.page-summary{font-size:var(--fs-md);line-height:var(--lh-snug);max-width:62ch}
.section-title-text{font-size:var(--fs-lg);line-height:var(--lh-snug);letter-spacing:-0.005em}
.sub-title{font-size:var(--fs-md)}
.dash-heading{font-size:var(--fs-xl);line-height:var(--lh-tight)}

/* Measure: long-form prose is capped so lines stay scannable. */
.section-content > .body-text,
.section-content > .sub-section > .body-text{max-width:68ch}

/* Tables and lists inherit the readable base rather than shrinking. */
table{font-size:var(--fs-sm)}
th{font-size:var(--fs-xs);letter-spacing:0.08em;text-transform:uppercase}
td{line-height:var(--lh-snug);padding-block:11px}
.chem-list li{font-size:var(--fs-base);line-height:var(--lh-body)}
.info-box{font-size:var(--fs-base);line-height:var(--lh-body)}
.q-text{font-size:var(--fs-md);line-height:var(--lh-snug)}
.opt{font-size:var(--fs-base)}
.q-explain{font-size:var(--fs-sm);line-height:var(--lh-body)}

/* Search field icon is now an SVG, not a glyph. */
.search-icon{width:15px;height:15px;flex-shrink:0;color:rgba(245,240,232,0.6)}
.search-box:focus-within .search-icon{color:var(--gold3)}

/* The nav check is a drawn mark, sized against its ring. */
.nav-check{font-size:10px;line-height:1}

/* Focus-mode rail: centre the collapsed nav numerals. */
body.reading-mode .nav-num{margin-inline:auto}

/* ── Dark-mode surface corrections ──
   The base sheet hard-codes several light-only surfaces; in dark theme they
   turned into white slabs (or invisible text). These re-bind them to tokens. */
[data-theme="dark"] .section{background:var(--section-bg);border-color:var(--line)}
[data-theme="dark"] .section-content{border-top-color:var(--line)}
[data-theme="dark"] .page-hero{background:var(--hero-bg)}
[data-theme="dark"] .tbl-wrap table{background:var(--card-bg)}
[data-theme="dark"] th{background:var(--cream2);color:var(--ink2)}
[data-theme="dark"] td{border-color:var(--line2);color:var(--ink2)}
[data-theme="dark"] tr:nth-child(even) td{background:rgba(255,255,255,0.018)}
[data-theme="dark"] .compare-card{background:var(--card-bg);border-color:var(--line)}
[data-theme="dark"] .info-box{background:var(--cream2);color:var(--ink2)}
[data-theme="dark"] .flip-front,
[data-theme="dark"] .flip-back{background:var(--card-bg);border-color:var(--line);color:var(--ink)}
[data-theme="dark"] .dash-card{background:var(--card-bg);border-color:var(--line)}
[data-theme="dark"] .search-results{background:#141109;border-color:rgba(255,255,255,0.14)}
[data-theme="dark"] mark{background:rgba(224,181,102,0.26);color:var(--gold3)}
[data-theme="dark"] .main::-webkit-scrollbar-thumb{background:var(--cream3)}

/* Selection matches the brand rather than the browser default. */
::selection{background:rgba(var(--accent-rgb),0.28);color:var(--ink)}

/* Sidebar type is tuned to the rail width so labels stay on one line. */
.nav-text{font-size:var(--fs-sm);line-height:1.3;padding:12px 10px 12px 8px}
.nav-num{font-size:10px;letter-spacing:.04em}
.logo-main{font-size:1.5rem}
.ctrl-btn{padding:7px 12px;letter-spacing:.06em}
.sidebar-controls{gap:8px}
@media(max-width:1180px){
  :root{--sidebar-w:272px}
}

/* Section markers are set numerals, not pictograms — they index the lecture
   and carry no invented meaning. */
.section-icon{
  width:auto;min-width:30px;height:auto;
  border:none;background:none;border-radius:0;
  font-family:var(--mono);font-size:var(--fs-xs);font-weight:400;
  letter-spacing:.08em;color:var(--gold);
  display:flex;align-items:center;justify-content:flex-start;
  padding-right:14px;margin-right:2px;
  border-right:1px solid var(--line);
  align-self:stretch;
}
.section.open .section-icon{color:var(--gold2)}

/* Flip cards lost their pictogram; the face now leads with its title. */
.flip-front{justify-content:center;gap:10px;text-align:center;padding:22px 18px}
.flip-front .hint{
  /* opacity was .8, which composited --ink3 down to 4.21:1 on the flip face —
     under the floor for 10px text, on L0 and L1's flip cards. The token passes
     at full strength; the quietness is already carried by the size, the
     letter-spacing and the uppercase. Third time this project has faded a
     passing token below the floor — see CLAUDE.md §12.8. */
  font-family:var(--mono);font-size:10px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--ink3);
}

/* ── Quiz result ──
   A typographic result card: label, grade, tally, note. No badge imagery. */
.quiz-complete{text-align:center;padding:48px 24px 44px}
.quiz-complete .qc-label{
  font-family:var(--mono);font-size:10px;letter-spacing:.22em;text-transform:uppercase;
  color:rgba(245,240,232,.5);margin-bottom:18px;
}
.quiz-complete .qc-grade{
  font-family:var(--serif);font-weight:900;font-size:4.2rem;line-height:1;
  color:var(--gold3);letter-spacing:-.02em;
}
.quiz-complete .qc-score{
  font-family:var(--mono);font-size:var(--fs-sm);color:rgba(245,240,232,.72);
  margin-top:12px;letter-spacing:.04em;
}
.quiz-complete .qc-msg{
  font-family:var(--body);font-size:var(--fs-sm);font-style:italic;
  color:rgba(245,240,232,.55);margin:14px auto 26px;max-width:38ch;line-height:1.6;
}
.quiz-complete .qc-actions{display:flex;gap:12px;justify-content:center;flex-wrap:wrap}
.quiz-complete .qc-retry{
  background:transparent;border:1px solid rgba(var(--accent-rgb),.45);color:var(--gold3);
  padding:11px 26px;border-radius:4px;cursor:pointer;
  font-family:var(--mono);font-size:var(--fs-xs);letter-spacing:.12em;text-transform:uppercase;
  transition:background .24s var(--ease),border-color .24s var(--ease);
}
.quiz-complete .qc-retry:hover{background:rgba(var(--accent-rgb),.16);border-color:var(--gold2)}

/* Bookmark control: text only, state carried by weight and rule. */
.bm-btn{
  font-family:var(--mono);font-size:var(--fs-xs);letter-spacing:.1em;text-transform:uppercase;
}
.bm-btn.saved{border-color:var(--gold-ui);color:var(--gold)}
.bm-item{padding:8px 0}

/* ── Flow diagrams ──
   Steps are legible on load; "Replay" re-runs the stagger. Content is never
   hidden behind an optional control. */
.flow-step{opacity:1;transform:none}
.flow-arrow{opacity:1}
.flow-wrap.replaying .flow-step{opacity:0;transform:translateX(-16px)}
.flow-wrap.replaying .flow-arrow{opacity:0}
.flow-wrap.replaying .flow-step.show{opacity:1;transform:translateX(0)}
.flow-wrap.replaying .flow-arrow.show{opacity:1}
.btn-animate{
  font-family:var(--mono);font-size:var(--fs-xs);letter-spacing:.1em;text-transform:uppercase;
}

/* ── Drawer scrim safety net ──
   The scrim is a drawer-only affordance. Scoping it to the drawer breakpoint
   means a stale `.open` class can never cover (and freeze) the desktop layout.
   Above the breakpoint it is inert regardless of state. */
@media(min-width:1025px){
  .sidebar-overlay,
  .sidebar-overlay.open{
    opacity:0!important;visibility:hidden!important;pointer-events:none!important;
  }
}
/* Never let the scrim intercept input while it is transparent. */
.sidebar-overlay{pointer-events:none}
.sidebar-overlay.open{pointer-events:auto}

/* ── QUIZ: the states that exist before and around a paper ──
   The quiz panel is a fixed dark surface in both themes (see the note at the
   top of this file), so these literals follow the ones already used by
   .quiz-hero and .q-text rather than the light-mode tokens. */
.quiz-intro{padding:28px 32px 32px;display:flex;flex-direction:column;align-items:flex-start;gap:14px}
.quiz-intro-head{font-family:var(--serif);font-size:1.05rem;font-weight:900;color:#f5f0e8;margin:0}
.quiz-intro-line{font-family:var(--body);font-size:var(--fs-base);line-height:1.7;color:rgba(245,240,232,0.78);margin:0;max-width:56ch}
.quiz-note{font-family:var(--mono);font-size:var(--fs-xs);line-height:1.65;color:rgba(245,240,232,0.62);margin:0;max-width:60ch}
.q-body .quiz-note,.quiz-wrap>div>.quiz-note{padding:0 32px;margin-top:16px}
.quiz-tools{display:flex;align-items:center;gap:10px;flex-wrap:wrap}

/* The back-to-platform link used inline onmouseover/onmouseout to change
   colour, which CSP forbids and which a keyboard user never triggered anyway.
   Same effect, in the place it belonged from the start.

   Its resting colour moved here too. It was `--ink3` set inline in the
   template — a token calibrated for the cream page, sitting on the dark
   sidebar at 2.10:1. A colour written inline is also a colour nobody finds
   when they go looking for it. */
.module-exit {
  display: inline-flex; align-items: center; gap: 6px; margin-bottom: 10px;
  /* 11px uppercase mono is a 22px-tall target, and WCAG 2.2 asks for 24.
     The padding buys the two pixels without moving the text — the margin
     below gives them back, so the lockup keeps the spacing it was tuned to. */
  padding: 4px 0;
  font-family: var(--mono); font-size: var(--fs-xs); letter-spacing: .1em;
  text-transform: uppercase; color: var(--ink-on-dark); text-decoration: none;
  transition: var(--trans);
}
.module-exit:hover,
.module-exit:focus-visible { color: var(--gold-on-dark); }
