'use client';

import { useMemo, useState } from 'react';
import SportBadge from '@/components/vyndr/SportBadge';
import SectionHead from '@/components/vyndr/SectionHead';
import GradeBadge from '@/components/vyndr/GradeBadge';
import ArchetypeBadge from '@/components/vyndr/ArchetypeBadge';
import StatStrip, { type StatCell, type StripProp, type StripArchetype } from '@/components/vyndr/StatStrip';
import TeamLogo from '@/components/vyndr/TeamLogo';
import { accentColor } from '@/lib/teamMeta';
import { playerHref } from '@/lib/playerHref';
import { isPreferredBook, bookInfo } from '@/lib/books';
import { pendingSummary, topReadForCard } from '@/lib/slateAdapter';
import { nextRunLabelET } from '@/lib/pipelineSchedule';
import { useParlay, legKey } from '@/contexts/ParlayContext';

export interface GameLine {
  book: string;
  awayML: string;
  homeML: string;
  ou: string;
  bestAway?: boolean;
  bestHome?: boolean;
  bestOU?: boolean;
  worstAway?: boolean;
  worstHome?: boolean;
}
export interface GameProp {
  player: string;
  stat: string;
  line: number;
  grade: string;
  side: string;
  delta?: string;
}
/** Session 42 — design's enhanced card: one strip per player (name once). */
export interface PlayerStrip {
  player: string;
  team: string;
  // Wave 2A — real headshot ids threaded from the snapshot grade.
  playerId?: string | number | null;
  espnId?: string | number | null;
  // Wave 2B — a resolved absolute ESPN headshot URL (wins over a constructed one).
  headshotUrl?: string | null;
  archetype?: StripArchetype;
  // Session 64 (A1-S5) — prop viability (lineup confirmation + injury wire).
  lineup?: { status: string; slot?: number } | null;
  injury?: { status: string; detail?: string | null } | null;
  stats: StatCell[];
  props: StripProp[];
}
export interface StartingPitcher {
  name: string;
  era: string;
  archetype?: string;
}
export interface GameCardData {
  id: string;
  sport: string;
  live?: boolean;
  score?: { away: number; home: number };
  clock?: string;
  away: { abbr: string; name: string };
  home: { abbr: string; name: string };
  time: string;
  venue?: string;
  gradeSummary?: { a: number; b: number };
  lines: GameLine[];
  props?: GameProp[];
  streaks?: Array<{ player: string; text: string }>;
  // Session 42 — Player Intelligence enhancements (optional, self-hiding).
  pitchers?: { away: StartingPitcher; home: StartingPitcher };
  playerStrips?: PlayerStrip[];
}

interface GameCardProps {
  game: GameCardData;
  onAddParlay?: (p: GameProp) => void;
  onOpen?: (id: string) => void;
  /** Session 49 — the user's preferred books, highlighted in the lines grid. */
  preferredBooks?: string[];
}

/* Session 59 (work-order 2.2) — cards were dumping entire rosters inline.
   Strips sort by their best grade (A+ → F) and the card shows at most
   MAX_VISIBLE_PROPS graded props; the rest sit behind "ALL N READS →",
   expanding in place. */
const MAX_VISIBLE_PROPS = 6;
const GRADE_RANK: Record<string, number> = {
  'A+': 0, A: 1, 'A-': 2, 'B+': 3, B: 4, 'B-': 5, 'C+': 6, C: 7, 'C-': 8, D: 9, F: 10,
};
const gradeRank = (g?: string | null) => (g && GRADE_RANK[g] !== undefined ? GRADE_RANK[g] : 99);
const stripBestRank = (ps: PlayerStrip) => Math.min(99, ...ps.props.map((p) => gradeRank(p.grade)));
const stripGradedCount = (ps: PlayerStrip) => ps.props.filter((p) => p.grade).length;

/** Sort strips best-grade-first and cut at the prop budget. Always shows at
 *  least one strip; ungraded-only strips sort last. */
function collapseStrips(strips: PlayerStrip[]) {
  const sorted = [...strips].sort((a, b) => stripBestRank(a) - stripBestRank(b));
  const totalReads = sorted.reduce((n, s) => n + stripGradedCount(s), 0);
  const visible: PlayerStrip[] = [];
  let budget = MAX_VISIBLE_PROPS;
  for (const s of sorted) {
    const cost = Math.max(1, stripGradedCount(s));
    if (visible.length > 0 && budget - cost < 0) break;
    visible.push(s);
    budget -= cost;
  }
  return { sorted, visible, totalReads, truncated: visible.length < sorted.length };
}

/** Clickable team → /team/:abbr (Session 51). DS0: renders the real LOGO +
 *  abbr (the entity layer), not a bare string. Stops propagation so it
 *  doesn't trigger the card's open-game handler. */
function TeamLink({ abbr, sport }: { abbr: string; sport: string }) {
  if (!abbr) return <span>—</span>;
  return (
    <a
      href={`/team/${encodeURIComponent(abbr)}?sport=${encodeURIComponent(sport || 'mlb')}`}
      onClick={(e) => e.stopPropagation()}
      style={{ display: 'inline-flex', alignItems: 'center', gap: 6, color: '#fff', textDecoration: 'none', borderBottom: '1px solid transparent' }}
      onMouseEnter={(e) => { e.currentTarget.style.color = 'var(--g-a)'; e.currentTarget.style.borderBottomColor = 'var(--g-a)'; }}
      onMouseLeave={(e) => { e.currentTarget.style.color = '#fff'; e.currentTarget.style.borderBottomColor = 'transparent'; }}
      title={`${abbr} team hub`}
    >
      <TeamLogo team={abbr} sport={sport} size={22} />
      {abbr}
    </a>
  );
}

/** A book-line cell with the Bloomberg pattern: best = green tint + green left
 *  border, worst = subtle red. The #1 visual upgrade (§13). */
function LineCell({ value, best, worst }: { value: string; best?: boolean; worst?: boolean }) {
  return (
    <div
      className="mono"
      style={{
        padding: '8px 6px',
        textAlign: 'center',
        fontSize: 13,
        fontWeight: best ? 700 : 500,
        color: best ? 'var(--g-a)' : worst ? '#ff8a8a' : 'var(--text-0)',
        background: best ? 'rgba(0,212,160,.13)' : worst ? 'rgba(255,82,82,.07)' : 'transparent',
        borderLeft: best ? '2px solid var(--g-a)' : worst ? '2px solid rgba(255,82,82,.4)' : '2px solid transparent',
        borderRadius: 3,
      }}
    >
      {value}
    </div>
  );
}

function PropRow({ prop: p, onAddParlay }: { prop: GameProp; onAddParlay?: (p: GameProp) => void }) {
  const deltaUp = p.delta && p.delta.startsWith('▲');
  const deltaDown = p.delta && p.delta.startsWith('▼');
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '8px 10px', background: 'var(--bg-2)', borderRadius: 7, border: '1px solid var(--border)' }}>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ fontSize: 14, fontWeight: 700, letterSpacing: '-0.01em', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{p.player}</div>
        <div className="mono" style={{ fontSize: 11.5, color: 'var(--text-1)', marginTop: 2 }}>
          {p.stat} <span style={{ color: 'var(--text-0)', fontWeight: 700 }}>{p.line}</span>
          {p.delta && p.delta !== '—' && (
            <span style={{ marginLeft: 7, color: deltaUp ? 'var(--g-a)' : deltaDown ? 'var(--miss)' : 'var(--text-2)', fontWeight: 700 }}>{p.delta}</span>
          )}
        </div>
      </div>
      <GradeBadge grade={p.grade} size={32} glow />
      {onAddParlay && (
        <button
          onClick={() => onAddParlay(p)}
          title="Add to parlay"
          style={{ width: 30, height: 30, borderRadius: 6, cursor: 'pointer', flexShrink: 0, background: 'transparent', border: '1px solid var(--border-hi)', color: 'var(--g-a)', fontSize: 18, fontWeight: 700, lineHeight: 1, display: 'flex', alignItems: 'center', justifyContent: 'center' }}
        >
          +
        </button>
      )}
    </div>
  );
}

/** Dashboard / Slate game card (§7) — game-lines grid w/ best-line highlight,
 *  graded props, inline streaks, live indicator. */
export default function GameCard({ game: g, onAddParlay, onOpen, preferredBooks }: GameCardProps) {
  // Session 50 — Parlay Lab "+" wiring. Builds a leg from the strip + game.
  const { addLeg, removeLeg, legs, hasLeg } = useParlay();
  // Session 59 — 2.2 card collapse + 3.2 mobile book-table expander.
  const [showAllReads, setShowAllReads] = useState(false);
  const [linesExpanded, setLinesExpanded] = useState(false);
  const collapsed = useMemo(() => collapseStrips(g.playerStrips || []), [g.playerStrips]);
  const stripsToRender = showAllReads ? collapsed.sorted : collapsed.visible;
  // DS2 (#2) — the ONE bold hero per card: the single best live graded read,
  // promoted large + mono + tabular. Everything else in the strips below stays
  // demoted context. (#14) — when the card has NO graded reads yet, the awaiting
  // props collapse to ONE pending line instead of six identical rows.
  const topRead = useMemo(() => topReadForCard(g.playerStrips || []), [g.playerStrips]);
  const pending = useMemo(() => pendingSummary(g.playerStrips || []), [g.playerStrips]);
  // A1 S11 — LIVE SLATE MODE: any strip prop carrying live tracking shows the
  // once-per-card label. Grades locked pre-game NEVER change in-game.
  const isTracking = useMemo(
    () => (g.playerStrips || []).some((s) => (s.props || []).some((p) => p.live)),
    [g.playerStrips],
  );
  const bestLine = (pick: (ln: GameLine) => boolean, val: (ln: GameLine) => string) => {
    const ln = (g.lines || []).find(pick);
    return ln ? val(ln) : (g.lines && g.lines[0] ? val(g.lines[0]) : '—');
  };
  const sportU = (g.sport || 'nba').toUpperCase();
  const gameId = `${g.away.abbr} @ ${g.home.abbr}`;
  const toLeg = (ps: PlayerStrip, p: StripProp) => ({
    sport: (sportU === 'MLB' || sportU === 'WNBA' ? sportU : 'NBA') as 'NBA' | 'MLB' | 'WNBA',
    player: ps.player, team: ps.team, game: gameId, archetype: ps.archetype?.primary,
    stat: String(p.stat), line: Number(p.line) || 0,
    direction: (String(p.side).toUpperCase() === 'U' ? 'under' : 'over') as 'over' | 'under',
    grade: String(p.grade || 'C'), confidence: 60,
  });
  const stripHandlers = (ps: PlayerStrip) => ({
    onAddLeg: (p: StripProp) => {
      const leg = toLeg(ps, p);
      const k = legKey(leg);
      const existing = legs.find((l) => legKey(l) === k);
      if (existing) removeLeg(existing.id); else addLeg(leg);
    },
    isLegActive: (p: StripProp) => hasLeg(legKey(toLeg(ps, p))),
  });
  // DS0 — a team-colored accent edge (home team) so the card reads as THIS
  // matchup, not a generic panel. Visible-color rule keeps it off near-black.
  const homeAccent = accentColor(g.home.abbr, g.sport) || 'var(--border)';
  return (
    <div className="scanlines" style={{ background: 'var(--bg-1)', border: '1px solid var(--border)', borderLeft: `3px solid color-mix(in srgb, ${homeAccent} 65%, transparent)`, borderRadius: 10, overflow: 'hidden' }}>
      {/* HEADER */}
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '13px 16px 11px' }}>
        <div onClick={() => onOpen && onOpen(g.id)} title="Open game detail" style={{ display: 'flex', alignItems: 'center', gap: 11, minWidth: 0, cursor: onOpen ? 'pointer' : 'default' }}>
          <SportBadge sport={g.sport} />
          <span className="mono" style={{ fontSize: 18, fontWeight: 700, letterSpacing: '0.01em' }}>
            <TeamLink abbr={g.away.abbr} sport={g.sport} /> <span style={{ color: 'var(--text-2)', fontWeight: 400 }}>@</span> <TeamLink abbr={g.home.abbr} sport={g.sport} />
          </span>
          {g.live && (
            <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6, marginLeft: 2 }}>
              <span className="live-dot" />
              {g.score && <span className="mono" style={{ fontSize: 12, color: 'var(--text-0)', fontWeight: 700 }}>{g.score.away} — {g.score.home}</span>}
              {g.clock && <span className="mono amber-glow" style={{ fontSize: 10.5, color: 'var(--amber)' }}>{g.clock}</span>}
            </span>
          )}
        </div>
        {g.gradeSummary && (g.gradeSummary.a > 0 || g.gradeSummary.b > 0) && (
          <span className="mono" style={{ fontSize: 12, fontWeight: 700, padding: '4px 9px', borderRadius: 4, background: 'var(--bg-2)', border: '1px solid var(--border-hi)', display: 'inline-flex', gap: 7 }}>
            {g.gradeSummary.a > 0 && <span style={{ color: 'var(--g-a)' }}>{g.gradeSummary.a}A</span>}
            {g.gradeSummary.b > 0 && <span style={{ color: 'var(--g-b)' }}>{g.gradeSummary.b}B</span>}
          </span>
        )}
      </div>

      {/* SUB-HEADER — Session 59 (3.2): venue drops FIRST on mobile
          (.gc-venue is display:none <640px) so time + pitchers never truncate. */}
      <div className="mono" style={{ padding: '0 16px 11px', fontSize: 11.5, color: 'var(--text-1)' }}>
        {g.away.name} <span style={{ color: 'var(--text-2)' }}>·</span> {g.home.name}
        <span style={{ color: 'var(--text-2)' }}> · </span><span style={{ whiteSpace: 'nowrap' }}>{g.time}</span>
        {g.venue && (<span className="gc-venue"><span style={{ color: 'var(--text-2)' }}> · </span>{g.venue}</span>)}
      </div>

      {/* MLB STARTING PITCHERS (Session 42) */}
      {g.pitchers && (
        <div className="mono" style={{ padding: '0 16px 11px', fontSize: 11, color: 'var(--text-1)', display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' }}>
          <span style={{ color: 'var(--text-2)', letterSpacing: '0.04em' }}>STARTING</span>
          <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6, color: '#C8CCD6', flexWrap: 'wrap', minWidth: 0 }}>
            {g.pitchers.away.name} <span style={{ color: 'var(--text-1)' }}>{g.pitchers.away.era} ERA</span>
            {g.pitchers.away.archetype && <ArchetypeBadge archetype={g.pitchers.away.archetype} size="sm" />}
          </span>
          <span style={{ color: 'var(--text-2)' }}>vs</span>
          <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6, color: '#C8CCD6', flexWrap: 'wrap', minWidth: 0 }}>
            {g.pitchers.home.name} <span style={{ color: 'var(--text-1)' }}>{g.pitchers.home.era} ERA</span>
            {g.pitchers.home.archetype && <ArchetypeBadge archetype={g.pitchers.home.archetype} size="sm" />}
          </span>
        </div>
      )}

      <div style={{ height: 1, background: 'var(--border)' }} />

      {/* GAME LINES — Session 59 (3.2): below 640px the 8-book table collapses
          to a best-line summary row with an "N BOOKS ⌄" expander; desktop
          always shows the full table. All values are real book numbers. */}
      {g.lines && g.lines.length > 0 && (
        <div style={{ padding: '13px 16px' }}>
          <SectionHead style={{ marginBottom: 11 }}>GAME LINES <span style={{ color: 'var(--text-2)' }}>· {g.lines.length} BOOKS</span></SectionHead>

          {/* Mobile summary (hidden ≥640px via .gl-summary) */}
          <div className="gl-summary mono" style={{ alignItems: 'center', gap: 10, fontSize: 12 }}>
            <span><span className="label" style={{ fontSize: 9.5 }}>{g.away.abbr}</span> <span style={{ color: 'var(--g-a)', fontWeight: 700 }}>{bestLine((l) => !!l.bestAway, (l) => l.awayML)}</span></span>
            <span><span className="label" style={{ fontSize: 9.5 }}>{g.home.abbr}</span> <span style={{ color: 'var(--g-a)', fontWeight: 700 }}>{bestLine((l) => !!l.bestHome, (l) => l.homeML)}</span></span>
            <span><span className="label" style={{ fontSize: 9.5 }}>O/U</span> <span style={{ color: 'var(--text-0)', fontWeight: 700 }}>{bestLine((l) => !!l.bestOU, (l) => l.ou)}</span></span>
            <button
              onClick={(e) => { e.stopPropagation(); setLinesExpanded((v) => !v); }}
              className="mono"
              aria-expanded={linesExpanded}
              style={{ marginLeft: 'auto', background: 'transparent', border: '1px solid var(--border-hi)', borderRadius: 6, color: 'var(--text-1)', fontSize: 10.5, fontWeight: 700, letterSpacing: '0.06em', padding: '5px 9px', cursor: 'pointer', minHeight: 30 }}
            >
              {g.lines.length} BOOKS {linesExpanded ? '⌃' : '⌄'}
            </button>
          </div>

          <div className={`gl-full ${linesExpanded ? 'gl-expanded' : ''} game-lines-grid`} style={{ display: 'grid', gridTemplateColumns: '78px 1fr 1fr 1fr', gap: '2px 4px', alignItems: 'center' }}>
            <div className="label" style={{ fontSize: 10 }}>BOOK</div>
            <div className="label" style={{ fontSize: 10, textAlign: 'center' }}>{g.away.abbr} ML</div>
            <div className="label" style={{ fontSize: 10, textAlign: 'center' }}>{g.home.abbr} ML</div>
            <div className="label" style={{ fontSize: 10, textAlign: 'center' }}>O/U</div>
            {g.lines.map((ln, i) => (
              <span key={i} style={{ display: 'contents' }}>
                <div className="mono" style={{ fontSize: 12, fontWeight: 700, color: isPreferredBook(ln.book, preferredBooks) ? 'var(--g-a)' : 'var(--text-1)', paddingLeft: 2, textShadow: isPreferredBook(ln.book, preferredBooks) ? '0 0 8px rgba(0,212,160,.5)' : 'none' }} title={isPreferredBook(ln.book, preferredBooks) ? 'Your book' : undefined}>{bookInfo(ln.book).name}</div>
                <LineCell value={ln.awayML} best={ln.bestAway} worst={ln.worstAway} />
                <LineCell value={ln.homeML} best={ln.bestHome} worst={ln.worstHome} />
                <LineCell value={ln.ou} best={ln.bestOU} />
              </span>
            ))}
          </div>
        </div>
      )}

      <div style={{ height: 1, background: 'var(--border)' }} />

      {/* PROPS — Session 42: prefer the player-grouped StatStrip (name once,
          archetype + horizontal stats + all graded props on one line); fall
          back to the legacy per-prop rows for callers that don't supply strips. */}
      <div style={{ padding: '13px 16px' }}>
        <SectionHead style={{ marginBottom: 11 }}>
          GRADED PROPS
          {isTracking && (
            <span
              className="mono"
              title="Every grade locked before first pitch and never changes in-game — live marks are progress tracking against the locked line, not a re-grade"
              style={{ marginLeft: 8, fontSize: 9, fontWeight: 800, letterSpacing: '0.08em', color: 'var(--text-1, #7A7A8E)' }}
            >
              · TRACKING — READ LOCKED PRE-GAME
            </span>
          )}
        </SectionHead>
        {/* DS2 (#2) — ONE bold hero: the card's best read, large + mono +
            tabular. The failure mode was every value at identical weight; this
            promotes the single number that matters and demotes the rest. */}
        {topRead && !pending && (
          <div
            style={{ display: 'flex', alignItems: 'center', gap: 12, marginBottom: 11, padding: '10px 12px', borderRadius: 9, background: 'var(--bg-2)', border: '1px solid var(--border-hi)' }}
          >
            <GradeBadge grade={topRead.grade} size={48} glow />
            <div style={{ minWidth: 0, flex: 1 }}>
              <div style={{ fontSize: 15, fontWeight: 800, letterSpacing: '-0.01em', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{topRead.player}</div>
              <div className="mono" style={{ fontSize: 12, color: 'var(--text-1)', marginTop: 3, fontVariantNumeric: 'tabular-nums' }}>
                {topRead.stat} {String(topRead.side).toUpperCase().startsWith('U') ? 'u' : 'o'}{topRead.line}
                {topRead.team ? <span style={{ color: 'var(--text-2)' }}> · {topRead.team}</span> : null}
              </div>
            </div>
            <span className="mono" style={{ fontSize: 9, fontWeight: 800, letterSpacing: '0.1em', color: 'var(--text-2)', flexShrink: 0 }}>TOP READ</span>
          </div>
        )}
        {/* DS2 (#14) — collapse the dead "Grades post …" repetition. An
            all-awaiting card renders ONE compact line, not six identical rows. */}
        {pending ? (
          <div className="mono" style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 12, color: 'var(--text-1)', flexWrap: 'wrap' }}>
            <span style={{ fontWeight: 800, color: 'var(--text-0)', fontVariantNumeric: 'tabular-nums' }}>{pending.count}</span>
            <span>props pending</span>
            <span style={{ color: 'var(--text-2)' }}>·</span>
            <span style={{ color: 'var(--text-2)' }}>{pending.players} player{pending.players === 1 ? '' : 's'}</span>
            <span style={{ color: 'var(--text-2)' }}>·</span>
            <span style={{ color: 'var(--text-2)', fontStyle: 'italic' }}>{nextRunLabelET() ? `grade ${nextRunLabelET()}` : 'grade on the next pipeline run'}</span>
          </div>
        ) : g.playerStrips && g.playerStrips.length > 0 ? (
          <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
            {stripsToRender.map((ps, i) => (
              <StatStrip
                key={i}
                player={ps.player}
                team={ps.team}
                sport={g.sport}
                playerId={ps.playerId}
                espnId={ps.espnId}
                headshotUrl={ps.headshotUrl}
                archetype={ps.archetype}
                lineup={ps.lineup}
                injury={ps.injury}
                stats={ps.stats}
                props={ps.props}
                variant="compact"
                onPlayerClick={() => { window.location.href = playerHref(ps.player, g.sport); }}
                {...stripHandlers(ps)}
              />
            ))}
            {/* Session 59 (2.2) — the rest of the roster expands in place. */}
            {collapsed.truncated && !showAllReads && (
              <button
                onClick={(e) => { e.stopPropagation(); setShowAllReads(true); }}
                className="mono"
                style={{ alignSelf: 'flex-start', background: 'transparent', border: 'none', cursor: 'pointer', color: 'var(--g-a)', fontSize: 12, fontWeight: 700, letterSpacing: '0.06em', padding: '6px 2px' }}
              >
                ALL {collapsed.totalReads} READS →
              </button>
            )}
            {collapsed.truncated && showAllReads && (
              <button
                onClick={(e) => { e.stopPropagation(); setShowAllReads(false); }}
                className="mono"
                style={{ alignSelf: 'flex-start', background: 'transparent', border: 'none', cursor: 'pointer', color: 'var(--text-1)', fontSize: 12, fontWeight: 700, letterSpacing: '0.06em', padding: '6px 2px' }}
              >
                COLLAPSE ↑
              </button>
            )}
          </div>
        ) : g.props && g.props.length > 0 ? (
          <div style={{ display: 'flex', flexDirection: 'column', gap: 7 }}>
            {g.props.map((p, i) => (
              <PropRow key={i} prop={p} onAddParlay={onAddParlay} />
            ))}
          </div>
        ) : (
          <div className="mono" style={{ fontSize: 12.5, color: 'var(--text-1)' }}>Props for this game aren&apos;t published yet.</div>
        )}
      </div>

      {/* INLINE STREAKS */}
      {g.streaks && g.streaks.length > 0 && (
        <div style={{ padding: '12px 16px 14px', borderTop: '1px solid var(--border)', background: 'linear-gradient(90deg, rgba(233,75,60,.08), rgba(233,75,60,.02) 60%, transparent)' }}>
          <SectionHead accent="#ff8b7a" style={{ marginBottom: 9 }}>🔥 STREAKS</SectionHead>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
            {g.streaks.map((s, i) => (
              <div key={i} className="mono" style={{ fontSize: 12.5, color: 'var(--text-0)' }}>
                <span style={{ fontWeight: 700, color: '#ffb0a4' }}>{s.player}</span>
                <span style={{ color: 'var(--text-2)' }}> — </span>{s.text}
              </div>
            ))}
          </div>
        </div>
      )}
    </div>
  );
}
