// Match Lobby — the marquee SSBU experience
// Stage striking/banning, lobby code, chat with opposing coach, score reporting

const STRIKE_ORDER_G1 = [
  { team: "away", count: 1, label: "Quartz Hill strikes 1 starter" },
  { team: "home", count: 2, label: "Hamilton strikes 2 starters" },
  { team: "away", count: 1, label: "Quartz Hill strikes 1 starter" },
];

const LobbyPage = ({ persona, matchId, onNav, gameState, setGameState, chat, setChat }) => {
  const D = window.NASEF_DATA;
  const match = D.matches.find(m => m.id === matchId) || D.matches.find(m => m.status === "live");
  const home = D.schoolsById[match.home];
  const away = D.schoolsById[match.away];
  const homeCoach = D.coaches[match.home];
  const awayCoach = D.coaches[match.away];

  const isCaptain = (() => { try { return localStorage.getItem("nasef.captain") === "1"; } catch { return false; } })();
  const canReport = persona === "coach" || persona === "admin" || (persona === "student" && isCaptain);
  const canForfeit = canReport;
  const isCoachLike = persona === "coach" || persona === "admin";

  const [tab, setTab] = React.useState("stage");
  const [chatInput, setChatInput] = React.useState("");
  const [chatTab, setChatTab] = React.useState("all");
  const [forfeitOpen, setForfeitOpen] = React.useState(false);
  const chatRef = React.useRef(null);

  React.useEffect(() => {
    if (chatRef.current) chatRef.current.scrollTop = chatRef.current.scrollHeight;
  }, [chat]);

  // Mount the SSBU wallpaper on <body> so it fills the viewport.
  // (Can't render it inside <main className="fade-in"> because the animation's
  //  translateY transform creates a containing block that breaks position:fixed.)
  React.useEffect(() => {
    document.body.classList.add("lobby-active");
    return () => document.body.classList.remove("lobby-active");
  }, []);

  const sendChat = () => {
    if (!chatInput.trim()) return;
    if (chatTab === "coach" && !isCoachLike) return;
    const me = persona === "coach" ? "ham_coach" : persona === "student" ? (isCaptain ? "ham_captain" : "ham_player") : "admin";
    const who = persona === "coach" ? "Edwin Guama (Hamilton HS)" :
                persona === "student" ? `Slate (Hamilton${isCaptain ? " · Captain" : ""})` :
                "James Wood (NASEF Admin)";
    setChat(c => [...c, {
      id: Date.now(),
      t: new Date().toLocaleTimeString("en-US", { hour: "2-digit", minute: "2-digit", hour12: false }),
      from: me, who, text: chatInput, kind: "msg", side: "home",
      channel: chatTab,
    }]);
    setChatInput("");
    setTimeout(() => {
      const replies = chatTab === "coach"
        ? ["Copy that, coach.", "Confirmed on our end.", "Sounds good.", "👍"]
        : ["GG.", "Ready when your players are.", "Confirmed.", "👍"];
      const replyWho = chatTab === "coach" ? "Marcus Riley (Quartz Hill HS)" :
        Math.random() > 0.5 ? "Marcus Riley (Quartz Hill HS)" : "Vex (Quartz Hill)";
      setChat(c => [...c, {
        id: Date.now() + 1,
        t: new Date().toLocaleTimeString("en-US", { hour: "2-digit", minute: "2-digit", hour12: false }),
        from: "qhl", who: replyWho,
        text: replies[Math.floor(Math.random() * replies.length)],
        kind: "msg", side: "away",
        channel: chatTab,
      }]);
    }, 1400 + Math.random() * 800);
  };

  return (
    <div>
      {/* SSBU wallpaper backdrop is rendered by body.lobby-active::before in styles.css
          so it fills the viewport (not constrained to .app-main's transform). */}
      {/* Lobby header — SSBU wallpaper banner */}
      <div style={{ marginBottom: 24 }}>
        <button className="btn ghost sm" onClick={() => onNav("schedule")} style={{ marginBottom: 12 }}>
          <IconChevLeft size={12} /> Back to schedule
        </button>
        <div className="card" style={{ padding: 0, overflow: "hidden", border: "1px solid rgba(255,59,92,0.3)" }}>
          <SSBUBanner height={220} overlay="match">
            <div className="lobby-hero-grid" style={{ padding: "22px 28px", display: "grid", gridTemplateColumns: "1fr auto 1fr", gap: 24, alignItems: "center", height: "100%" }}>
              <div className="row lobby-hero-team lobby-hero-home" style={{ gap: 16 }}>
                <Crest school={home} size="lg" />
                <div>
                  <div style={{ fontWeight: 700, fontSize: 20, textShadow: "0 2px 8px rgba(0,0,0,0.6)" }}>{home.name}</div>
                  <div style={{ fontSize: 12, color: "rgba(255,255,255,0.75)", textShadow: "0 1px 4px rgba(0,0,0,0.6)" }}>{home.mascot} · 4-0 Pacific Coast</div>
                </div>
              </div>
              <div className="lobby-hero-score" style={{ textAlign: "center" }}>
                <div className="mono" style={{ fontSize: 80, fontWeight: 800, lineHeight: 1, letterSpacing: "0.06em", display: "flex", alignItems: "center", justifyContent: "center", gap: 40, textShadow: "0 4px 16px rgba(0,0,0,0.7)" }}>
                  <span style={{ color: "var(--nasef-orange)" }}>{gameState.homeGames}</span>
                  <span style={{ color: gameState.awayGames > gameState.homeGames ? "var(--nasef-orange)" : "#fff" }}>{gameState.awayGames}</span>
                </div>
                <div className="upper" style={{ marginTop: 10, color: "rgba(255,255,255,0.85)", fontSize: 11, letterSpacing: "0.16em", textShadow: "0 1px 4px rgba(0,0,0,0.6)" }}>
                  Match {gameState.currentGame} of 5
                </div>
              </div>
              <div className="row lobby-hero-team lobby-hero-away" style={{ gap: 16, justifyContent: "flex-end" }}>
                <div style={{ textAlign: "right" }}>
                  <div style={{ fontWeight: 700, fontSize: 20, textShadow: "0 2px 8px rgba(0,0,0,0.6)" }}>{away.name}</div>
                  <div style={{ fontSize: 12, color: "rgba(255,255,255,0.75)", textShadow: "0 1px 4px rgba(0,0,0,0.6)" }}>{away.mascot} · 3-1 Pacific Coast</div>
                </div>
                <Crest school={away} size="lg" />
              </div>
            </div>
          </SSBUBanner>
          <div style={{ padding: "12px 28px", borderTop: "1px solid var(--border-soft)", background: "var(--bg-base)", display: "flex", justifyContent: "space-between", fontSize: 12 }}>
            <div className="row" style={{ gap: 24 }}>
              <div className="row-tight"><IconLink size={13} style={{ color: "var(--text-muted)" }} /><span className="upper muted">Lobby</span><span className="mono" style={{ fontWeight: 600, color: "var(--nasef-orange-soft)" }}>{match.lobby}</span><button className="btn ghost icon sm"><IconCopy size={11} /></button></div>
              <div className="row-tight"><IconClock size={13} style={{ color: "var(--text-muted)" }} /><span className="muted">Started 4:02 PM PT</span></div>
              <div className="row-tight"><IconUsers size={13} style={{ color: "var(--text-muted)" }} /><span className="muted">6 in lobby</span></div>
            </div>
            <div className="row" style={{ gap: 8 }}>
              {isCoachLike && <button className="btn sm"><IconChat size={11} />Notify admin</button>}
              {canForfeit && <button className="btn sm danger" onClick={() => setForfeitOpen(true)}><IconWarn size={11} />Forfeit match</button>}
            </div>
          </div>
        </div>

        {/* Dual-team roster strip */}
        <div className="lobby-roster-strip" style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12, marginTop: 12 }}>
          <RosterStrip school={home} roster={D.hamiltonRoster} side="home" />
          <RosterStrip school={away} roster={D.quartzHillRoster} side="away" />
        </div>
      </div>

      {/* Body — 3 col: game timeline | stage area | chat */}
      <div className="lobby-body" style={{ display: "grid", gridTemplateColumns: "240px 1fr 360px", gap: 20, alignItems: "flex-start" }}>
        {/* Timeline column */}
        <div className="card" style={{ padding: 0 }}>
          <div className="card-header"><h3>Match flow</h3></div>
          <div style={{ padding: 14, display: "flex", flexDirection: "column", gap: 10 }}>
            {gameState.games.map((g, i) => {
              const isCurrent = i + 1 === gameState.currentGame;
              const done = g.winner != null;
              return (
                <div key={i} style={{
                  padding: 12,
                  borderRadius: "var(--r-md)",
                  border: "1px solid",
                  borderColor: isCurrent ? "var(--nasef-orange)" : "var(--border-soft)",
                  background: isCurrent ? "rgba(242,104,34,0.08)" : "var(--bg-base)",
                }}>
                  <div className="row-tight" style={{ marginBottom: 6 }}>
                    <span className="upper" style={{ fontSize: 10, color: isCurrent ? "var(--nasef-orange-soft)" : "var(--text-muted)" }}>Game {i + 1}</span>
                    {isCurrent && <span className="badge live" style={{ fontSize: 9, padding: "1px 6px" }}><span className="dot" style={{ width: 4, height: 4 }} />NOW</span>}
                    {done && <span className="badge complete" style={{ fontSize: 9, padding: "1px 6px" }}>Final</span>}
                  </div>
                  <div style={{ fontSize: 12, fontWeight: 600 }}>{g.stage || "—"}</div>
                  {done && (
                    <div style={{ fontSize: 11, color: "var(--text-secondary)", marginTop: 4 }}>
                      Winner: {g.winner === "home" ? home.short : away.short}
                    </div>
                  )}
                </div>
              );
            })}
          </div>
        </div>

        {/* Stage striking / picking */}
        <div className="card" style={{ padding: 0 }}>
          <div className="card-header" style={{ paddingBottom: 0, borderBottom: "none" }}>
            <Tabs value={tab} onChange={setTab} items={[
              { value: "stage", label: "Stage Phase" },
              { value: "score", label: "Report Score" },
              { value: "rules", label: "Ruleset" },
            ]} />
          </div>
          <div style={{ padding: 22 }}>
            {tab === "stage" && <StagePhase gameState={gameState} setGameState={setGameState} persona={persona} />}
            {tab === "score" && <ScoreReport persona={persona} gameState={gameState} setGameState={setGameState} home={home} away={away} />}
            {tab === "rules" && <Ruleset />}
          </div>
        </div>

        {/* Chat column — All / Coach tabs */}
        <div className="card" style={{ padding: 0, display: "flex", flexDirection: "column", height: 620 }}>
          <div style={{ padding: "14px 18px 0", borderBottom: "1px solid var(--border-soft)" }}>
            <div className="row" style={{ justifyContent: "space-between", marginBottom: 10 }}>
              <h3 style={{ fontSize: 14 }}>Match chat</h3>
              <span className="muted" style={{ fontSize: 11 }}>{chat.filter(m => (m.channel || "all") === chatTab).length} messages</span>
            </div>
            <div style={{ display: "flex", gap: 4 }}>
              {[
                { v: "all", label: "All", sub: "Everyone in match" },
                { v: "coach", label: "Coach", sub: "Coaches only", lock: !isCoachLike },
              ].map(t => {
                const active = chatTab === t.v;
                return (
                  <button key={t.v}
                    onClick={() => setChatTab(t.v)}
                    style={{
                      all: "unset", cursor: "pointer",
                      padding: "8px 14px",
                      fontSize: 12, fontWeight: 600,
                      color: active ? "var(--nasef-orange-soft)" : "var(--text-muted)",
                      borderBottom: "2px solid",
                      borderColor: active ? "var(--nasef-orange)" : "transparent",
                      display: "flex", alignItems: "center", gap: 6,
                    }}
                    title={t.sub}
                  >
                    {t.label}
                    {t.lock && <IconLock size={10} style={{ opacity: 0.7 }} />}
                  </button>
                );
              })}
            </div>
          </div>
          <div ref={chatRef} style={{ flex: 1, overflowY: "auto", padding: "14px 16px", display: "flex", flexDirection: "column", gap: 10 }}>
            {chat.filter(m => (m.channel || "all") === chatTab).length === 0 ? (
              <div style={{ flex: 1, display: "flex", alignItems: "center", justifyContent: "center", color: "var(--text-muted)", fontSize: 12, textAlign: "center", padding: 20 }}>
                {chatTab === "coach" && !isCoachLike
                  ? "Coach-only channel. Players can't see what's posted here."
                  : "No messages in this channel yet."}
              </div>
            ) : (
              chat.filter(m => (m.channel || "all") === chatTab).map(m => (
                <ChatMessage key={m.id} m={m} persona={persona} />
              ))
            )}
          </div>
          <div style={{ padding: 10, borderTop: "1px solid var(--border-soft)", display: "flex", gap: 6 }}>
            {chatTab === "coach" && !isCoachLike ? (
              <div style={{ flex: 1, padding: "8px 12px", fontSize: 11, color: "var(--text-muted)", textAlign: "center", background: "var(--bg-base)", borderRadius: "var(--r-sm)" }}>
                <IconLock size={11} style={{ marginRight: 4, verticalAlign: "-1px" }} />
                Coach channel is read-only for players
              </div>
            ) : (
              <>
                <input
                  className="input"
                  placeholder={chatTab === "coach" ? "Message opposing coach…" : "Message everyone in match…"}
                  value={chatInput}
                  onChange={e => setChatInput(e.target.value)}
                  onKeyDown={e => e.key === "Enter" && sendChat()}
                  style={{ flex: 1 }}
                />
                <button className="btn primary icon" onClick={sendChat}><IconSend size={14} /></button>
              </>
            )}
          </div>
        </div>
      </div>
      {forfeitOpen && <ForfeitModal home={home} away={away} persona={persona} onClose={() => setForfeitOpen(false)} onConfirm={() => {
        setForfeitOpen(false);
        setChat(c => [...c, { id: Date.now(), kind: "system", text: `${home.short} forfeited the match`, channel: "all" }]);
      }} />}
    </div>
  );
};

const ChatMessage = ({ m, persona }) => {
  if (m.kind === "system") {
    return <div className="muted" style={{ fontSize: 11, textAlign: "center", padding: "4px 0", textTransform: "uppercase", letterSpacing: "0.06em" }}>· {m.text} ·</div>;
  }
  const isMe = m.side === "home";
  return (
    <div style={{ display: "flex", flexDirection: "column", alignItems: isMe ? "flex-end" : "flex-start", gap: 2 }}>
      <div style={{ fontSize: 10, color: "var(--text-muted)", padding: "0 4px" }}>{m.who} · {m.t}</div>
      <div style={{
        padding: "8px 12px",
        borderRadius: "var(--r-md)",
        background: isMe ? "rgba(242,104,34,0.15)" : "var(--bg-elevated)",
        border: "1px solid",
        borderColor: isMe ? "rgba(242,104,34,0.3)" : "var(--border)",
        fontSize: 13,
        maxWidth: "85%",
        lineHeight: 1.45,
      }}>
        {m.text}
      </div>
    </div>
  );
};

// Stage striking — interactive grid with scripted opponent (we are Hamilton/home)
const StagePhase = ({ gameState, setGameState, persona }) => {
  const D = window.NASEF_DATA;
  const phase = gameState.stagePhase; // 'striking' | 'picked' | 'completed'
  const struck = gameState.struckStages;
  const picked = gameState.pickedStage;

  const isCaptain = (() => { try { return localStorage.getItem("nasef.captain") === "1"; } catch { return false; } })();
  const canEdit = persona === "coach" || persona === "admin" || (persona === "student" && isCaptain);

  const starters = D.stages.filter(s => s.category === "Starter");
  const counterpicks = D.stages.filter(s => s.category === "Counterpick");

  // Which step are we on (0/1/2) based on strike count
  const stepCounts = STRIKE_ORDER_G1.map(s => s.count);
  let n = struck.length, stepIdx = 0;
  for (let i = 0; i < stepCounts.length; i++) {
    if (n >= stepCounts[i]) { n -= stepCounts[i]; stepIdx = i + 1; }
    else { stepIdx = i; break; }
  }
  if (struck.length >= 4) stepIdx = STRIKE_ORDER_G1.length;
  const currentStep = STRIKE_ORDER_G1[stepIdx];
  // From Hamilton's perspective: we ARE "home". Opponent is "away".
  const isOpponentTurn = currentStep && currentStep.team === "away";
  const isOurTurn = currentStep && currentStep.team === "home";

  // Script: the opposing coach picks one stage to strike when it's their turn.
  // Quartz Hill's "preferences" — they'll strike these in order (best-to-worst from their perspective).
  const OPPONENT_STRIKE_PRIORITY = ["bf", "ps2", "fd", "tc", "sv"];

  React.useEffect(() => {
    if (phase !== "striking") return;
    if (!isOpponentTurn) return;
    const remaining = starters.filter(s => !struck.includes(s.id));
    if (remaining.length <= 1) return;
    const pick = OPPONENT_STRIKE_PRIORITY.find(id => remaining.some(r => r.id === id))
      || remaining[0].id;
    const t = setTimeout(() => {
      setGameState({ ...gameState, struckStages: [...struck, pick] });
    }, 1400);
    return () => clearTimeout(t);
  }, [phase, struck.length, isOpponentTurn]);

  // Auto-lock when only one starter remains
  React.useEffect(() => {
    if (phase !== "striking") return;
    if (struck.length !== 4) return;
    const remaining = starters.filter(s => !struck.includes(s.id))[0];
    const t = setTimeout(() => {
      setGameState({ ...gameState, pickedStage: remaining?.id, stagePhase: "picked" });
    }, 700);
    return () => clearTimeout(t);
  }, [phase, struck.length]);

  const toggleStrike = (stageId) => {
    if (phase !== "striking" || !canEdit || !isOurTurn) return;
    if (struck.includes(stageId)) return;
    if (struck.length < 4) {
      setGameState({ ...gameState, struckStages: [...struck, stageId] });
    }
  };

  const reset = () => setGameState({ ...gameState, struckStages: [], pickedStage: null, stagePhase: "striking" });

  // How many of OUR strikes are committed this step?
  const homeStrikesDone = Math.min(2, Math.max(0, struck.length - 1));
  const ourStrikesNeededThisStep = currentStep && currentStep.team === "home" ? currentStep.count : 0;
  const remainingOurStrikes = isOurTurn ? Math.max(0, ourStrikesNeededThisStep - (struck.length - 1)) : 0;

  return (
    <div>
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start", marginBottom: 18, gap: 16 }}>
        <div style={{ flex: 1 }}>
          <div className="upper" style={{ color: "var(--nasef-orange-soft)", marginBottom: 4 }}>Game {gameState.currentGame} · Stage Striking</div>
          <h3 style={{ fontSize: 20, marginBottom: 6 }}>
            {phase === "picked"
              ? "Stage locked in"
              : isOpponentTurn
                ? "Waiting on Quartz Hill…"
                : isOurTurn
                  ? `Strike ${remainingOurStrikes} of your ${ourStrikesNeededThisStep} stages`
                  : "Stage selected"}
          </h3>
          <p className="muted" style={{ fontSize: 12, margin: 0, maxWidth: 520, lineHeight: 1.5 }}>
            CIF SSBU 1-2-1 strike order: away strikes 1, home strikes 2, away strikes 1. The last remaining starter is Game 1.
          </p>
        </div>
        <div className="row" style={{ gap: 6 }}>
          {canEdit && phase === "picked" && (
            <button className="btn ghost" onClick={reset}>Reset</button>
          )}
        </div>
      </div>

      {/* Strike progress — bigger, clearer turn indicators */}
      <div style={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 10, marginBottom: 22 }}>
        {STRIKE_ORDER_G1.map((step, i) => {
          let cumulative = 0;
          for (let j = 0; j <= i; j++) cumulative += STRIKE_ORDER_G1[j].count;
          const completed = struck.length >= cumulative;
          const active = !completed && stepIdx === i;
          const isHomeStep = step.team === "home";
          const accent = isHomeStep ? "var(--nasef-orange)" : "var(--neon-cyan)";
          return (
            <div key={i} style={{
              padding: "10px 14px",
              borderRadius: "var(--r-sm)",
              border: "1px solid",
              borderColor: active ? accent : completed ? "rgba(45,212,120,0.3)" : "var(--border-soft)",
              background: active ? (isHomeStep ? "rgba(242,104,34,0.1)" : "rgba(79,227,255,0.08)") : completed ? "rgba(45,212,120,0.06)" : "var(--bg-base)",
              transition: "all 0.18s",
            }}>
              <div className="row-tight" style={{ marginBottom: 4 }}>
                <div className="upper" style={{ fontSize: 10, color: active ? accent : completed ? "var(--success)" : "var(--text-muted)", letterSpacing: "0.1em" }}>
                  Step {i + 1}
                </div>
                {completed && <span className="badge complete" style={{ fontSize: 9, padding: "1px 5px" }}>Done</span>}
                {active && <span className="badge" style={{ fontSize: 9, padding: "1px 5px", color: accent, borderColor: accent, background: "transparent" }}>
                  <span className="dot" style={{ width: 4, height: 4, background: accent }} />Now
                </span>}
              </div>
              <div style={{ fontSize: 12.5, fontWeight: 600, lineHeight: 1.35 }}>{step.label}</div>
            </div>
          );
        })}
      </div>

      {/* Turn banner */}
      {(phase === "striking" || phase === "picked") && (() => {
        const isReady = phase === "picked";
        const stageName = isReady ? (starters.find(s => s.id === picked)?.name || "the selected stage") : null;
        const bg = isReady ? "rgba(45,212,120,0.08)" : isOpponentTurn ? "rgba(79,227,255,0.06)" : "rgba(242,104,34,0.06)";
        const border = isReady ? "rgba(45,212,120,0.35)" : isOpponentTurn ? "rgba(79,227,255,0.25)" : "rgba(242,104,34,0.3)";
        const dotColor = isReady ? "var(--success)" : isOpponentTurn ? "var(--neon-cyan)" : "var(--nasef-orange)";
        const dotGlow = isReady ? "rgba(45,212,120,0.22)" : isOpponentTurn ? "rgba(79,227,255,0.18)" : "rgba(242,104,34,0.18)";
        return (
          <div style={{
            padding: "12px 16px", borderRadius: "var(--r-md)",
            background: bg,
            border: `1px solid ${border}`,
            marginBottom: 18,
            display: "flex", alignItems: "center", gap: 12,
          }}>
            <div style={{
              width: 14, height: 14, borderRadius: 99,
              background: dotColor,
              boxShadow: `0 0 0 4px ${dotGlow}`,
              animation: isOpponentTurn ? "pulse 1.4s ease-in-out infinite" : "none",
            }} />
            <div style={{ fontSize: 13 }}>
              {isReady ? (
                <>
                  <strong style={{ color: "var(--success)" }}>Ready — both teams, load up {stageName}.</strong>
                  <span style={{ color: "var(--text-secondary)", marginLeft: 8 }}>Pick Game 1 in your Switch lobby and start the match.</span>
                </>
              ) : isOpponentTurn ? (
                <>
                  <strong style={{ color: "var(--neon-cyan)" }}>Quartz Hill is striking…</strong>
                  <span style={{ color: "var(--text-secondary)", marginLeft: 8 }}>You'll get your turn shortly.</span>
                </>
              ) : (
                <>
                  <strong style={{ color: "var(--nasef-orange-soft)" }}>Your turn — strike {remainingOurStrikes} starter{remainingOurStrikes === 1 ? "" : "s"}.</strong>
                  <span style={{ color: "var(--text-secondary)", marginLeft: 8 }}>Tap a stage below to remove it from Game 1's pool.</span>
                </>
              )}
            </div>
          </div>
        );
      })()}

      <div className="upper muted" style={{ fontSize: 10, marginBottom: 10 }}>Starter stages · pick 1 of {starters.length - struck.length}</div>
      <div style={{ display: "grid", gridTemplateColumns: "repeat(3, minmax(0, 1fr))", gap: 10, marginBottom: 22 }}>
        {starters.map(s => {
          const isStruck = struck.includes(s.id);
          const isPicked = picked === s.id;
          // Who struck it? — match strike order to find side
          const strikeIdx = struck.indexOf(s.id);
          let struckBy = null;
          if (strikeIdx >= 0) {
            let acc = 0;
            for (const step of STRIKE_ORDER_G1) {
              acc += step.count;
              if (strikeIdx < acc) { struckBy = step.team; break; }
            }
          }
          const clickable = phase === "striking" && canEdit && isOurTurn && !isStruck;
          return (
            <button key={s.id}
              onClick={() => toggleStrike(s.id)}
              disabled={!clickable}
              className="stage-card"
              style={{
                all: "unset", cursor: clickable ? "pointer" : "default",
                position: "relative",
                aspectRatio: "16 / 9",
                borderRadius: "var(--r-md)",
                border: "1px solid",
                borderColor: isPicked ? "var(--nasef-orange)" : isStruck ? "rgba(242,69,95,0.35)" : "var(--border)",
                background: isPicked
                  ? "linear-gradient(135deg, rgba(242,104,34,0.25) 0%, rgba(242,104,34,0.05) 100%)"
                  : isStruck
                  ? "var(--bg-base)"
                  : "var(--bg-elevated)",
                overflow: "hidden",
                transition: "all 0.18s",
                boxShadow: isPicked ? "var(--sh-glow-orange)" : "none",
                opacity: isStruck && !isPicked ? 0.55 : 1,
              }}
            >
              <StageArt id={s.img} />
              <div style={{
                position: "absolute", inset: 0,
                background: isStruck && !isPicked
                  ? "rgba(7,9,15,0.78)"
                  : "linear-gradient(180deg, transparent 38%, rgba(7,9,15,0.92) 100%)",
                display: "flex", flexDirection: "column", justifyContent: "flex-end",
                padding: "10px 12px 9px",
              }}>
                <div style={{
                  fontSize: 12, fontWeight: 700,
                  color: isStruck && !isPicked ? "var(--text-secondary)" : "#fff",
                  lineHeight: 1.25,
                  textShadow: "0 1px 4px rgba(0,0,0,0.7)",
                  textWrap: "balance",
                  wordBreak: "break-word",
                }}>
                  {s.name}
                </div>
              </div>
              {isStruck && !isPicked && (
                <>
                  <div style={{ position: "absolute", inset: 0, display: "flex", alignItems: "center", justifyContent: "center" }}>
                    <div style={{ width: 34, height: 34, borderRadius: 99, background: "rgba(242,69,95,0.22)", border: "2px solid var(--danger)", color: "var(--danger)", display: "flex", alignItems: "center", justifyContent: "center" }}>
                      <IconX size={16} />
                    </div>
                  </div>
                  {struckBy && (
                    <div style={{ position: "absolute", top: 8, left: 8 }}>
                      <span className="badge" style={{
                        fontSize: 9, padding: "2px 6px",
                        background: struckBy === "home" ? "rgba(242,104,34,0.18)" : "rgba(79,227,255,0.18)",
                        color: struckBy === "home" ? "var(--nasef-orange-soft)" : "var(--neon-cyan)",
                        borderColor: struckBy === "home" ? "rgba(242,104,34,0.35)" : "rgba(79,227,255,0.35)",
                      }}>
                        {struckBy === "home" ? "HAM struck" : "QHL struck"}
                      </span>
                    </div>
                  )}
                </>
              )}
              {isPicked && (
                <div style={{ position: "absolute", top: 10, right: 10 }}>
                  <span className="badge orange" style={{ fontSize: 10, fontWeight: 700, padding: "3px 9px" }}>GAME 1 STAGE</span>
                </div>
              )}
            </button>
          );
        })}
      </div>

      <div className="upper muted" style={{ fontSize: 10, marginBottom: 10 }}>Counterpick stages · Games 2-5</div>
      <div style={{ display: "grid", gridTemplateColumns: "repeat(4, minmax(0, 1fr))", gap: 8 }}>
        {counterpicks.map(s => (
          <div key={s.id} style={{
            position: "relative", aspectRatio: "16 / 10",
            borderRadius: "var(--r-md)",
            border: "1px solid var(--border-soft)",
            background: "var(--bg-base)",
            overflow: "hidden",
            opacity: 0.6,
          }}>
            <StageArt id={s.img} />
            <div style={{
              position: "absolute", inset: 0,
              background: "linear-gradient(180deg, transparent 40%, rgba(7,9,15,0.92) 100%)",
              display: "flex", alignItems: "flex-end", padding: "8px 10px",
            }}>
              <div style={{ fontSize: 11, fontWeight: 600, lineHeight: 1.2, textShadow: "0 1px 4px rgba(0,0,0,0.7)", textWrap: "balance", wordBreak: "break-word" }}>{s.name}</div>
            </div>
          </div>
        ))}
      </div>
    </div>
  );
};

// Abstract stylized stage thumbnails — original geometric placeholders, not Nintendo art
const StageArt = ({ id }) => {
  const palettes = {
    bf:  ["#1F2937", "#3B82F6", "#60A5FA"],
    fd:  ["#1E1B4B", "#7C3AED", "#A78BFA"],
    sv:  ["#0E4429", "#22C55E", "#86EFAC"],
    ps2: ["#7C2D12", "#F97316", "#FED7AA"],
    tc:  ["#1E3A8A", "#06B6D4", "#67E8F9"],
    kal: ["#5B21B6", "#EC4899", "#F9A8D4"],
    ho:  ["#581C87", "#A855F7", "#E9D5FF"],
    sbf: ["#1F2937", "#475569", "#94A3B8"],
    yos: ["#0E7490", "#FBBF24", "#FDE68A"],
  };
  const [bg, mid, hl] = palettes[id] || ["#1F2937", "#475569", "#94A3B8"];
  return (
    <svg width="100%" height="100%" viewBox="0 0 160 110" preserveAspectRatio="xMidYMid slice" style={{ display: "block" }}>
      <defs>
        <linearGradient id={`g-${id}`} x1="0" y1="0" x2="0" y2="1">
          <stop offset="0%" stopColor={bg} />
          <stop offset="100%" stopColor="#000" />
        </linearGradient>
      </defs>
      <rect width="160" height="110" fill={`url(#g-${id})`} />
      <circle cx="120" cy="30" r="18" fill={hl} opacity="0.35" />
      <circle cx="40" cy="20" r="8" fill={mid} opacity="0.5" />
      <path d={id === "fd" ? "M0 90 L60 80 L100 90 L160 75 L160 110 L0 110Z" : id === "bf" ? "M40 75 H120 V82 H40Z M55 60 H75 V67 H55Z M90 60 H110 V67 H90Z M70 50 H95 V57 H70Z" : id === "sv" ? "M0 78 L160 78 L160 110 L0 110Z" : "M0 75 Q80 65 160 75 L160 110 L0 110Z"}
        fill={mid} opacity="0.85" />
      <path d="M0 88 L160 82 L160 110 L0 110Z" fill={bg} opacity="0.7" />
    </svg>
  );
};

// Score report
const ScoreReport = ({ persona, gameState, setGameState, home, away }) => {
  const [reported, setReported] = React.useState({ winner: null, confirmed: false });
  const isCaptain = (() => { try { return localStorage.getItem("nasef.captain") === "1"; } catch { return false; } })();
  const canReport = persona === "coach" || persona === "admin" || (persona === "student" && isCaptain);

  const submit = () => {
    if (!reported.winner) return;
    setReported({ ...reported, confirmed: true });
    if (reported.winner === "home") {
      setGameState({ ...gameState, homeGames: gameState.homeGames + 1, currentGame: gameState.currentGame + 1, stagePhase: "striking", struckStages: [], pickedStage: null });
    } else {
      setGameState({ ...gameState, awayGames: gameState.awayGames + 1, currentGame: gameState.currentGame + 1, stagePhase: "striking", struckStages: [], pickedStage: null });
    }
    setTimeout(() => setReported({ winner: null, confirmed: false }), 2000);
  };

  if (!canReport) {
    return <Empty icon={IconLock} title="Score reporting is coach & captain only" body="Your coach or team captain will submit the result. You'll see it appear here once confirmed by both sides." />;
  }

  return (
    <div>
      <div style={{ marginBottom: 18 }}>
        <div className="upper" style={{ color: "var(--nasef-orange-soft)", marginBottom: 4 }}>Report Game {gameState.currentGame}</div>
        <h3 style={{ fontSize: 18, marginBottom: 6 }}>Who won the last game?</h3>
        <p className="muted" style={{ fontSize: 12, margin: 0 }}>Both coaches must report the same winner. The opposing coach will see this and confirm — match auto-advances when both agree.</p>
      </div>

      {reported.confirmed ? (
        <div style={{ padding: 32, textAlign: "center", background: "rgba(45,212,120,0.06)", border: "1px solid rgba(45,212,120,0.3)", borderRadius: "var(--r-md)" }}>
          <div style={{ width: 48, height: 48, borderRadius: 99, background: "rgba(45,212,120,0.18)", color: "var(--success)", display: "inline-flex", alignItems: "center", justifyContent: "center", marginBottom: 12 }}>
            <IconCheck size={22} />
          </div>
          <h3 style={{ marginBottom: 6 }}>Score reported</h3>
          <p className="muted" style={{ fontSize: 13 }}>Waiting for opposing coach confirmation…</p>
        </div>
      ) : (
        <>
          <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12, marginBottom: 18 }}>
            {[{ team: "home", school: home }, { team: "away", school: away }].map(({ team, school }) => (
              <button key={team} onClick={() => setReported({ ...reported, winner: team })}
                className="report-card"
                style={{
                  all: "unset", cursor: "pointer", padding: 22,
                  borderRadius: "var(--r-md)",
                  border: "1px solid",
                  borderColor: reported.winner === team ? "var(--nasef-orange)" : "var(--border)",
                  background: reported.winner === team ? "rgba(242,104,34,0.08)" : "var(--bg-base)",
                  display: "flex", alignItems: "center", gap: 14,
                  transition: "all 0.12s",
                }}>
                <Crest school={school} size="lg" />
                <div style={{ flex: 1 }}>
                  <div style={{ fontSize: 15, fontWeight: 600 }}>{school.name}</div>
                  <div className="muted" style={{ fontSize: 11 }}>Won game {gameState.currentGame}</div>
                </div>
                <div style={{
                  width: 22, height: 22, borderRadius: 99,
                  border: "2px solid",
                  borderColor: reported.winner === team ? "var(--nasef-orange)" : "var(--border-strong)",
                  background: reported.winner === team ? "var(--nasef-orange)" : "transparent",
                  display: "flex", alignItems: "center", justifyContent: "center",
                  color: "#14060A",
                }}>
                  {reported.winner === team && <IconCheck size={12} />}
                </div>
              </button>
            ))}
          </div>
          <div className="row" style={{ gap: 8 }}>
            <button className="btn primary" disabled={!reported.winner} onClick={submit}
              style={{ opacity: reported.winner ? 1 : 0.5 }}>
              Report winner <IconArrowR size={12} />
            </button>
            <button className="btn ghost">Report dispute <IconWarn size={12} /></button>
          </div>
        </>
      )}
    </div>
  );
};

const Ruleset = () => (
  <div>
    <div className="upper" style={{ color: "var(--neon-cyan)", marginBottom: 8 }}>CIF SSBU Varsity · Spring 2026</div>
    <h3 style={{ fontSize: 18, marginBottom: 14 }}>Match ruleset</h3>
    <div style={{ display: "flex", flexDirection: "column", gap: 8, fontSize: 13, color: "var(--text-secondary)" }}>
      {[
        ["Format",            "Best of 5, 1v1 singles. Winner stays. 3 stocks per game."],
        ["Time limit",        "7 minutes per game. Sudden Death disabled — go to stock count, then percent."],
        ["Stage selection",   "Game 1: 1-2-1 strike from Starters. Games 2-5: loser picks from Counterpick + Starter pool."],
        ["Stage bans",        "Loser may ban 2 stages before opponent's pick after first game."],
        ["Item set",          "All items off."],
        ["Hazards",           "Stage hazards on; non-applicable for selected stages."],
        ["DSR",               "Dave's Stupid Rule — winner of previous game cannot pick a stage they've already won on."],
        ["Coach involvement", "Coach may communicate with their player between games. No coaching during gameplay."],
      ].map(([k, v]) => (
        <div key={k} style={{ display: "grid", gridTemplateColumns: "140px 1fr", gap: 16, padding: "8px 0", borderBottom: "1px solid var(--border-soft)" }}>
          <span style={{ fontWeight: 600, color: "var(--text)" }}>{k}</span>
          <span>{v}</span>
        </div>
      ))}
    </div>
    <button className="btn ghost" style={{ marginTop: 14 }}><IconExternal size={12} /> Full rulebook (PDF)</button>
  </div>
);

// Forfeit confirmation
const ForfeitModal = ({ home, away, persona, onClose, onConfirm }) => {
  const [reason, setReason] = React.useState("");
  const [ack, setAck] = React.useState(false);
  return (
    <div style={{ position: "fixed", inset: 0, background: "var(--bg-overlay)", backdropFilter: "blur(4px)", zIndex: 100, display: "flex", alignItems: "center", justifyContent: "center" }} onClick={onClose}>
      <div className="card" style={{ width: 520, padding: 0 }} onClick={e => e.stopPropagation()}>
        <div style={{ padding: "18px 22px", borderBottom: "1px solid var(--border-soft)", display: "flex", justifyContent: "space-between" }}>
          <div>
            <h2 style={{ fontSize: 18 }}>Forfeit match</h2>
            <div className="muted" style={{ fontSize: 12, marginTop: 2 }}>{home.short} vs. {away.short}</div>
          </div>
          <button className="btn ghost icon" onClick={onClose}><IconX size={14} /></button>
        </div>
        <div style={{ padding: 22, display: "flex", flexDirection: "column", gap: 14 }}>
          <Toast kind="warning" title="This forfeits the entire match" body={`${away.short} will be awarded the win. The result is final and reflected in standings immediately.`} />
          <div>
            <label className="label">Reason (optional)</label>
            <textarea className="textarea" rows={3} placeholder="Player no-show, technical issue, etc.…" value={reason} onChange={e => setReason(e.target.value)} />
          </div>
          <label className="row-tight" style={{ fontSize: 12, color: "var(--text-secondary)", cursor: "pointer" }}>
            <input type="checkbox" checked={ack} onChange={e => setAck(e.target.checked)} />
            I understand this awards the win to {away.short} and cannot be undone without admin override.
          </label>
          <div className="row" style={{ justifyContent: "flex-end", gap: 8 }}>
            <button className="btn ghost" onClick={onClose}>Cancel</button>
            <button className="btn danger" disabled={!ack} style={{ opacity: ack ? 1 : 0.5 }} onClick={onConfirm}>
              <IconWarn size={12} /> Confirm forfeit
            </button>
          </div>
        </div>
      </div>
    </div>
  );
};

window.LobbyPage = LobbyPage;

// Dual-team roster strip — usernames + avatars for both sides
const RosterStrip = ({ school, roster, side }) => {
  const align = side === "away" ? "flex-end" : "flex-start";
  const accent = side === "home" ? "var(--nasef-orange)" : "var(--neon-cyan)";
  return (
    <div className="card" style={{
      padding: "12px 16px",
      display: "flex", alignItems: "center", gap: 14,
      flexDirection: side === "away" ? "row-reverse" : "row",
      borderLeft: side === "home" ? `2px solid ${accent}` : "1px solid var(--border)",
      borderRight: side === "away" ? `2px solid ${accent}` : "1px solid var(--border)",
    }}>
      <div style={{ display: "flex", flexDirection: "column", alignItems: align, gap: 2, minWidth: 110 }}>
        <div className="upper" style={{ fontSize: 9, color: "var(--text-muted)", letterSpacing: "0.14em" }}>
          {side === "home" ? "Home" : "Away"} · {roster.length} players
        </div>
        <div style={{ fontSize: 12, fontWeight: 600, color: accent }}>{school.short}</div>
      </div>
      <div style={{
        flex: 1, display: "flex", gap: 10,
        justifyContent: side === "away" ? "flex-end" : "flex-start",
        flexDirection: side === "away" ? "row-reverse" : "row",
        flexWrap: "wrap",
      }}>
        {roster.map(p => (
          <div key={p.id} style={{
            display: "flex", alignItems: "center", gap: 8,
            flexDirection: side === "away" ? "row-reverse" : "row",
            padding: "4px 10px 4px 4px",
            background: "var(--bg-base)",
            borderRadius: 999,
            border: "1px solid var(--border-soft)",
          }}
          title={`${p.gamer} (${p.real}) · ${p.main}`}>
            <Avatar src={p.avatar} name={p.gamer} size={28}
              ring={p.role === "Captain" ? accent : null}
              style={{ marginRight: side === "away" ? 0 : 0, marginLeft: side === "away" ? 0 : 0 }} />
            <div style={{ display: "flex", flexDirection: "column", textAlign: side === "away" ? "right" : "left" }}>
              <div style={{ fontSize: 12, fontWeight: 600, lineHeight: 1.1 }}>
                {p.gamer}
                {p.role === "Captain" && <IconStar size={9} style={{ marginLeft: 4, color: accent, verticalAlign: "1px" }} />}
              </div>
              <div style={{ fontSize: 10, color: "var(--text-muted)", lineHeight: 1.2 }}>{p.main}</div>
            </div>
          </div>
        ))}
      </div>
    </div>
  );
};

window.RosterStrip = RosterStrip;
