/* global React, ReactDOM */
const { useState, useEffect, useMemo, useCallback } = React;

const K_FACTOR = 32;
const BASE_ELO = 1000;

const HOUSES = ["Leadstore", "Legacy"];
const DEFAULT_HOUSE = "Legacy";

const DEFAULT_STATE = {
  season: 1,
  players: ["Mason Knarr", "Tanner Waxman", "Thomas Folmer", "Joel Usner", "Josh Gerloch"],
  teams: {
    "Mason Knarr": "Leadstore",
    "Joel Usner": "Leadstore",
    "Thomas Folmer": "Legacy",
    "Josh Gerloch": "Legacy",
    "Tanner Waxman": "",
  },
  matches: [],
};

const C = {
  bg: "#0d0618",
  panel: "#170d28",
  panelTop: "#1e1235",
  line: "#2f2248",
  text: "#ddd6f3",
  dim: "#8a7bb5",
  faint: "#5f5482",
  cyan: "#22e6f0",
  magenta: "#f45cd6",
  gold: "#ffe94a",
  green: "#54f08a",
  red: "#ff5c7a",
};

const HOUSE_COLOR = { Leadstore: C.cyan, Legacy: C.magenta };
const pixel = "'Press Start 2P', monospace";
const body = "'Space Grotesk', system-ui, sans-serif";

const firstName = (n) => (n || "").split(" ")[0];
const glow = (c, a = 1) => `0 0 8px ${c}${a === 1 ? "" : ""}, 0 0 20px ${c}55`;

/* ================= league math ================= */

function computeLeague(state) {
  const players = state.players || [];
  const matches = state.matches || [];
  const teams = state.teams || {};

  const elo = {};
  const rec = {};
  players.forEach((p) => {
    elo[p] = BASE_ELO;
    rec[p] = { w: 0, l: 0, pf: 0, pa: 0, streak: 0, last: null };
  });

  const h2h = {};
  players.forEach((a) => {
    h2h[a] = {};
    players.forEach((b) => (h2h[a][b] = { w: 0, l: 0 }));
  });

  const houses = {};
  HOUSES.forEach((h) => (houses[h] = { w: 0, l: 0, pf: 0, pa: 0 }));

  let marbs = null;
  const enriched = [];

  matches.forEach((m) => {
    const { winner, loser, ws, ls } = m;
    if (elo[winner] === undefined) elo[winner] = BASE_ELO;
    if (elo[loser] === undefined) elo[loser] = BASE_ELO;
    if (!rec[winner]) rec[winner] = { w: 0, l: 0, pf: 0, pa: 0, streak: 0, last: null };
    if (!rec[loser]) rec[loser] = { w: 0, l: 0, pf: 0, pa: 0, streak: 0, last: null };

    const expW = 1 / (1 + Math.pow(10, (elo[loser] - elo[winner]) / 400));
    const delta = Math.round(K_FACTOR * (1 - expW));
    elo[winner] += delta;
    elo[loser] -= delta;

    rec[winner].w++;
    rec[loser].l++;
    rec[winner].pf += ws;
    rec[winner].pa += ls;
    rec[loser].pf += ls;
    rec[loser].pa += ws;
    rec[winner].streak = rec[winner].last === "W" ? rec[winner].streak + 1 : 1;
    rec[winner].last = "W";
    rec[loser].streak = rec[loser].last === "L" ? rec[loser].streak + 1 : 1;
    rec[loser].last = "L";

    if (h2h[winner] && h2h[winner][loser]) h2h[winner][loser].w++;
    if (h2h[loser] && h2h[loser][winner]) h2h[loser][winner].l++;

    // House rivalry — only matches across the two houses count.
    const hw = teams[winner];
    const hl = teams[loser];
    const crossHouse = HOUSES.includes(hw) && HOUSES.includes(hl) && hw !== hl;
    if (crossHouse) {
      houses[hw].w++;
      houses[hw].pf += ws;
      houses[hw].pa += ls;
      houses[hl].l++;
      houses[hl].pf += ls;
      houses[hl].pa += ws;
    }

    if (marbs === null) marbs = winner;
    else if (loser === marbs) marbs = winner;

    enriched.push({ ...m, delta, crossHouse });
  });

  const standings = players
    .map((p) => {
      const r = rec[p];
      const gp = r.w + r.l;
      return {
        name: p,
        house: teams[p] || "",
        elo: Math.round(elo[p]),
        w: r.w,
        l: r.l,
        pct: gp ? Math.round((r.w / gp) * 100) : 0,
        diff: r.pf - r.pa,
        streak: r.last ? `${r.last}${r.streak}` : "—",
        last: r.last,
      };
    })
    .sort((a, b) => b.elo - a.elo || b.w - a.w || a.name.localeCompare(b.name));

  const rivalry = {
    total: houses.Leadstore.w + houses.Legacy.w,
    Leadstore: houses.Leadstore,
    Legacy: houses.Legacy,
  };

  return { standings, h2h, marbs, enriched, rivalry };
}

/* ================= pieces ================= */

function Panel({ children, style, edge }) {
  return (
    <div
      style={{
        background: `linear-gradient(180deg, ${C.panelTop}, ${C.panel})`,
        border: `1px solid ${edge || C.line}`,
        boxShadow: edge ? `0 0 18px ${edge}33, inset 0 0 22px ${edge}12` : "none",
        borderRadius: 4,
        position: "relative",
        ...style,
      }}
    >
      {children}
    </div>
  );
}

function Label({ children, color }) {
  return (
    <div style={{ fontSize: 10, letterSpacing: 2.2, color: color || C.dim, marginBottom: 10 }}>
      {children}
    </div>
  );
}

const inputStyle = {
  width: "100%",
  background: "#0a0414",
  border: `1px solid ${C.line}`,
  borderRadius: 3,
  color: C.text,
  fontFamily: body,
  fontSize: 14,
  padding: "0 12px",
  height: 42,
  outline: "none",
  boxSizing: "border-box",
};

/* ---- the rivalry scoreboard ---- */

function Rivalry({ rivalry }) {
  const ls = rivalry.Leadstore;
  const lg = rivalry.Legacy;
  const total = rivalry.total;
  const lsPct = total ? Math.round((ls.w / total) * 100) : 50;
  const lgPct = 100 - lsPct;

  return (
    <Panel style={{ padding: "20px 20px 18px", marginBottom: 16 }} edge={total ? (ls.w >= lg.w ? C.cyan : C.magenta) : null}>
      <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 12 }}>
        <div style={{ textAlign: "left", flex: 1 }}>
          <div style={{ fontFamily: pixel, fontSize: 11, color: C.cyan, textShadow: glow(C.cyan), lineHeight: 1.6 }}>
            LEADSTORE
          </div>
          <div style={{ fontFamily: pixel, fontSize: 30, color: C.cyan, textShadow: glow(C.cyan), marginTop: 12 }}>
            {ls.w}
          </div>
        </div>

        <div style={{ fontFamily: pixel, fontSize: 13, color: C.faint, padding: "0 6px" }}>VS</div>

        <div style={{ textAlign: "right", flex: 1 }}>
          <div style={{ fontFamily: pixel, fontSize: 11, color: C.magenta, textShadow: glow(C.magenta), lineHeight: 1.6 }}>
            LEGACY
          </div>
          <div style={{ fontFamily: pixel, fontSize: 30, color: C.magenta, textShadow: glow(C.magenta), marginTop: 12 }}>
            {lg.w}
          </div>
        </div>
      </div>

      <div style={{ display: "flex", height: 10, marginTop: 18, border: `1px solid ${C.line}`, background: "#0a0414" }}>
        <div style={{ width: `${lsPct}%`, background: C.cyan, boxShadow: `0 0 12px ${C.cyan}` }} />
        <div style={{ width: `${lgPct}%`, background: C.magenta, boxShadow: `0 0 12px ${C.magenta}` }} />
      </div>

      {total > 0 && (
        <div style={{ display: "flex", justifyContent: "space-between", fontSize: 12, color: C.dim, marginTop: 12 }}>
          <span style={{ color: C.cyan }}>{lsPct}% win rate</span>
          <span style={{ color: C.faint }}>
            {total} match{total === 1 ? "" : "es"} · {ls.pf}–{lg.pf} on points
          </span>
          <span style={{ color: C.magenta }}>{lgPct}% win rate</span>
        </div>
      )}
    </Panel>
  );
}

/* ================= app ================= */

function LPPL() {
  const [state, setState] = useState(DEFAULT_STATE);
  const [loaded, setLoaded] = useState(false);
  const [status, setStatus] = useState("");
  const [err, setErr] = useState("");
  const [pA, setPA] = useState(DEFAULT_STATE.players[0]);
  const [pB, setPB] = useState(DEFAULT_STATE.players[1]);
  const [sA, setSA] = useState("");
  const [sB, setSB] = useState("");
  const [settingsOpen, setSettingsOpen] = useState(false);
  const [newPlayer, setNewPlayer] = useState("");

  useEffect(() => {
    let alive = true;
    let first = true;
    async function pull() {
      try {
        const r = await fetch("/api/league");
        if (!r.ok) throw new Error();
        const data = await r.json();
        if (!alive) return;
        setState({ ...DEFAULT_STATE, ...data });
        if (first && data.players && data.players.length > 1) {
          setPA(data.players[0]);
          setPB(data.players[1]);
        }
        first = false;
      } catch (e) {
        if (alive && first) setErr("Can't reach the server. Refresh to try again.");
      } finally {
        if (alive) setLoaded(true);
      }
    }
    pull();
    const t = setInterval(pull, 10000);
    return () => {
      alive = false;
      clearInterval(t);
    };
  }, []);

  const send = useCallback(async (path, payload) => {
    setStatus("Saving");
    try {
      const r = await fetch(path, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(payload || {}),
      });
      const data = await r.json();
      if (!r.ok) {
        setErr(data.error || "That didn't save.");
        setStatus("");
        return;
      }
      setState({ ...DEFAULT_STATE, ...data });
      setErr("");
      setStatus("Saved");
      setTimeout(() => setStatus(""), 1600);
    } catch (e) {
      setStatus("");
      setErr("Can't reach the server. Try again.");
    }
  }, []);

  const saveRoster = useCallback((players, teams) => send("/api/roster", { players, teams }), [send]);

  const league = useMemo(() => computeLeague(state), [state]);
  const teams = state.teams || {};
  const holderHouse = league.marbs ? teams[league.marbs] : "";
  const leagueName = HOUSES.includes(holderHouse) ? holderHouse : DEFAULT_HOUSE;
  const nameColor = HOUSE_COLOR[leagueName] || C.cyan;

  function logMatch() {
    setErr("");
    const a = Number(sA);
    const b = Number(sB);
    if (pA === pB) return setErr("Pick two different players.");
    if (sA === "" || sB === "" || Number.isNaN(a) || Number.isNaN(b)) return setErr("Enter both scores.");
    if (a === b) return setErr("Ping pong doesn't tie. One of you won.");
    send("/api/match", {
      winner: a > b ? pA : pB,
      loser: a > b ? pB : pA,
      ws: Math.max(a, b),
      ls: Math.min(a, b),
    });
    setSA("");
    setSB("");
  }

  function addPlayer() {
    const n = newPlayer.trim();
    if (!n || state.players.includes(n)) return;
    saveRoster([...state.players, n], { ...teams, [n]: DEFAULT_HOUSE });
    setNewPlayer("");
  }

  const recent = [...league.enriched].reverse().slice(0, 10);

  if (!loaded) {
    return (
      <div style={{ background: C.bg, color: C.dim, fontFamily: pixel, fontSize: 11, padding: 60, textAlign: "center" }}>
        LOADING…
      </div>
    );
  }

  return (
    <div style={{ background: C.bg, minHeight: "100vh", fontFamily: body, color: C.text, position: "relative" }}>
      <style>{`
        .scan::before {
          content:""; position:fixed; inset:0; pointer-events:none; z-index:5;
          background: repeating-linear-gradient(0deg, rgba(255,255,255,.035) 0 1px, transparent 1px 3px);
        }
        select:focus, input:focus { border-color: ${C.cyan} !important; }
        tr.row:hover { background: rgba(255,255,255,.03); }
        @media (max-width: 760px) {
          .split { grid-template-columns: 1fr !important; }
          .form {
            grid-template-columns: 1fr 42px 1fr !important;
            grid-template-rows: 42px 42px 42px !important;
          }
          .form > button { grid-column: 1 / -1 !important; grid-row: 3 !important; }
        }
      `}</style>
      <div className="scan" />

      <div style={{ maxWidth: 940, margin: "0 auto", padding: "36px 16px 60px", position: "relative", zIndex: 1 }}>
        {/* hero */}
        <header style={{ textAlign: "center", marginBottom: 28 }}>
          <div style={{ fontFamily: pixel, fontSize: 9, color: C.magenta, letterSpacing: 2, textShadow: glow(C.magenta) }}>
            SEASON {state.season}
          </div>
          <h1
            style={{
              fontFamily: pixel,
              fontSize: "clamp(34px, 9vw, 62px)",
              color: C.cyan,
              textShadow: `0 0 12px ${C.cyan}, 0 0 40px ${C.cyan}77`,
              margin: "20px 0 16px",
              letterSpacing: 2,
            }}
          >
            LPPL
          </h1>
          <div style={{ fontSize: 12, letterSpacing: 3.4, color: nameColor, textShadow: `0 0 10px ${nameColor}88` }}>
            {leagueName.toUpperCase()} PING PONG LEAGUE
          </div>
        </header>

        {/* rivalry */}
        <Rivalry rivalry={league.rivalry} />

        {/* marbs */}
        <Panel style={{ padding: "18px 20px", marginBottom: 16 }} edge={league.marbs ? C.gold : null}>
          <div style={{ display: "flex", alignItems: "center", gap: 16, flexWrap: "wrap" }}>
            <div style={{ fontSize: 26 }}>🔮</div>
            <div style={{ flex: 1, minWidth: 220 }}>
              <Label color={C.gold}>MARBS HOLDER</Label>
              <div style={{ fontFamily: pixel, fontSize: 15, color: C.gold, textShadow: glow(C.gold), lineHeight: 1.5 }}>
                {league.marbs ? league.marbs.toUpperCase() : "UNCLAIMED"}
              </div>
              <div style={{ fontSize: 12.5, color: C.dim, marginTop: 10 }}>
                {league.marbs
                  ? `Holds them until someone beats them — and names the league ${leagueName} in the meantime.`
                  : "The winner of the first recorded match claims the marbs, and the naming rights."}
              </div>
            </div>
          </div>
        </Panel>

        {/* record a match */}
        <Panel style={{ padding: 20, marginBottom: 16 }}>
          <Label>RECORD A MATCH</Label>
          <div
            className="form"
            style={{
              display: "grid",
              gridTemplateColumns: "1fr 42px 1fr 118px",
              gridTemplateRows: "42px 42px",
              columnGap: 10,
              rowGap: 10,
            }}
          >
            <select style={{ ...inputStyle, gridColumn: 1, gridRow: 1 }} value={pA} onChange={(e) => setPA(e.target.value)}>
              {state.players.map((p) => <option key={p} value={p}>{p}</option>)}
            </select>
            <select style={{ ...inputStyle, gridColumn: 3, gridRow: 1 }} value={pB} onChange={(e) => setPB(e.target.value)}>
              {state.players.map((p) => <option key={p} value={p}>{p}</option>)}
            </select>

            <input
              style={{ ...inputStyle, gridColumn: 1, gridRow: 2 }}
              placeholder="Score"
              inputMode="numeric"
              value={sA}
              onChange={(e) => setSA(e.target.value)}
              onKeyDown={(e) => e.key === "Enter" && logMatch()}
            />
            <div
              style={{
                gridColumn: 2,
                gridRow: 2,
                fontFamily: pixel,
                fontSize: 11,
                color: C.magenta,
                textShadow: glow(C.magenta),
                display: "flex",
                alignItems: "center",
                justifyContent: "center",
              }}
            >
              VS
            </div>
            <input
              style={{ ...inputStyle, gridColumn: 3, gridRow: 2 }}
              placeholder="Score"
              inputMode="numeric"
              value={sB}
              onChange={(e) => setSB(e.target.value)}
              onKeyDown={(e) => e.key === "Enter" && logMatch()}
            />
            <button
              onClick={logMatch}
              style={{
                gridColumn: 4,
                gridRow: 2,
                height: 42,
                fontFamily: pixel,
                fontSize: 10,
                background: "transparent",
                color: C.cyan,
                border: `2px solid ${C.cyan}`,
                boxShadow: `0 0 14px ${C.cyan}44, inset 0 0 14px ${C.cyan}22`,
                cursor: "pointer",
                borderRadius: 3,
                letterSpacing: 1,
                boxSizing: "border-box",
              }}
            >
              LOG IT
            </button>
          </div>
          {err && <div style={{ color: C.red, fontSize: 13, marginTop: 12 }}>{err}</div>}
          {status && <div style={{ color: C.faint, fontSize: 12, marginTop: 12 }}>{status}</div>}
        </Panel>

        {/* standings */}
        <Panel style={{ padding: 20, marginBottom: 16 }}>
          <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline" }}>
            <Label>STANDINGS</Label>
            <div style={{ fontSize: 10, letterSpacing: 1.6, color: C.faint }}>ELO · K={K_FACTOR}</div>
          </div>
          <div style={{ overflowX: "auto" }}>
            <table style={{ width: "100%", borderCollapse: "collapse", minWidth: 560 }}>
              <thead>
                <tr style={{ fontSize: 10, letterSpacing: 1.4, color: C.faint, textAlign: "right" }}>
                  <th style={{ textAlign: "left", padding: "0 0 12px", width: 40 }}>#</th>
                  <th style={{ textAlign: "left", padding: "0 0 12px" }}>PLAYER</th>
                  <th style={{ padding: "0 0 12px" }}>ELO</th>
                  <th style={{ padding: "0 0 12px" }}>W-L</th>
                  <th style={{ padding: "0 0 12px" }}>WIN %</th>
                  <th style={{ padding: "0 0 12px" }}>DIFF</th>
                  <th style={{ padding: "0 0 12px" }}>STREAK</th>
                </tr>
              </thead>
              <tbody>
                {league.standings.map((s, i) => {
                  const hc = HOUSE_COLOR[s.house] || C.faint;
                  return (
                    <tr key={s.name} className="row" style={{ borderTop: `1px solid ${C.line}`, fontSize: 14 }}>
                      <td style={{ padding: "13px 0", fontFamily: pixel, fontSize: 9, color: i === 0 ? C.gold : C.faint }}>
                        {i + 1}
                      </td>
                      <td style={{ padding: "13px 0", fontWeight: 500 }}>
                        <span style={{ display: "inline-block", width: 3, height: 15, background: hc, boxShadow: `0 0 8px ${hc}`, marginRight: 10, verticalAlign: -3 }} />
                        {s.name}
                        {league.marbs === s.name && " 🔮"}
                      </td>
                      <td style={{ padding: "13px 0", textAlign: "right", fontFamily: pixel, fontSize: 11, color: C.cyan, textShadow: glow(C.cyan) }}>
                        {s.elo}
                      </td>
                      <td style={{ padding: "13px 0", textAlign: "right" }}>{s.w}-{s.l}</td>
                      <td style={{ padding: "13px 0", textAlign: "right" }}>{s.pct}%</td>
                      <td style={{ padding: "13px 0", textAlign: "right", color: s.diff > 0 ? C.green : s.diff < 0 ? C.red : C.text }}>
                        {s.diff > 0 ? `+${s.diff}` : s.diff}
                      </td>
                      <td style={{ padding: "13px 0", textAlign: "right", color: s.last === "W" ? C.green : s.last === "L" ? C.red : C.faint }}>
                        {s.streak}
                      </td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          </div>
        </Panel>

        {/* h2h + recent */}
        <div className="split" style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 16 }}>
          <Panel style={{ padding: 20 }}>
            <Label>HEAD TO HEAD</Label>
            <div style={{ overflowX: "auto" }}>
              <table style={{ borderCollapse: "collapse", fontSize: 12.5, width: "100%" }}>
                <thead>
                  <tr style={{ color: C.faint, fontSize: 10 }}>
                    <th style={{ textAlign: "left", padding: "0 8px 8px 0" }}>VS</th>
                    {state.players.map((n) => (
                      <th key={n} style={{ padding: "0 5px 8px", fontWeight: 400, color: HOUSE_COLOR[teams[n]] || C.faint }}>
                        {firstName(n)}
                      </th>
                    ))}
                  </tr>
                </thead>
                <tbody>
                  {state.players.map((a) => (
                    <tr key={a} style={{ borderTop: `1px solid ${C.line}` }}>
                      <td style={{ padding: "9px 8px 9px 0", whiteSpace: "nowrap", color: HOUSE_COLOR[teams[a]] || C.text }}>
                        {firstName(a)}
                      </td>
                      {state.players.map((b) => (
                        <td key={b} style={{ padding: "9px 5px", textAlign: "center", color: a === b ? C.faint : C.text }}>
                          {a === b ? "·" : `${league.h2h[a][b].w}-${league.h2h[a][b].l}`}
                        </td>
                      ))}
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          </Panel>

          <Panel style={{ padding: 20 }}>
            <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline" }}>
              <Label>RECENT MATCHES</Label>
              {state.matches.length > 0 && (
                <div style={{ fontSize: 10, color: C.faint, letterSpacing: 1.4 }}>{state.matches.length} PLAYED</div>
              )}
            </div>
            {recent.length === 0 ? (
              <div style={{ fontSize: 13, color: C.dim }}>No games yet. Log the first match to start the season.</div>
            ) : (
              recent.map((m, i) => (
                <div
                  key={m.id}
                  style={{
                    display: "flex",
                    justifyContent: "space-between",
                    alignItems: "center",
                    gap: 10,
                    padding: "10px 0",
                    borderTop: i === 0 ? "none" : `1px solid ${C.line}`,
                    fontSize: 13.5,
                  }}
                >
                  <div>
                    <span style={{ color: HOUSE_COLOR[teams[m.winner]] || C.text, fontWeight: 600 }}>{firstName(m.winner)}</span>
                    <span style={{ color: C.faint }}> def. </span>
                    <span style={{ color: HOUSE_COLOR[teams[m.loser]] || C.text }}>{firstName(m.loser)}</span>
                    <span style={{ color: C.dim }}> {m.ws}–{m.ls}</span>
                    {m.crossHouse && <span title="Counted in the house rivalry" style={{ color: C.gold }}> ★</span>}
                  </div>
                  <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
                    <span style={{ color: C.green, fontFamily: pixel, fontSize: 9 }}>+{m.delta}</span>
                    {i === 0 && (
                      <button
                        onClick={() => send("/api/undo")}
                        style={{ background: "transparent", border: `1px solid ${C.line}`, color: C.dim, borderRadius: 3, fontSize: 11, padding: "3px 8px", cursor: "pointer" }}
                      >
                        Undo
                      </button>
                    )}
                  </div>
                </div>
              ))
            )}
          </Panel>
        </div>

        {/* settings */}
        <div style={{ marginTop: 20 }}>
          <button
            onClick={() => setSettingsOpen((v) => !v)}
            style={{ background: "transparent", border: `1px solid ${C.line}`, color: C.dim, borderRadius: 3, fontSize: 12.5, padding: "8px 14px", cursor: "pointer", fontFamily: body }}
          >
            {settingsOpen ? "Hide league settings" : "League settings"}
          </button>

          {settingsOpen && (
            <Panel style={{ padding: 20, marginTop: 12 }}>
              <div className="split" style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 24 }}>
                <div>
                  <Label>PLAYERS &amp; HOUSES</Label>
                  <div style={{ fontSize: 12, color: C.faint, marginBottom: 12 }}>
                    Only matches between the two houses count toward the rivalry.
                  </div>
                  {state.players.map((p) => {
                    const locked = state.matches.some((m) => m.winner === p || m.loser === p);
                    return (
                      <div key={p} style={{ display: "flex", alignItems: "center", gap: 8, padding: "5px 0", fontSize: 13.5 }}>
                        <span style={{ flex: 1 }}>{p}</span>
                        <select
                          value={teams[p] || ""}
                          onChange={(e) => saveRoster(state.players, { ...teams, [p]: e.target.value })}
                          style={{ ...inputStyle, width: "auto", padding: "4px 6px", fontSize: 12, color: HOUSE_COLOR[teams[p]] || C.dim }}
                        >
                          <option value="">no house</option>
                          {HOUSES.map((h) => <option key={h} value={h}>{h}</option>)}
                        </select>
                        <button
                          onClick={() => !locked && saveRoster(state.players.filter((x) => x !== p), teams)}
                          disabled={locked}
                          style={{ background: "transparent", border: "none", color: locked ? C.faint : C.red, cursor: locked ? "default" : "pointer", fontSize: 11.5, fontFamily: body }}
                        >
                          {locked ? "in play" : "remove"}
                        </button>
                      </div>
                    );
                  })}
                  <div style={{ display: "flex", gap: 8, marginTop: 12 }}>
                    <input style={inputStyle} placeholder="Add a player" value={newPlayer} onChange={(e) => setNewPlayer(e.target.value)} onKeyDown={(e) => e.key === "Enter" && addPlayer()} />
                    <button onClick={addPlayer} style={{ background: "rgba(255,255,255,.06)", border: `1px solid ${C.line}`, color: C.text, borderRadius: 3, padding: "0 14px", cursor: "pointer", fontSize: 13, fontFamily: body }}>
                      Add
                    </button>
                  </div>
                </div>

                <div>
                  <Label>END THE SEASON</Label>
                  <div style={{ fontSize: 12.5, color: C.dim, marginBottom: 14 }}>
                    Clears every match, resets all ratings to {BASE_ELO}, and frees the marbs.
                  </div>
                  <button
                    onClick={() => send("/api/reset")}
                    style={{ background: "transparent", border: `1px solid ${C.red}66`, color: C.red, borderRadius: 3, padding: "9px 14px", cursor: "pointer", fontSize: 13, fontFamily: body }}
                  >
                    Start Season {state.season + 1}
                  </button>
                </div>
              </div>
            </Panel>
          )}
        </div>

        <div style={{ textAlign: "center", color: C.faint, fontSize: 11.5, marginTop: 30, lineHeight: 1.8 }}>
          Everyone starts at {BASE_ELO}. Beat someone rated higher and you take more from them.
          <br />
          ★ marks a cross-house match. The board refreshes every 10 seconds.
        </div>
      </div>
    </div>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<LPPL />);
