/* capstone.jsx — Master Engineer Lv.1 final exam.
   A sequence of design briefs. Each: read the spec, pick component values,
   the sim judges pass/fail with real consequences (LEDs pop, etc).
   Adult & kids modes. Certificate on completion.

   Depends on shared.jsx (TopBar, CommonTweaks, useTweaks, useCrossChapterPersistence,
   ChapterStrip, fmt) and visuals.jsx helpers indirectly. Self-contained SVGs here. */

const { useState, useEffect, useRef } = React;

/* ─── small helpers ─────────────────────────────────────────────────────── */
function clamp(x, lo, hi) { return Math.max(lo, Math.min(hi, x)); }

/* Standard E12 resistor values (the real ones you can actually buy). */
const E12 = [10, 12, 15, 18, 22, 27, 33, 39, 47, 56, 68, 82,
             100, 120, 150, 180, 220, 270, 330, 390, 470, 560, 680, 820,
             1000, 1200, 1500, 2200, 3300, 4700, 6800, 10000];

function ohmLabel(r) {
  if (r >= 1000) return (r / 1000).toFixed(r % 1000 ? 1 : 0).replace(/\.0$/, "") + " kΩ";
  return r + " Ω";
}

/* ─── A reusable "pick from a dropdown of real parts" control ───────────── */
function PartPicker({ label, value, options, fmtOption, onChange, accent }) {
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 6, marginBottom: 14 }}>
      <span style={{
        fontFamily: "'IBM Plex Mono', monospace", fontSize: 11,
        letterSpacing: "0.12em", textTransform: "uppercase", color: "var(--ink-soft)",
      }}>{label}</span>
      <select value={value} onChange={(e) => onChange(Number(e.target.value))}
              className="capstone-select"
              style={{ borderColor: accent ? `var(--${accent})` : "var(--rule-strong)" }}>
        {options.map(o => (
          <option key={o} value={o}>{fmtOption ? fmtOption(o) : o}</option>
        ))}
      </select>
    </div>
  );
}

/* ─── Verdict banner ────────────────────────────────────────────────────── */
function Verdict({ state, children }) {
  if (!state) return null;
  return (
    <div className={`capstone-verdict ${state}`}>
      <span className="v-icon">{state === "pass" ? "✓" : state === "warn" ? "!" : "✕"}</span>
      <div>{children}</div>
    </div>
  );
}

/* ═══════════════════════════════════════════════════════════════════════
   BRIEF 1 — Light an LED from a battery without frying it.
   Spec: LED wants ~2 V @ ~20 mA from a battery. Choose a series resistor.
   ═══════════════════════════════════════════════════════════════════════ */
function BriefLED({ kids, onResult }) {
  // Randomized each mount so retries differ.
  const [params] = useState(() => {
    const supplies = [5, 6, 9, 12];
    const vBatt = supplies[Math.floor(Math.random() * supplies.length)];
    const vLed = 2.0;
    const iTargetMa = 20;
    return { vBatt, vLed, iTargetMa };
  });
  const idealR = (params.vBatt - params.vLed) / (params.iTargetMa / 1000);
  const [r, setR] = useState(E12[Math.floor(E12.length / 2)]);
  const [checked, setChecked] = useState(false);

  // Actual current with chosen R (assuming LED clamps at vLed)
  const iActual = Math.max(0, (params.vBatt - params.vLed) / r) * 1000; // mA
  // LED outcome
  const ledState = iActual > 35 ? "pop" : iActual > 25 ? "bright" : iActual >= 12 ? "good" : iActual >= 4 ? "dim" : "off";
  const pass = ledState === "good" || ledState === "bright";
  const ideal = ledState === "good";

  useEffect(() => { if (checked) onResult(pass); }, [checked]);

  const glow = ledState === "pop" ? 0 : clamp(iActual / 22, 0, 1.1);

  return (
    <div className="brief">
      <div className="brief-spec">
        <div className="brief-tag">Brief 1 · The LED</div>
        <h3>{kids ? "Light the bulb without popping it." : "Drive the LED safely."}</h3>
        <p>
          {kids
            ? <>You have a <b>{params.vBatt} V</b> battery and a little LED. The LED is happy with a <b>gentle</b> trickle — about <b>20 mA</b>. Too much and it pops! Pick a pinch (resistor) that protects it.</>
            : <>Battery: <b>{params.vBatt} V</b>. LED forward voltage ≈ <b>2 V</b>, target current ≈ <b>20 mA</b>. Choose a series resistor so the LED runs bright but safe.</>}
        </p>
        {!kids && (
          <p className="brief-hint">
            Hint: the resistor drops the leftover voltage. R = (V<sub>batt</sub> − V<sub>LED</sub>) / I.
          </p>
        )}
      </div>

      <div className="brief-stage">
        <LEDDiagram vBatt={params.vBatt} r={r} ledState={ledState} glow={glow} kids={kids} />
        <div className="brief-controls">
          <PartPicker label="Series resistor"
            value={r} options={E12} fmtOption={ohmLabel} onChange={(v) => { setR(v); setChecked(false); }}
            accent="current" />
          <div className="brief-readout">
            <span>Current through LED</span>
            <span className="mono" style={{ color: ledState === "pop" ? "var(--current)" : "var(--ink)" }}>
              {ledState === "pop" ? "—" : iActual.toFixed(1) + " mA"}
            </span>
          </div>
          <button className="brief-check" onClick={() => setChecked(true)}>
            {kids ? "Try it!" : "Test the circuit"}
          </button>
        </div>
      </div>

      {checked && (
        <Verdict state={ledState === "pop" ? "fail" : pass ? "pass" : "warn"}>
          {ledState === "pop" && (kids
            ? <><b>Pop!</b> Too much flow — that resistor is too small. Try a bigger one to pinch the flow down.</>
            : <><b>LED destroyed.</b> {iActual.toFixed(0)} mA is well over the ~20 mA rating. Bigger resistor needed — aim near {ohmLabel(E12.find(v => v >= idealR) || 470)}.</>)}
          {ledState === "bright" && (kids
            ? <><b>It works — but it's running hot.</b> A slightly bigger pinch would be safer.</>
            : <><b>Lit, but a touch over.</b> {iActual.toFixed(0)} mA is above target; fine briefly, but a larger R is kinder to the LED.</>)}
          {ideal && (kids
            ? <><b>Perfect!</b> Nice steady glow. You protected the LED.</>
            : <><b>Nailed it.</b> {iActual.toFixed(0)} mA — right in the LED's happy zone. Ideal R ≈ {ohmLabel(E12.find(v => v >= idealR) || 220)}.</>)}
          {ledState === "dim" && (kids
            ? <><b>Too dim.</b> That pinch is too tight — barely any flow. Try a smaller resistor.</>
            : <><b>Under-driven.</b> Only {iActual.toFixed(1)} mA — visible but dim. A smaller R gets you closer to 20 mA.</>)}
          {ledState === "off" && <><b>Basically off.</b> Way too much resistance. Pick a much smaller value.</>}
        </Verdict>
      )}
    </div>
  );
}

function LEDDiagram({ vBatt, r, ledState, glow, kids }) {
  const W = 460, H = 230;
  const popped = ledState === "pop";
  const flowing = ledState !== "off" && !popped;
  const period = flowing ? clamp(1.8 / (glow + 0.2), 0.3, 4).toFixed(2) + "s" : "9999s";
  const loop = "M 70 60 L 390 60 L 390 180 L 70 180 Z";
  return (
    <svg viewBox={`0 0 ${W} ${H}`} width="100%" height="auto" style={{ maxHeight: 220 }}>
      <defs>
        <radialGradient id="led-glow" cx="50%" cy="50%" r="50%">
          <stop offset="0%" stopColor="var(--current-deep)" stopOpacity="0.95" />
          <stop offset="55%" stopColor="var(--current)" stopOpacity="0.4" />
          <stop offset="100%" stopColor="var(--current)" stopOpacity="0" />
        </radialGradient>
      </defs>
      <path d={loop} fill="none" stroke="var(--ink)" strokeWidth="2.5" strokeLinecap="round" />
      {/* battery, left side */}
      <line x1="56" y1="108" x2="84" y2="108" stroke="var(--ink)" strokeWidth="3" />
      <line x1="63" y1="132" x2="77" y2="132" stroke="var(--ink)" strokeWidth="3" />
      <line x1="56" y1="120" x2="84" y2="120" stroke="var(--ink)" strokeWidth="2.5" />
      <text x="34" y="124" fontFamily="IBM Plex Mono, monospace" fontSize="17.5" fill="var(--water)" textAnchor="middle">{vBatt}V</text>
      {/* resistor, top */}
      <rect x="180" y="48" width="100" height="24" rx="2" fill="var(--bg-card)" stroke="var(--ink)" strokeWidth="2.5" />
      <text x="230" y="38" fontFamily="IBM Plex Mono, monospace" fontSize="16" fill="var(--ink-faint)" textAnchor="middle">{ohmLabel(r)}</text>
      {/* LED, right */}
      <circle cx="390" cy="120" r="40" fill="url(#led-glow)" opacity={popped ? 0 : glow} />
      {popped ? (
        <g>
          <text x="390" y="128" fontSize="40.5" textAnchor="middle">💥</text>
          <text x="390" y="156" fontFamily="IBM Plex Mono, monospace" fontSize="15" fill="var(--current)" textAnchor="middle">POP</text>
        </g>
      ) : (
        <g>
          <polygon points="378,108 378,132 400,120" fill={flowing ? "var(--current-deep)" : "var(--bg-card)"} stroke="var(--ink)" strokeWidth="2" />
          <line x1="400" y1="106" x2="400" y2="134" stroke="var(--ink)" strokeWidth="2.5" />
        </g>
      )}
      {/* electrons */}
      {flowing && [0, 1, 2, 3].map(i => (
        <circle key={i} r="4" fill="var(--current)">
          <animateMotion path={loop} dur={period} begin={`-${i * 0.4}s`} repeatCount="indefinite" />
        </circle>
      ))}
    </svg>
  );
}

/* ═══════════════════════════════════════════════════════════════════════
   BRIEF 2 — Voltage divider: hit a target output voltage.
   ═══════════════════════════════════════════════════════════════════════ */
function BriefDivider({ kids, onResult }) {
  const [params] = useState(() => {
    const vIn = [9, 10, 12][Math.floor(Math.random() * 3)];
    const targets = [vIn / 3, vIn / 2, (2 * vIn) / 3];
    const vTarget = Math.round(targets[Math.floor(Math.random() * targets.length)] * 10) / 10;
    return { vIn, vTarget };
  });
  const [r1, setR1] = useState(1000);
  const [r2, setR2] = useState(1000);
  const [checked, setChecked] = useState(false);

  const vOut = params.vIn * (r2 / (r1 + r2));
  const err = Math.abs(vOut - params.vTarget);
  const tol = kids ? 0.6 : 0.25;
  const pass = err <= tol;

  useEffect(() => { if (checked) onResult(pass); }, [checked]);

  return (
    <div className="brief">
      <div className="brief-spec">
        <div className="brief-tag">Brief 2 · {kids ? "The Splitter" : "The Voltage Divider"}</div>
        <h3>{kids ? "Split the push to hit a target." : "Build a divider for the target voltage."}</h3>
        <p>
          {kids
            ? <>You have a <b>{params.vIn} V</b> push. Using two pinches stacked up, make the spot between them read about <b>{params.vTarget} V</b>.</>
            : <>Source: <b>{params.vIn} V</b>. Using two resistors in series, set the midpoint to <b>{params.vTarget} V</b>. (V<sub>out</sub> = V<sub>in</sub> · R₂/(R₁+R₂).)</>}
        </p>
      </div>

      <div className="brief-stage">
        <DividerDiagram vIn={params.vIn} r1={r1} r2={r2} vOut={vOut} kids={kids} />
        <div className="brief-controls">
          <PartPicker label={kids ? "Top pinch (R₁)" : "R₁ (top)"} value={r1} options={E12} fmtOption={ohmLabel}
            onChange={(v) => { setR1(v); setChecked(false); }} accent="water" />
          <PartPicker label={kids ? "Bottom pinch (R₂)" : "R₂ (bottom)"} value={r2} options={E12} fmtOption={ohmLabel}
            onChange={(v) => { setR2(v); setChecked(false); }} accent="water" />
          <div className="brief-readout">
            <span>{kids ? "Reading at the middle" : <Eq>V_out</Eq>}</span>
            <span className="mono" style={{ color: "var(--water)" }}>{vOut.toFixed(2)} V</span>
          </div>
          <button className="brief-check" onClick={() => setChecked(true)}>
            {kids ? "Measure it!" : <>Measure <Eq>V_out</Eq></>}
          </button>
        </div>
      </div>

      {checked && (
        <Verdict state={pass ? "pass" : "warn"}>
          {pass
            ? (kids
                ? <><b>Bang on!</b> {vOut.toFixed(1)} V — that's the target. The bigger the bottom pinch compared to the top, the more push is left at the middle.</>
                                : <><b>Within spec.</b> {vOut.toFixed(2)} V vs target {params.vTarget} V. The ratio R₂/(R₁+R₂) sets the fraction of <Eq>V_in</Eq> that appears at the midpoint.</>)
            : (kids
                ? <><b>Not yet.</b> You got {vOut.toFixed(1)} V, aiming for {params.vTarget} V. {vOut > params.vTarget ? "Make the bottom pinch smaller (or the top bigger)." : "Make the bottom pinch bigger (or the top smaller)."}</>
                : <><b>Off target.</b> {vOut.toFixed(2)} V vs {params.vTarget} V. {vOut > params.vTarget ? "Lower R₂/(R₁+R₂): shrink R₂ or grow R₁." : "Raise R₂/(R₁+R₂): grow R₂ or shrink R₁."} Equal resistors give exactly half.</>)}
        </Verdict>
      )}
    </div>
  );
}

function DividerDiagram({ vIn, r1, r2, vOut, kids }) {
  const W = 460, H = 230;
  const frac = r2 / (r1 + r2);
  return (
    <svg viewBox={`0 0 ${W} ${H}`} width="100%" height="auto" style={{ maxHeight: 220 }}>
      <line x1="120" y1="30" x2="120" y2="60" stroke="var(--ink)" strokeWidth="2.5" />
      {/* R1 */}
      <rect x="100" y="60" width="40" height="56" rx="2" fill="var(--bg-card)" stroke="var(--ink)" strokeWidth="2.5" />
      <text x="155" y="92" fontFamily="IBM Plex Mono, monospace" fontSize="16" fill="var(--ink-faint)">{ohmLabel(r1)}</text>
      {/* midpoint tap */}
      <line x1="120" y1="116" x2="120" y2="124" stroke="var(--ink)" strokeWidth="2.5" />
      <circle cx="120" cy="120" r="4" fill="var(--water)" />
      <line x1="120" y1="120" x2="250" y2="120" stroke="var(--water)" strokeWidth="2" strokeDasharray="4 4" />
      <text x="262" y="116" fontFamily="IBM Plex Mono, monospace" fontSize="19" fill="var(--water)">{vOut.toFixed(1)} V</text>
      <text x="262" y="134" fontFamily="IBM Plex Mono, monospace" fontSize="13.5" fill="var(--ink-faint)">{kids ? "the middle" : <><tspan>V</tspan><tspan dy="3" fontSize="11">out</tspan></>}</text>
      {/* R2 */}
      <rect x="100" y="124" width="40" height="56" rx="2" fill="var(--bg-card)" stroke="var(--ink)" strokeWidth="2.5" />
      <text x="155" y="158" fontFamily="IBM Plex Mono, monospace" fontSize="16" fill="var(--ink-faint)">{ohmLabel(r2)}</text>
      <line x1="120" y1="180" x2="120" y2="205" stroke="var(--ink)" strokeWidth="2.5" />
      {/* ground */}
      <line x1="106" y1="205" x2="134" y2="205" stroke="var(--ink)" strokeWidth="2" />
      <line x1="111" y1="210" x2="129" y2="210" stroke="var(--ink)" strokeWidth="2" />
      <line x1="115" y1="215" x2="125" y2="215" stroke="var(--ink)" strokeWidth="2" />
      {/* source label */}
      <text x="120" y="22" fontFamily="IBM Plex Mono, monospace" fontSize="17.5" fill="var(--water)" textAnchor="middle">{vIn} V</text>
      {/* fill bar showing fraction */}
      <rect x="320" y="40" width="24" height="140" rx="4" fill="var(--bg-card)" stroke="var(--rule-strong)" strokeWidth="1.5" />
      <rect x="320" y={40 + (1 - frac) * 140} width="24" height={frac * 140} rx="4" fill="var(--water)" opacity="0.6" />
      <text x="332" y="196" fontFamily="IBM Plex Mono, monospace" fontSize="12" fill="var(--ink-faint)" textAnchor="middle">{Math.round(frac * 100)}%</text>
    </svg>
  );
}

/* ═══════════════════════════════════════════════════════════════════════
   BRIEF 3 — RC timing: keep a lamp glowing N seconds after power off.
   ═══════════════════════════════════════════════════════════════════════ */
function BriefRC({ kids, onResult }) {
  const [params] = useState(() => {
    const targetS = [2, 3, 4][Math.floor(Math.random() * 3)];
    return { targetS };
  });
  // We use arbitrary-but-consistent units: time-to-dim ≈ 0.7 * R * C (seconds),
  // with R in kΩ and C in "units" (×100µF feel). Keep watchable.
  const rOpts = [1, 2, 5, 10, 22, 47];     // kΩ
  const cOpts = [0.5, 1, 2, 4, 6, 8];       // bucket size (6 added so 4 s target is reachable: R10·C6 = 4.2 s)
  const [r, setR] = useState(10);
  const [c, setC] = useState(1);
  const [checked, setChecked] = useState(false);
  const [playing, setPlaying] = useState(false);

  const holdTime = 0.7 * r * c * 0.1;       // seconds the lamp stays lit-ish
  const err = Math.abs(holdTime - params.targetS);
  const tol = kids ? 1.2 : 0.6;
  const pass = err <= tol;

  useEffect(() => { if (checked) onResult(pass); }, [checked]);

  return (
    <div className="brief">
      <div className="brief-spec">
        <div className="brief-tag">Brief 3 · {kids ? "The Afterglow" : "RC Timing"}</div>
        <h3>{kids ? "Keep the light on after you cut power." : "Hold the lamp lit after power-off."}</h3>
        <p>
          {kids
            ? <>Add a bucket (capacitor) so the lamp keeps glowing for about <b>{params.targetS} seconds</b> after you flip the power off. Bigger pinch and bigger bucket = longer glow.</>
            : <>Spec: the lamp must stay lit ≈ <b>{params.targetS} s</b> after the supply is cut. Pick R and C. (Hold time grows with R·C — the time constant.)</>}
        </p>
      </div>

      <div className="brief-stage">
        <RCDiagram r={r} c={c} holdTime={holdTime} playing={playing} kids={kids} />
        <div className="brief-controls">
          <PartPicker label={kids ? "Pinch (R)" : "R (kΩ)"} value={r} options={rOpts}
            fmtOption={(v) => v + " kΩ"} onChange={(v) => { setR(v); setChecked(false); setPlaying(false); }} />
          <PartPicker label={kids ? "Bucket (C)" : "C (size)"} value={c} options={cOpts}
            fmtOption={(v) => "×" + v} onChange={(v) => { setC(v); setChecked(false); setPlaying(false); }} accent="water" />
          <div className="brief-readout">
            <span>{kids ? "Glow lasts" : "Hold time"}</span>
            <span className="mono">{holdTime.toFixed(1)} s</span>
          </div>
          <button className="brief-check" onClick={() => { setChecked(true); setPlaying(true); }}>
            {kids ? "Cut the power!" : "Run the test"}
          </button>
        </div>
      </div>

      {checked && (
        <Verdict state={pass ? "pass" : "warn"}>
          {pass
            ? (kids
                ? <><b>Great timing!</b> About {holdTime.toFixed(1)} seconds of afterglow — right on target.</>
                : <><b>On spec.</b> Hold ≈ {holdTime.toFixed(1)} s vs {params.targetS} s target. Hold time scales with R·C, so trade one against the other.</>)
            : (kids
                ? <><b>Close-ish.</b> The glow lasted {holdTime.toFixed(1)} s, but you want {params.targetS} s. {holdTime < params.targetS ? "Use a bigger bucket or tighter pinch." : "Use a smaller bucket or looser pinch."}</>
                : <><b>Off target.</b> {holdTime.toFixed(1)} s vs {params.targetS} s. {holdTime < params.targetS ? "Increase R·C (bigger R or C)." : "Decrease R·C."}</>)}
        </Verdict>
      )}
    </div>
  );
}

function RCDiagram({ r, c, holdTime, playing, kids }) {
  const W = 460, H = 230;
  const [t, setT] = useState(0);
  useEffect(() => {
    if (!playing) { setT(0); return; }
    let raf, start = performance.now();
    const tick = (now) => {
      const elapsed = (now - start) / 1000;
      setT(elapsed);
      if (elapsed < holdTime + 1.5) raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [playing, holdTime]);

  // brightness: full until power cut at t=0.6s, then exponential decay over holdTime
  const cutAt = 0.6;
  let bright;
  if (!playing) bright = 1;
  else if (t < cutAt) bright = 1;
  else bright = Math.exp(-(t - cutAt) / (holdTime / 2.2));
  const lit = bright > 0.08;

  return (
    <svg viewBox={`0 0 ${W} ${H}`} width="100%" height="auto" style={{ maxHeight: 220 }}>
      <defs>
        <radialGradient id="rc-glow" cx="50%" cy="50%" r="50%">
          <stop offset="0%" stopColor="var(--current-deep)" stopOpacity="0.95" />
          <stop offset="55%" stopColor="var(--current)" stopOpacity="0.4" />
          <stop offset="100%" stopColor="var(--current)" stopOpacity="0" />
        </radialGradient>
      </defs>
      {/* battery + switch */}
      <line x1="50" y1="70" x2="50" y2="160" stroke="var(--ink)" strokeWidth="2.5" />
      <line x1="36" y1="104" x2="64" y2="104" stroke="var(--ink)" strokeWidth="3" />
      <line x1="43" y1="120" x2="57" y2="120" stroke="var(--ink)" strokeWidth="3" />
      <text x="50" y="180" fontFamily="IBM Plex Mono, monospace" fontSize="15" fill={playing && t > cutAt ? "var(--ink-faint)" : "var(--water)"} textAnchor="middle">
        {playing && t > 0.6 ? "OFF" : "ON"}
      </text>
      {/* R */}
      <line x1="50" y1="70" x2="120" y2="70" stroke="var(--ink)" strokeWidth="2.5" />
      <rect x="120" y="58" width="70" height="24" rx="2" fill="var(--bg-card)" stroke="var(--ink)" strokeWidth="2.5" />
      <text x="155" y="50" fontFamily="IBM Plex Mono, monospace" fontSize="15" fill="var(--ink-faint)" textAnchor="middle">{r} kΩ</text>
      <line x1="190" y1="70" x2="300" y2="70" stroke="var(--ink)" strokeWidth="2.5" />
      {/* capacitor (bucket) at the node */}
      <line x1="240" y1="70" x2="240" y2="110" stroke="var(--ink)" strokeWidth="2.5" />
      <line x1="222" y1="110" x2="258" y2="110" stroke="var(--water)" strokeWidth="4" />
      <line x1="222" y1="120" x2="258" y2="120" stroke="var(--ink)" strokeWidth="4" />
      <line x1="240" y1="120" x2="240" y2="160" stroke="var(--ink)" strokeWidth="2.5" />
      <text x="270" y="100" fontFamily="IBM Plex Mono, monospace" fontSize="15" fill="var(--water)">×{c}</text>
      {/* lamp on right */}
      <circle cx="300" cy="120" r="46" fill="url(#rc-glow)" opacity={lit ? bright : 0} />
      <circle cx="300" cy="120" r="22" fill="var(--bg-card)" stroke="var(--ink)" strokeWidth="2.5" />
      <path d="M 288 108 L 312 132 M 312 108 L 288 132" stroke={lit ? "var(--current-deep)" : "var(--ink-soft)"} strokeWidth="2" />
      <line x1="300" y1="70" x2="300" y2="98" stroke="var(--ink)" strokeWidth="2.5" />
      <line x1="300" y1="142" x2="300" y2="160" stroke="var(--ink)" strokeWidth="2.5" />
      <line x1="50" y1="160" x2="300" y2="160" stroke="var(--ink)" strokeWidth="2.5" />
      {/* timer */}
      {playing && (
        <text x="400" y="120" fontFamily="IBM Plex Mono, monospace" fontSize="27" fill="var(--ink)" textAnchor="middle">
          {Math.max(0, t - cutAt > 0 ? (t - cutAt) : 0).toFixed(1)}s
        </text>
      )}
      {playing && <text x="400" y="140" fontFamily="IBM Plex Mono, monospace" fontSize="12" fill="var(--ink-faint)" textAnchor="middle">since power cut</text>}
    </svg>
  );
}

/* ═══════════════════════════════════════════════════════════════════════
   BRIEF 4 — Transistor switch: control a big load with a tiny signal.
   ═══════════════════════════════════════════════════════════════════════ */
function BriefTransistor({ kids, onResult }) {
  const [params] = useState(() => {
    const loadMa = [200, 300, 500][Math.floor(Math.random() * 3)];
    return { loadMa };
  });
  // Learner picks: a component to drive the load, and the base drive level.
  const [device, setDevice] = useState("resistor"); // resistor | switch | transistor
  const [signalOn, setSignalOn] = useState(true);
  const [checked, setChecked] = useState(false);

  // Only the transistor lets a tiny 3V signal control the big load.
  const correct = device === "transistor";
  const pass = correct;
  useEffect(() => { if (checked) onResult(pass); }, [checked]);

  return (
    <div className="brief">
      <div className="brief-spec">
        <div className="brief-tag">Brief 4 · {kids ? "The Tiny Boss" : "The Transistor Switch"}</div>
        <h3>{kids ? "Use a tiny signal to run a big motor." : "Switch a big load with a small signal."}</h3>
        <p>
          {kids
            ? <>A little <b>3 V</b> control wire needs to turn a <b>big</b> motor on and off. The control wire is too weak to power the motor directly. Which part lets the small signal boss the big flow?</>
            : <>A microcontroller pin gives a weak <b>3 V</b> signal. The load needs <b>~{params.loadMa} mA</b> — far more than the pin can source. Pick the device that lets the small signal control the large current.</>}
        </p>
      </div>

      <div className="brief-stage">
        <TransistorDiagram device={device} signalOn={signalOn} kids={kids} loadMa={params.loadMa} />
        <div className="brief-controls">
          <div style={{ display: "flex", flexDirection: "column", gap: 8, marginBottom: 12 }}>
            <span style={{ fontFamily: "'IBM Plex Mono', monospace", fontSize: 11, letterSpacing: "0.12em", textTransform: "uppercase", color: "var(--ink-soft)" }}>
              {kids ? "Pick a part" : "Device under the signal"}
            </span>
            {[
              { id: "resistor", label: kids ? "Just a resistor" : "A resistor" },
              { id: "switch", label: kids ? "A hand switch" : "A manual switch" },
              { id: "transistor", label: kids ? "A transistor (magic valve)" : "A transistor" },
            ].map(o => (
              <button key={o.id} onClick={() => { setDevice(o.id); setChecked(false); }}
                className={`brief-choice ${device === o.id ? "sel" : ""}`}>
                {o.label}
              </button>
            ))}
          </div>
          <button className="brief-toggle" onClick={() => setSignalOn(s => !s)}>
            Signal: <b>{signalOn ? "3 V (high)" : "0 V (low)"}</b> — tap to flip
          </button>
          <button className="brief-check" onClick={() => setChecked(true)}>
            {kids ? "Try it!" : "Test the design"}
          </button>
        </div>
      </div>

      {checked && (
        <Verdict state={pass ? "pass" : "fail"}>
          {device === "transistor"
            ? (kids
                ? <><b>Yes!</b> The transistor lets the tiny 3 V signal open a big gate for the motor. Flip the signal and watch the motor follow.</>
                : <><b>Correct.</b> The transistor's base takes the weak 3 V signal and switches the full {params.loadMa} mA load. Small control, big result.</>)
            : device === "switch"
              ? (kids
                  ? <><b>Not quite.</b> A hand switch needs a finger! The whole point is the electric signal should do the switching by itself.</>
                  : <><b>No.</b> A manual switch needs a human. The signal can't actuate it — you need an electrically-controlled switch: a transistor.</>)
              : (kids
                  ? <><b>Nope.</b> A plain resistor just pinches flow — it can't turn things on and off from a signal. You need the magic valve.</>
                  : <><b>No.</b> A resistor only limits current; it can't switch. Only the transistor uses the small signal to gate the large current.</>)}
        </Verdict>
      )}
    </div>
  );
}

function TransistorDiagram({ device, signalOn, kids, loadMa }) {
  const W = 460, H = 230;
  // Load runs only if device==transistor AND signalOn, or device==switch AND signalOn (but switch is "wrong" answer conceptually—still show it works manually), resistor never really switches.
  const loadRuns = (device === "transistor" && signalOn) || (device === "switch" && signalOn);
  const spin = loadRuns;
  const period = "1.4s";
  return (
    <svg viewBox={`0 0 ${W} ${H}`} width="100%" height="auto" style={{ maxHeight: 220 }}>
      <defs>
        <radialGradient id="motor-glow" cx="50%" cy="50%" r="50%">
          <stop offset="0%" stopColor="var(--current)" stopOpacity="0.5" />
          <stop offset="100%" stopColor="var(--current)" stopOpacity="0" />
        </radialGradient>
      </defs>
      {/* supply top rail */}
      <line x1="60" y1="40" x2="360" y2="40" stroke="var(--ink)" strokeWidth="2.5" />
      <text x="60" y="32" fontFamily="IBM Plex Mono, monospace" fontSize="15" fill="var(--water)">+12V</text>
      {/* motor/load */}
      <circle cx="360" cy="90" r="42" fill="url(#motor-glow)" opacity={loadRuns ? 1 : 0} />
      <circle cx="360" cy="90" r="24" fill="var(--bg-card)" stroke="var(--ink)" strokeWidth="2.5" />
      <text x="360" y="95" fontFamily="IBM Plex Mono, monospace" fontSize="19" fill="var(--ink)" textAnchor="middle">M</text>
      <line x1="360" y1="40" x2="360" y2="66" stroke="var(--ink)" strokeWidth="2.5" />
      {spin && <g>
        <line x1="360" y1="74" x2="360" y2="106" stroke="var(--current)" strokeWidth="2">
          <animateTransform attributeName="transform" type="rotate" from="0 360 90" to="360 360 90" dur={period} repeatCount="indefinite" />
        </line>
      </g>}
      <text x="408" y="94" fontFamily="IBM Plex Mono, monospace" fontSize="13.5" fill="var(--ink-faint)">{loadMa}mA</text>
      <line x1="360" y1="114" x2="360" y2="150" stroke="var(--ink)" strokeWidth="2.5" />
      {/* device box */}
      <rect x="320" y="150" width="80" height="40" rx="4" fill="var(--bg-card)" stroke={device === "transistor" ? "var(--current)" : "var(--rule-strong)"} strokeWidth="2.5" />
      <text x="360" y="174" fontFamily="IBM Plex Mono, monospace" fontSize="15" fill="var(--ink)" textAnchor="middle">
        {device === "transistor" ? "TRANSISTOR" : device === "switch" ? "SWITCH" : "RESISTOR"}
      </text>
      <line x1="360" y1="190" x2="360" y2="205" stroke="var(--ink)" strokeWidth="2.5" />
      {/* ground rail */}
      <line x1="60" y1="205" x2="360" y2="205" stroke="var(--ink)" strokeWidth="2.5" />
      <line x1="100" y1="205" x2="120" y2="205" stroke="var(--ink)" strokeWidth="2" />
      {/* signal wire into device */}
      <line x1="240" y1="170" x2="320" y2="170" stroke={signalOn ? "var(--current)" : "var(--ink-faint)"} strokeWidth="2" strokeDasharray={device === "transistor" ? "0" : "4 4"} />
      <circle cx="232" cy="170" r="14" fill="var(--bg-card)" stroke="var(--ink)" strokeWidth="1.5" />
      <text x="232" y="174" fontFamily="IBM Plex Mono, monospace" fontSize="12" fill={signalOn ? "var(--current)" : "var(--ink-faint)"} textAnchor="middle">
        {signalOn ? "3V" : "0V"}
      </text>
      <text x="232" y="200" fontFamily="IBM Plex Mono, monospace" fontSize="12" fill="var(--ink-faint)" textAnchor="middle">{kids ? "signal" : "control"}</text>
      {/* status */}
      <text x="150" y="100" fontFamily="IBM Plex Mono, monospace" fontSize="17.5" fill={loadRuns ? "var(--current)" : "var(--ink-faint)"} textAnchor="middle">
        {loadRuns ? "MOTOR RUNNING" : "motor off"}
      </text>
      {device === "resistor" && (
        <text x="150" y="120" fontFamily="IBM Plex Mono, monospace" fontSize="12" fill="var(--ink-faint)" textAnchor="middle">(always on — can't switch)</text>
      )}
    </svg>
  );
}

/* ═══════════════════════════════════════════════════════════════════════
   BRIEF 5 — Diode: let current flow one way only (block the backflow).
   ═══════════════════════════════════════════════════════════════════════ */
function BriefDiode({ kids, onResult }) {
  // Randomize which orientation is "correct" so retries differ.
  const [params] = useState(() => ({
    scenario: ["solar", "battery", "usb"][Math.floor(Math.random() * 3)],
  }));
  const [part, setPart] = useState("resistor");  // resistor | capacitor | diode
  const [flip, setFlip] = useState(false);        // diode orientation
  const [checked, setChecked] = useState(false);

  // Correct: a diode, oriented forward (flip === false = anode to source).
  const pass = part === "diode" && !flip;
  useEffect(() => { if (checked) onResult(pass); }, [checked]);

  const scenarioText = {
    solar: { a: "a solar panel", b: "the battery it charges", why: "at night the battery would drain backward into the dark panel" },
    battery: { a: "a backup battery", b: "your circuit", why: "you don't want current sneaking back into the battery" },
    usb: { a: "a USB port", b: "your gadget", why: "plugging in backward could push current the wrong way" },
  }[params.scenario];

  return (
    <div className="brief">
      <div className="brief-spec">
        <div className="brief-tag">Brief 5 · {kids ? "The One-Way Gate" : "The Diode"}</div>
        <h3>{kids ? "Let current flow one way only." : "Block the backflow."}</h3>
        <p>
          {kids
            ? <>You're connecting {scenarioText.a} to {scenarioText.b}. Current should flow <b>only forward</b> — because {scenarioText.why}. Which part lets flow go one way and blocks the other? And which way should it face?</>
            : <>Connecting {scenarioText.a} to {scenarioText.b}: current must pass <b>forward only</b> ({scenarioText.why}). Choose the component <em>and</em> its orientation.</>}
        </p>
      </div>

      <div className="brief-stage">
        <DiodeBriefDiagram part={part} flip={flip} kids={kids} />
        <div className="brief-controls">
          <div style={{ display: "flex", flexDirection: "column", gap: 8, marginBottom: 12 }}>
            <span style={{ fontFamily: "'IBM Plex Mono', monospace", fontSize: 11, letterSpacing: "0.12em", textTransform: "uppercase", color: "var(--ink-soft)" }}>
              {kids ? "Pick a part" : "Component"}
            </span>
            {[
              { id: "resistor", label: kids ? "A resistor (pinch)" : "A resistor" },
              { id: "capacitor", label: kids ? "A capacitor (bucket)" : "A capacitor" },
              { id: "diode", label: kids ? "A diode (one-way gate)" : "A diode" },
            ].map(o => (
              <button key={o.id} onClick={() => { setPart(o.id); setChecked(false); }}
                className={`brief-choice ${part === o.id ? "sel" : ""}`}>{o.label}</button>
            ))}
          </div>
          <button className="brief-toggle" onClick={() => { setFlip(f => !f); setChecked(false); }}>
            Facing: <b>{flip ? "◁ backward (anode to load)" : "▷ forward (anode to source)"}</b> — tap to flip
          </button>
          <button className="brief-check" onClick={() => setChecked(true)}>
            {kids ? "Try it!" : "Test the design"}
          </button>
        </div>
      </div>

      {checked && (
        <Verdict state={pass ? "pass" : part === "diode" ? "warn" : "fail"}>
          {part === "diode" && !flip && (kids
            ? <><b>Perfect!</b> The diode is a one-way gate, facing the right way — forward flow passes, backflow is blocked.</>
            : <><b>Correct.</b> A forward-biased diode (anode toward the source) conducts one way and blocks reverse. Exactly what's needed.</>)}
          {part === "diode" && flip && (kids
            ? <><b>Right part, wrong way!</b> Flip the diode around — facing this way it blocks the flow you actually want.</>
            : <><b>Right component, reversed.</b> Backward, the diode blocks the forward current you need. Flip it: anode to the source.</>)}
          {part === "resistor" && (kids
            ? <><b>Nope.</b> A resistor pinches flow in <em>both</em> directions — it can't tell forward from backward.</>
            : <><b>No.</b> A resistor limits current symmetrically; it has no sense of direction. You need a diode.</>)}
          {part === "capacitor" && (kids
            ? <><b>Not this time.</b> A bucket stores and releases — it doesn't block a direction.</>
            : <><b>No.</b> A capacitor blocks steady (DC) current and passes changes, but doesn't enforce direction. The diode does.</>)}
        </Verdict>
      )}
    </div>
  );
}

function DiodeBriefDiagram({ part, flip, kids }) {
  const W = 460, H = 230;
  const blocks = part === "diode" && flip;
  const flows = (part === "diode" && !flip) || part === "resistor";
  const loop = "M 70 70 L 390 70 L 390 170 L 70 170 Z";
  const period = flows ? "1.3s" : "9999s";
  return (
    <svg viewBox={`0 0 ${W} ${H}`} width="100%" height="auto" style={{ maxHeight: 220 }}>
      <path d={loop} fill="none" stroke="var(--ink)" strokeWidth="2.5" strokeLinecap="round" />
      {/* source */}
      <line x1="56" y1="108" x2="84" y2="108" stroke="var(--ink)" strokeWidth="3" />
      <line x1="63" y1="132" x2="77" y2="132" stroke="var(--ink)" strokeWidth="3" />
      <text x="40" y="124" fontFamily="IBM Plex Mono, monospace" fontSize="16" fill="var(--water)" textAnchor="middle">src</text>
      {/* component in the top wire */}
      <g transform="translate(230 70)">
        {part === "resistor" && <rect x="-34" y="-12" width="68" height="24" rx="2" fill="var(--bg-card)" stroke="var(--ink)" strokeWidth="2.5" />}
        {part === "capacitor" && <g stroke="var(--ink)" strokeWidth="4"><line x1="-6" y1="-16" x2="-6" y2="16" /><line x1="8" y1="-16" x2="8" y2="16" /></g>}
        {part === "diode" && (
          <g transform={flip ? "scale(-1,1)" : ""}>
            <polygon points="-16,-14 -16,14 14,0" fill={blocks ? "var(--bg-card)" : "var(--current-deep)"} stroke="var(--ink)" strokeWidth="2.5" />
            <line x1="14" y1="-14" x2="14" y2="14" stroke="var(--ink)" strokeWidth="3" />
          </g>
        )}
      </g>
      <text x="230" y="44" fontFamily="IBM Plex Mono, monospace" fontSize="15" fill="var(--ink-faint)" textAnchor="middle">
        {part === "diode" ? (flip ? "blocking ✕" : "one-way ▷") : part}
      </text>
      {/* electrons */}
      {flows && [0, 1, 2, 3].map(i => (
        <circle key={i} r="4" fill="var(--current)">
          <animateMotion path={loop} dur={period} begin={`-${i * 0.32}s`} repeatCount="indefinite" />
        </circle>
      ))}
      <text x="230" y="200" fontFamily="IBM Plex Mono, monospace" fontSize="16"
            fill={flows ? "var(--current)" : "var(--ink-faint)"} textAnchor="middle">
        {blocks ? "blocked — no flow" : flows ? "current flowing" : "no flow"}
      </text>
    </svg>
  );
}

/* ═══════════════════════════════════════════════════════════════════════
   BRIEF 6 — Inductor: smooth a bumpy current / resist sudden change.
   ═══════════════════════════════════════════════════════════════════════ */
function BriefInductor({ kids, onResult }) {
  const [params] = useState(() => ({
    goal: ["smooth", "spike"][Math.floor(Math.random() * 2)],
  }));
  const [part, setPart] = useState("resistor"); // resistor | capacitor | inductor
  const [checked, setChecked] = useState(false);

  const pass = part === "inductor";
  useEffect(() => { if (checked) onResult(pass); }, [checked]);

  const prompt = params.goal === "smooth"
    ? { k: <>The current to your motor is <b>jumpy</b> — it surges and dips. You want to <b>smooth out the bumps</b> so the flow stays steady. Which part fights sudden <em>changes in flow</em>?</>,
        a: <>A load draws a <b>bumpy current</b>. You need to <b>smooth the current</b> (resist sudden changes in flow), keeping it steady through dips. Which component?</> }
    : { k: <>When you switch a motor off, the current tries to <b>stop instantly</b> and makes a nasty spike. Which part <b>resists the sudden change</b> and carries the flow through the gap?</>,
        a: <>Switching off an inductive load creates a current spike. You need a component that <b>opposes sudden current change</b>, carrying flow smoothly through transitions. Which one?</> };

  return (
    <div className="brief">
      <div className="brief-spec">
        <div className="brief-tag">Brief 6 · {kids ? "The Flywheel" : "The Inductor"}</div>
        <h3>{kids ? "Keep the flow steady." : "Resist the sudden change in current."}</h3>
        <p>{kids ? prompt.k : prompt.a}</p>
        {!kids && (
          <p className="brief-hint">
            Hint: a capacitor resists changes in <em>voltage</em>; its mirror resists changes in <em>current</em>.
          </p>
        )}
      </div>

      <div className="brief-stage">
        <InductorBriefDiagram part={part} kids={kids} />
        <div className="brief-controls">
          <div style={{ display: "flex", flexDirection: "column", gap: 8, marginBottom: 12 }}>
            <span style={{ fontFamily: "'IBM Plex Mono', monospace", fontSize: 11, letterSpacing: "0.12em", textTransform: "uppercase", color: "var(--ink-soft)" }}>
              {kids ? "Pick a part" : "Component"}
            </span>
            {[
              { id: "resistor", label: kids ? "A resistor (pinch)" : "A resistor" },
              { id: "capacitor", label: kids ? "A capacitor (bucket)" : "A capacitor" },
              { id: "inductor", label: kids ? "An inductor (flywheel)" : "An inductor" },
            ].map(o => (
              <button key={o.id} onClick={() => { setPart(o.id); setChecked(false); }}
                className={`brief-choice ${part === o.id ? "sel" : ""}`}>{o.label}</button>
            ))}
          </div>
          <button className="brief-check" onClick={() => setChecked(true)}>
            {kids ? "Try it!" : "Test the design"}
          </button>
        </div>
      </div>

      {checked && (
        <Verdict state={pass ? "pass" : "fail"}>
          {part === "inductor" && (kids
            ? <><b>Yes!</b> The inductor is a flywheel for current — heavy to speed up, heavy to slow down. It smooths the bumps and carries flow through gaps.</>
            : <><b>Correct.</b> An inductor opposes changes in current (it stores energy in a magnetic field), smoothing surges and carrying current through switching gaps.</>)}
          {part === "capacitor" && (kids
            ? <><b>Close — wrong twin!</b> The bucket smooths the <em>push</em> (voltage), not the <em>flow</em>. You want its mirror: the flywheel.</>
            : <><b>Not quite.</b> A capacitor smooths <em>voltage</em>. Its mirror — the inductor — is what smooths <em>current</em>.</>)}
          {part === "resistor" && (kids
            ? <><b>Nope.</b> A resistor just pinches flow and makes heat — it can't store momentum.</>
            : <><b>No.</b> A resistor only dissipates energy; it has no memory of current. The inductor does.</>)}
        </Verdict>
      )}
    </div>
  );
}

function InductorBriefDiagram({ part, kids }) {
  const W = 460, H = 230;
  const smooth = part === "inductor";
  // a wavy input line; output is smoothed only for inductor
  const inPts = Array.from({ length: 60 }, (_, i) => {
    const x = 60 + i * 5.5;
    const y = 80 + Math.sin(i * 0.8) * 18 + (i % 7 === 0 ? 10 : 0);
    return `${x},${y}`;
  }).join(" ");
  const outPts = Array.from({ length: 60 }, (_, i) => {
    const x = 60 + i * 5.5;
    const base = 160;
    const y = smooth ? base + Math.sin(i * 0.8) * 3
            : part === "capacitor" ? base + Math.sin(i * 0.8) * 14
            : base + Math.sin(i * 0.8) * 18 + (i % 7 === 0 ? 10 : 0);
    return `${x},${y}`;
  }).join(" ");
  return (
    <svg viewBox={`0 0 ${W} ${H}`} width="100%" height="auto" style={{ maxHeight: 220 }}>
      <text x="50" y="60" fontFamily="IBM Plex Mono, monospace" fontSize="13.5" fill="var(--ink-faint)">bumpy in</text>
      <polyline points={inPts} fill="none" stroke="var(--ink-faint)" strokeWidth="2" />
      {/* component glyph */}
      <g transform="translate(210 120)">
        {part === "resistor" && <rect x="-30" y="-12" width="60" height="24" rx="2" fill="var(--bg-card)" stroke="var(--ink)" strokeWidth="2.5" />}
        {part === "capacitor" && <g stroke="var(--ink)" strokeWidth="4"><line x1="-6" y1="-15" x2="-6" y2="15" /><line x1="8" y1="-15" x2="8" y2="15" /></g>}
        {part === "inductor" && (
          <g fill="none" stroke="var(--ink)" strokeWidth="2.5">
            <path d="M -30 0 q 7 -14 15 0 q 7 -14 15 0 q 7 -14 15 0" />
          </g>
        )}
      </g>
      <text x="210" y="150" fontFamily="IBM Plex Mono, monospace" fontSize="13.5" fill="var(--ink-faint)" textAnchor="middle">{part}</text>
      <text x="50" y="200" fontFamily="IBM Plex Mono, monospace" fontSize="13.5"
            fill={smooth ? "var(--current)" : "var(--ink-faint)"}>{smooth ? "smooth out ✓" : "still bumpy"}</text>
      <polyline points={outPts} fill="none" stroke={smooth ? "var(--current)" : "var(--ink-soft)"} strokeWidth="2.5" />
    </svg>
  );
}

Object.assign(window, { BriefLED, BriefDivider, BriefRC, BriefTransistor,
                        BriefDiode, BriefInductor, E12, ohmLabel });
