/* Arcade SPA — boot menu, game, cheat-sheet, history, results, settings. */

const HISTORY_KEY = 'cuttle.arcade.history.v1';
const NAME_KEY = 'cuttle.arcade.lastName.v1';
const SETTINGS_KEY = 'cuttle.arcade.settings.v1';
const SEEN_INTRO_KEY = 'cuttle.arcade.seenIntro.v1';
const NEXT_DEALER_KEY = 'cuttle.arcade.nextDealer.v1';
const NAME_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_ ';
const DEFAULT_SETTINGS = { cardHints: true, aiDifficulty: 'EASY' };

// Read the dealer for the next game (1 = AI deals / player goes first;
// 0 = player deals / AI goes first), then flip and persist for the round
// after. Called at the start of every new game so dealer alternates across
// rematches and across page reloads. Default is 1 (matches engine default).
function consumeNextDealer() {
  let d = 1;
  try {
    const raw = localStorage.getItem(NEXT_DEALER_KEY);
    if (raw === '0') d = 0;
  } catch {}
  try { localStorage.setItem(NEXT_DEALER_KEY, d === 0 ? '1' : '0'); } catch {}
  return d;
}

function loadHistory() {
  try { return JSON.parse(localStorage.getItem(HISTORY_KEY) || '[]'); } catch { return []; }
}
function saveHistory(h) { localStorage.setItem(HISTORY_KEY, JSON.stringify(h.slice(-200))); }
function loadLastName() {
  const v = localStorage.getItem(NAME_KEY);
  return (v && v.length === 3 && [...v].every(c => NAME_CHARS.includes(c))) ? v : 'AAA';
}
function loadSettings() {
  try {
    const raw = JSON.parse(localStorage.getItem(SETTINGS_KEY) || 'null');
    return { ...DEFAULT_SETTINGS, ...(raw || {}) };
  } catch { return { ...DEFAULT_SETTINGS }; }
}
function saveSettings(s) { localStorage.setItem(SETTINGS_KEY, JSON.stringify(s)); }

// ─── MENU / ATTRACT SCREEN ───────────────────────────────────────────────────
function MenuScreen({ onNav, history }) {
  const wins = history.filter(h => h.winner === 'player').length;
  const total = history.length;
  const wr = total ? Math.round(100 * wins / total) : 0;

  return (
    <div style={{
      width: '100%', height: '100%', position: 'relative', overflow: 'hidden',
      background: 'radial-gradient(ellipse at 50% 70%, #2a1810 0%, #160c06 55%, #0d0704 100%)',
    }}>
      {/* Felt bleed up from bottom — same green as the game table */}
      <div style={{
        position: 'absolute', bottom: 0, left: 0, right: 0, height: '45%',
        background: 'linear-gradient(to top, #1a4a3a 0%, #0d2a22 55%, transparent 100%)',
        opacity: 0.5,
      }} />
      {/* Brass grid — same accent as the table edge, very faint */}
      <div className="grid-floor" style={{ opacity: 0.14 }} />
      {/* Vertical wood-grain striping */}
      <div style={{
        position: 'absolute', inset: 0, pointerEvents: 'none',
        background: 'repeating-linear-gradient(90deg, transparent 0 72px, rgba(212,166,74,0.025) 72px 73px)',
      }} />

      {/* Wordmark */}
      <div style={{
        position: 'absolute', top: '13%', left: 0, right: 0,
        textAlign: 'center', zIndex: 3,
      }}>
        <div className="wordmark">CUTTLE</div>
        <div style={{
          fontFamily: 'VT323, monospace', fontSize: 24, color: 'var(--ink-dim)',
          marginTop: 6, letterSpacing: '0.4em',
        }}>
          ─── A COMBAT CARD GAME ───
        </div>
      </div>

      {/* Center row: player stats | cuttlefish portrait */}
      <div style={{
        position: 'absolute', top: '50%', left: '50%', transform: 'translate(-50%, 0)',
        display: 'flex', alignItems: 'center', gap: 44,
      }}>
        {/* Player stats — pix-panel wood-grain style */}
        <div style={{
          minWidth: 178, padding: '16px 20px', textAlign: 'right',
          background: 'repeating-linear-gradient(90deg, rgba(0,0,0,0) 0 8px, rgba(0,0,0,0.07) 8px 9px), linear-gradient(180deg, var(--bg-panel-2) 0%, var(--bg-panel) 100%)',
          boxShadow: '0 0 0 2px var(--bg-deep), 0 0 0 4px var(--accent), inset 0 0 0 1px rgba(255,255,255,0.03), inset 0 0 20px rgba(0,0,0,0.35)',
        }}>
          <div style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 10, color: 'var(--ink-dim)', letterSpacing: '0.26em' }}>1P SCORE</div>
          <div style={{ fontFamily: 'VT323, monospace', fontSize: 58, color: 'var(--accent-2)', textShadow: '0 0 12px var(--accent-2)', lineHeight: 1, marginTop: 2 }}>
            {String(wins).padStart(6, '0')}
          </div>
          <div style={{ height: 1, background: 'var(--line-bright)', margin: '8px 0' }} />
          <div style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 10, color: 'var(--ink-dim)', letterSpacing: '0.16em' }}>{total} GAMES</div>
          <div style={{ fontFamily: 'VT323, monospace', fontSize: 28, color: 'var(--accent-3)', lineHeight: 1.1 }}>{wr}% WIN RATE</div>
        </div>

        {/* Cuttlefish — brass bezel matching the table's card-panel treatment */}
        <div style={{
          padding: 14,
          background: 'repeating-linear-gradient(90deg, rgba(0,0,0,0) 0 8px, rgba(0,0,0,0.07) 8px 9px), linear-gradient(180deg, var(--bg-panel-2) 0%, var(--bg-panel) 100%)',
          boxShadow: '0 0 0 3px var(--bg-deep), 0 0 0 6px var(--accent), 10px 10px 0 6px rgba(0,0,0,0.65)',
        }}>
          <PixelCuttlefish mood="smug" size={160} />
        </div>
      </div>

      {/* Buttons */}
      <div style={{
        position: 'absolute', bottom: '13%', left: 0, right: 0,
        display: 'flex', justifyContent: 'center', gap: 20, flexWrap: 'wrap',
      }}>
        <button className="pix-btn primary" onClick={() => onNav('GAME')}>▶ Press Start</button>
        <button className="pix-btn" onClick={() => onNav('RULES')}>How To Play</button>
        <button className="pix-btn" onClick={() => onNav('HISTORY')}>High Scores</button>
        <button className="pix-btn" onClick={() => onNav('SETTINGS')}>Settings</button>
      </div>

      {/* Credits */}
      <div style={{
        position: 'absolute', bottom: 24, left: 0, right: 0, textAlign: 'center',
        fontFamily: 'JetBrains Mono, monospace', fontSize: 11, color: 'var(--ink-dim)',
        letterSpacing: '0.16em',
      }}>
        BY REMO DIVITO · ART: DRAWSGOOD.ITCH.IO · RULES: RICHARD SIPIE
      </div>
    </div>
  );
}

// ─── RULES / CHEAT SHEET ─────────────────────────────────────────────────────
function RulesScreen({ onBack }) {
  // Semantic colour palette — same three colours the table uses for callouts.
  const cyan = '#5fc8b6', mag = '#ff3b8b', yel = '#ffd23f', dim = 'var(--ink-dim)';

  // Card chip — a small playing-card shape with the rank inside, coloured by role.
  const Chip = ({ rank, color }) => (
    <div style={{
      width: 52, height: 70, flexShrink: 0,
      background: 'var(--bg-deep)',
      boxShadow: `0 0 0 2px var(--bg-deep), 0 0 0 4px ${color}, inset 0 0 8px ${color}33`,
      display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center',
      fontFamily: 'VT323, monospace', fontSize: 34, color,
      textShadow: `0 0 8px ${color}`,
      position: 'relative',
    }}>
      {rank}
      {/* suit pip in corner */}
      <div style={{ position: 'absolute', top: 3, left: 5, fontSize: 11, opacity: 0.55, lineHeight: 1 }}>♠</div>
    </div>
  );

  const Row = ({ rank, label, body, color }) => (
    <div style={{
      display: 'grid', gridTemplateColumns: '64px 1fr', gap: 16,
      padding: '12px 16px',
      borderBottom: '1px solid var(--line)',
      alignItems: 'start',
    }}>
      <Chip rank={rank} color={color} />
      <div>
        <div style={{
          fontFamily: 'VT323, monospace', fontSize: 24, color: 'var(--ink)',
          letterSpacing: '0.05em', lineHeight: 1.1,
        }}>
          <span style={{ color, marginRight: 6 }}>▸</span>{label}
        </div>
        <div style={{
          fontFamily: 'JetBrains Mono, monospace', fontSize: 12,
          color: 'var(--ink-dim)', lineHeight: 1.65, marginTop: 5,
        }}>{body}</div>
      </div>
    </div>
  );

  const SectionHead = ({ title, tone }) => (
    <div style={{
      display: 'flex', alignItems: 'center', gap: 12,
      padding: '16px 16px 8px',
    }}>
      <span style={{
        fontFamily: 'JetBrains Mono, monospace', fontSize: 10,
        letterSpacing: '0.22em', padding: '3px 10px',
        background: tone, color: 'var(--bg-deep)',
        boxShadow: '3px 3px 0 var(--bg-deep)',
      }}>{title}</span>
      <div style={{ flex: 1, height: 1, background: `${tone}44` }} />
    </div>
  );

  return (
    <div style={{ width: '100%', height: '100%', overflow: 'auto', background: 'var(--bg-deep)' }}>
      {/* Faint felt stripe at top — mirrors the table */}
      <div style={{
        position: 'sticky', top: 0, zIndex: 10,
        background: 'repeating-linear-gradient(90deg, rgba(0,0,0,0) 0 8px, rgba(0,0,0,0.07) 8px 9px), linear-gradient(180deg, var(--bg-panel-2) 0%, var(--bg-panel) 100%)',
        boxShadow: '0 0 0 2px var(--bg-deep), 0 0 0 3px var(--accent), 0 4px 16px rgba(0,0,0,0.5)',
        padding: '10px 22px',
        display: 'flex', alignItems: 'center', gap: 16,
      }}>
        <button className="pix-btn small" onClick={onBack}>◀ Back</button>
        <div style={{ fontFamily: 'VT323, monospace', fontSize: 32, color: 'var(--accent)', letterSpacing: '0.1em' }}>
          HOW TO PLAY
        </div>
        <div style={{ flex: 1 }} />
        {/* Colour key */}
        <div style={{ display: 'flex', gap: 18, alignItems: 'center' }}>
          {[[cyan,'UTILITY'],[mag,'ATTACK'],[yel,'PERMANENT'],[dim,'INERT']].map(([c,lbl]) => (
            <div key={lbl} style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
              <div style={{ width: 8, height: 8, background: c, boxShadow: `0 0 6px ${c}` }} />
              <span style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 10, color: c, letterSpacing: '0.16em' }}>{lbl}</span>
            </div>
          ))}
        </div>
      </div>

      <div style={{ maxWidth: 820, margin: '0 auto', padding: '20px 24px 80px' }}>

        {/* Objective — wood-panel block matching in-game panels */}
        <div style={{
          marginBottom: 24,
          background: 'repeating-linear-gradient(90deg, rgba(0,0,0,0) 0 8px, rgba(0,0,0,0.07) 8px 9px), linear-gradient(180deg, var(--bg-panel-2) 0%, var(--bg-panel) 100%)',
          boxShadow: '0 0 0 2px var(--bg-deep), 0 0 0 4px var(--accent), inset 0 0 0 1px rgba(255,255,255,0.03)',
          padding: '14px 18px',
        }}>
          <div style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 10, letterSpacing: '0.26em', color: 'var(--accent)', marginBottom: 6 }}>OBJECTIVE</div>
          <div style={{ fontFamily: 'VT323, monospace', fontSize: 22, color: 'var(--ink)', lineHeight: 1.6 }}>
            Score <span style={{ color: yel }}>21 POINTS</span> before Cuttlebot.
            Each turn: <span style={{ color: cyan }}>DRAW</span> or <span style={{ color: mag }}>PLAY</span> one card.
            Most cards have a special effect. You can also <span style={{ color: yel }}>SCUTTLE</span> — cover a
            lower-rank point card with a higher one to send both to the scrap pile.
          </div>
        </div>

        {/* Point cards */}
        <div style={{
          background: 'repeating-linear-gradient(90deg, rgba(0,0,0,0) 0 8px, rgba(0,0,0,0.07) 8px 9px), linear-gradient(180deg, var(--bg-panel-2) 0%, var(--bg-panel) 100%)',
          boxShadow: '0 0 0 2px var(--bg-deep), 0 0 0 4px var(--line-bright), inset 0 0 0 1px rgba(255,255,255,0.03)',
          marginBottom: 16,
        }}>
          <SectionHead title="POINT CARDS  ·  A – 10" tone="var(--accent)" />
          <div style={{ padding: '0 4px 4px', fontFamily: 'JetBrains Mono, monospace', fontSize: 11, color: 'var(--ink-dim)', paddingLeft: 16, paddingBottom: 12 }}>
            Worth face value on your field — or fired as a one-off (then scrapped).
          </div>
          <Row rank="A"  color={mag}  label="ACE — WIPE"         body="One-off: scrap ALL point cards from both fields." />
          <Row rank="2"  color={mag}  label="TWO — COUNTER / KILL" body="Reaction: cancel their one-off or Jack (both cards scrap). One-off: scrap any permanent — Queen, King, Glasses or an attached Jack." />
          <Row rank="3"  color={cyan} label="THREE — SALVAGE"    body="One-off: take any one card from the scrap pile into your hand." />
          <Row rank="4"  color={mag}  label="FOUR — FORCE DISCARD" body="One-off: opponent scraps 2 cards from hand." />
          <Row rank="5"  color={cyan} label="FIVE — DRAW 2"      body="One-off: draw 2 cards from the deck." />
          <Row rank="6"  color={mag}  label="SIX — ROYAL WIPE"   body="One-off: scrap all Queens, Kings and Glasses on both fields." />
          <Row rank="7"  color={cyan} label="SEVEN — FLIP"       body="One-off: flip the top card of the deck and play it immediately, or scrap it." />
          <Row rank="8"  color={yel}  label="EIGHT — GLASSES"    body="Permanent: lay on your field face-up; you can see your opponent's hand." />
          <Row rank="9"  color={mag}  label="NINE — BOUNCE"      body="One-off: return any permanent (Queen, King, Glasses or Jack) on either field to its controller's hand." />
          <Row rank="10" color={dim}  label="TEN — POINT ONLY"   body="No one-off effect. Worth 10 points, or used to scuttle a lower-rank point card." />
        </div>

        {/* Face cards */}
        <div style={{
          background: 'repeating-linear-gradient(90deg, rgba(0,0,0,0) 0 8px, rgba(0,0,0,0.07) 8px 9px), linear-gradient(180deg, var(--bg-panel-2) 0%, var(--bg-panel) 100%)',
          boxShadow: '0 0 0 2px var(--bg-deep), 0 0 0 4px var(--line-bright), inset 0 0 0 1px rgba(255,255,255,0.03)',
        }}>
          <SectionHead title="FACE CARDS  ·  J Q K" tone={yel} />
          <div style={{ padding: '0 4px 4px', fontFamily: 'JetBrains Mono, monospace', fontSize: 11, color: 'var(--ink-dim)', paddingLeft: 16, paddingBottom: 12 }}>
            Always permanents — stay on your field until removed.
          </div>
          <Row rank="J" color={yel} label="JACK — STEAL"         body="Play onto an unprotected opponent point card. It moves to your field, worth its original value." />
          <Row rank="Q" color={yel} label="QUEEN — PROTECT"      body="While a Queen is on your field, your other cards can't be targeted by opponent effects. Queens don't protect themselves." />
          <Row rank="K" color={yel} label="KING — LOWER TARGET"  body="Each King on your field lowers your win threshold. 0 Kings = 21 pts · 1 = 14 · 2 = 10 · 3 = 7 · 4 = 5." />
        </div>

      </div>
    </div>
  );
}

// ─── HISTORY / HIGH SCORES ───────────────────────────────────────────────────
function HistoryScreen({ onBack, history, onClear }) {
  const wins = history.filter(h => h.winner === 'player').length;
  const losses = history.length - wins;
  const wr = history.length ? Math.round(100 * wins / history.length) : 0;
  const sortedByScore = history.slice().sort((a, b) => {
    if ((b.winner === 'player') !== (a.winner === 'player')) return (b.winner === 'player') - (a.winner === 'player');
    if (b.playerScore !== a.playerScore) return b.playerScore - a.playerScore;
    return a.turns - b.turns;
  });
  return (
    <div style={{ width: '100%', height: '100%', overflow: 'auto', background: 'var(--bg-deep)' }}>
      {/* Sticky header — same wood-panel chrome as menu/rules/settings */}
      <div style={{
        position: 'sticky', top: 0, zIndex: 10,
        background: 'repeating-linear-gradient(90deg, rgba(0,0,0,0) 0 8px, rgba(0,0,0,0.07) 8px 9px), linear-gradient(180deg, var(--bg-panel-2) 0%, var(--bg-panel) 100%)',
        boxShadow: '0 0 0 2px var(--bg-deep), 0 0 0 3px var(--accent), 0 4px 16px rgba(0,0,0,0.5)',
        padding: '10px 22px',
        display: 'flex', alignItems: 'center', gap: 16,
      }}>
        <button className="pix-btn small" onClick={onBack}>◀ Back</button>
        <div style={{ fontFamily: 'VT323, monospace', fontSize: 32, color: 'var(--accent-3)', letterSpacing: '0.1em' }}>
          HIGH SCORES
        </div>
        <div style={{ flex: 1 }} />
        {history.length > 0 && <button className="pix-btn small" onClick={onClear}>Clear</button>}
      </div>

      <div style={{ maxWidth: 920, margin: '0 auto', padding: '24px 28px 80px' }}>
        {/* Summary stats */}
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 14, marginBottom: 24 }}>
          <Stat label="GAMES"    value={history.length} color="var(--ink)" />
          <Stat label="WINS"     value={wins}           color="var(--accent-2)" />
          <Stat label="WIN RATE" value={wr + '%'}       color="var(--accent-3)" />
        </div>

        {/* Runs table */}
        <div style={{
          background: 'repeating-linear-gradient(90deg, rgba(0,0,0,0) 0 8px, rgba(0,0,0,0.07) 8px 9px), linear-gradient(180deg, var(--bg-panel-2) 0%, var(--bg-panel) 100%)',
          boxShadow: '0 0 0 2px var(--bg-deep), 0 0 0 4px var(--line-bright), inset 0 0 0 1px rgba(255,255,255,0.03)',
        }}>
          <div style={{
            display: 'flex', alignItems: 'center', gap: 10, padding: '12px 16px 8px',
          }}>
            <span style={{
              fontFamily: 'JetBrains Mono, monospace', fontSize: 10, letterSpacing: '0.22em',
              padding: '3px 10px', background: 'var(--accent)', color: 'var(--bg-deep)',
              boxShadow: '3px 3px 0 var(--bg-deep)',
            }}>TOP RUNS</span>
            <div style={{ flex: 1, height: 1, background: 'var(--accent)44' }} />
          </div>
          {history.length === 0 ? (
            <div style={{ padding: 22, textAlign: 'center', color: 'var(--ink-dim)', fontFamily: 'VT323, monospace', fontSize: 26 }}>
              ─── NO RECORDS YET. INSERT COIN. ───
            </div>
          ) : (
            <div style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 13 }}>
              <div style={{
                display: 'grid', gridTemplateColumns: '40px 80px 90px 1fr 80px 80px 80px',
                gap: 12, padding: '8px 16px', borderBottom: '1px solid var(--line-bright)',
                color: 'var(--accent-2)', letterSpacing: '0.1em', textTransform: 'uppercase', fontSize: 11,
              }}>
                <div>RNK</div><div>RESULT</div><div>DATE</div><div>NAME</div><div>YOU</div><div>BOT</div><div>TURNS</div>
              </div>
              {sortedByScore.slice(0, 20).map((g, i) => (
                <div key={i} style={{
                  display: 'grid', gridTemplateColumns: '40px 80px 90px 1fr 80px 80px 80px',
                  gap: 12, padding: '8px 16px', alignItems: 'center',
                  borderBottom: '1px dashed var(--line)',
                  color: g.winner === 'player' ? 'var(--ink)' : 'var(--ink-dim)',
                }}>
                  <div style={{ color: i < 3 ? 'var(--accent-3)' : 'var(--ink-dim)', fontFamily: 'VT323, monospace', fontSize: 22 }}>
                    {String(i + 1).padStart(2, '0')}
                  </div>
                  <div style={{ color: g.winner === 'player' ? 'var(--accent-2)' : 'var(--accent)', fontWeight: 700 }}>
                    {g.winner === 'player' ? 'WIN' : 'LOSS'}
                  </div>
                  <div style={{ color: 'var(--ink-dim)' }}>{formatDate(g.endedAt)}</div>
                  <div style={{ fontFamily: 'VT323, monospace', fontSize: 22, letterSpacing: '0.1em' }}>
                    {g.winner === 'player' ? (g.name || 'PLAYER1') : 'CUTTLEBOT'}
                  </div>
                  <div style={{ fontFamily: 'VT323, monospace', fontSize: 22, color: 'var(--accent-2)' }}>{String(g.playerScore).padStart(2, '0')}</div>
                  <div style={{ fontFamily: 'VT323, monospace', fontSize: 22, color: 'var(--accent)' }}>{String(g.aiScore).padStart(2, '0')}</div>
                  <div style={{ fontFamily: 'VT323, monospace', fontSize: 22 }}>{g.turns}</div>
                </div>
              ))}
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

function Stat({ label, value, color }) {
  return (
    <div className="pix-panel" style={{ padding: 18 }}>
      <div style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 11, letterSpacing: '0.18em', color: 'var(--ink-dim)' }}>{label}</div>
      <div style={{ fontFamily: 'VT323, monospace', fontSize: 64, color, textShadow: `0 0 14px ${color}`, lineHeight: 1, marginTop: 4 }}>
        {value}
      </div>
    </div>
  );
}

function formatDate(ts) {
  const d = new Date(ts);
  const now = new Date();
  const sameDay = d.toDateString() === now.toDateString();
  if (sameDay) return d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', hour12: false });
  return (d.getMonth()+1) + '/' + d.getDate();
}

// ─── SETTINGS ────────────────────────────────────────────────────────────────
function SettingsScreen({ onBack, settings, onChange }) {
  return (
    <div style={{ width: '100%', height: '100%', overflow: 'auto', background: 'var(--bg-deep)' }}>
      {/* Sticky header */}
      <div style={{
        position: 'sticky', top: 0, zIndex: 10,
        background: 'repeating-linear-gradient(90deg, rgba(0,0,0,0) 0 8px, rgba(0,0,0,0.07) 8px 9px), linear-gradient(180deg, var(--bg-panel-2) 0%, var(--bg-panel) 100%)',
        boxShadow: '0 0 0 2px var(--bg-deep), 0 0 0 3px var(--accent), 0 4px 16px rgba(0,0,0,0.5)',
        padding: '10px 22px',
        display: 'flex', alignItems: 'center', gap: 16,
      }}>
        <button className="pix-btn small" onClick={onBack}>◀ Back</button>
        <div style={{ fontFamily: 'VT323, monospace', fontSize: 32, color: 'var(--accent-2)', letterSpacing: '0.1em' }}>
          SETTINGS
        </div>
      </div>

      <div style={{ maxWidth: 720, margin: '0 auto', padding: '24px 28px 80px' }}>
        <div style={{
          background: 'repeating-linear-gradient(90deg, rgba(0,0,0,0) 0 8px, rgba(0,0,0,0.07) 8px 9px), linear-gradient(180deg, var(--bg-panel-2) 0%, var(--bg-panel) 100%)',
          boxShadow: '0 0 0 2px var(--bg-deep), 0 0 0 4px var(--line-bright), inset 0 0 0 1px rgba(255,255,255,0.03)',
        }}>
          <SettingRow
            label="CARD HINTS"
            desc="Show a short description when you hover a card in your hand or a permanent on the field."
            value={settings.cardHints}
            onChange={(v) => onChange({ ...settings, cardHints: v })}
          />
          <ChoiceRow
            label="DIFFICULTY"
            desc="EASY: original AI (uniform-rollout MCTS). HARD: heuristic Cuttle-aware MCTS with late-game tactical solver."
            value={settings.aiDifficulty ?? 'EASY'}
            options={['EASY', 'HARD']}
            onChange={(v) => onChange({ ...settings, aiDifficulty: v })}
          />
        </div>
      </div>
    </div>
  );
}

function SettingRow({ label, desc, value, onChange }) {
  return (
    <div style={{ display: 'grid', gridTemplateColumns: '1fr auto', gap: 18, padding: '20px 22px', alignItems: 'center', borderBottom: '1px dashed var(--line)' }}>
      <div>
        <div style={{ fontFamily: 'VT323, monospace', fontSize: 26, color: 'var(--ink)', letterSpacing: '0.08em' }}>
          <span style={{ color: 'var(--accent-2)' }}>▸</span> {label}
        </div>
        <div style={{ fontSize: 13, color: 'var(--ink-dim)', lineHeight: 1.6, marginTop: 4 }}>{desc}</div>
      </div>
      <button
        onClick={() => onChange(!value)}
        className="pix-btn small"
        style={{ minWidth: 84 }}
      >
        {value ? 'ON' : 'OFF'}
      </button>
    </div>
  );
}

function ChoiceRow({ label, desc, value, options, onChange }) {
  return (
    <div style={{ display: 'grid', gridTemplateColumns: '1fr auto', gap: 18, padding: '20px 22px', alignItems: 'center', borderBottom: '1px dashed var(--line)' }}>
      <div>
        <div style={{ fontFamily: 'VT323, monospace', fontSize: 26, color: 'var(--ink)', letterSpacing: '0.08em' }}>
          <span style={{ color: 'var(--accent-2)' }}>▸</span> {label}
        </div>
        <div style={{ fontSize: 13, color: 'var(--ink-dim)', lineHeight: 1.6, marginTop: 4 }}>{desc}</div>
      </div>
      <div style={{ display: 'flex', gap: 6 }}>
        {options.map((opt) => (
          <button
            key={opt}
            onClick={() => onChange(opt)}
            className="pix-btn small"
            style={{
              minWidth: 84,
              opacity: opt === value ? 1.0 : 0.45,
              borderColor: opt === value ? 'var(--accent-2)' : undefined,
            }}
          >
            {opt}
          </button>
        ))}
      </div>
    </div>
  );
}

// ─── RESULTS ─────────────────────────────────────────────────────────────────
function ResultsScreen({ result, onRematch, onMenu }) {
  const win = result?.winner === 'player';
  // Yellow on win, magenta on loss — mirrors the menu's player/boss bezel pairing.
  const color = win ? 'var(--accent-2)' : 'var(--magenta)';
  // Pick once per result so the face doesn't flip between renders.
  const endMood = React.useMemo(() => pickAIMood(
    { winner: win ? 'player' : 'ai', turn: (result?.playerScore ?? 0) * 31 + (result?.aiScore ?? 0) },
  ), [win, result?.playerScore, result?.aiScore]);
  const woodStripe = 'repeating-linear-gradient(90deg, rgba(0,0,0,0) 0 8px, rgba(0,0,0,0.07) 8px 9px), linear-gradient(180deg, var(--bg-panel-2) 0%, var(--bg-panel) 100%)';
  return (
    <div style={{
      width: '100%', height: '100%', position: 'relative', overflow: 'hidden',
      background: 'radial-gradient(ellipse at 50% 60%, #2a1810 0%, #160c06 55%, #0d0704 100%)',
      display: 'flex', alignItems: 'center', justifyContent: 'center',
    }}>
      {/* Felt bleed up from bottom — same green as the game table / menu */}
      <div style={{
        position: 'absolute', bottom: 0, left: 0, right: 0, height: '40%',
        background: 'linear-gradient(to top, #1a4a3a 0%, #0d2a22 55%, transparent 100%)',
        opacity: 0.45,
      }} />
      <div className="grid-floor" style={{ opacity: 0.10 }} />

      <div style={{ textAlign: 'center', position: 'relative', zIndex: 2 }}>
        {/* Brass-bezelled cuttlefish portrait — colour reflects the outcome */}
        <div style={{ display: 'flex', justifyContent: 'center', marginBottom: 28 }}>
          <div style={{
            padding: 14,
            background: woodStripe,
            boxShadow: `0 0 0 3px var(--bg-deep), 0 0 0 6px ${color}, 10px 10px 0 6px rgba(0,0,0,0.65)`,
          }}>
            <PixelCuttlefish mood={endMood} size={140} />
          </div>
        </div>

        <div style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 11, letterSpacing: '0.4em', color: 'var(--ink-dim)' }}>
          {win ? '── ROUND CLEAR ──' : '── GAME OVER ──'}
        </div>
        <div className="pixel-text" style={{ fontSize: 148, color, lineHeight: 1, marginTop: 10 }}>
          {win ? 'YOU WIN' : 'YOU LOSE'}
        </div>

        {/* Single wood-panel strip housing P1 / CPU / TURNS with ruled dividers */}
        <div style={{
          display: 'inline-flex', gap: 0, marginTop: 32,
          background: woodStripe,
          boxShadow: `0 0 0 2px var(--bg-deep), 0 0 0 4px ${color}, inset 0 0 0 1px rgba(255,255,255,0.03)`,
        }}>
          {[
            ['P1',    result?.playerScore ?? 0, 'var(--accent-2)'],
            ['CPU',   result?.aiScore     ?? 0, 'var(--accent)'],
            ['TURNS', result?.turns       ?? 0, 'var(--accent-3)'],
          ].map(([lbl, val, c], i, arr) => (
            <React.Fragment key={lbl}>
              <div style={{ padding: '14px 28px', textAlign: 'center' }}>
                <div style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 10, letterSpacing: '0.22em', color: 'var(--ink-dim)' }}>{lbl}</div>
                <div style={{ fontFamily: 'VT323, monospace', fontSize: 76, color: c, textShadow: `0 0 14px ${c}`, lineHeight: 1, marginTop: 4 }}>
                  {String(val).padStart(2, '0')}
                </div>
              </div>
              {i < arr.length - 1 && <div style={{ width: 1, background: 'var(--line-bright)', margin: '16px 0' }} />}
            </React.Fragment>
          ))}
        </div>

        <div style={{ display: 'flex', gap: 18, justifyContent: 'center', marginTop: 36 }}>
          <button className="pix-btn primary" onClick={onRematch}>▶ Continue</button>
          <button className="pix-btn" onClick={onMenu}>Menu</button>
        </div>
      </div>
    </div>
  );
}

// ─── NAME ENTRY ──────────────────────────────────────────────────────────────
function NameEntryScreen({ result, onSubmit }) {
  const [initials, setInitials] = React.useState(() => loadLastName().split(''));
  const [pos, setPos] = React.useState(0);
  const [submitted, setSubmitted] = React.useState(false);
  const [blink, setBlink] = React.useState(true);

  React.useEffect(() => {
    const i = setInterval(() => setBlink(b => !b), 350);
    return () => clearInterval(i);
  }, []);

  function setCharAt(i, ch) {
    setInitials(prev => { const a = [...prev]; a[i] = ch; return a; });
  }
  function cycleChar(delta) {
    const cur = initials[pos];
    const idx = NAME_CHARS.indexOf(cur);
    const j = ((idx < 0 ? 0 : idx) + delta + NAME_CHARS.length) % NAME_CHARS.length;
    setCharAt(pos, NAME_CHARS[j]);
  }
  function movePos(delta) { setPos(p => Math.max(0, Math.min(2, p + delta))); }
  function submit() {
    if (submitted) return;
    setSubmitted(true);
    const name = initials.join('');
    localStorage.setItem(NAME_KEY, name);
    onSubmit(name);
  }

  React.useEffect(() => {
    const onKey = (e) => {
      if (submitted) return;
      if (e.key === 'ArrowUp') { e.preventDefault(); cycleChar(1); }
      else if (e.key === 'ArrowDown') { e.preventDefault(); cycleChar(-1); }
      else if (e.key === 'ArrowLeft') { e.preventDefault(); movePos(-1); }
      else if (e.key === 'ArrowRight') { e.preventDefault(); movePos(1); }
      else if (e.key === 'Enter') {
        e.preventDefault();
        if (pos < 2) movePos(1); else submit();
      }
      else if (e.key === 'Backspace') {
        e.preventDefault();
        setCharAt(pos, ' ');
        if (pos > 0) movePos(-1);
      }
      else if (e.key && e.key.length === 1) {
        const ch = e.key.toUpperCase();
        if (NAME_CHARS.includes(ch)) {
          e.preventDefault();
          setCharAt(pos, ch);
          if (pos < 2) setPos(p => p + 1);
        }
      }
    };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [pos, initials, submitted]);

  const woodStripe = 'repeating-linear-gradient(90deg, rgba(0,0,0,0) 0 8px, rgba(0,0,0,0.07) 8px 9px), linear-gradient(180deg, var(--bg-panel-2) 0%, var(--bg-panel) 100%)';
  return (
    <div style={{
      width: '100%', height: '100%', position: 'relative', overflow: 'hidden',
      background: 'radial-gradient(ellipse at 50% 70%, #2a1810 0%, #160c06 55%, #0d0704 100%)',
      display: 'flex', alignItems: 'center', justifyContent: 'center',
    }}>
      <div style={{
        position: 'absolute', bottom: 0, left: 0, right: 0, height: '40%',
        background: 'linear-gradient(to top, #1a4a3a 0%, #0d2a22 55%, transparent 100%)',
        opacity: 0.45,
      }} />
      <div className="grid-floor" style={{ opacity: 0.10 }} />

      <div style={{ textAlign: 'center', position: 'relative', zIndex: 2, padding: 24 }}>
        <div style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 11, letterSpacing: '0.4em', color: 'var(--ink-dim)' }}>
          ── NEW HIGH SCORE ──
        </div>
        <div className="pixel-text" style={{ fontSize: 84, color: 'var(--accent-2)', lineHeight: 1, marginTop: 8 }}>
          ENTER YOUR NAME
        </div>
        <div style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 12, color: 'var(--ink-dim)', marginTop: 10, letterSpacing: '0.22em' }}>
          {String(result?.playerScore ?? 0).padStart(2, '0')} PTS · {result?.turns ?? 0} TURNS
        </div>

        <div style={{ display: 'flex', gap: 20, justifyContent: 'center', marginTop: 44 }}>
          {initials.map((ch, i) => {
            const active = i === pos;
            return (
              <div key={i} style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 8 }}>
                <div style={{
                  fontFamily: 'VT323, monospace', fontSize: 32, lineHeight: 1,
                  color: 'var(--accent-2)',
                  opacity: active ? (blink ? 1 : 0.25) : 0,
                  transition: 'opacity 80ms',
                }}>▲</div>
                <div onClick={() => setPos(i)} style={{
                  width: 88, height: 118, cursor: 'pointer',
                  background: woodStripe,
                  boxShadow: active
                    ? '0 0 0 3px var(--bg-deep), 0 0 0 6px var(--accent-2), 0 0 24px rgba(255,210,63,0.4)'
                    : '0 0 0 3px var(--bg-deep), 0 0 0 5px var(--line-bright), 6px 6px 0 5px rgba(0,0,0,0.5)',
                  display: 'flex', alignItems: 'center', justifyContent: 'center',
                  fontFamily: 'VT323, monospace', fontSize: 88,
                  color: active ? 'var(--accent-2)' : 'var(--ink)',
                  textShadow: active ? '0 0 14px var(--accent-2)' : 'none',
                  lineHeight: 1, transition: 'box-shadow 120ms, color 120ms',
                  userSelect: 'none',
                }}>
                  {ch === ' ' ? '_' : ch}
                </div>
                <div style={{
                  fontFamily: 'VT323, monospace', fontSize: 32, lineHeight: 1,
                  color: 'var(--accent-2)',
                  opacity: active ? (blink ? 1 : 0.25) : 0,
                  transition: 'opacity 80ms',
                }}>▼</div>
              </div>
            );
          })}
        </div>

        <div style={{ display: 'flex', gap: 10, justifyContent: 'center', marginTop: 32, flexWrap: 'wrap' }}>
          <button className="pix-btn small" onClick={() => movePos(-1)}>◀</button>
          <button className="pix-btn small" onClick={() => cycleChar(-1)}>▼</button>
          <button className="pix-btn small" onClick={() => cycleChar(1)}>▲</button>
          <button className="pix-btn small" onClick={() => movePos(1)}>▶</button>
          <button className="pix-btn primary" onClick={submit}>✓ Enter</button>
        </div>

        <div style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 11, color: 'var(--ink-dim)', marginTop: 24, letterSpacing: '0.18em' }}>
          ARROWS TO CHOOSE · TYPE TO SET · ENTER TO CONFIRM
        </div>
      </div>
    </div>
  );
}

// ─── WELCOME / FIRST-TIME RULES POPUP ────────────────────────────────────────
function WelcomePopup({ onClose }) {
  return (
    <div style={{
      position: 'absolute', inset: 0, zIndex: 70,
      background: 'rgba(0,0,0,0.78)',
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      padding: 24,
    }}>
      <div className="pix-panel pix-fade-in" style={{ maxWidth: 560, padding: 32, textAlign: 'center' }}>
        <div style={{ fontFamily: 'VT323, monospace', fontSize: 20, letterSpacing: '0.32em', color: 'var(--ink-dim)' }}>
          ── BRIEFING ──
        </div>
        <div className="pixel-text" style={{ fontSize: 72, color: 'var(--accent)', lineHeight: 1, marginTop: 8 }}>
          CUTTLE
        </div>
        <div style={{ fontFamily: 'VT323, monospace', fontSize: 22, color: 'var(--ink-dim)', marginTop: 4, letterSpacing: '0.18em' }}>
          A COMBAT CARD GAME
        </div>
        <div style={{
          marginTop: 24, fontFamily: 'JetBrains Mono, monospace', fontSize: 14,
          color: 'var(--ink)', lineHeight: 1.7, textAlign: 'left',
        }}>
          <div><span style={{ color: 'var(--accent-3)' }}>▸</span> First to <b style={{ color: 'var(--accent-3)' }}>21 POINTS</b> wins.</div>
          <div style={{ marginTop: 8 }}><span style={{ color: 'var(--accent-2)' }}>▸</span> Play a card for its points, or its one-off / permanent effect.</div>
          <div style={{ marginTop: 8 }}><span style={{ color: 'var(--accent-2)' }}>▸</span> Hover any card to see what it does.</div>
        </div>
        <div style={{ marginTop: 28 }}>
          <button className="pix-btn primary" onClick={onClose}>▶ Got It</button>
        </div>
        <div style={{ fontFamily: 'VT323, monospace', fontSize: 16, color: 'var(--ink-dim)', marginTop: 16, letterSpacing: '0.16em' }}>
          FULL RULES VIA THE ? BUTTON · TOP RIGHT
        </div>
      </div>
    </div>
  );
}

// ─── GAME WRAPPER (CRT cabinet chrome around the table) ──────────────────────
function GameScreen({ seed, dealer, settings, onSettingsChange, onGameOver, onMenu }) {
  const [showRules, setShowRules] = React.useState(false);
  const [showSettings, setShowSettings] = React.useState(false);
  const [showIntro, setShowIntro] = React.useState(() => {
    try { return !localStorage.getItem(SEEN_INTRO_KEY); } catch { return false; }
  });
  const { w: vw, h: vh } = useViewport();
  const sizes = (window.responsiveSizes || (() => ({ hudH: 56 })))(vw, vh);
  const hudH = sizes.hudH;
  function dismissIntro() {
    try { localStorage.setItem(SEEN_INTRO_KEY, '1'); } catch {}
    setShowIntro(false);
  }
  // Push the AI difficulty into the (singleton) wasm engine adapter whenever
  // settings change. The adapter holds a process-global default that all
  // aiChooseAction calls fall back to when no per-call override is supplied.
  React.useEffect(() => {
    const d = settings?.aiDifficulty ?? 'EASY';
    window.CuttleEngine?.setDifficulty?.(d);
  }, [settings?.aiDifficulty]);
  // HUD font shrinks with the bar height so labels still fit on small screens.
  const hudFont = Math.round(hudH * 0.4);
  return (
    <div style={{ width: '100%', height: '100%', position: 'relative', background: 'var(--bg-deep)' }}>
      {/* Top arcade HUD bar */}
      <div style={{
        position: 'absolute', top: 0, left: 0, right: 0, height: hudH,
        background: 'var(--bg-panel)', borderBottom: '2px solid var(--accent)',
        display: 'flex', alignItems: 'center', padding: `0 ${Math.max(12, hudH * 0.4)}px`, gap: 10,
        fontFamily: 'VT323, monospace', fontSize: hudFont, color: 'var(--ink)',
        zIndex: 40,
      }}>
        <span style={{ color: 'var(--accent-2)' }}>▸</span>
        <span style={{ marginLeft: 8, letterSpacing: '0.16em' }}>STAGE 01 · CUTTLEBOT</span>
        <div style={{ flex: 1 }} />
        <button className="pix-btn small" onClick={() => setShowSettings(true)}>⚙ Setup</button>
        <button className="pix-btn small" onClick={() => setShowRules(true)}>? Rules</button>
        <button className="pix-btn small" onClick={onMenu}>◀ Quit</button>
      </div>

      <div style={{ position: 'absolute', top: hudH, left: 0, right: 0, bottom: 0 }}>
        <CuttleTable
          theme="arcade"
          layout="stacked"
          cardStyle="realistic"
          showHints
          cardHints={settings?.cardHints !== false}
          animSpeed={1}
          seed={seed}
          dealer={dealer}
          onGameOver={onGameOver}
        />
      </div>

      {showRules && (
        <div style={{
          position: 'absolute', inset: 0, zIndex: 60,
          background: 'rgba(0,0,0,0.78)',
        }}>
          <RulesScreen onBack={() => setShowRules(false)} />
        </div>
      )}

      {showIntro && <WelcomePopup onClose={dismissIntro} />}

      {showSettings && (
        <div style={{
          position: 'absolute', inset: 0, zIndex: 60,
          background: 'rgba(0,0,0,0.78)',
        }}>
          <SettingsScreen onBack={() => setShowSettings(false)} settings={settings} onChange={onSettingsChange} />
        </div>
      )}
    </div>
  );
}

// ─── TOO-SMALL GATE ──────────────────────────────────────────────────────────
// Below 760×760 even the responsive layout in responsive.mjs can't fit cleanly,
// so we replace the whole app with a friendly arcade-style "cabinet too small"
// notice. Above 760 the layout scales smoothly to the desktop ceiling at 1050.
const MIN_W = 760;
const MIN_H = 760;

function useViewport() {
  const [v, setV] = React.useState(() => ({ w: window.innerWidth, h: window.innerHeight }));
  React.useEffect(() => {
    const onResize = () => setV({ w: window.innerWidth, h: window.innerHeight });
    window.addEventListener('resize', onResize);
    window.addEventListener('orientationchange', onResize);
    return () => {
      window.removeEventListener('resize', onResize);
      window.removeEventListener('orientationchange', onResize);
    };
  }, []);
  return v;
}

function TooSmallGate({ w, h }) {
  const [show, setShow] = React.useState(true);
  React.useEffect(() => {
    const i = setInterval(() => setShow(s => !s), 600);
    return () => clearInterval(i);
  }, []);
  const wOk = w >= MIN_W;
  const hOk = h >= MIN_H;
  return (
    <div style={{
      width: '100vw', height: '100vh', position: 'relative', overflow: 'hidden',
      background: 'radial-gradient(ellipse at 50% 70%, #2a1810 0%, #160c06 55%, #0d0704 100%)',
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      padding: 16,
    }}>
      <div className="grid-floor" style={{ opacity: 0.14 }} />
      <div style={{
        position: 'absolute', inset: 0, pointerEvents: 'none',
        background: 'repeating-linear-gradient(90deg, transparent 0 72px, rgba(212,166,74,0.025) 72px 73px)',
      }} />

      <div className="pix-panel pix-fade-in" style={{
        position: 'relative', zIndex: 2,
        maxWidth: 520, width: '100%',
        padding: '28px 26px 24px',
        textAlign: 'center',
      }}>
        <div style={{ display: 'flex', justifyContent: 'center', marginBottom: 12 }}>
          <PixelCuttlefish mood="sleepy" size={96} />
        </div>

        <div style={{
          fontFamily: 'VT323, monospace', fontSize: 16, letterSpacing: '0.32em',
          color: 'var(--ink-dim)',
        }}>
          ── CABINET TOO SMALL ──
        </div>

        <div className="pixel-text" style={{
          fontFamily: 'VT323, monospace',
          fontSize: 56, color: 'var(--magenta)', lineHeight: 0.95, marginTop: 6,
          letterSpacing: '0.04em',
          textShadow: '0 0 14px rgba(255,59,139,0.55), 3px 0 0 var(--accent-2), -3px 0 0 var(--accent)',
        }}>
          INSERT BIGGER<br/>SCREEN
        </div>

        <div style={{
          fontFamily: 'JetBrains Mono, monospace', fontSize: 12,
          color: 'var(--ink)', lineHeight: 1.7, marginTop: 18,
          letterSpacing: '0.04em',
        }}>
          This cabinet is calibrated for a viewport of at least
          <div style={{
            fontFamily: 'VT323, monospace', fontSize: 36,
            color: 'var(--accent-2)', letterSpacing: '0.08em',
            textShadow: '0 0 10px var(--accent-2)',
            margin: '6px 0 4px',
          }}>
            {MIN_W} × {MIN_H}
          </div>
        </div>

        {/* Current size readout — colour-coded per axis so the player sees which
            one is too small. */}
        <div style={{
          marginTop: 14, padding: '10px 12px',
          background: 'rgba(0,0,0,0.35)',
          boxShadow: 'inset 0 0 0 1px rgba(255,255,255,0.04), inset 0 0 12px rgba(0,0,0,0.5)',
          display: 'inline-flex', gap: 18, alignItems: 'center',
          fontFamily: 'VT323, monospace', fontSize: 22, letterSpacing: '0.08em',
        }}>
          <span style={{ color: 'var(--ink-dim)', fontSize: 11, letterSpacing: '0.22em' }}>YOU</span>
          <span style={{ color: wOk ? 'var(--green)' : 'var(--magenta)' }}>
            {wOk ? '◆' : '✕'} {w}<span style={{ opacity: 0.5 }}>w</span>
          </span>
          <span style={{ color: 'var(--ink-dim)' }}>×</span>
          <span style={{ color: hOk ? 'var(--green)' : 'var(--magenta)' }}>
            {hOk ? '◆' : '✕'} {h}<span style={{ opacity: 0.5 }}>h</span>
          </span>
        </div>

        <div style={{
          fontFamily: 'JetBrains Mono, monospace', fontSize: 11,
          color: 'var(--ink-dim)', lineHeight: 1.7, marginTop: 18,
          letterSpacing: '0.06em',
        }}>
          ▸ Resize this window taller / wider<br/>
          ▸ Maximise the browser, hide the bookmarks bar<br/>
          ▸ Or come back from a desktop monitor
        </div>

        <div style={{
          fontFamily: 'VT323, monospace', fontSize: 18, color: 'var(--accent-2)',
          letterSpacing: '0.2em', marginTop: 18,
          opacity: show ? 1 : 0, transition: 'opacity 60ms',
        }}>
          AWAITING LARGER CABINET
        </div>
      </div>
    </div>
  );
}

// ─── App ─────────────────────────────────────────────────────────────────────
function App() {
  const { w, h } = useViewport();
  const tooSmall = w < MIN_W || h < MIN_H;
  const [screen, setScreen] = React.useState('MENU');
  const [history, setHistory] = React.useState(loadHistory);
  const [settings, setSettings] = React.useState(loadSettings);
  const [result, setResult] = React.useState(null);
  // ?seed=N in the URL forces a deterministic starting deck — useful for tests
  // and bug repro. Honoured for both the initial mount and subsequent rematches.
  const urlSeed = (() => {
    try {
      const v = new URL(location.href).searchParams.get('seed');
      const n = v == null ? null : Number(v);
      return Number.isFinite(n) ? n : null;
    } catch { return null; }
  })();
  const [seed, setSeed] = React.useState(() => urlSeed ?? Math.floor(Math.random() * 1e9));
  // Dealer for the current game: 1 = AI deals (player goes first; default),
  // 0 = player deals (AI goes first). Set freshly on each startGame via the
  // alternating localStorage counter; placeholder 1 before any game starts.
  const [dealer, setDealer] = React.useState(1);

  function nav(s) { setScreen(s); }
  function startGame() {
    setSeed(urlSeed ?? Math.floor(Math.random() * 1e9));
    setDealer(consumeNextDealer());
    setResult(null); setScreen('GAME');
  }
  function onGameOver(r) {
    setResult(r);
    if (r.winner === 'player') {
      setTimeout(() => setScreen('NAME_ENTRY'), 1300);
    } else {
      const next = [...history, r];
      setHistory(next); saveHistory(next);
      setTimeout(() => setScreen('RESULTS'), 1300);
    }
  }
  function submitName(name) {
    const entry = { ...result, name };
    const next = [...history, entry];
    setHistory(next); saveHistory(next);
    setResult(entry);
    setScreen('RESULTS');
  }

  if (tooSmall) return <TooSmallGate w={w} h={h} />;

  return (
    <div style={{ width: '100vw', height: '100vh', position: 'relative' }}>
      <div className="pix-fade-in" key={screen} style={{ width: '100%', height: '100%' }}>
        {screen === 'MENU' && <MenuScreen onNav={(s) => s === 'GAME' ? startGame() : nav(s)} history={history} />}
        {screen === 'GAME' && <GameScreen seed={seed} dealer={dealer} settings={settings} onSettingsChange={(s) => { setSettings(s); saveSettings(s); }} onGameOver={onGameOver} onMenu={() => nav('MENU')} />}
        {screen === 'RULES' && <RulesScreen onBack={() => nav('MENU')} />}
        {screen === 'HISTORY' && <HistoryScreen onBack={() => nav('MENU')} history={history} onClear={() => { setHistory([]); saveHistory([]); }} />}
        {screen === 'SETTINGS' && <SettingsScreen onBack={() => nav('MENU')} settings={settings} onChange={(s) => { setSettings(s); saveSettings(s); }} />}
        {screen === 'NAME_ENTRY' && <NameEntryScreen result={result} onSubmit={submitName} />}
        {screen === 'RESULTS' && <ResultsScreen result={result} onRematch={startGame} onMenu={() => nav('MENU')} />}
      </div>
    </div>
  );
}

function mount() {
  ReactDOM.createRoot(document.getElementById('root')).render(<App />);
}
if (window.CuttleEngine) mount();
else window.addEventListener('cuttle-ready', mount, { once: true });
