/* ==========================================================================
   QUEEN'S TUG — visual system
   Engraved stone, gold and silver, taken from the key art. Seat identity is
   Ludo-standard: red, green, blue, yellow.

   Layout law: the app is a fixed-height shell. Exactly one screen is mounted
   at a time and the page itself never scrolls, so the board cannot drift or
   reveal the screen behind it.
   ========================================================================== */

:root {
  --ink: #070a0f;
  --stone-900: #0d1119;
  --stone-800: #141926;
  --stone-700: #1c2231;
  --stone-600: #262e40;
  --line: #313c52;
  --line-soft: #232c3d;

  --gold: #d9a441;
  --gold-lt: #f7dda0;
  --gold-dk: #6f5218;
  --silver: #dbe3ef;
  --silver-dim: #98a5ba;
  --muted: #6b7890;

  --up: #4ea6e8;
  --down: #d6484c;
  --left: #63b84e;
  --right: #e6b13c;

  --danger: #d6484c;
  --ok: #57c06a;

  /* Ludo seats */
  --seat-0: #e0453f;
  --seat-1: #3faa54;
  --seat-2: #3d86e8;
  --seat-3: #e8b021;

  --display: 'Cinzel', 'Trajan Pro', Georgia, serif;
  --body: 'Spectral', Georgia, serif;
  --mono: 'JetBrains Mono', ui-monospace, monospace;

  --r-sm: 4px;
  --r-md: 8px;
  --r-lg: 14px;

  --shadow: 0 20px 60px rgba(0, 0, 0, 0.7);
  --bar-h: 52px;
}

* { box-sizing: border-box; }
[hidden] { display: none !important; }

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  overflow: hidden;
  overscroll-behavior: none;
}

body {
  background: radial-gradient(130% 100% at 50% -15%, #1a2233 0%, var(--ink) 60%), var(--ink);
  color: var(--silver);
  font-family: var(--body);
  font-size: 16px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent;
}

body::before {
  content: '';
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  background-image:
    linear-gradient(rgba(217, 164, 65, 0.05) 1px, transparent 1px),
    linear-gradient(90deg, rgba(217, 164, 65, 0.05) 1px, transparent 1px);
  background-size: 88px 88px;
  mask-image: radial-gradient(120% 85% at 50% 0%, #000 15%, transparent 75%);
  -webkit-mask-image: radial-gradient(120% 85% at 50% 0%, #000 15%, transparent 75%);
}

h1, h2, h3, h4 {
  font-family: var(--display);
  font-weight: 700;
  letter-spacing: 0.05em;
  margin: 0;
}

button { font: inherit; color: inherit; cursor: pointer; border: none; background: none; }
button:focus-visible, [tabindex]:focus-visible { outline: 2px solid var(--gold-lt); outline-offset: 3px; }

.num { font-family: var(--mono); font-variant-numeric: tabular-nums; }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ---------- the shell ---------- */

#app {
  position: relative;
  z-index: 1;
  height: 100vh;
  height: 100dvh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.screen {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  animation: fade-in 0.35s ease both;
}

@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }

/* ---------- buttons ---------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  padding: 13px 26px;
  border-radius: var(--r-md);
  font-family: var(--display);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  background: linear-gradient(180deg, var(--stone-600), var(--stone-800));
  border: 1px solid var(--line);
  color: var(--silver);
  transition: transform 0.12s ease, border-color 0.15s, filter 0.15s, opacity 0.15s;
  white-space: nowrap;
}
.btn:hover:not(:disabled) { border-color: var(--gold); transform: translateY(-1px); }
.btn:active:not(:disabled) { transform: translateY(1px); }
.btn:disabled { opacity: 0.35; cursor: not-allowed; }

.btn-gold {
  background: linear-gradient(180deg, #f2ce7c, var(--gold) 48%, #a87d20);
  border-color: #f7dda0;
  color: #261903;
  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.3);
  box-shadow: 0 6px 22px rgba(217, 164, 65, 0.24);
}
.btn-gold:hover:not(:disabled) { filter: brightness(1.09); }

.btn-ghost { background: transparent; border-color: var(--line); color: var(--silver-dim); }
.btn-ghost:hover:not(:disabled) { color: var(--silver); border-color: var(--gold); }
.btn-sm { padding: 8px 14px; font-size: 11px; letter-spacing: 0.12em; }
.btn-lg { padding: 17px 40px; font-size: 15px; }

.icon-btn {
  width: 34px; height: 34px;
  display: grid; place-items: center;
  border-radius: var(--r-sm);
  border: 1px solid transparent;
  color: var(--muted);
  transition: color 0.15s, border-color 0.15s, background 0.15s;
}
.icon-btn:hover { color: var(--gold-lt); border-color: var(--line); background: rgba(255,255,255,.04); }
.icon-btn svg { width: 18px; height: 18px; }

/* ==========================================================================
   TITLE
   ========================================================================== */

.title-screen {
  position: relative;
  justify-content: center;
  align-items: center;
  padding: 54px 16px 28px;
  overflow-y: auto;
}

/* Icons sit against the viewport, exactly as they do in the game bar, so they
   cannot drift with the width of the centred column. */
.floating-bar {
  position: absolute;
  top: 10px;
  right: 14px;
  display: flex;
  gap: 4px;
  z-index: 5;
}

/* One centred column. Every child is width:100% of it, so nothing can sit on
   a different axis from anything else. */
.title-inner {
  display: grid;
  justify-items: center;
  align-content: center;
  gap: 14px;
  width: 100%;
  max-width: 340px;
  margin-inline: auto;
  text-align: center;
}
.title-inner > * { width: 100%; max-width: 100%; min-width: 0; }

.title-art {
  width: min(268px, 62vw);
  justify-self: center;
  border-radius: var(--r-lg);
  display: block;
  margin: 0 auto 4px;
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.8), 0 0 0 1px rgba(217, 164, 65, 0.3);
  animation: art-in 0.8s cubic-bezier(.2,.8,.3,1) both;
}
@keyframes art-in { from { opacity: 0; transform: translateY(20px) scale(.97); } to { opacity: 1; transform: none; } }



/* ==========================================================================
   GAME SCREEN — single column, board first
   ========================================================================== */

.game-screen { align-items: center; padding: 0; }

.game-inner {
  width: 100%;
  max-width: 660px;
  height: 100%;
  display: flex;
  flex-direction: column;
  padding: 0 14px 12px;
  gap: 10px;
}

/* --- top bar --- */

.bar {
  height: var(--bar-h);
  flex: none;
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
}

.brand {
  font-family: var(--display);
  font-size: 13px;
  font-weight: 900;
  letter-spacing: 0.22em;
  color: var(--gold-lt);
  white-space: nowrap;
}
.bar-spacer { flex: 1; }

/* --- player strip --- */

.seat-strip {
  flex: none;
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
}

.seat-chip {
  position: relative;
  width: 52px;
  height: 52px;
  flex: none;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 32%, rgba(255,255,255,.1), rgba(0,0,0,.42));
  border: 2px solid color-mix(in srgb, var(--seat) 55%, #0b0f17);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.14), 0 3px 10px rgba(0,0,0,.5);
  transition: border-color .2s, box-shadow .2s, transform .2s;
}
.seat-chip .avatar { width: 30px; height: 30px; flex: none; color: var(--seat); }
.seat-chip .avatar svg { width: 100%; height: 100%; display: block; }
.seat-chip.is-you {
  border-color: var(--seat);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.18), 0 0 0 2px rgba(255,255,255,.09), 0 3px 12px rgba(0,0,0,.55);
}
.seat-chip.is-you::after {
  content: '';
  position: absolute;
  inset: -6px;
  border-radius: 50%;
  border: 1px solid color-mix(in srgb, var(--seat) 45%, transparent);
}
.seat-chip.empty { opacity: .38; border-style: dashed; }

/* The lock badge doubles as the "has this player committed" signal. */
.seat-chip .lock-badge {
  position: absolute;
  right: -3px;
  bottom: -3px;
  width: 20px;
  height: 20px;
  padding: 3px;
  border-radius: 50%;
  background: #10151f;
  border: 1px solid var(--line);
  color: var(--muted);
  opacity: 0;
  transition: opacity .2s, color .2s, transform .2s, border-color .2s;
}
.seat-chip .lock-badge svg { width: 100%; height: 100%; display: block; }
.seat-chip.pending .lock-badge { opacity: .55; }
.seat-chip.locked { box-shadow: inset 0 1px 0 rgba(255,255,255,.18), 0 0 14px color-mix(in srgb, var(--seat) 50%, transparent); }
.seat-chip.locked .lock-badge { opacity: 1; color: #0b0f17; background: var(--seat); border-color: var(--seat); }
.seat-chip.thinking .avatar { animation: think 1.3s ease-in-out infinite; }
@keyframes think { 0%,100% { opacity: .45; } 50% { opacity: 1; } }

/* --- timer --- */

.timer {
  flex: none;
  position: relative;
  width: 44px;
  height: 44px;
}
.timer svg { transform: rotate(-90deg); width: 100%; height: 100%; }
.timer .track { stroke: rgba(255,255,255,.08); }
.timer .fill { stroke: var(--gold); stroke-linecap: round; transition: stroke-dashoffset .25s linear, stroke .3s; }
.timer .digits {
  position: absolute; inset: 0; display: grid; place-items: center;
  font-family: var(--mono); font-size: 15px; color: var(--silver);
}
.timer.urgent .fill { stroke: var(--danger); }
.timer.urgent .digits { color: var(--danger); animation: urgent-pulse .9s ease-in-out infinite; }
@keyframes urgent-pulse { 0%,100% { opacity: 1; } 50% { opacity: .45; } }

/* --- board --- */

.board-wrap {
  flex: 1;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
}

/* Carved stone frame with a struck-gold inlay, as on the key art. */
.board-plate {
  position: relative;
  width: min(100%, calc(100vh - 240px));
  aspect-ratio: 1;
  max-height: 100%;
  padding: 13px;
  border-radius: var(--r-lg);
  background:
    linear-gradient(158deg, #39445c 0%, #232c3e 38%, #161c29 68%, #2d3749 100%);
  box-shadow:
    var(--shadow),
    inset 0 1px 0 rgba(255, 255, 255, 0.09),
    inset 0 -2px 5px rgba(0, 0, 0, 0.55);
}
/* outer gold hairline */
.board-plate::before {
  content: '';
  position: absolute; inset: 0;
  border-radius: var(--r-lg);
  padding: 1.5px;
  background: linear-gradient(150deg, #f7dda0, #9c7526 30%, #4a3814 55%, #d9a441 80%, #f7dda0);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
  pointer-events: none;
}
/* inner bevel that seats the playfield into the frame */
.board-plate::after {
  content: '';
  position: absolute; inset: 10px;
  border-radius: calc(var(--r-md) + 2px);
  pointer-events: none;
  box-shadow:
    0 0 0 1px rgba(217, 164, 65, 0.55),
    0 0 0 3px rgba(0, 0, 0, 0.5),
    inset 0 2px 9px rgba(0, 0, 0, 0.75);
  z-index: 9;
}

.board {
  position: relative;
  width: 100%;
  height: 100%;
  border-radius: var(--r-md);
  overflow: hidden;
  background: linear-gradient(150deg, #1a2130, #10151f 55%, #182030);
  touch-action: manipulation;
  container-type: inline-size;
}

.board-cells {
  position: absolute; inset: 0;
  display: grid;
  grid-template-columns: repeat(var(--cols, 12), 1fr);
  grid-template-rows: repeat(var(--rows, 12), 1fr);
}

.cell {
  position: relative;
  border-right: 1px solid rgba(150, 178, 220, 0.16);
  border-bottom: 1px solid rgba(150, 178, 220, 0.16);
}
.cell:nth-child(odd) { background: rgba(255, 255, 255, 0.018); }
/* the outer ring where no castle or treasure may ever sit */
.cell.edge-band {
  background: rgba(0, 0, 0, 0.3);
  border-color: rgba(150, 178, 220, 0.09);
}
.cell.edge-band:nth-child(odd) { background: rgba(0, 0, 0, 0.24); }

/* engraved centre-lines, like a surveyed stone floor */
.board-grid-lines {
  position: absolute; inset: 0;
  pointer-events: none;
  z-index: 1;
  background-image:
    linear-gradient(90deg, rgba(217,164,65,.22) 1px, transparent 1px),
    linear-gradient(rgba(217,164,65,.22) 1px, transparent 1px);
  background-size: calc(100% / 4) calc(100% / 4);
  background-position: -1px -1px;
  opacity: .85;
}

/* the four stakeable cells */
.cell.target { cursor: pointer; }
.cell.target::after {
  content: '';
  position: absolute; inset: 9%;
  border: 1.5px solid color-mix(in srgb, var(--dir) 55%, transparent);
  border-radius: var(--r-sm);
  background: color-mix(in srgb, var(--dir) 9%, transparent);
  transition: background .16s, border-color .16s;
  animation: target-breathe 2.4s ease-in-out infinite;
}
@keyframes target-breathe {
  0%,100% { opacity: .5; }
  50% { opacity: 1; }
}
.cell.target:hover::after { background: color-mix(in srgb, var(--dir) 26%, transparent); }
.cell.target.staked::after {
  background: color-mix(in srgb, var(--dir) 22%, transparent);
  border-color: var(--dir);
  animation: none;
  opacity: 1;
}

/* Direction hint chevron inside each stakeable cell */
.cell .dir-hint {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  color: var(--dir);
  opacity: .55;
  pointer-events: none;
  transition: opacity .16s;
}
.cell .dir-hint svg { width: 44%; height: 44%; display: block; }
.cell.staked .dir-hint { opacity: 0; }

/* Coin stack rendered on a staked cell */
.coin-stack {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  pointer-events: none;
}
.coin-stack .count {
  position: absolute;
  right: 2%;
  bottom: 2%;
  min-width: 44%;
  padding: 4% 8%;
  border-radius: 99px;
  background: #0b0f17;
  border: 1.5px solid var(--gold-lt);
  font-family: var(--mono);
  font-weight: 700;
  font-size: clamp(10px, 3.1cqw, 18px);
  line-height: 1.15;
  color: var(--gold-lt);
  z-index: 3;
  box-shadow: 0 2px 6px rgba(0,0,0,.8);
}
.coin-stack .disc {
  position: absolute;
  width: 84%; height: 84%;
  display: grid; place-items: center;
  filter: drop-shadow(0 2px 4px rgba(0,0,0,.6));
  animation: coin-drop .22s cubic-bezier(.3,1.5,.5,1) both;
}
.coin-stack .disc svg { width: 100%; height: 100%; display: block; }
@keyframes coin-drop {
  from { transform: translateY(-70%) scale(.6); opacity: 0; }
  to { transform: none; opacity: 1; }
}

.board-overlay { position: absolute; inset: 0; pointer-events: none; }

.marker {
  position: absolute;
  width: calc(100% / var(--cols, 12));
  height: calc(100% / var(--rows, 12));
  left: calc(var(--c) * 100% / var(--cols, 12));
  top: calc(var(--r) * 100% / var(--rows, 12));
  display: grid;
  place-items: center;
}

.queen { z-index: 8; }
.queen.armed { pointer-events: auto; cursor: pointer; }
/**
 * The "ready to lock" ring extends beyond the queen's own cell. It must never
 * take pointer events, or it swallows clicks aimed at the cells beside her —
 * which is exactly why some directions stopped accepting coins.
 */
.queen.armed::after {
  content: '';
  position: absolute;
  inset: -14%;
  border-radius: 50%;
  border: 2px dashed rgba(255, 226, 150, .55);
  animation: arm-spin 9s linear infinite;
  pointer-events: none;
}
/* Only the queen artwork itself is clickable, and only within her own cell. */
.queen.armed svg { pointer-events: auto; cursor: pointer; }
.queen.armed { pointer-events: none; }
.queen .queen-glow { pointer-events: none; }
.queen.armed:hover::after { border-color: var(--gold-lt); border-style: solid; }
@keyframes arm-spin { to { transform: rotate(360deg); } }
.queen svg { width: 84%; height: 84%; filter: drop-shadow(0 0 10px rgba(255,220,140,.95)); }
.queen.stepping svg { animation: queen-hop .26s ease-out; }
@keyframes queen-hop {
  0% { transform: scale(1); }
  45% { transform: translateY(-14%) scale(1.09); }
  100% { transform: scale(1); }
}
.queen-glow {
  position: absolute; inset: -25%;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255,227,150,.34), transparent 65%);
  animation: glow-pulse 2.8s ease-in-out infinite;
}
@keyframes glow-pulse { 0%,100% { opacity: .5; transform: scale(.92); } 50% { opacity: 1; transform: scale(1.08); } }

.castle-mark { z-index: 4; }
.castle-mark svg { width: 76%; height: 76%; }
.castle-mark.mine svg { filter: drop-shadow(0 0 8px currentColor); }
.castle-mark.win svg { animation: castle-win 1s ease-in-out infinite alternate; }
@keyframes castle-win { from { transform: scale(1); } to { transform: scale(1.14); } }

/* Bonus treasure stack — value shown on the coins, no prose needed */
.bonus-mark { z-index: 5; }
.bonus-pile {
  position: relative;
  width: 80%; height: 80%;
  display: grid; place-items: center;
}
.bonus-pile .glow {
  position: absolute; inset: -18%;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255,215,120,.42), transparent 66%);
  animation: glow-pulse 2.2s ease-in-out infinite;
}
.bonus-pile svg { width: 100%; height: 100%; position: relative; }
.bonus-pile .value {
  position: absolute;
  bottom: -4%;
  font-family: var(--mono);
  font-weight: 700;
  font-size: clamp(9px, 2.2cqw, 14px);
  color: var(--gold-lt);
  text-shadow: 0 1px 4px #000, 0 0 8px rgba(0,0,0,.9);
  z-index: 3;
}
.bonus-mark.fading .bonus-pile { filter: saturate(.55) brightness(.72); }
.bonus-mark.claimed { animation: claim 0.75s ease-out forwards; }
@keyframes claim {
  0% { transform: scale(1); opacity: 1; }
  40% { transform: scale(1.45); opacity: 1; }
  100% { transform: scale(.3) translateY(-60%); opacity: 0; }
}

/* replay-only: ownership ring around a historical bonus */
.bonus-ring {
  position: absolute;
  inset: 12%;
  border-radius: 50%;
  border: 2px solid var(--seat);
  box-shadow: 0 0 10px color-mix(in srgb, var(--seat) 60%, transparent);
  opacity: .85;
}

.path-layer { position: absolute; inset: 0; pointer-events: none; z-index: 3; }

/**
 * The boundary flash is a decorative strip laid along whichever wall the queen
 * hit. It is `position:absolute` with inline geometry, so it keeps covering
 * ~10% of the board along that wall long after the animation has faded to
 * opacity 0 — and at z-index 6 it sits ABOVE .board-cells.
 *
 * Without `pointer-events: none` it therefore eats every click aimed at the
 * cells beside the queen once she is standing against that wall, which is
 * exactly the "cannot stake in the legal directions next to a wall" bug.
 * An invisible decoration must never be able to take a pointer event.
 */
.wall-flash { position: absolute; opacity: 0; z-index: 6; pointer-events: none; }
.wall-flash.fire { animation: wall-hit .6s ease-out; }
@keyframes wall-hit { 0% { opacity: .95; } 100% { opacity: 0; } }

/* --- pre-game overlay --- */

.pregame {
  position: absolute; inset: 0;
  z-index: 20;
  display: grid;
  place-items: center;
  background: radial-gradient(circle at 50% 45%, rgba(12,16,24,.5), rgba(8,11,17,.9));
  backdrop-filter: blur(2px);
  padding: 18px;
  text-align: center;
}
.pregame-inner { display: grid; gap: 16px; justify-items: center; max-width: 330px; width: 100%; }
.pregame .lede { font-size: 14px; color: var(--silver-dim); line-height: 1.45; }

/* --- action row under the board --- */

/* The seat strip carries identity, timer and purse. */
.seat-strip { justify-content: center; }
.seat-group { display: flex; align-items: center; gap: 9px; }

.purse {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 6px 13px 6px 7px;
  border-radius: 99px;
  background: linear-gradient(180deg, rgba(255,255,255,.06), rgba(0,0,0,.34));
  border: 1px solid var(--line);
  flex: none;
}
.purse .coin-icon { width: 26px; height: 26px; flex: none; }
.purse .coin-icon svg { width: 100%; height: 100%; display: block; }
.purse .value { font-family: var(--mono); font-size: 19px; color: var(--gold-lt); line-height: 1; }

.purse.spending .value { animation: spend 0.5s ease; }
@keyframes spend { 0% { color: var(--danger); transform: scale(1.16); } 100% { color: var(--gold-lt); } }
.purse.gaining .value { animation: gain 0.7s ease; }
@keyframes gain { 0% { color: var(--ok); transform: scale(1.3); } 100% { color: var(--gold-lt); } }


/* --- status line --- */

.status {
  flex: none;
  min-height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  font-size: 14.5px;
  color: var(--silver-dim);
  width: 100%;
  padding: 0 4px;
}
.status b { color: var(--gold-lt); font-weight: 600; }
.status .verdict {
  font-family: var(--display);
  font-size: 15px;
  letter-spacing: .05em;
  color: var(--silver);
  animation: verdict-in .35s ease both;
}
@keyframes verdict-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }

/* ==========================================================================
   RESULT SCREEN
   ========================================================================== */

.result-screen { align-items: center; }
.result-inner {
  width: 100%; max-width: 660px; height: 100%;
  display: flex; flex-direction: column; gap: 10px; padding: 0 14px 12px;
}

.winner-line {
  flex: none;
  display: flex; align-items: center; justify-content: center; gap: 13px;
  padding: 4px 0 0;
}
.winner-line .avatar { width: 44px; height: 44px; color: var(--seat); flex: none; }
.winner-line .avatar svg { width: 100%; height: 100%; }
.winner-line h2 { font-size: clamp(20px, 5vw, 29px); color: var(--gold-lt); letter-spacing: .04em; }

.result-stats {
  flex: none;
  display: flex; justify-content: center; gap: 20px;
  font-size: 13px; color: var(--muted);
}
.result-stats b { font-family: var(--mono); color: var(--silver); font-size: 15px; font-weight: 500; }

.replay-bar {
  flex: none;
  display: flex; align-items: center; gap: 11px; width: 100%;
}
.replay-bar input[type='range'] { flex: 1; accent-color: var(--gold); min-width: 0; }
.replay-bar .round-label {
  font-family: var(--mono); font-size: 12px; color: var(--muted);
  min-width: 74px; text-align: right;
}

/* ==========================================================================
   MODAL
   ========================================================================== */

.modal {
  position: fixed; inset: 0; z-index: 100;
  display: grid; place-items: center;
  background: rgba(5, 8, 13, .88);
  backdrop-filter: blur(8px);
  padding: 20px;
  animation: fade-in .2s ease both;
}
.modal-card {
  width: min(560px, 100%);
  max-height: 86vh;
  overflow-y: auto;
  padding: 26px;
  border-radius: var(--r-lg);
  background: linear-gradient(180deg, var(--stone-700), var(--stone-900));
  border: 1px solid var(--line);
  box-shadow: var(--shadow);
}
.modal-card h2 { font-size: 19px; margin-bottom: 6px; }
.modal-card h4 {
  font-size: 11px; letter-spacing: .18em; text-transform: uppercase;
  color: var(--gold); margin: 19px 0 6px;
}
.modal-card p, .modal-card li { font-size: 14.5px; color: var(--silver-dim); }
.modal-card ul { padding-left: 19px; margin: 5px 0; }
.modal-card li { margin-bottom: 4px; }
.modal-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 4px; }

.rule-demo {
  background: rgba(0,0,0,.34);
  border: 1px solid var(--line);
  border-left: 2px solid var(--gold);
  border-radius: var(--r-sm);
  padding: 12px 14px;
  margin: 11px 0;
  font-size: 14px;
}

/* themed code entry */
.code-input {
  width: 100%;
  margin: 14px 0 4px;
  padding: 15px 17px;
  border-radius: var(--r-md);
  background: rgba(0,0,0,.45);
  border: 1px solid var(--line);
  color: var(--gold-lt);
  font-family: var(--mono);
  font-size: 20px;
  letter-spacing: .18em;
  text-align: center;
  text-transform: uppercase;
  transition: border-color .18s, box-shadow .18s;
}
.code-input::placeholder { color: var(--muted); letter-spacing: .12em; }
.code-input:focus {
  outline: none;
  border-color: var(--gold);
  box-shadow: 0 0 0 3px rgba(217,164,65,.16), inset 0 0 22px rgba(217,164,65,.09);
}
.modal-actions { display: flex; gap: 9px; justify-content: flex-end; margin-top: 16px; }

/* ==========================================================================
   TOASTS
   ========================================================================== */

.toast-stack {
  position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%);
  display: grid; gap: 7px; z-index: 90; pointer-events: none;
  width: min(400px, calc(100vw - 28px));
}
.toast {
  padding: 11px 17px;
  border-radius: var(--r-md);
  background: linear-gradient(180deg, var(--stone-700), var(--stone-900));
  border: 1px solid var(--line);
  box-shadow: var(--shadow);
  font-size: 14px; text-align: center;
  animation: toast-in .26s ease both;
}
.toast.gold { border-color: var(--gold); color: var(--gold-lt); }
.toast.bad { border-color: var(--danger); color: #ffb0b2; }
@keyframes toast-in { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }

/* ==========================================================================
   RESPONSIVE
   ========================================================================== */

@media (max-width: 620px) {
  :root { --bar-h: 46px; }
  .game-inner, .result-inner { padding: 0 9px 9px; gap: 8px; }
  .board-plate { width: 100%; padding: 6px; }
  .seat-chip { width: 44px; height: 44px; }
  .seat-chip .avatar { width: 25px; height: 25px; }
  .seat-chip .lock-badge { width: 17px; height: 17px; }
  .purse { padding: 5px 10px 5px 5px; }
  .purse .value { font-size: 17px; }
  .seat-group { gap: 6px; }
  .brand { font-size: 11px; letter-spacing: .16em; }
  .btn { padding: 12px 18px; }
  .status { font-size: 13.5px; min-height: 30px; }
  .result-stats { gap: 13px; font-size: 12px; }
}

@media (max-height: 760px) {
  .title-screen { padding-top: 46px; }
  .title-art { width: min(180px, 40vw); }
  .title-inner { gap: 10px; }
  .code-value { padding: 8px 6px; }
  .room-seats { gap: 9px; }
  .room-seats .seat-chip { width: 46px; height: 46px; }
}

/* ==========================================================================
   START SCREEN
   ========================================================================== */

/* Always a single row of four. Never allowed to wrap into a column. */
.room-seats {
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  gap: 12px;
  justify-content: center;
  align-items: center;
}
.room-seats .seat-chip { flex: 0 0 auto; }
/* Hold the row's height whatever the seats currently contain, so swapping a
   bot for a person never nudges the layout. */
.room-seats { min-height: 52px; }
@media (max-height: 760px) { .room-seats { min-height: 46px; } }

/**
 * Reserved space, not measured space.
 *
 * Lobby messages run from four words to a full sentence, and on a phone the
 * same sentence wraps to three lines where it takes one on a laptop. Letting
 * this box size itself meant the code, the buttons and the humans-only
 * checkbox all jumped up and down every time the lobby changed — worst of all
 * at the moment a player joins, which should feel like an arrival rather than
 * a lurch. The height is now fixed and the text is centred inside it, so
 * nothing below ever moves.
 */
.room-status {
  margin: 0;
  font-size: 13.5px;
  color: var(--silver-dim);
  line-height: 1.4;
  min-height: calc(1.4em * 2);
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
}
/* Narrow phones wrap the longer notices onto a third line. */
@media (max-width: 430px) {
  .room-status { min-height: calc(1.4em * 3); }
}
.room-status.error { color: #ffb0b2; }
.room-status.waiting { color: var(--gold-lt); }

/* the game code is itself the copy control */
.code-value {
  font-family: var(--mono);
  font-size: clamp(18px, 5.6vw, 25px);
  letter-spacing: .18em;
  color: var(--gold-lt);
  padding: 11px 8px;
  border-radius: var(--r-md);
  border: 1px dashed rgba(217,164,65,.45);
  background: rgba(217,164,65,.06);
  transition: background .15s, border-color .15s, transform .12s, color .15s;
}
.code-value:hover { background: rgba(217,164,65,.14); border-color: var(--gold); }
.code-value:active { transform: scale(.98); }
.code-value.copied { border-style: solid; border-color: var(--ok); color: var(--ok); }

.room-actions { display: flex; gap: 7px; }
.room-actions .btn { flex: 1; min-width: 0; padding-inline: 6px; }

/* a seat waiting to be claimed pulses gently */
.seat-chip.waiting { animation: seat-wait 2s ease-in-out infinite; }
@keyframes seat-wait { 0%,100% { opacity: .45; } 50% { opacity: .9; } }
.seat-chip.joined { animation: seat-pop .45s cubic-bezier(.3,1.6,.5,1) both; }
@keyframes seat-pop { 0% { transform: scale(.5); } 60% { transform: scale(1.14); } 100% { transform: scale(1); } }

/* result stats reuse the bottom message strip */
#result-status { color: var(--muted); font-size: 13.5px; }
#result-status b { font-family: var(--mono); color: var(--silver); font-weight: 500; }
#result-status .stat { margin: 0 9px; }

/* --- humans-only toggle --- */
.humans-only {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  font-size: 13.5px;
  color: var(--silver-dim);
  cursor: pointer;
  user-select: none;
  padding: 2px 0;
}
.humans-only input { accent-color: var(--gold); width: 16px; height: 16px; cursor: pointer; }
.humans-only:hover { color: var(--silver); }

/* an open seat waiting for a person, rather than a bot that will fill it */
.seat-chip.open-seat {
  border-style: dashed;
  background: transparent;
  opacity: .7;
}
.seat-chip.open-seat .avatar { opacity: .55; }

/* We have not heard from the server yet, so this seat's occupant is unknown.
   It must not read as a person or as a bot — both would be a guess. */
.seat-chip.unknown {
  border-style: dotted;
  background: transparent;
  opacity: .4;
}
.seat-chip.unknown .avatar { opacity: .4; }

/* The replay queen sits on a dark plinth so the bright trail cannot wash her
   out into a ghost. */
.queen .queen-plinth {
  position: absolute;
  width: 62%;
  height: 62%;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(10,14,22,.95), rgba(10,14,22,.55) 70%, transparent);
  z-index: 0;
}
.queen svg { position: relative; z-index: 1; }
.queen.solid svg { filter: drop-shadow(0 2px 5px rgba(0,0,0,.9)) drop-shadow(0 0 8px rgba(255,220,140,.85)); }

/* --- help sheet typography --- */
.lede-quote {
  font-family: var(--display);
  font-size: 14px !important;
  letter-spacing: .04em;
  color: var(--gold-lt) !important;
  border-bottom: 1px solid var(--line);
  padding-bottom: 14px;
  margin: 0 0 16px;
}
.modal-card p { margin: 0 0 11px; line-height: 1.6; }
.modal-card strong { color: var(--silver); }
.modal-card em { color: var(--gold-lt); font-style: italic; }
.modal-card .aside {
  color: var(--muted) !important;
  font-style: italic;
  border-left: 2px solid var(--gold-dk);
  padding-left: 12px;
}
.modal-card .sign-off {
  margin-top: 20px;
  padding-top: 15px;
  border-top: 1px solid var(--line);
  font-family: var(--display);
  font-size: 13px !important;
  letter-spacing: .05em;
  color: var(--gold-lt) !important;
  text-align: center;
}

/* A seat whose player left a humans-only game. Nobody is covering it, so it
   must read as neither an active player nor a bot. */
.seat-chip.retired { opacity: .32; filter: grayscale(1); }
.seat-chip.retired .lock-badge { display: none; }
