/* A Way Back Home — this game's skin, and nothing else.
 *
 * The header, start screen, log panel, dialog shell and fonts come from games/core/deckades.css,
 * linked BEFORE this file. What this sheet sets of the shared chrome it sets BY TOKEN — the
 * --dk-* values below are all documented in that sheet — never by selector; everything else here
 * is about THIS table: the boards, the pool, the bag, the tray.
 *
 * Greppable check:  grep -nE "#header-bar|\.deckades-logo|\.start-card|#ai-indicator" style.css
 * must return nothing.
 */

:root {
  /* Night sky and crystal light: the board is a deep blue dusk, the accent is the pale
     crystal glow at its centre, gold is the one colour that means "you may tap this". */
  --wb-sky: #182552;
  --wb-glow: #9fd8ff;
  --wb-glow-rgb: 159 216 255;
  --wb-gold: #ffe27a;
  --wb-gold-rgb: 255 226 122;
  --wb-ink: #eef4ff;
  --wb-ink-dim: rgba(238, 244, 255, 0.64);
  --wb-plate: rgba(12, 19, 46, 0.72);
  --wb-plate-line: rgba(var(--wb-glow-rgb) / 0.22);
  --wb-shadow: 0 10px 28px rgba(2, 6, 20, 0.55);

  --dk-accent: var(--wb-glow);
  --dk-accent-soft: rgba(var(--wb-glow-rgb) / 0.36);
  --dk-tint: rgba(48, 84, 170, 0.34);
  /* The shared header's documented opt-in: below 820px the four-word name runs under the
     tool buttons, so it yields there (it is still the title, the tab and the start card). */
  --dk-header-title-narrow: none;

  /* ── The start screen, the Orléans / Joan way ─────────────────────────────────────────
     The box cover is the hero and stays sharp; the card sits in the middle of it; the header
     goes, it is unreachable behind the card anyway. Every value is a documented --dk-start-*
     token; the scrim is a light gradient so the card's text has its own ground. */
  --dk-start-scrim: linear-gradient(180deg, rgba(8, 12, 30, 0.06) 0%, rgba(8, 12, 30, 0.30) 100%);
  --dk-start-blur: none;
  --dk-start-header: none;
  --dk-start-place: center;
  --dk-start-inset: 16px 0;
  --dk-start-origin: center;
  --dk-start-surface: linear-gradient(176deg, rgba(16, 24, 58, 0.94), rgba(10, 15, 40, 0.97));
  --dk-start-edge: rgba(var(--wb-glow-rgb) / 0.42);
  --dk-start-glow: 0 0 0 1px rgba(var(--wb-glow-rgb) / 0.12), 0 24px 60px rgba(2, 6, 20, 0.7);

  /* ── Dialogs, the log, the rules: the same night as the table, not the platform's violet.
     All documented --dk-* tokens (the list in deckades.css: dialog, panel, scrim, field). */
  --dk-dialog-top:    #14224f;
  --dk-dialog-bottom: #0b1332;
  --dk-dialog-line:   rgba(var(--wb-glow-rgb) / 0.42);
  --dk-panel:         #0c1637;
  --dk-panel-line:    rgba(var(--wb-glow-rgb) / 0.28);
  --dk-panel-text:    rgba(238, 244, 255, 0.92);
  --dk-panel-dim:     rgba(238, 244, 255, 0.58);
  --dk-scrim:         rgba(3, 6, 20, 0.78);
  --dk-field-bg:      #0f1c44;
  --dk-field-line:    #2c4685;
}

/* --------------------------------------------------- the cover, behind the start screen */
/* Positioned so the lantern on the hill is what the top half of the screen shows; the card
   covers the lettering below it and carries the title itself. */
body::before {
  content: '';
  position: fixed; inset: 0;
  background: #0d1430 url('assets/cover.webp') center 55% / cover no-repeat;
  pointer-events: none;
  z-index: -2;
}
body::after {
  content: '';
  position: fixed; inset: 0;
  background: radial-gradient(ellipse at 62% 30%, rgba(13, 20, 48, 0), rgba(13, 20, 48, 0.28) 80%);
  pointer-events: none;
  z-index: -1;
}
body:has(#start-screen:not(.hidden)) #game { visibility: hidden; }

/* the publisher line at the foot of the start card: the shared hint style, plus a link colour */
.wb-support a { color: var(--wb-glow); text-decoration: underline; text-underline-offset: 3px; opacity: 0.85; }
.wb-support a:hover { opacity: 1; }

/* --------------------------------------------------------------------------- the table */
/* The cover IS the table: the same night the start screen showed, dimmed to a ground the
   boards can sit on, with the silk of the sky (sky.js) moving faintly over it. */
#game {
  position: absolute;
  inset: var(--dk-header-h, 52px) 0 0 0;
  min-height: 0;
  overflow: hidden;
  font-family: var(--dk-font-ui);
  color: var(--wb-ink);
  background:
    linear-gradient(180deg, rgba(8, 12, 32, 0.78), rgba(6, 10, 26, 0.88)),
    #0d1430 url('assets/cover.webp') center 30% / cover no-repeat fixed;
}
#sky { position: absolute; inset: 0; pointer-events: none; z-index: 0; }
#sky-ripple { width: 100%; height: 100%; display: block; }

#table {
  position: relative; z-index: 1;
  height: 100%;
  display: grid;
  grid-template-columns: minmax(0, 1fr) clamp(240px, 27vw, 380px);
  grid-template-rows: auto minmax(0, 1fr) auto;
  gap: 10px 14px;
  padding: 10px 14px 12px;
  box-sizing: border-box;
}
#middle        { grid-column: 1; grid-row: 1; }
#my-board-wrap { grid-column: 1; grid-row: 2; }
#my-side       { grid-column: 1; grid-row: 3; }
#opponents     { grid-column: 2; grid-row: 1 / 4; }

.strip-title {
  font-size: 11px; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--wb-ink-dim);
}

/* --------------------------------------------------------------- the pool and the prompt */
/* Only as wide as the pool, the prompt and its buttons need: a plate that ran the whole row
   was a bar with nothing in its right half. It sits at the left edge of the board's column. */
#middle {
  display: grid; grid-template-columns: auto auto; grid-template-rows: auto auto; gap: 4px 16px; align-items: center;
  justify-self: center; width: fit-content; max-width: 100%;
  padding: 6px 14px 8px 12px;
  background: var(--wb-plate);
  border: 1px solid var(--wb-plate-line);
  border-radius: 14px;
  box-shadow: var(--wb-shadow);
}
#pool { display: flex; align-items: center; gap: 10px; }
#pool-title { writing-mode: vertical-rl; transform: rotate(180deg); line-height: 1; padding: 2px 0; }
#pool-stacks { display: flex; gap: 8px; align-items: flex-end; position: relative; padding-bottom: 8px; }
/* the shelf the piles stand on */
#pool-stacks::after {
  content: ''; position: absolute; left: -2px; right: -2px; bottom: 0; height: 2px;
  background: linear-gradient(90deg, transparent, rgba(var(--wb-glow-rgb) / 0.45), transparent);
  border-radius: 2px;
}
/* Side B: the character tile stands at the left end of the shelf — its art while the
   tile can still be won, the "1VP" back once a seat holds it (the physical tile is
   flipped), greyed in the box. The haul is the strip where a pick lands until the take is
   complete: it appears only while a haul is in progress, so the shelf never changes width
   for nothing. */
.wb-tile { display: flex; align-items: center; gap: 8px; max-width: 240px; padding: 4px 8px 4px 4px; border-radius: 10px;
  background: rgba(var(--wb-glow-rgb) / 0.08); border: 1px solid rgba(var(--wb-glow-rgb) / 0.22); }
.wb-tile-art { width: 40px; height: 59px; border-radius: 4px; object-fit: cover; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.45); flex: 0 0 auto; }
.wb-tile.pool .wb-tile-art { box-shadow: 0 0 0 2px var(--wb-gold), 0 2px 10px rgba(0, 0, 0, 0.45); }
.wb-tile.box { opacity: 0.55; }
.wb-tile.box .wb-tile-art { filter: grayscale(1); }
.wb-tile-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.wb-tile-name { font-weight: 700; font-size: 13px; white-space: nowrap; }
.wb-tile-line { font-size: 11px; color: var(--wb-ink-dim); line-height: 1.25; }
.wb-tile-seeks { font-size: 11px; color: var(--wb-ink-dim); line-height: 1.25; }
#haul { display: flex; align-items: center; gap: 6px; padding: 4px 8px; border-radius: 10px;
  background: rgba(var(--wb-gold-rgb) / 0.10); border: 1px dashed rgba(var(--wb-gold-rgb) / 0.5); }
#haul[hidden] { display: none; }
.haul-gems { display: flex; gap: 2px; align-items: center; }
/* the "+1" a seat wears while it holds the tile */
.tile-badge { display: inline-flex; align-items: center; justify-content: center; min-width: 22px; height: 18px; padding: 0 5px;
  border-radius: 9px; font-size: 11px; font-weight: 700; color: #1a1408; background: var(--wb-gold); margin-left: 6px; flex: 0 0 auto; }
.res-tile { display: inline-flex; align-items: center; justify-content: center; min-width: 26px; height: 22px; border-radius: 11px;
  font-size: 12px; font-weight: 700; color: #1a1408; background: var(--wb-gold); }
/* the building the character seeks, while the tile is in the pool */
.wb-board .seek-ring { animation: wb-pulse 2.4s ease-in-out infinite; }
.wb-board.compact .seek-ring { animation: none; }

/* Each pile is a glass button in its own colour (core/glassButton.css; the wrap carries
   --gb-tint). The capsule stands upright: the pile of gems above, the count below. */
.stack .gb { width: 52px; height: 76px; min-height: 0; padding: 0; }
.stack .gb-text { flex-direction: column; gap: 3px; }
.stack .pile { position: relative; width: 24px; height: 44px; }
.stack .pile .gem-icon {
  position: absolute; left: 0;
  bottom: calc(var(--k, 0) * 6px);
  transform: translateX(calc(var(--j, 0) * 1.5px)) rotate(calc(var(--j, 0) * 6deg));
  filter: drop-shadow(0 2px 2px rgba(0, 0, 0, 0.45));
}
.stack .pile .gem-icon.ghosted { opacity: 0.28; filter: none; }
.stack-n {
  font-size: 12px; font-weight: 700; line-height: 1; color: var(--wb-ink);
  font-variant-numeric: tabular-nums;
}
.stack.empty .stack-n { color: var(--wb-ink-dim); }


/* The button stands beside the piles and the prompt runs under them, so the plate is the
   piles' width plus one button — and STAYS that width: the prompt is a line inside it, not
   a column beside it, so nothing shifts as the wording changes turn by turn. #status
   dissolves (display: contents) and its two children take their own grid cells. */
#status { display: contents; }
#status-text { grid-column: 1 / 3; grid-row: 2; font-size: 14px; line-height: 1.3; color: var(--wb-ink-dim); min-height: 1.3em; }
#status-text.mine { color: var(--wb-ink); }
/* The last-turn warning ahead of the prompt: a gold pill, and on the human's OWN last turn a
   lit one that breathes — the one line in the game that must not be read as routine. */
.wb-warn {
  display: inline-block; margin: 0 8px 2px 0; padding: 1px 8px; border-radius: 8px;
  font-size: 12px; font-weight: 600; color: var(--wb-gold);
  background: rgba(var(--wb-gold-rgb) / 0.10); border: 1px solid rgba(var(--wb-gold-rgb) / 0.45);
}
.wb-warn.mine {
  font-size: 13px; font-weight: 700; color: #1a1408; background: var(--wb-gold);
  box-shadow: 0 0 0 0 rgba(var(--wb-gold-rgb) / 0.6);
  animation: wb-warn-breathe 1.6s ease-in-out infinite;
}
@keyframes wb-warn-breathe { 0%, 100% { box-shadow: 0 0 0 0 rgba(var(--wb-gold-rgb) / 0.55); } 50% { box-shadow: 0 0 0 5px rgba(var(--wb-gold-rgb) / 0); } }
/* The table's controls are glass buttons (core/glassButton.css), tinted with this table's
   glow and shaded with its night; the pool under each pane needs a little room below. */
:root { --gb-tint: var(--wb-glow-rgb); --gb-ink: var(--wb-ink); --gb-shade: 2 6 20; }
/* The button's cell is reserved even while there is no button (the opponents' turns), so the
   plate is the same width on every turn. */
#actions { grid-column: 2; grid-row: 1; display: flex; gap: 10px; align-items: center; justify-content: flex-end; align-self: center; margin-bottom: 8px; min-width: 112px; min-height: 44px; }
.wb-dialog-actions { display: flex; flex-direction: column; gap: 12px; margin-top: 18px; }
.wb-dialog-actions.row { flex-direction: row; justify-content: center; flex-wrap: wrap; }
.wb-dialog-actions.row .gb-wrap { flex: 1 1 160px; }
.wb-dialog-actions.row .gb-wrap .gb { width: 100%; }

/* ── Call the end: the standings above the question ─────────────────────────────────── */
.wb-declare { width: min(460px, 94vw); }
.wb-standings { display: flex; flex-direction: column; gap: 4px; margin: 4px 0 10px; }
.wb-standing {
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  padding: 6px 12px; border-radius: 10px;
  background: rgba(255, 255, 255, 0.04);
}
.wb-standing.me { background: rgba(var(--wb-gold-rgb) / 0.12); box-shadow: inset 0 0 0 1px rgba(var(--wb-gold-rgb) / 0.45); }
.wb-standing-name { font-weight: 600; font-size: 15px; }
.wb-standing.me .wb-standing-name { color: var(--wb-gold); }
.wb-standing-total { font-family: var(--dk-font-display); font-size: 24px; line-height: 1; font-weight: 700; color: var(--wb-glow); font-variant-numeric: tabular-nums; }
.wb-standing-total.neg { color: #ffb59f; }
.wb-verdict { font-family: var(--dk-font-display); font-size: 20px; font-weight: 600; margin: 2px 0 8px; color: var(--wb-ink); }
.wb-verdict.good { color: #9fe8b0; }
.wb-verdict.bad { color: #ffb59f; }
.wb-declare-body { color: var(--dk-panel-dim); font-size: 14px; line-height: 1.5; }

/* ── The rules: a column with a scrolling body and buttons that stay on screen ───────── */
.wb-rules {
  width: min(680px, 94vw);
  display: flex; flex-direction: column;
  text-align: left;
}
.wb-rules h2 { text-align: center; flex: 0 0 auto; }
.wb-rules-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding-right: 6px; scrollbar-width: thin; scrollbar-color: rgba(var(--wb-glow-rgb) / 0.35) transparent; }
.wb-rule { font-size: 15px; line-height: 1.6; margin: 0 0 12px; max-width: 68ch; }
.wb-rule-h { font-family: var(--dk-font-display); font-size: 17px; font-weight: 700; color: var(--wb-glow); margin-right: 6px; letter-spacing: 0.01em; }
.wb-rules .wb-dialog-actions { flex: 0 0 auto; margin-top: 14px; }

/* ------------------------------------------------------------------------- your board */
#my-board-wrap { position: relative; min-height: 0; min-width: 0; display: flex; align-items: center; justify-content: center; }
/* The last move, set in the sky at the top of the board in the display face: a line of
   light, not a label — no plate, a halo instead of a box, and it drifts in when it changes. */
#board-caption {
  position: absolute; z-index: 2; pointer-events: none;   /* the SVG's filter stacks it; stay above */
  display: flex; align-items: center; justify-content: center; text-align: center;
  font-family: var(--dk-font-display); font-weight: 600; letter-spacing: 0.03em; line-height: 1.25;
  color: #f2f7ff;
  text-shadow: 0 0 6px rgba(var(--wb-glow-rgb) / 0.9), 0 0 18px rgba(var(--wb-glow-rgb) / 0.45), 0 1px 2px rgba(0, 0, 0, 0.8);
  text-wrap: balance;
  overflow: hidden;
  opacity: 0.92;
}
#board-caption.show { animation: wb-caption 520ms cubic-bezier(.22,.75,.3,1) both; }
@keyframes wb-caption {
  from { opacity: 0; transform: translateY(6px); filter: blur(3px); }
  to   { opacity: 0.92; transform: none; filter: blur(0); }
}
#my-board-wrap svg { width: 100%; height: 100%; max-height: 100%; display: block; filter: drop-shadow(0 10px 24px rgba(2, 6, 20, 0.6)); }

/* ---------------------------------------------------------- your bag, tray and paths */
/* Like the top plate: only as wide as the bag, the tray and the six paths need, centred
   under the board. */
#my-side {
  display: flex; align-items: center; gap: 22px; min-height: 0; min-width: 0;
  justify-self: center; width: fit-content; max-width: 100%;
  background: var(--wb-plate);
  border: 1px solid var(--wb-plate-line);
  border-radius: 14px;
  box-shadow: var(--wb-shadow);
  padding: 8px 14px;
  box-sizing: border-box;
  transition: box-shadow 200ms, border-color 200ms;
}
#my-side.active { border-color: var(--wb-gold); box-shadow: 0 0 0 1px var(--wb-gold), 0 0 26px rgba(var(--wb-gold-rgb) / 0.22), var(--wb-shadow); }
#my-head { display: flex; align-items: center; }
#my-name { font-weight: 600; font-size: 15px; }

#my-bag { display: flex; align-items: center; gap: 12px; }
.pouch { position: relative; width: 34px; height: 38px; flex: 0 0 auto; }
.pouch.big { width: 50px; height: 56px; }
.pouch svg { width: 100%; height: 100%; display: block; filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.5)); }
/* the bag, shaken as a crystal is pulled out of it */
.pouch.shake { animation: wb-shake 320ms cubic-bezier(.36,.07,.19,.97); transform-origin: 50% 20%; }
@keyframes wb-shake {
  0%   { transform: rotate(0); }
  25%  { transform: rotate(-7deg) translateY(1px); }
  55%  { transform: rotate(6deg); }
  80%  { transform: rotate(-3deg); }
  100% { transform: rotate(0); }
}
.pouch-n {
  position: absolute; left: 50%; top: 58%; transform: translate(-50%, -50%);
  font-weight: 700; font-size: 13px; color: var(--wb-ink);
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.8);
  font-variant-numeric: tabular-nums;
}
.pouch.big .pouch-n { font-size: 17px; }
/* The game-over table still uses the dot for its column heads and cells. */
.dot {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 22px; height: 22px; padding: 0 4px; border-radius: 11px;
  background: var(--c); color: #0c1633; font-size: 12px; font-weight: 700;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.35);
  font-variant-numeric: tabular-nums;
}

#my-tray { display: flex; align-items: center; gap: 10px; min-height: 48px; }
.tray-slots { display: flex; gap: 6px; }
.tray-slot {
  width: 48px; height: 48px; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 11px; border: 1px solid transparent;
  background: rgba(255, 255, 255, 0.05);
  color: inherit; font: inherit; cursor: default;
  -webkit-tap-highlight-color: transparent;
  transition: opacity 150ms, transform 160ms cubic-bezier(.22,.75,.3,1), box-shadow 160ms;
}
.opp-tray .tray-slot { width: 24px; height: 24px; background: none; }
.tray-slot.can { cursor: pointer; border-color: var(--wb-glow); box-shadow: 0 0 0 1px rgba(var(--wb-glow-rgb) / 0.5), 0 0 14px rgba(var(--wb-glow-rgb) / 0.35); background: rgba(var(--wb-glow-rgb) / 0.10); }
.tray-slot.can:hover { transform: translateY(-2px); }
.tray-slot:focus-visible { outline: 2px solid var(--wb-gold); outline-offset: 2px; }
.tray-slot.sel { border-color: var(--wb-gold); box-shadow: 0 0 0 1px var(--wb-gold); background: rgba(var(--wb-gold-rgb) / 0.12); }
.tray-slot:disabled:not(.can) { opacity: 0.5; }
/* an empty place in the tray: the outline of where a crystal will land */
.tray-slot.vacant { background: none; border: 1px dashed rgba(var(--wb-glow-rgb) / 0.35); opacity: 1; }
.tray-slot.arriving, .tray-slot.gone { opacity: 0; }

/* The six paths and their sum: each path as the space it stands on — a disc in the path's
   colour with the value on it, drawn like the board's own spaces (white figure, dark
   halo, a thin inner ring) — then "=" and the total in the display face. */
#my-sum { display: flex; align-items: center; gap: 10px; }
#my-paths { display: flex; gap: 6px; transition: gap 160ms; }
/* the discs grow when a wild is choosing its path; give their gold rings room */
#my-paths:has(.can) { gap: 14px; padding: 0 4px; }
.path-chip {
  position: relative;
  width: 36px; height: 36px; padding: 0;
  border-radius: 50%; border: 0;
  background: radial-gradient(circle at 38% 32%, color-mix(in srgb, var(--c) 78%, #fff), var(--c) 55%, color-mix(in srgb, var(--c) 72%, #000));
  box-shadow: inset 0 0 0 1.5px rgba(255, 255, 255, 0.45), 0 2px 4px rgba(2, 6, 20, 0.5);
  color: #fff; font: inherit; font-weight: 700; font-size: 13px; line-height: 1;
  text-shadow: 0 0 2px rgba(0, 0, 0, 0.7), 0 1px 1px rgba(0, 0, 0, 0.6);
  cursor: default; -webkit-tap-highlight-color: transparent;
  font-variant-numeric: tabular-nums;
  transition: transform 160ms cubic-bezier(.22,.75,.3,1), box-shadow 160ms, filter 160ms;
}
.path-chip:disabled { opacity: 1; }
/* not started: the disc is still dark — nothing lit on that path yet */
.path-chip.unlit { filter: saturate(0.55) brightness(0.62); }
/* below zero: the path is lit, but it is costing points — the figure says so in the warm ink */
.path-chip.neg { color: #ffd2c4; }
.path-chip.can {
  cursor: pointer; transform: scale(1.22);
  box-shadow: inset 0 0 0 1.5px rgba(255, 255, 255, 0.6), 0 0 0 2px var(--wb-gold), 0 0 14px rgba(var(--wb-gold-rgb) / 0.5);
}
.path-chip:focus-visible { outline: 2px solid var(--wb-gold); outline-offset: 3px; }
#my-sum .eq { font-family: var(--dk-font-display); font-size: 22px; color: var(--wb-ink-dim); line-height: 1; }
#my-score {
  font-family: var(--dk-font-display); font-size: 32px; line-height: 1; font-weight: 700;
  color: var(--wb-glow); font-variant-numeric: tabular-nums; min-width: 2ch; text-align: right;
  text-shadow: 0 0 14px rgba(var(--wb-glow-rgb) / 0.35);
}
#my-score.neg { color: #ffb59f; text-shadow: 0 0 14px rgba(255, 181, 159, 0.3); }

/* -------------------------------------------------------- the opponents, down the right */
/* ONE plate for all the opponents, hugging what is in it: a stack of name-lines and boards,
   each board as wide as the column. When the stack is taller than the column (three or four
   seats on a short screen) the boards give way — flex-shrink with min-height 0, and the SVG
   letterboxes inside its box — so the last card never scrolls out of sight and the plate
   never grows past the table. The seat to act is marked on its board, not with a second
   border: the name goes gold and the board gets the gold ring. */
#opponents {
  display: flex; flex-direction: column; gap: 10px;
  align-self: start;
  max-height: 100%; min-height: 0; min-width: 0;
  background: var(--wb-plate);
  border: 1px solid var(--wb-plate-line);
  border-radius: 14px;
  box-shadow: var(--wb-shadow);
  padding: 8px 10px 10px;
  box-sizing: border-box;
}
.opp {
  flex: 0 1 auto; min-width: 0; min-height: 0;
  display: flex; flex-direction: column;
}
.opp.declared .opp-name::after { content: ' ⌛'; }
.opp-head { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; flex: 0 0 auto; }
.opp-name { flex: 1 1 auto; font-weight: 600; font-size: 14px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; transition: color 200ms; }
.opp.active .opp-name { color: var(--wb-gold); }
.opp-head .pouch { width: 26px; height: 29px; }
.opp-head .pouch-n { font-size: 10px; }
.opp-score { font-family: var(--dk-font-display); font-size: 22px; line-height: 1; font-weight: 700; color: var(--wb-glow); font-variant-numeric: tabular-nums; min-width: 34px; text-align: right; }
.opp-board {
  flex: 0 1 auto; min-height: 0; width: 100%; aspect-ratio: 1000 / 706; /* the print's frame, board.js FRAME */
  display: flex; align-items: center; justify-content: center;
  border-radius: 10px;
  transition: box-shadow 200ms;
}
.opp.active .opp-board { box-shadow: 0 0 0 2px var(--wb-gold), 0 0 22px rgba(var(--wb-gold-rgb) / 0.3); }
/* The opponent whose turn it is, blown up for the length of it (Joan's rule for a column of
   thumbnails): grown from its RIGHT edge into the table, so it expands over the felt and not
   off the window; WHERE on that edge is `--acting-y`, set by game.js so the enlarged card stays
   inside the column's top and the window's bottom. The scale is measured by game.js from the
   room actually there (never over the left half of your own board, never taller than the
   column) and published as `--acting-scale`. Elevated above the table and the caption, with a
   lift, so the overlap reads as one card held up. `settling` keeps the elevation while it
   shrinks, or the card would drop behind the felt mid-way. The head is counter-scaled: a
   14px name at ×2.4 is a 34px name covering the corner it labels. */
.opp {
  position: relative;
  transition: transform var(--acting-ms, 420ms) cubic-bezier(.22,.75,.3,1), filter var(--acting-ms, 420ms), box-shadow 200ms;
  transform-origin: right var(--acting-y, 50%);
}
.opp { cursor: zoom-in; }
.opp.acting { transform: scale(var(--acting-scale, 2)); filter: drop-shadow(0 12px 26px rgba(0, 0, 0, 0.72)); cursor: zoom-out; }
.opp.acting, .opp.settling { z-index: 60; }
/* Enlarged, the card is the board and nothing else: no gold ring (the size says whose turn it
   is), and the head — name, bag, score — steps out of the flow so the board grows over the
   place it had, instead of the bag being printed over the board. */
.opp.acting .opp-board { box-shadow: none; }
.opp.acting .opp-head { position: absolute; opacity: 0; pointer-events: none; }
/* a rebuild mid-turn lands at the enlarged size without animating there (see renderOpponents) */
.opp.no-anim, .opp.no-anim .opp-head { transition: none !important; }
.opp.acting .opp-board { background: var(--wb-plate); border-radius: 10px; }
.opp-head { transform-origin: top right; transition: transform var(--acting-ms, 420ms) cubic-bezier(.22,.75,.3,1); }
.opp.acting .opp-head { transform: scale(calc(1 / var(--acting-scale, 2))); }
.opp-board svg { width: 100%; height: 100%; max-height: 100%; display: block; border-radius: 10px; }
/* An opponent's tray lies ON its board, over the "World of Zura" stones at the bottom edge
   (a strip no path crosses), not under it — so a draw never grows the card and the boards
   in the column keep their places. Positioned inside .opp-board (renderOpponents puts it
   there), which fills its aspect box exactly. */
.opp-board { position: relative; }
.opp-tray { position: absolute; left: 50%; bottom: 3.5%; transform: translateX(-50%); display: flex; gap: 2px; justify-content: center; margin: 0; z-index: 2;
  padding: 2px 4px; border-radius: 8px; background: rgba(6, 10, 26, 0.45); }
.opp-tray[hidden] { display: none; }

/* The toast: one line over the table, three seconds, then gone — the same gold as the pill
   it repeats, big enough to be seen from across the room, in front of everything. */
#wb-toast {
  position: fixed; left: 50%; top: calc(var(--dk-header-h, 52px) + 18px); z-index: 1200;
  transform: translate(-50%, -12px); opacity: 0; pointer-events: none;
  max-width: min(92vw, 640px); padding: 12px 22px; border-radius: 14px;
  font-family: var(--dk-font-display); font-size: 20px; font-weight: 700; line-height: 1.3; text-align: center;
  color: #1a1408; background: var(--wb-gold);
  box-shadow: 0 10px 34px rgba(0, 0, 0, 0.6), 0 0 0 1px rgba(255, 255, 255, 0.35) inset;
  transition: opacity 260ms ease, transform 260ms cubic-bezier(.22,.75,.3,1);
}
#wb-toast.show { opacity: 1; transform: translate(-50%, 0); }

/* The facet flash on a gem (boardView.js drawGlint): a share of a 7-13 s cycle, so the stops
   are tiny — rise in a twentieth of the period, gone by a tenth. transform-box makes the
   <g>'s own centre the origin, or the scale would swing it around the SVG's corner. */
.gem-glint { opacity: 0; transform-box: fill-box; transform-origin: center; animation: wb-glint 9s linear infinite; }
.gem-glint-flash { transform-box: fill-box; transform-origin: center; }
@keyframes wb-glint {
  0%, 100% { opacity: 0; transform: scale(0.3); }
  2.5%     { opacity: 1; transform: scale(1.15); }
  4.5%     { opacity: 0.55; transform: scale(0.9); }
  7%       { opacity: 0; transform: scale(0.5); }
}

/* --------------------------------------------------------------------------- the board */
.wb-board .next-ring { animation: wb-pulse 1.8s ease-in-out infinite; }
.wb-board.compact .next-ring { animation: none; }
.wb-board .hl { cursor: pointer; }
.wb-board .hl-ring { animation: wb-pulse 1.1s ease-in-out infinite; }
@keyframes wb-pulse { 0%, 100% { stroke-opacity: 0.35; } 50% { stroke-opacity: 1; } }
.wb-board text { font-family: var(--dk-font-ui); pointer-events: none; user-select: none; }

/* The night moving in the board: a third of the specks twinkle, slowly and out of step
   (duration and phase are per speck, set inline); two falling stars cross the open sky on
   long cycles. Ambience — slower than any signal on the board. */
.wb-board .speck.twinkle { transform-box: fill-box; transform-origin: center; animation: wb-twinkle 5s ease-in-out infinite; }
@keyframes wb-twinkle {
  0%, 100% { opacity: 0.22; transform: scale(0.75); }
  50%      { opacity: 0.95; transform: scale(1.35); }
}
.wb-board .meteor-run { opacity: 0; animation: wb-meteor 31s linear infinite; }
.wb-board .meteor-head { filter: drop-shadow(0 0 3px rgba(226, 238, 255, 0.9)); }
@keyframes wb-meteor {
  0%    { transform: translateX(-40px); opacity: 0; }
  0.6%  { opacity: 0.9; }
  3.0%  { opacity: 0.9; }
  3.8%  { transform: translateX(var(--len, 300px)); opacity: 0; }
  100%  { transform: translateX(var(--len, 300px)); opacity: 0; }
}

/* ---------------------------------------------------------------------- flying crystals */
.gem-icon.ghost {
  position: fixed; z-index: 1150; pointer-events: none;
  filter: drop-shadow(0 4px 6px rgba(0, 0, 0, 0.5));
  will-change: transform;
}

/* a line under the start subtitle saying why an online game ended (host left, started without you) */
.wb-start-notice {
  margin: -6px auto 14px; padding: 8px 14px; max-width: 420px; border-radius: 10px;
  background: rgba(var(--wb-gold-rgb) / 0.12); box-shadow: inset 0 0 0 1px rgba(var(--wb-gold-rgb) / 0.4);
  color: var(--wb-gold); font-size: 14px; line-height: 1.4; text-align: center;
}

/* ---------------------------------------------------------------------- the online lobby */
.mp-panel { width: min(460px, 94vw); }
.mp-blurb { font-size: 14px; line-height: 1.5; color: var(--dk-panel-dim); margin: 0 0 8px; }
.mp-note { font-size: 12px; letter-spacing: 0.04em; color: var(--dk-panel-dim); margin: 0 0 8px; }
.mp-field { display: flex; flex-direction: column; align-items: stretch; gap: 4px; text-align: left; margin: 8px 0; }
.mp-field span { font-size: 12px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--dk-panel-dim); }
.mp-field input {
  min-height: 44px; padding: 0 12px; border-radius: 10px;
  border: 1px solid var(--dk-field-line); background: var(--dk-field-bg); color: var(--wb-ink);
  font: inherit; font-size: 16px;
}
.mp-field input:focus-visible { outline: 2px solid var(--wb-gold); outline-offset: 2px; }
.mp-code-input { text-transform: uppercase; letter-spacing: 0.35em; font-family: var(--dk-font-display); font-size: 22px !important; text-align: center; }
.mp-code {
  font-family: var(--dk-font-display); font-size: 40px; font-weight: 700; letter-spacing: 0.32em;
  color: var(--wb-glow); text-shadow: 0 0 18px rgba(var(--wb-glow-rgb) / 0.4); margin: 4px 0 8px;
  user-select: all;
}
.mp-copy { margin-bottom: 10px; }
.mp-list-title { font-size: 11px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--dk-panel-dim); margin: 6px 0 4px; text-align: left; }
.mp-seats { display: flex; flex-direction: column; gap: 4px; margin-bottom: 6px; }
.mp-seat { display: flex; align-items: center; gap: 10px; padding: 6px 12px; border-radius: 10px; background: rgba(255, 255, 255, 0.04); text-align: left; font-size: 15px; }
.mp-seat.me { background: rgba(var(--wb-gold-rgb) / 0.12); box-shadow: inset 0 0 0 1px rgba(var(--wb-gold-rgb) / 0.45); }
.mp-seat-n { font-family: var(--dk-font-display); font-weight: 700; color: var(--dk-panel-dim); min-width: 14px; }
.mp-seat .mp-ai, .mp-seat .mp-wait { color: var(--dk-panel-dim); font-style: italic; }
.mp-err { min-height: 1.4em; font-size: 13px; color: #ffb59f; margin: 4px 0; }

/* -------------------------------------------------------------------------- game over */
.wb-over { width: min(640px, 96vw); }
.wb-reason { font-size: 14px; line-height: 1.5; color: var(--dk-panel-dim); margin: -4px 0 10px; }
.over-table-wrap { overflow-x: auto; margin: 6px 0 2px; }
.over-table { border-collapse: separate; border-spacing: 0 4px; width: 100%; font-size: 14px; }
.over-table th, .over-table td { padding: 4px 4px; text-align: center; vertical-align: middle; }
.over-table thead th { padding-bottom: 0; }
.over-table tbody th { text-align: left; font-weight: 600; white-space: nowrap; padding-left: 8px; }
.over-table tbody tr td:first-child { border-radius: 10px 0 0 10px; }
.over-table tbody tr td:last-child { border-radius: 0 10px 10px 0; }
.over-table tbody tr.win td, .over-table tbody tr.win th { background: rgba(var(--wb-gold-rgb) / 0.10); }
.over-table tbody tr.win th { color: var(--wb-gold); }
.over-table tbody tr.me th::after { content: ''; }
.res-rank { font-family: var(--dk-font-display); font-size: 16px; color: var(--dk-panel-dim); width: 22px; font-variant-numeric: tabular-nums; }
.res-called { display: block; font-size: 11px; font-weight: 500; color: var(--dk-panel-dim); letter-spacing: 0.04em; }
.res-head { display: inline-block; width: 12px; height: 12px; border-radius: 50%; background: var(--c); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4); }
.tot-h { font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--dk-panel-dim); font-weight: 600; }
.res-disc {
  display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; border-radius: 50%;
  background: radial-gradient(circle at 38% 32%, color-mix(in srgb, var(--c) 78%, #fff), var(--c) 55%, color-mix(in srgb, var(--c) 72%, #000));
  box-shadow: inset 0 0 0 1.5px rgba(255, 255, 255, 0.45), 0 2px 4px rgba(2, 6, 20, 0.5);
  color: #fff; font-weight: 700; font-size: 12px; line-height: 1;
  text-shadow: 0 0 2px rgba(0, 0, 0, 0.7), 0 1px 1px rgba(0, 0, 0, 0.6);
  font-variant-numeric: tabular-nums;
}
.res-disc.unlit { filter: saturate(0.55) brightness(0.62); }
.res-disc.neg { color: #ffd2c4; }
.over-table td.tot { font-family: var(--dk-font-display); font-size: 22px; font-weight: 700; color: var(--wb-glow); font-variant-numeric: tabular-nums; padding-right: 10px; }
.over-table td.tot.neg { color: #ffb59f; }

/* ------------------------------------------------------------------- responsive layout */
/* Short landscape (phones): the opponents' column narrows, their thumbnails go, the
   bottom strip tightens; the board keeps what height is left. */
@media (max-height: 560px) {
  #table { gap: 6px 8px; padding: 6px 8px 6px; grid-template-columns: minmax(0, 1fr) clamp(180px, 27vw, 260px); }
  #opponents { gap: 6px; padding: 6px 8px 8px; }
  #middle { padding: 4px 10px 4px 8px; gap: 10px; }
  #pool-title { display: none; }
  #pool-stacks { gap: 4px; padding-bottom: 4px; }
  .stack .gb { width: 42px; height: 60px; }
  .stack .pile { width: 20px; height: 34px; }
  .stack .pile .gem-icon { width: 20px; height: 20px; bottom: calc(var(--k, 0) * 5px); }
  .stack-n { font-size: 11px; }
  /* The plate cannot hold piles, prompt and button in one row at this width, and every row
     it grows is a row the board loses. So the button joins the piles' row and the prompt
     becomes one ellipsised line under them: #status dissolves (display: contents) and its
     two children take their own grid cells. */
  #middle { gap: 2px 10px; }
  #actions { margin-bottom: 6px; }
  #status-text { font-size: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  #status-text .wb-warn { display: block; width: max-content; max-width: 100%; margin-bottom: 2px; }
  .act .gb { min-height: 40px; }
  .act .gb { padding: 0 14px; font-size: 14px; }
  #my-side { padding: 4px 10px; gap: 10px; }
  #my-score { font-size: 22px; }
  .pouch.big { width: 38px; height: 42px; }
  .pouch.big .pouch-n { font-size: 13px; }
  .tray-slot { width: 44px; height: 44px; }
  #my-tray .strip-title { display: none; }
  /* the strip is plainly yours here — gold-edged, holding your pouch — so the name goes */
  #my-head { display: none; }
  #my-sum { gap: 6px; }
  #my-paths { gap: 3px; }
  #my-paths:has(.can) { gap: 8px; padding: 0 3px; }
  .path-chip { width: 28px; height: 28px; font-size: 11px; }
  .path-chip.can { transform: scale(1.35); }
  #my-score { font-size: 20px; min-width: 0; }
  #my-sum .eq { display: none; }
  #my-side { gap: 8px; }
  .opp-score { font-size: 17px; }
}
/* The dialogs on a short screen: tighter type, discs and rows, buttons side by side — the
   whole panel fits the window; a panel that scrolls to its buttons reads as cut off. */
@media (max-height: 560px) {
  .wb-over, .wb-declare, .wb-rules { padding: 12px 16px; }
  .wb-over h2, .wb-declare h2, .wb-rules h2 { font-size: 19px; margin-bottom: 4px; }
  .wb-reason { margin: 0 0 4px; font-size: 12px; }
  .over-table { border-spacing: 0 2px; font-size: 12px; }
  .over-table th, .over-table td { padding: 2px 3px; }
  .res-disc { width: 26px; height: 26px; font-size: 11px; }
  .over-table td.tot { font-size: 18px; }
  .res-called { display: inline; margin-left: 6px; }
  .wb-dialog-actions { flex-direction: row; gap: 8px; margin-top: 8px; }
  .wb-dialog-actions .gb-wrap { flex: 1 1 0; }
  .wb-dialog-actions .gb-lg { min-height: 44px; font-size: 15px; }
  .wb-standings { gap: 2px; margin: 2px 0 6px; }
  .wb-standing { padding: 3px 10px; }
  .wb-standing-total { font-size: 18px; }
  .wb-verdict { font-size: 16px; margin: 0 0 4px; }
  .wb-declare-body { font-size: 12px; line-height: 1.35; margin-bottom: 4px; }
  .wb-rule { font-size: 13px; line-height: 1.45; margin-bottom: 8px; }
  .wb-rule-h { font-size: 14px; }
}
@media (max-height: 400px) {
  .opp-board, .opp-tray { display: none; }
  .stack .gb { height: 54px; }
  .stack .pile { height: 30px; }
  #table { grid-template-columns: minmax(0, 1fr) 150px; }
  .opp-head { margin-bottom: 0; }
}

/* Portrait: the opponents go back to a row across the top, then the pool, the board, and
   your strip under it; the board takes the width. */
@media (orientation: portrait) {
  #table {
    grid-template-columns: 1fr;
    grid-template-rows: auto auto minmax(0, 1fr) auto;
    gap: 8px;
    padding: 8px 10px 10px;
  }
  /* A portrait screen shows the whole portrait cover, credits and all; pull it down past
     them — on the table, and on the strip of it the header lets through. */
  #game { background-size: auto, auto 135%; background-position: center, center 42%; }
  body::before { background-size: auto 135%; background-position: center 42%; }
  #opponents     { grid-column: 1; grid-row: 1; flex-direction: row; justify-content: center; min-width: 0; align-self: stretch; max-height: none; gap: 12px; }
  #middle        { grid-column: 1; grid-row: 2; grid-template-columns: 1fr; grid-template-rows: auto auto auto; gap: 6px; min-width: 0; justify-self: stretch; width: auto; }
  #actions       { grid-column: 1; grid-row: 2; justify-content: center; margin-bottom: 0; min-width: 0; min-height: 0; }
  #status-text   { grid-column: 1; grid-row: 3; text-align: center; }
  #my-board-wrap { grid-column: 1; grid-row: 3; }
  #my-side       { grid-column: 1; grid-row: 4; flex-wrap: wrap; justify-content: space-between; gap: 8px 14px; justify-self: stretch; width: auto; }
  .opp { flex: 0 1 auto; max-width: 240px; }
  .opp-board { flex: 0 0 auto; width: auto; height: 110px; }
  #pool { flex-direction: column; align-items: center; gap: 4px; min-width: 0; }
  #pool-title { writing-mode: horizontal-tb; transform: none; padding: 0; }
  #my-sum { flex: 1 1 100%; justify-content: center; }
}
@media (orientation: portrait) and (max-width: 480px) {
  #table { padding: 6px 8px 8px; gap: 6px; }
  .opp-board { display: none; }
  .opp-tray { display: none; }
  #pool-stacks { gap: 4px; }
  .stack .gb { width: 44px; height: 66px; }
  .stack .pile { height: 38px; }
  #my-side { gap: 8px 10px; padding: 8px 10px; }
  #my-bag { gap: 8px; }
  #my-tray { gap: 6px; }
  .tray-slot { width: 44px; height: 44px; }
}

@media (prefers-reduced-motion: reduce) {
  .wb-board .next-ring, .wb-board .hl-ring, .wb-board .seek-ring, .wb-board .speck.twinkle, .wb-board .meteor-run { animation: none; }
  .opp, .opp-head { transition: none; }
  .gem-glint { animation: none; opacity: 0; }
  #wb-toast { transition: none; }
  .wb-warn.mine { animation: none; }
  .wb-board .meteor-run { opacity: 0; }
  .opp, #my-side, .tray-slot, .stack, .path-chip { transition: none; }
  .pouch.shake { animation: none; }
  #board-caption.show { animation: none; }
}

/* ── the rules link on the start screen ───────────────────────────────────────────
   its own class, NOT .start-play — those are launch buttons and the shared sheet gives them
   width:100%, which would make a one-word link the widest control on the card */
.rules-link {
    align-self: center; display: inline-block; width: auto; margin-top: 2px; padding: 7px 16px;
    text-align: center; white-space: nowrap; font-family: var(--dk-font-ui); font-size: 13px;
    text-decoration: none; color: rgba(var(--wb-glow-rgb) / 0.82);
    border: 1px solid var(--dk-accent-soft); border-radius: var(--dk-radius);
}
.rules-link:hover { color: var(--dk-text); border-color: var(--dk-accent); }

/* ── Crawlable copy (#intro in index.html): below the fold, never display:none ─────────
   The start screen is fixed and #game absolute, so the document has nothing to scroll; the
   lock keeps the block below the fold from ever being scrolled into. */
body { overflow: hidden; }
#intro {
    margin: 100vh auto 0; max-width: 720px; padding: 4px 20px 8px; text-align: center;
    color: var(--dk-text-muted, #b8c4e0); font-family: var(--dk-font-ui); font-size: 14px;
    line-height: 1.55;
}
#intro h1 { color: var(--dk-text, #eef4ff); font-family: var(--dk-font-display); font-weight: 700;
            font-size: 27px; letter-spacing: 0.04em; margin: 0 0 4px; }
#intro .intro-tagline { font-size: 12px; letter-spacing: 2px; text-transform: uppercase; margin: 0 0 14px; }
#intro img { display: block; width: 100%; max-width: 460px; height: auto; margin: 0 auto 14px;
             border: 1px solid var(--dk-accent-soft); border-radius: 8px; }
#intro h2 { color: var(--dk-text, #eef4ff); font-family: var(--dk-font-display); font-weight: 700;
            font-size: 17px; letter-spacing: 0.03em; margin: 14px 0 5px; }
#intro p { margin: 0 0 9px; }
#intro strong { color: var(--dk-text, #eef4ff); }
#intro em { color: var(--dk-accent); font-style: normal; }
#intro a { color: var(--dk-accent); }
