/* math-stream.jsx — "Math for Builders": five short support units (M-01…M-05).
   One data-driven template; each mathN.html renders <MathApp unitN="M-0n" />.
   Units are deliberately gentle: 10 minutes each, zero gatekeeping. */

const { useState: mUseState, useEffect: mUseEffect } = React;

const MATH_TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "theme": "paper",
  "audience": "adult"
}/*EDITMODE-END*/;

/* small example card used throughout */
function MExample({ title, children }) {
  return (
    <div className="card" style={{ background: "transparent", padding: "18px 22px", marginTop: 16 }}>
      <div className="eyebrow" style={{ marginBottom: 8 }}>{title}</div>
      <div style={{ fontSize: 15.5, lineHeight: 1.65 }}>{children}</div>
    </div>
  );
}

/* the famous triangle, drawn */
function MTriangle() {
  return (
    <svg viewBox="0 0 220 150" width="200" style={{ display: "block", margin: "14px 0 4px" }}>
      <path d="M 110 14 L 22 132 L 198 132 Z" fill="var(--bg-card)" stroke="var(--ink)" strokeWidth="2.5" strokeLinejoin="round" />
      <line x1="58" y1="84" x2="162" y2="84" stroke="var(--ink)" strokeWidth="2" />
      <line x1="110" y1="84" x2="110" y2="132" stroke="var(--ink)" strokeWidth="2" />
      <text x="110" y="64" textAnchor="middle" fontFamily="IBM Plex Mono, monospace" fontSize="24" fill="var(--water-deep)" fontWeight="600">V</text>
      <text x="76" y="116" textAnchor="middle" fontFamily="IBM Plex Mono, monospace" fontSize="24" fill="var(--current-deep)" fontWeight="600">I</text>
      <text x="144" y="116" textAnchor="middle" fontFamily="IBM Plex Mono, monospace" fontSize="24" fill="var(--ink)" fontWeight="600">R</text>
    </svg>
  );
}

/* prefix ladder for M-02 */
function MPrefixLadder({ kids }) {
  const rows = [
    ["M", "mega", "×1,000,000", kids ? "a megaphone-sized million" : "10⁶"],
    ["k", "kilo", "×1,000", kids ? "a thousand — like kilometres" : "10³"],
    ["—", "(plain)", "×1", kids ? "just the unit itself" : "10⁰"],
    ["m", "milli", "÷1,000", kids ? "a thousandth" : "10⁻³"],
    ["µ", "micro", "÷1,000,000", kids ? "a millionth" : "10⁻⁶"],
  ];
  return (
    <div className="card" style={{ background: "transparent", padding: "16px 20px", marginTop: 16 }}>
      <div className="eyebrow" style={{ marginBottom: 10 }}>the ladder · each rung is ×1,000</div>
      <div style={{ display: "grid", gap: 6 }}>
        {rows.map(r => (
          <div key={r[0]} style={{ display: "grid", gridTemplateColumns: "44px 70px 110px 1fr", gap: 10, fontFamily: "IBM Plex Mono, monospace", fontSize: 13.5, padding: "7px 10px", background: r[0] === "—" ? "var(--bg-deeper)" : "transparent", borderRadius: 6 }}>
            <b style={{ fontSize: 16 }}>{r[0]}</b><span>{r[1]}</span><span>{r[2]}</span>
            <span style={{ color: "var(--ink-faint)" }}>{r[3]}</span>
          </div>
        ))}
      </div>
    </div>
  );
}

/* simple curve card for M-03 */
function MCurves() {
  const pts = (f) => Array.from({ length: 61 }, (_, i) => {
    const x = i / 60;
    return `${20 + x * 180},${118 - f(x) * 96}`;
  }).join(" ");
  const curves = [
    { name: "straight (V = I·R)", f: (x) => x, c: "var(--water)" },
    { name: "saturating (cap charging)", f: (x) => 1 - Math.exp(-x * 3.2), c: "var(--current)" },
    { name: "decaying (cap draining)", f: (x) => Math.exp(-x * 3.2), c: "var(--ink-soft)" },
  ];
  return (
    <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(160px, 1fr))", gap: 12, marginTop: 16 }}>
      {curves.map(cv => (
        <div key={cv.name} className="card" style={{ background: "transparent", padding: "12px 14px" }}>
          <svg viewBox="0 0 220 140" width="100%" style={{ display: "block" }}>
            <line x1="20" y1="118" x2="206" y2="118" stroke="var(--rule-strong)" strokeWidth="1.4" />
            <line x1="20" y1="118" x2="20" y2="14" stroke="var(--rule-strong)" strokeWidth="1.4" />
            <polyline points={pts(cv.f)} fill="none" stroke={cv.c} strokeWidth="2.6" />
          </svg>
          <div style={{ fontFamily: "IBM Plex Mono, monospace", fontSize: 11.5, color: "var(--ink-soft)", marginTop: 6, textAlign: "center" }}>{cv.name}</div>
        </div>
      ))}
    </div>
  );
}

/* ─── unit content ─────────────────────────────────────────────────────── */
const MATH_UNITS = {
  "M-01": {
    title: <>Moving the <em>Letters</em>.</>,
    sub: "Rearrange any equation",
    lede: {
      adult: <>Every formula in this course is one sentence wearing three disguises. Learn the single move that flips between them, and no equation can ever corner you again.</>,
      kids: <>V = I·R can be flipped around to answer three different questions — and flipping it is one simple move you already know from sharing snacks fairly.</>,
    },
    sections: (kids) => [
      {
        id: "rule", marker: "§ 02 · the one rule", title: <>Do the same thing<br/>to <em>both sides</em>.</>,
        body: <>
          <p className="lede">
            {kids
              ? <>An equation is a balanced see-saw. You can do anything you like to it — as long as you do it to BOTH sides. Divide both sides by the same thing and it stays balanced.</>
              : <>An equation is a balance. Any operation is legal if applied to both sides. To free a letter, undo what's attached to it — division undoes multiplication, subtraction undoes addition — on both sides at once.</>}
          </p>
          <MExample title={kids ? "watch the flip" : "worked: solve V = I·R for I"}>
            {kids
              ? <>Start with <b>V = I·R</b>. You want I alone. I is being multiplied by R — so divide BOTH sides by R: <b>V ÷ R = I</b>. Done! The R on the right cancelled itself out.</>
              : <>V = I·R → divide both sides by R → V/R = I·R/R → <b>I = V/R</b>. The R on the right cancels. Same move solves for R: divide both sides by I → <b>R = V/I</b>. One sentence, three spellings.</>}
          </MExample>
          {!kids && <MExample title="it works on every formula here">
            τ = R·C → C = τ/R. P = V·I → I = P/V. E = P·t → t = E/P. Gain = 1 + R₁/R₂ → R₁ = R₂·(Gain − 1). Always the same single move, sometimes twice.
          </MExample>}
        </>,
      },
      {
        id: "triangle", marker: "§ 03 · the lazy triangle", title: <>Or just use<br/>the <em>triangle</em>.</>,
        body: <>
          <p className="lede">
            {kids
              ? <>Too lazy to flip? Use the magic triangle. Cover the letter you want with a finger — what's left is the answer's recipe!</>
              : <>For the three-letter formulas there's a classic shortcut: write them in a triangle, cover the unknown, and read off the rest. Side-by-side means multiply; stacked means divide.</>}
          </p>
          <MTriangle />
          <MExample title={kids ? "try it" : "reading it"}>
            {kids
              ? <>Cover V → you see I next to R → <b>V = I × R</b>. Cover I → you see V over R → <b>I = V ÷ R</b>. Cover R → V over I → <b>R = V ÷ I</b>. Works for P = V·I and τ = R·C too — same triangle, different letters!</>
              : <>Cover V: I·R. Cover I: V/R. Cover R: V/I. The same triangle serves P = V·I and τ = R·C. (The triangle isn't different math — it's the both-sides rule, pre-chewed.)</>}
          </MExample>
        </>,
      },
    ],
    checkpoint: (kids) => [
      { q: kids ? "To get I alone in V = I·R, you…" : "Solving V = I·R for I requires…",
        options: ["divide both sides by R", "subtract R from both sides", "square both sides", "give up"], correct: 0,
        explain: kids ? "I is multiplied by R, so divide both sides by R — the R cancels and I stands alone."
                      : "Undo the multiplication: V/R = I." },
      { q: "P = V·I, and you know P and V. Then I = …",
        options: ["P / V", "P · V", "V / P", "P − V"], correct: 0,
        explain: kids ? "Cover the I in the triangle: P sits over V. Divide!" : "Divide both sides by V: I = P/V." },
      { q: "τ = R·C. Solve for C:",
        options: ["C = τ / R", "C = τ · R", "C = R / τ", "C = τ − R"], correct: 0,
        explain: kids ? "Same flip as always: divide both sides by R." : "Divide both sides by R. Every 3-letter formula flips identically." },
      { q: kids ? "The one golden rule of equations is…" : "The invariant behind every rearrangement:",
        options: ["whatever you do, do it to both sides", "always divide", "move letters left", "memorize each version"], correct: 0,
        explain: kids ? "Keep the see-saw balanced and you can never go wrong." : "Equality is preserved under identical operations. Everything else is technique." },
    ],
    practice: [
      (rng) => {
        const i = rng.pick([2, 3, 4]), r = rng.pick([3, 5, 6]);
        return {
          q: { adult: `V = I·R with I = ${i} A and R = ${r} Ω. Find V.`, kids: `Flow is ${i}, squeeze is ${r}. The triangle says push = flow × squeeze. Find the push!` },
          unit: "V", answer: i * r,
          hint: { adult: "Cover V: I·R.", kids: "Multiply them!" },
          solution: { adult: `V = ${i}·${r} = ${i * r} V.`, kids: `${i} × ${r} = ${i * r}.` },
        };
      },
      (rng) => {
        const v = rng.pick([12, 18, 24]), r = rng.pick([3, 4, 6]);
        return {
          q: { adult: `Rearrange V = I·R to find I when V = ${v} V, R = ${r} Ω.`, kids: `Push is ${v}, squeeze is ${r}. Flip the triangle to find the flow.` },
          unit: "A", answer: v / r,
          hint: { adult: "I = V/R.", kids: "Cover I: push ÷ squeeze." },
          solution: { adult: `I = ${v}/${r} = ${(v / r).toFixed(1)} A.`, kids: `${v} ÷ ${r} = ${(v / r).toFixed(1)}.` },
        };
      },
      (rng) => {
        const p = rng.pick([24, 36, 60]), v = rng.pick([12, 6]);
        return {
          q: { adult: `P = V·I. A device draws ${p} W from ${v} V. Find I.`, kids: `Work-per-second is ${p}, push is ${v}. How much flow? (Same triangle, new letters!)` },
          unit: "A", answer: p / v,
          hint: { adult: "I = P/V.", kids: "Cover the flow: work ÷ push." },
          solution: { adult: `I = ${p}/${v} = ${(p / v).toFixed(1)} A.`, kids: `${p} ÷ ${v} = ${(p / v).toFixed(1)}.` },
        };
      },
    ],
    quiz: (kids) => [
      { q: kids ? "An equation is like…" : "The mental model for an equation:",
        options: [kids ? "a balanced see-saw" : "a balance — operate on both sides equally", kids ? "a ladder" : "a recipe", kids ? "a race" : "a one-way street", kids ? "a secret" : "a definition only"], correct: 0,
        explain: kids ? "Keep both sides matched and you can reshape it freely." : "Equality survives identical operations — the only rule you need." },
      { q: "R = V/I came from V = I·R by…", kind: "math",
        options: ["dividing both sides by I", "multiplying both sides by I", "swapping letters", "luck"], correct: 0,
        explain: kids ? "Divide both sides by I — the I on the right cancels away." : "One division frees R." },
      { q: "In the triangle, letters side-by-side mean…", kind: "concept",
        options: ["multiply", "divide", "add", "subtract"], correct: 0,
        explain: kids ? "Side-by-side = times. Stacked = divide." : "Horizontal neighbors multiply; vertical stacking divides." },
      { q: "E = P·t. You know E and t. P = …", kind: "math",
        options: ["E / t", "E · t", "t / E", "E + t"], correct: 0,
        explain: kids ? "Cover P: E over t." : "Divide both sides by t." },
      { q: kids ? "Gain = 1 + R₁/R₂ looks scary. First move to find R₁?" : "Solving Gain = 1 + R₁/R₂ for R₁, step one:", kind: "math",
        options: [kids ? "subtract 1 from both sides" : "subtract 1 from both sides", kids ? "panic" : "divide by Gain", kids ? "multiply by 2" : "invert everything", kids ? "skip it" : "take a square root"], correct: 0,
        explain: kids ? "Peel the onion: undo the +1 first, then undo the divide. Two flips, not one." : "Undo operations outside-in: −1, then ×R₂. Multi-step is just the rule, twice." },
      { q: kids ? "Why does the SAME move (÷I) work on both V = I·R and E = P·t?" : "Why does isolating a variable always come down to the same handful of moves?",
        kind: "concept",
        options: [kids ? "Because every recipe here is really just multiply/divide dressed differently" : "Every formula in this course is a chain of multiply/divide (and occasionally add/subtract) — so the same 'undo' moves solve all of them",
                  kids ? "Because letters like to trade places" : "Because Ohm's law is special", kids ? "It's a coincidence" : "It only works for electrical formulas", kids ? "It doesn't — every formula is different" : "It doesn't generalize"],
        correct: 0,
        explain: kids ? "Once you can flip ONE recipe, you can flip them ALL — they're built from the same few moves." : "There's no separate skill per formula — V=IR, E=Pt, Gain=1+R₁/R₂ are all multiply/divide/add chains, so one 'undo' toolkit solves every equation in this course." },
    ],
    next: { href: "math2.html", label: "M·2 — Powers of Ten" },
    prev: { href: "index.html", label: "Course map" },
    summary: {
      adult: <>One rule (both sides), one shortcut (the triangle), and every formula in the course is yours from any direction.</>,
      kids: <>Equations are see-saws: do the same to both sides. Or cover a letter on the triangle and read the recipe!</>,
    },
  },

  "M-02": {
    title: <>Powers of <em>Ten</em>.</>,
    sub: "milli, micro, kilo, mega",
    lede: {
      adult: <>Electronics spans absurd scales — milliamps through megaohms, microfarads through kilovolts. The prefixes are a ladder, and every rung is exactly ×1,000.</>,
      kids: <>Why do parts say things like "milli" and "kilo"? They're size nicknames — and they all step by exactly one thousand!</>,
    },
    sections: (kids) => [
      {
        id: "ladder", marker: "§ 02 · the ladder", title: <>Five rungs,<br/>each <em>×1,000</em>.</>,
        body: <>
          <p className="lede">
            {kids
              ? <>"kilo" means a thousand of something. "milli" means a thousandTH of something. That's it — they're just nicknames for big and small, so we don't drown in zeros.</>
              : <>SI prefixes exist so nobody writes 0.000047 F. Five rungs cover this entire course: mega, kilo, plain, milli, micro — each a factor of exactly 1,000 from its neighbor.</>}
          </p>
          <MPrefixLadder kids={kids} />
          <MExample title={kids ? "say it out loud" : "instant translations"}>
            {kids
              ? <>330 mA is "330 thousandths of an amp" — about a third of an amp. 4.7 kΩ is "4,700 ohms." 100 µF is "100 millionths of a farad." The nickname tells you the size!</>
              : <>330 mA = 0.33 A. 4.7 kΩ = 4,700 Ω. 100 µF = 0.0001 F. 2 MΩ = 2,000,000 Ω. Notice why the farad needs µ: a whole farad is enormous, so practical caps live six rungs down.</>}
          </MExample>
        </>,
      },
      {
        id: "convert", marker: "§ 03 · climbing safely", title: <>Converting without<br/><em>tears</em>.</>,
        body: <>
          <p className="lede">
            {kids
              ? <>Going DOWN the ladder (kilo → plain → milli), numbers get BIGGER: 1 amp is 1,000 milliamps. Going UP, numbers get smaller. If that feels backwards, you're normal — smaller units need more of them!</>
              : <>The classic stumble: converting 0.5 A to mA, which way do the zeros go? Anchor it physically: a smaller unit means MORE of them. 0.5 A = 500 mA. One pizza = 8 slices — smaller pieces, bigger count.</>}
          </p>
          <MExample title={kids ? "the pizza check" : "the sanity anchor"}>
            {kids
              ? <>One pizza = 8 slices. Slices are smaller, so the NUMBER got bigger (1 → 8). Same with amps: 2 A = 2,000 mA. Smaller unit, bigger number. Always double-check with the pizza!</>
              : <>Every conversion, ask: "did my unit get smaller?" If yes, the number must grow ×1,000 per rung. Mixing rungs is the #1 calculator error in practice problems — Ohm's law wants base units (or consistent ones: volts with milliamps gives kilohms, a handy pairing).</>}
          </MExample>
          {!kids && <MExample title="why V/mA = kΩ is a gift">
            12 V / 27 mA: convert (0.027 A → 444 Ω), or use the pairing: volts ÷ milliamps = kilohms → 12/27 = 0.444 kΩ = 444 Ω. Real engineers lean on this constantly.
          </MExample>}
        </>,
      },
    ],
    checkpoint: (kids) => [
      { q: "2 A, in milliamps, is…", options: ["2,000 mA", "0.002 mA", "20 mA", "200 mA"], correct: 0,
        explain: kids ? "Milliamps are smaller, so you need MORE of them: ×1,000." : "Down one rung: ×1,000." },
      { q: "4,700 Ω, said with a prefix:", options: ["4.7 kΩ", "47 kΩ", "4.7 MΩ", "470 mΩ"], correct: 0,
        explain: kids ? "Kilo means a thousand: 4.7 thousand ohms." : "÷1,000, name the rung: kilo." },
      { q: "Which is the BIGGEST current?", options: ["1 A", "500 mA", "900 µA", "999 mA"], correct: 0,
        explain: kids ? "A whole amp beats any number of milli- or micro-amps here." : "1 A = 1,000 mA > 999 mA > 500 mA > 0.9 mA." },
      { q: "100 µF in farads:", options: ["0.0001 F", "0.1 F", "100,000 F", "0.001 F"], correct: 0,
        explain: kids ? "Micro is a millionth — 100 millionths is 0.0001." : "100 × 10⁻⁶ = 10⁻⁴ F. (This is why caps are labeled in µF.)" },
    ],
    practice: [
      (rng) => {
        const ma = rng.pick([150, 330, 750, 1500]);
        return {
          q: { adult: `Convert ${ma} mA to amps.`, kids: `${ma} milliamps — how many whole amps is that?` },
          unit: "A", answer: ma / 1000,
          hint: { adult: "Up one rung: ÷1,000.", kids: "Going to a BIGGER unit means a smaller number: ÷1,000." },
          solution: { adult: `${ma}/1,000 = ${ma / 1000} A.`, kids: `${ma} ÷ 1,000 = ${ma / 1000}.` },
        };
      },
      (rng) => {
        const k = rng.pick([2.2, 4.7, 10, 47]);
        return {
          q: { adult: `A resistor reads ${k} kΩ. How many ohms?`, kids: `The stripe says ${k} kilo-ohms. How many plain ohms?` },
          unit: "Ω", answer: k * 1000,
          hint: { adult: "kilo = ×1,000.", kids: "Kilo just means a thousand of them." },
          solution: { adult: `${k} × 1,000 = ${k * 1000} Ω.`, kids: `${k} × 1,000 = ${k * 1000}.` },
        };
      },
      (rng) => {
        const v = rng.pick([9, 12]), ma = rng.pick([20, 30, 60]);
        return {
          q: { adult: `${v} V pushes ${ma} mA through a resistor. Find R in ohms (convert first!).`, kids: `Push of ${v}, flow of ${ma} thousandths. Squeeze = push ÷ flow — but make the flow plain first!` },
          unit: "Ω", answer: v / (ma / 1000),
          hint: { adult: "R = V/I with I in amps — or use V/mA = kΩ.", kids: `${ma} thousandths = ${ma / 1000}.` },
          solution: { adult: `R = ${v}/0.0${ma} = ${Math.round(v / (ma / 1000))} Ω (= ${(v / ma).toFixed(2)} kΩ directly).`, kids: `${v} ÷ ${ma / 1000} = ${Math.round(v / (ma / 1000))}.` },
        };
      },
    ],
    quiz: (kids) => [
      { q: "Each rung of the prefix ladder is…", kind: "concept", options: ["×1,000", "×10", "×100", "×1,000,000"], correct: 0,
        explain: kids ? "Mega → kilo → plain → milli → micro: a thousand each step." : "Engineering notation steps in 10³." },
      { q: "µ (micro) means…", kind: "concept", options: ["a millionth", "a thousandth", "a million", "a thousand"], correct: 0,
        explain: kids ? "Two rungs down: thousandth of a thousandth = millionth." : "10⁻⁶." },
      { q: "0.05 A in milliamps:", kind: "math", options: ["50 mA", "5 mA", "500 mA", "0.00005 mA"], correct: 0,
        explain: kids ? "Smaller unit, bigger number: 0.05 × 1,000 = 50." : "×10³." },
      { q: "2 MΩ vs 500 kΩ — which resists more?", kind: "math", options: ["2 MΩ — it's 2,000 kΩ", "500 kΩ", "they're equal", "can't compare"], correct: 0,
        explain: kids ? "Mega beats kilo: 2 mega = 2,000 kilo." : "2 MΩ = 2,000 kΩ ≫ 500 kΩ." },
      { q: kids ? "Why do capacitors use µF instead of F?" : "Capacitors are labeled in µF because…", kind: "concept",
        options: ["a whole farad is huge — real parts are tiny fractions of one", "µ looks cool", "farads are obsolete", "they aren't"], correct: 0,
        explain: kids ? "A 1-farad bucket would be giant! Everyday buckets are millionths." : "Practical capacitances run pF–mF; the farad itself is an enormous unit." },
      { q: kids ? "12 V ÷ 27 mA — why is the answer already in kilohms without converting?" : "Why does V ÷ mA conveniently give kΩ directly?",
        kind: "math",
        options: [kids ? "Because milli and kilo are opposite steps, so they cancel neatly" : "Because dividing by a milli-unit is the same as multiplying by 1,000 — which is exactly one kilo-rung",
                  kids ? "It's a lucky coincidence every time" : "It's a coincidence specific to this one problem", kids ? "It only works for voltage" : "It only works because of Ohm's law, not the prefixes",
                  kids ? "It doesn't — you always have to convert" : "It doesn't — you must always convert to base units first"],
        correct: 0,
        explain: kids ? "Milli (÷1000) and kilo (×1000) are opposite ladder rungs — divide by one, and you've climbed the other!" : "V/mA = V/(A×10⁻³) = 1000×(V/A) = 1000×Ω = kΩ. The units do the conversion for free — a favorite shortcut once you trust the ladder." },
    ],
    next: { href: "math3.html", label: "M·3 — Reading Curves" },
    prev: { href: "math1.html", label: "M·1 — Moving the Letters" },
    summary: {
      adult: <>Five rungs, ×1,000 each. Convert by asking "did my unit shrink?" — and never feed mixed rungs into a formula.</>,
      kids: <>Kilo = a thousand, milli = a thousandth, micro = a millionth. Smaller pieces, bigger count — remember the pizza!</>,
    },
  },

  "M-03": {
    title: <>Reading <em>Curves</em>.</>,
    sub: "Graphs without fear",
    lede: {
      adult: <>This course shows you curves constantly — charge ramps, discharge tails, square waves. A graph is just a sentence about change; here's how to read it at a glance.</>,
      kids: <>Squiggly chart lines aren't scary — each one is just a little story about something changing over time. Let's learn to read the three stories this course tells.</>,
    },
    sections: (kids) => [
      {
        id: "axes", marker: "§ 02 · what a graph says", title: <>Left-to-right is time.<br/>Up is <em>more</em>.</>,
        body: <>
          <p className="lede">
            {kids
              ? <>Almost every chart in this course works the same way: walking right means time passing; height means "how much" (push, flow, fullness). To read it, walk along it and narrate: "starts empty… climbs fast… levels off."</>
              : <>Convention: x is time, y is the quantity (V, I, level). Three questions decode any curve: Where does it start? Where does it end up? And is it changing fast (steep) or slowly (flat) along the way?</>}
          </p>
          <MExample title={kids ? "steepness = speed" : "slope is rate"}>
            {kids
              ? <>A steep part means things are changing FAST. A flat part means nothing's changing. The bucket chart from chapter 4 starts steep (filling furiously) and goes flat (nearly full, barely trickling).</>
              : <>Slope is the rate of change — steep means fast. The RC charge curve is steepest at t = 0 (maximum drive) and flattens as the cap approaches the supply: the slope literally is the charging current, scaled.</>}
          </MExample>
        </>,
      },
      {
        id: "shapes", marker: "§ 03 · the three shapes", title: <>Three shapes tell<br/><em>every story here</em>.</>,
        body: <>
          <p className="lede">
            {kids
              ? <>Good news: this course only really uses three line-shapes. The straight climb (steady), the tired climb (fast then leveling), and the slide (fast drop, then a long slow tail).</>
              : <>Three families cover the course: linear (Ohm's law sweeps), saturating exponential (charging — fast start, asymptotic finish), and decaying exponential (discharge — half-life-style tail). Recognize the family and you've read 80% of the graph.</>}
          </p>
          <MCurves />
          <MExample title={kids ? "the famous landmark" : "the τ landmark"}>
            {kids
              ? <>The tired-climb has a famous landmark: after one "characteristic time," it's about 63% of the way there. After five of them — basically done. You met this in chapter 4!</>
              : <>Exponentials are read by τ: 63% there at 1τ, ~86% at 2τ, ~99% at 5τ. You never compute e⁻ᵗ/ᵀ by hand — you read multiples of τ off the axis. That's the entire practical skill.</>}
          </MExample>
        </>,
      },
    ],
    checkpoint: (kids) => [
      { q: "A flat (horizontal) stretch of a curve means…", options: ["nothing is changing", "things change fastest", "time stopped", "the value is zero"], correct: 0,
        explain: kids ? "No climb, no change — the value is just holding still." : "Zero slope = zero rate of change. (Flat ≠ zero value — it can hold still at any height.)" },
      { q: "The bucket-charging curve is steepest…", options: ["at the very start", "at the end", "in the middle", "never"], correct: 0,
        explain: kids ? "An empty bucket fills furiously — the drive is biggest at the start." : "Max voltage difference at t=0 → max current → max slope." },
      { q: kids ? "After one 'characteristic time,' the tired-climb is about…" : "At t = 1τ, an RC charge has covered about…",
        options: ["63% of the way", "10%", "100%", "50%"], correct: 0,
        explain: kids ? "Around two-thirds done after one landmark time. Five landmarks ≈ finished." : "1 − e⁻¹ ≈ 0.63. At 5τ, ~99%." },
      { q: "A square wave on a scope means…", options: ["something snapping between two levels", "smooth sloshing", "a broken probe", "DC"], correct: 0,
        explain: kids ? "Flat–jump–flat–jump: on, off, on, off — like the blinker's light!" : "Two flat levels with fast transitions — digital signals and 555 outputs." },
    ],
    practice: [
      (rng) => {
        const tau = rng.pick([2, 3, 5]);
        return {
          q: { adult: `An RC circuit has τ = ${tau} s. Roughly how long until the cap is ~99% charged?`, kids: `The bucket's landmark time is ${tau} seconds. About how long until it's basically full (99%)?` },
          unit: "s", answer: 5 * tau,
          hint: { adult: "The 5τ rule.", kids: "Five landmark times ≈ done." },
          solution: { adult: `5τ = ${5 * tau} s.`, kids: `5 × ${tau} = ${5 * tau} seconds.` },
        };
      },
      (rng) => {
        const v = rng.pick([10, 12]), tau = rng.pick([2, 4]);
        return {
          q: { adult: `Charging toward ${v} V with τ = ${tau} s: roughly what voltage at t = ${tau} s? (63% rule)`, kids: `The bucket aims for ${v} and its landmark time is ${tau} s. About how full (in push) after ${tau} s?` },
          unit: "V", answer: v * 0.63, tol: 0.1,
          hint: { adult: "63% of the target at 1τ.", kids: "About two-thirds of the way there." },
          solution: { adult: `0.63 × ${v} ≈ ${(v * 0.63).toFixed(1)} V.`, kids: `Around ${(v * 0.63).toFixed(1)} — two-thirds-ish of ${v}.` },
        };
      },
    ],
    quiz: (kids) => [
      { q: "On this course's graphs, the horizontal axis is almost always…", kind: "concept", options: ["time", "voltage", "resistance", "temperature"], correct: 0,
        explain: kids ? "Walking right = time passing." : "Time-domain plots throughout." },
      { q: "Steeper means…", kind: "concept", options: ["changing faster", "bigger value", "more voltage", "more time"], correct: 0,
        explain: kids ? "Steep = the story is happening quickly right now." : "Slope = rate, independent of the value itself." },
      { q: "The discharge curve's long shallow tail means…", kind: "concept", options: ["the last bit drains very slowly", "it never started", "the cap broke", "time slowed"], correct: 0,
        explain: kids ? "Less depth = less push = lazier draining. The last drops take forever!" : "Drive shrinks with the remaining voltage — exponential decay's signature." },
      { q: "Which shape is Ohm's law (V vs I, fixed R)?", kind: "concept", options: ["a straight line through zero", "a tired climb", "a slide", "a circle"], correct: 0,
        explain: kids ? "Double the push, double the flow — that makes a perfectly straight line." : "Linear, slope = R. Curvature would mean R changing." },
      { q: kids ? "You never have to…" : "Reading exponentials in practice means…", kind: "concept",
        options: [kids ? "compute the curvy math by hand — just read the landmarks" : "counting multiples of τ — never evaluating e⁻ᵗ/ᵀ by hand",
                  kids ? "look at graphs again" : "memorizing every point", kids ? "use landmarks" : "calculus", kids ? "tell stories" : "guessing"], correct: 0,
        explain: kids ? "63% at one landmark, done by five. That's all the curve-math you'll ever need here." : "1τ→63%, 2τ→86%, 3τ→95%, 5τ→99%. The lookup beats the formula." },
      { q: kids ? "A steep line and a gentle line can both be headed to the same final height. What's different?" : "Two exponential curves reach the same final value but at different τ. What actually differs?",
        kind: "concept",
        options: [kids ? "How FAST they get there — not where they end up" : "The RATE of approach — τ sets speed, not the destination", kids ? "Where they end up" : "The final value itself", kids ? "Nothing, they're identical" : "Nothing — τ only affects the starting point", kids ? "The color of the line" : "The units being measured"],
        correct: 0,
        explain: kids ? "Same destination, different speed getting there — that's exactly what a bigger or smaller bucket (τ) changes." : "τ is purely a clock — it scales time, not the asymptote. Two RC circuits with different τ can still settle at the exact same final voltage." },
    ],
    next: { href: "math4.html", label: "M·4 — Good Guessing" },
    prev: { href: "math2.html", label: "M·2 — Powers of Ten" },
    summary: {
      adult: <>x is time, slope is rate, and three curve families (linear, saturating, decaying) cover the whole course. Read exponentials by counting τ.</>,
      kids: <>Right = time, up = more, steep = fast. Three shapes tell every story — and the tired-climb is 63% done after one landmark time.</>,
    },
  },

  "M-04": {
    title: <>Good <em>Guessing</em>.</>,
    sub: "Estimation & sanity checks",
    lede: {
      adult: <>Engineers estimate before they compute — a rough answer first makes wrong answers obvious. This unit teaches the two habits: round brutally, then sanity-check the result.</>,
      kids: <>Pros guess FIRST and calculate second! A quick rough guess tells you when the calculator answer is nonsense (it happens a lot).</>,
    },
    sections: (kids) => [
      {
        id: "round", marker: "§ 02 · round brutally", title: <>Ugly numbers are<br/><em>optional</em>.</>,
        body: <>
          <p className="lede">
            {kids
              ? <>Before any real math, do it with friendly numbers. 9.2 V through 330 Ω? Call it "9 through 300" — that's 0.03, or 30 thousandths. The real answer will be close to that.</>
              : <>Round everything to one comfortable digit, compute in your head, THEN reach for the calculator. 9.2 V / 330 Ω → "9/300" → 30 mA. The exact answer (27.9 mA) must land near it — if the calculator says 2.79 A, you slipped a rung on the prefix ladder.</>}
          </p>
          <MExample title={kids ? "guess like a pro" : "the two-step"}>
            {kids
              ? <>Step 1: friendly-number guess (30-ish). Step 2: real math (27.9). They're neighbors, so the math is trustworthy. If the real answer came out 100× different — something's fishy, check the units!</>
              : <>Estimate → compute → compare. Agreement to within ~2× means trust it; a 10×/1000× gap means a prefix or rearrangement slip. The estimate costs ten seconds and catches the two most common error families cold.</>}
          </MExample>
        </>,
      },
      {
        id: "sanity", marker: "§ 03 · smell tests", title: <>Does the answer<br/><em>smell right</em>?</>,
        body: <>
          <p className="lede">
            {kids
              ? <>Some answers are just silly, and you can learn to smell them: a watch battery can't pour out 100 amps. An LED can't want 50 volts. A bedroom light doesn't use as much power as an oven.</>
              : <>Build a shelf of reference magnitudes and compare every answer to it: LEDs sip ~20 mA at ~2–3 V. USB is 5 V. Car batteries are 12 V. A phone holds ~3,000 mAh. Mains heaters draw ~10 A. A result far outside its family deserves a second look before you trust it.</>}
          </p>
          <MExample title={kids ? "the smell-test shelf" : "magnitudes worth memorizing"}>
            {kids
              ? <>Little lights: a few thousandths of an amp. Batteries: 1.5 to 12 in push. Phone screens: about a watt. Toasters: about a thousand watts. Keep this little shelf in your head and silly answers jump right out!</>
              : <>~20 mA (LED) · 5 V (USB) · 12 V (car) · 0.5–2 W (phone) · 60 W (old bulb) · 1 kW (toaster) · 3,000 mAh (phone battery). Seven numbers; they'll flag 90% of your future mistakes.</>}
          </MExample>
        </>,
      },
    ],
    checkpoint: (kids) => [
      { q: "Estimate 11.8 V / 270 Ω the pro way:", options: ["≈ 12/300 = 40 mA", "≈ 12 × 300", "≈ 118/27", "no need to estimate"], correct: 0,
        explain: kids ? "Friendly numbers: 12 through 300 gives 40 thousandths. The real answer (43.7) is right next door." : "12/300 = 0.04 A. Exact: 43.7 mA — same neighborhood, math confirmed." },
      { q: "Your calculator says an LED draws 2.5 A. Your reaction:", options: ["suspicious — LEDs sip ~20 mA, check the prefix rungs", "sounds right", "LEDs vary, accept it", "buy a bigger LED"], correct: 0,
        explain: kids ? "That's a hundred times too thirsty for a little light — sniff sniff — probably a milli mistake!" : "100× off the family value almost always means a slipped 10³." },
      { q: "Estimate-then-compute mainly catches…", options: ["unit-prefix slips and flipped rearrangements", "soldering errors", "typos in chat", "nothing"], correct: 0,
        explain: kids ? "The guess can't slip a rung — so when the 'real' answer is wildly off the guess, the rung slipped in the calculator." : "Both error families produce 10ⁿ× or inverted results — exactly what a rough estimate exposes." },
      { q: kids ? "A toaster uses about…" : "Order of magnitude, a toaster draws…",
        options: ["a thousand watts", "one watt", "a million watts", "a thousandth of a watt"], correct: 0,
        explain: kids ? "Big heat = about a thousand watts. Remember the shelf!" : "~1 kW — heating elements dominate household draw." },
    ],
    practice: [
      (rng) => {
        const v = rng.pick([9, 12]), r = rng.pick([270, 330, 470]);
        return {
          q: { adult: `WITHOUT a calculator: estimate ${v} V across ${r} Ω, in mA. (Generous tolerance — it's an estimate!)`, kids: `Rough-guess time! Push of ${v} through a squeeze of ${r}. About how many thousandths of flow?` },
          unit: "mA", answer: (v / r) * 1000, tol: 0.35,
          hint: { adult: "Round: 9→9 or 12→12, R→250/300/500, divide.", kids: `Call it ${v} through ${r < 400 ? 300 : 500} — friendly numbers!` },
          solution: { adult: `≈ ${Math.round((v / r) * 1000)} mA (exact ${((v / r) * 1000).toFixed(1)}).`, kids: `About ${Math.round((v / r) * 1000)} — close enough to spot trouble!` },
        };
      },
      (rng) => {
        const w = rng.pick([1200, 900, 1500]);
        return {
          q: { adult: `A ${w} W heater on 120 V mains: estimate the current.`, kids: `A big heater does ${w} watts of work each second from a push of 120. Estimate the flow!` },
          unit: "A", answer: w / 120, tol: 0.2,
          hint: { adult: "I = P/V; round to friendly numbers.", kids: "Flow = work ÷ push. Round it friendly!" },
          solution: { adult: `${w}/120 = ${(w / 120).toFixed(1)} A — heaters are why breakers are 15 A.`, kids: `${w} ÷ 120 = ${(w / 120).toFixed(1)}.` },
        };
      },
    ],
    quiz: (kids) => [
      { q: "The professional order of operations is…", kind: "concept", options: ["estimate, then compute, then compare", "compute twice", "compute, then round", "trust the calculator"], correct: 0,
        explain: kids ? "Guess first! Then the calculator can't sneak nonsense past you." : "The estimate is the error detector for the computation." },
      { q: "A result 1,000× away from your estimate usually means…", kind: "concept", options: ["a prefix-rung slip (milli/kilo)", "the formula is wrong forever", "physics changed", "round again"], correct: 0,
        explain: kids ? "Three zeros = one ladder rung. Check the millis and kilos!" : "10³ gaps are the prefix ladder's signature." },
      { q: "An LED's happy current is about…", kind: "concept", options: ["20 mA", "2 A", "20 A", "2 µA"], correct: 0,
        explain: kids ? "Little lights sip about 20 thousandths." : "10–30 mA for indicator LEDs — shelf number one." },
      { q: "A phone battery holds roughly…", kind: "concept", options: ["3,000 mAh", "3 mAh", "300,000 mAh", "30 mAh"], correct: 0,
        explain: kids ? "A few thousand of the little units — that's a day of phone." : "~3 Ah; useful for runtime estimates (ch. 3's barrel math)." },
      { q: kids ? "Smell tests work because…" : "Reference magnitudes are powerful because…", kind: "concept",
        options: ["real devices cluster around familiar sizes", "all answers are equal", "guessing is cheating", "calculators lie"], correct: 0,
        explain: kids ? "Things in the world come in typical sizes — silly answers stick out like a giraffe in a parking lot." : "Engineering quantities are tightly clustered by device family; outliers are nearly always errors." },
      { q: kids ? "You calculate an LED needs 20,000 mA. What probably went wrong?" : "A calculation says an indicator LED needs 20 A. What's the likely error?",
        kind: "math",
        options: [kids ? "A prefix rung got missed — probably meant 20 mA" : "A units/prefix slip — 20 A is 1,000× a normal LED current (20 mA); almost certainly a missed milli", kids ? "LEDs really do need that much" : "LEDs really can draw that much", kids ? "The battery is broken" : "The formula is wrong", kids ? "Nothing — that's normal" : "Nothing unusual"],
        correct: 0,
        explain: kids ? "20,000 mA would fry any LED instantly — that huge a number almost always means a missing milli!" : "A 1,000× gap from a known reference magnitude (LEDs run ~20 mA) is the prefix ladder's fingerprint — check for a dropped or extra milli/kilo before doubting the physics." },
    ],
    quizNote: null,
    next: { href: "math5.html", label: "M·5 — The Shorthand" },
    prev: { href: "math3.html", label: "M·3 — Reading Curves" },
    summary: {
      adult: <>Round brutally, compute, compare — and keep a shelf of reference magnitudes. Most wrong answers announce themselves.</>,
      kids: <>Guess first with friendly numbers, then check that the real answer is a neighbor. And learn the smell-test shelf — silly answers stink!</>,
    },
  },

  "M-05": {
    title: <>The <em>Shorthand</em>.</>,
    sub: "Symbols, units & tolerances",
    lede: {
      adult: <>Engineering writing is dense with tiny marks that all mean something: ~, ≈, ·, subscripts, Greek letters, ±. Ten minutes here and nothing in a datasheet footnote will ever ambush you.</>,
      kids: <>Engineers write in a secret shorthand — squiggles, dots, and tiny letters. Here's the decoder ring!</>,
    },
    sections: (kids) => [
      {
        id: "marks", marker: "§ 02 · the decoder ring", title: <>Six marks,<br/><em>fully decoded</em>.</>,
        body: <>
          <p className="lede">
            {kids
              ? <>None of these squiggles are math you have to DO — they're just abbreviations, like emoji for engineers.</>
              : <>None of these denote operations you must perform — they're compression. Read them out loud once and they're yours.</>}
          </p>
          <MExample title="the marks">
            <div style={{ display: "grid", gap: 8, fontFamily: "IBM Plex Mono, monospace", fontSize: 13.5 }}>
              <div><b>~ and ≈</b> — "roughly." ~0.7 V reads "around 0.7 volts." {kids ? "Engineers guess proudly!" : "Estimation is a feature, not sloppiness."}</div>
              <div><b>·</b> — "times." V = I·R is just V = I × R. {kids ? "" : "(Avoids confusing × with the letter x.)"}</div>
              <div><b>V_in, I_C</b> — tiny labels, not math. "The voltage going IN." "The current at the Collector." {kids ? "Like name tags!" : "Subscripts name which one — never an operation."}</div>
              <div><b>τ, β, Δ, Ω</b> — Greek nicknames. τ = the RC landmark time, β = a transistor's multiplier, Δ = "the change in," Ω = ohms. {kids ? "Fancy letters, friendly meanings." : "Convention, not calculus."}</div>
              <div><b>±</b> — "give or take." 330 Ω ±5% means the real part is anywhere from 313 to 347. {kids ? "Parts are a little different from their label — that's normal!" : ""}</div>
              <div><b>k = 10³ on schematics</b> — "4k7" means 4.7 kΩ (the k marks the decimal point — it can't rub off like a period can).</div>
            </div>
          </MExample>
        </>,
      },
      {
        id: "tolerance", marker: "§ 03 · the honest label", title: <>Every part is a<br/><em>little bit wrong</em>.</>,
        body: <>
          <p className="lede">
            {kids
              ? <>Here's a secret that makes electronics LESS scary: no part is exactly its label. A "330" resistor might really be 320 or 341 — and everything still works! Circuits are designed with wiggle room.</>
              : <>Tolerance is why the course keeps saying "about": a ±5% resistor wanders ±5%, a cap ±20%, a transistor's β by 2–3×. Good designs (voltage dividers' ratios, feedback loops, 5τ margins) are built so this wander doesn't matter. Precision is bought only where it's needed.</>}
          </p>
          <MExample title={kids ? "why your build will work" : "design for wander"}>
            {kids
              ? <>When you build the Beacon, your blink won't be EXACTLY the math answer — maybe 1.1 seconds instead of 1.0. That's not a mistake. That's parts being parts. If it blinks, you built it right!</>
              : <>This reframes every practice answer: 27.9 mA "exact" is really 27.9 ±, and the grader's tolerance mirrors reality. It's also why ratio-based circuits (dividers, op-amp gains) beat absolute ones — ratios of same-batch parts track far better than their absolute values.</>}
          </MExample>
        </>,
      },
    ],
    checkpoint: (kids) => [
      { q: "~0.7 V means…", options: ["around 0.7 volts", "exactly 0.7", "0.7 is wrong", "negative 0.7"], correct: 0,
        explain: kids ? "The squiggle means roughly. Engineers estimate on purpose!" : "Tilde = approximately. Diode drops genuinely vary by part and current." },
      { q: "In I_C, the little C is…", options: ["a name tag — 'the collector current'", "times C", "to the power C", "coulombs"], correct: 0,
        explain: kids ? "Tiny letters just say WHICH one. No math hiding there." : "Subscripts identify; they never operate." },
      { q: "330 Ω ±5% could really be…", options: ["anywhere from ~313 to ~347 Ω", "exactly 330", "335 max", "5 Ω"], correct: 0,
        explain: kids ? "Give or take 5 out of every 100 — about 16-ish either way." : "330 × 0.05 ≈ 16.5; the band is 313.5–346.5 Ω." },
      { q: "On a schematic, '4k7' means…", options: ["4.7 kΩ", "47 kΩ", "4,700 kΩ", "a typo"], correct: 0,
        explain: kids ? "The k sits where the decimal point goes — 4.7 thousand." : "RKM code: the multiplier marks the radix point (decimal points vanish in photocopies)." },
    ],
    practice: [
      (rng) => {
        const r = rng.pick([220, 330, 470, 1000]), pct = rng.pick([5, 10]);
        return {
          q: { adult: `A ${r} Ω ±${pct}% resistor: what's its MAXIMUM possible real value?`, kids: `A ${r} squeeze with ±${pct}% wiggle room — how big could it really be, at most?` },
          unit: "Ω", answer: r * (1 + pct / 100),
          hint: { adult: "Add pct% of the label.", kids: `${pct} out of every 100, added on.` },
          solution: { adult: `${r} × 1.0${pct} = ${(r * (1 + pct / 100)).toFixed(0)} Ω.`, kids: `${r} + ${(r * pct / 100).toFixed(0)} = ${(r * (1 + pct / 100)).toFixed(0)}.` },
        };
      },
      (rng) => {
        const a = rng.pick([["2k2", 2200], ["3k3", 3300], ["1k5", 1500], ["6k8", 6800]]);
        return {
          q: { adult: `Decode the schematic marking "${a[0]}" into ohms.`, kids: `A drawing says "${a[0]}". The k marks the decimal spot — how many plain ohms?` },
          unit: "Ω", answer: a[1],
          hint: { adult: "k marks the decimal point AND means ×1,000.", kids: `${a[0][0]}.${a[0][2]} thousand.` },
          solution: { adult: `${a[0]} = ${a[0][0]}.${a[0][2]} kΩ = ${a[1]} Ω.`, kids: `${a[0][0]}.${a[0][2]} thousand = ${a[1]}.` },
        };
      },
    ],
    quiz: (kids) => [
      { q: "≈ and ~ both signal…", kind: "concept", options: ["an estimate — roughly this value", "an error", "multiplication", "a warning"], correct: 0,
        explain: kids ? "Roughly! Engineers say 'about' constantly, in symbol form." : "Approximation is the native mode of engineering arithmetic." },
      { q: "Δt usually reads…", kind: "concept", options: ["'the change in time'", "delta times t", "triangle t", "4t"], correct: 0,
        explain: kids ? "Δ is the 'how much did it change?' mark." : "Delta = difference; ΔV/Δt = rate of voltage change." },
      { q: "Subscripts (V_in, R_load) exist to…", kind: "concept", options: ["name which quantity you mean", "raise to a power", "multiply", "look impressive"], correct: 0,
        explain: kids ? "Name tags. Nothing more!" : "Disambiguation — circuits are full of different voltages at once." },
      { q: "A ±20% capacitor in a timing circuit means your blink rate…", kind: "concept", options: ["wanders ~20% too — and good designs absorb that", "fails", "is exact anyway", "doubles"], correct: 0,
        explain: kids ? "The bucket's a bit off-label, so the rhythm is a bit off-math. Normal and fine!" : "τ = R·C inherits C's tolerance. Hence margins, trimmers, and the 5τ habit." },
      { q: kids ? "If your build behaves a little off from the math…" : "Measured ≠ calculated, by a few percent, usually means…", kind: "concept",
        options: [kids ? "that's parts being parts — normal!" : "tolerance doing what tolerance does", kids ? "you failed" : "a build error", kids ? "the math is broken" : "bad multimeter", kids ? "start over" : "quantum effects"], correct: 0,
        explain: kids ? "Real parts wiggle around their labels. Working-but-slightly-off is the natural state of electronics." : "±5% parts compose into ±10–15% behaviors. Reserve alarm for 2× and bigger." },
      { q: kids ? "R = 4.7 kΩ ± 5%. What's the WORST-case resistance?" : "R = 4.7 kΩ ± 5%. What's the range?",
        kind: "math",
        options: ["4.465 kΩ – 4.935 kΩ", "4.7 kΩ exactly, always", "0 kΩ – 9.4 kΩ", "4.7 kΩ ± 5 kΩ"],
        correct: 0,
        explain: kids ? "5% of 4.7 is about 0.235 — so it could be anywhere from about 4.47 to 4.94." : "±5% of 4.7 kΩ = ±0.235 kΩ, so the real part lands somewhere in 4.465–4.935 kΩ — never assume the printed value is exact." },
    ],
    next: { href: "index.html", label: "Back to the course map" },
    prev: { href: "math4.html", label: "M·4 — Good Guessing" },
    summary: {
      adult: <>~ is "roughly," · is "times," subscripts are name tags, Greek letters are nicknames, ± is honesty about parts. Decode complete.</>,
      kids: <>The squiggle means roughly, the dot means times, tiny letters are name tags — and every part is a little bit wrong on purpose!</>,
    },
  },
};

/* ─── the shared template ──────────────────────────────────────────────── */
function MathApp({ unitN }) {
  const [t, setTweak] = useTweaks(MATH_TWEAK_DEFAULTS);
  useCrossChapterPersistence(t, setTweak);
  mUseEffect(() => { document.body.setAttribute("data-theme", t.theme); }, [t.theme]);
  const kids = t.audience === "kids";
  const U = MATH_UNITS[unitN];
  const meta = M_CHAPTERS.find(c => c.n === unitN);
  const secs = U.sections(kids);

  const navItems = [
    { id: "cover", label: "Cover" },
    ...secs.map(s => ({ id: s.id, label: s.marker.split("·")[1].trim().split(" ").slice(0, 2).join(" ") })),
    ...(U.practice ? [{ id: "practice", label: "Practice" }] : []),
    { id: "quiz", label: "Quiz" },
  ];

  return (
    <>
      <ProgressBar />
      <TopBar currentN={unitN} audience={t.audience} setAudience={(a) => setTweak("audience", a)} />
      <ChapterNav items={navItems} />

      <main>
        <CoverPage chapterN={unitN}
                   chapterTitle={U.title}
                   chapterSub={U.sub}
                   kids={kids}
                   lede={kids ? U.lede.kids : U.lede.adult}>
          <ChapterStartMarker chapterN={unitN} />
          <div className="marg">
            Math for Builders · optional support stream · ≈ {meta ? meta.min : 10} min. Dip in whenever a chapter's math feels slippery.
          </div>
        </CoverPage>

        {secs.map(s => (
          <section className="section" id={s.id} key={s.id} data-screen-label={s.marker}>
            <div className="marker">{s.marker}</div>
            <div className="section-inner" style={{ maxWidth: 860 }}>
              <h2 className="serif">{s.title}</h2>
              {s.body}
            </div>
          </section>
        ))}

        <CheckpointQuiz kids={kids} label="Checkpoint" pick={2}
          title={kids ? "Quick check!" : "Did it stick?"}
          questions={U.checkpoint(kids)} />

        {U.practice && (
          <PracticeProblems chapterN={unitN} kids={kids} problems={U.practice} />
        )}

        <ChapterQuiz chapterN={unitN} pick={4}
          title={kids ? "Quick quiz!" : "Check your understanding."}
          questions={U.quiz(kids)} />

        <WhatsNext currentN={unitN} kids={kids}
          summary={kids ? U.summary.kids : U.summary.adult}
          prevHref={U.prev.href} prevLabel={U.prev.label}
          nextHref={U.next.href} nextLabel={U.next.label} />
      </main>

      <TweaksPanel title="Tweaks">
        <CommonTweaks t={t} setTweak={setTweak} />
      </TweaksPanel>
      <GlossaryFab />
    </>
  );
}

Object.assign(window, { MathApp });
