// simple-games.jsx — coin flip, slots, craps

// ═════════════════════════════════════════════════════════════
// COIN FLIP — pick MAHA or MON
// ═════════════════════════════════════════════════════════════
function CoinFlip({ onBack, onHistory, onRules, onTip }) {
  const { balance, settle } = useStore();
  const [bet, setBet] = React.useState(null);
  const [pick, setPick] = React.useState('MAHA');
  const [spinning, setSpinning] = React.useState(false);
  const [result, setResult] = React.useState(null);
  const [angle, setAngle] = React.useState(0);

  const flip = () => {
    if (spinning || !bet || bet > balance) return;
    setSpinning(true); setResult(null);
    const outcome = Math.random() < 0.5 ? 'MAHA' : 'MON';
    const fullSpins = 8 + Math.floor(Math.random() * 3);
    const targetExtra = outcome === 'MAHA' ? 0 : 180;
    setAngle((a) => a + fullSpins * 360 + targetExtra - (a % 360));
    setTimeout(() => {
      const win = outcome === pick;
      const delta = win ? bet : -bet;
      settle('Coin Flip', delta, `${win ? '✓' : '×'} ${outcome}`);
      setResult({ face: outcome, win, delta });
      setSpinning(false);
    }, 1700);
  };

  return (
    <>
      <TopBar onBack={onBack} title="HEADS · TAILS" balance={balance} onRules={onRules} onTip={onTip} />
      <div className="stage">
        <div style={{ flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 36 }}>
          <div style={{ perspective: 800 }}>
            <div style={{
              width: 168, height: 168, position: 'relative',
              transformStyle: 'preserve-3d',
              transform: `rotateY(${angle}deg)`,
              transition: 'transform 1700ms cubic-bezier(.18,.7,.18,1)',
            }}>
              <CoinFace label="MAHA" front />
              <CoinFace label="MON" />
            </div>
          </div>
          <ResultLine result={result && { delta: result.delta, label: result.win ? 'won' : 'lost' }} />
        </div>

        <div style={{ padding: '0 24px 16px', display: 'flex', gap: 12 }}>
          <button className={'btn' + (pick === 'MAHA' ? ' primary' : '')} onClick={() => setPick('MAHA')} disabled={spinning}>MAHA</button>
          <button className={'btn' + (pick === 'MON' ? ' primary' : '')} onClick={() => setPick('MON')} disabled={spinning}>MON</button>
        </div>

        <div style={{ padding: '0 0 16px' }}>
          <div className="eyebrow" style={{ padding: '0 24px 12px' }}>Stake</div>
          <BetSelector value={bet} onChange={setBet} />
        </div>

        <div style={{ padding: '8px 24px 24px', borderTop: '1px solid var(--line)' }}>
          <button className="btn" onClick={flip} disabled={spinning || !bet || bet > balance}
            style={{ width: '100%', height: 56, letterSpacing: '0.3em' }}>
            {spinning ? '· · ·' : 'Flip'}
          </button>
        </div>
      </div>
    </>
  );
}

function CoinFace({ label, front }) {
  return (
    <div style={{
      position: 'absolute', inset: 0, borderRadius: '50%',
      backfaceVisibility: 'hidden',
      transform: front ? 'rotateY(0deg)' : 'rotateY(180deg)',
      background: '#0a0a0a',
      border: '1px solid rgba(255,255,255,0.18)',
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      boxShadow: 'inset 0 1px 0 rgba(255,255,255,0.06)',
      color: 'var(--text)',
    }}>
      <div className="serif" style={{ fontSize: 22, fontStyle: 'italic', lineHeight: 1, letterSpacing: '0.04em' }}>{label}</div>
    </div>
  );
}

// ═════════════════════════════════════════════════════════════
// SLOTS — three reels
// ═════════════════════════════════════════════════════════════
const SLOT_SYMBOLS = ['VII', 'X', 'IX', 'V', '·'];
const SLOT_PAYOUT = { 'VII': 50, 'X': 20, 'IX': 12, 'V': 6, '·': 3 };

function Slots({ onBack, onHistory, onRules, onTip }) {
  const { balance, settle } = useStore();
  const [bet, setBet] = React.useState(null);
  const [spinning, setSpinning] = React.useState(false);
  const [result, setResult] = React.useState(null);
  const [reelOffsets, setReelOffsets] = React.useState([0, 0, 0]);
  const [animating, setAnimating] = React.useState(false);

  const SYMBOL_H = 80;
  const STRIP_LEN = 44;
  const WIN_IDX = [30, 34, 38];

  const stripRef = React.useRef(null);
  if (!stripRef.current) {
    stripRef.current = Array.from({ length: 3 }, () =>
      Array.from({ length: STRIP_LEN }, () => SLOT_SYMBOLS[Math.floor(Math.random() * SLOT_SYMBOLS.length)])
    );
  }

  const spin = () => {
    if (spinning || !bet || bet > balance) return;

    // Re-seed the strip ABOVE the win index so each spin shows fresh symbols passing by,
    // but leave the previously visible row in place — no jump.
    [0,1,2].forEach((i) => {
      for (let k = 0; k < WIN_IDX[i] - 1; k++) {
        stripRef.current[i][k] = SLOT_SYMBOLS[Math.floor(Math.random() * SLOT_SYMBOLS.length)];
      }
    });

    setSpinning(true); setResult(null);
    setReelOffsets([0, 0, 0]);
    setAnimating(false);
    // Rolling decel sound matching the 2.4s reel animation
    try {
      if (typeof sounds !== 'undefined') {
        sounds.rollingDecel(2400, 750, 200, 0.04);
      }
    } catch (e) {}

    const final = (() => {
      // ~13% chance of all-three match, ~30% chance of adjacent pair
      const r = Math.random();
      if (r < 0.13) {
        const sym = SLOT_SYMBOLS[Math.floor(Math.random() * SLOT_SYMBOLS.length)];
        return [sym, sym, sym];
      }
      if (r < 0.43) {
        const sym = SLOT_SYMBOLS[Math.floor(Math.random() * SLOT_SYMBOLS.length)];
        const other = SLOT_SYMBOLS[Math.floor(Math.random() * SLOT_SYMBOLS.length)];
        return Math.random() < 0.5 ? [sym, sym, other] : [other, sym, sym];
      }
      return [0,1,2].map(() => SLOT_SYMBOLS[Math.floor(Math.random() * SLOT_SYMBOLS.length)]);
    })();

    [0,1,2].forEach((i) => {
      const strip = stripRef.current[i];
      strip[WIN_IDX[i]] = final[i];
      strip[WIN_IDX[i] - 1] = SLOT_SYMBOLS[Math.floor(Math.random() * SLOT_SYMBOLS.length)];
      strip[WIN_IDX[i] + 1] = SLOT_SYMBOLS[Math.floor(Math.random() * SLOT_SYMBOLS.length)];
    });

    const targets = WIN_IDX.map((idx) => SYMBOL_H - idx * SYMBOL_H);
    requestAnimationFrame(() => {
      setAnimating(true);
      setReelOffsets(targets);
    });

    setTimeout(() => {
      const winRow = final;
      let mult = 0;
      if (winRow[0] === winRow[1] && winRow[1] === winRow[2]) {
        mult = SLOT_PAYOUT[winRow[0]] ?? 0;
      } else if (winRow[0] === winRow[1] || winRow[1] === winRow[2]) {
        mult = 0.5;
      }
      const delta = mult > 0 ? Math.round(bet * mult) - bet : -bet;
      const detail = winRow.join(' · ') + (mult > 0 ? `  ${mult}×` : '');
      settle('Slot Machine', delta, detail);
      setResult({ delta, mult, row: winRow });
      setSpinning(false);
      setAnimating(false); // freeze in place — no further transitions on offsets
    }, 2700);
  };

  return (
    <>
      <TopBar onBack={onBack} title="SLOT MACHINE" balance={balance} onRules={onRules} onTip={onTip} />
      <div className="stage">
        <div style={{ flex: 1, display: 'flex', flexDirection: 'column', justifyContent: 'center', alignItems: 'center', gap: 28, padding: '0 24px' }}>
          <div style={{
            display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)',
            width: '100%', position: 'relative',
          }}>
            {[0,1,2].map((ri) => (
              <div key={ri} style={{
                height: SYMBOL_H * 3, overflow: 'hidden', position: 'relative',
                background: 'transparent',
              }}>
                {/* Stronger top/bottom dim */}
                <div style={{
                  position: 'absolute', inset: 0, zIndex: 2, pointerEvents: 'none',
                  background:
                    'linear-gradient(to bottom,' +
                    ' rgba(5,5,5,0.96) 0%,' +
                    ' rgba(5,5,5,0.88) 28%,' +
                    ' rgba(5,5,5,0.0) 38%,' +
                    ' rgba(5,5,5,0.0) 62%,' +
                    ' rgba(5,5,5,0.88) 72%,' +
                    ' rgba(5,5,5,0.96) 100%)',
                }} />
                <div style={{
                  transform: `translateY(${reelOffsets[ri]}px)`,
                  transition: animating ? `transform ${2400 + ri*150}ms cubic-bezier(.15,.55,.18,1)` : 'none',
                  willChange: 'transform',
                }}>
                  {stripRef.current[ri].map((sym, i) => (
                    <div key={i} style={{
                      height: SYMBOL_H, display: 'flex', alignItems: 'center', justifyContent: 'center',
                      fontFamily: 'var(--font-serif)', fontStyle: 'italic',
                      fontSize: 36, color: 'var(--text)',
                    }}>{sym}</div>
                  ))}
                </div>
              </div>
            ))}
          </div>

          <ResultLine result={result && { delta: result.delta, label: result.mult > 0 ? `× ${result.mult}` : '' }} />
        </div>

        <div style={{ padding: '0 0 16px' }}>
          <div className="eyebrow" style={{ padding: '0 24px 12px' }}>Stake</div>
          <BetSelector value={bet} onChange={setBet} />
        </div>
        <div style={{ padding: '8px 24px 24px', borderTop: '1px solid var(--line)' }}>
          <button className="btn" onClick={spin} disabled={spinning || !bet || bet > balance}
            style={{ width: '100%', height: 56, letterSpacing: '0.3em' }}>
            {spinning ? '· · ·' : 'Spin'}
          </button>
        </div>
      </div>
    </>
  );
}

// ═════════════════════════════════════════════════════════════
// CRAPS — pass line
// ═════════════════════════════════════════════════════════════
function Craps({ onBack, onHistory, onRules, onTip }) {
  const { balance, settle } = useStore();
  const [bet, setBet] = React.useState(null);
  const [phase, setPhase] = React.useState('come-out');
  const [point, setPoint] = React.useState(null);
  const [dice, setDice] = React.useState([3, 4]);
  const [rolling, setRolling] = React.useState(false);
  const [result, setResult] = React.useState(null);
  const [rotKey, setRotKey] = React.useState(0);

  const roll = () => {
    if (rolling || !bet || bet > balance) return;
    setRolling(true); setResult(null);
    setRotKey(k => k + 1);
    let tumbleCount = 0;
    const tumble = () => {
      setDice([1 + Math.floor(Math.random()*6), 1 + Math.floor(Math.random()*6)]);
      // Play dice click every 2 tumbles to avoid noise overload
      if (tumbleCount++ % 2 === 0) {
        try { if (typeof sounds !== 'undefined') sounds.diceRoll(); } catch (e) {}
      }
    };
    const interval = setInterval(tumble, 70);
    setTimeout(() => {
      clearInterval(interval);
      const d1 = 1 + Math.floor(Math.random()*6);
      const d2 = 1 + Math.floor(Math.random()*6);
      setDice([d1, d2]);
      const sum = d1 + d2;
      let delta = 0, label = '', nextPhase = phase, nextPoint = point;
      if (phase === 'come-out') {
        if (sum === 7 || sum === 11) { delta = bet; label = `pass (${sum})`; }
        else if (sum === 2 || sum === 3 || sum === 12) { delta = -bet; label = `craps (${sum})`; }
        else { nextPoint = sum; nextPhase = 'point'; label = `point ${sum}`; delta = 0; }
      } else {
        if (sum === point) { delta = bet; label = `point hit (${sum})`; nextPhase = 'come-out'; nextPoint = null; }
        else if (sum === 7) { delta = -bet; label = `seven-out`; nextPhase = 'come-out'; nextPoint = null; }
        else { label = `${sum}`; }
      }
      if (delta !== 0) settle('Dice', delta, label);
      setResult({ delta, label, sum });
      setPhase(nextPhase);
      setPoint(nextPoint);
      setRolling(false);
    }, 1100);
  };

  return (
    <>
      <TopBar onBack={onBack} title="DICE · PASS LINE" balance={balance} onRules={onRules} onTip={onTip} />
      <div className="stage">
        <div style={{ flex: 1, display: 'flex', flexDirection: 'column', justifyContent: 'center', alignItems: 'center', gap: 28, padding: '0 24px' }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 24 }}>
            <div style={{ textAlign: 'center', opacity: phase === 'come-out' ? 1 : 0.3, transition: 'opacity 200ms' }}>
              <div className="eyebrow">Come-out</div>
              <div style={{ fontSize: 14, marginTop: 6, color: 'var(--text-2)' }}>·</div>
            </div>
            <div style={{ width: 1, height: 28, background: 'var(--line-2)' }} />
            <div style={{ textAlign: 'center', opacity: phase === 'point' ? 1 : 0.3, transition: 'opacity 200ms' }}>
              <div className="eyebrow">Point</div>
              <div className="serif" style={{ fontSize: 18, marginTop: 0, fontStyle: 'italic' }}>{point ?? '—'}</div>
            </div>
          </div>

          <div key={rotKey} style={{ display: 'flex', gap: 18 }}>
            <Die value={dice[0]} rolling={rolling} delay={0} />
            <Die value={dice[1]} rolling={rolling} delay={120} />
          </div>

          <ResultLine result={result && { delta: result.delta, label: result.label }} />
        </div>

        <div style={{ padding: '0 0 16px' }}>
          <div className="eyebrow" style={{ padding: '0 24px 12px' }}>Pass-line stake</div>
          <BetSelector value={bet} onChange={setBet} />
        </div>
        <div style={{ padding: '8px 24px 24px', borderTop: '1px solid var(--line)' }}>
          <button className="btn" onClick={roll} disabled={rolling || !bet || bet > balance}
            style={{ width: '100%', height: 56, letterSpacing: '0.3em' }}>
            {rolling ? '· · ·' : (phase === 'come-out' ? 'Roll' : 'Roll for point')}
          </button>
        </div>
      </div>
    </>
  );
}

function Die({ value, rolling, delay }) {
  const pips = {
    1: [[1,1]],
    2: [[0,0],[2,2]],
    3: [[0,0],[1,1],[2,2]],
    4: [[0,0],[0,2],[2,0],[2,2]],
    5: [[0,0],[0,2],[1,1],[2,0],[2,2]],
    6: [[0,0],[0,2],[1,0],[1,2],[2,0],[2,2]],
  }[value] || [];
  return (
    <div style={{
      width: 88, height: 88,
      background: '#0a0a0a',
      border: '1px solid var(--line-2)',
      borderRadius: 14,
      position: 'relative',
      transform: rolling ? `rotate(${(Math.random()-0.5)*30}deg)` : 'rotate(0deg)',
      transition: `transform ${rolling ? 80 : 280}ms ease`,
      transitionDelay: `${delay}ms`,
      padding: 14,
    }}>
      <div style={{
        position: 'relative', width: '100%', height: '100%',
        display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gridTemplateRows: 'repeat(3, 1fr)',
      }}>
        {pips.map(([r, c], i) => (
          <div key={i} style={{
            gridColumn: c+1, gridRow: r+1,
            alignSelf: 'center', justifySelf: 'center',
            width: 8, height: 8, borderRadius: '50%',
            background: 'var(--text)',
          }} />
        ))}
      </div>
    </div>
  );
}

// ═════════════════════════════════════════════════════════════
// CRASH — multiplier rises until it crashes
// ═════════════════════════════════════════════════════════════
function Crash({ onBack, onHistory, onRules, onTip }) {
  const { balance, settle } = useStore();
  const [bet, setBet] = React.useState(null);
  const [autoCashout, setAutoCashout] = React.useState(0); // 0 = manual
  const [phase, setPhase] = React.useState('bet'); // bet | running | crashed | cashed
  const [multiplier, setMultiplier] = React.useState(1.00);
  const [pathPoints, setPathPoints] = React.useState([]);
  const [result, setResult] = React.useState(null);

  const startRef = React.useRef(0);
  const rafRef = React.useRef(0);
  const crashRef = React.useRef(0);
  const acRef = React.useRef(0);

  React.useEffect(() => { acRef.current = autoCashout; }, [autoCashout]);
  React.useEffect(() => () => cancelAnimationFrame(rafRef.current), []);

  // Crash distribution: P(crash >= m) = 0.99 / m, with 1% instant crash for house edge
  const generateCrashPoint = () => {
    const r = Math.random();
    if (r < 0.01) return 1.00;
    return Math.max(1.00, 0.99 / (1 - r));
  };

  const start = () => {
    if (!bet || bet > balance) return;
    const cp = generateCrashPoint();
    crashRef.current = cp;
    setMultiplier(1.00);
    setPathPoints([[0, 1]]);
    setResult(null);
    setPhase('running');
    startRef.current = performance.now();

    // Continuous rising-tick sound — interval shortens as multiplier grows
    let lastTickAt = performance.now();

    const tick = (t) => {
      const elapsed = (t - startRef.current) / 1000;
      const m = Math.exp(0.085 * elapsed);

      // Rising tick: tighter spacing as m grows. ~500ms at 1×, ~120ms at 10×
      try {
        const now = performance.now();
        const tickInterval = Math.max(110, 600 / Math.pow(m, 0.55));
        if (now - lastTickAt >= tickInterval) {
          lastTickAt = now;
          if (typeof sounds !== 'undefined') sounds.crashRise(m);
        }
      } catch (e) {}

      if (m >= crashRef.current) {
        setMultiplier(crashRef.current);
        setPathPoints((pp) => [...pp, [elapsed, crashRef.current]]);
        try { if (typeof sounds !== 'undefined') sounds.crash(); } catch (e) {}
        const delta = -bet;
        settle('Crash', delta, `crashed at ${crashRef.current.toFixed(2)}×`);
        setResult({ delta, label: `crashed at ${crashRef.current.toFixed(2)}×` });
        setPhase('crashed');
        return;
      }

      if (acRef.current > 1 && m >= acRef.current) {
        cashOutAt(acRef.current, elapsed);
        return;
      }

      setMultiplier(m);
      setPathPoints((pp) => {
        const last = pp[pp.length - 1];
        if (!last || elapsed - last[0] > 0.05) return [...pp, [elapsed, m]];
        return pp;
      });
      rafRef.current = requestAnimationFrame(tick);
    };
    rafRef.current = requestAnimationFrame(tick);
  };

  const cashOutAt = (m, elapsed) => {
    cancelAnimationFrame(rafRef.current);
    setMultiplier(m);
    setPathPoints((pp) => [...pp, [elapsed, m]]);
    const delta = Math.floor(bet * m - bet);
    settle('Crash', delta, `cash · ${m.toFixed(2)}×`);
    setResult({ delta, label: `${m.toFixed(2)}× · cashed` });
    setPhase('cashed');
  };

  const cashOut = () => {
    if (phase !== 'running') return;
    const elapsed = (performance.now() - startRef.current) / 1000;
    cashOutAt(multiplier, elapsed);
  };

  const newRound = () => {
    setPhase('bet'); setMultiplier(1.00); setPathPoints([]); setResult(null);
  };

  const svgPath = React.useMemo(() => {
    if (pathPoints.length < 2) return '';
    const maxT = Math.max(pathPoints[pathPoints.length - 1][0], 3);
    const maxM = Math.max(pathPoints[pathPoints.length - 1][1], 1.4);
    const w = 280, h = 100;
    return pathPoints.map(([t, m], i) => {
      const x = (t / maxT) * w;
      const y = h - ((m - 1) / (maxM - 1 + 0.001)) * h;
      return (i === 0 ? 'M' : 'L') + x.toFixed(1) + ' ' + y.toFixed(1);
    }).join(' ');
  }, [pathPoints]);

  const isCrashed = phase === 'crashed';
  const isCashed = phase === 'cashed';
  const heroColor = isCrashed ? '#b85450' : (isCashed ? 'var(--win)' : 'var(--text)');
  const lineColor = isCrashed ? '#b85450' : (isCashed ? 'var(--accent)' : 'var(--text)');

  return (
    <>
      <TopBar onBack={onBack} title="CRASH" balance={balance} onRules={onRules} onTip={onTip} />
      <div className="stage">
        <div style={{ flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', padding: '0 24px', gap: 22 }}>
          <div style={{ textAlign: 'center' }}>
            <div className="serif" style={{
              fontStyle: 'italic', fontSize: 84, lineHeight: 1,
              letterSpacing: '-0.03em', color: heroColor, fontWeight: 400,
              transition: 'color 240ms', fontVariantNumeric: 'tabular-nums',
            }}>
              {multiplier.toFixed(2)}<span style={{ fontSize: 44, color: 'var(--text-3)', marginLeft: 6 }}>×</span>
            </div>
            <div className="mono" style={{
              fontSize: 10, letterSpacing: '0.22em', textTransform: 'uppercase',
              color: 'var(--text-4)', marginTop: 10,
            }}>
              {phase === 'bet' ? 'Stake then start' :
               phase === 'running' ? 'Cash before crash' :
               isCrashed ? 'Crashed' : 'Cashed out'}
            </div>
          </div>

          <div style={{ width: 280, height: 100, position: 'relative' }}>
            <svg width="280" height="100" viewBox="0 0 280 100" style={{ overflow: 'visible' }}>
              <line x1="0" y1="100" x2="280" y2="100" stroke="var(--line)" strokeWidth="1" />
              <line x1="0" y1="0" x2="0" y2="100" stroke="var(--line)" strokeWidth="1" />
              {svgPath && (
                <path
                  d={svgPath}
                  fill="none"
                  stroke={lineColor}
                  strokeWidth="1.5"
                  strokeLinecap="round"
                  strokeLinejoin="round"
                />
              )}
            </svg>
          </div>

          <div style={{ minHeight: 22, textAlign: 'center' }}>
            {result ? <ResultLine result={{ delta: result.delta, label: result.label }} /> : <div style={{ height: 18 }} />}
          </div>
        </div>

        {phase === 'bet' && (
          <>
            <div style={{ padding: '0 24px 14px' }}>
              <div className="eyebrow" style={{ marginBottom: 10 }}>Auto cash at</div>
              <div style={{ display: 'flex', gap: 6, justifyContent: 'space-between' }}>
                {[
                  { v: 0,    label: 'Off' },
                  { v: 1.5,  label: '1.5×' },
                  { v: 2,    label: '2×' },
                  { v: 5,    label: '5×' },
                  { v: 10,   label: '10×' },
                ].map((opt) => (
                  <button key={opt.v}
                    className={'chip press' + (autoCashout === opt.v ? ' active' : '')}
                    onClick={() => setAutoCashout(opt.v)}>{opt.label}</button>
                ))}
              </div>
            </div>
            <div style={{ padding: '0 0 16px' }}>
              <div className="eyebrow" style={{ padding: '0 24px 12px' }}>Stake</div>
              <BetSelector value={bet} onChange={setBet} />
            </div>
            <div style={{ padding: '8px 24px 24px', borderTop: '1px solid var(--line)' }}>
              <button className="btn" onClick={start} disabled={!bet || bet > balance}
                style={{ width: '100%', height: 56, letterSpacing: '0.3em' }}>Start</button>
            </div>
          </>
        )}

        {phase === 'running' && (
          <div style={{ padding: '8px 24px 24px', borderTop: '1px solid var(--line)' }}>
            <button className="btn primary" onClick={cashOut}
              style={{ width: '100%', height: 56, letterSpacing: '0.3em' }}>
              Cash {Math.floor(bet * multiplier).toLocaleString('en-US')}
            </button>
          </div>
        )}

        {(isCrashed || isCashed) && (
          <div style={{ padding: '8px 24px 24px', borderTop: '1px solid var(--line)' }}>
            <button className="btn primary" onClick={newRound}
              style={{ width: '100%', height: 56, letterSpacing: '0.3em' }}>New Round</button>
          </div>
        )}
      </div>
    </>
  );
}

// ═════════════════════════════════════════════════════════════
// LIMBO — predict a multiplier, beat the random
// ═════════════════════════════════════════════════════════════
function Limbo({ onBack, onHistory, onRules, onTip }) {
  const { balance, settle } = useStore();
  const [bet, setBet] = React.useState(null);
  const [target, setTarget] = React.useState(2.00);
  const [phase, setPhase] = React.useState('bet'); // bet | rolling | done
  const [rolled, setRolled] = React.useState(1.00);
  const [result, setResult] = React.useState(null);
  const rafRef = React.useRef(0);

  React.useEffect(() => () => cancelAnimationFrame(rafRef.current), []);

  // Same distribution as Crash: P(roll >= m) = 0.99 / m
  const generateRoll = () => {
    const r = Math.random();
    if (r < 0.01) return 1.00;
    return Math.max(1.00, 0.99 / (1 - r));
  };

  const start = () => {
    if (!bet || bet > balance || target < 1.10) return;
    const final = generateRoll();
    setPhase('rolling');
    setResult(null);
    try { if (typeof sounds !== 'undefined') sounds.spinStart(); } catch (e) {}

    const startTime = performance.now();
    const dur = 1400;
    const startVal = 1.00;

    const tick = (t) => {
      const k = Math.min(1, (t - startTime) / dur);
      const eased = 1 - Math.pow(1 - k, 3);
      const cur = startVal + (final - startVal) * eased;
      setRolled(cur);
      if (k < 1) {
        rafRef.current = requestAnimationFrame(tick);
      } else {
        setRolled(final);
        const win = final >= target;
        const delta = win ? Math.floor(bet * target - bet) : -bet;
        settle('Limbo', delta, `${final.toFixed(2)}× vs ${target.toFixed(2)}×`);
        setResult({ delta, label: `${final.toFixed(2)}× · target ${target.toFixed(2)}×`, win });
        setPhase('done');
      }
    };
    rafRef.current = requestAnimationFrame(tick);
  };

  const newRound = () => {
    setPhase('bet'); setRolled(1.00); setResult(null);
  };

  const isLost = result && !result.win;
  const isWon = result && result.win;
  const heroColor = isLost ? '#b85450' : (isWon ? 'var(--win)' : 'var(--text)');

  const stepTarget = (delta) => {
    let v = +(target + delta).toFixed(2);
    if (v < 1.10) v = 1.10;
    if (v > 1000) v = 1000;
    setTarget(v);
  };

  return (
    <>
      <TopBar onBack={onBack} title="LIMBO" balance={balance} onRules={onRules} onTip={onTip} />
      <div className="stage">
        <div style={{ flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', padding: '0 24px', gap: 28 }}>
          <div style={{ textAlign: 'center' }}>
            <div className="serif" style={{
              fontStyle: 'italic', fontSize: 96, lineHeight: 1,
              letterSpacing: '-0.03em', color: heroColor, fontWeight: 400,
              transition: 'color 240ms', fontVariantNumeric: 'tabular-nums',
            }}>
              {rolled.toFixed(2)}<span style={{ fontSize: 52, color: 'var(--text-3)', marginLeft: 6 }}>×</span>
            </div>
            <div className="mono" style={{
              fontSize: 10, letterSpacing: '0.22em', textTransform: 'uppercase',
              color: 'var(--text-4)', marginTop: 12,
            }}>
              {phase === 'bet' ? `target ${target.toFixed(2)}×` :
               phase === 'rolling' ? '·' :
               isWon ? `target ${target.toFixed(2)}× · over` : `target ${target.toFixed(2)}× · under`}
            </div>
          </div>

          <div style={{ minHeight: 22, textAlign: 'center' }}>
            {result ? <ResultLine result={{ delta: result.delta, label: result.label }} /> : <div style={{ height: 18 }} />}
          </div>
        </div>

        {phase === 'bet' && (
          <>
            <div style={{ padding: '0 24px 14px' }}>
              <div className="eyebrow" style={{ marginBottom: 10 }}>Target multiplier</div>
              <div style={{
                display: 'flex', alignItems: 'center',
                border: '1px solid var(--line)', height: 56,
              }}>
                <button className="press" onClick={() => stepTarget(-0.25)}
                  style={{
                    flex: '0 0 56px', height: '100%',
                    background: 'transparent',
                    color: 'var(--text)', fontSize: 13,
                    fontFamily: 'var(--font-mono)',
                    borderRight: '1px solid var(--line)',
                  }}>−</button>
                <input
                  className="mono"
                  type="number"
                  step="0.01"
                  min="1.10"
                  max="1000"
                  value={target}
                  onChange={(e) => {
                    const v = parseFloat(e.target.value);
                    if (!Number.isNaN(v)) setTarget(Math.max(1.10, Math.min(1000, v)));
                  }}
                  style={{
                    flex: 1, textAlign: 'center', fontSize: 22, color: 'var(--text)',
                    background: 'transparent', border: 0, outline: 0,
                    fontVariantNumeric: 'tabular-nums', letterSpacing: '0.02em',
                  }}
                />
                <span style={{ fontSize: 14, color: 'var(--text-3)', marginRight: 12 }}>×</span>
                <button className="press" onClick={() => stepTarget(0.25)}
                  style={{
                    flex: '0 0 56px', height: '100%',
                    background: 'transparent',
                    color: 'var(--text)', fontSize: 13,
                    fontFamily: 'var(--font-mono)',
                    borderLeft: '1px solid var(--line)',
                  }}>+</button>
              </div>
              <div className="mono" style={{ fontSize: 10, color: 'var(--text-4)', letterSpacing: '0.06em', marginTop: 8, textAlign: 'right' }}>
                win chance · {(99 / target).toFixed(2)}%
              </div>
            </div>
            <div style={{ padding: '0 0 16px' }}>
              <div className="eyebrow" style={{ padding: '0 24px 12px' }}>Stake</div>
              <BetSelector value={bet} onChange={setBet} />
            </div>
            <div style={{ padding: '8px 24px 24px', borderTop: '1px solid var(--line)' }}>
              <button className="btn" onClick={start} disabled={!bet || bet > balance || target < 1.10}
                style={{ width: '100%', height: 56, letterSpacing: '0.3em' }}>Roll</button>
            </div>
          </>
        )}

        {phase === 'rolling' && (
          <div style={{ padding: '8px 24px 24px', borderTop: '1px solid var(--line)' }}>
            <button className="btn" disabled style={{ width: '100%', height: 56, letterSpacing: '0.3em' }}>· · ·</button>
          </div>
        )}

        {phase === 'done' && (
          <div style={{ padding: '8px 24px 24px', borderTop: '1px solid var(--line)' }}>
            <button className="btn primary" onClick={newRound}
              style={{ width: '100%', height: 56, letterSpacing: '0.3em' }}>New Round</button>
          </div>
        )}
      </div>
    </>
  );
}

Object.assign(window, { CoinFlip, Slots, Craps, Crash, Limbo });
