/* ============================================================
   Weekend Games — a scorecard for EVERY tee-time group, using
   the manager's selected game for that day. The Group Tees at
   the top drive every card. Scores are shared with the group
   (synced + live), blank until game day, dots = strokes vs the
   group's low handicap (the low player has none).
   ============================================================ */
const STAKE_LABEL = { skins: "Skin value", stableford: "Ante (each)", nassau: "Bet / match", "split-sixes": "Point value" };

function GamesScreen({ ctx }) {
  const Y = window.YCC;
  const G = window.YCC_GAMES;
  const ENG = window.YCC_SCORING;
  const { tour, member, gameConfig, setGameConfig, role, scores, setScore, sideResults, setSideResult } = ctx;
  const isManager = role === "manager";
  const { skinValue, carryover, scoring, groupTee } = gameConfig;
  const setCfg = (patch) => setGameConfig({ ...gameConfig, ...patch });
  const [rulesOpen, setRulesOpen] = useState(null);
  const todayISO = Y.isoDay(Y.TODAY);

  const dayMeta = [
    { iso: tour.satISO, label: "Saturday" },
    { iso: tour.sunISO, label: "Sunday" },
  ];
  const groups = [];
  dayMeta.forEach((d) => {
    Y.sortByTime(tour.slots[d.iso] || []).forEach((s) => {
      if (s.players && s.players.length > 0)
        groups.push({ dayISO: d.iso, dayLabel: d.label, slotId: s.id, time: s.time, slot: s });
    });
  });

  const idsInPlay = Array.from(new Set(groups.map((g) => ENG.whichGame(gameConfig, g.dayISO, tour.satISO))));
  const anySkins = idsInPlay.includes("skins");
  const stakeLabel = idsInPlay.length === 1 ? (STAKE_LABEL[idsInPlay[0]] || "Stake") : "Stake";
  const satGame = G.gameById(ENG.whichGame(gameConfig, tour.satISO, tour.satISO));
  const sunGame = G.gameById(ENG.whichGame(gameConfig, tour.sunISO, tour.satISO));

  // daily field low handicap (lowest course handicap among everyone signed up that day)
  const hiN = (h) => { const n = typeof h === "number" ? h : parseFloat(h); return isFinite(n) ? n : null; };
  const dayLow = {};
  dayMeta.forEach((d) => {
    const chs = [];
    (tour.slots[d.iso] || []).forEach((s) => s.players.forEach((p) => { const n = hiN(p.hi); if (n != null) chs.push(Y.courseHandicapForTee(n, groupTee)); }));
    dayLow[d.iso] = chs.length ? Math.min(...chs) : null;
  });
  const lowMode = gameConfig.lowMode || "day";

  // ===== EMPTY STATE — no groups have players yet =====
  if (groups.length === 0) {
    const sameGame = satGame.id === sunGame.id;
    return (
      <div className="page fade-in">
        <div className="page-head">
          <div className="eyebrow">Weekend Games</div>
          <h1 style={{ marginTop: 6 }}>Weekend Games</h1>
          <p>{sameGame ? <>This weekend the DIV Tour is playing <strong>{satGame.name}</strong>.</> : <>Saturday is <strong>{satGame.name}</strong>, Sunday is <strong>{sunGame.name}</strong>.</>} A scorecard opens for each tee-time group, on game day. Tap any game below to read its rules.</p>
        </div>
        <div className="grid" style={{ gridTemplateColumns: sameGame ? "1fr" : "1fr 1fr", marginBottom: 22, gap: "var(--gap)" }}>
          {(sameGame ? [["This weekend", satGame]] : [["Saturday", satGame], ["Sunday", sunGame]]).map(([label, gm]) => (
            <div key={label} className="card" style={{ overflow: "hidden", border: "1px solid var(--accent)" }}>
              <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 14, padding: "16px var(--card-pad)", background: "var(--brand)", color: "var(--on-brand)", flexWrap: "wrap" }}>
                <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
                  <Icon name="trophy" size={20} style={{ color: "var(--accent)" }} />
                  <div>
                    <div style={{ fontSize: 11.5, fontWeight: 700, letterSpacing: ".06em", textTransform: "uppercase", color: "rgba(244,241,230,.7)" }}>{label}'s game</div>
                    <div className="serif" style={{ fontSize: 24, fontWeight: 700, lineHeight: 1.1 }}>{gm.name}</div>
                  </div>
                </div>
                <button className="btn btn-accent btn-sm" onClick={() => setRulesOpen(gm)}><Icon name="info" size={14} /> Rules</button>
              </div>
              <div className="card-pad" style={{ paddingTop: 16, paddingBottom: 16 }}>
                <p style={{ fontSize: 14.5, lineHeight: 1.5, margin: 0 }}>{gm.blurb}</p>
              </div>
            </div>
          ))}
        </div>
        <div className="eyebrow" style={{ marginBottom: 12 }}>All game formats</div>
        <G.GameRulesGrid activeId={satGame.id} />
        {rulesOpen && <G.GameRulesModal game={rulesOpen} onClose={() => setRulesOpen(null)} />}
      </div>
    );
  }

  return (
    <div className="page fade-in">
      <div className="page-head" style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-end", flexWrap: "wrap", gap: 16 }}>
        <div>
          <div className="eyebrow">Weekend Games</div>
          <h1 style={{ marginTop: 6 }}>Group scorecards</h1>
          <p>{satGame.id === sunGame.id ? <>Playing <strong>{satGame.name}</strong> both days.</> : <>Saturday: <strong>{satGame.name}</strong> · Sunday: <strong>{sunGame.name}</strong>.</>} Each tee-time group has its own card below — scores are shared live with everyone in the group on game day.</p>
        </div>
      </div>

      {/* global controls (manager) — Group Tees drive every card */}
      {/* Game controls (skin value, scoring, group tees, carryover) now live in
          Manager → Tour Setup → Weekend Games. They still drive every card here. */}

      <div className="stack" style={{ gap: 26 }}>
        {groups.map((g) => (
          <GroupScorecard key={g.dayISO + "|" + g.slotId} group={g} gameConfig={gameConfig}
            scoring={scoring} carryover={carryover} stake={skinValue} groupTee={groupTee}
            isManager={isManager} member={member} scores={scores} setScore={setScore}
            sideResults={sideResults} setSideResult={setSideResult}
            todayISO={todayISO} lowMode={lowMode} dayLowCH={dayLow[g.dayISO]}
            confirmedNames={ctx.confirmedNames} onRules={(gm) => setRulesOpen(gm)} />
        ))}
      </div>
      {rulesOpen && <G.GameRulesModal game={rulesOpen} onClose={() => setRulesOpen(null)} />}
    </div>
  );
}

/* -------- one tee-time group's standings + scorecard -------- */
function GroupScorecard({ group, gameConfig, scoring, carryover, stake, groupTee, isManager, member, scores, setScore, sideResults, setSideResult, todayISO, lowMode, dayLowCH, confirmedNames, onRules }) {
  const Y = window.YCC;
  const G = window.YCC_GAMES;
  const ENG = window.YCC_SCORING;
  const resolvedId = gameConfig.splitDays
    ? (group.dayLabel === "Saturday" ? (gameConfig.gameSat || "skins") : (gameConfig.gameSun || "skins"))
    : (gameConfig.gameType || "skins");
  const game = G.gameById(resolvedId);

  const players = group.slot.players.map((p) => ({
    name: p.name, initials: p.initials, hi: p.hi, ghin: p.ghin,
    transport: p.transport || "walk", self: p.name === member.name, guest: !!p.guest,
  }));

  const hiNum = (h) => { const n = typeof h === "number" ? h : parseFloat(h); return isFinite(n) ? n : null; };
  const cHcp = players.map((p) => { const n = hiNum(p.hi); return n == null ? null : Y.courseHandicapForTee(n, groupTee); });
  const cHcpCalc = cHcp.map((c) => (c == null ? 0 : c));
  const numericCH = cHcp.filter((c) => c != null);
  const groupLow = numericCH.length ? Math.min(...numericCH) : 0;
  const lowCH = (lowMode === "day" && dayLowCH != null) ? dayLowCH : groupLow;
  const lowIdx = cHcp.findIndex((c) => c != null && c === lowCH);

  const groupKey = group.dayISO + "|" + group.slotId;
  const groupScores = (scores && scores[groupKey]) || {};
  const grossOf = (name, hIdx) => { const a = groupScores[name]; const v = a && a[hIdx]; return (typeof v === "number" && isFinite(v)) ? v : null; };
  const locked = todayISO < group.dayISO;
  const inThisGroup = players.some((p) => p.self);
  const canEdit = !locked && (isManager || inThisGroup); // only players in the group (or a manager) enter scores
  const siOf = (pIdx, hIdx) => Y.siForTee(groupTee, hIdx);
  const dotsFor = (pIdx, hIdx) => (cHcp[pIdx] == null ? 0 : Y.strokesVsLow(cHcp[pIdx], lowCH, siOf(pIdx, hIdx)));

  // Add-on games for THIS day → column highlighting on the scorecard.
  // Closest-to-the-Pin holes get a gold tint; the Longest-Drive hole a green tint,
  // running the full column from the Yards row down through the last player.
  const sgDayKey = group.dayLabel === "Saturday" ? "sat" : "sun";
  const sgActive = G.activeSideGames(gameConfig, sgDayKey);
  const ctpSet = new Set(sgActive.includes("ctp") ? G.ctpHolesForDay(gameConfig, sgDayKey) : []);
  const ldNum = sgActive.includes("longDrive") ? G.longDriveHoleForDay(gameConfig, sgDayKey) : null;
  const HL = {
    ctp: { bg: "color-mix(in srgb, var(--accent) 17%, transparent)", bgDark: "color-mix(in srgb, var(--accent) 42%, transparent)", bar: "var(--accent)", label: "Closest to pin" },
    ld: { bg: "color-mix(in srgb, var(--ok) 18%, transparent)", bgDark: "color-mix(in srgb, var(--ok) 50%, transparent)", bar: "var(--ok)", label: "Longest drive" },
  };
  const holeKind = (hIdx) => { const n = hIdx + 1; if (ctpSet.has(n)) return "ctp"; if (ldNum === n) return "ld"; return null; };
  const colStyle = (hIdx, dark) => {
    const k = holeKind(hIdx); if (!k) return null;
    const c = HL[k];
    return dark
      ? { background: c.bgDark, boxShadow: "inset 0 -3px 0 " + c.bar }
      : { background: c.bg };
  };

  const scoresMatrix = players.map((p) => Y.HOLES.map((h, i) => grossOf(p.name, i)));
  const engine = ENG.computeGame(resolvedId, { players, scores: scoresMatrix, holes: Y.HOLES, cHcps: cHcpCalc, siOf, stake, scoring, carryover });
  const ranked = [...engine.standings].sort((a, b) => {
    if (engine.computable) return b.money - a.money;
    const av = a.lines[0] && typeof a.lines[0].value === "number" ? a.lines[0].value : 0;
    const bv = b.lines[0] && typeof b.lines[0].value === "number" ? b.lines[0].value : 0;
    return av - bv;
  });
  const anyScores = scoresMatrix.some((row) => row.some((v) => v != null));
  const showStandings = !locked && anyScores;
  const playDateLabel = Y.fmtDate(new Date(group.dayISO + "T00:00:00"));

  const front = Y.HOLES.slice(0, 9), back = Y.HOLES.slice(9, 18);
  const gTee = Y.teeByName(groupTee);
  const yOut = front.reduce((s, h, i) => s + Y.yardsForTee(groupTee, i), 0);
  const yIn = back.reduce((s, h, i) => s + Y.yardsForTee(groupTee, i + 9), 0);
  const pOut = front.reduce((s, h) => s + h.par, 0);
  const pIn = back.reduce((s, h) => s + h.par, 0);
  const SC = { hole: 40, stub: 150, edge: 50 };
  const cellTd = (extra) => ({ padding: "7px 0", textAlign: "center", width: SC.hole, ...extra });
  const edgeTd = (extra) => ({ padding: "7px 0", textAlign: "center", width: SC.edge, background: "var(--surface-2)", fontWeight: 700, ...extra });
  const stubTd = (extra) => ({ padding: "9px 14px", textAlign: "left", width: SC.stub, position: "sticky", left: 0, background: "var(--surface)", zIndex: 1, whiteSpace: "nowrap", ...extra });
  const sumRange = (name, from, to) => { let s = 0, any = false; for (let i = from; i < to; i++) { const v = grossOf(name, i); if (v != null) { s += v; any = true; } } return any ? s : ""; };

  function Dots({ n }) {
    if (!n) return null;
    return (
      <span style={{ position: "absolute", top: 3, left: 5, display: "flex", gap: 2, alignItems: "center", pointerEvents: "none" }}>
        {n <= 4
          ? Array.from({ length: n }).map((_, i) => <span key={i} style={{ width: 4, height: 4, borderRadius: "50%", background: "var(--accent-deep)" }}></span>)
          : <span style={{ fontSize: 8.5, fontWeight: 800, color: "var(--accent-deep)", lineHeight: 1 }}>{n}<span style={{ fontSize: 6 }}>●</span></span>}
      </span>
    );
  }
  function ScoreCell({ name, pIdx, h, hIdx }) {
    const raw = grossOf(name, hIdx);
    const won = engine.winnerByHole && engine.winnerByHole[hIdx] === pIdx;
    const toPar = raw == null ? 0 : raw - h.par;
    return (
      <td style={{ ...cellTd(), position: "relative", ...(colStyle(hIdx) || {}) }}>
        <Dots n={dotsFor(pIdx, hIdx)} />
        <span style={{
          display: "inline-grid", placeItems: "center", width: 28, height: 28, borderRadius: won ? "50%" : 7,
          background: won ? "var(--accent)" : "transparent",
          border: won ? "none" : raw != null && toPar <= -1 ? "1.5px solid var(--brand)" : "1px solid transparent",
        }}>
          <input value={raw == null ? "" : raw} inputMode="numeric" disabled={!canEdit} placeholder={canEdit ? "·" : ""}
            onFocusCapture={(e) => e.target.select()}
            onChange={(e) => {
              const d = e.target.value.replace(/[^0-9]/g, "").slice(0, 2);
              if (d === "") { setScore(group.dayISO, group.slotId, name, hIdx, null); return; }
              setScore(group.dayISO, group.slotId, name, hIdx, Math.max(1, Math.min(15, parseInt(d, 10))));
            }}
            style={{
              width: 26, height: 26, textAlign: "center", border: "none", background: "transparent", outline: "none",
              fontFamily: "var(--font-body)", fontSize: 13.5, fontWeight: won ? 800 : raw != null && toPar < 0 ? 700 : 500,
              color: won ? "#1b1404" : raw == null ? "var(--ink-faint)" : "var(--ink)", padding: 0, cursor: canEdit ? "text" : "default",
            }} />
        </span>
      </td>
    );
  }
  function PlayerRow({ p, pIdx }) {
    const fOut = sumRange(p.name, 0, 9), fIn = sumRange(p.name, 9, 18);
    const tot = (typeof fOut === "number" ? fOut : 0) + (typeof fIn === "number" ? fIn : 0);
    const isLow = pIdx === lowIdx;
    return (
      <tr style={{ borderTop: "1px solid var(--line)" }}>
        <td style={stubTd()}>
          <div style={{ display: "flex", alignItems: "center", gap: 9 }}>
            <Avatar initials={p.initials} size={26} tone={p.self ? "accent" : "brand"} />
            <div style={{ minWidth: 0 }}>
              <div style={{ display: "flex", alignItems: "center", gap: 6 }}>
                <span style={{ fontWeight: p.self ? 700 : 600, fontSize: 12.5, whiteSpace: "nowrap" }}>{p.self ? "You" : p.name}</span>
                {isLow && <span title={lowMode === "day" ? "Day's low handicap — the whole field plays off this player" : "Group's low handicap — this group plays off this player"} style={{ fontSize: 8.5, fontWeight: 800, letterSpacing: ".05em", color: "var(--brand)", background: "var(--brand-soft)", padding: "1px 5px", borderRadius: 4 }}>LOW</span>}
              </div>
              <div className="faint" style={{ fontSize: 10.5, marginTop: 1 }}>CH {cHcp[pIdx] == null ? "—" : cHcp[pIdx]}</div>
            </div>
          </div>
        </td>
        {Y.HOLES.map((h, hIdx) => {
          const cells = [<ScoreCell key={h.n} name={p.name} pIdx={pIdx} h={h} hIdx={hIdx} />];
          if (h.n === 9) cells.push(<td key="out" style={edgeTd()}>{fOut}</td>);
          if (h.n === 18) { cells.push(<td key="in" style={edgeTd()}>{fIn}</td>); cells.push(<td key="tot" style={edgeTd({ color: "var(--brand)", fontFamily: "var(--font-display)", fontSize: 16 })}>{tot || ""}</td>); }
          return cells;
        })}
      </tr>
    );
  }
  function MetaRow({ label, get, out, inn, tot, dark }) {
    return (
      <tr style={dark ? { background: "var(--brand-deep)", color: "var(--on-brand)" } : { background: "var(--surface-2)" }}>
        <td style={stubTd(dark ? { background: "var(--brand-deep)", color: "var(--on-brand)", fontWeight: 700, fontSize: 11, letterSpacing: ".06em", textTransform: "uppercase" } : { background: "var(--surface-2)", fontWeight: 700, fontSize: 11, letterSpacing: ".05em", textTransform: "uppercase", color: "var(--ink-soft)" })}>{label}</td>
        {Y.HOLES.map((h, hIdx) => {
          const cells = [<td key={h.n} style={cellTd(dark ? { fontWeight: 700, fontSize: 12.5, ...(colStyle(hIdx, true) || {}) } : { fontSize: 12, color: "var(--ink-soft)", ...(colStyle(hIdx) || {}) })}>{get(h, hIdx)}</td>];
          if (h.n === 9) cells.push(<td key="o" style={edgeTd(dark ? { color: "var(--accent)" } : {})}>{out}</td>);
          if (h.n === 18) { cells.push(<td key="i" style={edgeTd(dark ? { color: "var(--accent)" } : {})}>{inn}</td>); cells.push(<td key="t" style={edgeTd(dark ? { color: "var(--accent)" } : {})}>{tot}</td>); }
          return cells;
        })}
      </tr>
    );
  }

  return (
    <div>
      {/* group heading */}
      <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 14, marginBottom: 12, flexWrap: "wrap" }}>
        <div style={{ display: "flex", alignItems: "baseline", gap: 12, flexWrap: "wrap" }}>
          <span className="serif" style={{ fontSize: 24, fontWeight: 700 }}>{group.time}</span>
          <span className="faint" style={{ fontSize: 13, fontWeight: 600 }}>{group.dayLabel}</span>
          <span className="pill pill-accent" style={{ whiteSpace: "nowrap" }}><Icon name="trophy" size={11} /> {game.name}</span>
          {group.slot.players.some((p) => p.name === member.name) && <span className="pill" style={{ background: "color-mix(in srgb,var(--accent) 18%,transparent)", color: "var(--accent-deep)" }}>Your group</span>}
          {!locked && <button onClick={() => onRules(game)} style={{ background: "none", padding: 0, color: "var(--accent-deep)", fontWeight: 700, fontSize: 12.5 }}>Rules</button>}
        </div>
        {!locked ? (
          <span className="pill" style={{ background: "var(--brand-soft)", color: "var(--brand)", whiteSpace: "nowrap" }}>
            <span style={{ width: 7, height: 7, borderRadius: "50%", background: "var(--ok)", display: "inline-block" }}></span> Live · {canEdit ? "enter scores" : "view only"}
          </span>
        ) : (
          <span className="faint" style={{ fontSize: 12.5, fontWeight: 600 }}>{engine.summary}</span>
        )}
      </div>

      {/* lock banner */}
      {locked && (
        <div style={{ display: "flex", alignItems: "center", gap: 12, padding: "13px 16px", borderRadius: "var(--radius)", background: "color-mix(in srgb,var(--accent) 12%,var(--surface))", border: "1px solid var(--accent)", marginBottom: 14 }}>
          <Icon name="clock" size={18} style={{ color: "var(--accent-deep)", flex: "0 0 auto" }} />
          <div style={{ fontSize: 13, lineHeight: 1.5 }}><strong>Opens on game day — {playDateLabel}.</strong> Any player in this group can enter scores once play begins; everyone sees them live.</div>
        </div>
      )}

      {/* standings */}
      {showStandings && (
        <div className="grid" style={{ gridTemplateColumns: "repeat(auto-fit, minmax(200px, 1fr))", marginBottom: 14 }}>
          {ranked.map((st, rank) => {
            const p = players[st.idx];
            return (
              <div key={st.idx} className="card card-pad" style={{ padding: "16px 18px", border: rank === 0 ? "1px solid var(--accent)" : "1px solid var(--line)", background: rank === 0 ? "color-mix(in srgb, var(--accent) 9%, var(--surface))" : "var(--surface)" }}>
                <div style={{ display: "flex", alignItems: "center", gap: 11, marginBottom: 12 }}>
                  <Avatar initials={p.initials} size={34} tone={rank === 0 ? "accent" : "brand"} />
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div style={{ fontSize: 14, fontWeight: 700, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{p.self ? "You" : p.name}</div>
                    <div className="faint" style={{ fontSize: 11, whiteSpace: "nowrap", display: "flex", alignItems: "center", gap: 6 }}>CH {cHcp[st.idx] == null ? "—" : cHcp[st.idx]} <Transport mode={p.transport} /></div>
                  </div>
                  {rank === 0 && <span title="Leader" style={{ flex: "0 0 auto", width: 24, height: 24, borderRadius: "50%", background: "var(--accent)", color: "#1b1404", display: "grid", placeItems: "center" }}><Icon name="trophy" size={13} /></span>}
                </div>
                <div style={{ display: "flex", alignItems: "baseline", gap: 14, flexWrap: "wrap" }}>
                  {st.lines.map((ln, i) => (
                    <div key={i}><div className="serif" style={{ fontSize: typeof ln.value === "number" ? 28 : 17, fontWeight: 700, lineHeight: 1, color: "var(--brand)" }}>{ln.value}</div><div className="faint" style={{ fontSize: 10.5, marginTop: 3 }}>{ln.label}</div></div>
                  ))}
                  {engine.computable && <div><div className="serif" style={{ fontSize: 28, fontWeight: 700, lineHeight: 1, color: "var(--accent-deep)" }}>${st.money}</div><div className="faint" style={{ fontSize: 10.5, marginTop: 3 }}>won</div></div>}
                </div>
              </div>
            );
          })}
        </div>
      )}

      {/* scorecard */}
      <div className="card" style={{ overflow: "hidden" }}>
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", gap: 14, padding: "16px var(--card-pad)", background: "var(--brand-deep)", color: "var(--on-brand)", flexWrap: "wrap" }}>
          <div style={{ display: "flex", alignItems: "center", gap: 13 }}>
            <div className="crest" style={{ borderColor: "var(--accent)", color: "var(--accent)" }}>YCC</div>
            <div>
              <div className="serif" style={{ fontSize: 21, fontWeight: 700, lineHeight: 1.05 }}>Yardley Country Club</div>
              <div style={{ fontSize: 11.5, letterSpacing: ".04em", color: "rgba(244,241,230,.7)", marginTop: 2 }}>
                {group.dayLabel.toUpperCase()} · {group.time} · {game.name.toUpperCase()} · <strong style={{ color: "var(--accent)", fontWeight: 800, letterSpacing: ".06em" }}>{groupTee.toUpperCase()} TEES</strong>
              </div>
            </div>
          </div>
          <div style={{ display: "flex", gap: 22, fontSize: 12.5 }}>
            {[[gTee.total.toLocaleString(), "Yards"], [gTee.rating.toFixed(1), "Rating"], [String(gTee.slope), "Slope"], ["72", "Par"]].map(([v, l]) => (
              <div key={l} style={{ textAlign: "center" }}>
                <div className="serif" style={{ fontSize: 19, fontWeight: 700, color: "var(--accent)" }}>{v}</div>
                <div style={{ fontSize: 10, letterSpacing: ".08em", textTransform: "uppercase", color: "rgba(244,241,230,.6)" }}>{l}</div>
              </div>
            ))}
          </div>
        </div>

        <div className="scroll-x">
          <table style={{ borderCollapse: "collapse", width: "100%", minWidth: 900, fontSize: 13 }}>
            <thead><MetaRow dark label="Hole" get={(h) => h.n} out="Out" inn="In" tot="Tot" /></thead>
            <tbody>
              <MetaRow label="Yards" get={(h, i) => Y.yardsForTee(groupTee, i)} out={yOut} inn={yIn} tot={gTee.total} />
              <MetaRow label="Par" get={(h) => h.par} out={pOut} inn={pIn} tot={pOut + pIn} />
              <MetaRow label="Hcp" get={(h, i) => Y.siForTee(groupTee, i)} out="" inn="" tot="" />
              {players.map((p, pIdx) => <PlayerRow key={p.name} p={p} pIdx={pIdx} />)}
              {engine.perHole && !locked && (
                <tr style={{ borderTop: "2px solid var(--line-strong)", background: "var(--surface-2)" }}>
                  <td style={stubTd({ background: "var(--surface-2)", fontWeight: 700, fontSize: 11, letterSpacing: ".05em", textTransform: "uppercase", color: "var(--ink-soft)" })}>{engine.perHole.label}</td>
                  {Y.HOLES.map((h, hIdx) => {
                    const c = engine.perHole.cells[hIdx];
                    const cells = [<td key={h.n} style={cellTd(colStyle(hIdx) || {})}>{typeof c === "string" && c.startsWith("$") ? <span style={{ fontWeight: 700, color: "var(--accent-deep)", fontSize: 11.5 }}>{c}</span> : <span className="faint" style={{ fontSize: 11 }}>{c}</span>}</td>];
                    if (h.n === 9) cells.push(<td key="o" style={edgeTd()}></td>);
                    if (h.n === 18) { cells.push(<td key="i" style={edgeTd()}></td>); cells.push(<td key="t" style={edgeTd()}></td>); }
                    return cells;
                  })}
                </tr>
              )}
            </tbody>
          </table>
        </div>

        <div style={{ padding: "13px var(--card-pad)", borderTop: "1px solid var(--line)", display: "flex", gap: 22, flexWrap: "wrap", fontSize: 12, color: "var(--ink-soft)", alignItems: "center" }}>
          <span style={{ display: "flex", alignItems: "center", gap: 7 }}><span style={{ display: "flex", gap: 2 }}><span style={{ width: 4, height: 4, borderRadius: "50%", background: "var(--accent-deep)" }}></span><span style={{ width: 4, height: 4, borderRadius: "50%", background: "var(--accent-deep)" }}></span></span> Strokes vs {lowMode === "day" ? "the day's low" : "the group's low"}</span>
          {engine.winnerByHole && <span style={{ display: "flex", alignItems: "center", gap: 7 }}><span style={{ width: 18, height: 18, borderRadius: "50%", background: "var(--accent)" }}></span> Skin won</span>}
          <span style={{ display: "flex", alignItems: "center", gap: 7 }}><span style={{ width: 18, height: 18, borderRadius: 6, border: "1.5px solid var(--brand)" }}></span> Birdie or better</span>
          {ctpSet.size > 0 && <span style={{ display: "flex", alignItems: "center", gap: 7 }}><span style={{ width: 18, height: 18, borderRadius: 5, background: HL.ctp.bg, boxShadow: "inset 0 -3px 0 " + HL.ctp.bar }}></span> Closest to the pin {ctpSet.size < 4 ? "(" + [...ctpSet].sort((a, b) => a - b).map((n) => "#" + n).join(" ") + ")" : ""}</span>}
          {ldNum && <span style={{ display: "flex", alignItems: "center", gap: 7 }}><span style={{ width: 18, height: 18, borderRadius: 5, background: HL.ld.bg, boxShadow: "inset 0 -3px 0 " + HL.ld.bar }}></span> Longest drive (#{ldNum})</span>}
          {canEdit && <span>Tap any score to edit</span>}
          {!locked && !canEdit && <span style={{ color: "var(--accent-deep)", fontWeight: 600 }}><Icon name="shield" size={11} style={{ verticalAlign: "-1px" }} /> Read-only — only players in this group enter scores</span>}
          {!engine.computable && !locked && <span style={{ color: "var(--accent-deep)", fontWeight: 600 }}>Winner settled by your group</span>}
        </div>
      </div>

      {/* Daily add-on games — Closest to the Pin / Longest Drive winners */}
      {(() => {
        const dayKey = group.dayLabel === "Saturday" ? "sat" : "sun";
        const activeIds = G.activeSideGames(gameConfig, dayKey);
        if (!activeIds.length) return null;
        const sideRes = (sideResults && sideResults[groupKey]) || {};
        const ctpOn = activeIds.includes("ctp");
        const ldOn = activeIds.includes("longDrive");
        const ctpHoleNums = G.ctpHolesForDay(gameConfig, dayKey);
        const par3s = Y.HOLES.filter((h) => h.par === 3 && ctpHoleNums.includes(h.n));
        const ldHole = Y.HOLES.find((h) => h.n === G.longDriveHoleForDay(gameConfig, dayKey)) || Y.HOLES[0];

        const Chip = ({ name, initials, self, won, onClick }) => (
          <button disabled={!canEdit} onClick={onClick} title={won ? "Winner — tap to clear" : (canEdit ? "Mark as winner" : "")}
            style={{
              display: "inline-flex", alignItems: "center", gap: 7, padding: "5px 12px 5px 5px", borderRadius: 999,
              border: "1.5px solid " + (won ? "var(--accent)" : "var(--line-strong)"),
              background: won ? "var(--accent)" : "var(--surface)", color: won ? "#1b1404" : "var(--ink)",
              cursor: canEdit ? "pointer" : "default", transition: "all .12s", opacity: (canEdit || won) ? 1 : .8,
            }}>
            <Avatar initials={initials} size={22} tone={won ? "accent" : "brand"} />
            <span style={{ fontSize: 12.5, fontWeight: won ? 800 : 600, whiteSpace: "nowrap" }}>{self ? "You" : name.split(" ")[0]}</span>
            {won && <Icon name="check" size={13} />}
          </button>
        );

        const pins = {};
        if (ctpOn) par3s.forEach((h) => { const w = (sideRes.ctp || {})[h.n - 1]; if (w) pins[w] = (pins[w] || 0) + 1; });
        const pinLeaders = Object.entries(pins).sort((a, b) => b[1] - a[1]);

        const Row = ({ hLabel, sub, winner, onPick }) => (
          <div style={{ display: "flex", alignItems: "center", gap: 14, flexWrap: "wrap", padding: "10px 0", borderTop: "1px solid var(--line)" }}>
            <div style={{ minWidth: 116 }}>
              <div style={{ fontWeight: 700, fontSize: 13.5, fontFamily: "var(--font-display)" }}>{hLabel}</div>
              <div className="faint" style={{ fontSize: 11 }}>{sub}</div>
            </div>
            <div style={{ display: "flex", gap: 8, flexWrap: "wrap", flex: 1, alignItems: "center" }}>
              {players.map((p) => (
                <Chip key={p.name} name={p.name} initials={p.initials} self={p.self} won={winner === p.name} onClick={() => onPick(winner === p.name ? null : p.name)} />
              ))}
              {winner == null && <span className="faint" style={{ fontSize: 11.5, marginLeft: 2 }}>{canEdit ? "Tap the winner" : "Not marked yet"}</span>}
            </div>
          </div>
        );

        return (
          <div className="card" style={{ overflow: "hidden", marginTop: 14 }}>
            <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 12, padding: "13px var(--card-pad)", borderBottom: "1px solid var(--line)", background: "var(--surface-2)", flexWrap: "wrap" }}>
              <span style={{ display: "flex", alignItems: "center", gap: 9 }}>
                <Icon name="pin" size={16} style={{ color: "var(--accent-deep)" }} />
                <span className="eyebrow">Add-on games · {group.dayLabel}</span>
              </span>
              {!canEdit && !locked && <span className="faint" style={{ fontSize: 11.5 }}>Players in this group mark winners</span>}
              {canEdit && <span className="faint" style={{ fontSize: 11.5 }}>Tap a player to mark a winner</span>}
            </div>
            <div className="card-pad" style={{ paddingTop: 6, paddingBottom: 16 }}>
              {ctpOn && par3s.length > 0 && (
                <div style={{ marginBottom: ldOn ? 20 : 0 }}>
                  <div style={{ display: "flex", alignItems: "baseline", justifyContent: "space-between", gap: 12, flexWrap: "wrap", padding: "10px 0 2px" }}>
                    <div>
                      <div className="serif" style={{ fontSize: 18, fontWeight: 700 }}>Closest to the Pin</div>
                      <div className="muted" style={{ fontSize: 12.5 }}>Nearest tee shot on each par 3 wins the hole.</div>
                    </div>
                    {pinLeaders.length > 0 && (
                      <div style={{ display: "flex", gap: 8, flexWrap: "wrap" }}>
                        {pinLeaders.map(([n, c]) => (
                          <span key={n} className="pill pill-accent" style={{ whiteSpace: "nowrap" }}><Icon name="pin" size={11} /> {n === member.name ? "You" : n.split(" ")[0]} · {c} pin{c > 1 ? "s" : ""}</span>
                        ))}
                      </div>
                    )}
                  </div>
                  {par3s.map((h) => {
                    const hIdx = h.n - 1;
                    return <Row key={h.n} hLabel={"Hole " + h.n} sub={"Par 3 · " + Y.yardsForTee(groupTee, hIdx) + " yds"} winner={(sideRes.ctp || {})[hIdx]} onPick={(name) => setSideResult(group.dayISO, group.slotId, "ctp", hIdx, name)} />;
                  })}
                </div>
              )}
              {ldOn && (
                <div>
                  <div style={{ padding: "10px 0 2px" }}>
                    <div className="serif" style={{ fontSize: 18, fontWeight: 700 }}>Longest Drive</div>
                    <div className="muted" style={{ fontSize: 12.5 }}>Longest drive in the fairway on the designated hole.</div>
                  </div>
                  <Row hLabel={"Hole " + ldHole.n} sub={"Par " + ldHole.par + " · " + Y.yardsForTee(groupTee, ldHole.n - 1) + " yds"} winner={sideRes.longDrive} onPick={(name) => setSideResult(group.dayISO, group.slotId, "longDrive", null, name)} />
                </div>
              )}
            </div>
          </div>
        );
      })()}
    </div>
  );
}

function TeeSelect({ value, onChange }) {
  const dot = { Blue: "#2f5db0", White: "#c7c8b3", Green: "#3a7a4f", Gold: "#b08d4f", Red: "#9e3b2f" };
  return (
    <span style={{ display: "inline-flex", alignItems: "center", gap: 7, padding: "3px 4px 3px 10px", borderRadius: 8, border: "1px solid var(--line-strong)", background: "var(--surface)" }}>
      <span style={{ width: 11, height: 11, borderRadius: "50%", background: dot[value] || "var(--brand)", border: "1px solid rgba(0,0,0,.15)" }}></span>
      <select value={value} onChange={(e) => onChange(e.target.value)} style={{ border: "none", background: "transparent", fontFamily: "var(--font-body)", fontSize: 12.5, fontWeight: 600, color: "var(--ink)", padding: "3px 4px", cursor: "pointer" }}>
        {["Blue", "White", "Green", "Gold", "Red"].map((t) => <option key={t} value={t}>{t} tees</option>)}
      </select>
    </span>
  );
}

function Seg({ label, value, onChange, options }) {
  return (
    <div style={{ display: "flex", alignItems: "center", gap: 11 }}>
      <span className="eyebrow">{label}</span>
      <div style={{ display: "inline-flex", background: "var(--surface-2)", borderRadius: 9, padding: 3, border: "1px solid var(--line)" }}>
        {options.map(([val, lab]) => (
          <button key={val} onClick={() => onChange(val)} style={{
            padding: "6px 13px", borderRadius: 7, fontSize: 12.5, fontWeight: 600, transition: "all .15s",
            background: value === val ? "var(--surface)" : "transparent", color: value === val ? "var(--brand)" : "var(--ink-soft)",
            boxShadow: value === val ? "var(--shadow-sm)" : "none",
          }}>{lab}</button>
        ))}
      </div>
    </div>
  );
}

Object.assign(window, { GamesScreen, GroupScorecard, TeeSelect, Seg });
