// CREST Guided Tour — Certification Test
// A scripted, interactive 5-over scoring drill. Coach overlay highlights what
// to tap; advancing only happens when the user clicks the right thing.
// End: a shareable "CREST CERTIFIED · SCORER" certificate.

const { useState, useEffect, useRef, useCallback, useMemo } = React;

// ─── Coach overlay ───────────────────────────────────────────────────────────
// Spotlight + speech bubble pinned to a target rect (looked up by data-cert).
function CoachOverlay({ targetSel, instruction, sub, stepN, totalN, side = 'top', onSkip }) {
  const [rect, setRect] = useState(null);
  const tipRef = useRef(null);

  useEffect(() => {
    if (!targetSel) { setRect(null); return; }
    let raf = 0;
    const measure = () => {
      const el = document.querySelector(targetSel);
      if (!el) { setRect(null); return; }
      const r = el.getBoundingClientRect();
      setRect({
        x: r.left, y: r.top, w: r.width, h: r.height,
        cx: r.left + r.width/2, cy: r.top + r.height/2,
      });
    };
    measure();
    const loop = () => { measure(); raf = requestAnimationFrame(loop); };
    raf = requestAnimationFrame(loop);
    return () => cancelAnimationFrame(raf);
  }, [targetSel, instruction]);

  // Choose bubble position
  const tip = useMemo(() => {
    if (!rect) return null;
    const W = window.innerWidth, H = window.innerHeight;
    const pad = 16;
    let x, y, anchor;
    if (side === 'auto' || !side) {
      // Pick the side with most room
      const above = rect.y;
      const below = H - (rect.y + rect.h);
      anchor = above > below ? 'top' : 'bottom';
    } else {
      anchor = side;
    }
    if (anchor === 'top')    { x = Math.min(Math.max(rect.cx, 180), W-180); y = Math.max(rect.y - pad, 100); }
    else if (anchor === 'bottom') { x = Math.min(Math.max(rect.cx, 180), W-180); y = Math.min(rect.y + rect.h + pad, H-160); }
    else if (anchor === 'left')   { x = Math.max(rect.x - pad, 180); y = Math.min(Math.max(rect.cy, 80), H-100); }
    else                           { x = Math.min(rect.x + rect.w + pad, W-180); y = Math.min(Math.max(rect.cy, 80), H-100); }
    return { x, y, anchor };
  }, [rect, side]);

  // SVG mask cutout — full-screen dark with target hole
  const W = window.innerWidth, H = window.innerHeight;
  const holePad = 8;

  return (
    <div className="ct-coach" aria-live="polite">
      {/* Subtle radial vignette around the target — no full-page mask */}
      {rect && (
        <div
          className="ct-coach-vignette"
          style={{
            background: `radial-gradient(circle ${Math.max(rect.w, rect.h) * 1.4}px at ${rect.cx}px ${rect.cy}px, transparent 0%, transparent 60%, rgba(2,4,10,0.20) 100%)`,
          }}
        />
      )}

      {rect && (
        <>
          <div
            className="ct-coach-ring"
            style={{
              left: rect.x - holePad, top: rect.y - holePad,
              width: rect.w + holePad*2, height: rect.h + holePad*2,
            }}
          />
          <div
            className="ct-coach-finger"
            style={{
              left: tip.anchor === 'right'  ? rect.x + rect.w + 4 :
                    tip.anchor === 'left'   ? rect.x - 22 :
                                              rect.cx - 11,
              top:  tip.anchor === 'bottom' ? rect.y + rect.h + 4 :
                    tip.anchor === 'top'    ? rect.y - 22 :
                                              rect.cy - 11,
              transform: tip.anchor === 'left' ? 'rotate(-90deg)' :
                         tip.anchor === 'right' ? 'rotate(90deg)' :
                         tip.anchor === 'bottom' ? 'rotate(180deg)' : 'none',
            }}
            aria-hidden="true"
          >
            <svg viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="#F59E0B" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
              <path d="M12 3v14"/><path d="M6 11l6 6 6-6"/>
            </svg>
          </div>
        </>
      )}

      {tip && (
        <div
          ref={tipRef}
          className={`ct-coach-tip ct-tip-${tip.anchor}`}
          style={{ left: tip.x, top: tip.y }}
        >
          <div className="ct-tip-head">
            <span className="ct-tip-step">STEP {String(stepN).padStart(2,'0')} / {String(totalN).padStart(2,'0')}</span>
            {onSkip && <button className="ct-tip-skip" onClick={onSkip}>SKIP DRILL ›</button>}
          </div>
          <div className="ct-tip-body">{instruction}</div>
          {sub && <div className="ct-tip-sub">{sub}</div>}
        </div>
      )}
    </div>
  );
}

// ─── Scoring data ────────────────────────────────────────────────────────────

const BATTERS = [
  { name: 'A. Hughes', r:0, b:0, fours:0, sixes:0, out:false, how:null },
  { name: 'J. Whitaker', r:0, b:0, fours:0, sixes:0, out:false, how:null },
  { name: 'A. Malhotra', r:0, b:0, fours:0, sixes:0, out:false, how:null },
  { name: 'O. Grant', r:0, b:0, fours:0, sixes:0, out:false, how:null },
  { name: 'R. Iyer', r:0, b:0, fours:0, sixes:0, out:false, how:null },
  { name: 'K. Deshpande', r:0, b:0, fours:0, sixes:0, out:false, how:null },
  { name: 'S. Mehta', r:0, b:0, fours:0, sixes:0, out:false, how:null },
  { name: 'N. Perera', r:0, b:0, fours:0, sixes:0, out:false, how:null },
  { name: 'T. Bradley', r:0, b:0, fours:0, sixes:0, out:false, how:null },
  { name: 'M. Roper', r:0, b:0, fours:0, sixes:0, out:false, how:null },
  { name: 'N. Cole', r:0, b:0, fours:0, sixes:0, out:false, how:null },
];
const BOWLERS = [
  { name: 'Bell',   o:0, m:0, r:0, w:0 },
  { name: 'Carter', o:0, m:0, r:0, w:0 },
  { name: 'Davies', o:0, m:0, r:0, w:0 },
  { name: 'Evans',  o:0, m:0, r:0, w:0 },
  { name: 'Foster', o:0, m:0, r:0, w:0 },
];

// Each instruction tells the user EXACTLY what button to tap.
// `target` is a data-cert attr selector. `delta` mutates the live scorecard
// once the user taps. `legal` = does this count as a ball faced.
// `modal` opens an overlay; `closeModal` advances back.
// The 5-over script — 30 legal balls — woven with every feature.
const SCRIPT = [
  // OVER 1 — Ringer 1
  { kind:'ball', target:'[data-cert="key-1"]', tip:'Score a single. Tap 1.', delta:{ runs:1, b:1, sr:1, swap:true } },
  { kind:'feature', target:'[data-cert="btn-pulse"]', tip:'Open CrestPulse™ to read live momentum.', sub:'A new feature debuts every over — get a feel for it.', modal:'pulse' },
  { kind:'closeModal', target:'[data-cert="modal-close"]', tip:'Pulse is climbing. Close to continue.' },
  { kind:'ball', target:'[data-cert="key-WD"]', tip:'Loose delivery — tap WIDE.', delta:{ runs:1, extras:1 }, legal:false },
  { kind:'ball', target:'[data-cert="key-4"]', tip:'Boundary! Tap 4.', delta:{ runs:4, b:1, sr:4, fours:1 } },
  { kind:'ball', target:'[data-cert="key-1"]', tip:'Rotate strike. Tap 1.', delta:{ runs:1, b:1, sr:1, swap:true } },
  { kind:'ball', target:'[data-cert="key-0"]', tip:'Tight delivery — tap 0 (dot ball).', delta:{ b:1 } },
  { kind:'ball', target:'[data-cert="key-2"]', tip:'Quick two. Tap 2.', delta:{ runs:2, b:1, sr:2 } },
  { kind:'ball', target:'[data-cert="key-6"]', tip:'Last ball — tap 6 to finish the over with a six.', delta:{ runs:6, b:1, sr:6, sixes:1 } },
  // End of over 1
  { kind:'feature', target:'[data-cert="btn-bowler"]', tip:'Over complete. Tap CHANGE BOWLER.', sub:'CREST closes the over and prompts for the next bowler.', modal:'bowler' },
  { kind:'closeModal', target:'[data-cert="modal-pick-Ringer 2"]', tip:'Pick RINGER 2 for the next over.' },

  // OVER 2 — Ringer 2
  { kind:'ball', target:'[data-cert="key-1"]', tip:'Single off the first ball. Tap 1.', delta:{ runs:1, b:1, sr:1, swap:true } },
  { kind:'feature', target:'[data-cert="btn-undo"]', tip:'Oops — you meant 2. Tap UNDO.', sub:'Every action is reversible. Click UNDO once.' , action:'undo' },
  { kind:'ball', target:'[data-cert="key-2"]', tip:'Now log the correct value. Tap 2.', delta:{ runs:2, b:1, sr:2 } },
  { kind:'ball', target:'[data-cert="key-NB"]', tip:'Bowler oversteps — tap NO BALL.', delta:{ runs:1, extras:1 }, legal:false },
  { kind:'ball', target:'[data-cert="key-4"]', tip:'Free hit — punished for four. Tap 4.', delta:{ runs:4, b:1, sr:4, fours:1 } },
  { kind:'feature', target:'[data-cert="btn-crestsmart"]', tip:'Tap CRESTSMART to see the live milestone panel.', sub:'CrestSmart auto-surfaces partnerships, milestones and run-rate context.', modal:'smart' },
  { kind:'closeModal', target:'[data-cert="modal-close"]', tip:'Got it. Close CrestSmart to continue.' },
  { kind:'ball', target:'[data-cert="key-1"]', tip:'Push for one. Tap 1.', delta:{ runs:1, b:1, sr:1, swap:true } },
  { kind:'ball', target:'[data-cert="key-0"]', tip:'Defended back — tap 0.', delta:{ b:1 } },
  { kind:'ball', target:'[data-cert="key-W"]', tip:'WICKET! Tap W to bring up the dismissal panel.', modal:'wicket' },
  { kind:'closeModal', target:'[data-cert="modal-pick-Caught"]', tip:'Pick CAUGHT — keeper takes the edge.', action:'wicket' },
  { kind:'feature', target:'[data-cert="btn-drinks"]', tip:'End of the 2nd over — DRINKS BREAK. Tap DRINKS.', sub:'Match pauses; we resume in a moment.', modal:'drinks' },
  { kind:'closeModal', target:'[data-cert="modal-close"]', tip:'Resume play — tap PLAY ON.' },
  { kind:'feature', target:'[data-cert="btn-bowler"]', tip:'Pick a bowler for the 3rd over.', modal:'bowler' },
  { kind:'closeModal', target:'[data-cert="modal-pick-Ringer 3"]', tip:'Bring on RINGER 3.' },

  // OVER 3 — Ringer 3 (light coach, the user is getting it)
  { kind:'ball', target:'[data-cert="key-1"]', tip:'Tap 1.', delta:{ runs:1, b:1, sr:1, swap:true } },
  { kind:'ball', target:'[data-cert="key-4"]', tip:'Tap 4.', delta:{ runs:4, b:1, sr:4, fours:1 } },
  { kind:'feature', target:'[data-cert="btn-swap"]', tip:'Batters crossed during the throw. Tap SWAP STRIKE.', sub:'Manually swap when CREST cannot infer the cross.', action:'swap' },
  { kind:'ball', target:'[data-cert="key-2"]', tip:'Tap 2.', delta:{ runs:2, b:1, sr:2 } },
  { kind:'ball', target:'[data-cert="key-0"]', tip:'Tap 0.', delta:{ b:1 } },
  { kind:'ball', target:'[data-cert="key-1"]', tip:'Tap 1.', delta:{ runs:1, b:1, sr:1, swap:true } },
  { kind:'ball', target:'[data-cert="key-6"]', tip:'Tap 6 — finish the over.', delta:{ runs:6, b:1, sr:6, sixes:1 } },

  // OVER 4 — Ringer 4
  { kind:'feature', target:'[data-cert="btn-bowler"]', tip:'Change bowler.', modal:'bowler' },
  { kind:'closeModal', target:'[data-cert="modal-pick-Ringer 4"]', tip:'Bring on RINGER 4.' },
  { kind:'ball', target:'[data-cert="key-4"]', tip:'Tap 4.', delta:{ runs:4, b:1, sr:4, fours:1 } },
  { kind:'ball', target:'[data-cert="key-W"]', tip:'WICKET — tap W.', modal:'wicket' },
  { kind:'closeModal', target:'[data-cert="modal-pick-Bowled"]', tip:'BOWLED — stumps cartwheel.', action:'wicket' },
  { kind:'ball', target:'[data-cert="key-0"]', tip:'New batter sees one off. Tap 0.', delta:{ b:1 } },
  { kind:'ball', target:'[data-cert="key-1"]', tip:'Tap 1.', delta:{ runs:1, b:1, sr:1, swap:true } },
  { kind:'ball', target:'[data-cert="key-2"]', tip:'Tap 2.', delta:{ runs:2, b:1, sr:2 } },
  { kind:'ball', target:'[data-cert="key-4"]', tip:'Tap 4 — over done.', delta:{ runs:4, b:1, sr:4, fours:1 } },

  // OVER 5 — Ringer 5 (final over)
  { kind:'feature', target:'[data-cert="btn-bowler"]', tip:'Last over. Bring on the death bowler.', modal:'bowler' },
  { kind:'closeModal', target:'[data-cert="modal-pick-Ringer 5"]', tip:'Bring on RINGER 5.' },
  { kind:'ball', target:'[data-cert="key-6"]', tip:'Tap 6.', delta:{ runs:6, b:1, sr:6, sixes:1 } },
  { kind:'ball', target:'[data-cert="key-4"]', tip:'Tap 4.', delta:{ runs:4, b:1, sr:4, fours:1 } },
  { kind:'ball', target:'[data-cert="key-1"]', tip:'Tap 1.', delta:{ runs:1, b:1, sr:1, swap:true } },
  { kind:'ball', target:'[data-cert="key-6"]', tip:'Tap 6.', delta:{ runs:6, b:1, sr:6, sixes:1 } },
  { kind:'ball', target:'[data-cert="key-2"]', tip:'Tap 2.', delta:{ runs:2, b:1, sr:2 } },
  { kind:'ball', target:'[data-cert="key-4"]', tip:'Last ball. Tap 4 — finish in style.', delta:{ runs:4, b:1, sr:4, fours:1 } },
];

// ─── Stage components ───────────────────────────────────────────────────────

const TEAM_A = { name: 'CREST STRIKERS', short: 'STR' };
const TEAM_B = { name: 'CREST THUNDERS', short: 'THU' };

function IntroStage({ onStart }) {
  return (
    <div className="ct-intro">
      <div className="ct-intro-grid">
        <div className="ct-intro-left">
          <div className="ct-intro-eyebrow">★ FINAL DRILL · CREST CERTIFIED</div>
          <h1 className="ct-intro-title">
            Score a live <span className="ct-accent">5-over</span> match.
            <br/>Earn the badge.
          </h1>
          <p className="ct-intro-body">
            We'll set up a quick match between <b>Crest Strikers</b> and <b>Crest Thunders</b>.
            You'll score every ball in advanced mode — wides, no-balls, undo, drinks,
            strike rotation, bowler changes — and meet CrestPulse™ and CrestSmart™
            live as the match unfolds. Finish all five overs and you'll get a
            shareable certificate.
          </p>
          <ul className="ct-intro-list">
            <li><span className="ct-intro-check">✓</span> Match setup &amp; squad confirmation</li>
            <li><span className="ct-intro-check">✓</span> 30 legal balls in advanced scoring</li>
            <li><span className="ct-intro-check">✓</span> Every key control: WD · NB · UNDO · SWAP · DRINKS</li>
            <li><span className="ct-intro-check">✓</span> Post-match analytics tour &amp; broadcast exports</li>
          </ul>
          <button className="ct-intro-cta" onClick={onStart}>
            BEGIN DRILL
            <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg>
          </button>
          <div className="ct-intro-meta">≈ 3–4 minutes · You can skip any time</div>
        </div>
        <div className="ct-intro-right" aria-hidden="true">
          <div className="ct-intro-cert">
            <div className="ct-intro-cert-eye">CERTIFICATE OF PROFICIENCY</div>
            <div className="ct-intro-cert-lock">
              <svg viewBox="0 0 24 24" width="42" height="42" fill="none" stroke="#F59E0B" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
                <rect x="4" y="10" width="16" height="11" rx="2"/>
                <path d="M8 10V7a4 4 0 0 1 8 0v3"/>
              </svg>
            </div>
            <div className="ct-intro-cert-lab">— LOCKED —</div>
            <div className="ct-intro-cert-name">YOUR NAME HERE</div>
            <div className="ct-intro-cert-sub">CREST CERTIFIED · SCORER</div>
          </div>
        </div>
      </div>
    </div>
  );
}

// ─── Setup stage — real form, real required fields ───────────────────────

// Pre-canned opposition options so the user doesn't have to type from scratch
// but still makes the choice. Same for venue.
const OPP_TEAMS = [
  { name: 'CREST THUNDERS',       short: 'THU', logo: 'T' },
  { name: 'CREST CHARGERS',       short: 'CHG', logo: 'C' },
  { name: 'CREST FALCONS',        short: 'FAL', logo: 'F' },
  { name: 'CREST MAVERICKS',      short: 'MAV', logo: 'M' },
  { name: 'CREST WARRIORS',       short: 'WAR', logo: 'W' },
  { name: 'CREST TITANS',         short: 'TIT', logo: 'T' },
];
const VENUES = [
  'Crest Oval',
  'Crest Cricket Ground',
  'Crest Park',
  'Crest Stadium',
  'Crest Arena',
];
// Match types — drive totalInnings and whether overs apply.
const MATCH_TYPES = [
  { id: 'LIMITED', label: 'Limited Overs', sub: 'One innings per side',  innings: 1 },
  { id: 'TWO_INN', label: 'Two Innings',   sub: 'Club two-innings game', innings: 2 },
  { id: 'TEST',    label: 'Multi-day · Test', sub: 'Unlimited overs · 2 innings', innings: 2 },
];
// Format presets — only meaningful for LIMITED + TWO_INN. Test has no overs cap.
const FORMATS = [
  { id: 'T10', label: 'T10', overs: 10 },
  { id: 'T20', label: 'T20', overs: 20 },
  { id: 'ODI', label: 'ODI', overs: 50 },
  { id: 'CUSTOM', label: 'Custom', overs: null },
];
const COMPS = ['LEAGUE', 'CUP', 'FRIENDLY'];

function SetupStage({ initial, onConfirm, onBack }) {
  const [matchType, setMatchType] = useState(initial?.matchType || 'LIMITED');
  const [opp, setOpp]         = useState(initial?.opp || '');
  const [venue, setVenue]     = useState(initial?.venue || '');
  const [format, setFormat]   = useState(initial?.format || 'T20');
  const [comp, setComp]       = useState(initial?.comp || 'FRIENDLY');
  const [date]                = useState('SAT 24 MAY · 14:00');

  const isTest = matchType === 'TEST';
  const matchTypeObj = MATCH_TYPES.find(m => m.id === matchType);
  const innings = matchTypeObj?.innings || 1;

  // Overs: explicit field. Auto-derives from format preset on change.
  const formatObj = FORMATS.find(f => f.id === format);
  const [overs, setOvers] = useState(initial?.overs || formatObj?.overs || 20);

  // When format preset changes (and not Custom), sync overs to preset default.
  React.useEffect(() => {
    if (isTest) return; // Test ignores overs
    if (formatObj && formatObj.overs != null) setOvers(formatObj.overs);
  }, [format, isTest, formatObj]);

  const oppObj = OPP_TEAMS.find(o => o.name === opp);
  // Mandatory: matchType, opp, venue. Overs mandatory unless Test.
  const oversOK = isTest || (overs >= 1 && overs <= 50);
  const valid = matchType && opp && venue && oversOK;

  // Track which fields the user touched, so we don't scream "required" at first paint.
  const [touched, setTouched] = useState({ opp:false, venue:false, overs:false });
  const touch = (k) => setTouched(t => ({ ...t, [k]: true }));

  // Friendly label of competition
  const compHint = comp === 'LEAGUE' ? 'Counts toward standings.' : comp === 'CUP' ? 'Knockout — every ball matters.' : 'Warm-up — relaxed scoring.';

  return (
    <div className="ct-setup">

      <div className="ct-setup-card ct-setup-card-wide">
        <button className="ct-back ct-back-inline" onClick={onBack}>
          <svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M15 18l-6-6 6-6"/></svg>
          Back
        </button>
        <div className="ct-stage-eye">SCOREBOOK · MATCH DETAILS</div>
        <h2 className="ct-stage-title">New match</h2>
        <p className="ct-stage-sub">
          A real Scorebook starts here. Items tagged <span className="ct-req ct-req-inline">required</span> are
          mandatory — the engine needs them to score a ball. Everything else has sensible defaults.
        </p>

        {/* Two-column grid: left = teams/venue, right = match shape */}
        <div className="ct-setup-grid">
          {/* ── LEFT column ───────────────────────────────────────── */}
          <div className="ct-setup-col">
            <div className="ct-setup-col-eye">WHO &amp; WHERE</div>

            {/* Home team is fixed */}
            <div className="ct-field">
              <label className="ct-field-lab">YOUR TEAM</label>
              <div className="ct-field-fixed">
                <span className="ct-team-chip ct-team-chip-a">B</span>
                <div>
                  <div className="ct-field-fixed-name">CREST STRIKERS</div>
                  <div className="ct-field-fixed-sub">Your club · auto-selected</div>
                </div>
              </div>
            </div>

            {/* Opposition — required */}
            <div className="ct-field">
              <label className="ct-field-lab">
                OPPOSITION <span className="ct-req">required</span>
              </label>
              <div className={`ct-chips ${touched.opp && !opp ? 'invalid' : ''} ${!opp ? 'ct-focus-pulse' : ''}`}>
                {OPP_TEAMS.map(o => (
                  <button
                    key={o.name}
                    data-cert={`opp-${o.short}`}
                    className={`ct-chip ${opp === o.name ? 'selected' : ''}`}
                    onClick={() => { setOpp(o.name); touch('opp'); }}
                  >
                    <span className="ct-chip-logo">{o.logo}</span>
                    <span className="ct-chip-name">{o.short}</span>
                  </button>
                ))}
              </div>
              {touched.opp && !opp && <div className="ct-field-err">Pick an opposition team to continue.</div>}
            </div>

            {/* Venue — required */}
            <div className="ct-field">
              <label className="ct-field-lab" htmlFor="ct-venue">
                VENUE <span className="ct-req">required</span>
              </label>
              <select
                id="ct-venue"
                data-cert="venue"
                className={`ct-select ${touched.venue && !venue ? 'invalid' : ''} ${!venue ? 'ct-focus-pulse' : ''}`}
                value={venue}
                onChange={(e) => { setVenue(e.target.value); touch('venue'); }}
                onBlur={() => touch('venue')}
              >
                <option value="">— Pick a ground —</option>
                {VENUES.map(v => <option key={v} value={v}>{v}</option>)}
              </select>
              {touched.venue && !venue && <div className="ct-field-err">Every match needs a venue.</div>}
            </div>

            {/* Date — read-only */}
            <div className="ct-field ct-field-tight">
              <label className="ct-field-lab">DATE &amp; TIME</label>
              <div className="ct-field-fixed-sm">{date}</div>
            </div>
          </div>

          {/* ── RIGHT column ──────────────────────────────────────── */}
          <div className="ct-setup-col">
            <div className="ct-setup-col-eye">MATCH SHAPE</div>

            {/* Match Type — required */}
            <div className="ct-field">
              <label className="ct-field-lab">
                MATCH TYPE <span className="ct-req">required</span>
              </label>
              <div className="ct-radio-stack">
                {MATCH_TYPES.map(m => (
                  <button
                    key={m.id}
                    data-cert={`mtype-${m.id}`}
                    className={`ct-radio-card ${matchType === m.id ? 'selected' : ''}`}
                    onClick={() => setMatchType(m.id)}
                    type="button"
                  >
                    <span className="ct-radio-dot" />
                    <span className="ct-radio-meta">
                      <span className="ct-radio-name">{m.label}</span>
                      <span className="ct-radio-sub">{m.sub}</span>
                    </span>
                    <span className="ct-radio-tag">{m.innings} {m.innings === 1 ? 'innings' : 'innings'}/side</span>
                  </button>
                ))}
              </div>
            </div>

            {/* Format + Overs — both required when not Test */}
            {!isTest ? (
              <div className="ct-field-row">
                <div className="ct-field">
                  <label className="ct-field-lab">
                    FORMAT <span className="ct-req">required</span>
                  </label>
                  <div className="ct-seg ct-seg-wrap">
                    {FORMATS.map(f => (
                      <button
                        key={f.id}
                        className={`ct-seg-btn ${format === f.id ? 'active' : ''}`}
                        onClick={() => setFormat(f.id)}
                        type="button"
                      >{f.label}</button>
                    ))}
                  </div>
                  <div className="ct-field-hint">Preset auto-fills overs.</div>
                </div>
                <div className="ct-field">
                  <label className="ct-field-lab" htmlFor="ct-overs">
                    OVERS / SIDE <span className="ct-req">required</span>
                  </label>
                  <div className="ct-stepper">
                    <button
                      type="button"
                      className="ct-stepper-btn"
                      onClick={() => { setOvers(o => Math.max(1, o - 1)); setFormat('CUSTOM'); touch('overs'); }}
                      aria-label="Decrease overs"
                    >–</button>
                    <input
                      id="ct-overs"
                      type="number"
                      min="1" max="50"
                      className="ct-stepper-input"
                      value={overs}
                      onChange={(e) => { setOvers(Math.max(1, Math.min(50, +e.target.value || 1))); setFormat('CUSTOM'); touch('overs'); }}
                    />
                    <button
                      type="button"
                      className="ct-stepper-btn"
                      onClick={() => { setOvers(o => Math.min(50, o + 1)); setFormat('CUSTOM'); touch('overs'); }}
                      aria-label="Increase overs"
                    >+</button>
                  </div>
                  <div className="ct-field-hint">1 – 50 overs</div>
                </div>
              </div>
            ) : (
              <div className="ct-field">
                <label className="ct-field-lab">FORMAT</label>
                <div className="ct-field-fixed-sm ct-field-test">
                  <b>TEST</b> · unlimited overs · timed by days, not overs
                </div>
              </div>
            )}

            {/* Innings per side — derived, but displayed */}
            <div className="ct-field-row">
              <div className="ct-field">
                <label className="ct-field-lab">
                  INNINGS / SIDE <span className="ct-req">required</span>
                </label>
                <div className="ct-seg">
                  {[1, 2].map(n => (
                    <button
                      key={n}
                      className={`ct-seg-btn ${innings === n ? 'active' : ''} ${innings !== n ? 'disabled' : ''}`}
                      onClick={() => {
                        // Switch matchType to the corresponding option
                        if (n === 1) setMatchType('LIMITED');
                        else setMatchType(matchType === 'TEST' ? 'TEST' : 'TWO_INN');
                      }}
                      type="button"
                    >{n}</button>
                  ))}
                </div>
                <div className="ct-field-hint">Set by match type.</div>
              </div>
              <div className="ct-field">
                <label className="ct-field-lab">COMPETITION</label>
                <div className="ct-seg">
                  {COMPS.map(c => (
                    <button
                      key={c}
                      className={`ct-seg-btn ${comp === c ? 'active' : ''}`}
                      onClick={() => setComp(c)}
                      type="button"
                    >{c}</button>
                  ))}
                </div>
                <div className="ct-field-hint">{compHint}</div>
              </div>
            </div>
          </div>
        </div>

        <div className="ct-setup-foot">
          <div className="ct-setup-summary">
            {valid ? (
              <>STR vs <b>{oppObj?.short || opp}</b> · {isTest ? 'Test' : `${overs} ov`} · {innings} inn/side · {comp} · {venue.split(',')[0]}</>
            ) : (
              <span className="ct-setup-summary-incomplete">Fill the required fields to continue ↗</span>
            )}
          </div>
          <button
            data-cert="setup-save"
            className={`ct-stage-cta ${!valid ? 'disabled' : ''}`}
            onClick={() => {
              if (!valid) { setTouched({ opp:true, venue:true, overs:true }); return; }
              onConfirm({
                matchType, innings,
                opp, oppShort: oppObj?.short, oppLogo: oppObj?.logo,
                venue, format, overs: isTest ? null : overs, comp,
              });
            }}
            disabled={!valid}
          >
            CONTINUE TO SQUADS
            <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg>
          </button>
        </div>
      </div>
    </div>
  );
}

// ─── Squads stage — assign captain + wicket-keeper for both sides ──────

function SquadsStage({ matchDetails, initial, onConfirm, onBack }) {
  // Pre-fill squads with real Crest Strikers + opposition names so the scorebook reads like the real app.
  const STRIKERS_XI = [
    { name: 'A. Hughes',    role: 'BAT' },
    { name: 'J. Whitaker',  role: 'BAT' },
    { name: 'A. Malhotra',  role: 'BAT' },
    { name: 'O. Grant',     role: 'BAT' },
    { name: 'R. Iyer',      role: 'BAT' },
    { name: 'K. Deshpande', role: 'AR'  },
    { name: 'S. Mehta',     role: 'AR'  },
    { name: 'N. Perera',    role: 'AR'  },
    { name: 'T. Bradley',   role: 'WK'  },
    { name: 'M. Roper',     role: 'BOWL'},
    { name: 'N. Cole',      role: 'BOWL'},
  ];
  const home = useMemo(() => STRIKERS_XI, []);
  const away = useMemo(() => {
    const short = matchDetails?.oppShort || 'THU';
    const names = ['Bell', 'Carter', 'Davies', 'Evans', 'Foster', 'Green', 'Hall', 'Irwin', 'Jones', 'King', 'Lane'];
    return names.map((n, i) => ({
      name: `${n}`,
      role: i < 5 ? 'BAT' : i < 8 ? 'AR' : i < 9 ? 'WK' : 'BOWL',
    }));
  }, [matchDetails]);

  const [homeC, setHomeC]     = useState(initial?.homeC ?? null);
  const [homeWK, setHomeWK]   = useState(initial?.homeWK ?? null);
  const [awayC, setAwayC]     = useState(initial?.awayC ?? null);
  const [awayWK, setAwayWK]   = useState(initial?.awayWK ?? null);

  const [toss, setToss]           = useState(initial?.toss || 'home');     // 'home' | 'away'
  const [tossElection, setElect]  = useState(initial?.election || 'bat');  // 'bat'  | 'bowl'

  const valid = homeC !== null && homeWK !== null && awayC !== null && awayWK !== null;

  const sideEditor = (team, list, captain, setCaptain, wk, setWK, eyebrow, chip) => {
    const ready = captain !== null && wk !== null;
    return (
      <div className={`ct-squad ${ready ? 'is-ready' : 'needs-cwk'}`}>
        <div className="ct-squad-head">
          <span className={`ct-team-chip ct-team-chip-${chip}`}>{chip === 'a' ? 'B' : matchDetails?.oppLogo || 'R'}</span>
          <div className="ct-squad-head-meta">
            <div className="ct-squad-head-name">{eyebrow}</div>
            <div className="ct-squad-head-sub">
              {ready
                ? <span className="ct-squad-ready">✓ C &amp; WK locked</span>
                : <span className="ct-squad-req">Pick C and WK <span className="ct-req">required</span></span>
              }
            </div>
          </div>
        </div>
        <ol className="ct-squad-list ct-squad-list-2col">
          {list.map((p, i) => (
            <li key={i} className={`${captain === i ? 'is-c' : ''} ${wk === i ? 'is-wk' : ''}`}>
              <span className="ct-squad-num">{i+1}</span>
              <span className="ct-squad-name">{p.name}</span>
              <div className="ct-squad-actions">
                <button
                  className={`ct-squad-btn ${captain === i ? 'active' : ''} ${captain === null ? 'ct-focus-pulse-sm' : ''}`}
                  onClick={() => setCaptain(captain === i ? null : i)}
                  aria-label="Make captain"
                  title="Captain"
                >C</button>
                <button
                  className={`ct-squad-btn ct-squad-btn-wk ${wk === i ? 'active' : ''} ${wk === null ? 'ct-focus-pulse-sm wk' : ''}`}
                  onClick={() => setWK(wk === i ? null : i)}
                  aria-label="Make wicket-keeper"
                  title="Wicket-keeper"
                >WK</button>
              </div>
            </li>
          ))}
        </ol>
      </div>
    );
  };

  return (
    <div className="ct-squads">

      <div className="ct-squads-card ct-squads-card-wide">
        <div className="ct-squads-head">
          <div className="ct-squads-head-left">
            <button className="ct-back ct-back-inline" onClick={onBack}>
              <svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M15 18l-6-6 6-6"/></svg>
              Back
            </button>
            <div className="ct-stage-eye">SCOREBOOK · SQUADS</div>
            <h2 className="ct-stage-title ct-stage-title-sm">Captains, keepers &amp; toss</h2>
          </div>
          <p className="ct-stage-sub ct-stage-sub-inline">
            XIs pre-filled. Tap <b className="ct-c-mark">C</b> + <b className="ct-wk-mark">WK</b> for each side, then call the toss.
          </p>
        </div>        <div className="ct-squads-grid">
          {sideEditor(
            'home', home, homeC, setHomeC, homeWK, setHomeWK,
            'CREST STRIKERS', 'a',
          )}
          {sideEditor(
            'away', away, awayC, setAwayC, awayWK, setAwayWK,
            matchDetails?.opp || 'CREST THUNDERS', 'b',
          )}
        </div>

        {/* Toss — inline single row */}
        <div className="ct-toss-block ct-toss-inline">
          <div className="ct-toss-eye">TOSS</div>
          <div className="ct-toss-q">
            <span>Won by</span>
            <div className="ct-seg">
              <button className={`ct-seg-btn ${toss === 'home' ? 'active' : ''}`} onClick={() => setToss('home')}>STR</button>
              <button className={`ct-seg-btn ${toss === 'away' ? 'active' : ''}`} onClick={() => setToss('away')}>{matchDetails?.oppShort || 'OPP'}</button>
            </div>
          </div>
          <div className="ct-toss-q">
            <span>Elected to</span>
            <div className="ct-seg">
              <button className={`ct-seg-btn ${tossElection === 'bat'  ? 'active' : ''}`} onClick={() => setElect('bat')}>BAT</button>
              <button className={`ct-seg-btn ${tossElection === 'bowl' ? 'active' : ''}`} onClick={() => setElect('bowl')}>BOWL</button>
            </div>
          </div>
          <div className="ct-toss-summary">
            <b>{toss === 'home' ? 'STR' : (matchDetails?.oppShort || 'Opposition')}</b> · <b>{tossElection.toUpperCase()}</b> first
          </div>
        </div>

        <div className="ct-setup-foot">
          <div className="ct-setup-summary">
            {valid ? <>✓ Squads locked · C &amp; WK assigned for both sides.</> :
             <span className="ct-setup-summary-incomplete">Pick captain &amp; keeper for both teams ↑</span>}
          </div>
          <button
            data-cert="squads-confirm"
            className={`ct-stage-cta ${valid ? 'ct-stage-cta-hot' : 'disabled'}`}
            onClick={() => {
              if (!valid) return;
              const battingFirst = (toss === 'home' && tossElection === 'bat') || (toss === 'away' && tossElection === 'bowl')
                ? 'home' : 'away';
              onConfirm({
                home, away, homeC, homeWK, awayC, awayWK,
                toss, election: tossElection, battingFirst,
              });
            }}
            disabled={!valid}
          >
            START INNINGS
            <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg>
          </button>
        </div>
      </div>
    </div>
  );
}

// ─── Free-play scoring stage ─────────────────────────────────────────────
// Replaces the old lockstep flow. The user explores the Scorebook freely; a
// right-side checklist HUD ticks tasks off as they happen, certificate
// unlocks at the end. Hints flash the relevant control when asked.

// Tasks the user has to perform (any order) to earn the badge.
const DRILL_TASKS = [
  { id:'boundary',   label:'Hit a boundary (4 or 6)',   icon:'★', sel:'[data-cert="key-4"]',
    test: (ev) => ev.some(e => e.kind === 'ball' && (e.label === '4' || e.label === '6')) },
  { id:'single',     label:'Rotate strike — score a 1', icon:'⇄', sel:'[data-cert="key-1"]',
    test: (ev) => ev.some(e => e.kind === 'ball' && e.label === '1') },
  { id:'dot',        label:'Defend a dot ball',         icon:'•', sel:'[data-cert="key-0"]',
    test: (ev) => ev.some(e => e.kind === 'ball' && e.label === '0') },
  { id:'extra',      label:'Call a wide or no-ball',    icon:'+1', sel:'[data-cert="key-WD"]',
    test: (ev) => ev.some(e => e.kind === 'ball' && (e.label === 'wd' || e.label === 'nb')) },
  { id:'wicket',     label:'Take a wicket',             icon:'×', sel:'[data-cert="key-W"]',
    test: (ev) => ev.some(e => e.kind === 'wicket') },
  { id:'undo',       label:'Undo a ball',               icon:'↺', sel:'[data-cert="btn-undo"]',
    test: (ev) => ev.some(e => e.kind === 'undo') },
  { id:'pulse',      label:'Open CrestPulse™',          icon:'♥', sel:'[data-cert="btn-pulse"]',
    test: (ev) => ev.some(e => e.kind === 'openPulse') },
  { id:'smart',      label:'Open CrestSmart™ (CS key)', icon:'✦', sel:'[data-cert="btn-crestsmart"]',
    test: (ev) => ev.some(e => e.kind === 'openSmart') },
  { id:'bowler',     label:'Change the bowler',         icon:'◯', sel:'[data-cert="btn-bowler"]',
    test: (ev) => ev.some(e => e.kind === 'changeBowler') },
  { id:'drinks',     label:'Take drinks',               icon:'🥛', sel:'[data-cert="btn-drinks"]',
    test: (ev) => ev.some(e => e.kind === 'drinks') },
];

const MIN_TO_FINISH = 7; // 7/10 unlocks "Generate anyway"; 10/10 is the gold path.

function ScoringStage({ matchDetails, squads, onComplete, onBack, onSkip }) {
  const [events, setEvents] = useState([]);
  const state = useMemo(() => replayEvents(events), [events]);
  const [modal, setModal] = useState(null);
  const [hintingTask, setHintingTask] = useState(null);

  const push = useCallback((ev) => setEvents(es => [...es, ev]), []);

  // Ball-tagging modal sequence — after a boundary or wicket, prompt the
  // user to tag the delivery via the Wagon Wheel and Ball Analysis modals
  // (same components used post-match, now inline during scoring).
  const [tagSeq, setTagSeq] = useState(null);
  // Track which event indexes we've already prompted for, so undo doesn't loop.
  const [taggedIdx, setTaggedIdx] = useState(new Set());

  useEffect(() => {
    if (events.length === 0) return;
    const idx = events.length - 1;
    if (taggedIdx.has(idx)) return;
    const last = events[idx];
    // Real scorers tag EVERY delivery — prompt the Ball Analysis + Wagon Wheel
    // sequence after each ball or wicket (skip the viewing/utility events).
    const isBall = last.kind === 'wicket' || last.kind === 'ball';
    if (!isBall) return;
    // Brief delay so the keypad press has time to settle.
    const t = setTimeout(() => {
      let label;
      if (last.kind === 'wicket') label = 'WICKET BALL';
      else if (last.label === '0') label = 'DOT BALL';
      else if (last.label === '4' || last.label === '6') label = `${last.label} RUNS`;
      else if (last.label === 'wd' || last.label === 'nb' || last.label === 'b' || last.label === 'lb') {
        const sig = { wd:'WIDE', nb:'NO-BALL', b:'BYE', lb:'LEG-BYE' }[last.label];
        const ex = last.extras ? ` +${last.extras}` : '';
        label = `${sig}${ex}`;
      } else label = `${last.label} RUN${last.label === '1' ? '' : 'S'}`;
      // Capture who's involved so the tag cards read the real delivery.
      const bowlerName = state.currentBowler;
      let batterName;
      if (last.kind === 'wicket') {
        const o = [...state.batters].reverse().find(b => b.out);
        batterName = o ? o.name : (state.batters[state.striker] || {}).name;
      } else {
        batterName = (state.batters[state.striker] || {}).name;
      }
      setTagSeq({
        eventIdx: idx,
        stage: 'ba',
        ba: {},
        ww: {},
        kind: last.kind === 'wicket' ? 'wicket' : last.label,
        label,
        bowler: bowlerName,
        batter: batterName,
      });
      setTaggedIdx(s => new Set([...s, idx]));
    }, 280);
    return () => clearTimeout(t);
  }, [events]); // eslint-disable-line react-hooks/exhaustive-deps

  // ── Flash hint: briefly glow the target element so the user can find it.
  const flashHint = useCallback((task) => {
    setHintingTask(task.id);
    const el = document.querySelector(task.sel);
    if (el) {
      el.classList.add('ct-hint-flash');
      setTimeout(() => el.classList.remove('ct-hint-flash'), 1800);
    }
    setTimeout(() => setHintingTask(null), 2000);
  }, []);

  const [pendingExtra, setPendingExtra] = useState(null); // { kind: 'wd'|'nb'|'b'|'lb' } when an extras signal is waiting for runs

  // ── Handlers
  const onKey = (id) => {
    if (id === 'R') {
      // Repeat last delivery — re-apply the most recent ball/wicket.
      const last = [...events].reverse().find(e => e.kind === 'ball' || e.kind === 'wicket');
      if (last) push({ ...last });
      return;
    }
    if (id === 'W')  { setPendingExtra(null); setModal('wicket'); return; }
    if (id === 'CS') { push({ kind:'openSmart' }); setModal('smart'); return; }

    // Extras signal — toggle into "pending" mode. The existing number pad
    // then supplies additional runs (0 default). Press the signal again to
    // commit the bare signal (0 extra runs).
    if (id === 'WD' || id === 'NB' || id === 'B' || id === 'LB') {
      const k = id.toLowerCase();
      if (pendingExtra && pendingExtra.kind === k) {
        // Second press → confirm with 0 extras.
        push({ kind:'ball', label: k, extras: 0 });
        setPendingExtra(null);
      } else {
        setPendingExtra({ kind: k });
      }
      return;
    }

    // Numbers / dots: if we're in pending-extra mode, this is the extras count.
    const labelMap = { '0':'0','1':'1','2':'2','3':'3','4':'4','6':'6' };
    const lab = labelMap[id] || id;
    if (pendingExtra) {
      push({ kind:'ball', label: pendingExtra.kind, extras: Number(lab) || 0 });
      setPendingExtra(null);
      return;
    }
    push({ kind:'ball', label: lab });
  };
  const onTool = (id) => {
    if (id === 'btn-undo')        push({ kind:'undo' });
    else if (id === 'btn-swap')   push({ kind:'swap' });
    else if (id === 'btn-bowler') setModal('bowler');
    else if (id === 'btn-pulse')  { push({ kind:'openPulse' }); setModal('pulse'); }
    else if (id === 'btn-drinks') { push({ kind:'drinks' }); setModal('drinks'); }
  };

  const onWicketPick = (mode) => {
    push({ kind:'wicket', mode });
    setModal(null);
  };
  const onBowlerPick = (name) => {
    push({ kind:'changeBowler', name });
    setModal(null);
  };

  // CrestSmart heartbeat: fires when a milestone or wicket happens and stays lit
  // until the user opens the panel. Reset on open (kind === 'openSmart').
  const csPulse = useMemo(() => {
    // Has the latest interesting event been viewed yet?
    let pendingEvent = null;
    for (const e of events) {
      if (e.kind === 'wicket') pendingEvent = 'wicket';
      else if (e.kind === 'ball' && (e.label === '4' || e.label === '6')) pendingEvent = pendingEvent || 'boundary';
      else if (e.kind === 'openSmart') pendingEvent = null;
    }
    // Also pulse on milestones (striker reaching 50, partnership 50)
    if (state.batters.some(b => b.r >= 50 && b.b > 0)) pendingEvent = pendingEvent || 'fifty';
    if (events.find(e => e.kind === 'openSmart')) {
      // Has a milestone happened SINCE the last open?
      let lastOpenIdx = -1;
      events.forEach((e, i) => { if (e.kind === 'openSmart') lastOpenIdx = i; });
      const since = events.slice(lastOpenIdx + 1);
      if (!since.some(e => e.kind === 'wicket' || (e.kind === 'ball' && (e.label === '4' || e.label === '6')))) {
        pendingEvent = null;
      } else {
        pendingEvent = 'fresh';
      }
    }
    return pendingEvent !== null;
  }, [events, state.batters]);


  const SB_TABS = ['INNINGS','STATS','INSIGHTS','PULSE','CRESTSMART','COMMENTARY','FLIP','FAN MSG'];
  const [tabNudge, setTabNudge] = useState(null);

  const srOf = (p) => p.b ? Math.round(p.r/p.b*100) : 0;
  const striker = state.batters[state.striker];
  const nonStriker = state.batters[state.nonStriker];
  const currOver = state.overs.slice(-1)[0] || [];
  const bowler = state.bowlers[state.bowlerIdx];
  const rr = state.balls ? (state.runs/(state.balls/6)).toFixed(1) : '0.0';
  const ovLabel = `${Math.floor(state.balls/6)}.${state.balls%6}`;

  const completedIds = new Set(DRILL_TASKS.filter(t => t.test(events, state)).map(t => t.id));
  const doneCount = completedIds.size;
  const allDone = doneCount === DRILL_TASKS.length;
  const minMet  = doneCount >= MIN_TO_FINISH;

  return (
    <div className="ct-sb">
      <div className="ct-sb-grid">
        <div className="ct-sb-main">
          {/* Status bar */}
          <div className="ct-sb-status">
            {onBack ? (
              <button className="ct-sb-back" onClick={onBack} aria-label="Back to squads">
                <svg viewBox="0 0 24 24" width="11" height="11" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><path d="M15 18l-6-6 6-6"/></svg>
                Squads
              </button>
            ) : <span>9:41</span>}
            <span className="ct-sb-status-mid">SCOREBOOK · ADVANCED</span>
            <span className="ct-sb-status-right">●●● ▴ 100</span>
          </div>

          {/* Tabs */}
          <div className="ct-sb-tabs-wrap">
            <div className="ct-sb-tabs">
              {SB_TABS.map((t, i) => (
                <button
                  key={t}
                  className={`ct-sb-tab ${i === 0 ? 'active' : ''}`}
                  onClick={() => { if (i !== 0) setTabNudge(t); }}
                >{t}</button>
              ))}
            </div>
            <div className="ct-sb-tabs-fade-l"></div>
            <div className="ct-sb-tabs-fade-r"></div>
          </div>

          {/* Body */}
          <div className="ct-sb-body">
            <div className="ct-sb-head">
              <div className="ct-sb-team">STR</div>
              <div className="ct-sb-runs">{state.runs}<span>/{state.wickets}</span></div>
              <div className="ct-sb-overs">{ovLabel} / {matchDetails?.overs || 5} ov · RR {rr} · vs {matchDetails?.oppShort || 'OPP'}</div>
              <div className="ct-sb-pbar"><div className="ct-sb-pfill" style={{height:`${Math.min(95, 25 + state.runs*2)}%`}}></div></div>
            </div>

            <div className="ct-sb-batters">
              <div className="ct-sb-brow">
                <span className="ct-sb-bname">{striker.name}*</span>
                <span className="ct-sb-bstat"><b>{striker.r}</b> <i>({striker.b})</i> SR {srOf(striker)}</span>
              </div>
              <div className="ct-sb-brow">
                <span className="ct-sb-bname">{nonStriker.name}</span>
                <span className="ct-sb-bstat"><b>{nonStriker.r}</b> <i>({nonStriker.b})</i> SR {srOf(nonStriker)}</span>
              </div>
            </div>

            <div className="ct-sb-bowler">
              <span className="ct-sb-blab">BOWLING</span>
              <span className="ct-sb-bname">{bowler.name}</span>
              <span className="ct-sb-bstat">{bowler.o.toFixed(1)} ov · {bowler.r}-{bowler.w}</span>
            </div>

            <div className="ct-sb-over">
              <span className="ct-sb-over-lab">THIS OVER</span>
              {currOver.length === 0 && <span className="ct-sb-over-empty">— new over —</span>}
              {currOver.map((b, i) => (
                <span key={i} className={`ct-sb-ball ${
                  b === 'W' ? 'ct-sb-ball-w' :
                  b === '4' ? 'ct-sb-ball-four' :
                  b === '6' ? 'ct-sb-ball-six' :
                  b === '•' || b === '0' ? 'ct-sb-ball-dot' :
                  /^(Wd|Nb|B|Lb)/.test(b) ? 'ct-sb-ball-extra' :
                  'ct-sb-ball-run'
                }`}>{b}</span>
              ))}
            </div>

            <ScoreToolbar onClick={onTool} />
            {pendingExtra && (
              <div className="ct-sb-pending" role="status">
                <span className="ct-sb-pending-sig">{
                  pendingExtra.kind === 'wd' ? 'Wd' :
                  pendingExtra.kind === 'nb' ? 'Nb' :
                  pendingExtra.kind === 'b'  ? 'B'  :
                  'Lb'
                }</span>
                <span className="ct-sb-pending-body">
                  Signal locked — <b>tap a number for additional runs</b>
                  <span className="ct-sb-pending-hint"> (0 default · tap {pendingExtra.kind.toUpperCase()} again to confirm 0)</span>
                </span>
                <button className="ct-sb-pending-cancel" onClick={() => setPendingExtra(null)} aria-label="Cancel extras">✕</button>
              </div>
            )}
            <ScoreKeypad onClick={onKey} csPulse={csPulse} pendingExtra={pendingExtra} />
          </div>
        </div>

        {/* Right-side HUD */}
        <ChecklistHUD
          tasks={DRILL_TASKS}
          completedIds={completedIds}
          onHint={flashHint}
          hintingTask={hintingTask}
          minMet={minMet}
          allDone={allDone}
          onGenerate={() => onComplete(state, events)}
          onSkip={() => onComplete(state, events)}
        />
      </div>

      {/* Modals */}
      {modal === 'pulse'  && <PulseModal  state={state} onClose={() => setModal(null)} />}
      {modal === 'smart'  && <SmartModal  state={state} onClose={() => setModal(null)} />}
      {modal === 'bowler' && <BowlerModal state={state} onPick={onBowlerPick} onClose={() => setModal(null)} />}
      {modal === 'wicket' && <WicketModal onPick={onWicketPick} onClose={() => setModal(null)} />}
      {modal === 'drinks' && <DrinksModal onClose={() => setModal(null)} />}

      {/* Ball-tagging modal sequence — wagon wheel + ball analysis */}
      {tagSeq && (() => {
        const BAC = window.BallAnalysisCard;
        const WWC = window.WagonWheelCard;
        if (!BAC || !WWC) return null;
        const close = () => setTagSeq(null);
        const goBA = () => setTagSeq(s => s && ({ ...s, stage: 'ba' }));
        const goWW = () => setTagSeq(s => s && ({ ...s, stage: 'ww' }));
        const setBA = (ba) => setTagSeq(s => s && ({ ...s, ba }));
        const setWW = (ww) => setTagSeq(s => s && ({ ...s, ww }));
        const onBAConfirm = () => {
          setTagSeq(s => s && ({ ...s, ba: { ...s.ba, confirmed: true }, stage: 'ww' }));
        };
        const onWWConfirm = () => {
          push({ kind: 'tagDelivery' });
          setTagSeq(null);
        };
        return (
          <div className="ct-sb-tag-backdrop" onClick={close}>
            <div className="ct-sb-tag-pane" onClick={(e) => e.stopPropagation()}>
              <div className="ct-sb-tag-head">
                <div className="ct-sb-tag-eye">★ TAG DELIVERY · {tagSeq.label || (tagSeq.kind === 'wicket' ? 'WICKET BALL' : `${tagSeq.kind} RUNS`)}</div>
                <div className="ct-sb-tag-tabs">
                  <button className={`ct-sb-tag-tab ${tagSeq.stage === 'ba' ? 'is-active' : ''} ${tagSeq.ba.confirmed ? 'is-done' : ''}`} onClick={goBA} type="button">
                    <span className="ct-sb-tag-tab-num">01</span> BALL ANALYSIS
                    {tagSeq.ba.confirmed && <span className="ct-sb-tag-tab-tick">✓</span>}
                  </button>
                  <button className={`ct-sb-tag-tab ${tagSeq.stage === 'ww' ? 'is-active' : ''} ${tagSeq.ww.confirmed ? 'is-done' : ''}`} onClick={goWW} type="button">
                    <span className="ct-sb-tag-tab-num">02</span> WAGON WHEEL
                    {tagSeq.ww.confirmed && <span className="ct-sb-tag-tab-tick">✓</span>}
                  </button>
                </div>
                <button className="ct-sb-tag-skip" onClick={close} type="button" aria-label="Skip tagging">SKIP ✕</button>
              </div>
              {tagSeq.stage === 'ba'
                ? <BAC data={tagSeq.ba} onChange={setBA} onConfirm={onBAConfirm} bowler={tagSeq.bowler} batter={tagSeq.batter} outcome={tagSeq.label}/>
                : <WWC data={tagSeq.ww} onChange={setWW} onConfirm={onWWConfirm} bowler={tagSeq.bowler} batter={tagSeq.batter} outcome={tagSeq.label} kind={tagSeq.kind}/>
              }
            </div>
          </div>
        );
      })()}

      {tabNudge && (
        <div key={tabNudge + Date.now()} className="ct-sb-toast" onAnimationEnd={() => setTabNudge(null)}>
          {tabNudge === 'PULSE'      ? 'Use the PULSE button in the toolbar, not the tab.' :
           tabNudge === 'CRESTSMART' ? 'Use the SMART button in the toolbar, not the tab.' :
           `${tabNudge} is preview-only — explore the controls below.`}
        </div>
      )}
    </div>
  );
}

function ScoreToolbar({ onClick }) {
  // Toolbar mirrors the "advanced controls" the real Scorebook lays out on the side:
  // undo, swap, change bowler, pulse, drinks. CrestSmart is on the KEYPAD (CS key), not here.
  const Btn = ({ id, label, icon }) => (
    <button
      data-cert={id}
      className="ct-sb-tool"
      onClick={() => onClick(id)}
    >
      <span className="ct-sb-tool-icon" aria-hidden="true">{icon}</span>
      <span className="ct-sb-tool-label">{label}</span>
    </button>
  );
  return (
    <div className="ct-sb-toolbar">
      <Btn id="btn-undo"   label="UNDO"   icon="↺"/>
      <Btn id="btn-swap"   label="SWAP"   icon="⇄"/>
      <Btn id="btn-bowler" label="BOWLER" icon="◯"/>
      <Btn id="btn-pulse"  label="PULSE"  icon="♥"/>
      <Btn id="btn-drinks" label="DRINKS" icon="🥛"/>
    </div>
  );
}

function ScoreKeypad({ onClick, csPulse, pendingExtra }) {
  // Layout mirrors the real scoring_keypad.dart:
  //   Row 1: 0 1 2 3 4 6
  //   Row 2: W Wd Nb B Lb CS  (CS = CrestSmart, heartbeat-pulses when an event is queued)
  const keys = [
    { k:'0',  id:'0'  }, { k:'1', id:'1' }, { k:'2', id:'2' }, { k:'3', id:'3' }, { k:'4', id:'4' }, { k:'6', id:'6' }, { k:'R', id:'R' },
    { k:'W',  id:'W'  }, { k:'Wd', id:'WD' }, { k:'Nb', id:'NB' }, { k:'B', id:'B' }, { k:'Lb', id:'LB' }, { k:'CS', id:'CS' },
  ];
  const pendingKey = pendingExtra ? pendingExtra.kind.toUpperCase() : null;
  const isNumber = (id) => /^[0-9]$/.test(id);
  const cls = (id) => {
    const base =
      id === 'W'  ? 'ct-sb-key-w' :
      id === 'R'  ? 'ct-sb-key-repeat' :
      (id === '4' || id === '6') ? 'ct-sb-key-boundary' :
      (id === 'WD' || id === 'NB' || id === 'B' || id === 'LB') ? 'ct-sb-key-extra' :
      id === 'CS' ? `ct-sb-key-cs ${csPulse ? 'pulsing' : ''}` :
      '';
    // When an extras signal is pending, highlight the runs-picker (number row)
    // and mark the active extras key.
    if (pendingExtra) {
      if (id === pendingKey) return `${base} ct-sb-key-pending`;
      if (isNumber(id))      return `${base} ct-sb-key-runs-mode`;
    }
    return base;
  };
  return (
    <div className={`ct-sb-keypad ${pendingExtra ? 'is-runs-mode' : ''}`}>
      {keys.map(({ k, id }) => (
        <button
          key={id}
          data-cert={id === 'CS' ? 'btn-crestsmart' : `key-${id}`}
          className={`ct-sb-key ${cls(id)}`}
          onClick={() => onClick(id)}
        >
          {id === 'CS' ? (
            <>
              <span className="ct-sb-cs-mark">CS</span>
              {csPulse && <span className="ct-sb-cs-dot" aria-hidden="true"></span>}
            </>
          ) : k}
        </button>
      ))}
    </div>
  );
}

function ChecklistHUD({ tasks, completedIds, onHint, hintingTask, minMet, allDone, onGenerate, onSkip }) {
  const done = completedIds.size;
  const total = tasks.length;
  const pct = (done / total) * 100;

  return (
    <aside className="ct-checklist" aria-label="Drill checklist">
      <div className="ct-checklist-head">
        <div className="ct-checklist-eye">DRILL CHECKLIST</div>
        <div className="ct-checklist-title">Try each control</div>
        <div className="ct-checklist-sub">Score freely. Ticks fill in as you go. No order, no rush.</div>
      </div>

      <div className="ct-checklist-progress">
        <div className="ct-checklist-progress-bar"><div style={{width:`${pct}%`}}></div></div>
        <div className="ct-checklist-progress-row">
          <span><b>{done}</b> / {total} done</span>
          <span className={`ct-checklist-status ${allDone ? 'gold' : minMet ? 'ready' : 'pending'}`}>
            {allDone ? '★ ALL GOLD' : minMet ? 'READY' : `${MIN_TO_FINISH - done} TO UNLOCK`}
          </span>
        </div>
      </div>

      <ul className="ct-checklist-list">
        {tasks.map(t => {
          const isDone = completedIds.has(t.id);
          return (
            <li key={t.id} className={`ct-checklist-item ${isDone ? 'done' : ''} ${hintingTask === t.id ? 'hinting' : ''}`}>
              <span className="ct-checklist-tick">{isDone ? '✓' : t.icon}</span>
              <span className="ct-checklist-label">{t.label}</span>
              {!isDone && (
                <button
                  className="ct-checklist-hint"
                  onClick={() => onHint(t)}
                  aria-label={`Show me where to ${t.label}`}
                  title="Show me"
                >?</button>
              )}
            </li>
          );
        })}
      </ul>

      <div className="ct-checklist-foot">
        {minMet ? (
          <button
            className={`ct-checklist-cta ${allDone ? 'ct-checklist-cta-gold' : ''}`}
            onClick={onGenerate}
          >
            <span>{allDone ? '★ GENERATE CERTIFICATE' : 'GENERATE CERTIFICATE'}</span>
            <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg>
          </button>
        ) : (
          <div className="ct-checklist-cta ct-checklist-cta-locked">
            <svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><rect x="4" y="10" width="16" height="11" rx="2"/><path d="M8 10V7a4 4 0 0 1 8 0v3"/></svg>
            <span>UNLOCK AT {MIN_TO_FINISH}/{total}</span>
          </div>
        )}
        <button className="ct-checklist-exit" onClick={onSkip}>Skip drill</button>
      </div>
    </aside>
  );
}

// ─── State derivation ───────────────────────────────────────────────────
// Turn the user's event log into a live scorecard state. Undo collapses
// the log first (pop the most recent applicable event), then we replay.

function replayEvents(events) {
  // Collapse undos first
  const log = [];
  for (const ev of events) {
    if (ev.kind === 'undo') {
      // pop last *applicable* event (ball, wicket, swap, changeBowler). Skip popping the
      // viewing events like openPulse/openSmart/drinks — undo shouldn't erase them.
      for (let i = log.length - 1; i >= 0; i--) {
        if (['ball','wicket','swap','changeBowler'].includes(log[i].kind)) {
          log.splice(i, 1);
          break;
        }
      }
    } else {
      log.push(ev);
    }
  }

  const batters = BATTERS.map(b => ({...b}));
  const bowlers = BOWLERS.map(b => ({...b}));
  let striker = 0, nonStriker = 1, nextBat = 2;
  let runs = 0, wickets = 0, balls = 0, extras = 0;
  let overs = [[]];
  let bowlerIdx = 0;
  bowlers[0].active = true;

  const swap = () => { [striker, nonStriker] = [nonStriker, striker]; };

  for (const ev of log) {
    if (ev.kind === 'ball') {
      const lab = ev.label;
      const extraRuns = ev.extras || 0; // additional runs after a Wd/Nb/B/Lb signal
      const r = lab === '4' ? 4 :
                lab === '6' ? 6 :
                lab === '0' ? 0 :
                lab === '5' ? 5 :
                lab === 'wd' || lab === 'nb' ? 1 + extraRuns :
                lab === 'b'  || lab === 'lb' ? extraRuns :
                Number(lab) || 0;
      const isExtra = ['wd','nb','b','lb'].includes(lab);
      const isBatterRuns = !isExtra; // bye/lb/wd/nb runs are extras, not batter's
      const legal = !['wd','nb'].includes(lab);
      // Charge bowler for wd/nb (penalty + runs); NOT for b/lb.
      const chargeBowler = lab !== 'b' && lab !== 'lb';

      runs += r;
      if (isExtra) extras += r;
      if (legal) {
        balls += 1;
        batters[striker].b += 1;
      }
      if (isBatterRuns) {
        batters[striker].r += r;
        if (lab === '4') batters[striker].fours += 1;
        if (lab === '6') batters[striker].sixes += 1;
      }
      if (chargeBowler) bowlers[bowlerIdx].r += r;
      bowlers[bowlerIdx].balls = (bowlers[bowlerIdx].balls || 0) + (legal ? 1 : 0);

      // Display: "Wd", "Wd+2", "Nb+1", "B 2", "Lb 4", or just the number.
      let display;
      if (lab === 'wd') display = extraRuns > 0 ? `Wd+${extraRuns}` : 'Wd';
      else if (lab === 'nb') display = extraRuns > 0 ? `Nb+${extraRuns}` : 'Nb';
      else if (lab === 'b')  display = `B${extraRuns}`;
      else if (lab === 'lb') display = `Lb${extraRuns}`;
      else if (lab === '0')  display = '•';
      else display = lab;
      overs[overs.length - 1].push(display);

      // Strike rotation: odd total runs swap (true for byes/leg-byes too).
      if (r % 2 === 1) swap();

      if (legal && balls > 0 && balls % 6 === 0) {
        overs.push([]);
        bowlers[bowlerIdx].o = balls / 6;
        swap(); // end-of-over crossover
      }
    } else if (ev.kind === 'wicket') {
      batters[striker].out = true;
      batters[striker].how = ev.mode === 'Bowled' ? `b ${bowlers[bowlerIdx].name}` :
                             ev.mode === 'Run Out' ? `run out` :
                             ev.mode === 'LBW' ? `lbw b ${bowlers[bowlerIdx].name}` :
                             ev.mode === 'Stumped' ? `st † b ${bowlers[bowlerIdx].name}` :
                             `c † b ${bowlers[bowlerIdx].name}`;
      bowlers[bowlerIdx].w += 1;
      wickets += 1;
      balls += 1;
      batters[striker].b += 1;
      bowlers[bowlerIdx].balls = (bowlers[bowlerIdx].balls || 0) + 1;
      overs[overs.length - 1].push('W');
      striker = nextBat;
      nextBat += 1;
      if (balls % 6 === 0) {
        overs.push([]);
        bowlers[bowlerIdx].o = balls / 6;
        swap();
      }
    } else if (ev.kind === 'swap') {
      swap();
    } else if (ev.kind === 'changeBowler') {
      const idx = bowlers.findIndex(b => b.name === ev.name);
      if (idx >= 0) {
        bowlers[bowlerIdx].active = false;
        bowlers[bowlerIdx].o = (bowlers[bowlerIdx].balls || 0) / 6;
        bowlerIdx = idx;
        bowlers[bowlerIdx].active = true;
      }
    }
    // 'openPulse', 'openSmart', 'drinks' — no state effect, just tracked for the checklist.
  }

  bowlers[bowlerIdx].o = Math.floor((bowlers[bowlerIdx].balls || 0) / 6) +
                        (((bowlers[bowlerIdx].balls || 0) % 6) / 10);

  return {
    runs, wickets, balls, extras,
    overs,
    striker, nonStriker,
    batters, bowlers, bowlerIdx,
    currentBowler: bowlers[bowlerIdx].name,
  };
}

// ── Legacy replay kept for stats reference (not used at runtime).
function replay(steps) {
  const batters = BATTERS.map(b => ({...b}));
  const bowlers = BOWLERS.map(b => ({...b}));
  let striker = 0, nonStriker = 1, nextBat = 2;
  let runs = 0, wickets = 0, balls = 0, extras = 0;
  let overs = [[]]; // each over is array of ball labels
  let currentBowlerName = 'Ringer 1';
  bowlers[0].active = true;
  let bowlerIdx = 0;
  let lastWicket = null;

  const swap = () => { [striker, nonStriker] = [nonStriker, striker]; };

  for (const s of steps) {
    if (s.kind === 'ball' && s.delta) {
      const d = s.delta;
      const label =
        d.extras === 1 && d.runs === 1 && d.legal === false ? null : null;
      // Build display label for ball strip
      let lab;
      if (s.legal === false && d.extras) {
        // wide or no-ball
        lab = s.target.includes('WD') ? 'wd' : 'nb';
      } else if (d.runs === 4) lab = '4';
      else if (d.runs === 6) lab = '6';
      else if (d.runs === 0) lab = '•';
      else lab = String(d.runs);

      runs += d.runs || 0;
      extras += d.extras || 0;
      if (s.legal !== false) {
        balls += 1;
        batters[striker].b += 1;
        bowlers[bowlerIdx].balls = (bowlers[bowlerIdx].balls||0) + 1;
      }
      if (d.sr) batters[striker].r += d.sr;
      if (d.fours) batters[striker].fours += 1;
      if (d.sixes) batters[striker].sixes += 1;
      bowlers[bowlerIdx].r += (d.runs || 0);
      if (d.swap) swap();

      overs[overs.length - 1].push(lab);

      // End of over check
      if (balls > 0 && balls % 6 === 0 && s.legal !== false) {
        overs.push([]);
        bowlers[bowlerIdx].o = Math.floor((bowlers[bowlerIdx].balls||0)/6);
      }
    } else if (s.kind === 'closeModal' && s.action === 'wicket') {
      // Apply wicket — striker out, next bat in
      const mode = s.target.match(/modal-pick-(\w+)/)?.[1] || 'Caught';
      batters[striker].out = true;
      batters[striker].how = mode === 'Bowled' ? `b ${currentBowlerName}` : `c † b ${currentBowlerName}`;
      bowlers[bowlerIdx].w += 1;
      wickets += 1;
      // Also count the ball
      balls += 1;
      batters[striker].b += 1;
      bowlers[bowlerIdx].balls = (bowlers[bowlerIdx].balls||0) + 1;
      overs[overs.length - 1].push('W');
      lastWicket = batters[striker].name;
      striker = nextBat;
      nextBat += 1;
      if (balls % 6 === 0) {
        overs.push([]);
        bowlers[bowlerIdx].o = Math.floor((bowlers[bowlerIdx].balls||0)/6);
      }
    } else if (s.kind === 'closeModal' && /modal-pick-Ringer/.test(s.target)) {
      const name = s.target.match(/modal-pick-(.+)"]$/)?.[1];
      const idx = bowlers.findIndex(b => b.name === name);
      if (idx >= 0) {
        bowlers[bowlerIdx].active = false;
        bowlers[bowlerIdx].o = Math.floor((bowlers[bowlerIdx].balls||0)/6);
        bowlerIdx = idx;
        bowlers[bowlerIdx].active = true;
        currentBowlerName = name;
      }
    } else if (s.action === 'undo') {
      // Undo: pop last ball
      const last = overs[overs.length - 1].pop();
      if (last == null && overs.length > 1) {
        overs.pop();
        const popped = overs[overs.length - 1].pop();
        runs -= popped === '4' ? 4 : popped === '6' ? 6 : popped === '•' ? 0 : Number(popped) || 0;
        balls -= 1;
        batters[striker].b -= 1;
        bowlers[bowlerIdx].r -= popped === '4' ? 4 : popped === '6' ? 6 : popped === '•' ? 0 : Number(popped) || 0;
      } else if (last) {
        const val = last === '4' ? 4 : last === '6' ? 6 : last === '•' ? 0 : Number(last) || 0;
        if (last !== 'wd' && last !== 'nb') {
          balls -= 1;
          batters[striker].b -= 1;
          batters[striker].r -= val;
          if (last === '4') batters[striker].fours -= 1;
          if (last === '6') batters[striker].sixes -= 1;
        }
        runs -= val;
        bowlers[bowlerIdx].r -= val;
        // Undo strike swap if odd
        if (val % 2 === 1) swap();
      }
    } else if (s.action === 'swap') {
      swap();
    }
  }
  bowlers[bowlerIdx].o = Math.floor((bowlers[bowlerIdx].balls||0)/6) + (((bowlers[bowlerIdx].balls||0) % 6) / 10);

  return {
    runs, wickets, balls, extras,
    overs,
    striker, nonStriker,
    batters, bowlers, bowlerIdx,
    currentBowler: currentBowlerName,
    overNum: Math.floor(balls / 6),
    ballInOver: balls % 6,
    lastWicket,
  };
}

// ─── Modals ─────────────────────────────────────────────────────────────────

function ModalShell({ title, eye, children, onClose, closeLabel = 'CLOSE' }) {
  return (
    <div className="ct-modal-back">
      <div className="ct-modal" onClick={(e) => e.stopPropagation()}>
        <div className="ct-modal-head">
          <div>
            <div className="ct-modal-eye">{eye}</div>
            <div className="ct-modal-title">{title}</div>
          </div>
        </div>
        <div className="ct-modal-body">{children}</div>
        {onClose && (
          <div className="ct-modal-foot">
            <button data-cert="modal-close" className="ct-modal-cta" onClick={onClose}>
              {closeLabel}
            </button>
          </div>
        )}
      </div>
    </div>
  );
}

function PulseModal({ state, onClose }) {
  const striker = state.batters[state.striker];
  // Tiers per CREST_PULSE.md spec — 5 tiers + warming-up sentinel for first 3 balls.
  const ballsFaced = striker.b || 0;
  const warming = ballsFaced < 3;
  const v = Math.min(98, 20 + striker.r * 3 + striker.fours * 4 + striker.sixes * 6);
  const tier =
    warming         ? 'WARMING UP' :
    v >= 80         ? 'UNLEASHED'  :
    v >= 60         ? 'ROARING'    :
    v >= 40         ? 'ALIVE'      :
    v >= 20         ? 'WAKING'     : 'DORMANT';
  const tagline = warming ? 'Feeling the pitch — eyes in.' :
    tier === 'UNLEASHED' ? 'SMOKING HOT. Absolutely unstoppable!' :
    tier === 'ROARING'   ? 'Finding gaps for fun — pressure flipped.' :
    tier === 'ALIVE'     ? 'Settled and ticking — momentum building.' :
    tier === 'WAKING'    ? 'Just starting to warm — pick the right ball.' :
                            'Quiet so far — needs a release shot.';
  const sr = striker.b ? Math.round(striker.r/striker.b*100) : 0;

  return (
    <ModalShell eye="CRESTPULSE™" title="Live Momentum" onClose={onClose} closeLabel="GOT IT">
      <div className="ct-pulse-grid">
        <div className="ct-pulse-bar">
          {!warming && <div className="ct-pulse-fill" style={{height:`${v}%`}}></div>}
          {warming && <div className="ct-pulse-warming"><span></span></div>}
        </div>
        <div className="ct-pulse-info">
          <div className="ct-pulse-name">{striker.name}</div>
          <div className={`ct-pulse-tier tier-${tier.toLowerCase().replace(' ','-')}`}>{tier} · {warming ? '—' : v}</div>
          <div className="ct-pulse-tag">"{tagline}"</div>
          <div className="ct-pulse-ladder">
            {['DORMANT','WAKING','ALIVE','ROARING','UNLEASHED'].map(t => (
              <span key={t} className={`ct-pulse-tick ${tier === t ? 'on' : ''}`}>{t}</span>
            ))}
          </div>
          <div className="ct-pulse-stats">
            <div><span>RUNS</span><b>{striker.r}</b></div>
            <div><span>BALLS</span><b>{striker.b}</b></div>
            <div><span>SR</span><b>{sr}</b></div>
            <div><span>4s/6s</span><b>{striker.fours}/{striker.sixes}</b></div>
          </div>
        </div>
      </div>
    </ModalShell>
  );
}

// CrestSmart — 14-card carousel in the real app; we expose a representative 4-card
// swipeable that auto-picks the highest-signal card for page 0.
function SmartModal({ state, onClose }) {
  const striker = state.batters[state.striker];
  const partnership = state.runs - state.extras;
  const cards = [
    // Page 0: auto-detected event. Pick wicket > 4/6 > default
    state.wickets > 0 ? 'wicket' : (striker.fours + striker.sixes) > 0 ? 'milestone' : 'projection',
    'topbat', 'topbowl', 'projection',
  ];
  // De-dupe page 0 if it equals a later page
  const ordered = [cards[0], ...cards.slice(1).filter(c => c !== cards[0])];
  const [page, setPage] = useState(0);

  const renderCard = (id) => {
    if (id === 'milestone') {
      return (
        <div className="ct-smart-card">
          <div className="ct-smart-card-eye">MILESTONE WATCH</div>
          <div className="ct-smart-hero">
            <div className="ct-smart-big">{Math.max(0, 50 - striker.r)}</div>
            <div className="ct-smart-sub">runs to {striker.name}'s fifty</div>
          </div>
          <div className="ct-smart-rows">
            <div className="ct-smart-row"><span>Strike rate</span><b>{striker.b ? Math.round(striker.r/striker.b*100) : 0}</b></div>
            <div className="ct-smart-row"><span>Boundaries</span><b>{striker.fours}×4 · {striker.sixes}×6</b></div>
            <div className="ct-smart-row"><span>Partnership</span><b>{partnership} ({state.balls})</b></div>
          </div>
        </div>
      );
    }
    if (id === 'wicket') {
      const fallen = state.batters.find(b => b.out);
      return (
        <div className="ct-smart-card">
          <div className="ct-smart-card-eye" style={{color:'#FCA5A5'}}>WICKET</div>
          <div className="ct-smart-hero">
            <div className="ct-smart-big" style={{color:'#FCA5A5'}}>{fallen?.r ?? 0}</div>
            <div className="ct-smart-sub">{fallen?.name || 'Batter'} out · {fallen?.how || ''}</div>
          </div>
          <div className="ct-smart-rows">
            <div className="ct-smart-row"><span>Wickets lost</span><b>{state.wickets}</b></div>
            <div className="ct-smart-row"><span>Next bat</span><b>{state.batters[state.striker].name}</b></div>
          </div>
        </div>
      );
    }
    if (id === 'topbat') {
      const top = [...state.batters].sort((a,b) => b.r - a.r)[0];
      return (
        <div className="ct-smart-card">
          <div className="ct-smart-card-eye">TOP BATTER</div>
          <div className="ct-smart-2col">
            <div className="ct-smart-avatar">{top.name.split(' ').map(w=>w[0]).join('').slice(0,2)}</div>
            <div className="ct-smart-rows">
              <div className="ct-smart-row"><span>{top.name}</span><b>{top.r}{top.out ? '' : '*'}</b></div>
              <div className="ct-smart-row"><span>Balls</span><b>{top.b}</b></div>
              <div className="ct-smart-row"><span>4s · 6s</span><b>{top.fours} · {top.sixes}</b></div>
            </div>
          </div>
        </div>
      );
    }
    if (id === 'topbowl') {
      const top = [...state.bowlers].filter(b => b.balls).sort((a,b) => b.w - a.w || a.r - b.r)[0] || state.bowlers[state.bowlerIdx];
      const econ = top.balls ? (top.r/(top.balls/6)).toFixed(1) : '—';
      return (
        <div className="ct-smart-card">
          <div className="ct-smart-card-eye">TOP BOWLER</div>
          <div className="ct-smart-2col">
            <div className="ct-smart-avatar bowl">{top.name.split(' ').map(w=>w[0]).join('').slice(0,2)}</div>
            <div className="ct-smart-rows">
              <div className="ct-smart-row"><span>{top.name}</span><b>{top.w}-{top.r}</b></div>
              <div className="ct-smart-row"><span>Overs</span><b>{top.o.toFixed(1)}</b></div>
              <div className="ct-smart-row"><span>Econ</span><b>{econ}</b></div>
            </div>
          </div>
        </div>
      );
    }
    // projection
    const rr = state.balls ? (state.runs/(state.balls/6)) : 0;
    const projected = Math.round(state.balls ? state.runs + rr * (5 - state.balls/6) : 0);
    return (
      <div className="ct-smart-card">
        <div className="ct-smart-card-eye">PROJECTION · 5 OV</div>
        <div className="ct-smart-hero">
          <div className="ct-smart-big">{projected || '—'}</div>
          <div className="ct-smart-sub">projected at current rate</div>
        </div>
        <div className="ct-smart-rows">
          <div className="ct-smart-row"><span>Current RR</span><b>{rr.toFixed(1)}</b></div>
          <div className="ct-smart-row"><span>Balls left</span><b>{Math.max(0, 30 - state.balls)}</b></div>
        </div>
      </div>
    );
  };

  return (
    <ModalShell eye="✨ CRESTSMART™" title="Auto-detected insight" onClose={onClose} closeLabel="GOT IT">
      <div className="ct-smart-stage">
        {renderCard(ordered[page])}
      </div>
      <div className="ct-smart-pager">
        <button
          className="ct-smart-pager-btn"
          onClick={() => setPage(p => (p - 1 + ordered.length) % ordered.length)}
          aria-label="Previous card"
        >‹</button>
        <div className="ct-smart-pager-dots">
          {ordered.map((_, i) => (
            <span key={i} className={`ct-smart-dot ${i === page ? 'on' : ''}`}></span>
          ))}
        </div>
        <button
          className="ct-smart-pager-btn"
          onClick={() => setPage(p => (p + 1) % ordered.length)}
          aria-label="Next card"
        >›</button>
      </div>
      <div className="ct-smart-note">CrestSmart auto-picks the highest-signal moment. Swipe for context.</div>
    </ModalShell>
  );
}

function BowlerModal({ state, onPick, onClose }) {
  return (
    <ModalShell eye="SELECT BOWLER" title="Who's bowling the next over?" onClose={onClose} closeLabel="CANCEL">
      <div className="ct-bowler-list">
        {state.bowlers.map((b) => (
          <button
            key={b.name}
            data-cert={`modal-pick-${b.name}`}
            className={`ct-bowler-row ${b.name === state.currentBowler ? 'used' : ''}`}
            onClick={(e) => onPick(b.name, e)}
            disabled={b.name === state.currentBowler}
          >
            <span className="ct-bowler-mark">{b.name.charAt(0)}</span>
            <span className="ct-bowler-name">{b.name}</span>
            <span className="ct-bowler-stats">
              {b.o.toFixed(1)} · {b.r}-{b.w}
              {b.name === state.currentBowler && <i> · LAST OVER</i>}
            </span>
          </button>
        ))}
      </div>
    </ModalShell>
  );
}

function WicketModal({ onPick, onClose }) {
  // Dismissal modes per TESTER_GUIDE.md scoring keypad spec.
  const modes = ['Bowled', 'Caught', 'LBW', 'Run Out', 'Stumped', 'Hit Wicket'];
  return (
    <ModalShell eye="DISMISSAL" title="How was the batter out?" onClose={onClose} closeLabel="CANCEL">
      <div className="ct-wicket-grid">
        {modes.map(m => (
          <button
            key={m}
            data-cert={`modal-pick-${m}`}
            className="ct-wicket-tile"
            onClick={(e) => onPick(m, e)}
          >
            <span className="ct-wicket-name">{m.toUpperCase()}</span>
          </button>
        ))}
      </div>
    </ModalShell>
  );
}

function DrinksModal({ onClose }) {
  return (
    <ModalShell eye="MATCH PAUSED" title="Drinks Break · 90 sec" onClose={onClose} closeLabel="PLAY ON">
      <div className="ct-drinks">
        <div className="ct-drinks-art" aria-hidden="true">
          <svg viewBox="0 0 80 80" width="64" height="64" fill="none" stroke="#F59E0B" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
            <path d="M22 20h36l-4 44a6 6 0 0 1-6 6H32a6 6 0 0 1-6-6L22 20z"/>
            <path d="M22 30h36"/>
            <path d="M40 12v8"/>
          </svg>
        </div>
        <div className="ct-drinks-body">Players are hydrating. Scoreboard is saved automatically; you'll pick up exactly where you left off.</div>
      </div>
    </ModalShell>
  );
}

// ─── Post-match free-explore stage ───────────────────────────────────────
// User taps any tab in any order. A "tabs explored" counter HUD ticks them
// off; "Generate certificate" unlocks at 4/7 (and turns gold at 7/7).

const PM_TABS = [
  { id:'summary',    label:'SUMMARY' },
  { id:'hawkeye',    label:'HAWK-EYE' },
  { id:'wagon',      label:'WAGON' },
  { id:'pulse',      label:'PULSE' },
  { id:'predictor',  label:'WIN PROB' },
  { id:'report',     label:'REPORT' },
  { id:'flex',       label:'FLEX CARDS' },
];
const PM_MIN_TABS = 4;

function PostMatchStage({ finalState, matchDetails, onFinish, onBack, onSkip }) {
  const [tab, setTab] = useState(0);
  const [visited, setVisited] = useState(() => new Set(['summary']));

  const visit = (i) => {
    setTab(i);
    setVisited(v => {
      const next = new Set(v);
      next.add(PM_TABS[i].id);
      return next;
    });
  };

  const minMet = visited.size >= PM_MIN_TABS;
  const allDone = visited.size === PM_TABS.length;
  const won = Math.max(7, finalState.runs - 80);

  return (
    <div className="ct-postmatch">
      {onBack && (
        <button className="ct-back ct-back-floating" onClick={onBack}>
          <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M15 18l-6-6 6-6"/></svg>
          Back to scoring
        </button>
      )}
      <div className="ct-pm-banner">
        <div className="ct-pm-banner-left">
          <div className="ct-pm-banner-eye">★ MATCH COMPLETE</div>
          <div className="ct-pm-banner-title">CREST STRIKERS won by {won} runs</div>
          <div className="ct-pm-banner-sub">{finalState.runs}/{finalState.wickets} · {matchDetails?.overs || 5}.0 ov · RR {(finalState.runs/(matchDetails?.overs || 5)).toFixed(1)} · vs {matchDetails?.opp || 'Opposition'}</div>
        </div>
        <div className="ct-pm-banner-progress">
          <div className="ct-pm-banner-prog-lab">TABS EXPLORED</div>
          <div className="ct-pm-banner-prog-row">
            <div className="ct-pm-banner-bar"><div style={{width:`${(visited.size/PM_TABS.length)*100}%`}}></div></div>
            <span><b>{visited.size}</b> / {PM_TABS.length}</span>
          </div>
          {minMet ? (
            <button
              data-cert="pm-generate"
              className={`ct-pm-banner-cta ${allDone ? 'gold' : ''}`}
              onClick={onFinish}
            >
              {allDone ? '★ GENERATE CERTIFICATE' : 'GENERATE CERTIFICATE'}
              <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg>
            </button>
          ) : (
            <div className="ct-pm-banner-cta locked">
              <svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><rect x="4" y="10" width="16" height="11" rx="2"/><path d="M8 10V7a4 4 0 0 1 8 0v3"/></svg>
              <span>UNLOCK AT {PM_MIN_TABS}/{PM_TABS.length}</span>
            </div>
          )}
        </div>
      </div>

      <div className="ct-pm-tabs">
        {PM_TABS.map((t, i) => (
          <button
            key={t.id}
            data-cert={`pm-tab-${t.id}`}
            className={`ct-pm-tab ${i === tab ? 'active' : ''} ${visited.has(t.id) && i !== tab ? 'visited' : ''}`}
            onClick={() => visit(i)}
          >
            {t.label}
            {visited.has(t.id) && i !== tab && <span className="ct-pm-tick">✓</span>}
          </button>
        ))}
      </div>

      <div className="ct-pm-body">
        {PM_TABS[tab].id === 'summary'   && <PMSummary state={finalState} matchDetails={matchDetails}/>}
        {PM_TABS[tab].id === 'hawkeye'   && <PMHawkeye/>}
        {PM_TABS[tab].id === 'wagon'     && <PMWagon state={finalState}/>}
        {PM_TABS[tab].id === 'pulse'     && <PMPulse/>}
        {PM_TABS[tab].id === 'predictor' && <PMPredictor/>}
        {PM_TABS[tab].id === 'report'    && <PMReport state={finalState} matchDetails={matchDetails}/>}
        {PM_TABS[tab].id === 'flex'      && <PMFlex state={finalState} matchDetails={matchDetails}/>}
      </div>

      <button className="ct-pm-skip" onClick={onSkip}>Skip review →</button>
    </div>
  );
}

function PMSummary({ state, matchDetails }) {
  const ov = matchDetails?.overs || 5;
  const venue = matchDetails?.venue || 'Venue';
  const format = matchDetails?.format || 'T5';
  const comp = matchDetails?.comp || 'Friendly';
  return (
    <div className="ct-pm-summary">
      <div className="ct-pm-card">
        <div className="ct-pm-eye">RESULT</div>
        <div className="ct-pm-result">CREST STRIKERS won by <b>{Math.max(7, state.runs - 80)} runs</b></div>
        <div className="ct-pm-meta">{ov} ov · {venue.split(',')[0]} · {format} {comp}</div>
      </div>
      <div className="ct-pm-stat-grid">
        <div className="ct-pm-stat"><span>TOTAL</span><b>{state.runs}/{state.wickets}</b></div>
        <div className="ct-pm-stat"><span>RUN RATE</span><b>{(state.runs / 5).toFixed(1)}</b></div>
        <div className="ct-pm-stat"><span>BOUNDARIES</span><b>{state.overs.flat().filter(b => b==='4'||b==='6').length}</b></div>
        <div className="ct-pm-stat"><span>EXTRAS</span><b>{state.extras}</b></div>
      </div>
      <div className="ct-pm-bat-table">
        <div className="ct-pm-table-head">BATTING</div>
        {state.batters.filter(b => b.b > 0 || b.out).slice(0, 6).map((b, i) => (
          <div key={i} className="ct-pm-table-row">
            <span className="ct-pm-name">{b.name}</span>
            <span className="ct-pm-how">{b.out ? b.how : (i === state.striker ? 'not out *' : i === state.nonStriker ? 'not out' : 'did not bat')}</span>
            <span className="ct-pm-r"><b>{b.r}</b> ({b.b})</span>
          </div>
        ))}
      </div>
    </div>
  );
}

function PMHawkeye() {
  return (
    <div className="ct-pm-viz">
      <div className="ct-pm-viz-head">HAWK-EYE · DELIVERY MAP</div>
      <div className="ct-hawkeye">
        <div className="ct-pitch"></div>
        {Array.from({length: 30}, (_, i) => {
          const x = 30 + (i*7) % 130;
          const y = 80 + Math.sin(i*1.3)*60 + i*1.5;
          const type = i % 9 === 0 ? 'w' : i % 5 === 0 ? '6' : i % 3 === 0 ? '4' : 'd';
          return <span key={i} className={`ct-he-dot ct-he-${type}`} style={{left:`${x}px`, top:`${y}px`}}></span>;
        })}
      </div>
      <div className="ct-pm-leg">
        <span><i style={{background:'#3B82F6'}}></i>4s</span>
        <span><i style={{background:'#F59E0B'}}></i>6s</span>
        <span><i style={{background:'#EF4444'}}></i>Wickets</span>
        <span><i style={{background:'#475569'}}></i>Dots</span>
      </div>
    </div>
  );
}

function PMWagon({ state }) {
  return (
    <div className="ct-pm-viz">
      <div className="ct-pm-viz-head">WAGON WHEEL · WHERE THE RUNS WENT</div>
      <div className="ct-wagon-large">
        <div className="ct-wagon-ring"></div>
        <div className="ct-wagon-pitch"></div>
        {[[40,30,'#3B82F6'],[200,40,'#3B82F6'],[260,80,'#F59E0B'],[80,180,'#22C55E'],[230,200,'#22C55E'],[140,260,'#3B82F6'],[260,180,'#F59E0B'],[60,80,'#3B82F6'],[170,30,'#F59E0B'],[200,260,'#3B82F6']].map(([x,y,c],i)=>(
          <div key={i} className="ct-wagon-line" style={{'--x':`${x}px`,'--y':`${y}px`,'--c':c,'--len':`${Math.hypot(x-150,y-150)}px`,'--ang':`${Math.atan2(y-150,x-150)*180/Math.PI}deg`}}></div>
        ))}
      </div>
      <div className="ct-pm-leg">
        <span><i style={{background:'#3B82F6'}}></i>4s ({state.overs.flat().filter(b=>b==='4').length})</span>
        <span><i style={{background:'#F59E0B'}}></i>6s ({state.overs.flat().filter(b=>b==='6').length})</span>
        <span><i style={{background:'#22C55E'}}></i>Ones</span>
      </div>
    </div>
  );
}

function PMPulse() {
  return (
    <div className="ct-pm-viz">
      <div className="ct-pm-viz-head">CRESTPULSE™ · BALL-BY-BALL MOMENTUM</div>
      <svg viewBox="0 0 320 160" className="ct-pulse-chart" preserveAspectRatio="none">
        <defs>
          <linearGradient id="pg" x1="0" y1="0" x2="0" y2="1">
            <stop offset="0%" stopColor="#F59E0B" stopOpacity="0.5"/>
            <stop offset="100%" stopColor="#3B82F6" stopOpacity="0.1"/>
          </linearGradient>
        </defs>
        <path d="M0,120 L20,100 L40,90 L60,70 L80,80 L100,60 L120,50 L140,40 L160,30 L180,38 L200,28 L220,40 L240,25 L260,18 L280,30 L300,14 L320,8" stroke="#F59E0B" strokeWidth="2.5" fill="none"/>
        <path d="M0,120 L20,100 L40,90 L60,70 L80,80 L100,60 L120,50 L140,40 L160,30 L180,38 L200,28 L220,40 L240,25 L260,18 L280,30 L300,14 L320,8 L320,160 L0,160 Z" fill="url(#pg)"/>
      </svg>
      <div className="ct-pm-leg">
        <span><i style={{background:'#F59E0B'}}></i>Pulse · Player 1</span>
        <span className="ct-pulse-tier-tag">PEAKED · UNLEASHED</span>
      </div>
    </div>
  );
}

function PMPredictor() {
  return (
    <div className="ct-pm-viz">
      <div className="ct-pm-viz-head">WIN PREDICTOR <span className="ct-elite-tag">★ ELITE</span></div>
      <svg viewBox="0 0 320 160" className="ct-pulse-chart" preserveAspectRatio="none">
        <path d="M0,80 L40,68 L80,50 L120,40 L160,30 L200,18 L240,12 L280,8 L320,4" stroke="#3B82F6" strokeWidth="2.5" fill="none"/>
        <path d="M0,80 L40,92 L80,120 L120,130 L160,140 L200,148 L240,152 L280,154 L320,156" stroke="#EF4444" strokeWidth="2.5" fill="none"/>
      </svg>
      <div className="ct-pm-pred">
        <div className="ct-pm-pred-row"><span className="ct-pm-pred-team">STR</span><div className="ct-pm-pred-bar"><div style={{width:'94%',background:'#3B82F6'}}></div></div><b>94%</b></div>
        <div className="ct-pm-pred-row"><span className="ct-pm-pred-team">RIN</span><div className="ct-pm-pred-bar"><div style={{width:'6%',background:'#EF4444'}}></div></div><b>6%</b></div>
      </div>
    </div>
  );
}

function PMReport({ state, matchDetails }) {
  const opp = matchDetails?.opp || 'Opposition';
  const ov = matchDetails?.overs || 5;
  const rr = (state.runs / ov).toFixed(1);
  return (
    <div className="ct-pm-report">
      <div className="ct-pm-report-doc">
        <div className="ct-pm-report-head">
          <span>CREST STRIKERS · MATCH REPORT</span>
          <span>PDF · A4</span>
        </div>
        <div className="ct-pm-report-title">vs {opp} · 24 May 2026</div>
        <div className="ct-pm-report-stats">
          <div><span>TOTAL</span><b>{state.runs}/{state.wickets}</b></div>
          <div><span>OVERS</span><b>{ov}.0</b></div>
          <div><span>RR</span><b>{rr}</b></div>
        </div>
        <div className="ct-pm-report-lines">
          {Array.from({length: 16}, (_, i) => <span key={i} className="ct-pm-report-line" style={{width:`${50 + Math.sin(i*1.7)*30}%`}}></span>)}
        </div>
        <div className="ct-pm-report-foot">© CREST · Auto-generated · 2 pages</div>
      </div>
      <button className="ct-pm-dl" onClick={(e) => e.stopPropagation()}>
        <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M12 4v12M6 12l6 6 6-6M5 21h14"/></svg>
        DOWNLOAD PDF
      </button>
    </div>
  );
}

function PMFlex({ state, matchDetails }) {
  const oppShort = matchDetails?.oppShort || 'OPP';
  return (
    <div className="ct-pm-flex">
      <div className="ct-pm-flex-head">FLEX CARDS · 4 STYLES READY</div>
      <div className="ct-pm-flex-grid">
        <div className="ct-flex-tile ct-flex-winner">
          <div className="ct-flex-eye">— MATCH RESULT —</div>
          <div className="ct-flex-big">STRIKERS WIN</div>
          <div className="ct-flex-sub">BY {Math.max(7, state.runs - 80)} RUNS</div>
          <div className="ct-flex-score">{state.runs}/{state.wickets} vs 80</div>
          <div className="ct-flex-tag">WINNER</div>
        </div>
        <div className="ct-flex-tile ct-flex-potm">
          <div className="ct-flex-photo">P1</div>
          <div className="ct-flex-eye">— PLAYER OF THE MATCH —</div>
          <div className="ct-flex-name">PLAYER <b>1</b></div>
          <div className="ct-flex-hero">{state.batters[0].r} <span>R</span></div>
          <div className="ct-flex-tag">PORTRAIT</div>
        </div>
        <div className="ct-flex-tile ct-flex-scorecard">
          <div className="ct-flex-eye">— FULL SCORECARD —</div>
          <div className="ct-flex-scorecard-rows">
            <div>STR <b>{state.runs}/{state.wickets}</b> ({matchDetails?.overs || 5}.0)</div>
            <div>{oppShort} <b>80</b> ({matchDetails?.overs || 5}.0)</div>
            <div className="ct-flex-result">STRIKERS WON BY {Math.max(7, state.runs - 80)} RUNS</div>
          </div>
          <div className="ct-flex-tag">SCORECARD</div>
        </div>
        <div className="ct-flex-tile ct-flex-spell">
          <div className="ct-flex-eye">— BOWLING SPELL —</div>
          <div className="ct-flex-name">{state.bowlers[4].name}</div>
          <div className="ct-flex-hero">{state.bowlers[4].w} <span>W</span></div>
          <div className="ct-flex-sub">{state.bowlers[4].r} runs · 1 over</div>
          <div className="ct-flex-tag">SPELL</div>
        </div>
      </div>
      <button className="ct-pm-flex-share">
        <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M4 12v8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8M16 6l-4-4-4 4M12 2v13"/></svg>
        SHARE CARDS
      </button>
    </div>
  );
}

// ─── Certificate ────────────────────────────────────────────────────────────

function CertificateStage({ finalState, events, matchDetails, onRestart, onBack, onExit }) {
  const [name, setName] = useState('');
  const date = useMemo(() => {
    return new Date().toLocaleDateString('en-GB', { day: '2-digit', month: 'short', year: 'numeric' }).toUpperCase();
  }, []);
  const cred = useMemo(() => 'CREST-' + Math.random().toString(36).slice(2, 8).toUpperCase(), []);

  // Confetti — light, brand-coloured
  const conf = useMemo(() => Array.from({length: 28}, (_, i) => ({
    left: Math.random()*100,
    delay: Math.random()*0.6,
    color: ['#F59E0B', '#3B82F6', '#22C55E', '#FFFFFF'][i % 4],
    rot: Math.random()*360,
    size: 6 + Math.random()*6,
  })), []);

  const shareText = encodeURIComponent(`I just got CREST Certified — scored a live 5-over match end-to-end. Try it: crestcricket.com`);

  return (
    <div className="ct-certificate-wrap">
      {onBack && (
        <button className="ct-back ct-back-floating" onClick={onBack}>
          <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M15 18l-6-6 6-6"/></svg>
          Back to review
        </button>
      )}
      <div className="ct-confetti" aria-hidden="true">
        {conf.map((c, i) => (
          <span key={i} className="ct-confetti-piece" style={{
            left:`${c.left}%`, background:c.color, animationDelay:`${c.delay}s`,
            transform:`rotate(${c.rot}deg)`, width:`${c.size}px`, height:`${c.size*0.4}px`,
          }}/>
        ))}
      </div>

      <div className="ct-cert-title">
        <div className="ct-cert-eye">★ DRILL COMPLETE</div>
        <h1>You're <span className="ct-accent">CREST Certified</span>.</h1>
        <p>Share it — or print it and stick it on the dressing-room wall.</p>
      </div>

      <div className="ct-cert">
        <div className="ct-cert-corner ct-cert-corner-tl"></div>
        <div className="ct-cert-corner ct-cert-corner-tr"></div>
        <div className="ct-cert-corner ct-cert-corner-bl"></div>
        <div className="ct-cert-corner ct-cert-corner-br"></div>

        <div className="ct-cert-head">
          <img src="assets/crest_logo.png" alt="" className="ct-cert-logo"/>
          <div className="ct-cert-head-text">
            <div className="ct-cert-head-brand">CREST</div>
            <div className="ct-cert-head-sub">CRICKET INTELLIGENCE</div>
          </div>
        </div>

        <div className="ct-cert-eye-line">— CERTIFICATE OF PROFICIENCY —</div>
        <div className="ct-cert-line-1">This is to certify that</div>

        <div className="ct-cert-name-wrap">
          <input
            className="ct-cert-name-input"
            value={name}
            onChange={(e) => setName(e.target.value.slice(0, 30))}
            placeholder="YOUR NAME"
            spellCheck={false}
          />
          <div className="ct-cert-name-rule"></div>
        </div>

        <div className="ct-cert-body">
          has successfully completed the CREST Scorer Drill —<br/>
          demonstrating fluency with the scorebook, CrestPulse™, CrestSmart™,<br/>
          the broadcast toolkit and the ball-tagging intel modals.
        </div>

        <div className="ct-cert-foot">
          <div className="ct-cert-foot-col">
            <div className="ct-cert-foot-lab">ISSUED</div>
            <div className="ct-cert-foot-val">{date}</div>
          </div>
          <div className="ct-cert-seal">
            <svg viewBox="0 0 80 80" width="64" height="64">
              <circle cx="40" cy="40" r="36" fill="none" stroke="#F59E0B" strokeWidth="1.5"/>
              <circle cx="40" cy="40" r="30" fill="none" stroke="#F59E0B" strokeWidth="0.5"/>
              <text x="40" y="36" textAnchor="middle" fill="#F59E0B" style={{font:'700 8px Barlow,sans-serif',letterSpacing:'1.5px'}}>CREST</text>
              <text x="40" y="46" textAnchor="middle" fill="#F59E0B" style={{font:'600 5px Barlow,sans-serif',letterSpacing:'1px'}}>CERTIFIED</text>
              <text x="40" y="55" textAnchor="middle" fill="#F59E0B" style={{font:'600 4.5px Barlow,sans-serif',letterSpacing:'0.5px'}}>★ SCORER</text>
            </svg>
          </div>
          <div className="ct-cert-foot-col">
            <div className="ct-cert-foot-lab">CRED. NO.</div>
            <div className="ct-cert-foot-val">{cred}</div>
          </div>
        </div>
      </div>

      <div className="ct-cert-actions">
        <a
          className="ct-share ct-share-x"
          href={`https://twitter.com/intent/tweet?text=${shareText}`}
          target="_blank" rel="noopener noreferrer"
        >
          <svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/></svg>
          POST TO X
        </a>
        <a
          className="ct-share ct-share-li"
          href={`https://www.linkedin.com/sharing/share-offsite/?url=${encodeURIComponent('https://crestcricket.com')}`}
          target="_blank" rel="noopener noreferrer"
        >
          <svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor"><path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.049c.476-.9 1.637-1.852 3.37-1.852 3.602 0 4.267 2.37 4.267 5.455v6.288zM5.337 7.433a2.062 2.062 0 11-.001-4.125 2.062 2.062 0 010 4.125zM3.555 20.452h3.564V9H3.555v11.452z"/></svg>
          SHARE ON LINKEDIN
        </a>
        <a
          className="ct-share ct-share-wa"
          href={`https://wa.me/?text=${shareText}`}
          target="_blank" rel="noopener noreferrer"
        >
          <svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor"><path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.149-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.151-.174.2-.298.3-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51l-.57-.01c-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413"/></svg>
          SHARE ON WHATSAPP
        </a>
        <button className="ct-share ct-share-dl" onClick={() => window.print()}>
          <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M12 4v12M6 12l6 6 6-6M5 21h14"/></svg>
          PRINT / SAVE PDF
        </button>
      </div>

      <div className="ct-cert-after">
        <button className="ct-cert-restart" onClick={onRestart}>
          <svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M3 12a9 9 0 0 1 15.5-6.3L21 8M21 3v5h-5"/></svg>
          Restart drill
        </button>
        <button className="ct-cert-exit" onClick={onExit}>← Back to tour</button>
      </div>
    </div>
  );
}

// ─── Root ───────────────────────────────────────────────────────────────────

function CrestCertificationTest({ onExit }) {
  const [stage, setStage] = useState('intro'); // intro · setup · squads · scoring · innings_complete · postmatch · cert
  const [matchDetails, setMatchDetails] = useState(null);
  const [squads, setSquads] = useState(null);
  const [finalState, setFinalState] = useState(null);
  const [finalEvents, setFinalEvents] = useState([]);

  const completeScoring = (state, events) => {
    setFinalState(state);
    setFinalEvents(events);
    setStage('innings_complete');
    setTimeout(() => setStage('postmatch'), 1400);
  };

  const skip = () => setStage('cert');

  const restart = () => {
    setMatchDetails(null);
    setSquads(null);
    setFinalState(null);
    setFinalEvents([]);
    setStage('intro');
  };

  // Click-back from the rail — jumps to any earlier completed stage.
  const order = ['intro','setup','squads','scoring','innings_complete','postmatch','cert'];
  const cur = order.indexOf(stage);
  const railClick = (target) => {
    const t = order.indexOf(target);
    if (t < cur) setStage(target);
  };

  return (
    <div className="ct-root">
      <div className="ct-rail">
        <div className="ct-rail-brand">
          <img src="assets/crest_logo.png" alt="" className="ct-rail-logo"/>
          <span>CREST · DRILL</span>
        </div>
        <div className="ct-rail-steps">
          {[
            { k:'intro',     l:'INTRO' },
            { k:'setup',     l:'MATCH' },
            { k:'squads',    l:'SQUADS' },
            { k:'scoring',   l:'SCORE' },
            { k:'postmatch', l:'REVIEW' },
            { k:'cert',      l:'BADGE' },
          ].map((s, i) => {
            const mine = order.indexOf(s.k);
            const done = cur > mine || (s.k === 'scoring' && stage === 'innings_complete');
            const active = cur === mine || (s.k === 'scoring' && stage === 'innings_complete');
            const clickable = done && !active;
            return (
              <button
                key={i}
                type="button"
                className={`ct-rail-step ${active?'active':''} ${done?'done':''} ${clickable?'clickable':''}`}
                onClick={() => clickable && railClick(s.k)}
                disabled={!clickable}
                title={clickable ? `Go back to ${s.l}` : ''}
              >
                <span className="ct-rail-dot">{done && !active ? '✓' : i+1}</span>
                <span className="ct-rail-label">{s.l}</span>
              </button>
            );
          })}
        </div>
        <button className="ct-rail-exit" onClick={onExit}>← Exit drill</button>
      </div>

      <div className="ct-stage">
        {stage === 'intro' && <IntroStage onStart={() => setStage('setup')}/>}
        {stage === 'setup' && (
          <SetupStage
            initial={matchDetails}
            onBack={() => setStage('intro')}
            onConfirm={(md) => { setMatchDetails(md); setStage('squads'); }}
          />
        )}
        {stage === 'squads' && (
          <SquadsStage
            matchDetails={matchDetails}
            initial={squads}
            onBack={() => setStage('setup')}
            onConfirm={(sq) => { setSquads(sq); setStage('scoring'); }}
          />
        )}
        {stage === 'scoring' && (
          <ScoringStage
            matchDetails={matchDetails}
            squads={squads}
            onComplete={completeScoring}
            onBack={() => setStage('squads')}
            onSkip={skip}
          />
        )}
        {stage === 'innings_complete' && finalState && <InningsCompleteOverlay state={finalState} matchDetails={matchDetails}/>}
        {stage === 'postmatch' && finalState && window.BallTaggingStage && (() => {
          const BallTaggingStage = window.BallTaggingStage;
          return (
            <BallTaggingStage
              finalState={finalState}
              matchDetails={matchDetails}
              onFinish={() => setStage('cert')}
              onBack={() => setStage('scoring')}
              onSkip={skip}
            />
          );
        })()}
        {stage === 'cert' && (
          <CertificateStage
            finalState={finalState || { runs: 0, wickets: 0 }}
            events={finalEvents}
            matchDetails={matchDetails}
            onRestart={restart}
            onBack={() => setStage('postmatch')}
            onExit={onExit}
          />
        )}
      </div>
    </div>
  );
}

function InningsCompleteOverlay({ state, matchDetails }) {
  const ov = matchDetails?.overs || 5;
  return (
    <div className="ct-innings-done">
      <div className="ct-innings-card">
        <div className="ct-innings-eye">★ INNINGS COMPLETE</div>
        <div className="ct-innings-score">{state.runs}<span>/{state.wickets}</span></div>
        <div className="ct-innings-meta">{ov}.0 overs · RR {(state.runs/ov).toFixed(1)}</div>
        <div className="ct-innings-sub">Reviewing post-match analytics…</div>
      </div>
    </div>
  );
}

window.CrestCertificationTest = CrestCertificationTest;
