// Type-aware editor for correcting normalized finished-game entries.
// The server remains authoritative for validation, totals, winners, and auditing.

const FINISHED_GAME_EDITOR_CSS = `
  .fgc-overlay {
    position: fixed; inset: 0; z-index: 1200; display: grid; place-items: center;
    padding: 24px; background: rgba(5, 3, 18, .82); backdrop-filter: blur(12px);
  }
  .fgc-dialog {
    width: min(1120px, 100%); max-height: min(900px, calc(100vh - 48px)); overflow: auto;
    background: linear-gradient(155deg, #211850 0%, #120a30 72%);
    color: var(--ink); border: 3px solid var(--border); border-radius: 26px;
    box-shadow: 12px 12px 0 #05030d; overscroll-behavior: contain;
  }
  .fgc-header {
    position: sticky; top: 0; z-index: 4; display: flex; justify-content: space-between;
    gap: 20px; align-items: flex-start; padding: 22px 24px 20px;
    background: rgba(18, 10, 48, .95); border-bottom: 2px solid var(--border);
    backdrop-filter: blur(14px);
  }
  .fgc-title { margin: 4px 0 0; font: 800 clamp(28px, 5vw, 46px)/.95 'Space Grotesk', sans-serif; letter-spacing: -.035em; }
  .fgc-eyebrow { font: 800 11px/1.2 'DM Sans', sans-serif; letter-spacing: .18em; text-transform: uppercase; }
  .fgc-close, .fgc-icon-button {
    min-width: 44px; min-height: 44px; border: 2px solid var(--border); border-radius: 13px;
    background: rgba(255,255,255,.06); color: var(--ink); cursor: pointer;
    font: 800 15px/1 'Space Grotesk', sans-serif;
  }
  .fgc-close { font-size: 22px; flex: 0 0 44px; }
  .fgc-body { display: grid; grid-template-columns: minmax(0, 1.65fr) minmax(280px, .75fr); gap: 22px; padding: 24px; }
  .fgc-entry-list { display: grid; gap: 14px; }
  .fgc-entry-card {
    background: rgba(255,255,255,.045); border: 2px solid rgba(255,255,255,.17);
    border-radius: 18px; padding: 16px;
  }
  .fgc-entry-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 14px; }
  .fgc-entry-name { font: 800 17px/1.1 'Space Grotesk', sans-serif; }
  .fgc-entry-actions { display: flex; gap: 7px; }
  .fgc-entry-actions .fgc-icon-button { min-width: 40px; min-height: 40px; font-size: 14px; }
  .fgc-fields { display: grid; gap: 12px; }
  .fgc-field-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
  .fgc-player-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px; }
  .fgc-field { display: grid; gap: 7px; min-width: 0; }
  .fgc-field label, .fgc-field-label {
    color: var(--ink-dim); font: 700 11px/1.2 'DM Sans', sans-serif;
    letter-spacing: .1em; text-transform: uppercase;
  }
  .fgc-input, .fgc-select, .fgc-textarea {
    width: 100%; min-height: 46px; box-sizing: border-box; border: 2px solid rgba(255,255,255,.2);
    border-radius: 13px; background: rgba(255,255,255,.07); color: var(--ink); outline: none;
    padding: 11px 13px; font: 700 16px/1.25 'Space Grotesk', sans-serif;
  }
  .fgc-input:focus, .fgc-select:focus, .fgc-textarea:focus { border-color: var(--teal); box-shadow: 0 0 0 3px rgba(61,219,217,.18); }
  .fgc-select option { color: #120a30; }
  .fgc-signed { display: grid; grid-template-columns: minmax(0, 1fr) 46px; gap: 7px; }
  .fgc-sign-button {
    min-width: 46px; min-height: 46px; border: 2px solid var(--border); border-radius: 13px;
    background: var(--yellow); color: #090713; cursor: pointer;
    font: 900 20px/1 'Space Grotesk', sans-serif;
  }
  .fgc-check {
    display: flex; align-items: center; gap: 9px; min-height: 46px; padding: 9px 11px;
    border: 2px solid rgba(255,255,255,.14); border-radius: 13px; color: var(--ink-dim);
    font: 700 12px/1.3 'DM Sans', sans-serif;
  }
  .fgc-check input { width: 20px; height: 20px; accent-color: var(--yellow); }
  .fgc-add {
    width: 100%; min-height: 52px; border: 2px dashed rgba(255,255,255,.34); border-radius: 16px;
    background: rgba(168,230,53,.07); color: var(--lime); cursor: pointer;
    font: 800 15px/1 'Space Grotesk', sans-serif;
  }
  .fgc-side { display: flex; flex-direction: column; gap: 14px; min-width: 0; }
  .fgc-panel { background: rgba(255,255,255,.05); border: 2px solid var(--border); border-radius: 18px; padding: 17px; }
  .fgc-panel-title { margin: 0 0 13px; font: 800 18px/1.1 'Space Grotesk', sans-serif; }
  .fgc-standing { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 9px; align-items: center; padding: 9px 0; border-top: 1px solid rgba(255,255,255,.1); }
  .fgc-dot { width: 12px; height: 12px; border: 1px solid var(--border); border-radius: 999px; }
  .fgc-status { margin-top: 12px; padding: 10px 12px; border-radius: 12px; background: rgba(255,210,63,.1); color: var(--yellow); font: 700 12px/1.4 'DM Sans', sans-serif; }
  .fgc-status.is-incomplete { background: rgba(255,138,92,.12); color: var(--coral); }
  .fgc-textarea { min-height: 92px; resize: vertical; font-family: 'DM Sans', sans-serif; font-weight: 600; }
  .fgc-counter { text-align: right; color: var(--ink-dim); font-size: 11px; margin-top: 5px; }
  .fgc-error { padding: 12px 13px; border: 2px solid var(--coral); border-radius: 13px; background: rgba(255,138,92,.12); color: #ffd8ca; font-weight: 700; font-size: 13px; }
  .fgc-save, .fgc-secondary {
    min-height: 52px; border: 3px solid var(--border); border-radius: 15px; cursor: pointer;
    padding: 12px 16px; font: 800 15px/1.1 'Space Grotesk', sans-serif;
  }
  .fgc-save { background: var(--lime); color: #090713; box-shadow: 5px 5px 0 #05030d; }
  .fgc-secondary { background: transparent; color: var(--ink); }
  .fgc-save:disabled, .fgc-secondary:disabled, .fgc-icon-button:disabled { opacity: .38; cursor: not-allowed; box-shadow: none; }
  .fgc-decision { border-color: var(--coral); background: linear-gradient(145deg, rgba(255,138,92,.16), rgba(255,255,255,.04)); }
  .fgc-decision-actions { display: grid; gap: 9px; margin-top: 14px; }
  .fgc-empty { padding: 30px 18px; text-align: center; border: 2px dashed rgba(255,255,255,.2); border-radius: 18px; color: var(--ink-dim); }
  @media (max-width: 800px) {
    .fgc-overlay { padding: 0; place-items: stretch; }
    .fgc-dialog { width: 100%; max-height: 100vh; min-height: 100vh; border-radius: 0; border-left: 0; border-right: 0; box-shadow: none; }
    .fgc-header { padding: 18px 16px; }
    .fgc-body { grid-template-columns: 1fr; padding: 16px; }
    .fgc-side { order: -1; }
    .fgc-field-grid { grid-template-columns: 1fr; }
    .fgc-player-grid { grid-template-columns: 1fr; }
    .fgc-entry-card { padding: 14px; }
  }
`;

const FGC_ACCENTS = {
  "danish-500": "var(--pink)",
  backgammon: "var(--teal)",
  shithead: "var(--yellow)",
  uno: "var(--coral)",
  stigegolf: "#a78bfa",
  roevhul: "#8e6cff",
  "magical-athlete": "#f59e42",
};

function fgcClone(value) {
  return JSON.parse(JSON.stringify(value));
}

function fgcInitialEntries(game) {
  return (Array.isArray(game?.rounds) ? game.rounds : []).map((round, index) => ({
    ...(round?.data && typeof round.data === "object" ? fgcClone(round.data) : {}),
    id: String(round?.data?.id || `legacy-${game.id}-${index + 1}`),
  }));
}

function fgcDefaultEntry(game) {
  const playerCount = game.players.length;
  const id = newActiveGameEntryId();
  if (game.game === "danish-500") return { id, scores: game.players.map(() => 0) };
  if (game.game === "backgammon") return { id, winner: 0, type: "single", cube: 1 };
  if (game.game === "shithead") return { id, shitheadIdx: 0 };
  if (game.game === "uno") return { id, winnerIdx: 0, points: 0 };
  if (game.game === "stigegolf") return { id, raw: [0, 0], bonus: [false, false] };
  if (game.game === "roevhul") return { id, order: game.players.map((_, index) => index) };
  if (game.game === "magical-athlete") return {
    id,
    awards: { first: 0, second: playerCount > 1 ? 1 : null },
    adjustments: game.players.map(() => 0),
  };
  return { id };
}

function fgcNumber(value, fallback = 0) {
  const parsed = Number(value);
  return Number.isFinite(parsed) ? Math.trunc(parsed) : fallback;
}

function fgcPreview(game, entries) {
  try {
    const count = game.players.length;
    let finalScores = game.players.map(() => 0);
    let winnerIndexes = [0];
    let complete = false;
    if (game.game === "danish-500") {
      entries.forEach((entry) => {
        if (!Array.isArray(entry.scores) || entry.scores.length !== count) throw new Error("Every round needs one score per player.");
        entry.scores.forEach((score, index) => { finalScores[index] += fgcNumber(score); });
      });
      winnerIndexes = [finalScores.indexOf(Math.max(...finalScores))];
      complete = finalScores.some((score) => score >= 500);
    } else if (game.game === "backgammon") {
      const values = { single: 1, gammon: 2, backgammon: 3 };
      entries.forEach((entry) => {
        if (![0, 1].includes(entry.winner) || !values[entry.type]) throw new Error("Check the Backgammon result.");
        finalScores[entry.winner] += values[entry.type] * fgcNumber(entry.cube, 1);
      });
      winnerIndexes = [finalScores[0] > finalScores[1] ? 0 : 1];
      complete = finalScores.some((score) => score >= fgcNumber(game.meta?.target, 7));
    } else if (game.game === "shithead") {
      const losses = game.players.map(() => 0);
      entries.forEach((entry) => {
        if (!Number.isInteger(entry.shitheadIdx) || entry.shitheadIdx < 0 || entry.shitheadIdx >= count) throw new Error("Choose the Shithead for every hand.");
        losses[entry.shitheadIdx] += 1;
      });
      const max = Math.max(0, ...losses);
      finalScores = losses.map((loss) => max - loss);
      winnerIndexes = [losses.indexOf(Math.min(...losses))];
      complete = entries.length > 0;
    } else if (game.game === "uno") {
      entries.forEach((entry) => {
        if (!Number.isInteger(entry.winnerIdx) || entry.winnerIdx < 0 || entry.winnerIdx >= count) throw new Error("Choose a winner for every round.");
        finalScores[entry.winnerIdx] += Math.max(0, fgcNumber(entry.points));
      });
      winnerIndexes = [finalScores.indexOf(Math.max(...finalScores))];
      complete = finalScores.some((score) => score >= fgcNumber(game.meta?.target, 500));
    } else if (game.game === "stigegolf") {
      const target = fgcNumber(game.meta?.target, 21);
      entries.forEach((entry) => {
        if (!Array.isArray(entry.raw) || entry.raw.length !== 2) throw new Error("Every round needs two raw scores.");
        const gains = entry.raw.map((raw, index) => fgcNumber(raw) + (entry.bonus?.[index] ? 1 : 0));
        const overtime = finalScores[0] >= target && finalScores[1] >= target;
        [0, 1].forEach((index) => {
          if (overtime || finalScores[index] + gains[index] <= target) finalScores[index] += gains[index];
        });
      });
      winnerIndexes = [finalScores[0] > finalScores[1] ? 0 : 1];
      const [a, b] = finalScores;
      complete = (a >= target && b < target) || (b >= target && a < target)
        || (a >= target && b >= target && Math.abs(a - b) >= 2);
    } else if (game.game === "roevhul") {
      let latest = [];
      entries.forEach((entry) => {
        const order = Array.isArray(entry.order) ? entry.order : [];
        if (order.length !== count || new Set(order).size !== count
          || order.some((index) => !Number.isInteger(index) || index < 0 || index >= count)) {
          throw new Error("Every hand must rank every player exactly once.");
        }
        order.forEach((playerIndex, place) => { finalScores[playerIndex] += count - place; });
        latest = order;
      });
      const high = Math.max(...finalScores);
      winnerIndexes = [latest.find((index) => finalScores[index] === high) ?? 0];
      complete = entries.length > 0;
    } else if (game.game === "magical-athlete") {
      const payouts = [[3, 1], [4, 2], [4, 2], [5, 3]];
      if (entries.length > 4) throw new Error("Magical Athlete has four races.");
      entries.forEach((entry, raceIndex) => {
        const first = entry.awards?.first;
        const second = entry.awards?.second;
        if (first !== null && (!Number.isInteger(first) || first < 0 || first >= count)) throw new Error("Check first place.");
        if (second !== null && (!Number.isInteger(second) || second < 0 || second >= count)) throw new Error("Check second place.");
        if (first === null && second !== null) throw new Error("Second place needs a first-place finisher.");
        if (first !== null) finalScores[first] += payouts[raceIndex][0];
        if (second !== null) finalScores[second] += payouts[raceIndex][1];
        if (!Array.isArray(entry.adjustments) || entry.adjustments.length !== count) throw new Error("Every player needs a race adjustment.");
        entry.adjustments.forEach((adjustment, playerIndex) => { finalScores[playerIndex] += fgcNumber(adjustment); });
        if (finalScores.some((score) => score < 0)) throw new Error("Point chips cannot fall below zero.");
      });
      const high = Math.max(...finalScores);
      winnerIndexes = finalScores.map((score, index) => score === high ? index : null).filter((index) => index !== null);
      complete = entries.length === 4;
    }
    return { finalScores, winnerIndexes, complete, error: "" };
  } catch (error) {
    return { finalScores: game.players.map(() => 0), winnerIndexes: [], complete: false, error: error.message || "Check the entries." };
  }
}

function FgcSignedScoreInput({ player, value, onChange }) {
  const [text, setText] = React.useState(String(value ?? 0));
  React.useEffect(() => { setText(String(value ?? 0)); }, [value]);
  const commit = (next) => {
    setText(next);
    if (/^-?\d+$/.test(next)) onChange(fgcNumber(next));
  };
  const toggle = () => {
    if (!text || text === "0") { setText("-"); return; }
    commit(text.startsWith("-") ? text.slice(1) || "0" : `-${text}`);
  };
  return (
    <div className="fgc-field">
      <label>{player.name}</label>
      <div className="fgc-signed">
        <input
          className="fgc-input"
          type="text"
          inputMode="numeric"
          value={text}
          onChange={(event) => {
            const next = event.target.value.replace(/[^0-9-]/g, "");
            if (/^-?\d*$/.test(next)) commit(next);
          }}
          onBlur={() => { if (text === "" || text === "-") commit("0"); }}
          aria-label={`${player.name} score`}
        />
        <button className="fgc-sign-button" type="button" onClick={toggle} aria-label={`Toggle negative score for ${player.name}`}>±</button>
      </div>
    </div>
  );
}

function FgcPlayerSelect({ players, value, onChange, allowNone = false, label }) {
  return (
    <div className="fgc-field">
      <label>{label}</label>
      <select className="fgc-select" value={value === null ? "none" : value} onChange={(event) => onChange(event.target.value === "none" ? null : Number(event.target.value))}>
        {allowNone && <option value="none">Not awarded</option>}
        {players.map((player, index) => <option value={index} key={player.name}>{player.name}</option>)}
      </select>
    </div>
  );
}

function FgcEntryFields({ game, entry, onChange }) {
  const players = game.players;
  if (game.game === "danish-500") return (
    <div className="fgc-player-grid">
      {players.map((player, playerIndex) => (
        <FgcSignedScoreInput
          key={player.name}
          player={player}
          value={entry.scores?.[playerIndex] ?? 0}
          onChange={(score) => {
            const scores = [...(entry.scores || players.map(() => 0))];
            scores[playerIndex] = score;
            onChange({ ...entry, scores });
          }}
        />
      ))}
    </div>
  );
  if (game.game === "backgammon") return (
    <div className="fgc-field-grid">
      <FgcPlayerSelect players={players} value={entry.winner} onChange={(winner) => onChange({ ...entry, winner })} label="Winner" />
      <div className="fgc-field"><label>Win type</label><select className="fgc-select" value={entry.type} onChange={(event) => onChange({ ...entry, type: event.target.value })}><option value="single">Single</option><option value="gammon">Gammon</option><option value="backgammon">Backgammon</option></select></div>
      <div className="fgc-field"><label>Doubling cube</label><select className="fgc-select" value={entry.cube} onChange={(event) => onChange({ ...entry, cube: Number(event.target.value) })}>{[1,2,4,8,16,32,64].map((cube) => <option value={cube} key={cube}>{cube}×</option>)}</select></div>
    </div>
  );
  if (game.game === "shithead") return <FgcPlayerSelect players={players} value={entry.shitheadIdx} onChange={(shitheadIdx) => onChange({ ...entry, shitheadIdx })} label="Who was the Shithead?" />;
  if (game.game === "uno") return (
    <div className="fgc-field-grid">
      <FgcPlayerSelect players={players} value={entry.winnerIdx} onChange={(winnerIdx) => onChange({ ...entry, winnerIdx })} label="Round winner" />
      <div className="fgc-field"><label>Points</label><input className="fgc-input" type="number" min="0" step="1" inputMode="numeric" value={entry.points} onChange={(event) => onChange({ ...entry, points: Math.max(0, fgcNumber(event.target.value)) })} /></div>
    </div>
  );
  if (game.game === "stigegolf") return (
    <div className="fgc-field-grid">
      {players.map((player, index) => (
        <div className="fgc-fields" key={player.name}>
          <div className="fgc-field"><label>{player.name} raw score</label><input className="fgc-input" type="number" min="0" max="9" inputMode="numeric" value={entry.raw?.[index] ?? 0} onChange={(event) => { const raw = [...(entry.raw || [0,0])]; raw[index] = Math.max(0, Math.min(9, fgcNumber(event.target.value))); onChange({ ...entry, raw }); }} /></div>
          <label className="fgc-check"><input type="checkbox" checked={!!entry.bonus?.[index]} onChange={(event) => { const bonus = [...(entry.bonus || [false,false])]; bonus[index] = event.target.checked; onChange({ ...entry, bonus }); }} /> Bonus +1</label>
        </div>
      ))}
    </div>
  );
  if (game.game === "roevhul") return (
    <div className="fgc-player-grid">
      {players.map((_, place) => <FgcPlayerSelect key={place} players={players} value={entry.order?.[place] ?? place} onChange={(playerIndex) => { const order = [...(entry.order || players.map((__, index) => index))]; order[place] = playerIndex; onChange({ ...entry, order }); }} label={`${place + 1}${place === 0 ? "st" : place === 1 ? "nd" : place === 2 ? "rd" : "th"} place`} />)}
    </div>
  );
  if (game.game === "magical-athlete") return (
    <div className="fgc-fields">
      <div className="fgc-field-grid">
        <FgcPlayerSelect players={players} allowNone value={entry.awards?.first ?? null} onChange={(first) => onChange({ ...entry, awards: { ...entry.awards, first, ...(first === null ? { second: null } : {}) } })} label="First place" />
        <FgcPlayerSelect players={players} allowNone value={entry.awards?.second ?? null} onChange={(second) => onChange({ ...entry, awards: { ...entry.awards, second } })} label="Second place" />
      </div>
      <div className="fgc-player-grid">
        {players.map((player, index) => <div className="fgc-field" key={player.name}><label>{player.name} adjustment</label><input className="fgc-input" type="number" step="1" inputMode="numeric" value={entry.adjustments?.[index] ?? 0} onChange={(event) => { const adjustments = [...(entry.adjustments || players.map(() => 0))]; adjustments[index] = fgcNumber(event.target.value); onChange({ ...entry, adjustments }); }} /></div>)}
      </div>
    </div>
  );
  return null;
}

function FinishedGameEditor({ game, familyId, onClose, onSaved, onReopened }) {
  const [entries, setEntries] = React.useState(() => fgcInitialEntries(game));
  const [reason, setReason] = React.useState("");
  const [busy, setBusy] = React.useState(false);
  const [error, setError] = React.useState("");
  const [decision, setDecision] = React.useState(null);
  const closeRef = React.useRef(null);
  const dialogRef = React.useRef(null);
  const preview = React.useMemo(() => fgcPreview(game, entries), [game, entries]);
  const accent = FGC_ACCENTS[game.game] || "var(--teal)";
  const entryLabel = game.game === "backgammon" ? "game" : game.game === "roevhul" || game.game === "shithead" ? "hand" : game.game === "magical-athlete" ? "race" : "round";

  React.useEffect(() => {
    const previousOverflow = document.body.style.overflow;
    document.body.style.overflow = "hidden";
    closeRef.current?.focus();
    const onKey = (event) => {
      if (event.key === "Escape" && !busy) onClose();
      if (event.key !== "Tab" || !dialogRef.current) return;
      const focusable = [...dialogRef.current.querySelectorAll(
        'button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])',
      )];
      if (focusable.length === 0) return;
      const first = focusable[0];
      const last = focusable[focusable.length - 1];
      if (event.shiftKey && document.activeElement === first) {
        event.preventDefault(); last.focus();
      } else if (!event.shiftKey && document.activeElement === last) {
        event.preventDefault(); first.focus();
      }
    };
    window.addEventListener("keydown", onKey);
    return () => { document.body.style.overflow = previousOverflow; window.removeEventListener("keydown", onKey); };
  }, [busy, onClose]);
  React.useEffect(() => { setDecision(null); }, [entries]);

  const updateEntry = (index, next) => setEntries((current) => current.map((entry, entryIndex) => entryIndex === index ? next : entry));
  const moveEntry = (index, delta) => setEntries((current) => {
    const target = index + delta;
    if (target < 0 || target >= current.length) return current;
    const next = [...current];
    [next[index], next[target]] = [next[target], next[index]];
    return next;
  });
  const removeEntry = (index) => setEntries((current) => current.filter((_, entryIndex) => entryIndex !== index));
  const addEntry = () => setEntries((current) => [...current, fgcDefaultEntry(game)]);

  const save = async (resolution = "") => {
    if (preview.error || busy) return;
    setBusy(true); setError("");
    try {
      const result = await window.svendeApi.correctFinishedGame(game.id, {
        expectedVersion: game.version,
        entries,
        reason,
        ...(resolution ? { resolution } : {}),
        ...(familyId ? { familyId } : {}),
      });
      if (result.status === "active") {
        onReopened(result.game);
      } else {
        onSaved(result.game);
      }
    } catch (saveError) {
      if (saveError.data?.code === "REOPEN_DECISION_REQUIRED") {
        setDecision(saveError.data.preview || true);
      } else if (saveError.data?.code === "STALE_GAME_VERSION") {
        setError("Someone else corrected this game first. Close and reopen it to load their changes; your unsaved values are still here.");
      } else {
        setError(saveError.message || "Could not save the correction.");
      }
    } finally {
      setBusy(false);
    }
  };

  const canAdd = game.game !== "magical-athlete" || entries.length < 4;
  const winners = preview.winnerIndexes.map((index) => game.players[index]?.name).filter(Boolean).join(" & ");
  return (
    <div className="fgc-overlay" onMouseDown={(event) => { if (event.target === event.currentTarget && !busy) onClose(); }}>
      <style>{FINISHED_GAME_EDITOR_CSS}</style>
      <section ref={dialogRef} className="fgc-dialog" role="dialog" aria-modal="true" aria-labelledby="fgc-title">
        <header className="fgc-header" style={{ boxShadow: `inset 8px 0 0 ${accent}` }}>
          <div>
            <div className="fgc-eyebrow" style={{ color: accent }}>Correct a finished {GAME_TITLES[game.game] || game.game} game</div>
            <h2 className="fgc-title" id="fgc-title">Fix the scorecard</h2>
          </div>
          <button ref={closeRef} className="fgc-close" type="button" onClick={onClose} disabled={busy} aria-label="Close correction editor">×</button>
        </header>
        <div className="fgc-body">
          <div className="fgc-entry-list">
            {entries.length === 0 && <div className="fgc-empty">No entries remain. Add a {entryLabel} or save and choose what should happen to this incomplete game.</div>}
            {entries.map((entry, index) => (
              <article className="fgc-entry-card" key={entry.id}>
                <div className="fgc-entry-head">
                  <div className="fgc-entry-name">{entryLabel[0].toUpperCase() + entryLabel.slice(1)} {index + 1}</div>
                  <div className="fgc-entry-actions">
                    <button className="fgc-icon-button" type="button" onClick={() => moveEntry(index, -1)} disabled={index === 0 || busy} aria-label={`Move ${entryLabel} ${index + 1} earlier`}>↑</button>
                    <button className="fgc-icon-button" type="button" onClick={() => moveEntry(index, 1)} disabled={index === entries.length - 1 || busy} aria-label={`Move ${entryLabel} ${index + 1} later`}>↓</button>
                    <button className="fgc-icon-button" type="button" onClick={() => removeEntry(index)} disabled={busy} aria-label={`Delete ${entryLabel} ${index + 1}`} style={{ color: "var(--coral)" }}>✕</button>
                  </div>
                </div>
                <FgcEntryFields game={game} entry={entry} onChange={(next) => updateEntry(index, next)} />
              </article>
            ))}
            <button className="fgc-add" type="button" onClick={addEntry} disabled={!canAdd || busy}>+ Add {entryLabel}</button>
          </div>
          <aside className="fgc-side">
            <div className="fgc-panel">
              <h3 className="fgc-panel-title">Corrected standings</h3>
              {game.players.map((player, index) => (
                <div className="fgc-standing" key={player.name}>
                  <span className="fgc-dot" style={{ background: player.color }} />
                  <strong>{player.name}{preview.winnerIndexes.includes(index) ? " 👑" : ""}</strong>
                  <strong>{preview.finalScores[index] ?? 0}</strong>
                </div>
              ))}
              {preview.error
                ? <div className="fgc-status is-incomplete">{preview.error}</div>
                : <div className={`fgc-status ${preview.complete ? "" : "is-incomplete"}`}>
                    {preview.complete ? `${winners || "A winner"} still satisfies the ending rule.` : "This result no longer satisfies the normal ending rule. You can choose to keep it finished or reopen it when saving."}
                  </div>}
            </div>
            <div className="fgc-panel">
              <div className="fgc-field">
                <label htmlFor="fgc-reason">Why was this corrected? (optional)</label>
                <textarea id="fgc-reason" className="fgc-textarea" maxLength="500" value={reason} onChange={(event) => setReason(event.target.value)} placeholder="For example: Entered the wrong sign" />
              </div>
              <div className="fgc-counter">{Array.from(reason).length}/500</div>
            </div>
            {decision && (
              <div className="fgc-panel fgc-decision">
                <h3 className="fgc-panel-title">The game is no longer complete</h3>
                <div style={{ color: "var(--ink-dim)", fontSize: 13, lineHeight: 1.5 }}>Keep this as a corrected historical result, or reopen it so the family can continue playing.</div>
                <div className="fgc-decision-actions">
                  <button className="fgc-save" type="button" disabled={busy} onClick={() => save("active")}>Reopen and continue →</button>
                  <button className="fgc-secondary" type="button" disabled={busy} onClick={() => save("finished")}>Keep finished</button>
                </div>
              </div>
            )}
            {error && <div className="fgc-error" role="alert">{error}</div>}
            {!decision && <button className="fgc-save" type="button" onClick={() => save()} disabled={busy || !!preview.error}>{busy ? "Saving correction…" : "Save correction"}</button>}
            <button className="fgc-secondary" type="button" onClick={onClose} disabled={busy}>Cancel</button>
          </aside>
        </div>
      </section>
    </div>
  );
}
