// game.jsx — Round + Results screens; main App container.
// Globals: React, AlgebraQuestions, AlgebraSprites, __algebraScreens, Tweaks helpers.

const { useState: gUseState, useEffect: gUseEffect, useRef: gUseRef, useMemo: gUseMemo, useCallback: gUseCallback } = React;
const { TitleScreen, TopicSelect, ProfileSelectScreen, NewProfileScreen, ChunkyButton, PixelText, HpBar, Hearts, sfx, THEMES } = window.__algebraScreens;
const { PixelSprite, PixelBurst, MONSTER_ORDER, MONSTER_HP, MONSTER_NAMES } = window.AlgebraSprites;
const { generate: genQ, TOPICS } = window.AlgebraQuestions;

// ─── Tone-of-voice strings ─────────────────────────────────
const VOICE = {
  hype: {
    correctOpen: ["NICE!","BOOM!","CRITICAL HIT!","KAPOW!","SOLID!","SLICK!"],
    streak: ["x{n} COMBO!","ON FIRE!","UNSTOPPABLE!","CHAIN!","WAY TO GO!"],
    wrongOpen: ["MISSED!","OOF!","SHAKE IT OFF!","CLOSE!","TRY AGAIN!"],
    win: "STAGE CLEAR!",
    lose: "GAME OVER",
  },
  coach: {
    correctOpen: ["Great work.","Got it.","That's right.","Well done.","Exactly."],
    streak: ["{n} in a row!","Streak of {n}.","Keep it going.","Building momentum."],
    wrongOpen: ["Not quite.","Almost.","Let's try again.","Take another look."],
    win: "Round complete.",
    lose: "Round ended.",
  },
  silly: {
    correctOpen: ["YASSS!","BIG BRAIN!","GALAXY MIND!","🧠 unlocked!","CERTIFIED smart!"],
    streak: ["{n}× SILLY STREAK!","math goblin defeated x{n}","BIGGER BRAIN!","u r built different"],
    wrongOpen: ["whoopsie","my bad my bad","skill issue (mine)","the pixels lied","try try try"],
    win: "VICTORY DANCE TIME",
    lose: "the math won this round",
  },
};

// ─── Bobbing CSS keyframe (injected once) ──────────────────
function injectAnims() {
  if (document.getElementById("__alg_anim")) return;
  const s = document.createElement("style");
  s.id = "__alg_anim";
  s.textContent = `
    @keyframes bob { 0%,100%{transform:translateY(0)} 50%{transform:translateY(-6px)} }
    @keyframes shake { 0%{transform:translate(0)} 20%{transform:translate(-6px,2px)} 40%{transform:translate(6px,-2px)} 60%{transform:translate(-4px,2px)} 80%{transform:translate(4px,0)} 100%{transform:translate(0)} }
    @keyframes flash { 0%,100%{filter:brightness(1)} 50%{filter:brightness(2.5) saturate(2)} }
    @keyframes scanline { 0%{background-position:0 0} 100%{background-position:0 100vh} }
    @keyframes pop { 0%{transform:scale(0.4);opacity:0} 50%{transform:scale(1.2);opacity:1} 100%{transform:scale(1);opacity:1} }
    @keyframes tickerIn { 0%{transform:translateX(-100%)} 100%{transform:translateX(0)} }
    @keyframes blink { 0%,49%{opacity:1} 50%,100%{opacity:0.15} }
    @keyframes burstFade { 0%{opacity:1; transform:translate(-50%,-50%) scale(0.6)} 60%{opacity:1; transform:translate(-50%,-50%) scale(1.4)} 100%{opacity:0; transform:translate(-50%,-50%) scale(1.8)} }
    @keyframes risefade { 0%{opacity:0; transform:translate(-50%,0)} 20%{opacity:1} 100%{opacity:0; transform:translate(-50%,-40px)} }
    @keyframes timerPulse { 0%,100%{color:var(--c)} 50%{color:#fff} }
  `;
  document.head.appendChild(s);
}

// ─── Round screen ──────────────────────────────────────────
function RoundScreen({ theme, topicId, voice, sound, hintOn, timerOn, startLevel, onEnd, onExit }) {
  const [waveIdx, setWaveIdx] = gUseState(0);
  const [monsterHp, setMonsterHp] = gUseState(MONSTER_HP[MONSTER_ORDER[0]]);
  const [hearts, setHearts] = gUseState(3);
  const [score, setScore] = gUseState(0);
  const [combo, setCombo] = gUseState(0);
  const [maxCombo, setMaxCombo] = gUseState(0);
  const [time, setTime] = gUseState(timerOn ? 120 : 999);
  const [level, setLevel] = gUseState(startLevel);
  const [q, setQ] = gUseState(null);
  const [reveal, setReveal] = gUseState(null); // { kind: 'right' | 'wrong', picked }
  const [shaking, setShaking] = gUseState(false);
  const [floats, setFloats] = gUseState([]); // floating "+100" texts
  const [burst, setBurst] = gUseState(false);
  const [hintShown, setHintShown] = gUseState(false);
  const [coach, setCoach] = gUseState({ text: "", kind: "" });
  const [stats, setStats] = gUseState({ correct: 0, total: 0, perTopic: {} });
  const acc = gUseRef({ rolling: [] }); // last 5 results
  const floatId = gUseRef(0);

  // pick a topic
  const nextTopic = gUseCallback(() => {
    if (topicId !== "ALL") return topicId;
    return MONSTER_ORDER /* unused */ && TOPICS[Math.floor(Math.random() * TOPICS.length)].id;
  }, [topicId]);

  // generate next question
  const nextQ = gUseCallback(() => {
    setQ(genQ(nextTopic(), level));
    setReveal(null);
    setHintShown(false);
  }, [nextTopic, level]);

  // mount: first question + ticking
  gUseEffect(() => { nextQ(); }, []);
  gUseEffect(() => {
    if (!timerOn) return;
    if (time <= 0) { handleEnd("time"); return; }
    const t = setTimeout(() => setTime(s => s - 1), 1000);
    return () => clearTimeout(t);
  }, [time, timerOn]);

  // adapt difficulty by recent accuracy
  const adapt = (correct) => {
    const r = [...acc.current.rolling, correct].slice(-5);
    acc.current.rolling = r;
    if (r.length >= 4) {
      const rate = r.filter(Boolean).length / r.length;
      if (rate >= 0.8 && level < 5) { setLevel(l => Math.min(5, l + 1)); acc.current.rolling = []; }
      else if (rate <= 0.4 && level > 1) { setLevel(l => Math.max(1, l - 1)); acc.current.rolling = []; }
    }
  };

  const popFloat = (text, color) => {
    const id = ++floatId.current;
    setFloats(f => [...f, { id, text, color }]);
    setTimeout(() => setFloats(f => f.filter(x => x.id !== id)), 1200);
  };

  const showCoach = (text, kind) => {
    setCoach({ text, kind });
    setTimeout(() => setCoach(c => (c.text === text ? { text:"", kind:"" } : c)), 1600);
  };

  const handlePick = (choice) => {
    if (reveal || !q) return;
    const right = choice === q.answer;
    setStats(s => {
      const pt = { ...s.perTopic, [q.topic]: { ...(s.perTopic[q.topic] || { c:0, t:0 }) } };
      pt[q.topic].t++; if (right) pt[q.topic].c++;
      return { correct: s.correct + (right ? 1 : 0), total: s.total + 1, perTopic: pt };
    });
    if (right) {
      const newCombo = combo + 1;
      const mult = Math.min(5, 1 + Math.floor(newCombo / 3));
      const gained = 100 * mult * level;
      setCombo(newCombo); setMaxCombo(c => Math.max(c, newCombo));
      setScore(s => s + gained);
      setReveal({ kind: "right", picked: choice });
      sfx.correct(sound);
      popFloat(`+${gained}`, theme.warn);
      if (newCombo >= 3) {
        sfx.combo(sound, newCombo);
        const tpl = pickFrom(VOICE[voice].streak);
        showCoach(tpl.replace("{n}", newCombo), "good");
      } else {
        showCoach(pickFrom(VOICE[voice].correctOpen), "good");
      }
      // damage monster
      setMonsterHp(hp => {
        const next = hp - mult;
        if (next <= 0) {
          setBurst(true);
          sfx.explode(sound);
          setTimeout(() => setBurst(false), 600);
          // advance wave
          setTimeout(() => {
            const nw = waveIdx + 1;
            if (nw >= MONSTER_ORDER.length) {
              handleEnd("clear");
              return;
            }
            setWaveIdx(nw);
            setMonsterHp(MONSTER_HP[MONSTER_ORDER[nw]]);
            nextQ();
          }, 700);
          return 0;
        }
        return next;
      });
      adapt(true);
      if (monsterHp - mult > 0) setTimeout(() => nextQ(), 750);
    } else {
      setCombo(0);
      setReveal({ kind: "wrong", picked: choice });
      setShaking(true);
      sfx.wrong(sound);
      showCoach(pickFrom(VOICE[voice].wrongOpen), "bad");
      setTimeout(() => setShaking(false), 400);
      setHearts(h => {
        const nh = h - 1;
        if (nh <= 0) { setTimeout(() => handleEnd("dead"), 900); }
        return nh;
      });
      adapt(false);
      setTimeout(() => nextQ(), 1500);
    }
  };

  const handleEnd = (reason) => {
    onEnd({ reason, score, hearts, maxCombo, stats, time, finalLevel: level });
  };

  const monster = MONSTER_ORDER[waveIdx];
  const monsterMaxHp = MONSTER_HP[monster];
  const timerColor = time <= 10 ? theme.danger : time <= 30 ? theme.warn : theme.text;

  return (
    <div style={{ height: "100%", display: "flex", flexDirection: "column", padding: 18, gap: 14, position:"relative" }}>
      {/* HUD */}
      <div style={{ display: "grid", gridTemplateColumns: "1fr auto 1fr", alignItems:"center", gap: 16, borderBottom: `3px solid ${theme.accent}`, paddingBottom: 12 }}>
        <div style={{ display:"flex", flexDirection:"column", gap: 4 }}>
          <PixelText size={9} color={theme.dim}>SCORE</PixelText>
          <PixelText size={20} color={theme.accent}>{String(score).padStart(6, "0")}</PixelText>
        </div>
        <div style={{ display:"flex", flexDirection:"column", alignItems:"center", gap: 4 }}>
          <PixelText size={9} color={theme.dim}>WAVE {waveIdx + 1}/{MONSTER_ORDER.length} · LV{level}</PixelText>
          <div style={{ display:"flex", gap: 8, alignItems:"center" }}>
            <Hearts n={hearts} />
            <PixelText size={9} color={theme.dim} style={{ margin: "0 8px" }}>·</PixelText>
            <div style={{ display:"flex", gap: 4, alignItems:"center" }}>
              <PixelText size={11} color={theme.warn}>x{combo}</PixelText>
              {combo >= 3 && <PixelSprite name="star" scale={2} />}
            </div>
          </div>
        </div>
        <div style={{ display:"flex", flexDirection:"column", alignItems:"flex-end", gap: 4 }}>
          <PixelText size={9} color={theme.dim}>{timerOn ? "TIME" : "MODE"}</PixelText>
          <PixelText size={20} color={timerColor} style={{ "--c": timerColor, animation: timerOn && time <= 10 ? "timerPulse 0.5s steps(2) infinite" : "none" }}>
            {timerOn ? formatTime(time) : "ZEN"}
          </PixelText>
        </div>
      </div>

      {/* Monster + question */}
      <div style={{ flex: 1, display:"grid", gridTemplateColumns: "260px 1fr", gap: 24, alignItems:"center", minHeight: 0 }}>
        <div style={{ display:"flex", flexDirection:"column", alignItems:"center", gap: 10, position:"relative" }}>
          <PixelText size={11} color={theme.accent2}>WAVE {waveIdx + 1}</PixelText>
          <PixelText size={14} color={theme.text}>{MONSTER_NAMES[monster]}</PixelText>
          <div style={{
            position:"relative",
            animation: shaking ? "shake .35s steps(3)" : reveal?.kind==="right" ? "flash .3s steps(2)" : "bob 1.6s steps(2) infinite",
          }}>
            {monsterHp > 0 && <PixelSprite name={monster} scale={7} />}
            {burst && (
              <div style={{ position:"absolute", left:"50%", top:"50%", animation:"burstFade .6s steps(4) forwards" }}>
                <PixelBurst scale={8} color={theme.warn} color2={theme.accent2} />
              </div>
            )}
          </div>
          <HpBar value={monsterHp} max={monsterMaxHp} color={theme.danger} bg={theme.accent} />
        </div>

        <div style={{ display:"flex", flexDirection:"column", gap: 18, minHeight: 0 }}>
          {/* equation */}
          <div style={{
            background: theme.panel,
            border: `3px solid ${theme.accent}`,
            padding: "26px 22px",
            boxShadow: `6px 6px 0 ${theme.accent2}`,
            position: "relative",
          }}>
            <PixelText size={9} color={theme.dim} style={{ position:"absolute", top: 8, left: 12 }}>
              ▶ {topicLabel(q?.topic)}
            </PixelText>
            <div style={{ marginTop: 8 }}>
              <span style={{ fontFamily: '"VT323", monospace', fontSize: 48, color: theme.text, textShadow: `2px 2px 0 ${theme.bg}` }}>
                {q?.prompt || "—"}
              </span>
            </div>
            {hintOn && q && (
              <button
                onClick={() => { sfx.click(sound); setHintShown(true); }}
                disabled={hintShown}
                style={{
                  position:"absolute", top: 6, right: 8,
                  background:"transparent", border: `2px solid ${theme.warn}`,
                  color: theme.warn, padding: "4px 8px",
                  fontFamily:'"Press Start 2P", monospace', fontSize: 9,
                  cursor: hintShown ? "default" : "pointer",
                  opacity: hintShown ? 0.4 : 1,
                }}
              >? HINT</button>
            )}
            {hintShown && q && (
              <div style={{ marginTop: 10, fontFamily:'"VT323", monospace', fontSize: 22, color: theme.warn }}>
                💡 {q.hint}
              </div>
            )}
          </div>

          {/* coach line / floating score */}
          <div style={{ height: 28, display:"flex", alignItems:"center", justifyContent:"center", position:"relative" }}>
            {coach.text && (
              <PixelText size={14} color={coach.kind === "good" ? theme.warn : theme.danger}
                style={{ animation: "pop .25s steps(3)", textShadow: `2px 2px 0 ${theme.bg}` }}>
                {coach.text}
              </PixelText>
            )}
            {floats.map(f => (
              <div key={f.id} style={{
                position:"absolute", left:"50%", top:0,
                fontFamily:'"Press Start 2P", monospace', fontSize: 16,
                color: f.color, animation:"risefade 1.1s steps(8) forwards",
                textShadow:`2px 2px 0 ${theme.bg}`,
              }}>{f.text}</div>
            ))}
          </div>

          {/* answer tiles */}
          <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }}>
            {q?.choices.map((c, i) => {
              const isRight = reveal && c === q.answer;
              const isPicked = reveal && reveal.picked === c;
              const wrongPick = reveal?.kind === "wrong" && isPicked;
              const bg = isRight ? theme.accent : wrongPick ? theme.danger : theme.panel;
              const fg = isRight || wrongPick ? theme.bg : theme.text;
              const bd = reveal ? (isRight ? theme.warn : wrongPick ? theme.warn : theme.dim) : theme.accent;
              return (
                <button key={i}
                  disabled={!!reveal}
                  onClick={() => handlePick(c)}
                  onMouseEnter={() => sfx.hover(sound)}
                  style={{
                    background: bg, color: fg, border: `3px solid ${bd}`,
                    fontFamily: '"VT323", monospace', fontSize: 30,
                    padding: "16px 18px", textAlign: "left",
                    cursor: reveal ? "default" : "pointer",
                    boxShadow: reveal ? "none" : `4px 4px 0 ${theme.accent2}`,
                    display: "flex", alignItems: "center", gap: 14,
                    transition:"transform 80ms steps(2)",
                    transform: isPicked ? "translate(4px,4px)" : "none",
                  }}
                >
                  <span style={{ fontFamily:'"Press Start 2P", monospace', fontSize: 13, color: isRight || wrongPick ? theme.bg : theme.accent }}>
                    {String.fromCharCode(65 + i)}
                  </span>
                  <span>{c}</span>
                  {isRight && <span style={{ marginLeft:"auto", fontSize: 22 }}>✓</span>}
                  {wrongPick && <span style={{ marginLeft:"auto", fontSize: 22 }}>✗</span>}
                </button>
              );
            })}
          </div>
        </div>
      </div>

      {/* exit */}
      <div style={{ position:"absolute", bottom: 14, right: 18 }}>
        <button onClick={() => { sfx.click(sound); onExit(); }} style={{
          background:"transparent", border:`2px solid ${theme.dim}`, color: theme.dim,
          fontFamily:'"Press Start 2P", monospace', fontSize: 9, padding:"4px 8px", cursor:"pointer",
        }}>QUIT</button>
      </div>
    </div>
  );
}

// ─── Results screen ────────────────────────────────────────
function ResultsScreen({ theme, voice, result, onAgain, onHome, sound, prevHi, gain }) {
  const win = result.reason === "clear";
  gUseEffect(() => { (win ? sfx.win : sfx.lose)(sound); }, []);
  const acc = result.stats.total ? Math.round(100 * result.stats.correct / result.stats.total) : 0;
  return (
    <div style={{ display:"flex", flexDirection:"column", alignItems:"center", justifyContent:"center", height:"100%", gap: 22 }}>
      <PixelText size={14} color={theme.accent2}>{win ? "★ ★ ★" : "▼ ▼ ▼"}</PixelText>
      <PixelText size={42} color={win ? theme.accent : theme.danger}
        style={{ textShadow: `4px 4px 0 ${theme.bg}` }}>
        {VOICE[voice][win ? "win" : "lose"].toUpperCase()}
      </PixelText>

      <div style={{ display:"grid", gridTemplateColumns:"auto auto", gap: "10px 28px", marginTop: 6, padding: "20px 28px", border:`3px solid ${theme.accent}`, background: theme.panel, boxShadow:`6px 6px 0 ${theme.accent2}` }}>
        <PixelText size={11} color={theme.dim}>SCORE</PixelText>
        <PixelText size={16} color={theme.warn}>{String(result.score).padStart(6,"0")}</PixelText>
        <PixelText size={11} color={theme.dim}>HI-SCORE</PixelText>
        <PixelText size={16} color={theme.text}>{String(Math.max(prevHi, result.score)).padStart(6,"0")} {result.score > prevHi && <span style={{ color: theme.accent }}>NEW!</span>}</PixelText>
        <PixelText size={11} color={theme.dim}>ACCURACY</PixelText>
        <PixelText size={16} color={theme.accent}>{acc}% ({result.stats.correct}/{result.stats.total})</PixelText>
        <PixelText size={11} color={theme.dim}>BEST COMBO</PixelText>
        <PixelText size={16} color={theme.accent2}>x{result.maxCombo}</PixelText>
        <PixelText size={11} color={theme.dim}>HEARTS LEFT</PixelText>
        <div><Hearts n={result.hearts} /></div>
        <PixelText size={11} color={theme.dim}>FINAL LEVEL</PixelText>
        <PixelText size={16} color={theme.warn}>LV {result.finalLevel}</PixelText>
      </div>

      <div style={{ display:"flex", gap: 12, alignItems:"center" }}>
        <PixelSprite name="star" scale={3} />
        <PixelText size={14} color={theme.warn}>+{gain.xp} XP · +${gain.coins}</PixelText>
        <PixelSprite name="star" scale={3} />
      </div>

      <div style={{ display:"flex", gap: 14, marginTop: 8 }}>
        <ChunkyButton onClick={onAgain} color={theme.accent} fg={theme.bg} sound={sound}>PLAY AGAIN</ChunkyButton>
        <ChunkyButton onClick={onHome} color={theme.panel} fg={theme.text} sound={sound}>HOME</ChunkyButton>
      </div>
    </div>
  );
}

// ─── helpers ───────────────────────────────────────────────
const formatTime = (t) => {
  const m = Math.floor(t / 60); const s = t % 60;
  return `${m}:${String(s).padStart(2, "0")}`;
};
const pickFrom = (a) => a[Math.floor(Math.random() * a.length)];
const topicLabel = (id) => {
  const t = TOPICS.find(t => t.id === id);
  return t ? t.name : "—";
};

// ─── App ───────────────────────────────────────────────────
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "theme": "neon",
  "sound": true,
  "timer": true,
  "hints": true,
  "voice": "hype",
  "difficulty": "adaptive",
  "topics": ["one-step","two-step","like-terms","distributive","evaluate","inequality","slope","systems"]
}/*EDITMODE-END*/;

function App() {
  injectAnims();
  const [t, setT] = useTweaks(TWEAK_DEFAULTS);
  const theme = THEMES[t.theme] || THEMES.neon;

  const P = window.AlgebraProfiles;

  // profile state + a tick to force re-reads after writes
  const [, setTick] = gUseState(0);
  const bump = () => setTick(n => n + 1);

  const profiles = P.list();
  const activeId = P.activeId();
  const profile = P.active();

  // initial screen — go straight to onboarding if no profiles yet
  const initialScreen = profiles.length === 0 ? "newProfile" : "title";
  const [screen, setScreen] = gUseState(initialScreen);
  const [topicId, setTopicId] = gUseState("ALL");
  const [result, setResult] = gUseState(null);
  const [lastGain, setLastGain] = gUseState({ xp: 0, coins: 0 });
  const [prevHi, setPrevHi] = gUseState(0);

  const startLevel = t.difficulty === "easy" ? 1 : t.difficulty === "hard" ? 4 : 2;

  // background scanline overlay
  const wrapStyle = {
    position: "fixed", inset: 0, background: theme.bg,
    fontFamily: '"Press Start 2P", monospace', color: theme.text,
    overflow: "hidden", display: "flex", alignItems:"center", justifyContent:"center",
  };
  const innerStyle = {
    width: "min(1200px, 96vw)", height: "min(800px, 92vh)",
    background: theme.bg, position:"relative",
    border: `4px solid ${theme.accent}`,
    boxShadow: `0 0 0 4px ${theme.bg}, 0 0 0 7px ${theme.accent2}, 0 0 60px ${theme.accent}33`,
    imageRendering:"pixelated",
  };

  const beginRound = () => {
    if (!profile) { setScreen("newProfile"); return; }
    setPrevHi(profile.hi || 0);
    sfx.start(t.sound);
    setScreen("select");
  };

  return (
    <div style={wrapStyle}>
      {/* CRT scanlines + vignette */}
      <div style={{ pointerEvents:"none", position:"fixed", inset: 0, zIndex: 50,
        background: "repeating-linear-gradient(transparent 0 2px, rgba(0,0,0,.18) 2px 3px)",
        mixBlendMode:"multiply" }} />
      <div style={{ pointerEvents:"none", position:"fixed", inset: 0, zIndex: 51,
        background:`radial-gradient(circle at 50% 50%, transparent 55%, rgba(0,0,0,.55) 100%)` }} />

      <div style={innerStyle}>
        {screen === "title" && profile && (
          <TitleScreen theme={theme} profile={profile}
            leaderboard={P.leaderboard(5)} sound={t.sound}
            onStart={beginRound}
            onSwitchPlayer={() => setScreen("profiles")} />
        )}
        {screen === "profiles" && (
          <ProfileSelectScreen theme={theme} sound={t.sound}
            profiles={profiles} activeId={activeId}
            onPick={(id) => { P.setActive(id); bump(); setScreen("title"); }}
            onNew={() => setScreen("newProfile")}
            onDelete={(id) => { P.remove(id); bump(); if (P.list().length === 0) setScreen("newProfile"); }}
            onRename={(id, name) => { P.rename(id, name); bump(); }} />
        )}
        {screen === "newProfile" && (
          <NewProfileScreen theme={theme} sound={t.sound}
            canBack={profiles.length > 0}
            onCreate={(name, avatar) => { P.create(name, avatar); bump(); setScreen("title"); }}
            onBack={() => setScreen(profiles.length ? "profiles" : "title")} />
        )}
        {screen === "select" && (
          <TopicSelect theme={theme} allowed={t.topics} sound={t.sound}
            onPick={(id) => { setTopicId(id); setScreen("round"); }}
            onBack={() => setScreen("title")} />
        )}
        {screen === "round" && (
          <RoundScreen
            theme={theme} topicId={topicId} voice={t.voice} sound={t.sound}
            hintOn={t.hints} timerOn={t.timer} startLevel={startLevel}
            onEnd={(r) => {
              const { gain } = P.applyRound(activeId, r);
              setLastGain(gain);
              bump();
              setResult(r); setScreen("results");
            }}
            onExit={() => setScreen("title")}
          />
        )}
        {screen === "results" && result && profile && (
          <ResultsScreen theme={theme} voice={t.voice} result={result} sound={t.sound}
            prevHi={prevHi}
            gain={lastGain}
            onAgain={() => setScreen("round")}
            onHome={() => setScreen("title")} />
        )}
      </div>

      <TweaksPanel title="Tweaks">
        <TweakSection label="Look" />
        <TweakColor
          label="Theme"
          value={theme.accent}
          options={[THEMES.neon.accent, THEMES.gameboy.accent, THEMES.pinkpop.accent, THEMES.amber.accent]}
          onChange={(v) => {
            const k = Object.keys(THEMES).find(k => THEMES[k].accent === v) || "neon";
            setT("theme", k);
          }}
        />
        <PixelText size={9} color="#888" style={{ marginTop: -4 }}>{theme.name}</PixelText>

        <TweakSection label="Game" />
        <TweakRadio label="Difficulty" value={t.difficulty}
          options={["easy","adaptive","hard"]}
          onChange={(v) => setT("difficulty", v)} />
        <TweakToggle label="Timer" value={t.timer} onChange={(v) => setT("timer", v)} />
        <TweakToggle label="Hints" value={t.hints} onChange={(v) => setT("hints", v)} />
        <TweakToggle label="Sound" value={t.sound} onChange={(v) => setT("sound", v)} />
        <TweakSelect label="Tone" value={t.voice}
          options={[{value:"hype",label:"Hype coach"},{value:"coach",label:"Calm coach"},{value:"silly",label:"Silly goose"}]}
          onChange={(v) => setT("voice", v)} />

        <TweakSection label="Players" />
        <TweakButton label="Switch / manage players" onClick={() => setScreen("profiles")} />
        {profile && (
          <TweakButton label={`Reset ${profile.name}'s score`} onClick={() => {
            if (confirm(`Reset score, XP, and coins for "${profile.name}"?`)) {
              P.update(profile.id, { hi: 0, xp: 0, level: 1, coins: 0, plays: 0, perTopic: {} });
              bump();
            }
          }} />
        )}

        <TweakSection label="Topics" />
        {TOPICS.map(tp => (
          <TweakToggle key={tp.id} label={tp.name} value={t.topics.includes(tp.id)}
            onChange={(v) => {
              const next = v ? [...new Set([...t.topics, tp.id])]
                            : t.topics.filter(x => x !== tp.id);
              setT("topics", next.length ? next : [tp.id]);
            }} />
        ))}
      </TweaksPanel>
    </div>
  );
}

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