/* Predict page — three numbered blocks: choose match, pick winner, your details. */

function NumberedHeader({ n, label }) {
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 14, marginBottom: 22 }}>
      <div className="clip-paral font-display" style={{
        width: 54, height: 44, background: 'var(--orange)', color: '#fff',
        display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 18, flexShrink: 0,
      }}>
        {String(n).padStart(2, '0')}
      </div>
      <h2 className="font-display" style={{
        margin: 0, fontSize: 22, letterSpacing: '0.06em', textTransform: 'uppercase',
      }}>
        {label}
      </h2>
    </div>
  );
}

/* ---------- Match list ---------- */
function MatchCard({ match, selected, onSelect }) {
  const disabled = match.status !== 'OPEN';
  const ko = formatKickoff(match.kickoffAt);

  return (
    <button
      onClick={() => !disabled && onSelect(match.id)}
      disabled={disabled}
      style={{
        background: 'none', border: 'none', padding: 0, width: '100%', textAlign: 'left',
        cursor: disabled ? 'not-allowed' : 'pointer',
        opacity: disabled ? 0.55 : 1,
      }}>
      <div className="lift" style={{
        background: selected ? 'var(--orange-50)' : '#fff',
        border: selected ? '2px solid var(--orange)' : '1px solid var(--grey-200)',
        borderRadius: 10,
        overflow: 'hidden',
        boxShadow: selected
          ? '0 4px 20px rgba(241,86,35,0.22)'
          : (disabled ? 'none' : '0 2px 10px rgba(17,6,24,0.06)'),
        padding: 0,
        position: 'relative',
        ...(disabled ? {} : { cursor: 'pointer' }),
      }}
      onMouseEnter={(e) => {
        if (disabled || selected) return;
        e.currentTarget.style.borderColor = 'var(--orange)';
        e.currentTarget.style.transform = 'translateY(-2px)';
        e.currentTarget.style.boxShadow = '0 6px 18px rgba(241,86,35,0.16)';
      }}
      onMouseLeave={(e) => {
        if (disabled || selected) return;
        e.currentTarget.style.borderColor = 'var(--grey-200)';
        e.currentTarget.style.transform = 'translateY(0)';
        e.currentTarget.style.boxShadow = '0 2px 10px rgba(17,6,24,0.06)';
      }}>
        {/* Header: status + countdown */}
        <div style={{
          display: 'flex', justifyContent: 'space-between', alignItems: 'center',
          padding: '12px 18px', borderBottom: '1px solid var(--grey-200)',
          background: selected ? 'transparent' : 'var(--grey-50)',
        }}>
          <StatusBadge status={match.status} size="sm" />
          {match.status === 'OPEN' && <Countdown to={match.kickoffMs} tone="orange" size="sm" prefix="CLOSE" />}
          {match.status === 'SCHEDULED' && <Countdown to={match.kickoffMs - HOURS(24)} tone="light" size="sm" prefix="OPENS" />}
          {match.status === 'CLOSED' && (
            <span className="font-mono" style={{ fontSize: 11, color: 'var(--grey-500)', letterSpacing: '0.08em' }}>AWAITING RESULT</span>
          )}
          {match.status === 'SETTLED' && match.settled && (
            <span className="font-mono" style={{ fontSize: 12, color: 'var(--ink)', letterSpacing: '0.04em', fontWeight: 700 }}>
              {match.settled.scoreA}–{match.settled.scoreB}
            </span>
          )}
        </div>

        {/* Top: teams + VS */}
        <div className="match-row" style={{
          display: 'grid',
          gridTemplateColumns: '1fr auto 1fr',
          alignItems: 'center', gap: 12,
          padding: '18px 18px 14px',
        }}>
          <TeamRow team={match.teamA} align="left" />
          <VSHex size={40} />
          <TeamRow team={match.teamB} align="right" />
        </div>

        {/* Foot strip */}
        <div style={{
          background: 'var(--grey-50)', borderTop: '1px solid var(--grey-200)',
          padding: '10px 18px',
          display: 'flex', gap: 20, fontSize: 12, color: 'var(--grey-600)', flexWrap: 'wrap',
        }}>
          <FootItem icon="calendar">{ko}</FootItem>
          <FootItem icon="flag">{match.stage}</FootItem>
          <FootItem icon="pin">{match.venue}</FootItem>
        </div>
      </div>
    </button>
  );
}

function TeamRow({ team, align }) {
  return (
    <div style={{
      display: 'flex', alignItems: 'center', gap: 10,
      flexDirection: align === 'right' ? 'row-reverse' : 'row',
      textAlign: align,
      minWidth: 0,
    }}>
      <Flag code={team.flag} w={42} h={28} />
      <div className="font-display" style={{ fontSize: 'clamp(15px, 3.4vw, 18px)', letterSpacing: '-0.01em', minWidth: 0 }}>{team.name}</div>
    </div>
  );
}

function FootItem({ icon, children }) {
  return (
    <span style={{ display: 'inline-flex', alignItems: 'center', gap: 7 }}>
      <Icon name={icon} size={14} color="var(--grey-500)" />
      {children}
    </span>
  );
}

/* ---------- Pick winner ---------- */
function PickButton({ kind, label, selected, onClick, disabled, flagCode }) {
  return (
    <button
      onClick={onClick}
      disabled={disabled}
      className="lift"
      style={{
        position: 'relative',
        background: selected ? 'var(--orange-50)' : '#fff',
        border: selected ? '2px solid var(--orange)' : '1px solid var(--grey-200)',
        borderRadius: 10,
        boxShadow: selected ? '0 4px 16px rgba(241,86,35,0.22)' : '0 2px 8px rgba(17,6,24,0.05)',
        padding: '22px 18px',
        display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 14,
        cursor: disabled ? 'not-allowed' : 'pointer',
        opacity: disabled ? 0.4 : 1,
        minHeight: 168,
      }}
      onMouseEnter={(e) => {
        if (disabled || selected) return;
        e.currentTarget.style.borderColor = 'var(--orange)';
      }}
      onMouseLeave={(e) => {
        if (disabled || selected) return;
        e.currentTarget.style.borderColor = 'var(--grey-200)';
      }}
    >
      {selected && (
        <span style={{
          position: 'absolute', top: 10, right: 10, width: 10, height: 10,
          background: 'var(--orange)', borderRadius: '50%',
        }} />
      )}
      {kind === 'draw' ? (
        <div style={{
          width: 78, height: 56, background: 'var(--ink)', display: 'flex', alignItems: 'center', justifyContent: 'center',
        }}>
          <Icon name="scale" size={30} color="var(--orange)" />
        </div>
      ) : (
        <Flag code={flagCode} w={78} h={52} rounded={5} />
      )}
      <div className="font-display" style={{ fontSize: 15, textAlign: 'center', letterSpacing: '-0.01em' }}>
        {label}
      </div>
      <div style={{
        fontSize: 10, letterSpacing: '0.16em', textTransform: 'uppercase', color: 'var(--grey-500)', fontWeight: 700,
      }}>
        {kind === 'draw' ? 'Match drawn' : `${kind === 'A' ? 'Team A' : 'Team B'} wins`}
      </div>
    </button>
  );
}

/* ---------- Form field ---------- */
function Field({ label, hint, children, mono }) {
  return (
    <label style={{ display: 'block' }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline' }}>
        <span className="font-subheading" style={{ fontSize: 11.5, letterSpacing: '0.14em', textTransform: 'uppercase', color: 'var(--ink)' }}>{label}</span>
        {hint && <span style={{ fontSize: 11, color: 'var(--grey-500)', fontFamily: mono ? "'JetBrains Mono', monospace" : undefined }}>{hint}</span>}
      </div>
      <div style={{ marginTop: 8 }}>{children}</div>
    </label>
  );
}
const inputStyle = {
  width: '100%',
  border: '1.5px solid var(--grey-200)',
  borderRadius: 6,
  background: '#fff',
  padding: '13px 14px',
  fontSize: 15,
  color: 'var(--ink)',
  transition: 'border-color 0.15s, box-shadow 0.15s',
};

/* Inline pick button used inside match cards */
function InlinePickBtn({ label, selected, onClick, disabled }) {
  return (
    <button
      onClick={onClick}
      disabled={disabled}
      style={{
        padding: '9px 6px',
        border: selected ? '2px solid var(--orange)' : '1px solid var(--grey-200)',
        borderRadius: 8,
        background: selected ? 'var(--orange)' : '#fff',
        color: selected ? '#fff' : disabled ? 'var(--grey-400)' : 'var(--ink)',
        fontSize: 12, fontWeight: 700, textAlign: 'center',
        cursor: disabled ? 'not-allowed' : 'pointer',
        opacity: disabled ? 0.45 : 1,
        transition: 'all 0.12s',
        width: '100%',
        fontFamily: "'DM Sans', sans-serif",
        whiteSpace: 'nowrap',
        overflow: 'hidden',
        textOverflow: 'ellipsis',
      }}
    >
      {label}
    </button>
  );
}

/* ---------- Toast ---------- */
function SuccessToast({ message, onDone }) {
  useEffect(() => {
    const t = setTimeout(onDone, 4200);
    return () => clearTimeout(t);
  }, [onDone]);
  return (
    <div className="toast-in" style={{
      position: 'fixed', top: 22, left: '50%', zIndex: 50,
      background: 'var(--success-bg)', color: '#0f5f2e',
      border: '1px solid var(--success)',
      borderRadius: 8,
      boxShadow: '0 4px 16px rgba(15,95,46,0.12)',
      padding: '14px 22px',
      display: 'flex', alignItems: 'center', gap: 12, minWidth: 320, maxWidth: 560,
    }}>
      <div style={{ width: 28, height: 28, background: 'var(--success)', borderRadius: '50%', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
        <Icon name="check" size={18} color="#fff" stroke={3} />
      </div>
      <div style={{ fontSize: 14, fontWeight: 600, lineHeight: 1.4 }}>{message}</div>
    </div>
  );
}

/* ---------- Predict page — flow: Details → Match+Pick (inline) → Submit ---------- */
function PredictPage() {
  // Step 1 — Details
  const [name,   setName]   = useState('');
  const [phone,  setPhone]  = useState(''); // 7 digits only, +960 prefix fixed
  const [bill,   setBill]   = useState('');
  const [amount, setAmount] = useState('');
  // Match + Pick — combined (one active at a time)
  const [selectedMatchId, setSelectedMatchId] = useState(null);
  const [pick, setPick] = useState(null); // 'A' | 'DRAW' | 'B'

  // Per-card submission state
  const [submitting,    setSubmitting]    = useState(null);  // matchId being submitted
  const [cardErrors,    setCardErrors]    = useState({});    // { matchId: errorMsg }
  const [submitted,     setSubmitted]     = useState(new Set()); // matchIds done
  const [submittedPicks, setSubmittedPicks] = useState({});  // { matchId: 'A'|'DRAW'|'B' }

  const matchRef = useRef(null);
  const [showAllMatches, setShowAllMatches] = useState(false);

  // Bill validation state — explicit Validate button flow
  const [billValidation, setBillValidation] = useState({
    state: 'idle',   // 'idle' | 'validating' | 'valid' | 'invalid'
    error: null,
    maxVotes: 0, usedVotes: 0, remainingVotes: 0, amountMvr: 0,
  });

  // Reset validation when bill or amount changes
  useEffect(() => {
    setBillValidation(prev =>
      prev.state === 'idle' ? prev : { state: 'idle', error: null, maxVotes: 0, usedVotes: 0, remainingVotes: 0, amountMvr: 0 }
    );
    setSubmitted(new Set());
    setSubmittedPicks({});
  }, [bill, amount]);

  async function validateBill() {
    if (billValidation.state === 'validating') return;
    setBillValidation({ state: 'validating', error: null, maxVotes: 0, usedVotes: 0, remainingVotes: 0, amountMvr: 0 });
    try {
      const r = await fetch('/api/validate-bill', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ bill_number: bill.trim().toUpperCase(), amount_myr: parseFloat(amount) }),
      });
      const data = await r.json();
      if (data.valid) {
        setBillValidation({ state: 'valid', error: null, maxVotes: data.maxVotes, usedVotes: data.usedVotes, remainingVotes: data.remainingVotes, amountMvr: data.amountMvr });
        // Pre-populate prior predictions from DB
        const ids   = new Set((data.predictions || []).map(p => p.matchId));
        const pkMap = {};
        (data.predictions || []).forEach(p => { pkMap[p.matchId] = p.pick; });
        setSubmitted(ids);
        setSubmittedPicks(pkMap);
      } else {
        setBillValidation({ state: 'invalid', error: data.error || 'Bill validation failed.', maxVotes: 0, usedVotes: 0, remainingVotes: 0, amountMvr: 0 });
        setSubmitted(new Set());
        setSubmittedPicks({});
      }
    } catch (_) {
      setBillValidation({ state: 'invalid', error: 'Network error. Check connection and try again.', maxVotes: 0, usedVotes: 0, remainingVotes: 0, amountMvr: 0 });
    }
  }

  // All upcoming matches — open for voting until kickoff
  const allUpcoming = useMemo(() => {
    const nowMs = Date.now();
    return [...MATCHES]
      .filter(m => m.status !== 'SETTLED' && m.status !== 'CLOSED' && nowMs < m.kickoffMs)
      .sort((a, b) => a.kickoffMs - b.kickoffMs);
  }, []);

  const visibleMatches = showAllMatches ? allUpcoming : allUpcoming.slice(0, 6);

  // A match is voteable if kickoff hasn't happened yet
  const isVoteable = (m) => Date.now() < m.kickoffMs;

  // ── Validation ──
  const nameOk    = name.trim().length >= 2 && name.trim().length <= 80;
  const phoneOk   = /^\d{7}$/.test(phone.trim());
  const billOk    = bill.trim().length > 0 && bill.length <= 50;
  const amountOk  = !isNaN(parseFloat(amount)) && parseFloat(amount) > 0;
  // detailsOk requires bill validated against DB
  const detailsOk = nameOk && phoneOk && billValidation.state === 'valid';

  // Vote quota comes from validated bill
  const maxVotes       = billValidation.maxVotes;
  const remainingVotes = Math.max(0, maxVotes - submitted.size);

  // Enable Validate button when bill + amount are filled (name/phone not required yet)
  const canValidate = billOk && amountOk && billValidation.state !== 'validating';

  // Auto-scroll to matches when details become valid
  const prevDetailsOk = useRef(false);
  useEffect(() => {
    if (detailsOk && !prevDetailsOk.current && matchRef.current) {
      setTimeout(() => {
        const y = matchRef.current.getBoundingClientRect().top + window.scrollY - 80;
        window.scrollTo({ top: y, behavior: 'smooth' });
      }, 120);
    }
    prevDetailsOk.current = detailsOk;
  }, [detailsOk]);

  function selectPick(matchId, pickValue) {
    if (selectedMatchId === matchId && pick === pickValue) {
      setPick(null); // deselect
    } else {
      setSelectedMatchId(matchId);
      setPick(pickValue);
      // Clear error for this card when user changes pick
      setCardErrors(prev => { const n = {...prev}; delete n[matchId]; return n; });
    }
  }

  async function submitCard(m, cardPick) {
    if (submitting || submitted.has(m.id)) return;
    setCardErrors(prev => { const n = {...prev}; delete n[m.id]; return n; });
    setSubmitting(m.id);
    try {
      const res = await fetch('/api/submit-prediction', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          name:       name.trim(),
          phone:      '+960' + phone.trim(),
          bill:       bill.trim().toUpperCase(),
          amount:     billValidation.amountMvr,  // always use DB-verified amount
          matchId:    m.id,
          matchLabel: `${m.teamA.name} vs ${m.teamB.name}`,
          pick:       cardPick,
        }),
      });
      const data = await res.json();
      if (!res.ok) {
        setCardErrors(prev => ({ ...prev, [m.id]: data.error || 'Something went wrong. Try again.' }));
        setSubmitting(null);
        return;
      }
      // Success — mark card as done, record the pick, clear active selection
      setSubmitted(prev => new Set([...prev, m.id]));
      setSubmittedPicks(prev => ({ ...prev, [m.id]: cardPick }));
      setSelectedMatchId(null);
      setPick(null);
      // Update local remainingVotes (submitted.size drives it reactively)
    } catch (e) {
      setCardErrors(prev => ({ ...prev, [m.id]: 'Network error. Check your connection.' }));
    }
    setSubmitting(null);
  }

  const upcomingCount = allUpcoming.length;
  // For mobile sticky: find the active pick context
  const activeMatch = visibleMatches.find(m => m.id === selectedMatchId);

  return (
    <main style={{ paddingBottom: 120 }}>

      <PageBand
        eyebrow="Make your call"
        title={<>Pick the winner. <span style={{ color: 'var(--orange)' }}>Lock in your shot.</span></>}
        sub="Fill in your details, pick your match winner and submit. One bill, one prediction per match."
        right={
          <div className="hide-mobile" style={{ display: 'flex', gap: 24, alignItems: 'center' }}>
            <div style={{ textAlign: 'right' }}>
              <div className="font-highlight" style={{ fontSize: 11, letterSpacing: '0.14em', textTransform: 'uppercase', color: 'var(--grey-500)' }}>Upcoming matches</div>
              <div className="font-display" style={{ fontSize: 36, lineHeight: 1, marginTop: 4 }}>{upcomingCount}</div>
            </div>
          </div>
        }
      />

      <section style={{ padding: 'clamp(20px, 4vw, 32px) 0 clamp(40px, 8vw, 60px)' }}>
        <div style={{ maxWidth: 860, margin: '0 auto', padding: '0 clamp(16px, 4vw, 22px)' }}>

          {/* ── Block 1 — Your details ── */}
          <NumberedHeader n={1} label="Your details" />
          <div className="form-grid" style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: 16 }}>

            <Field label="Full name" hint={`${name.length}/80`}>
              <input
                type="text" value={name} maxLength={80} autoFocus
                onChange={(e) => setName(e.target.value)}
                placeholder="Full name"
                style={inputStyle}
              />
            </Field>

            <Field label="Mobile number" hint="7 digits">
              <div style={{ display: 'flex', alignItems: 'stretch', border: '1.5px solid var(--grey-200)', borderRadius: 6, overflow: 'hidden', background: '#fff', transition: 'border-color 0.15s, box-shadow 0.15s' }}>
                <div className="font-mono" style={{
                  padding: '13px 12px 13px 14px', background: 'var(--grey-50)',
                  borderRight: '1.5px solid var(--grey-200)',
                  fontSize: 15, fontWeight: 700, color: 'var(--ink)',
                  flexShrink: 0, display: 'flex', alignItems: 'center', userSelect: 'none',
                }}>
                  +960
                </div>
                <input
                  type="tel" inputMode="numeric"
                  value={phone}
                  maxLength={7}
                  onChange={(e) => setPhone(e.target.value.replace(/\D/g, '').slice(0, 7))}
                  placeholder="7-digit number"
                  className="font-mono"
                  style={{ ...inputStyle, border: 'none', flex: 1, borderRadius: 0, boxShadow: 'none' }}
                />
              </div>
            </Field>

            <Field label="Bill / receipt number" hint="auto-uppercased">
              <input
                type="text" value={bill} maxLength={50}
                onChange={(e) => setBill(e.target.value.toUpperCase())}
                placeholder="Bill number"
                autoCapitalize="characters" autoCorrect="off" spellCheck="false"
                className="input-upper font-mono"
                style={{
                  ...inputStyle,
                  fontFamily: "'JetBrains Mono', monospace",
                  borderColor: billValidation.state === 'valid' ? 'var(--success)' : billValidation.state === 'invalid' ? '#ef4444' : undefined,
                }}
              />
            </Field>

            <Field label="Bill amount (MVR)">
              <input
                type="number" inputMode="decimal" value={amount} min="0.01" step="0.01"
                onChange={(e) => setAmount(e.target.value)}
                placeholder="Amount"
                style={{
                  ...inputStyle,
                  borderColor: billValidation.state === 'valid' ? 'var(--success)' : billValidation.state === 'invalid' ? '#ef4444' : undefined,
                }}
              />
            </Field>
          </div>

          {/* ── Validate bill button + result ── */}
          <div style={{ marginTop: 14, display: 'flex', alignItems: 'center', gap: 12, flexWrap: 'wrap' }}>
            <button
              onClick={validateBill}
              disabled={!canValidate}
              className="font-display btn-press"
              style={{
                background: canValidate ? 'var(--ink)' : 'var(--grey-300)',
                color: '#fff', border: 'none', borderRadius: 6,
                padding: '12px 22px', fontSize: 13, letterSpacing: '0.06em', textTransform: 'uppercase',
                boxShadow: canValidate ? '0 4px 12px rgba(17,6,24,0.20)' : 'none',
                cursor: canValidate ? 'pointer' : 'not-allowed',
                display: 'inline-flex', alignItems: 'center', gap: 8,
                transition: 'background 0.15s',
              }}
            >
              {billValidation.state === 'validating'
                ? <><span style={{ width: 14, height: 14, border: '2px solid rgba(255,255,255,0.4)', borderTopColor: '#fff', borderRadius: '50%', display: 'inline-block', animation: 'spin 0.7s linear infinite' }} /> Validating…</>
                : <><Icon name="check" size={14} stroke={2.5} /> Validate Bill</>
              }
            </button>

            {/* Validation result */}
            {billValidation.state === 'valid' && (
              <div style={{
                display: 'inline-flex', alignItems: 'center', gap: 10,
                background: 'var(--success-bg)', border: '1px solid var(--success)',
                borderRadius: 8, padding: '10px 16px',
              }}>
                <div style={{ width: 24, height: 24, borderRadius: '50%', background: 'var(--success)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
                  <Icon name="check" size={14} color="#fff" stroke={3} />
                </div>
                <div>
                  <div style={{ fontSize: 13, fontWeight: 700, color: '#0f5f2e' }}>
                    Bill verified ·{' '}
                    <span style={{ color: 'var(--success)', fontSize: 16 }}>{remainingVotes}</span>
                    {' '}vote{remainingVotes !== 1 ? 's' : ''} remaining
                  </div>
                  {submitted.size > 0 && (
                    <div style={{ fontSize: 11.5, color: '#166534', marginTop: 2 }}>
                      {submitted.size} used · {maxVotes} total
                    </div>
                  )}
                </div>
              </div>
            )}

            {/* Invalid bill error */}
            {billValidation.state === 'invalid' && (
              <div style={{
                display: 'inline-flex', alignItems: 'center', gap: 8,
                background: '#fee2e2', border: '1px solid #fca5a5',
                borderRadius: 8, padding: '10px 16px',
                fontSize: 13, fontWeight: 600, color: '#b91c1c',
              }}>
                <Icon name="bolt" size={14} color="#b91c1c" />
                {billValidation.error}
              </div>
            )}
          </div>

          {/* ── Block 2 — Choose match + pick inline ── */}
          <div ref={matchRef} style={{
            marginTop: 48,
            opacity: detailsOk ? 1 : 0.35,
            pointerEvents: detailsOk ? 'auto' : 'none',
            transition: 'opacity 0.25s',
          }}>
            <NumberedHeader n={2} label="Pick your winner" />
            {!detailsOk && (
              <div style={{
                border: '2px dashed var(--grey-300)', padding: '22px 24px', borderRadius: 8,
                color: 'var(--grey-400)', fontSize: 14, marginBottom: 14, textAlign: 'center',
              }}>
                Validate your bill above to unlock match predictions.
              </div>
            )}

            <div style={{ display: 'grid', gap: 14 }}>
              {visibleMatches.map(m => {
                const isSubmitted  = submitted.has(m.id);
                const isSubmitting = submitting === m.id;
                const isSelected   = selectedMatchId === m.id;
                const currentPick  = isSelected ? pick : null;
                const voteable     = isVoteable(m);
                const cardError    = cardErrors[m.id];
                // Can submit: details valid, match not kicked off, votes remaining, not already submitted
                const canSubmit    = isSelected && currentPick && detailsOk && voteable && !isSubmitted && remainingVotes > 0;

                // ── Submitted success state — full match visualization ──
                if (isSubmitted) {
                  const myPick = submittedPicks[m.id]; // 'A' | 'DRAW' | 'B'
                  const ko = formatKickoff(m.kickoffAt);
                  return (
                    <div key={m.id} style={{
                      border: '2px solid var(--success)',
                      borderRadius: 12,
                      overflow: 'hidden',
                      background: '#fff',
                    }}>
                      {/* Success header */}
                      <div style={{
                        background: 'var(--success)', color: '#fff',
                        padding: '10px 16px',
                        display: 'flex', alignItems: 'center', gap: 10,
                        fontSize: 13, fontWeight: 700, letterSpacing: '0.04em',
                      }}>
                        <div style={{ width: 22, height: 22, borderRadius: '50%', background: 'rgba(255,255,255,0.25)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
                          <Icon name="check" size={13} color="#fff" stroke={3} />
                        </div>
                        Prediction locked in!
                        <span style={{ marginLeft: 'auto', fontSize: 11, fontWeight: 400, opacity: 0.85 }}>
                          {m.stage}
                        </span>
                      </div>

                      {/* Teams */}
                      <div style={{
                        display: 'grid', gridTemplateColumns: '1fr auto 1fr',
                        alignItems: 'center', gap: 10, padding: '16px 16px 10px',
                      }}>
                        <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 5 }}>
                          <Flag code={m.teamA.flag} w={48} h={32} />
                          <div className="font-display" style={{ fontSize: 14, textAlign: 'center', lineHeight: 1.2 }}>{m.teamA.name}</div>
                        </div>
                        <VSHex size={30} />
                        <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 5 }}>
                          <Flag code={m.teamB.flag} w={48} h={32} />
                          <div className="font-display" style={{ fontSize: 14, textAlign: 'center', lineHeight: 1.2 }}>{m.teamB.name}</div>
                        </div>
                      </div>

                      {/* Pick result — locked read-only buttons */}
                      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 8, padding: '0 16px 14px' }}>
                        {[
                          { key: 'A',    label: m.teamA.name },
                          { key: 'DRAW', label: 'Draw' },
                          { key: 'B',    label: m.teamB.name },
                        ].map(opt => {
                          const picked = myPick === opt.key;
                          return (
                            <div key={opt.key} style={{
                              padding: '9px 6px',
                              border: picked ? '2px solid var(--success)' : '1px solid var(--grey-200)',
                              borderRadius: 8,
                              background: picked ? 'var(--success)' : 'var(--grey-50)',
                              color: picked ? '#fff' : 'var(--grey-400)',
                              fontSize: 12, fontWeight: picked ? 700 : 500,
                              textAlign: 'center',
                              display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 4,
                            }}>
                              {picked && <Icon name="check" size={12} color="#fff" stroke={3} />}
                              {opt.label}
                            </div>
                          );
                        })}
                      </div>

                      {/* Match details footer */}
                      <div style={{
                        background: 'var(--grey-50)', borderTop: '1px solid var(--grey-100)',
                        padding: '8px 16px', fontSize: 11.5, color: 'var(--grey-500)',
                        display: 'flex', gap: 16, flexWrap: 'wrap',
                      }}>
                        <FootItem icon="calendar">{ko}</FootItem>
                        <FootItem icon="pin">{m.venue}</FootItem>
                        <span style={{ marginLeft: 'auto', fontSize: 11, color: '#0f5f2e', fontWeight: 600 }}>
                          ✓ Watch your phone for results
                        </span>
                      </div>
                    </div>
                  );
                }

                return (
                  <div key={m.id} style={{
                    border: isSelected ? '2px solid var(--orange)' : '1px solid var(--grey-200)',
                    borderRadius: 12,
                    background: isSelected ? 'var(--orange-50)' : '#fff',
                    boxShadow: isSelected ? '0 4px 20px rgba(241,86,35,0.18)' : '0 2px 8px rgba(17,6,24,0.06)',
                    overflow: 'hidden',
                    transition: 'border-color 0.15s, box-shadow 0.15s, background 0.15s',
                  }}>
                    {/* Card header — countdown to kickoff = prediction close */}
                    <div style={{
                      display: 'flex', justifyContent: 'space-between', alignItems: 'center',
                      padding: '10px 16px', borderBottom: '1px solid var(--grey-100)',
                      background: isSelected ? 'transparent' : 'var(--grey-50)',
                    }}>
                      <StatusBadge status={m.status} size="sm" />
                      {voteable && <Countdown to={m.kickoffMs} tone={m.status === 'OPEN' ? 'orange' : 'light'} size="sm" prefix="CLOSE" />}
                    </div>

                    {/* Teams */}
                    <div style={{
                      display: 'grid', gridTemplateColumns: '1fr auto 1fr',
                      alignItems: 'center', gap: 10, padding: '14px 16px 10px',
                    }}>
                      <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 5 }}>
                        <Flag code={m.teamA.flag} w={44} h={30} />
                        <div className="font-display" style={{ fontSize: 13.5, textAlign: 'center', lineHeight: 1.2 }}>{m.teamA.name}</div>
                      </div>
                      <VSHex size={30} />
                      <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 5 }}>
                        <Flag code={m.teamB.flag} w={44} h={30} />
                        <div className="font-display" style={{ fontSize: 13.5, textAlign: 'center', lineHeight: 1.2 }}>{m.teamB.name}</div>
                      </div>
                    </div>

                    {/* Pick buttons */}
                    {!voteable ? (
                      <div style={{ padding: '10px 16px 14px', fontSize: 12, color: 'var(--grey-400)', fontWeight: 600, letterSpacing: '0.06em', textTransform: 'uppercase' }}>
                        Predictions closed · Match started
                      </div>
                    ) : remainingVotes === 0 && !isSelected && detailsOk ? (
                      <div style={{ padding: '10px 16px 14px', fontSize: 12.5, color: 'var(--grey-500)' }}>
                        No votes remaining — increase your bill amount to vote on more matches.
                      </div>
                    ) : (
                      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 8, padding: '0 16px 14px' }}>
                        <InlinePickBtn label={m.teamA.name} selected={currentPick === 'A'} disabled={!voteable || (remainingVotes === 0 && !isSelected)} onClick={() => selectPick(m.id, 'A')} />
                        <InlinePickBtn label="Draw"         selected={currentPick === 'DRAW'} disabled={!voteable || (remainingVotes === 0 && !isSelected)} onClick={() => selectPick(m.id, 'DRAW')} />
                        <InlinePickBtn label={m.teamB.name} selected={currentPick === 'B'} disabled={!voteable || (remainingVotes === 0 && !isSelected)} onClick={() => selectPick(m.id, 'B')} />
                      </div>
                    )}

                    {/* ── Lock button + confirmation — appears on this card when pick made ── */}
                    {canSubmit && (
                      <div style={{
                        margin: '0 16px 16px',
                        background: '#fff',
                        border: '1.5px solid var(--orange)',
                        borderRadius: 10,
                        padding: '14px 16px',
                        display: 'flex', alignItems: 'center', justifyContent: 'space-between',
                        gap: 12, flexWrap: 'wrap',
                      }}>
                        <div style={{ fontSize: 13.5, color: 'var(--ink)', fontWeight: 600, flex: 1, minWidth: 0 }}>
                          <span style={{ color: 'var(--grey-500)', fontWeight: 400, fontSize: 12 }}>Your pick: </span>
                          <strong style={{ color: 'var(--orange)' }}>
                            {currentPick === 'A' ? m.teamA.name : currentPick === 'B' ? m.teamB.name : 'Draw'}
                          </strong>
                        </div>
                        <button
                          onClick={() => submitCard(m, currentPick)}
                          disabled={isSubmitting}
                          className="font-display btn-press"
                          style={{
                            background: 'var(--orange)', color: '#fff', border: 'none',
                            borderRadius: 6, flexShrink: 0,
                            padding: '12px 20px', fontSize: 13, letterSpacing: '0.06em', textTransform: 'uppercase',
                            boxShadow: '0 4px 14px rgba(241,86,35,0.30)',
                            display: 'inline-flex', alignItems: 'center', gap: 8,
                            cursor: isSubmitting ? 'wait' : 'pointer',
                          }}
                        >
                          <Icon name="check" size={15} stroke={3} />
                          {isSubmitting ? 'Saving…' : 'Lock My Prediction'}
                        </button>
                      </div>
                    )}

                    {/* Per-card error */}
                    {cardError && (
                      <div style={{
                        margin: '0 16px 14px', padding: '10px 14px',
                        background: '#fee2e2', color: '#b91c1c',
                        border: '1px solid #fecaca', borderRadius: 6,
                        fontSize: 13, fontWeight: 600,
                      }}>{cardError}</div>
                    )}

                    {/* Footer */}
                    <div style={{
                      background: isSelected ? 'rgba(241,86,35,0.04)' : 'var(--grey-50)',
                      borderTop: '1px solid var(--grey-100)',
                      padding: '8px 16px', fontSize: 11.5, color: 'var(--grey-500)',
                      display: 'flex', gap: 16,
                    }}>
                      <FootItem icon="flag">{m.stage}</FootItem>
                      <FootItem icon="pin">{m.venue}</FootItem>
                    </div>
                  </div>
                );
              })}
            </div>

            {/* Show all toggle */}
            {allUpcoming.length > 6 && (
              <button
                onClick={() => setShowAllMatches(v => !v)}
                style={{
                  marginTop: 16, width: '100%',
                  background: 'none', border: '1.5px dashed var(--grey-300)', borderRadius: 8,
                  padding: '12px 0', cursor: 'pointer',
                  color: 'var(--grey-600)', fontSize: 13, fontWeight: 700, letterSpacing: '0.08em',
                  textTransform: 'uppercase',
                }}
              >
                {showAllMatches
                  ? `Show fewer`
                  : `Show all ${allUpcoming.length} upcoming matches`}
              </button>
            )}
          </div>

          <p style={{ marginTop: 20, fontSize: 12.5, color: 'var(--grey-500)', maxWidth: 600, lineHeight: 1.55 }}>
            By submitting, you confirm the bill is from your own SunFront purchase.
            One bill = one prediction per match.
          </p>
        </div>
      </section>

      {/* ── Mobile sticky CTA — only visible when a pick is active ── */}
      {activeMatch && pick && detailsOk && !submitted.has(activeMatch.id) && isVoteable(activeMatch) && (
        <div className="sticky-cta only-mobile" style={{ bottom: 'calc(60px + env(safe-area-inset-bottom))' }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
            <div style={{ flex: 1, minWidth: 0 }}>
              <div className="font-highlight" style={{ fontSize: 10.5, letterSpacing: '0.16em', textTransform: 'uppercase', color: 'var(--grey-500)' }}>Your pick</div>
              <div className="font-display" style={{ fontSize: 13, lineHeight: 1.15, marginTop: 3, color: 'var(--ink)' }}>
                {pick === 'A' ? activeMatch.teamA.name : pick === 'B' ? activeMatch.teamB.name : 'Draw'}
                {' — '}{activeMatch.teamA.name} vs {activeMatch.teamB.name}
              </div>
            </div>
            <button
              onClick={() => submitCard(activeMatch, pick)}
              disabled={submitting === activeMatch.id}
              className="font-display btn-press"
              style={{
                background: submitting === activeMatch.id ? 'var(--grey-300)' : 'var(--orange)',
                color: '#fff', border: 'none', borderRadius: 6,
                padding: '14px 18px', fontSize: 13, letterSpacing: '0.06em', textTransform: 'uppercase',
                boxShadow: '0 4px 12px rgba(241,86,35,0.28)',
                display: 'inline-flex', alignItems: 'center', gap: 8, flexShrink: 0,
              }}
            >
              <Icon name="check" size={16} stroke={3} />
              {submitting === activeMatch.id ? '…' : 'Lock in'}
            </button>
          </div>
        </div>
      )}
    </main>
  );
}


Object.assign(window, { PredictPage });
