/* chapter9.jsx — Chapter 9: The Flywheel (Inductors). */

const { useState, useEffect, useRef } = React;

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

function BigIdeaBeat({ onView, kids }) {
  const ref = useInViewCallback(onView);
  return (
    <div className="beat" id="begin" data-screen-label="01 Momentum" ref={ref}>
      <div className="beat-marker">§ 01 · a heavy wheel</div>
      {kids ? (
        <>
          <h2 className="serif">A wheel that<br/>doesn't like <em>change</em>.</h2>
          <p className="lede">
            Imagine a big, heavy paddlewheel in the pipe. When water starts to
            flow, the wheel is slow to get going. But once it's spinning fast,
            it wants to <em>keep</em> spinning — even if you shut the water off.
          </p>
          <p>An <em>inductor</em> is that heavy wheel, for electricity.</p>
        </>
      ) : (
        <>
          <h2 className="serif">The component<br/>with <em>momentum</em>.</h2>
          <p className="lede">
            A capacitor resists changes in <em>voltage</em>. An inductor is its
            mirror image: it resists changes in <em>current</em>. Picture a
            heavy paddlewheel — slow to spin up, but once moving it carries the
            flow along by sheer momentum.
          </p>
          <p>
            Physically it's just a coil of wire. Current through it stores energy
            in a magnetic field; that field fights any attempt to change the
            current quickly.
          </p>
          <div className="marg" style={{ marginTop: 12 }}>
            R, C, and now L — the three passive components. You've met them all.
          </div>
        </>
      )}
      <div className="pull">Slow to start, slow to stop. It hates sudden change.</div>
    </div>
  );
}

function SpinUpBeat({ driveOn, setDriveOn, cur, onView, kids }) {
  const ref = useInViewCallback(onView);
  return (
    <div className="beat" id="spinup" data-screen-label="02 Spin up" ref={ref}>
      <div className="beat-marker">§ 02 · spin it up, let it coast</div>
      <div className="chip current" style={{ marginBottom: 16 }}>try it</div>
      <h2 className="serif">Turn it on.<br/>Then turn it <em>off</em>.</h2>
      <p className="lede">
        {kids
          ? <>Switch the water on and watch the wheel slowly speed up. Switch it off and watch it coast — it doesn't stop right away!</>
          : <>Toggle the source. Current ramps up gradually (not instantly), and when you cut the source it decays rather than snapping to zero. The chart shows the lag.</>}
      </p>
      <div style={{ display: "flex", gap: 10, marginTop: 22, flexWrap: "wrap" }}>
        <button onClick={() => setDriveOn(true)} style={spinBtn(driveOn, "var(--water)")}>▶ Source ON</button>
        <button onClick={() => setDriveOn(false)} style={spinBtn(!driveOn, "var(--current)")}>■ Source OFF</button>
      </div>
      <div className="card" style={{ background: "transparent", marginTop: 22, padding: "16px 20px" }}>
        <div className="eyebrow" style={{ marginBottom: 8 }}>wheel speed</div>
        <p style={{ margin: 0, fontSize: 17 }}>
          <span className="mono" style={{ color: "var(--current)" }}>{Math.round(cur * 100)}%</span>
          {" "}of full speed —{" "}
          {driveOn
            ? (cur > 0.9 ? "spun up." : "still speeding up…")
            : (cur < 0.1 ? "coasted to a stop." : "coasting down…")}
        </p>
      </div>
    </div>
  );
}

function LBeat({ L, setL, onView, kids }) {
  const ref = useInViewCallback(onView);
  return (
    <div className="beat" id="inductance" data-screen-label="03 Inductance" ref={ref}>
      <div className="beat-marker">§ 03 · how heavy the wheel</div>
      <h2 className="serif">{kids ? "Light wheel, heavy wheel" : "Inductance (L)"}.</h2>
      {kids ? (
        <p className="lede">
          A light wheel speeds up fast. A heavy wheel takes longer but coasts
          longer too. Drag the slider to change how heavy the wheel is.
        </p>
      ) : (
        <>
          <p className="lede">
            <em>Inductance</em>, measured in <span className="mono">henries (H)</span>,
            is how strongly the coil resists current change — the "heaviness" of
            the wheel. More inductance, slower ramp, more stored momentum.
          </p>
          <p>
            More turns of wire (or an iron core) means more inductance. Named for
            Joseph Henry, who discovered it the same time as Faraday.
          </p>
        </>
      )}
      <div className="rule">try it</div>
      <Slider name={kids ? "Wheel weight" : "Inductance · L"} value={L} min={0.5} max={5} step={0.1}
              unit={kids ? "" : "H"} accent="current" onChange={setL} />
      <div className="marg" style={{ marginTop: 12 }}>
        {kids ? <>Heavier = slower to start and slower to stop.</>
              : <>Watch the chart: bigger L stretches both the spin-up and the coast-down.</>}
      </div>
    </div>
  );
}

function PredictBeat({ onView, kids }) {
  const ref = useInViewCallback(onView);
  return (
    <div className="beat" id="predict" data-screen-label="04 Predict" ref={ref}>
      <div className="beat-marker">§ 04 · check your gut</div>
      <h2 className="serif">A puzzle<br/>(or two).</h2>
      <PredictReveal
        question={kids
          ? "An inductor (heavy wheel) is the opposite of which component?"
          : "An inductor resists changes in current. Which component is its mirror (resisting changes in voltage)?"}
        options={["A resistor", "A capacitor", "A battery", "A switch"]}
        correct={1}
        explanation={kids
          ? "The capacitor! A capacitor stores a 'push' (voltage); the inductor stores 'motion' (current). Opposites."
          : "The capacitor. C stores energy in an electric field and resists voltage change; L stores energy in a magnetic field and resists current change. Perfect duals."}
        accent="water" />
      <PredictReveal
        question={kids
          ? "You suddenly cut the power to a spinning inductor. The current…"
          : "You abruptly open a switch feeding an inductor carrying current. The current tries to…"}
        options={[
          "instantly becomes zero",
          "keeps flowing for a moment (a voltage spike)",
          "doubles",
          "reverses forever"]}
        correct={1}
        explanation={kids
          ? "Like a spinning wheel, it wants to keep going! That sudden 'keep going' can make a big voltage spark — which is how spark plugs work."
          : "Current can't change instantly, so the inductor forces it to keep flowing momentarily, producing a large voltage spike (V = L·di/dt). This is exactly how ignition coils and boost converters work — and why you add a flyback diode."}
        accent="current" />
    </div>
  );
}

function PlaygroundBeat({ driveOn, setDriveOn, L, setL, cur, onView, kids }) {
  const ref = useInViewCallback(onView);
  return (
    <div className="beat" id="playground" data-screen-label="05 Playground" ref={ref}>
      <div className="beat-marker">§ 05 · all knobs unlocked</div>
      <h2 className="serif">Drive the<br/><em>flywheel</em>.</h2>
      <p className="lede">
        {kids ? <>Flip the power and change the wheel weight. Watch the chart lag behind.</>
              : <>Toggle the drive and vary L. The current curve always lags — that lag is the whole point of an inductor.</>}
      </p>
      <div style={{ display: "flex", gap: 10, marginTop: 20, flexWrap: "wrap" }}>
        <button onClick={() => setDriveOn(!driveOn)} style={spinBtn(true, driveOn ? "var(--water)" : "var(--current)")}>
          {driveOn ? "▶ ON" : "■ OFF"} · tap to flip
        </button>
      </div>
      <div style={{ marginTop: 18 }}>
        <Slider name={kids ? "Wheel weight" : "Inductance · L"} value={L} min={0.5} max={5} step={0.1}
                unit={kids ? "" : "H"} accent="current" onChange={setL} />
      </div>
      <div className="card" style={{ background: "transparent", marginTop: 18, padding: "16px 20px" }}>
        <div className="eyebrow" style={{ marginBottom: 8 }}>now</div>
        <p style={{ margin: 0, fontSize: 17 }}>
          Wheel at <span className="mono" style={{ color: "var(--current)" }}>{Math.round(cur * 100)}%</span>,
          {" "}{driveOn ? "climbing toward full" : "coasting toward rest"}.
        </p>
      </div>
    </div>
  );
}

function spinBtn(active, color) {
  return {
    appearance: "none",
    border: `2px solid ${active ? color : "var(--rule-strong)"}`,
    background: active ? color : "transparent",
    color: active ? "var(--bg-card)" : "var(--ink)",
    padding: "11px 22px", borderRadius: 8, cursor: "pointer",
    fontFamily: "'IBM Plex Mono', monospace", fontSize: 13,
    letterSpacing: "0.1em", textTransform: "uppercase", fontWeight: 500,
  };
}

/* ─── LoopSection9 — the momentum loop (real charges, not the analogy) ─── */
function LoopSection9({ kids }) {
  const [driveOn, setDriveOn] = useState(true);
  const cur = useInductorSim({ driveOn, L: 2.4, running: true, offFactor: 3.5 });
  const ref = useInViewCallback(() => {});
  return (
    <section className="section" id="momentum-loop" data-screen-label="Momentum loop" ref={ref}
             style={{ background: "var(--bg-deeper)" }}>
      <div className="marker">§ the real picture · charges with momentum</div>
      <div className="section-inner" style={{ maxWidth: 900 }}>
        <h2 className="serif" style={{ marginBottom: 12 }}>
          {kids ? <>Watch the charges<br/><em>get heavy.</em></> : <>The charges themselves<br/>have <em>momentum.</em></>}
        </h2>
        <p className="lab-lede" style={{ marginBottom: 20 }}>
          {kids
            ? <>The paddlewheel was the picture; here are the real charges. Flip the source on — see how they're <b>slow to speed up</b>. Flip it off while they're racing, and watch the <b>gap open up in the wire</b>: the charges refuse to just stop, so they keep shoving — until the push (voltage) gets big enough to <b>leap the gap</b>. That leap is the spark.</>
            : <>Same loop, real charges. Watch the switch itself: opening it doesn't just stop the flow — it <b>breaks the path</b>. The coil won't let current change instantly, so it keeps driving charge at that broken gap, and voltage <b>climbs</b> (right below the current readout) until it's high enough to arc across the air. The spike isn't a side-effect of current falling — it's the coil <b>fighting</b> the cut, and losing that fight looks like a spark.</>}
        </p>
        <div style={{ display: "flex", gap: 10, marginBottom: 18, flexWrap: "wrap" }}>
          <button onClick={() => setDriveOn(true)} style={spinBtn(driveOn, "var(--water)")}>▶ Source ON</button>
          <button onClick={() => setDriveOn(false)} style={spinBtn(!driveOn, "var(--current)")}>■ Source OFF</button>
        </div>
        <div className="lab-stage" style={{ background: "var(--bg-card)", border: "1px solid var(--rule)", borderRadius: 12, padding: 10 }}>
          <LoopScene9 cur={cur} driveOn={driveOn} kids={kids} />
        </div>
        <p className="lab-foot" style={{ marginTop: 16, fontSize: 14, color: "var(--ink-soft)" }}>
          {kids
            ? <>This is the mirror of the bucket: the bucket fought to keep its <b>level</b>, the wheel fights to keep its <b>flow</b>.</>
            : <>The dual of the capacitor: where C resisted a change in <b>voltage</b>, L resists a change in <b>current</b> — storing energy in a magnetic field instead of an electric one.</>}
        </p>
        <p className="lab-foot" style={{ marginTop: 8, fontSize: 14, color: "var(--ink-soft)" }}>
          {kids
            ? <>And that spark isn't just for show — it's <b>exactly</b> how a spark plug fires, and exactly what engineers add a little "safety valve" part to tame in motors and relays. Both coming up next.</>
            : <>This spike is never just a curiosity to route around — engines <b>deliberately</b> cut an inductor to fire spark plugs, and every relay/motor driver needs a flyback diode to survive it. Both real circuits, next.</>}
        </p>
      </div>
    </section>
  );
}

function LessonScrollyteller({ showChart, kids }) {
  const [driveOn, setDriveOn] = useState(true);
  const [L, setL] = useState(2);
  const [nav, setNav] = useState("begin");
  const cur = useInductorSim({ driveOn, L, running: true });
  const visHeight = showChart ? 340 : 540;
  return (
    <section className="lesson">
      <div className="lesson-scroll">
        <BigIdeaBeat onView={() => setNav("begin")} kids={kids} />
        <SpinUpBeat driveOn={driveOn} setDriveOn={setDriveOn} cur={cur}
                    onView={() => setNav("spinup")} kids={kids} />
        <LBeat L={L} setL={setL} onView={() => setNav("inductance")} kids={kids} />
        <PredictBeat onView={() => setNav("predict")} kids={kids} />
        <PlaygroundBeat driveOn={driveOn} setDriveOn={setDriveOn} L={L} setL={setL} cur={cur}
                        onView={() => setNav("playground")} kids={kids} />
      </div>
      <aside className="lesson-sticky" data-single={showChart ? "0" : "1"}>
        {showChart && <VisTabs labels={["WATER", "CHART"]} />}
        <div className="vis-block">
          <div className="stage-label">WATER · the paddlewheel</div>
          <InductorWaterScene voltage={6} cur={cur} driveOn={driveOn} height={visHeight} />
        </div>
        {showChart && (
          <div className="vis-block">
            <div className="stage-label">CHART · current over time</div>
            <InductorChart cur={cur} driveOn={driveOn} height={visHeight} />
          </div>
        )}
        <div className="vis-readout">
          <div className="ro-v">
            <span className="ro-name">Source</span>
            <span className="ro-val" style={{ fontSize: 20, color: driveOn ? "var(--water)" : "var(--current)" }}>
              {driveOn ? "ON" : "OFF"}
            </span>
          </div>
          <div className="ro-r">
            <span className="ro-name">{kids ? "Weight" : "L"}</span>
            <span className="ro-val">{fmt(L, 1)}<span className="ro-unit">{kids ? "" : "H"}</span></span>
          </div>
          <div className="ro-i ro-active">
            <span className="ro-name">{kids ? "Speed" : "Current"}</span>
            <span className="ro-val">{Math.round(cur * 100)}<span className="ro-unit">%</span></span>
          </div>
          <div className="ro-p">
            <span className="ro-name">State</span>
            <span className="ro-val" style={{ fontSize: 17 }}>{driveOn ? "SPIN-UP" : "COAST"}</span>
          </div>
        </div>
      </aside>
    </section>
  );
}

/* ─── SpikeSection — cut the current, watch the voltage leap ───────────
   Interactive: power a coil, then cut it. A strip-chart shows current
   collapsing and the voltage spike it produces. A flyback-diode toggle
   tames the spike — chapter 7 meeting chapter 9. Also introduces
   E = ½LI² (the energy that has to go SOMEWHERE when you cut). */
function SpikeSection({ kids }) {
  const [on, setOn] = useState(true);
  const [L, setL] = useState(2);
  const [flyback, setFlyback] = useState(false);
  const iRef = useRef(0);
  const histRef = useRef([]);          // [{i, v}]
  const [, force] = useState(0);
  const onRef = useRef(on); onRef.current = on;
  const LRef = useRef(L); LRef.current = L;
  const fbRef = useRef(flyback); fbRef.current = flyback;

  useEffect(() => {
    let raf, last = performance.now(), acc = 0;
    const tick = (now) => {
      const dt = Math.min(0.05, (now - last) / 1000); last = now;
      const Lc = LRef.current;
      const tauUp = 0.35 + Lc * 0.30;
      // OFF: without a flyback path the field collapses brutally fast;
      // with the diode it coasts down gently through the safe loop.
      const tauDn = fbRef.current ? 0.22 + Lc * 0.18 : 0.085;
      const target = onRef.current ? 1 : 0;
      const tau = onRef.current ? tauUp : tauDn;
      const di = (target - iRef.current) * (dt / tau);
      const v = -Lc * (di / dt) * 0.55;          // toy scale for the chart
      iRef.current += di;
      acc += dt;
      if (acc > 0.033) {
        acc = 0;
        histRef.current.push({ i: iRef.current, v: fbRef.current ? Math.max(-0.16, Math.min(0.16, v)) : Math.max(-4.6, Math.min(4.6, v)) });
        if (histRef.current.length > 150) histRef.current.shift();
        force(n => n + 1);
      }
      raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, []);

  const hist = histRef.current;
  const W = 640, H = 270, x0 = 46, x1 = W - 16, yMid = 168, iY0 = 150, iAmp = 92;
  const X = (k) => x0 + (k / 149) * (x1 - x0);
  const iPts = hist.map((h, k) => `${X(k).toFixed(1)},${(iY0 - h.i * iAmp + 60).toFixed(1)}`).join(" ");
  const vPts = hist.map((h, k) => `${X(k).toFixed(1)},${(yMid - h.v * 26).toFixed(1)}`).join(" ");
  const iNow = iRef.current;
  const energy = 0.5 * L * iNow * iNow * 4;      // toy display amps
  const sparking = !on && !flyback && hist.length && Math.abs(hist[hist.length - 1].v) > 0.7;
  const spikeV = Math.round(12 + L * 90 * Math.min(1, iNow + 0.4));

  return (
    <section className="section" id="spike" data-screen-label="05 The spike"
             style={{ background: "var(--bg-deeper)" }}>
      <div className="marker">§ 05½ · cut it and see</div>
      <div className="section-inner">
        <div className="two-col">
          <div>
            <h2 className="serif">Cut the current.<br/>Watch it <em>bite</em>.</h2>
            <p className="lede">
              {kids
                ? <>Get the wheel spinning, then slam the gate shut. All that motion has to go SOMEWHERE — watch the bottom line of the chart jump!</>
                : <>Build up current, then open the switch. The collapsing field forces a huge voltage across the gap — that's the spike. Then arm the flyback diode and cut again.</>}
            </p>
            <p>
              {kids
                ? <>How big is the slam? It depends on how much oomph the wheel holds:</>
                : <>How much energy is in the slam? Exactly what the field was holding:</>}
            </p>
            <div className="eq" style={{ fontSize: 30, margin: "12px 0 6px" }}>
              <span style={{ color: "var(--ink)" }}>E</span>
              <span className="op">=</span>
              <span className="num">½</span>
              <span className="op">·</span>
              <span style={{ fontStyle: "italic" }}>L</span>
              <span className="op">·</span>
              <span className="I">I</span>
              <span style={{ fontSize: "0.6em", transform: "translateY(-0.5em)" }}>2</span>
            </div>
            <EqEase kids={kids}>
              {kids
                ? <>(Heavier wheel × faster spin = bigger slam. The "²" means speed counts double!)</>
                : <>(Half, times the inductance, times the current squared — the twin of the capacitor's ½CV². Current counts twice: double the flow, four times the stored energy. You'll use this in the practice problems below.)</>}
            </EqEase>
            <div className="rule">try it</div>
            <div style={{ display: "flex", gap: 10, marginTop: 16, flexWrap: "wrap" }}>
              <button onClick={() => setOn(o => !o)} style={spinBtn(true, on ? "var(--current)" : "var(--water)")}>
                {on ? "✂ CUT THE POWER" : "▶ POWER BACK ON"}
              </button>
              <button onClick={() => setFlyback(f => !f)} style={spinBtn(flyback, "var(--water)")}>
                {flyback ? "✓ flyback diode in" : "+ add flyback diode"}
              </button>
            </div>
            <div style={{ marginTop: 14 }}>
              <Slider name={kids ? "Wheel weight" : "Inductance · L"} value={L} min={0.5} max={5} step={0.1}
                      unit={kids ? "" : "H"} accent="current" onChange={setL} />
            </div>
          </div>
          <div>
            <div className="card" style={{ padding: "16px 18px" }}>
              <div className="eyebrow" style={{ marginBottom: 8 }}>
                {kids ? "flow (top) · kick (bottom)" : "current (top) · voltage across the switch (bottom)"}
              </div>
              <svg viewBox={`0 0 ${W} ${H}`} width="100%" style={{ display: "block" }}>
                <line x1={x0} y1={iY0 + 60 - iAmp} x2={x1} y2={iY0 + 60 - iAmp} stroke="var(--rule-strong)" strokeWidth="1" strokeDasharray="4 5" />
                <line x1={x0} y1={iY0 + 60} x2={x1} y2={iY0 + 60} stroke="var(--rule)" strokeWidth="1" />
                <text x={x0 - 6} y={iY0 + 60 - iAmp + 4} textAnchor="end" fontFamily="IBM Plex Mono, monospace" fontSize="11" fill="var(--ink-faint)">full</text>
                <text x={x0 - 6} y={iY0 + 64} textAnchor="end" fontFamily="IBM Plex Mono, monospace" fontSize="11" fill="var(--ink-faint)">0</text>
                {hist.length > 1 && <polyline points={iPts} fill="none" stroke="var(--water)" strokeWidth="2.5" />}
                <line x1={x0} y1={yMid + 62} x2={x1} y2={yMid + 62} stroke="var(--rule)" strokeWidth="1" />
                {hist.length > 1 && (
                  <polyline points={hist.map((h, k) => `${X(k).toFixed(1)},${(yMid + 62 - Math.abs(h.v) * 26).toFixed(1)}`).join(" ")}
                            fill="none" stroke={sparking ? "oklch(0.55 0.2 35)" : "var(--current)"} strokeWidth={sparking ? 3 : 2.5} />
                )}
                <text x={x0 - 6} y={yMid + 66} textAnchor="end" fontFamily="IBM Plex Mono, monospace" fontSize="11" fill="var(--ink-faint)">0</text>
                {sparking && (
                  <g>
                    <text x={x1 - 14} y={yMid - 18} textAnchor="end" fontFamily="IBM Plex Mono, monospace"
                          fontSize="16" fontWeight="600" fill="oklch(0.55 0.2 35)">⚡ ~{spikeV} V!</text>
                  </g>
                )}
                {!on && flyback && (
                  <text x={x1 - 14} y={yMid - 18} textAnchor="end" fontFamily="IBM Plex Mono, monospace"
                        fontSize="13" fill="var(--water-deep)">clamped — coasting through the diode</text>
                )}
              </svg>
              <div className="branch-readout" style={{ marginTop: 10 }}>
                <span>{kids ? "oomph stored right now" : "stored energy · ½LI²"}</span>
                <span className="mono" style={{ color: "var(--current-deep)" }}>{energy.toFixed(1)} J</span>
              </div>
            </div>
            <div className="marg" style={{ marginTop: 14 }}>
              {kids
                ? <>The one-way valve (from the diode chapter!) gives the wheel a little loop to coast in — no slam, no sparks.</>
                : <>Without the diode the spike scales with L and how fast the switch opens — tens to thousands of volts from a 12 V circuit. With it, the energy coasts off gently at ~0.7 V. Chapter 7 saving chapter 9.</>}
            </div>
          </div>
        </div>
      </div>
    </section>
  );
}

function WorkedExampleSection({ kids }) {
  return (
    <section className="section" id="example" data-screen-label="06 Spark">
      <div className="marker">§ 06 · a real inductor job · the spark</div>
      <div className="section-inner">
        <div className="two-col">
          <div>
            <h2 className="serif">A practical story:<br/><em>the ignition coil</em>.</h2>
            {kids ? (
              <>
                <p className="lede">
                  A car engine needs a BIG spark to light its fuel — way bigger
                  than its little battery can make. So how does it do it? With
                  our stubborn coil!
                </p>
                <p>
                  Watch the loop below: the battery fills the coil with push,
                  then a switch <b>snaps open</b>. The coil refuses to stop —
                  and all that push leaps across a tiny gap inside the engine
                  as a spark. Boom — the fuel lights, the engine runs.
                </p>
              </>
            ) : (
              <>
                <p className="lede">
                  A car engine needs a spark of tens of thousands of volts to ignite
                  fuel — but the battery is only 12 V. Where does that huge voltage
                  come from? An inductor's refusal to let current change suddenly.
                </p>
                <p>
                  Current builds up in a coil. Then a switch abruptly cuts it. The
                  coil, desperate to keep its current flowing, drives the voltage
                  sky-high — V = L·(di/dt), and di/dt is enormous when you cut it
                  fast. That spike jumps the spark-plug gap.
                </p>
                <p>
                  The same trick (storing energy in a magnetic field, then releasing
                  it) runs the <em>boost converters</em> that step your phone
                  battery up to drive its screen.
                </p>
              </>
            )}
          </div>
          <div>
            <div className="card" style={{ padding: "24px 26px" }}>
              <div className="eyebrow" style={{ marginBottom: 14 }}>the spike</div>
              <div className="mono" style={{ fontSize: 16, lineHeight: 1.8 }}>
                {kids ? (
                  <>fill the coil with push →<br/>snap the switch open →<br/><span style={{ color: "var(--current)" }}>a giant spark jumps!</span></>
                ) : (
                  <>V = L · (di/dt)<br/><br/>cut current fast →<br/>di/dt is huge →<br/><span style={{ color: "var(--current)" }}>V leaps to 30,000 V</span></>
                )}
              </div>
              <p className="marg" style={{ marginTop: 16 }}>
                {kids
                  ? <>Here the spark is the WHOLE POINT — the engine wants it. In other machines it's a problem, and the one-way valve tames it (next section!).</>
                  : <>That's why you add a <em>flyback diode</em> across coils and motors — to give that surge a safe path instead of frying your switch.</>}
              </p>
            </div>
            <div className="marg" style={{ marginTop: 18 }}>
              {kids
                ? <>The spinning wheel (this chapter) + the one-way valve (chapter 7): together they make — and tame — a spark.</>
                : <>Inductor (Ch 9) + diode (Ch 7): two ideas combine to make and tame a spark.</>}
            </div>
          </div>
        </div>
        <div style={{ marginTop: 28 }}>
          <div className="eyebrow" style={{ marginBottom: 12 }}>{kids ? "watch it fire" : "the whole circuit, firing"}</div>
          <IgnitionScene kids={kids} />
        </div>
      </div>
    </section>
  );
}

const Q_ADULT = [
  { q: "An inductor resists changes in…", kind: "concept", options: ["voltage", "current", "resistance", "temperature"], correct: 1, explain: "Current. It's the mirror of the capacitor, which resists voltage change." },
  { q: "The water analogy for an inductor is a…", kind: "concept", options: ["bucket", "one-way valve", "heavy paddlewheel (momentum)", "pinch"], correct: 2, explain: "A heavy flywheel — slow to spin up, keeps going once moving." },
  { q: "Inductance is measured in…", kind: "concept", options: ["farads", "henries (H)", "ohms", "hertz"], correct: 1, explain: "The henry, after Joseph Henry." },
  { q: "Physically, an inductor is usually just a…", kind: "concept", options: ["pair of plates", "coil of wire", "block of carbon", "crystal"], correct: 1, explain: "A coil — current through it stores energy in a magnetic field." },
  { q: "Abruptly cutting current to an inductor produces a…", kind: "concept", options: ["smooth stop", "large voltage spike", "drop to half", "permanent reversal"], correct: 1, explain: "Current can't change instantly, so voltage spikes (V = L·di/dt) — used in ignition coils." },
  { q: "R, C, and L are the three…", kind: "concept", options: ["power sources", "passive components", "kinds of wire", "logic gates"], correct: 1, explain: "Resistor, capacitor, inductor — the three passive building blocks." },
  {
    q: "An inductor resists changes in…",
    kind: "concept",
    options: ["voltage", "current", "temperature", "color"],
    correct: 1,
    explain: "The flywheel fights changes in FLOW. (The capacitor is its mirror: it fights changes in voltage.)",
  },
  {
    q: "Cut power to a coil suddenly and it…", kind: "concept",
    options: ["does nothing", "tries to keep the current going — voltage spikes", "becomes a resistor", "charges up like a battery"],
    correct: 1,
    explain: "The spinning flywheel doesn't stop on command — it shoves the current onward, spiking the voltage. (That's why relays get flyback diodes.)",
  },
  {
    q: "Capacitor is to voltage as inductor is to…", kind: "concept",
    options: ["resistance", "current", "power", "heat"],
    correct: 1,
    explain: "C stores charge and steadies voltage; L stores momentum and steadies current. Perfect mirrors.",
  },
  {
    q: "Where does the voltage spike energy come from when you cut current to an inductor?",
    kind: "concept",
    options: [
      "It's created from nothing",
      "The magnetic field around the coil, collapsing and dumping its stored energy back into the circuit",
      "The wire itself heats up and releases it",
      "It comes from the switch",
    ],
    correct: 1,
    explain: "An inductor stores energy in its magnetic field while current flows. Cut the current and that field collapses, shoving its stored energy back out as a voltage spike — enough to arc across a switch's contacts.",
  },
  {
    q: "Why do relays and motors need a 'flyback diode' across their coil?",
    kind: "concept",
    options: [
      "To make them spin faster",
      "To give the collapsing field's spike a safe path, protecting the switch/transistor that drives it",
      "To store extra charge",
      "To rectify AC",
    ],
    correct: 1,
    explain: "Without a return path, the inductor's collapse-spike can be hundreds of volts — enough to destroy a switching transistor. The flyback diode gives that energy somewhere safe to go.",
  },
  {
    q: "A bigger inductor (more henries) means the current…",
    kind: "math",
    options: ["changes MORE easily", "changes MORE slowly for the same voltage", "is unaffected", "reverses instantly"],
    correct: 1,
    explain: "V = L·(di/dt) — for a fixed voltage, a bigger L means a smaller rate of current change. More henries, more sluggish.",
  },
];
const Q_KIDS = [
  { q: "An inductor is like a heavy…", kind: "concept", options: ["bucket", "spinning wheel", "wall", "balloon"], correct: 1, explain: "A heavy paddlewheel — hard to start, hard to stop!" },
  { q: "When you turn the power on, the wheel speeds up…", kind: "concept", options: ["instantly", "slowly", "never", "backward"], correct: 1, explain: "Slowly — it has momentum, like a real heavy wheel." },
  { q: "When you turn the power off, the wheel…", kind: "concept", options: ["stops instantly", "coasts for a bit", "explodes", "reverses"], correct: 1, explain: "It coasts — it wants to keep going!" },
  { q: "The inductor is the opposite of the…", kind: "concept", options: ["battery", "capacitor (bucket)", "wire", "switch"], correct: 1, explain: "The capacitor stores a push; the inductor stores motion. Opposites!" },
  { q: "A heavier wheel is…", kind: "concept", options: ["faster to change", "slower to change", "the same", "lighter"], correct: 1, explain: "Slower to speed up AND slower to stop." },
  {
    q: "The heavy waterwheel is hard to…", kind: "concept",
    options: ["paint", "start AND stop", "see", "lift"],
    correct: 1,
    explain: "It resists changes — slow to spin up, and once spinning it doesn't want to stop.",
  },
  {
    q: "When you stop pushing, the spinning wheel…", kind: "concept",
    options: ["stops instantly", "keeps the water moving a little longer", "reverses", "disappears"],
    correct: 1,
    explain: "Its momentum keeps the flow going for a moment — that's what an inductor does.",
  },
  {
    q: "Which pair are opposites-buddies?", kind: "concept",
    options: ["bucket and flywheel", "pipe and pipe", "switch and wire", "barrel and barrel"],
    correct: 0,
    explain: "The bucket (capacitor) smooths the push; the flywheel (inductor) smooths the flow.",
  },
  {
    q: "Where does the extra push come from when you suddenly stop the wheel?",
    kind: "concept",
    options: ["Nowhere, it's magic", "The wheel's own spinning energy, let out all at once", "The battery makes more", "The wire creates it"],
    correct: 1,
    explain: "The spinning wheel was storing energy. Stop it suddenly and that energy has to go somewhere — out it comes as a big push!",
  },
  {
    q: "A heavier flywheel changes speed…",
    kind: "concept",
    options: ["faster", "more slowly", "the same", "never"],
    correct: 1,
    explain: "More weight (inductance) means more sluggish — slower to speed up, slower to stop.",
  },
];

function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  useCrossChapterPersistence(t, setTweak);
  useEffect(() => { document.body.setAttribute("data-theme", t.theme); }, [t.theme]);
  const kids = t.audience === "kids";
  const navItems = [
    { id: "cover", label: "Cover" },
    { id: "begin", label: kids ? "Heavy wheel" : "Momentum" },
    { id: "spinup", label: kids ? "On/off" : "Spin up" },
    { id: "inductance", label: kids ? "Weight" : "Inductance" },
    { id: "predict", label: "Predict" },
    { id: "playground", label: "Playground" },
    ...(kids ? [] : [{ id: "example", label: "The spark" }]),
    { id: "practice", label: "Practice" },
    { id: "quiz", label: "Quiz" },
    { id: "whats-next", label: "What's next" },
  ];
  return (
    <>
      <ChapterStartMarker chapterN="09" />
      <ProgressBar />
      <TopBar currentN="09" chapterLabel="Ch. 09 — The Flywheel"
              audience={t.audience} setAudience={(v) => setTweak("audience", v)} />
      <ChapterNav items={navItems} />
      <main>
        <CoverPage chapterN="09"
                   chapterTitle={<>The <em>Flywheel</em>.</>}
                   chapterSub="Chapter 9 · Inductors & momentum"
                   kids={kids}
                   lede={kids
                     ? <>Meet the heavy wheel. An <em>inductor</em> is slow to get going and slow to stop — it gives a circuit momentum, like a spinning wheel that won't quit.</>
                     : <>The last passive component. Where a capacitor resists voltage change, an inductor resists <em>current</em> change — storing energy in a magnetic field. The flywheel of electronics.</>} />
        <LessonScrollyteller showChart={t.showChart} kids={kids} />

        <LoopSection9 kids={kids} />

        <CheckpointQuiz kids={kids} label="Checkpoint 1" pick={2}
          title={kids ? "Quick check!" : "Did it stick?"}
          questions={[
            {
              q: "You flip the tap ON. With a heavy wheel in the pipe, the flow…",
              options: ["Rises slowly — the wheel fights any change at first", "Jumps to full instantly", "Reverses", "Never starts"],
              correct: 0,
              explain: kids ? "All the early push goes into getting the heavy wheel turning. Only as it spins up does the water really move."
                            : "An inductor opposes dI/dt: at switch-on it develops back-voltage and the current ramps gradually toward V/R instead of stepping.",
            },
            {
              q: "You cut the tap OFF while the wheel is spinning fast. The flow…",
              options: ["Keeps shoving for a moment — it hates to stop", "Stops dead instantly", "Reverses politely", "Was never moving"],
              correct: 0,
              explain: kids ? "A spinning wheel doesn't care that you closed the tap — its momentum keeps pushing the water, hard, for a moment."
                            : "Stored energy (½LI²) must go somewhere: the inductor drives its current onward, spiking voltage across whatever tries to interrupt it.",
            },
            {
              q: "Inductor vs. capacitor — the relationship?",
              options: [kids ? "Opposites: the wheel hates flow changing; the bucket hates the level changing" : "Duals: L resists current change, C resists voltage change", "Identical parts", "Both are kinds of resistor", "No relationship"],
              correct: 0,
              explain: kids ? "Bucket: keeps the LEVEL steady. Wheel: keeps the FLOW steady. Two stubborn opposites — together they can make a rhythm!"
                            : "Mirror components: C stores energy in an electric field and smooths V; L stores it in a magnetic field and smooths I. Paired, they resonate.",
            },
            {
              q: "The energy in a spinning flywheel is stored as…",
              options: [kids ? "Motion — and it must go somewhere when you stop it" : "Motion — a magnetic field, in the inductor's case", "Heat", "Extra water", "Sound"],
              correct: 0,
              explain: kids ? "A heavy spinning thing is full of stored oomph. Stop it suddenly and that oomph slams into whatever's in the way."
                            : "½LI² sits in the magnetic field while current flows. Interrupt the path and the field collapses, dumping that energy as a voltage kick.",
            },
          ]} />

        <WorkedExampleSection kids={kids} />
        <SpikeSection kids={kids} />

        <CheckpointQuiz kids={kids} label="Checkpoint 2" pick={2}
          title={kids ? "Spot it in real life!" : "Out in the wild."}
          intro={kids ? "Heavy-wheel behavior is all around — and it bites!" : "Where the flywheel shows up (and bites)."}
          questions={[
            {
              q: "Unplug a vacuum cleaner mid-run and a fat spark snaps at the outlet. That's…",
              options: ["The motor coil's momentum — current refusing to stop, spiking the push to jump the gap", "Static from the carpet", "The outlet shorting", "Totally imaginary"],
              correct: 0,
              explain: kids ? "The motor's 'wheel' was spinning hard. Yank its path away and the flow leaps across the air gap rather than stop — snap!"
                            : "Interrupting an inductive load forces dI/dt → the coil generates whatever voltage it takes to keep current flowing — enough to arc across the parting contacts.",
            },
            {
              q: "Circuits that drive a relay or motor coil add a 'flyback' diode across the coil to…",
              options: ["Catch the kick when the coil's current is cut — give it a safe lap to coast in", "Make the coil louder", "Charge the battery", "Add resistance"],
              correct: 0,
              explain: kids ? "When the gate slams shut, the spinning wheel needs SOMEWHERE to push its water. The one-way valve gives it a little loop to coast around safely."
                            : "The diode (ch. 7) provides a path for the collapsing field's current, clamping the spike to a safe ~0.7 V above supply instead of frying the transistor.",
            },
            {
              q: "Power supplies use inductors to…",
              options: ["Smooth bumpy current — a flywheel coasting through the gaps", "Add resistance on purpose", "Store light", "Make noise"],
              correct: 0,
              explain: kids ? "Gulp-gulp-gulp pours in, steady stream coasts out — the heavy wheel keeps the flow even between gulps."
                            : "Chokes resist current ripple just as caps resist voltage ripple. Every switching supply pairs an L and a C to turn pulses into a steady output.",
            },
            {
              q: "Why do the lights dim for a blink when a big motor (AC unit, power saw) kicks on?",
              options: ["It gulps a huge starting surge while its 'wheel' spins up", "It pushes electricity backwards", "It lowers the house voltage permanently", "The bulbs get nervous"],
              correct: 0,
              explain: kids ? "Getting a heavy wheel moving takes a giant first shove — for a split second the motor drinks so much that everyone else's push dips."
                            : "A motor at standstill draws several times its running current (inrush). The surge drops extra voltage across the house wiring — everyone else browns out briefly.",
            },
          ]} />

        <PracticeProblems chapterN="09" kids={kids} problems={[
          (rng) => {
            const l = rng.pick([1, 2, 0.5, 3]), didt = rng.int(2, 6, 1);
            return {
              q: { adult: `A ${l} H inductor's current changes at ${didt} A per second. What voltage appears across it?`, kids: `A heavy flywheel of size ${l}, with flow speeding up by ${didt} each second. Push-back = size × how-fast-it-changes.` },
              unit: "V", answer: +(l * didt).toFixed(2), tol: 0.04,
              hint: "V = L × (di/dt).",
              solution: { adult: `V = L × (di/dt) = ${l} H × ${didt} A/s = ${+(l * didt).toFixed(2)} V.`, kids: `${l} × ${didt} = ${+(l * didt).toFixed(2)}.` } };
          },
          (rng) => {
            const l = rng.pick([0.5, 1, 2]), i = rng.int(1, 4, 1);
            const e = +(0.5 * l * i * i).toFixed(2);
            return {
              q: { adult: `How much energy is stored in a ${l} H inductor carrying ${i} A? (Answer in joules.)`, kids: `Energy in a spinning flywheel = ½ × size × flow × flow. Size ${l}, flow ${i}.` },
              unit: "J", answer: e, tol: 0.04,
              hint: "E = ½ L I².",
              solution: { adult: `E = ½ L I² = ½ × ${l} × ${i}² = ${e} J.`, kids: `½ × ${l} × ${i} × ${i} = ${e}.` } };
          },
          (rng) => {
            const l = rng.pick([1, 2, 0.5]), r = rng.pick([50, 100, 200, 250]);
            const ms = +(l / r * 1000).toFixed(1);
            return {
              q: { adult: `A ${l} H inductor sits with a ${r} Ω resistor. What is the L/R time constant? (Answer in milliseconds.)`, kids: `How quickly the flywheel settles = size ÷ pinch. Size ${l}, pinch ${r}. (in thousandths of a second)` },
              unit: "ms", answer: ms, tol: 0.05,
              hint: "\u03c4 = L ÷ R, then ×1000 for ms.",
              solution: { adult: `\u03c4 = L ÷ R = ${l} ÷ ${r} = ${+(l / r).toFixed(4)} s = ${ms} ms.`, kids: `${l} ÷ ${r} = ${ms} thousandths.` } };
          },
        ]} />

        <ChapterQuiz chapterN="09"
          title={kids ? "Quick quiz!" : "Check your understanding."}
          intro={kids ? "Five quick questions about the flywheel." : "Inductors & momentum. 70% to pass; retry freely."}
          questions={kids ? Q_KIDS : Q_ADULT} pick={5} />
        <div className="section" style={{ paddingTop: 0 }}>
          <div className="section-inner">
            <p className="lede" style={{ maxWidth: "46em", color: "var(--ink-soft)" }}>
              {kids
                ? <>Try it: open <b>The Sandbox</b> and load <b>“Inductor (RL)”</b> — watch the charges start slow and speed up, because the heavy wheel hates a sudden change. Then try <b>“LC oscillator”</b> and see the flow swing back and forth.</>
                : <>See it move: in <b>The Sandbox</b>, the <b>RL</b> example shows current ramping in (the inductor opposing the change); <b>LC</b> rings as energy sloshes L↔C, and <b>RLC</b> shows that ringing damp away. Probe a node to scope it.</>}
            </p>
            <a className="wn-link" href="flow-sandbox.html?ex=rl" style={{ display: "inline-block", marginTop: 8 }}>Open The Sandbox →</a>
          </div>
        </div>
        <WhatsNext currentN="09" kids={kids}
          summary={kids
            ? <>You've met the heavy wheel — and now all the parts! Next, we put them together into something that blinks: the 555 timer.</>
            : <>R, C, and L — you now know all three passive components, plus diodes, transistors, and AC. Next we combine them into a working oscillator: the 555 timer.</>}
          prevHref="chapter8.html" prevLabel="Chapter 8"
          nextHref="chapter10.html" nextLabel="Chapter 10 · The Blinker" />
      </main>
      <TweaksPanel title="Tweaks">
        <CommonTweaks t={t} setTweak={setTweak}
          animationToggles={[{ key: "showChart", label: "Show chart" }]} />
      </TweaksPanel>
      <GlossaryFab />
    </>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
