:root {
  --bg: #15181d;
  --panel: #1f242c;
  --line: #333a45;
  --text: #e8ecf1;
  --muted: #9aa4b2;
  --accent: #5aa9ff;
  --warn: #ff6b6b;
  --ok: #4cd18a;
  --white: #f4f4f4;
  --blue: #2f6fd8;
  --green: #2f9e57;
  --red: #d64545;
  --black: #3a3a3a;
  --gold: #e3b341;
}
* { box-sizing: border-box; }
html, body { height: 100%; }
body { margin: 0; font: 14px/1.4 system-ui, sans-serif; background: var(--bg); color: var(--text); display: flex; flex-direction: column; }
h1 { font-size: 18px; margin: 0; }
h2 { font-size: 14px; margin: 0 0 6px; }
.muted { color: var(--muted); font-weight: normal; }
.error { color: var(--warn); min-height: 1em; }
button, .button {
  background: #2b3340; color: var(--text); border: 1px solid var(--line); border-radius: 6px;
  padding: 5px 10px; cursor: pointer; font: inherit; text-decoration: none; display: inline-block;
}
button:hover:not(:disabled), .button:hover { border-color: var(--accent); }
button:disabled { opacity: .45; cursor: not-allowed; }
button.primary { background: #1e5bb8; border-color: #2f74de; }

.topbar { display: flex; align-items: center; gap: 12px; padding: 8px 14px; border-bottom: 1px solid var(--line); }
.spacer { flex: 1; }
.pill { padding: 3px 10px; border-radius: 999px; background: #2b3340; font-weight: 600; }
.pill.running { background: #1d4d33; }
.pill.paused { background: #6a4b12; }
.pill.finished { background: #4a2a5e; }
/* Whose turn: the player's turn is the loudest thing on screen; the AI's turn is calm and shows it working. */
.turn-banner {
  display: flex; align-items: center; gap: 10px; padding: 8px 14px; font-weight: 700; font-size: 15px;
  border-bottom: 1px solid var(--line); background: #2b3340; color: var(--muted);
}
.turn-banner[hidden] { display: none; }
.turn-banner .ply { margin-left: auto; font-weight: 500; font-size: 12px; opacity: .85; }
.turn-banner.you { background: #1e5bb8; border-color: #5aa9ff; color: #fff; box-shadow: inset 4px 0 0 var(--gold); }
.turn-banner.ai { background: #232a34; color: var(--text); }
.turn-banner.paused { background: #4a3810; color: var(--text); }
.turn-banner.over { background: #3d2650; color: var(--text); }
.clock { font: 600 20px/1 ui-monospace, monospace; min-width: 80px; text-align: right; }
.clock.low { color: var(--gold); }
.clock.over { color: var(--warn); }
.seedbar { padding: 4px 14px; color: var(--muted); font-size: 12px; border-bottom: 1px solid var(--line); }
.seedbar code { color: var(--text); }
.toast {
  position: fixed; top: 54px; left: 50%; transform: translateX(-50%); z-index: 20;
  background: #4a1f1f; border: 1px solid var(--warn); padding: 8px 14px; border-radius: 6px;
}
.toast.info { background: #1f344a; border-color: var(--accent); }

/* The page is a fixed viewport shell: each column scrolls on its own, so a growing log never stretches the page. */
.layout { flex: 1; min-height: 0; display: grid; grid-template-columns: minmax(520px, 1.3fr) minmax(330px, 1fr) 340px; gap: 12px; padding: 12px; }
.board, .players, .side { display: flex; flex-direction: column; gap: 10px; min-width: 0; min-height: 0; overflow-y: auto; }
/* The market takes the board column's remaining height and sizes its cards from its own box: three tier rows high,
   deck 86px + 4 cards + 4 gaps wide. Below the card-width floor (short viewports) the column scrolls instead. */
.board > .market { --card-min: 76px; flex: 1 1 0; min-height: calc(3 * var(--card-min) * 128 / 94 + 2 * 8px);
  container-type: size; --card-w: min(calc((100cqb - 2 * 8px) / 3 * 94 / 128), calc((100cqi - 118px) / 4)); }
.log-panel { flex: 1; min-height: 160px; display: flex; flex-direction: column; }
.board > *, .players > *, .side > :not(.log-panel) { flex-shrink: 0; }
.panel { background: var(--panel); border: 1px solid var(--line); border-radius: 8px; padding: 10px; }
.panel-head { display: flex; justify-content: space-between; align-items: center; gap: 6px; flex-wrap: wrap; }
.exports { display: flex; gap: 4px; }
.exports button, .exports .button { padding: 2px 7px; font-size: 12px; }

.review { display: flex; align-items: center; gap: 6px; }
.review span { flex: 1; min-width: 210px; text-align: center; color: var(--muted); }
.review.active span { color: var(--gold); font-weight: 600; }

.nobles { display: flex; gap: 8px; }
.noble {
  width: 74px; height: 74px; border-radius: 6px; background: #e9dcc0; color: #222; padding: 4px;
  display: flex; flex-direction: column; justify-content: space-between; border: 2px solid transparent;
}
.noble .pts { font-weight: 700; font-size: 16px; line-height: 1; }
/* A held noble: up to three requirement pips wrap to two rows, so they shrink to stay inside the tile. */
.noble.small { width: 56px; height: 62px; font-size: 11px; }
.noble.small .pts { font-size: 12px; line-height: 1.2; }
.noble.small .reqs { gap: 1px; }
.noble.small .reqs .pip { min-width: 15px; height: 15px; font-size: 10px; padding: 0 3px; }
.noble.pickable { border-color: var(--accent); cursor: pointer; box-shadow: 0 0 0 2px var(--accent); }
.noble.picked { border-color: var(--ok); box-shadow: 0 0 0 3px var(--ok); }
.reqs { display: flex; gap: 2px; flex-wrap: wrap; }

.market { display: flex; flex-direction: column; gap: 8px; }
.tier-row { display: flex; gap: 8px; align-items: stretch; }
.deck {
  width: 86px; border-radius: 8px; background: repeating-linear-gradient(45deg, #2a3240, #2a3240 6px, #232a35 6px, #232a35 12px);
  border: 1px solid var(--line); display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px; padding: 4px;
}
.deck .count { font-size: 18px; font-weight: 700; }
.deck button { font-size: 10px; padding: 2px 4px; }

.card {
  width: max(var(--card-min, 94px), var(--card-w, 94px)); aspect-ratio: 94 / 128; border-radius: 8px; position: relative; padding: 5px;
  display: flex; flex-direction: column; justify-content: space-between; border: 2px solid transparent;
  color: #111; background: #ddd; user-select: none;
}
.card.empty { background: transparent; border: 1px dashed var(--line); }
.card .head { display: flex; justify-content: space-between; align-items: center; }
.card .pts { font-weight: 800; font-size: 20px; line-height: 1; }
.card .gem { width: 16px; height: 16px; border-radius: 50%; border: 1px solid #0006; }
.card .cost { display: flex; flex-direction: column; gap: 1px; align-items: flex-start; }
.card .tierlabel { position: absolute; right: 5px; bottom: 4px; font-size: 10px; opacity: .65; }
.card.bonus-white { background: linear-gradient(#fafafa, #d9d9d9); }
.card.bonus-blue { background: linear-gradient(#8fb6f2, #4c7fd0); }
.card.bonus-green { background: linear-gradient(#9fdcb4, #4ea36c); }
.card.bonus-red { background: linear-gradient(#f2a1a1, #c95353); }
.card.bonus-black { background: linear-gradient(#9a9a9a, #565656); color: #fff; }
.card.hidden { background: repeating-linear-gradient(45deg, #2a3240, #2a3240 6px, #232a35 6px, #232a35 12px); color: var(--text); }
.card.mini { width: 86px; height: 113px; aspect-ratio: auto; padding: 4px; }
.card.mini .pts { font-size: 18px; }
.card.actionable { cursor: pointer; }
.card.actionable:hover { border-color: var(--accent); }
.card.selected { border-color: var(--ok); box-shadow: 0 0 0 3px var(--ok); }
.card.unavailable { cursor: not-allowed; }

.pip {
  display: inline-flex; align-items: center; justify-content: center; min-width: 20px; height: 20px; padding: 0 4px;
  border-radius: 10px; font-size: 12px; font-weight: 700; border: 1px solid #0007;
}
.cost .pip { min-width: 28px; height: 28px; padding: 0 6px; border-radius: 14px; font-size: 15px; }
/* Four distinct cost colors need all four rows of the vertical stack; shrink to keep the card's height. */
.cost:has(.pip:nth-child(4)) .pip { min-width: 22px; height: 22px; padding: 0 5px; border-radius: 11px; font-size: 13px; }
.reqs .pip { min-width: 20px; height: 20px; padding: 0 4px; border-radius: 10px; font-size: 12px; }
.c-white { background: var(--white); color: #222; }
.c-blue { background: var(--blue); color: #fff; }
.c-green { background: var(--green); color: #fff; }
.c-red { background: var(--red); color: #fff; }
.c-black { background: var(--black); color: #fff; }
.card.mini .cost .pip { min-width: 18px; height: 18px; font-size: 12px; padding: 0 4px; border-radius: 9px; }
.card.mini .cost { gap: 1px; }
/* Short viewports shrink market cards below their 94px design width; compact pips keep four cost rows inside. */
@container (max-height: 399px) {
  .card .cost .pip { min-width: 16px; height: 16px; font-size: 11px; padding: 0 3px; border-radius: 8px; }
  .card .pts { font-size: 17px; }
}
.c-gold { background: var(--gold); color: #222; }
/* Colors inside move text: a coin carries its count, a card mark stands for a card of that bonus color.
   A coin centers on the text's x-height; lines holding one need a line height that clears its 16px. */
.pip.coin { min-width: 16px; height: 16px; padding: 0 3px; border-radius: 8px; font-size: 10px; vertical-align: middle; margin: 0 1px; }
.card-mark-wrap { white-space: nowrap; }
.card-mark { display: inline-block; width: 9px; height: 12px; border-radius: 2px; border: 1px solid #0007; vertical-align: -2px; }

.bank { display: flex; gap: 10px; align-items: center; padding: 8px; background: var(--panel); border-radius: 8px; border: 1px solid var(--line); }
.bank .label { color: var(--muted); margin-right: 4px; }
.token {
  width: 48px; height: 48px; border-radius: 50%; display: flex; align-items: center; justify-content: center;
  font-weight: 800; font-size: 17px; border: 3px solid #0006; position: relative; user-select: none;
}
.token.pickable { cursor: pointer; box-shadow: 0 0 0 2px var(--accent); }
.token.blocked { opacity: .45; cursor: not-allowed; }
.token .badge {
  position: absolute; top: -6px; right: -6px; background: var(--ok); color: #111; border-radius: 10px;
  font-size: 11px; padding: 0 5px; border: 1px solid #111;
}
.token .badge.ret { background: var(--warn); }
.token.held { width: 36px; height: 36px; font-size: 14px; }
.shake { animation: shake .3s; }
@keyframes shake { 25% { transform: translateX(-4px); } 75% { transform: translateX(4px); } }

/* A fixed height, so the market never resizes or scrolls while a turn is composed: measured at the narrowest board
   column, it fits the draft row, one row of payment choices or a two-line hint, and the buttons. A rare second row
   of payment choices scrolls inside the composer. */
.composer { height: 156px; overflow-y: auto; background: var(--panel); border: 1px solid var(--line); border-radius: 8px; padding: 10px; }
.composer .row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-top: 6px; }
.composer .hint { color: var(--muted); }
.composer .hint.bad { color: var(--warn); }
.composer .hint.good { color: var(--ok); }
.payments { display: flex; gap: 6px; flex-wrap: wrap; }
.payments button.on { border-color: var(--ok); box-shadow: 0 0 0 2px var(--ok); }
.composer .token-count { margin-left: auto; font-variant-numeric: tabular-nums; color: var(--muted); white-space: nowrap; }
.composer .token-count.over { color: var(--gold); font-weight: 700; }
/* Returning tokens: the player's own coins, beside the move, in the warning color's frame. */
.composer .return-picker { padding: 3px 8px; border: 1px solid var(--gold); border-radius: 8px; background: #3a2f12; }
.composer .return-head { font-weight: 700; color: var(--gold); }
.composer .return-picker .token { border-width: 2px; padding: 0; }

.player { background: var(--panel); border: 1px solid var(--line); border-radius: 8px; padding: 10px; display: flex; flex-direction: column; gap: 8px; }
.player.active { border-color: var(--accent); box-shadow: 0 0 0 2px #5aa9ff55; }
.player .title { display: flex; align-items: baseline; gap: 8px; }
.player .name { font-size: 16px; font-weight: 700; }
.player .prestige { margin-left: auto; font-size: 26px; font-weight: 800; }
.player .prestige small { font-size: 12px; color: var(--muted); font-weight: 400; }
.player .row { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
.player .label { color: var(--muted); width: 74px; font-size: 12px; }
.player .total.full { color: var(--warn); font-weight: 700; }
.bonusbar { display: flex; flex-direction: column; align-items: center; gap: 2px; width: 36px; }
.bonusbar .bar { width: 22px; background: #2b3340; border-radius: 3px; height: 42px; display: flex; align-items: flex-end; overflow: hidden; }
.bonusbar .bar div { width: 100%; }
.cards-row { display: flex; gap: 6px; flex-wrap: wrap; }
.tag { font-size: 11px; padding: 1px 6px; border-radius: 4px; background: #2b3340; color: var(--muted); }
.tag.turn { background: #1e5bb8; color: #fff; }

.ai .thinking { display: flex; align-items: center; gap: 8px; }
.spinner { width: 14px; height: 14px; border: 2px solid var(--muted); border-top-color: var(--accent); border-radius: 50%; animation: spin .8s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
/* Fixed layout and tabular digits: the panel re-renders every search slice, and nothing may shift when numbers change.
   The 20px line height holds a coin, so a coin on a clamped choice's second line is not cut off. */
.ai table { width: 100%; border-collapse: collapse; font-size: 12px; line-height: 20px; margin-top: 6px; table-layout: fixed; }
.ai td, .ai th { text-align: left; padding: 2px 4px; border-bottom: 1px solid var(--line); vertical-align: top; }
.ai .n { text-align: right; font-variant-numeric: tabular-nums; }
.ai col.c-visits { width: calc(7ch + 8px); }
.ai col.c-share { width: calc(5ch + 8px); }
.ai col.c-win { width: calc(7ch + 8px); }
/* Every row holds two lines whatever its text, so rows reordering between slices never changes their heights. */
.ai td.choice > div { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; height: 2lh; }
.ai tr.selected td { color: var(--ok); }
.ai .live-head { margin-top: 6px; font-weight: 600; }
.ai .live-stats { white-space: nowrap; }
.num { display: inline-block; text-align: right; font-variant-numeric: tabular-nums; }

.graph { width: 100%; height: auto; display: block; margin-top: 4px; }
.graph .even { stroke: var(--muted); stroke-width: 1.25; stroke-dasharray: 5 4; opacity: .85; }
.graph .trend { fill: none; stroke: var(--accent); stroke-width: 1.5; }
.graph circle.model { fill: var(--accent); }
.graph circle.human { fill: var(--gold); }
.graph circle.live { fill: none; stroke: var(--text); stroke-width: 1.5; }
.graph .cursor { stroke: var(--text); stroke-width: 1; opacity: .7; }
.graph circle.reviewed { stroke: var(--text); stroke-width: 1.5; }
#graph .reviewed-estimate { color: var(--text); font-weight: 400; }
#graph .estimate { color: var(--accent); }
#graph .legend { font-size: 11px; }
#graph .human-dot { color: var(--gold); }

.log { flex: 1; min-height: 0; overflow: auto; margin: 6px 0 0; padding-left: 4px; font-size: 12px; list-style: none; }
.log li { padding: 2px 4px; border-radius: 4px; cursor: pointer; }
.log li .position { display: inline-block; min-width: 3ch; margin-right: 4px; text-align: right; color: var(--muted); font-variant-numeric: tabular-nums; }
.log li:hover { background: #2b3340; }
.log li.current { background: #3b3220; }
.log li.future { opacity: .35; }
.log li .who { font-weight: 700; }
.log li .meta { color: var(--muted); }
.log li.over .meta { color: var(--warn); }
.log li .reaction { font-weight: 700; }
.log li .reaction.bad { color: var(--warn); }
.log li .reaction.good { color: var(--ok); }
.log li .reaction.even { color: var(--muted); }

.menu {
  position: absolute; z-index: 30; background: #252c37; border: 1px solid var(--accent); border-radius: 8px; padding: 6px;
  display: flex; flex-direction: column; gap: 4px; min-width: 150px; box-shadow: 0 6px 20px #0008;
}
.menu[hidden], .toast[hidden] { display: none; }
.menu .why { color: var(--muted); font-size: 11px; max-width: 220px; }

dialog { background: var(--panel); color: var(--text); border: 1px solid var(--line); border-radius: 10px; width: min(640px, calc(100vw - 16px)); max-height: 90vh; overflow: auto; }
dialog > section { border-top: 1px solid var(--line); margin-top: 8px; }
dialog .resume table { width: 100%; border-collapse: collapse; font-size: 12px; margin-top: 6px; }
dialog .resume td, dialog .resume th { text-align: left; padding: 3px 4px; border-bottom: 1px solid var(--line); }
dialog::backdrop { background: #000a; }
dialog label { display: flex; flex-direction: column; gap: 4px; margin: 10px 0; }
dialog label.check { flex-direction: row; align-items: flex-start; }
dialog input, dialog select { background: #12161b; color: var(--text); border: 1px solid var(--line); border-radius: 6px; padding: 6px; font: inherit; }
dialog .row { display: flex; gap: 6px; }
dialog .row input { flex: 1; }
dialog fieldset { border: 1px solid var(--line); border-radius: 6px; }
dialog fieldset label:has(input[type=radio]) { flex-direction: row; margin: 4px 0; }
dialog label[hidden] { display: none; }
dialog menu { display: flex; justify-content: flex-end; gap: 8px; padding: 0; }
dialog details { margin: 10px 0; }
dialog summary { cursor: pointer; color: var(--muted); font-size: 12px; }
dialog .notice { font-size: 12px; margin: 8px 0 0; }
dialog label.check small { display: block; margin-top: 2px; }
dialog .error:empty { display: none; }

.result { font-weight: 700; font-size: 15px; }

/* Narrow screens (phones, portrait tablets): one scrolling column in play order — board, players, model and log. The
   market sizes its cards from the column width instead of the viewport height, and the composer stays pinned to the
   bottom of the screen so a decision can be confirmed without scrolling back. */
@media (max-width: 900px) {
  html, body { height: auto; }
  .topbar { flex-wrap: nowrap; gap: 6px; padding: 6px 8px; white-space: nowrap; }
  .topbar h1 { display: none; }
  /* The turn banner already shows match status. Keep only available actions in the header. */
  .topbar #status, .topbar #btn-start:disabled, .topbar #btn-pause:disabled { display: none; }
  .topbar .spacer { min-width: 0; }
  .turn-banner { position: sticky; top: 0; z-index: 25; padding: 7px 10px; font-size: 14px; }
  .clock { min-width: 0; font-size: 18px; }
  .seedbar { display: none; }
  .layout { display: flex; flex-direction: column; gap: 8px; padding: 8px; }
  .board, .players, .side { overflow: visible; }
  .review span { min-width: 0; font-size: 12px; }
  .board > .market { --card-min: 0px; flex: none; min-height: 0; gap: 6px; container-type: inline-size;
    --card-w: calc((100cqi - 52px - 4 * 6px) / 4); }
  .tier-row { gap: 6px; }
  .deck { width: 52px; font-size: 11px; padding: 2px; }
  .deck .count { font-size: 15px; }
  .deck button { display: none; }
  .card { padding: 3px; border-radius: 6px; }
  .card .pts { font-size: 15px; }
  .card .gem { width: 12px; height: 12px; }
  .card .tierlabel { font-size: 8px; right: 3px; bottom: 2px; }
  .card .cost .pip, .cost:has(.pip:nth-child(4)) .pip { min-width: 15px; height: 15px; font-size: 10px; padding: 0 3px; border-radius: 8px; }
  .card.mini { width: 64px; height: 87px; }
  .nobles { gap: 6px; }
  .bank { gap: 6px; flex-wrap: wrap; justify-content: center; padding: 6px; }
  .bank .label { display: none; }
  .token { width: 42px; height: 42px; font-size: 15px; }
  .token.held { width: 32px; height: 32px; font-size: 13px; }
  .composer { position: sticky; bottom: 0; z-index: 20; height: auto; max-height: 45vh; box-shadow: 0 -4px 14px #0009; }
  .player { padding: 8px; gap: 6px; }
  .player .label { width: 52px; font-size: 11px; }
  .bonusbar { width: 30px; }
  .log-panel { min-height: 0; }
  .log { max-height: 50vh; }
  .exports { flex-wrap: wrap; }
  button, .button { min-height: 32px; }
}
