
// FearlessTracker.jsx — Fearless Draft series tracker.
//
// In Fearless Draft tournaments (Bo3/Bo5), once a champion is played in any
// game, neither team can pick them again for the rest of the series. This
// screen tracks locked champs per game + shows what each crew member still has
// available in their pool.
//
// Persisted under localStorage key 'cozydraft-fearless-v1'.

(() => {
  if (document.getElementById('fearless-tracker-css')) return;
  const s = document.createElement('style');
  s.id = 'fearless-tracker-css';
  s.textContent = `
    @keyframes ft-lock-pulse {
      0%, 100% { box-shadow: 0 0 0 0 #E8555550; }
      50%      { box-shadow: 0 0 0 6px #E8555500; }
    }
    @keyframes ft-shimmer-red {
      0%   { filter: drop-shadow(0 0 0 #E85555a0); }
      50%  { filter: drop-shadow(0 0 6px #E85555a0); }
      100% { filter: drop-shadow(0 0 0 #E85555a0); }
    }
    @keyframes ft-shake-soft {
      0%, 100% { transform: translateX(0); }
      25%      { transform: translateX(-2px); }
      75%      { transform: translateX(2px); }
    }
    @keyframes ft-game-pulse {
      0%, 100% { box-shadow: 0 0 0 0 #C4845A40; }
      50%      { box-shadow: 0 0 0 6px #C4845A00; }
    }
    @keyframes ft-roll-down {
      0%   { transform: translateY(-8px); opacity: 0; }
      100% { transform: translateY(0);    opacity: 1; }
    }

    .ft-lock-shimmer { animation: ft-shimmer-red 2.4s ease-in-out infinite; }
    .ft-game-pulse   { animation: ft-game-pulse 1.8s ease-out infinite; }
    .ft-warn-shake   { animation: ft-shake-soft 0.7s ease-in-out 2; }
    .ft-roll-down    { animation: ft-roll-down 0.35s cubic-bezier(0.34, 1.2, 0.64, 1); }

    .ft-hex-input {
      background: var(--surface-nested); padding: 10px 18px;
      border: 2px solid var(--border-emphasis); border-radius: 999px;
      font-family: 'Nunito'; font-weight: 800; font-size: 13px;
      color: var(--text-primary); outline: none; width: 100%; box-sizing: border-box;
      transition: box-shadow 0.18s, border-color 0.18s;
    }
    .ft-hex-input:focus { box-shadow: 0 0 0 3px var(--border-default); }
    .ft-hex-wrap {
      position: relative; flex: 1; min-width: 200px;
    }
    .ft-format-pill {
      background: #F7DFA0; padding: 8px 22px;
      border: 2px solid var(--border-emphasis); border-radius: 999px;
      font-family: 'Nunito'; font-weight: 800; font-size: 12px;
      color: var(--text-primary); outline: none; cursor: pointer;
      appearance: none; -webkit-appearance: none; text-align: center;
    }

    .ft-grid-cards { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
    .ft-lane-strip { display: grid; grid-template-columns: repeat(5, 1fr); gap: 10px; }
    @media (max-width: 1400px) and (min-width: 901px) {
      .ft-lane-strip { grid-template-columns: repeat(3, 1fr) !important; }
    }
    @media (max-width: 900px) {
      .ft-grid-cards { grid-template-columns: 1fr !important; }
      .ft-lane-strip { grid-template-columns: repeat(2, 1fr) !important; }
    }
    @media (max-width: 540px) {
      .ft-lane-strip { grid-template-columns: 1fr !important; }
    }
  `;
  document.head.appendChild(s);
})();

const FearlessTrackerNS = (() => {
  const { useState, useEffect, useMemo, useRef } = React;

  const STORAGE_KEY = 'cozydraft-fearless-v1';
  const POSITIONS = ['TOP', 'JUNGLE', 'MID', 'ADC', 'SUPPORT'];
  const FORMAT_GAMES = { Bo1: 1, Bo3: 3, Bo5: 5 };

  // ── persistence ───────────────────────────────────────────────────────────
  function load() {
    try {
      const raw = localStorage.getItem(STORAGE_KEY);
      if (raw) return JSON.parse(raw);
    } catch {}
    return { currentSeries: null, archivedSeries: [] };
  }
  function save(state) {
    try { localStorage.setItem(STORAGE_KEY, JSON.stringify(state)); } catch {}
  }
  function newSeries(name = '') {
    return {
      id: Date.now(),
      seriesName: name,
      format: 'Bo3',
      currentGame: 1,
      games: [],
      status: 'active',
      createdAt: new Date().toISOString(),
    };
  }
  function emptyGamePicks() {
    return POSITIONS.map(p => ({ position: p, championId: null }));
  }

  // ── Tiny champion picker popover ──────────────────────────────────────────
  function ChampionPicker({ champions, onPick, onClose, exclude = new Set(), anchorStyle = {} }) {
    const [q, setQ] = useState('');
    const ref = useRef(null);
    useEffect(() => {
      const h = (e) => { if (ref.current && !ref.current.contains(e.target)) onClose(); };
      document.addEventListener('mousedown', h);
      return () => document.removeEventListener('mousedown', h);
    }, [onClose]);

    const list = useMemo(() => {
      const arr = Object.values(champions || {});
      const f = q.trim().toLowerCase();
      return arr
        .filter(c => !exclude.has(c.id))
        .filter(c => (window.matchesChampionSearch ? window.matchesChampionSearch(c, q) : (!f || c.name.toLowerCase().includes(f))))
        .sort((a, b) => a.name.localeCompare(b.name))
        .slice(0, 60);
    }, [q, champions, exclude]);

    return (
      <div ref={ref} className="pop-in" style={{
        position: 'absolute', zIndex: 200,
        background: 'var(--surface-modal)', border: '2.5px solid var(--border-emphasis)',
        borderRadius: 18, padding: 10, width: 260,
        boxShadow: '0 12px 32px rgba(74, 55, 40, 0.3)',
        ...anchorStyle,
      }}>
        <input
          autoFocus value={q} onChange={e => setQ(e.target.value)}
          placeholder="Search champ…"
          style={{
            width: '100%', boxSizing: 'border-box',
            padding: '6px 10px', borderRadius: 12,
            border: '2px solid var(--border-default)', background: 'var(--surface-nested)',
            fontFamily: 'Nunito', fontWeight: 800, fontSize: 13,
            color: 'var(--text-primary)', outline: 'none', marginBottom: 8,
          }}
        />
        <div style={{
          display: 'grid', gridTemplateColumns: 'repeat(6, 1fr)',
          gap: 4, maxHeight: 240, overflowY: 'auto',
        }}>
          {list.map(c => (
            <button key={c.id} onClick={() => { onPick(c.id); onClose(); }} className="cozy-btn" style={{
              border: 'none', background: 'transparent', padding: 2,
              cursor: 'pointer', borderRadius: 8,
            }} title={c.name}>
              <window.ChampionIcon championId={c.id} size={34} noAnim />
            </button>
          ))}
          {list.length === 0 && (
            <div style={{ gridColumn: '1/-1', textAlign: 'center', padding: 14, color: 'var(--text-muted)', fontWeight: 700, fontSize: 12 }}>
              No matches 🌱
            </div>
          )}
        </div>
      </div>
    );
  }

  // ── Locked champion tile (in a game row) ──────────────────────────────────
  function LockedTile({ championId, position, champName, accent = 'sage' }) {
    const posColor = window.POSITION_COLORS[position];
    const colors = accent === 'sage'
      ? { ring: '#7CBF8E', glow: '#7CBF8E40' }
      : { ring: '#E8A0A0', glow: '#E8A0A040' };

    if (!championId) {
      return (
        <div style={{
          display: 'flex', flexDirection: 'column', alignItems: 'center',
          gap: 3, flex: 1, minWidth: 0,
        }}>
          <window.HexFrame size={52} color="var(--surface-nested)" borderColor="var(--border-default)" borderWidth={2}>
            <window.RoleIcon pos={position} size={20} />
          </window.HexFrame>
          <span style={{ fontSize: 10, fontWeight: 800, color: 'var(--text-muted)' }}>—</span>
        </div>
      );
    }

    return (
      <div style={{
        display: 'flex', flexDirection: 'column', alignItems: 'center',
        gap: 3, flex: 1, minWidth: 0,
      }}>
        <div className="ft-lock-shimmer" style={{ position: 'relative' }}>
          <window.HexFrame size={56} color={colors.ring} borderColor={colors.ring} borderWidth={2.5}>
            <div style={{ position: 'relative', width: '78%', height: '78%' }}>
              <window.ChampionIcon championId={championId} size="100%" noAnim
                style={{ width: '100%', height: '100%', borderWidth: 0, opacity: 0.7 }}
              />
              {/* Lock dim overlay */}
              <div style={{
                position: 'absolute', inset: 0,
                background: 'linear-gradient(180deg, rgba(232, 85, 85, 0.12), rgba(232, 85, 85, 0.2))',
                borderRadius: 6,
              }} />
            </div>
          </window.HexFrame>
          {/* Lock badge */}
          <div style={{
            position: 'absolute', top: -2, right: -2,
            width: 20, height: 20, borderRadius: '50%',
            background: 'var(--text-primary)', color: 'var(--surface-nested)',
            border: '2px solid var(--surface-card)',
            display: 'flex', alignItems: 'center', justifyContent: 'center',
            fontSize: 10,
          }}>🔒</div>
        </div>
        <span style={{
          fontSize: 11, fontWeight: 800, color: 'var(--text-primary)',
          maxWidth: 80, overflow: 'hidden', textOverflow: 'ellipsis',
          whiteSpace: 'nowrap', textAlign: 'center',
        }}>{champName || championId}</span>
        <span style={{
          fontSize: 9, fontWeight: 800,
          background: posColor, color: 'var(--text-on-light-pastel)',
          border: '1px solid var(--border-default)',
          borderRadius: 8, padding: '1px 6px',
          fontFamily: 'Nunito', letterSpacing: 0.5,
        }}>{position.charAt(0)}</span>
      </div>
    );
  }

  // ── Game section divider ──────────────────────────────────────────────────
  function GameDivider({ gameNumber, accent }) {
    return (
      <div style={{
        display: 'flex', alignItems: 'center', gap: 10,
        margin: '14px 0 8px',
      }}>
        <div style={{
          background: accent, color: 'var(--surface-nested)',
          borderRadius: 14, padding: '3px 12px',
          fontFamily: 'Fredoka One', fontSize: 13,
          boxShadow: '0 2px 0 rgba(0,0,0,0.15)',
        }}>Game {gameNumber}</div>
        <div style={{ flex: 1, height: 0, borderTop: '1.5px dashed var(--border-default)' }} />
      </div>
    );
  }

  // ── Side card (ours / enemy locked champs) ────────────────────────────────
  function LockedCard({ side, games, champions, format, onLogGame, currentGame, status }) {
    const isUs = side === 'us';
    const accent = isUs ? '#7CBF8E' : '#E8A0A0';
    const headColor = isUs ? '#2d6b47' : '#8b3a5a';
    const title  = isUs ? 'Our Locked Champions 🛡️' : 'Enemy Locked Champions ⚔️';
    const subtitle = isUs ? 'champs locked this series' : 'champs they can\'t repeat';
    const buttonColor = isUs ? 'terracotta' : 'pink';

    const totalLocked = games.reduce(
      (n, g) => n + (isUs ? g.ourPicks : g.enemyPicks).filter(p => p.championId).length,
      0,
    );

    const maxGames = FORMAT_GAMES[format] || 3;
    const canLogMore = status === 'active' && games.length < maxGames;

    return (
      <div className="cozy-card" style={{ padding: 18, display: 'flex', flexDirection: 'column' }}>
        <div className="corner-dot corner-dot-bl"></div>
        <div className="corner-dot corner-dot-br"></div>

        <div style={{ marginTop: 4 }}>
          <h3 className="fredoka" style={{ color: headColor, fontSize: 19, margin: 0 }}>
            {title}
          </h3>
          <div style={{ fontSize: 12, fontWeight: 800, color: 'var(--text-muted)', marginTop: 2 }}>
            {totalLocked} {subtitle}
          </div>
        </div>

        <div style={{ marginTop: 4, flex: 1 }}>
          {games.length === 0 ? (
            <div style={{
              padding: '24px 12px', textAlign: 'center',
              color: 'var(--text-muted)', fontWeight: 700, fontSize: 13,
              background: 'var(--surface-nested)', border: '1.5px dashed var(--border-default)',
              borderRadius: 14, marginTop: 10,
            }}>
              <div className="float" style={{ marginBottom: 8 }}>
                <window.PawPrint size={22} color="var(--accent-orange)" />
              </div>
              No champs locked yet — start logging when Game 1 ends! 🐾
            </div>
          ) : (
            games.map(g => (
              <div key={g.gameNumber}>
                <GameDivider gameNumber={g.gameNumber} accent={accent} />
                <div style={{ display: 'flex', gap: 8, alignItems: 'flex-start' }}>
                  {POSITIONS.map(pos => {
                    const pick = (isUs ? g.ourPicks : g.enemyPicks).find(p => p.position === pos);
                    return (
                      <LockedTile
                        key={pos}
                        position={pos}
                        championId={pick?.championId}
                        champName={pick?.championId ? champions[pick.championId]?.name : null}
                        accent={isUs ? 'sage' : 'pink'}
                      />
                    );
                  })}
                </div>
              </div>
            ))
          )}
        </div>

        {canLogMore && (
          <div style={{ marginTop: 14, textAlign: 'center' }}>
            <window.CozyButton color={buttonColor} onClick={() => onLogGame(side)}>
              {games.length === 0 ? `+ Log Game 1 picks` : `+ Log Game ${currentGame} picks`}
            </window.CozyButton>
          </div>
        )}
      </div>
    );
  }

  // ── One lane mini-card in the availability strip ──────────────────────────
  function LaneAvailability({ pos, player, champions, lockedIds, lockedInfo }) {
    const posColor = window.POSITION_COLORS[pos];
    const labels = window.POSITION_LABELS;
    const archetype = window.ARCHETYPE_BY_POSITION[pos];
    const allPool = (player?.pool || []).filter(e => e.position === pos);
    const total = allPool.length;
    const available = allPool.filter(e => !lockedIds.has(e.championId)).length;
    const low = total > 0 && available <= 2;

    return (
      <div className="cozy-card" style={{
        padding: 12, background: posColor + '30',
        display: 'flex', flexDirection: 'column', gap: 6,
      }}>
        <div className="corner-dot corner-dot-bl"></div>
        <div className="corner-dot corner-dot-br"></div>

        <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginTop: 4 }}>
          <window.HexFrame size={30} color={posColor} borderColor="var(--border-emphasis)" borderWidth={2}>
            <window.RoleSilhouette archetype={archetype} size={16} color="var(--text-on-light)" />
          </window.HexFrame>
          <div style={{ minWidth: 0 }}>
            <div style={{ fontFamily: 'Fredoka One', fontSize: 13, color: 'var(--text-primary)' }}>
              {labels[pos]}
            </div>
            <div style={{
              fontSize: 10, fontWeight: 800, color: 'var(--text-muted)',
              overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap',
            }}>
              {player?.name || '—'}
            </div>
          </div>
        </div>

        <div className={low ? 'ft-warn-shake' : ''} style={{
          fontFamily: 'Fredoka One',
          fontSize: 22,
          color: low ? '#C97070' : 'var(--text-primary)',
          textAlign: 'center', lineHeight: 1.1, marginTop: 2,
        }}>
          {available} <span style={{ fontSize: 13, color: 'var(--text-muted)' }}>of {total} available</span>
        </div>

        {low && (
          <div style={{
            background: '#F9D0D0', border: '1.5px solid #E8A0A0',
            borderRadius: 12, padding: '3px 8px',
            fontFamily: 'Nunito', fontWeight: 800, fontSize: 10.5,
            color: '#8b3a3a', textAlign: 'center',
          }}>
            ⚠️ Running low on options!
          </div>
        )}

        <div style={{
          display: 'flex', flexWrap: 'wrap', gap: 4, padding: 4,
          background: 'var(--surface-card)', borderRadius: 10,
          border: '1.5px dashed var(--border-default)', minHeight: 44,
          alignItems: 'flex-start',
        }}>
          {allPool.length === 0 && (
            <span style={{ fontSize: 10, color: 'var(--text-muted)', fontWeight: 700, margin: 'auto' }}>
              No pool yet 🌱
            </span>
          )}
          {allPool.map(e => {
            const lockInfo = lockedInfo?.[e.championId];
            const locked = !!lockInfo;
            const name = champions[e.championId]?.name || e.championId;
            const tooltip = locked
              ? `🔒 ${name} — played by ${lockInfo.side === 'us' ? 'our crew' : 'enemy'} in Game ${lockInfo.gameNumber}`
              : name;
            return (
              <div
                key={e.championId}
                title={tooltip}
                style={{
                  position: 'relative',
                  opacity: locked ? 0.3 : 1,
                  filter: locked ? 'grayscale(70%)' : 'none',
                }}
              >
                <window.ChampionIcon championId={e.championId} size={32} noAnim />
                {locked && (
                  <>
                    <div style={{
                      position: 'absolute', inset: 0,
                      display: 'flex', alignItems: 'center', justifyContent: 'center',
                      pointerEvents: 'none',
                    }}>
                      <svg viewBox="0 0 32 32" width="32" height="32">
                        <path d="M5 16 L27 16" stroke="#E85555" strokeWidth="2.5" strokeLinecap="round" />
                      </svg>
                    </div>
                    <div style={{
                      position: 'absolute', top: -3, right: -3,
                      width: 14, height: 14, borderRadius: '50%',
                      background: lockInfo.side === 'us' ? 'var(--text-primary)' : '#8b3a3a',
                      color: 'var(--surface-nested)',
                      border: '1.5px solid var(--surface-card)',
                      display: 'flex', alignItems: 'center', justifyContent: 'center',
                      fontSize: 8,
                    }}>🔒</div>
                  </>
                )}
              </div>
            );
          })}
        </div>
      </div>
    );
  }

  // ── Quick-add modal for logging a game ────────────────────────────────────
  function LogGameModal({ gameNumber, initialOur, initialEnemy, champions, excludeIds, onSave, onClose, defaultSide }) {
    const [our, setOur]     = useState(initialOur);
    const [enemy, setEnemy] = useState(initialEnemy);
    const [pickerOpen, setPickerOpen] = useState(null); // { side, pos }

    useEffect(() => {
      const onKey = (e) => { if (e.key === 'Escape') onClose(); };
      document.addEventListener('keydown', onKey);
      const prevOverflow = document.body.style.overflow;
      document.body.style.overflow = 'hidden';
      return () => {
        document.removeEventListener('keydown', onKey);
        document.body.style.overflow = prevOverflow;
      };
    }, [onClose]);

    const setPick = (side, pos, championId) => {
      const list = side === 'us' ? our : enemy;
      const setter = side === 'us' ? setOur : setEnemy;
      setter(list.map(p => p.position === pos ? { ...p, championId } : p));
    };

    const handleSave = () => {
      onSave({
        gameNumber,
        ourPicks: our,
        enemyPicks: enemy,
      });
    };

    const renderColumn = (side, picks, title, accent) => (
      <div style={{
        background: accent + '20', border: `2px solid ${accent}`,
        borderRadius: 14, padding: 12,
      }}>
        <div className="fredoka" style={{ color: accent, fontSize: 14, marginBottom: 8 }}>
          {title}
        </div>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
          {picks.map(p => {
            const posColor = window.POSITION_COLORS[p.position];
            return (
              <div key={p.position} style={{
                display: 'flex', alignItems: 'center', gap: 8,
                background: 'var(--surface-card)', border: '1.5px solid var(--border-default)',
                borderRadius: 10, padding: '4px 8px', position: 'relative',
              }}>
                <window.HexFrame size={28} color={posColor} borderColor="var(--border-emphasis)" borderWidth={2}>
                  <window.RoleIcon pos={p.position} size={14} />
                </window.HexFrame>
                <span style={{ fontSize: 11, fontWeight: 800, color: 'var(--text-muted)', width: 50 }}>
                  {p.position}
                </span>
                {p.championId ? (
                  <>
                    <window.ChampionIcon championId={p.championId} size={32} noAnim />
                    <span style={{ flex: 1, fontSize: 12, fontWeight: 800, color: 'var(--text-primary)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
                      {champions[p.championId]?.name || p.championId}
                    </span>
                    <button onClick={() => setPick(side, p.position, null)} style={{
                      width: 22, height: 22, borderRadius: '50%',
                      background: 'var(--surface-nested)', border: '1.5px solid var(--border-default)',
                      cursor: 'pointer', fontFamily: 'Nunito', fontWeight: 800, fontSize: 11,
                      color: 'var(--accent-orange)', padding: 0, lineHeight: '18px',
                    }}>×</button>
                  </>
                ) : (
                  <button
                    onClick={() => setPickerOpen({ side, pos: p.position })}
                    className="cozy-btn"
                    style={{
                      flex: 1, padding: '4px 10px',
                      border: '2px dashed var(--border-emphasis)', borderRadius: 10,
                      background: 'transparent', color: 'var(--accent-orange)',
                      fontFamily: 'Nunito', fontWeight: 800, fontSize: 12,
                      cursor: 'pointer', textAlign: 'left',
                    }}
                  >
                    Click to add champion…
                  </button>
                )}
                {pickerOpen && pickerOpen.side === side && pickerOpen.pos === p.position && (
                  <ChampionPicker
                    champions={champions}
                    exclude={excludeIds}
                    onClose={() => setPickerOpen(null)}
                    onPick={(id) => setPick(side, p.position, id)}
                    anchorStyle={{ top: '100%', left: 0, marginTop: 4 }}
                  />
                )}
              </div>
            );
          })}
        </div>
      </div>
    );

    return (
      <div
        onMouseDown={e => { if (e.target === e.currentTarget) onClose(); }}
        style={{
          position: 'fixed', inset: 0, zIndex: 1000,
          background: 'rgba(74, 55, 40, 0.5)',
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          padding: 16,
        }}
      >
        <div className="cozy-card pop-in" style={{
          width: '100%', maxWidth: 720, maxHeight: '88vh',
          padding: 22, display: 'flex', flexDirection: 'column',
          overflow: 'hidden',
        }}>
          <div className="corner-dot corner-dot-bl"></div>
          <div className="corner-dot corner-dot-br"></div>

          <h2 className="fredoka" style={{ color: 'var(--accent-orange)', fontSize: 22, margin: '4px 0 4px' }}>
            Log Game {gameNumber} Picks 📝
          </h2>
          <p style={{ color: 'var(--text-muted)', fontWeight: 700, fontSize: 12.5, margin: '0 0 14px' }}>
            Lock in everything the two teams played this game — they're out of the pool for the rest of the series.
          </p>

          <div className="responsive-two-column" style={{ overflowY: 'auto', minHeight: 0 }}>
            {renderColumn('us',    our,   'Our crew 🛡️',    '#7CBF8E')}
            {renderColumn('enemy', enemy, 'Enemy squad ⚔️', '#E8A0A0')}
          </div>

          <div style={{
            display: 'flex', gap: 10, justifyContent: 'flex-end',
            marginTop: 14, paddingTop: 14,
            borderTop: '1.5px dashed var(--border-default)',
          }}>
            <window.CozyButton color="cream" onClick={onClose}>Cancel 👋</window.CozyButton>
            <window.CozyButton color="sage" onClick={handleSave}>Save game 🌟</window.CozyButton>
          </div>
        </div>
      </div>
    );
  }

  // ── Empty / pre-series state ──────────────────────────────────────────────
  function NoSeriesState({ onStart }) {
    return (
      <div className="cozy-card" style={{
        maxWidth: 540, margin: '40px auto', padding: '36px 28px',
        textAlign: 'center',
      }}>
        <div className="corner-dot corner-dot-bl"></div>
        <div className="corner-dot corner-dot-br"></div>
        <div className="float" style={{ display: 'inline-block', marginBottom: 14 }}>
          <svg viewBox="0 0 120 110" width="130" height="120">
            <ellipse cx="58" cy="68" rx="36" ry="30" fill="var(--surface-card)" stroke="var(--border-emphasis)" strokeWidth="2.5" />
            <ellipse cx="58" cy="76" rx="22" ry="16" fill="var(--surface-nested)" />
            <path d="M30 46 Q26 32 38 30 L44 44 Z" fill="var(--surface-card)" stroke="var(--border-emphasis)" strokeWidth="2.5" strokeLinejoin="round" />
            <path d="M86 46 Q90 32 78 30 L72 44 Z" fill="var(--surface-card)" stroke="var(--border-emphasis)" strokeWidth="2.5" strokeLinejoin="round" />
            <circle cx="48" cy="60" r="2.5" fill="var(--text-primary)" />
            <circle cx="66" cy="60" r="2.5" fill="var(--text-primary)" />
            <circle cx="48.7" cy="59.3" r="0.8" fill="var(--surface-card)" />
            <circle cx="66.7" cy="59.3" r="0.8" fill="var(--surface-card)" />
            <ellipse cx="57" cy="67" rx="3" ry="2" fill="var(--text-primary)" />
            <path d="M54 70 Q57 73 60 70" stroke="var(--text-primary)" strokeWidth="1.6" fill="none" strokeLinecap="round" />
            <ellipse cx="41" cy="66" rx="3" ry="2" fill="#F2A7C3" opacity="0.6" />
            <ellipse cx="73" cy="66" rx="3" ry="2" fill="#F2A7C3" opacity="0.6" />
            {/* lock charm */}
            <rect x="86" y="48" width="14" height="12" rx="2" fill="#F7DFA0" stroke="var(--border-emphasis)" strokeWidth="1.5" />
            <path d="M88 48 L88 44 Q88 40 93 40 Q98 40 98 44 L98 48" stroke="var(--border-emphasis)" strokeWidth="2" fill="none" />
            <circle cx="93" cy="54" r="1.6" fill="var(--text-primary)" />
            <path d="M93 54 L93 58" stroke="var(--text-primary)" strokeWidth="1.5" strokeLinecap="round" />
          </svg>
        </div>
        <h2 className="fredoka" style={{ color: 'var(--accent-orange)', fontSize: 26, margin: '0 0 8px' }}>
          Ready for tournament day? 🐾
        </h2>
        <p style={{ color: 'var(--text-muted)', fontWeight: 700, fontSize: 13.5, margin: '0 0 20px', maxWidth: 360, marginLeft: 'auto', marginRight: 'auto', lineHeight: 1.5 }}>
          Start tracking your Fearless Draft series — never play the same champ twice!
        </p>
        <window.CozyButton color="sage" onClick={onStart}>
          Start a series 🌟
        </window.CozyButton>
      </div>
    );
  }

  // ── Top series setup bar ──────────────────────────────────────────────────
  function SeriesBar({ series, onUpdate, onEnd, onNew }) {
    const max = FORMAT_GAMES[series.format] || 3;
    const currentGame = Math.min((series.games || []).length + 1, max);
    const isSeriesEnded = !!(series.seriesEnded || series.status === 'ended');
    const debouncedSeriesName = window.useDebounceFirebaseUpdate(
      series.seriesName || '',
      (val) => onUpdate({ seriesName: val })
    );

    return (
      <div className="cozy-card" style={{
        padding: '14px 16px', marginBottom: 16,
        display: 'flex', flexWrap: 'wrap', gap: 10, alignItems: 'center',
      }}>
        <div className="corner-dot corner-dot-bl"></div>
        <div className="corner-dot corner-dot-br"></div>

        <div className="ft-hex-wrap" style={{ minWidth: 240, marginLeft: 14 }}>
          <input
            className="ft-hex-input"
            value={debouncedSeriesName.value}
            onChange={e => debouncedSeriesName.onChange(e.target.value)}
            onBlur={debouncedSeriesName.onBlur}
            onFocus={debouncedSeriesName.onFocus}
            placeholder="vs Enemy Team — Quarterfinals"
          />
        </div>

        <select
          value={series.format || 'Bo3'}
          onChange={e => onUpdate({ format: e.target.value })}
          className="ft-format-pill"
        >
          {['Bo1', 'Bo3', 'Bo5'].map(f => <option key={f} value={f}>{f}</option>)}
        </select>

        <div className={!isSeriesEnded ? 'ft-game-pulse' : ''} style={{
          background: isSeriesEnded ? '#E6E1DA' : 'var(--accent-orange)',
          color: isSeriesEnded ? '#6B5F52' : 'var(--surface-nested)',
          borderRadius: 16, padding: '6px 14px',
          fontFamily: 'Fredoka One', fontSize: 13,
          display: 'inline-flex', alignItems: 'center', gap: 6,
        }}>
          {isSeriesEnded ? (
            <>🏁 Series ended</>
          ) : (
            <>Game {currentGame} of {max}</>
          )}
        </div>

        <div style={{ marginLeft: 'auto', display: 'inline-flex', gap: 8 }}>
          {!isSeriesEnded && (
            <window.CozyButton color="cream" small onClick={onEnd}>
              End series 🏁
            </window.CozyButton>
          )}
          <window.CozyButton color="sage" small onClick={onNew}>
            New series 🌱
          </window.CozyButton>
        </div>
      </div>
    );
  }

  // ── Main screen ───────────────────────────────────────────────────────────
  function FearlessTracker() {
    const {
      players, champions, showToast,
      fearlessSeries, updateFearlessSeries,
      fearlessSeriesHistory, lobbyCode
    } = window.useApp();
    
    const hasGlobal = fearlessSeries !== undefined && updateFearlessSeries !== undefined;
    const [localState, setLocalState] = useState(() => {
      try {
        const raw = localStorage.getItem('cozydraft-fearless-v2');
        if (raw) return JSON.parse(raw);
      } catch {}
      return { fearlessSeries: null, fearlessSeriesHistory: {} };
    });
    
    const stateSeries = hasGlobal ? fearlessSeries : localState.fearlessSeries;
    const stateHistory = hasGlobal ? fearlessSeriesHistory : localState.fearlessSeriesHistory;
    
    const setState = useCallback((updater) => {
      if (hasGlobal) {
        const prev = fearlessSeries || null;
        const next = typeof updater === 'function' ? updater({ fearlessSeries: prev }).fearlessSeries : updater;
        updateFearlessSeries(next);
      } else {
        setLocalState(prev => {
          const next = typeof updater === 'function' ? updater(prev) : updater;
          try { localStorage.setItem('cozydraft-fearless-v2', JSON.stringify(next)); } catch {}
          return next;
        });
      }
    }, [hasGlobal, fearlessSeries, updateFearlessSeries]);

    const [modal, setModal] = useState(null); // { gameNumber }
    const [confettiKey, setConfettiKey] = useState(0);

    const series = stateSeries;
    const isSeriesEnded = !!(series?.seriesEnded || series?.status === 'ended');

    const startNew = () => {
      const db = window.db;
      
      // Archive current series if it has any logged games.
      if (series && (series.games || []).length > 0) {
        const timestamp = Date.now();
        const archivedData = {
          ...series,
          id: series.id || timestamp,
          endedAt: new Date().toISOString()
        };
        if (hasGlobal && db && lobbyCode) {
          db.ref(`rooms/${lobbyCode}/state/fearlessSeriesHistory/${timestamp}`).set(archivedData).catch(err => {
            console.error("Firebase archive failed:", err);
          });
        } else {
          setLocalState(prev => {
            const nextHistory = { ...(prev.fearlessSeriesHistory || {}), [timestamp]: archivedData };
            const nextState = { ...prev, fearlessSeriesHistory: nextHistory };
            try { localStorage.setItem('cozydraft-fearless-v2', JSON.stringify(nextState)); } catch {}
            return nextState;
          });
        }
      }

      // Reset active series
      const freshSeries = {
        seriesName: '',
        format: 'Bo3',
        currentGame: 1,
        games: [],
        seriesEnded: false,
        createdAt: Date.now()
      };

      if (hasGlobal && db && lobbyCode) {
        db.ref(`rooms/${lobbyCode}/state/fearlessSeries`).set(freshSeries).catch(err => {
          console.error("Firebase reset failed:", err);
        });
      } else {
        setState(prev => ({
          ...prev,
          fearlessSeries: freshSeries
        }));
      }

      // Hide the 'Series wrapped' banner & reset any other local states
      setConfettiKey(0);
      setModal(null);

      // Scroll to the top of the page
      window.scrollTo({ top: 0, behavior: 'smooth' });

      showToast && showToast('New series started 🌱');
    };

    const updateSeries = (patch) => {
      const db = window.db;
      if (hasGlobal && db && lobbyCode) {
        db.ref(`rooms/${lobbyCode}/state/fearlessSeries`).update(patch).catch(err => {
          console.error("Firebase update failed:", err);
        });
      } else {
        setState(prev => ({
          ...prev,
          fearlessSeries: { ...prev.fearlessSeries, ...patch }
        }));
      }
    };

    const endSeries = () => {
      if (!series) return;
      if (!window.confirm('End this series? You can start a new one right after.')) return;
      
      const patch = { seriesEnded: true, status: 'ended', endedAt: new Date().toISOString() };
      const db = window.db;
      if (hasGlobal && db && lobbyCode) {
        db.ref(`rooms/${lobbyCode}/state/fearlessSeries`).update(patch).catch(err => {
          console.error("Firebase update failed:", err);
        });
      } else {
        setState(prev => ({
          ...prev,
          fearlessSeries: { ...prev.fearlessSeries, ...patch }
        }));
      }
      setConfettiKey(k => k + 1);
      showToast && showToast('Series wrapped — GGs 🏁✦');
    };

    const openLogModal = () => {
      if (!series) return;
      const max = FORMAT_GAMES[series.format] || 3;
      const gameNumber = Math.min((series.games || []).length + 1, max);
      setModal({ gameNumber });
    };

    const saveGame = (gameData) => {
      const cur = series;
      if (!cur) return;
      const db = window.db;
      const existing = (cur.games || []).find(g => g.gameNumber === gameData.gameNumber);
      const games = existing
        ? (cur.games || []).map(g => g.gameNumber === gameData.gameNumber ? gameData : g)
        : [...(cur.games || []), gameData].sort((a, b) => a.gameNumber - b.gameNumber);
      const max = FORMAT_GAMES[cur.format] || 3;
      const isEnded = games.length >= max;
      
      const patch = {
        games,
        currentGame: Math.min(games.length + 1, max),
        seriesEnded: isEnded,
        status: isEnded ? 'ended' : 'active'
      };

      if (hasGlobal && db && lobbyCode) {
        db.ref(`rooms/${lobbyCode}/state/fearlessSeries`).update(patch).catch(err => {
          console.error("Firebase update failed:", err);
        });
      } else {
        setState(prev => ({
          ...prev,
          fearlessSeries: { ...prev.fearlessSeries, ...patch }
        }));
      }
      setModal(null);
      showToast && showToast(`Game ${gameData.gameNumber} locked in 🔒`);
    };

    // Derive locked-id sets (the union: in Fearless, ANY champion either team
    // played is out of the pool for everyone for the rest of the series).
    const lockedOurIds = useMemo(() => {
      const s = new Set();
      series?.games?.forEach(g => g.ourPicks.forEach(p => p.championId && s.add(p.championId)));
      return s;
    }, [series]);
    const lockedEnemyIds = useMemo(() => {
      const s = new Set();
      series?.games?.forEach(g => g.enemyPicks.forEach(p => p.championId && s.add(p.championId)));
      return s;
    }, [series]);
    const lockedAllIds = useMemo(() => {
      return new Set([...lockedOurIds, ...lockedEnemyIds]);
    }, [lockedOurIds, lockedEnemyIds]);
    // championId → { side: 'us'|'enemy', gameNumber } for tooltips/badges.
    const lockedInfo = useMemo(() => {
      const map = {};
      series?.games?.forEach(g => {
        g.ourPicks.forEach(p => {
          if (p.championId && !map[p.championId]) map[p.championId] = { side: 'us', gameNumber: g.gameNumber };
        });
        g.enemyPicks.forEach(p => {
          if (p.championId && !map[p.championId]) map[p.championId] = { side: 'enemy', gameNumber: g.gameNumber };
        });
      });
      return map;
    }, [series]);

    // Stats
    const flexRemaining = useMemo(() => {
      if (!series) return 0;
      return POSITIONS.reduce((n, pos) => {
        const player = players.find(p => p.position === pos);
        const pool = (player?.pool || []).filter(e => e.position === pos);
        return n + pool.filter(e => !lockedAllIds.has(e.championId)).length;
      }, 0);
    }, [series, players, lockedAllIds]);

    const warnings = useMemo(() => {
      if (!series) return [];
      const out = [];
      POSITIONS.forEach(pos => {
        const player = players.find(p => p.position === pos);
        const pool = (player?.pool || []).filter(e => e.position === pos);
        const avail = pool.filter(e => !lockedAllIds.has(e.championId)).length;
        if (pool.length > 0 && avail <= 2) {
          out.push(`${window.POSITION_LABELS[pos]} lane has only ${avail} left`);
        }
      });
      return out;
    }, [series, players, lockedAllIds]);

    const archivedList = useMemo(() => {
      const history = stateHistory;
      if (!history) return [];
      const arr = (Array.isArray(history) ? history : Object.values(history)).filter(Boolean);
      return arr.sort((a, b) => (b.createdAt || b.id || 0) - (a.createdAt || a.id || 0));
    }, [stateHistory]);

    if (!series) {
      return (
        <div style={{ padding: 20 }}>
          <h1 className="fredoka" style={{ color: 'var(--accent-orange)', fontSize: 28, marginBottom: 4 }}>
            Fearless Tracker 🔒
          </h1>
          <p style={{ color: 'var(--text-muted)', fontWeight: 700, fontSize: 14, margin: '0 0 20px 0' }}>
            One champ, one game — no repeats. The crew is locked in.
          </p>
          <NoSeriesState onStart={startNew} />
          {archivedList.length > 0 && (
            <ArchivedSeriesStrip archived={archivedList} champions={champions} />
          )}
        </div>
      );
    }

    const totalLocked = (series.games || []).reduce(
      (n, g) => n + g.ourPicks.filter(p => p.championId).length + g.enemyPicks.filter(p => p.championId).length, 0,
    );

    return (
      <div style={{ padding: 20, position: 'relative' }}>
        <h1 className="fredoka" style={{ color: 'var(--accent-orange)', fontSize: 28, marginBottom: 4 }}>
          Fearless Tracker 🔒
        </h1>
        <p style={{ color: 'var(--text-muted)', fontWeight: 700, fontSize: 14, margin: '0 0 16px 0' }}>
          Tournament day — track everything the two teams have played this series.
        </p>

        <SeriesBar series={series} onUpdate={updateSeries} onEnd={endSeries} onNew={startNew} />

        {/* Confetti burst on series end */}
        {isSeriesEnded && (
          <SeriesEndedBanner key={confettiKey} series={series} onStartNew={startNew} />
        )}

        {/* Locked champion cards */}
        <div className="ft-grid-cards" style={{ marginBottom: 16 }}>
          <LockedCard
            side="us" games={series.games || []} champions={champions}
            format={series.format} currentGame={Math.min((series.games || []).length + 1, FORMAT_GAMES[series.format] || 3)}
            status={isSeriesEnded ? 'ended' : 'active'} onLogGame={openLogModal}
          />
          <LockedCard
            side="enemy" games={series.games || []} champions={champions}
            format={series.format} currentGame={Math.min((series.games || []).length + 1, FORMAT_GAMES[series.format] || 3)}
            status={isSeriesEnded ? 'ended' : 'active'} onLogGame={openLogModal}
          />
        </div>

        {/* Lane availability strip */}
        <div className="cozy-card" style={{ padding: 16, marginBottom: 16 }}>
          <div className="corner-dot corner-dot-bl"></div>
          <div className="corner-dot corner-dot-br"></div>
          <div style={{ marginTop: 4, marginBottom: 12 }}>
            <h3 className="fredoka" style={{ color: 'var(--accent-orange)', fontSize: 19, margin: 0, display: 'inline-flex', alignItems: 'center', gap: 8 }}>
              Our Available Pool by Lane <span>🌿</span>
            </h3>
            <div style={{ fontSize: 12, fontWeight: 800, color: 'var(--text-muted)', marginTop: 2 }}>
              Live count after locking in {lockedAllIds.size} champ{lockedAllIds.size !== 1 ? 's' : ''} across both teams
            </div>
          </div>
          <div className="ft-lane-strip">
            {POSITIONS.map(pos => (
              <LaneAvailability
                key={pos} pos={pos}
                player={players.find(p => p.position === pos)}
                champions={champions}
                lockedIds={lockedAllIds}
                lockedInfo={lockedInfo}
              />
            ))}
          </div>
        </div>

        {/* Series stats */}
        <div className="cozy-card" style={{ padding: 16 }}>
          <div className="corner-dot corner-dot-bl"></div>
          <div className="corner-dot corner-dot-br"></div>
          <div style={{ marginTop: 4, marginBottom: 12 }}>
            <h3 className="fredoka" style={{ color: 'var(--accent-orange)', fontSize: 19, margin: 0 }}>
              Series Stats 📊
            </h3>
          </div>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))', gap: 12 }}>
            <StatTile emoji="📊" label="Total locked picks" value={totalLocked} />
            <StatTile emoji="🌿" label="Flex options remaining" value={flexRemaining} color="#7CBF8E" />
            <StatTile
              emoji="⚠️"
              label="Warnings"
              value={warnings.length ? `${warnings.length} lane${warnings.length !== 1 ? 's' : ''} thin` : 'All good 🌸'}
              color={warnings.length ? '#C97070' : '#7CBF8E'}
              hint={warnings.join(' · ')}
            />
          </div>
        </div>

        {modal && (
          <LogGameModal
            gameNumber={modal.gameNumber}
            initialOur={emptyGamePicks()}
            initialEnemy={emptyGamePicks()}
            champions={champions}
            excludeIds={new Set([...lockedOurIds, ...lockedEnemyIds])}
            onClose={() => setModal(null)}
            onSave={saveGame}
          />
        )}
      </div>
    );
  }

  // ── Stat tile + ended banner + archived strip ─────────────────────────────
  function StatTile({ emoji, label, value, color = 'var(--text-primary)', hint }) {
    return (
      <div style={{
        background: 'var(--surface-nested)', border: '1.5px solid var(--border-default)',
        borderRadius: 14, padding: '12px 14px',
        display: 'flex', flexDirection: 'column', gap: 4,
      }}>
        <div style={{ fontSize: 11, fontWeight: 800, color: 'var(--text-muted)', letterSpacing: 0.4, textTransform: 'uppercase' }}>
          {emoji} {label}
        </div>
        <div style={{ fontFamily: 'Fredoka One', fontSize: 22, color }}>
          {value}
        </div>
        {hint && (
          <div style={{ fontSize: 11, fontWeight: 700, color: 'var(--text-muted)', lineHeight: 1.35 }}>
            {hint}
          </div>
        )}
      </div>
    );
  }

  function SeriesEndedBanner({ series, onStartNew }) {
    // Simple celebratory hextech sparkle burst
    const sparkles = Array.from({ length: 16 }, (_, i) => i);
    return (
      <div className="cozy-card" style={{
        padding: '16px 18px', marginBottom: 16,
        background: 'var(--surface-card)',
        position: 'relative', overflow: 'hidden',
        textAlign: 'center',
      }}>
        <div className="corner-dot corner-dot-bl"></div>
        <div className="corner-dot corner-dot-br"></div>

        {sparkles.map(i => {
          const left = (i * 73) % 100;
          const top  = (i * 47) % 90;
          const delay = (i * 0.08).toFixed(2);
          const colors = ['#C5B4E3', '#F7DFA0', '#AED6F1', '#F2A7C3', '#7CBF8E'];
          return (
            <div key={i} className="float" style={{
              position: 'absolute', left: `${left}%`, top: `${top}%`,
              animationDelay: `${delay}s`, pointerEvents: 'none',
            }}>
              <window.CrystalSparkle size={10 + (i % 3) * 3} color={colors[i % colors.length]} />
            </div>
          );
        })}

        <div className="fredoka" style={{ color: 'var(--accent-orange)', fontSize: 22, marginTop: 6, position: 'relative' }}>
          🏁 Series wrapped — GGs!
        </div>
        <p style={{
          color: 'var(--text-muted)', fontWeight: 700, fontSize: 13,
          margin: '4px 0 12px', position: 'relative',
        }}>
          {(series.games || []).length} game{(series.games || []).length !== 1 ? 's' : ''} logged ·
          {' '}{series.seriesName || 'unnamed series'}
        </p>
        <div style={{ position: 'relative' }}>
          <window.CozyButton color="sage" onClick={onStartNew}>
            Start next series →
          </window.CozyButton>
        </div>
      </div>
    );
  }

  function ArchivedSeriesStrip({ archived, champions }) {
    if (!archived || archived.length === 0) return null;
    return (
      <div style={{ marginTop: 22 }}>
        <div className="fredoka" style={{ color: 'var(--accent-orange)', fontSize: 17, marginBottom: 8 }}>
          📚 Past series
        </div>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
          {archived.slice(0, 5).map(s => (
            <div key={s.id || s.createdAt} className="cozy-card" style={{ padding: '10px 14px' }}>
              <div className="corner-dot corner-dot-bl"></div>
              <div className="corner-dot corner-dot-br"></div>
              <div style={{ display: 'flex', alignItems: 'center', gap: 10, paddingLeft: 12, flexWrap: 'wrap' }}>
                <span className="fredoka" style={{ color: 'var(--text-primary)', fontSize: 14 }}>
                  {s.seriesName || 'Unnamed series'}
                </span>
                <span style={{ fontSize: 11, fontWeight: 800, color: 'var(--text-muted)' }}>
                  · {s.format} · {(s.games || []).length} game{(s.games || []).length !== 1 ? 's' : ''}
                </span>
              </div>
            </div>
          ))}
        </div>
      </div>
    );
  }

  return { FearlessTracker };
})();

Object.assign(window, { FearlessTracker: FearlessTrackerNS.FearlessTracker });
