﻿:root {
  color-scheme: light dark;
  /* sky / page background */
  --sky-1: #8fd8d2;  --sky-2: #f7e8c9;  --sky-mid: #c3e0d6;
  /* surfaces */
  --surface: #fdf8ec;          /* dock, cards */
  --surface-raised: #ffffff;   /* chips, inputs */
  --sign-face: #2b3a3a;        /* dark sign boards (market, menus) */
  --sign-post: #d94f2b;        /* market post / primary sign color */
  /* ink */
  --ink: #2b3a3a;  --ink-muted: rgba(43, 58, 58, 0.72);   /* >=4.5:1 on --surface (AA) */
  --ink-on-dark: #fff8ea;      /* text on sign-face */
  /* board */
  --cell: #cfe7e2;  --cell-border: #9fc9c1;   /* pool-water cells */
  --board-frame: rgba(255, 255, 255, 0.42);
  --drag-ghost-veil: rgba(255, 255, 255, 0.42);   /* must stay translucent: a covered tile shows through it */
  /* the one tile */
  --tile-face: #fdf6e3;  --tile-ink: #2b3a3a;  --tile-points: #b8532a;
  --tile-top-sheen: rgba(255, 255, 255, 0.75);
  --tile-bottom-shade: rgba(43, 58, 58, 0.14);
  --tile-wildcard-ring: rgba(255, 255, 255, 0.58);
  --tile-wildcard-dash: rgba(35, 49, 58, 0.42);
  --on-accent-ink: #ffffff;
  /* accents */
  --coral: #d94f2b;   --coral-deep: #9c3517;
  --orange: #f0783c;  --orange-deep: #b8532a;   /* button hover */
  --teal: #3aa6a0;    --teal-deep: #237873;  --teal-soft: #5fc0b8;
  /* tile placement: destination ring while dragging + uncommitted-tile ring.
     Soft = the same color at 50% alpha, NOT a glow token (issue #5). */
  --placement-accent: #3aa6a0;                       /* = --teal; night flips to cyan neon */
  --placement-accent-soft: rgba(58, 166, 160, 0.5);
  --gold: #ffd97a;    --gold-deep: #e0a32f;
  --pink-neon: #ff9ecb;  --cyan-neon: #58ead9;  /* mostly night; day fallback ok */
  --red-neon: #ff425f;   /* night electric red, parallels --cyan-neon */
  --red-glow: rgba(255, 66, 95, 0.6);   /* red neon glow (glow-strength gated) */
  --ring-dark: #3f2611;  /* Saturn ring's dark gaps — darker than the gold planet */
  /* "hot" accent: now-playing badge bg + username + negative/spent score.
     Day = the coral MARKET post (--sign-post); night = electric red. */
  --hot-accent: var(--sign-post);
  /* effects */
  --glow-strength: 0;          /* 0 by day; night mode turns glows on */
  --shadow-soft: rgba(43, 58, 58, 0.25);
  --orange-glow: rgba(240, 120, 60, 0.55);   /* focus rings + placement-error flash glow */
  --tile-glow: rgba(242, 230, 216, 0.3);     /* night tile glow (day: inert, no drop shadow swap) */
  --teal-glow: rgba(58, 166, 160, 0.5);      /* night letter-bonus cell glow */
  --gold-glow: rgba(255, 217, 122, 0.5);     /* night word-bonus/start cell glow */
  --coral-glow: rgba(217, 79, 43, 0.55);     /* night triple-word cell glow */
  --gold-wash: rgba(255, 217, 122, 0.35);    /* always-on gold tint (rank #1 / winner highlight gradients), not glow-gated */
  --sheen-soft: rgba(255, 255, 255, 0.3);    /* generic light inset sheen (sign posts/boards) */
  --shade-soft: rgba(43, 58, 58, 0.35);      /* generic dark text/inset shadow */
  --rainbow-1: #d94f2b;  --rainbow-2: #ffd97a;  --rainbow-3: #3aa6a0;
  --rainbow-4: #6a8fd8;  --rainbow-5: #c96a9e;
  /* word-theme accents (Themes word packs; unrelated to the data-theme color mode) */
  --theme-accent: #c96a9e;                       /* day plum (= --rainbow-5) */
  --theme-accent-deep: #9c4a76;
  --theme-accent-soft: rgba(201, 106, 158, 0.5);
  --theme-glow: rgba(255, 158, 203, 0.5);        /* glow-strength gated: inert by day */
  --play-width: min(72vh, 90vw, 560px);
  /* rules highway */
  --road-asphalt: rgba(43, 58, 58, 0.16);      /* day: soft asphalt tint from --sign-face */
  --road-centerline: var(--gold);
  --road-centerline-glow: rgba(255, 217, 122, 0);  /* day: no glow */
  --sign-wood: #a9612f;   --sign-wood-deep: #7a4420;   /* signpost timber */
}
html[data-theme="dark"] { /* night overrides */
  --sky-1: #0b1026; --sky-2: #3d1f2e;  --sky-mid: #1c1230;
  --surface: #120c22; --surface-raised: #17102b;
  --sign-face: #10091d; --sign-post: #2a0f14;
  --ink: #f2e6d8; --ink-muted: rgba(242, 230, 216, 0.6); --ink-on-dark: #f2e6d8;
  --cell: #171230; --cell-border: #2c2450;
  --board-frame: #1b1c33;   /* solid: the gaps between cells hide Saturn behind the board */
  --drag-ghost-veil: rgba(27, 28, 51, 0.55);   /* NOT --board-frame: that is opaque at night and would mask the covered tile */
  --tile-face: #f2e6d8;                        /* tiles STAY cream at night */
  --tile-wildcard-ring: rgba(255, 255, 255, 0.58);
  --tile-wildcard-dash: rgba(35, 49, 58, 0.42);
  --on-accent-ink: #ffffff;
  --glow-strength: 1;
  --placement-accent: #58ead9;                       /* = --cyan-neon */
  --placement-accent-soft: rgba(88, 234, 217, 0.5);
  --hot-accent: var(--red-neon);   /* night: electric red for now-playing/username/negative */
  --red-glow: rgba(255, 66, 95, 0.75);
  --shadow-soft: rgba(0, 0, 0, 0.5);
  --orange-glow: rgba(240, 120, 60, 0.65);
  --tile-glow: rgba(242, 230, 216, 0.32);
  --teal-glow: rgba(88, 234, 217, 0.5);
  --gold-glow: rgba(255, 217, 122, 0.55);
  --coral-glow: rgba(255, 92, 138, 0.55);
  --gold-wash: rgba(255, 217, 122, 0.16);
  --sheen-soft: rgba(255, 255, 255, 0.1);
  --shade-soft: rgba(0, 0, 0, 0.45);
  --rainbow-1: #d94f2b;  --rainbow-2: #ffd97a;  --rainbow-3: #3aa6a0;
  --rainbow-4: #6a8fd8;  --rainbow-5: #c96a9e;
  --theme-accent: #ff9ecb;                       /* night pink neon (= --pink-neon) */
  --theme-accent-deep: #c96a9e;
  --theme-accent-soft: rgba(255, 158, 203, 0.5);
  --theme-glow: rgba(255, 158, 203, 0.55);
  --teal-soft: #5fc0b8;
  /* rules highway: night */
  --road-asphalt: rgba(0, 0, 0, 0.45);           /* darker night asphalt */
  --road-centerline: var(--gold);
  --road-centerline-glow: rgba(255, 217, 122, 0.55);  /* faint centerline glow at night */
  --sign-wood: #7d4d2a;   --sign-wood-deep: #4a2c16;   /* lighter at night so posts read against the dark sky */
}

/* Night pass: tile / board (structural — cream glow replaces drop shadow, bonus/start cells gain glow borders) */
html[data-theme="dark"] .tile {
  box-shadow:
    inset 0 2px 0 var(--tile-top-sheen),
    inset 0 -0.22em 0 var(--tile-bottom-shade),
    0 0 calc(9px * var(--glow-strength)) var(--tile-glow);
}

html[data-theme="dark"] .tile-wildcard {
  box-shadow:
    inset 0 0 0 0.18rem var(--tile-wildcard-ring),
    inset 0 2px 0 var(--tile-top-sheen),
    inset 0 -0.22em 0 var(--tile-bottom-shade),
    0 0 calc(9px * var(--glow-strength)) var(--tile-glow);
}

html[data-theme="dark"] .board .tile,
html[data-theme="dark"] .rules-example .tile,
html[data-theme="dark"] .rules-board-example .tile {
  box-shadow:
    inset 0 2px 0 var(--tile-top-sheen),
    inset 0 -0.22em 0 var(--tile-bottom-shade),
    0 0 calc(7px * var(--glow-strength)) var(--tile-glow);
}

html[data-theme="dark"] .board-cell-bonus-doubleLetter,
html[data-theme="dark"] .board-cell-bonus-tripleLetter {
  box-shadow: 0 0 calc(8px * var(--glow-strength)) var(--teal-glow);
}

html[data-theme="dark"] .board-cell-bonus-doubleWord,
html[data-theme="dark"] .board-cell-start {
  box-shadow: 0 0 calc(8px * var(--glow-strength)) var(--gold-glow);
}

html[data-theme="dark"] .board-cell-bonus-tripleWord {
  box-shadow: 0 0 calc(8px * var(--glow-strength)) var(--coral-glow);
}

* {
  box-sizing: border-box;
}

html {
  scrollbar-gutter: stable;
}

body {
  position: relative;
  min-height: 100vh;
  margin: 0;
  overflow-x: hidden;
  overflow-y: auto;
  background: linear-gradient(180deg, var(--sky-1), var(--sky-mid), var(--sky-2));
  color: var(--ink);
  font-family: system-ui, sans-serif;
  display: flex;
  flex-direction: column;
}

/* Scenery: faint gutter ornaments on the page background, day = starbursts +
   dot planets, night = star field + ringed Saturn. Gutter-positioned (<=15% /
   >=85%) so they never sit under the centered content column; decorative only. */
body::before,
body::after {
  content: "";
  position: fixed;
  z-index: -2; /* star field sits behind the Saturn div (z-index: -1) */
  pointer-events: none;
  opacity: 0.5;
}

body::before {
  inset: 0 auto auto 0;
  width: 40vw;
  height: 60vh;
  background:
    radial-gradient(circle at 8% 12%, var(--gold) 0 3px, transparent 4px),
    radial-gradient(circle at 4% 30%, var(--coral) 0 2px, transparent 3px),
    conic-gradient(from 0deg at 10% 20%, transparent 0deg 80deg, var(--gold) 82deg 84deg, transparent 86deg 170deg, var(--gold) 172deg 174deg, transparent 176deg 260deg, var(--gold) 262deg 264deg, transparent 266deg 350deg, var(--gold) 352deg 354deg, transparent 356deg 360deg);
  mask-image: radial-gradient(circle at 10% 20%, black 0 3rem, transparent 6rem);
}

body::after {
  inset: 0 0 auto auto;
  width: 40vw;
  height: 60vh;
  background:
    radial-gradient(circle at 92% 18%, var(--teal) 0 2px, transparent 3px),
    radial-gradient(circle at 88% 8%, var(--coral) 0 3px, transparent 4px),
    conic-gradient(from 0deg at 90% 14%, transparent 0deg 80deg, var(--teal) 82deg 84deg, transparent 86deg 170deg, var(--teal) 172deg 174deg, transparent 176deg 260deg, var(--teal) 262deg 264deg, transparent 266deg 350deg, var(--teal) 352deg 354deg, transparent 356deg 360deg);
  mask-image: radial-gradient(circle at 90% 14%, black 0 2.4rem, transparent 5rem);
}

html[data-theme="dark"] body::before {
  background:
    radial-gradient(circle at 6% 10%, var(--ink-on-dark) 0 1px, transparent 2px),
    radial-gradient(circle at 12% 22%, var(--ink-on-dark) 0 1px, transparent 2px),
    radial-gradient(circle at 4% 38%, var(--ink-on-dark) 0 1px, transparent 2px),
    radial-gradient(circle at 9% 48%, var(--ink-on-dark) 0 1px, transparent 2px),
    radial-gradient(circle at 3% 60%, var(--ink-on-dark) 0 1px, transparent 2px);
  mask-image: none;
}

/* Night right-gutter star field (Saturn itself is the .saturn div below). */
html[data-theme="dark"] body::after {
  background:
    radial-gradient(circle at 93% 44%, var(--ink-on-dark) 0 1px, transparent 2px),
    radial-gradient(circle at 84% 56%, var(--ink-on-dark) 0 1px, transparent 2px),
    radial-gradient(circle at 96% 66%, var(--ink-on-dark) 0 1px, transparent 2px),
    radial-gradient(circle at 88% 78%, var(--ink-on-dark) 0 1px, transparent 2px);
  mask-image: none;
}

/* Ringed Saturn — a real element (night only), fixed in the top-right, fully
   below the top edge. The opaque planet is painted AFTER the ring so the ring
   passes BEHIND it: only the tilted ring tips show either side. */
.saturn {
  display: none;
}

html[data-theme="dark"] .saturn {
  display: block;
  position: fixed;
  top: 2.25rem;
  right: -2rem;
  width: 14rem;
  height: 11rem;
  z-index: -1;
  pointer-events: none;
  opacity: 0.6;
}

.saturn-ring,
.saturn-planet {
  position: absolute;
  top: 50%;
  left: 50%;
}

.saturn-ring {
  width: 14rem;
  height: 4.6rem;
  transform: translate(-50%, -50%) rotate(-18deg);
  /* multi-band ring: light bands + dark Cassini-style gaps (--ring-dark) */
  background: radial-gradient(ellipse closest-side at 50% 50%,
    transparent 0 55%,
    var(--gold) 58% 63%,
    var(--ring-dark) 65% 68%,
    var(--gold-deep) 70% 82%,
    var(--ring-dark) 84% 86%,
    var(--gold) 88% 96%,
    transparent 99%);
}

/* Ring-back sits behind the planet (DOM order); the planet occludes its far
   half. Ring-front is the same ellipse clipped to only its near (bottom) arc
   and painted after the planet, so it crosses IN FRONT of the planet — the
   two together give a real Saturn instead of "ears". */
.saturn-ring-front {
  clip-path: inset(50% 0 0 0);
}

.saturn-planet {
  width: 9rem;
  height: 9rem;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: radial-gradient(circle at 40% 35%, var(--tile-face), var(--gold) 45%, var(--gold-deep) 90%);
}

/* Scale the whole planet+ring up on larger screens, anchored to the corner. */
@media (min-width: 1024px) {
  html[data-theme="dark"] .saturn {
    transform: scale(1.45);
    transform-origin: 100% 0;
  }
}

.font-script {
  font-family: "Pacifico", "Brush Script MT", cursive;
}

.font-display {
  font-family: "Righteous", "Trebuchet MS", sans-serif;
}

main {
  min-height: calc(100vh - 3.4rem);
  width: min(100vw, 1080px);
  margin: 0 auto;
  padding: clamp(2rem, 7vw, 5rem) clamp(0.5rem, 2vw, 1.25rem);
  display: grid;
  place-items: center;
  gap: 1.25rem;
  text-align: center;
  flex: 1 0 auto;
}

.site-footer {
  width: min(100vw, 1080px);
  margin: 0 auto;
  padding: 0.7rem clamp(0.5rem, 2vw, 1.25rem) 1rem;
  color: var(--ink-muted);
  text-align: center;
  font: 700 0.78rem/1.35 system-ui, sans-serif;
  flex: 0 0 auto;
}

.site-footer-links {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.65rem;
  margin-right: 0.55rem;
}

.site-footer a {
  color: var(--coral);
  font-weight: 900;
  text-decoration-thickness: 2px;
  text-underline-offset: 0.15rem;
}

.site-footer-copy {
  white-space: nowrap;
}

/* Deploy stamp: which branch/build is live. Rendered on its own line, muted and
   monospace so it reads as an ops readout, not a footer link. */
.site-footer-build {
  display: block;
  margin-top: 0.4rem;
  color: var(--ink-muted);
  opacity: 0.75;
  font: 600 0.68rem/1.3 ui-monospace, "SFMono-Regular", "Consolas", monospace;
  letter-spacing: 0.01em;
}

.masthead {
  display: grid;
  width: 100%;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  justify-items: stretch;
  gap: 1rem 1.25rem;
  transition: transform 220ms ease, padding 220ms ease;
}

/* Brand road-sign wordmark rules live in public/brand.css (shared with
   privacy.html + terms.html). App-only masthead placement stays below. */

.game-controls {
  display: grid;
  justify-self: end;
  justify-items: end;
  gap: 0.75rem;
}

.identity-panel,
.identity-bar,
.identity-menu {
  display: none;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.75rem;
}

.identity-panel {
  position: relative;
  grid-column: 1 / -1;
  gap: 0.95rem;
  justify-items: center;
  margin-top: 0.9rem;
  padding: 1.6rem 1.1rem 1.1rem;
  border: 2px solid var(--cell-border);
  border-radius: 16px;
  background: var(--surface);
  box-shadow: 0 0.4rem 0 var(--shadow-soft), 0 0 calc(16px * var(--glow-strength)) var(--pink-neon);
}

.identity-panel::before {
  content: "VACANCY";
  position: absolute;
  top: -0.85rem;
  left: 50%;
  transform: translateX(-50%) rotate(-2deg);
  padding: 0.3rem 0.85rem;
  border-radius: 999px;
  background: var(--gold);
  color: var(--sign-face);
  font: 800 0.68rem/1 "Righteous", "Trebuchet MS", sans-serif;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  box-shadow: 0.12rem 0.12rem 0 var(--gold-deep), 0 0 calc(10px * var(--glow-strength)) var(--gold-glow);
}

.identity-bar {
  position: relative;
  align-items: center;
  flex-wrap: nowrap;
  color: var(--ink);
  font: 700 0.92rem/1.25 system-ui, sans-serif;
}

.identity-current {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  min-width: 0;
}

.identity-current .ww-icon {
  color: var(--hot-accent);
  flex: 0 0 auto;
  width: 1.55em;
  height: 1.55em;
  /* flat by day (matches the MARKET board), electric-red glow by night */
  filter: drop-shadow(0 0 calc(7px * var(--glow-strength)) var(--red-glow));
}

.identity-name {
  color: var(--hot-accent);
  /* Flat fill so it reads as the same solid color as the MARKET board by day
     (no crisp white offset); night adds only the electric-red neon glow. */
  font-family: "Pacifico", "Brush Script MT", cursive;
  font-weight: 400;
  font-size: 1.2em;
  line-height: 1.1;
  -webkit-text-stroke: 0.6px currentColor;
  text-shadow: 0 0 calc(14px * var(--glow-strength)) var(--red-glow);
  overflow-wrap: anywhere;
}

.identity-name:focus-visible {
  outline: 2px solid var(--coral);
  outline-offset: 3px;
  border-radius: 4px;
}

html[data-theme="dark"] .identity-name:focus-visible {
  outline-color: var(--gold);
}

.identity-provider {
  display: none;
  color: var(--ink-muted);
  font: 800 0.68rem/1 system-ui, sans-serif;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* Name + icon are one link to the player's own profile page. */
a.identity-current,
a.identity-current:visited {
  color: inherit;
  text-decoration: none;
  cursor: pointer;
}

/* Filter on the container so the icon's own neon drop-shadow filter is
   brightened with it rather than replaced. */
a.identity-current:hover,
a.identity-current:focus-visible {
  filter: brightness(1.2) saturate(1.15);
}

.oauth-buttons {
  display: grid;
  justify-items: stretch;
  gap: 0.55rem;
  width: min(82vw, 22rem);
}

.oauth-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.62rem;
  width: 100%;
  border-color: var(--cell-border);
}

.oauth-button:focus-visible {
  outline: none;
  border-color: var(--coral);
  box-shadow: 0.18rem 0.18rem 0 var(--cell-border), 0 0 0 3px var(--orange-glow);
}

html[data-theme="dark"] .oauth-button:focus-visible {
  border-color: var(--gold);
  box-shadow: 0.18rem 0.18rem 0 var(--cell-border), 0 0 0 3px var(--gold-glow);
}

.oauth-icon {
  display: inline-grid;
  place-items: center;
  width: 1.35rem;
  height: 1.35rem;
  flex: 0 0 auto;
  font: 900 1rem/1 Arial, sans-serif;
}

.oauth-button.google .oauth-icon svg {
  display: block;
  width: 1.2rem;
  height: 1.2rem;
}

.email-login-panel {
  display: grid;
  justify-items: stretch;
  gap: 0.55rem;
  width: min(82vw, 22rem);
}

.email-login-control {
  width: 100%;
}

.email-login-buttons {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.55rem;
}

.email-login-buttons .game-button:disabled {
  cursor: not-allowed;
  opacity: 0.6;
}

.email-login-link {
  justify-self: center;
  padding: 0;
  border: none;
  background: none;
  color: var(--ink-muted);
  font: 700 0.8rem/1.2 system-ui, sans-serif;
  text-decoration: none;
  cursor: pointer;
}

.email-login-link:hover:not(:disabled) {
  color: var(--coral-deep);
}

.email-login-link:disabled {
  cursor: not-allowed;
  opacity: 0.6;
}

.dev-login-panel {
  display: grid;
  justify-items: stretch;
  gap: 0.4rem;
  margin-top: 0.35rem;
  padding-top: 0.6rem;
  border-top: 1px solid var(--cell-border);
}

/* Keep the [hidden] attribute authoritative despite the display:grid above,
   so the panel stays invisible off localhost. */
.dev-login-panel[hidden] {
  display: none;
}

.dev-login-note {
  justify-self: center;
  color: var(--ink-muted);
  font: 700 0.72rem/1.2 system-ui, sans-serif;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.dev-login-row {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0.4rem;
}

.dev-login-button:disabled {
  cursor: not-allowed;
  opacity: 0.6;
}

.reset-password-page {
  grid-column: 1 / -1;
  clear: both;
  justify-self: center;
  width: min(92vw, 26rem);
  display: none;
  margin-top: clamp(1.5rem, 3vw, 2.25rem);
  justify-items: stretch;
  gap: 0.55rem;
  padding: clamp(1rem, 3vw, 1.35rem);
  border: 2px solid color-mix(in srgb, var(--ink) 22%, transparent);
  border-radius: 8px;
  background: color-mix(in srgb, var(--surface-raised) 72%, transparent);
  box-shadow: 0.18rem 0.18rem 0 color-mix(in srgb, var(--teal) 18%, transparent);
  font: 700 0.95rem/1.35 system-ui, sans-serif;
}

.toast-container {
  position: fixed;
  top: 1rem;
  left: 50%;
  transform: translateX(-50%);
  display: grid;
  gap: 0.5rem;
  justify-items: center;
  z-index: 100;
  pointer-events: none;
  width: min(92vw, 26rem);
}

.toast {
  pointer-events: auto;
  cursor: pointer;
  max-width: 100%;
  padding: 0.6rem 1.1rem;
  border-radius: 999px;
  border: 2px solid var(--ink);
  background: var(--surface, #fff);
  color: var(--ink);
  font-size: 0.9rem;
  text-align: center;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.18);
  opacity: 0;
  transform: translateY(-0.5rem);
  transition: opacity 0.2s ease, transform 0.2s ease;
}

.toast.toast-visible {
  opacity: 1;
  transform: translateY(0);
}

.toast.toast-error {
  border-color: var(--hot-accent);
  color: var(--hot-accent);
}

/* Sticky toasts (auth failures) never auto-hide: dismissal is the X button
   only, so a stray click can't lose a message the player still needs. */
.toast.toast-sticky {
  cursor: default;
  display: flex;
  align-items: center;
  gap: 0.6rem;
  text-align: left;
}

.toast-close {
  flex: none;
  display: grid;
  place-items: center;
  width: 1.4rem;
  height: 1.4rem;
  padding: 0;
  border: 2px solid currentColor;
  border-radius: 999px;
  background: transparent;
  color: inherit;
  font: 700 0.85rem/1 system-ui, sans-serif;
  cursor: pointer;
}

.toast-close:hover {
  background: color-mix(in srgb, currentColor 14%, transparent);
}

.toast-close:focus-visible {
  outline: 2px solid var(--coral);
  outline-offset: 2px;
}

html[data-theme="dark"] .toast-close:focus-visible {
  outline-color: var(--gold);
}

@media (prefers-reduced-motion: reduce) {
  .toast {
    transition: none;
    transform: none;
  }
}

/* Persistent, non-dismissible strip while signed in with an unverified email
   identity (see body.email-unverified below). Sticky + normal document flow
   (not position: fixed) so it naturally pushes everything else down instead
   of needing a fragile fixed-offset hack -- .rack-wrap uses the same sticky
   in-flow approach for the bottom dock. */
.verify-email-banner {
  display: none;
  position: sticky;
  top: 0;
  z-index: 20;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 0.5rem 0.9rem;
  width: 100%;
  padding: 0.5rem clamp(0.75rem, 3vw, 1.25rem);
  padding-top: calc(0.5rem + env(safe-area-inset-top, 0px));
  background: var(--gold);
  color: var(--sign-face);
  font: 700 0.82rem/1.3 system-ui, sans-serif;
  text-align: center;
  box-shadow: 0 2px 10px var(--shadow-soft);
}

body.email-unverified .verify-email-banner {
  display: flex;
}

.verify-email-banner-resend {
  flex: 0 0 auto;
  min-height: 1.9rem;
  padding: 0.3rem 0.85rem;
  border: 2px solid var(--sign-face);
  border-radius: 999px;
  background: var(--surface-raised);
  color: var(--sign-face);
  font: 800 0.75rem/1 system-ui, sans-serif;
  cursor: pointer;
}

.verify-email-banner-resend:hover {
  background: var(--surface);
}

.verify-email-banner-resend:disabled {
  cursor: not-allowed;
  opacity: 0.6;
}

html[data-theme="dark"] .verify-email-banner {
  background: var(--gold-deep);
  color: var(--ink-on-dark);
}

html[data-theme="dark"] .verify-email-banner-resend {
  border-color: var(--ink-on-dark);
  background: var(--surface);
  color: var(--ink-on-dark);
}

.leaderboard-button-with-icon,
.game-list-button-with-icon,
.rules-button-with-icon,
.themes-button-with-icon,
.changelog-button-with-icon,
.create-game-button-with-icon,
.profile-button-with-icon,
.logout-button-with-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.45rem;
  min-height: 3.1875rem;
  padding-block: 0;
}

.game-button.public-leaderboard-button {
  padding: 0.7rem 1.1rem;
  width: min(82vw, 22rem);
}

.leaderboard-crown-icon,
.game-list-crossword-icon,
.rules-guide-icon,
.changelog-history-icon,
.create-game-playlist-icon,
.profile-account-icon,
.logout-icon {
  color: var(--gold-deep);
  flex: 0 0 auto;
  width: 1.15rem;
  height: 1.15rem;
}

.game-list-crossword-icon {
  color: var(--teal-deep);
}

.rules-guide-icon {
  color: var(--coral);
}

.changelog-history-icon {
  color: var(--teal-deep);
}

.create-game-playlist-icon {
  color: var(--coral);
}

.logout-icon {
  color: currentColor;
}

body.screen-leaderboard .public-leaderboard-button {
  display: none;
}

.menu-button {
  position: relative;
  width: 2.75rem;
  min-width: 2.75rem;
  height: 2.75rem;
  display: grid;
  place-items: center;
  line-height: 1;
}

.menu-notification-count {
  position: absolute;
  top: -0.35rem;
  left: -0.35rem;
  display: none;
  min-width: 1.3rem;
  height: 1.3rem;
  place-items: center;
  padding-inline: 0.28rem;
  border: 2px solid var(--on-accent-ink);
  border-radius: 999px;
  background: var(--coral-deep);
  color: var(--on-accent-ink);
  font: 900 0.72rem/1 system-ui, sans-serif;
  box-shadow: 0.08rem 0.08rem 0 var(--shadow-soft);
}

.menu-button.has-notifications .menu-notification-count {
  display: grid;
}

.game-button.menu-button {
  padding: 0;
  padding-inline: 0;
}

.ww-icon {
  width: 1.35em;
  height: 1.35em;
  flex: 0 0 auto;
  fill: currentColor;
  vertical-align: -0.24em;
  display: inline-block;
  line-height: 1;
}

.identity-menu {
  position: absolute;
  top: calc(100% + 0.45rem);
  right: 0;
  z-index: 10;
  min-width: 10rem;
  padding: 0.55rem;
  border: 2px solid var(--sign-post);
  border-radius: 8px;
  background: var(--sign-face);
  color: var(--ink-on-dark);
  box-shadow: 0.25rem 0.25rem 0 var(--gold), 0 0 calc(14px * var(--glow-strength)) var(--pink-neon);
}

.identity-menu .game-button.secondary {
  border-color: var(--gold-deep);
  background: transparent;
  color: var(--ink-on-dark);
  box-shadow: none;
}

.identity-menu .game-button.secondary:hover {
  background: color-mix(in srgb, var(--gold) 12%, transparent);
}

.identity-menu .leaderboard-crown-icon,
.identity-menu .game-list-crossword-icon,
.identity-menu .rules-guide-icon,
.identity-menu .changelog-history-icon,
.identity-menu .create-game-playlist-icon,
.identity-menu .profile-account-icon,
.identity-menu .logout-icon {
  color: var(--gold);
}

body.menu-open .identity-menu {
  display: grid;
}

.identity-menu > .game-button {
  width: 100%;
  display: inline-flex;
  align-items: center;
  justify-content: flex-start;
  gap: 0.45rem;
  text-align: left;
}

.identity-menu > .game-button:not(.identity-menu-checkbox):not(.create-game-button-with-icon):not(.game-list-button-with-icon):not(.leaderboard-button-with-icon):not(.rules-button-with-icon):not(.themes-button-with-icon):not(.changelog-button-with-icon):not(.profile-button-with-icon):not(.logout-button-with-icon)::before {
  content: "";
  width: 1.15rem;
  height: 1.15rem;
  flex: 0 0 auto;
}

.identity-menu-checkbox {
  display: inline-flex;
  align-items: center;
  justify-content: flex-start;
  gap: 0.45rem;
  text-align: left;
  user-select: none;
}

.identity-menu-checkbox[hidden] {
  display: none;
}

.identity-menu-checkbox input {
  width: 1.15rem;
  height: 1.15rem;
  accent-color: var(--gold);
  flex: 0 0 auto;
}

.identity-menu-checkbox[aria-disabled="true"] {
  cursor: not-allowed;
  opacity: 0.58;
}

.menu-waiting-games {
  display: none;
  width: 100%;
  gap: 0.75rem;
  padding-top: 0.55rem;
  border-top: 2px solid var(--sign-post);
}

.menu-waiting-games.has-games {
  display: grid;
}

.menu-waiting-title {
  margin: 0;
  color: var(--ink-on-dark);
  opacity: 0.65;
  font: 900 0.68rem/1 system-ui, sans-serif;
  letter-spacing: 0.08em;
  text-align: left;
  text-transform: uppercase;
}

.menu-waiting-game {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 0.55rem;
  width: 100%;
  min-height: 3.15rem;
  padding: 0.7rem 1.1rem;
  text-align: left;
}

.identity-menu .menu-waiting-game {
  min-height: 3.15rem;
}

.menu-waiting-game-id {
  overflow: hidden;
  color: var(--gold);
  font-weight: 900;
  text-overflow: ellipsis;
}

.menu-waiting-game-turn {
  color: var(--ink-on-dark);
  opacity: 0.65;
  font-size: 0.78rem;
  font-weight: 900;
  white-space: nowrap;
}

.player-setup {
  display: none;
  justify-items: center;
  gap: 0.65rem;
  width: 100%;
  max-width: 42rem;
}

.player-name-list {
  display: grid;
  gap: 0.45rem;
}

.invite-setup {
  display: grid;
  justify-items: stretch;
  gap: 0.65rem;
  width: min(82vw, 32rem);
  font: 700 0.9rem/1.35 system-ui, sans-serif;
  text-align: left;
}

/* Standard setup panel: solid cell-border card, 12px radius (owner call
   2026-07-17: one box treatment, no dashed borders in UI chrome). */
.friend-invite-panel {
  position: relative;
  display: grid;
  gap: 0.5rem;
  padding: 0.75rem 0.9rem;
  border: 2px solid var(--cell-border);
  border-radius: 12px;
  background: var(--surface);
}

html[data-theme="dark"] .friend-invite-panel {
  background: var(--surface-raised);
}

.friend-invite-panel h3 {
  margin: 0;
  color: var(--ink-muted);
  font: 400 0.85rem/1 "Righteous", "Trebuchet MS", sans-serif;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.friend-invite-list {
  display: grid;
  gap: 0.4rem;
}

.friend-invite-empty,
.invite-copy,
.invite-link-copy {
  margin: 0;
  color: var(--ink-muted);
  font: 700 0.86rem/1.35 system-ui, sans-serif;
}

.friend-invite-option {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 0.55rem;
  min-height: 2.75rem;
  padding: 0.48rem 0.65rem;
  border: 2px solid var(--cell-border);
  border-radius: 8px;
  background: var(--surface-raised);
}

.friend-invite-option input {
  width: 1.05rem;
  height: 1.05rem;
  accent-color: var(--coral);
}

.friend-invite-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--ink);
  font-weight: 900;
}

.friend-invite-recency {
  color: var(--ink-muted);
  font-size: 0.78rem;
  font-weight: 800;
  white-space: nowrap;
}

/* Invite panel: standard setup card with the stamp corner kept */
.invite-link-panel {
  display: none;
  position: relative;
  justify-items: center;
  gap: 0.42rem;
  width: min(82vw, 32rem);
  padding: 0.75rem 0.9rem;
  border: 2px solid var(--cell-border);
  border-radius: 12px;
  background: var(--surface);
  font: 700 0.9rem/1.35 system-ui, sans-serif;
}

.invite-link-panel::after {
  content: "\2709";
  position: absolute;
  top: -0.55rem;
  right: 0.65rem;
  display: grid;
  place-items: center;
  width: 1.5rem;
  height: 1.5rem;
  border: 1px solid var(--gold-deep);
  border-radius: 3px;
  background: var(--gold);
  color: var(--ink);
  font-size: 0.85rem;
  transform: rotate(6deg);
  pointer-events: none;
}

html[data-theme="dark"] .invite-link-panel {
  border-color: var(--pink-neon);
  background: var(--surface-raised);
}

html[data-theme="dark"] .invite-link-panel::after {
  border-color: var(--cyan-neon);
  background: var(--sign-face);
  color: var(--cyan-neon);
}

body.screen-play .invite-link-panel {
  display: grid;
}

body.screen-play .invite-link-panel[hidden],
.invite-link-panel[hidden] {
  display: none;
}

.invite-link-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.5rem;
}

.invite-link-value {
  max-width: 100%;
  overflow-wrap: anywhere;
  color: var(--coral);
  font: 800 0.82rem/1.35 system-ui, sans-serif;
}

html[data-theme="dark"] .invite-link-value {
  color: var(--cyan-neon);
}

.player-name-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 0.45rem;
  padding: 0.3rem;
  border: 2px solid var(--cell-border);
  border-radius: 8px;
  background: var(--surface);
}

html[data-theme="dark"] .player-name-row {
  background: var(--surface-raised);
}

.player-name-row.locked .player-name-input {
  grid-column: 1 / -1;
}

/* Setup fieldsets share the standard panel card (no UA fieldset chrome). */
.game-length-control,
.game-mode-control,
.game-theme-control {
  border: 2px solid var(--cell-border);
  border-radius: 12px;
  margin: 0;
  padding: 0.75rem 0.9rem 0.9rem;
}

.game-length-control {
  display: grid;
  gap: 0.5rem;
  justify-items: center;
  font: 800 0.86rem/1 system-ui, sans-serif;
}

.game-length-control legend {
  color: var(--ink-muted);
  font: 400 0.78rem/1 "Righteous", "Trebuchet MS", sans-serif;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 0 0.4rem;
}

.game-length-options {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.55rem;
}

/* Billboard card: cream face, coral border + lift when its radio is checked */
.game-length-option {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  min-height: 2.75rem;
  padding: 0.5rem 0.85rem;
  border: 2px solid var(--cell-border);
  border-radius: 8px;
  background: var(--surface);
  box-shadow: 0.14rem 0.14rem 0 var(--shadow-soft);
  cursor: pointer;
  transition: border-color 140ms ease, box-shadow 140ms ease, transform 140ms ease;
}

.game-length-option:has(input:checked) {
  border-color: var(--coral);
  background: var(--surface-raised);
  box-shadow: 0.18rem 0.18rem 0 var(--coral-deep);
  transform: translateY(-0.08rem);
}

html[data-theme="dark"] .game-length-option:has(input:checked) {
  border-color: var(--gold);
  box-shadow:
    0.18rem 0.18rem 0 var(--coral-deep),
    0 0 calc(12px * var(--glow-strength)) var(--gold-glow);
}

.game-length-option input:focus-visible {
  outline: 2px solid var(--coral);
  outline-offset: 2px;
}

html[data-theme="dark"] .game-length-option input:focus-visible {
  outline-color: var(--gold);
}

.game-length-copy {
  display: grid;
  gap: 0.12rem;
}

.game-length-name {
  color: var(--ink);
  font: 400 1rem/1 "Righteous", "Trebuchet MS", sans-serif;
  letter-spacing: 0.02em;
}

.game-length-pool {
  color: var(--ink-muted);
  font: 800 0.68rem/1 system-ui, sans-serif;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
}

.game-mode-control {
  display: grid;
  justify-items: center;
  gap: 0.5rem;
  max-width: 30rem;
}

.game-mode-control legend {
  color: var(--ink-muted);
  font: 400 0.78rem/1 "Righteous", "Trebuchet MS", sans-serif;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 0 0.4rem;
}

.game-mode-selector {
  display: flex;
  align-items: center;
  gap: 0.65rem;
}

.game-mode-label {
  color: var(--ink-muted);
  font: 800 0.82rem/1 system-ui, sans-serif;
  cursor: pointer;
  user-select: none;
  transition: color 140ms ease;
}

.game-mode-label.is-selected {
  color: var(--ink);
}

.game-mode-switch {
  position: relative;
  display: inline-flex;
  cursor: pointer;
}

.game-mode-switch input {
  position: absolute;
  inset: 0;
  z-index: 1;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: inherit;
}

.game-mode-track {
  position: relative;
  width: 3.4rem;
  height: 1.8rem;
  border: 2px solid var(--cell-border);
  border-radius: 999px;
  background: var(--surface);
  box-shadow: 0.12rem 0.12rem 0 var(--shadow-soft);
  transition: border-color 140ms ease, background 140ms ease, box-shadow 140ms ease;
}

.game-mode-thumb {
  position: absolute;
  top: 0.18rem;
  left: 0.2rem;
  width: 1.16rem;
  height: 1.16rem;
  border-radius: 50%;
  background: var(--teal-deep);
  transition: transform 160ms ease, background 140ms ease;
}

.game-mode-switch input:checked + .game-mode-track {
  border-color: var(--coral);
  background: var(--surface-raised);
  box-shadow: 0.14rem 0.14rem 0 var(--coral-deep);
}

.game-mode-switch input:checked + .game-mode-track .game-mode-thumb {
  background: var(--coral);
  transform: translateX(1.55rem);
}

.game-mode-switch input:focus-visible + .game-mode-track {
  outline: 2px solid var(--coral);
  outline-offset: 3px;
}

.game-mode-switch input:disabled + .game-mode-track {
  cursor: wait;
  opacity: 0.6;
}

.game-mode-switch input:disabled {
  cursor: wait;
}

.game-mode-help {
  min-height: 2.35em;
  margin: 0;
  color: var(--ink-muted);
  font: 700 0.78rem/1.35 system-ui, sans-serif;
  text-align: center;
}

.player-name-input {
  min-height: 2.75rem;
  width: min(82vw, 22rem);
  border: 2px solid var(--cell-border);
  border-radius: 999px;
  padding: 0.65rem 1.05rem;
  background: var(--surface-raised);
  color: var(--ink);
  font: 700 1rem/1 system-ui, sans-serif;
  transition: border-color 140ms ease, box-shadow 140ms ease;
}

.player-name-input:focus-visible {
  outline: none;
  border-color: var(--coral);
  box-shadow: 0 0 0 3px var(--orange-glow);
}

html[data-theme="dark"] .player-name-input:focus-visible {
  border-color: var(--gold);
  box-shadow: 0 0 0 3px var(--gold-glow);
}

.player-name-remove {
  min-width: 2.75rem;
  padding-inline: 0.75rem;
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  clip-path: inset(50%);
}

.game-button {
  min-height: 2.75rem;
  border: 2px solid var(--ink);
  border-radius: 999px;
  padding: 0.7rem 1.1rem;
  background: var(--coral);
  color: var(--on-accent-ink);
  cursor: pointer;
  font: 700 1rem/1 system-ui, sans-serif;
  box-shadow: 0.18rem 0.18rem 0 var(--coral-deep);
}

.game-button.secondary {
  background: var(--surface-raised);
  color: var(--ink);
  box-shadow: 0.18rem 0.18rem 0 var(--cell-border);
}

.game-button:hover {
  background: var(--orange);
}

.game-button.secondary:hover {
  background: var(--surface);
}

.game-button:focus-visible {
  outline: 2px solid var(--coral);
  outline-offset: 2px;
}

html[data-theme="dark"] .game-button:focus-visible {
  outline-color: var(--gold);
}

.oauth-button.game-button.secondary,
.public-leaderboard-button.game-button.secondary,
.identity-menu > .game-button.secondary,
.active-games-actions > .game-button.secondary {
  min-height: 3.1875rem;
}

.active-games {
  grid-column: 1 / -1;
  clear: both;
  justify-self: center;
  width: 100%;
  max-width: 42rem;
  display: none;
  margin-top: clamp(1.5rem, 3vw, 2.25rem);
  gap: 0.65rem;
  justify-items: stretch;
  font: 700 0.95rem/1.35 system-ui, sans-serif;
}

.leaderboard-page {
  grid-column: 1 / -1;
  clear: both;
  justify-self: center;
  width: var(--play-width);
  max-width: var(--play-width);
  display: none;
  margin-top: clamp(1.5rem, 3vw, 2.25rem);
  gap: 0.65rem;
  justify-items: stretch;
  font: 700 0.95rem/1.35 system-ui, sans-serif;
}

.profile-page {
  grid-column: 1 / -1;
  clear: both;
  justify-self: center;
  width: var(--play-width);
  max-width: var(--play-width);
  display: none;
  margin-top: clamp(1.5rem, 3vw, 2.25rem);
  gap: 0.75rem;
  justify-items: stretch;
  font: 700 0.95rem/1.35 system-ui, sans-serif;
}

.leaderboard-title,
.game-list-title,
.rules-title,
.changelog-title,
.spectator-title,
.profile-title,
.new-game-title {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
}

.leaderboard-title .leaderboard-crown-icon,
.game-list-title .game-list-crossword-icon,
.rules-title .rules-guide-icon,
.changelog-title .changelog-history-icon,
.spectator-title .spectator-eyeglasses-icon,
.profile-title .profile-account-icon,
.new-game-title .create-game-playlist-icon {
  width: 1.8rem;
  height: 1.8rem;
}

/* Shared with the reset-password panel's copy line. */
.display-name-copy {
  margin: 0;
  color: var(--ink-muted);
  font: 700 0.98rem/1.35 system-ui, sans-serif;
  text-align: center;
}

.section-title {
  position: relative;
  margin: 0;
  color: var(--ink);
  font: 400 clamp(1.35rem, 4vw, 2rem)/1 "Righteous", "Trebuchet MS", sans-serif;
  letter-spacing: 0.02em;
  text-align: center;
}

.active-games-list {
  display: grid;
  gap: 0.8rem;
}

.leaderboard-summary {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0.55rem;
}

.leaderboard-summary-item,
.leaderboard-highlight-item {
  display: grid;
  min-width: 0;
  border: 2px solid var(--cell-border);
  border-radius: 8px;
  background: var(--surface);
  box-shadow: 0.12rem 0.12rem 0 var(--shadow-soft);
}

.leaderboard-summary-item {
  gap: 0.22rem;
  padding: 0.6rem 0.65rem;
}

.leaderboard-summary-value,
.leaderboard-highlight-value {
  min-width: 0;
  overflow: hidden;
  color: var(--coral);
  font: 950 1.02rem/1.08 system-ui, sans-serif;
  text-overflow: ellipsis;
  white-space: nowrap;
}

html[data-theme="dark"] .leaderboard-summary-value,
html[data-theme="dark"] .leaderboard-highlight-value {
  color: var(--gold);
}

.leaderboard-summary-label,
.leaderboard-highlight-label {
  color: var(--ink-muted);
  font: 950 0.62rem/1 system-ui, sans-serif;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.leaderboard-highlights {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(8.8rem, 1fr));
  gap: 0.5rem;
  min-width: 0;
}

.leaderboard-highlight-item {
  display: grid;
  grid-template-rows: auto minmax(1.45rem, auto) auto auto;
  gap: 0.22rem;
  padding: 0.6rem 0.65rem;
}

.leaderboard-highlights a,
.leaderboard-highlights a:visited,
.leaderboard-highlights a:hover,
.leaderboard-highlights a:focus,
.leaderboard-highlight-link {
  color: inherit;
  text-decoration: none;
  text-decoration-line: none;
}

.leaderboard-highlight-link {
  cursor: pointer;
}

.leaderboard-highlight-link *,
.leaderboard-highlight-link *:visited {
  text-decoration: none;
  text-decoration-line: none;
}

.leaderboard-highlight-link:hover,
.leaderboard-highlight-link:focus-visible {
  border-color: var(--teal);
  box-shadow: 0.16rem 0.16rem 0 var(--teal-glow);
  outline: none;
}

.leaderboard-highlight-link:focus-visible {
  outline: 2px solid var(--coral);
  outline-offset: 2px;
}

html[data-theme="dark"] .leaderboard-highlight-link:focus-visible {
  outline-color: var(--gold);
}

.leaderboard-highlight-detail {
  min-width: 0;
  overflow: hidden;
  color: var(--ink-muted);
  font: 750 0.74rem/1.12 system-ui, sans-serif;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.leaderboard-highlight-words {
  display: grid;
  gap: 0.12rem;
  min-width: 0;
  padding-top: 0.15rem;
}

.leaderboard-highlight-words span {
  min-width: 0;
  overflow: hidden;
  color: var(--ink);
  font: 950 0.78rem/1.05 system-ui, sans-serif;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.leaderboard-highlight-item-words-value .leaderboard-highlight-words {
  align-self: start;
  padding-top: 0;
}

.leaderboard-highlight-item-words-value .leaderboard-highlight-words span {
  color: var(--coral);
  font-size: 1.02rem;
  line-height: 1.08;
}

html[data-theme="dark"] .leaderboard-highlight-item-words-value .leaderboard-highlight-words span {
  color: var(--gold);
}

.leaderboard-table {
  display: grid;
  gap: 0.32rem;
  min-width: 0;
}

/* Zebra cream rows on the diner-style leaderboard table */
.leaderboard-row {
  display: grid;
  grid-template-columns: 3.3rem minmax(0, 1fr) minmax(5.4rem, auto) minmax(5.2rem, auto) minmax(4.2rem, auto) minmax(4.2rem, auto);
  align-items: center;
  gap: 0.5rem;
  min-height: 2.9rem;
  padding: 0.5rem 0.65rem;
  border: 2px solid var(--cell-border);
  border-radius: 8px;
  background: var(--surface);
  font: 400 0.92rem/1.15 system-ui, sans-serif;
}

/* nth-child (not nth-of-type): rows are a mix of <a> (linked players) and
   <div> (unlinked), and nth-of-type counts each element type separately. */
.leaderboard-row:not(.leaderboard-header):nth-child(even) {
  background: var(--surface-raised);
}

.leaderboard-row span {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.leaderboard-row span:nth-child(1) {
  text-align: center;
}

.leaderboard-row span:nth-child(n + 3) {
  text-align: right;
}

.leaderboard-row:not(.leaderboard-header) span:nth-child(2) {
  color: var(--ink);
  text-align: left;
}

.leaderboard-header {
  min-height: 2.2rem;
  background: transparent;
  color: var(--ink-muted);
  font: 950 0.66rem/1 system-ui, sans-serif;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* Rank #1 highlight row: gold fill, first data row right after the header.
   .leaderboard-table prefix keeps specificity >= the zebra rule above so the gold fill wins. */
.leaderboard-table .leaderboard-header + .leaderboard-row {
  border-color: var(--gold-deep);
  background: linear-gradient(135deg, var(--gold-wash), var(--surface-raised) 70%);
  box-shadow: 0.14rem 0.14rem 0 var(--gold-deep);
  font-weight: 800;
}

html[data-theme="dark"] .leaderboard-table .leaderboard-header + .leaderboard-row {
  border-color: var(--gold);
  background: linear-gradient(135deg, var(--gold-wash), var(--surface-raised) 70%);
  box-shadow: 0 0 calc(12px * var(--glow-strength)) var(--gold-glow);
}

.leaderboard-empty {
  display: grid;
  min-height: 4.5rem;
  place-items: center;
  border: 2px solid var(--cell-border);
  border-radius: 8px;
  color: var(--ink-muted);
  font: 400 0.95rem/1.25 system-ui, sans-serif;
}

.active-games-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.65rem;
}

.new-game-disabled-link {
  display: none;
}

html.new-games-disabled .new-game-enabled-control {
  display: none;
}

html.new-games-disabled .new-game-disabled-link {
  display: inline-flex;
}

/* Same creation-hiding technique as new-games-disabled above, but scoped to
   the unverified-email gate: only the create-game controls are hidden (no
   new-game-disabled-link swap-in -- that link's "go to WordWefter.com" copy
   doesn't apply here; the verify-to-create-note below explains instead). */
body.email-unverified .new-game-enabled-control {
  display: none;
}

/* In-panel explanation for the setup screen while unverified -- the menu's
   New Game entry stays clickable, so without this the screen would show only
   its title. Text styling matches the panel's .invite-copy blurb. */
.verify-to-create-note {
  display: none;
  margin: 0;
  color: var(--ink-muted);
  font: 700 0.86rem/1.35 system-ui, sans-serif;
}

body.email-unverified .verify-to-create-note {
  display: block;
}

.active-games-group {
  display: grid;
  gap: 0.45rem;
}

.active-games-group + .active-games-group {
  margin-top: 0.55rem;
}

.active-games-group-title {
  justify-self: start;
  margin: 0;
  padding: 0.14rem 0.42rem;
  border: 2px solid var(--sign-face);
  border-radius: 5px;
  background: var(--surface);
  color: var(--ink);
  font: 400 0.72rem/1 "Righteous", "Trebuchet MS", sans-serif;
  letter-spacing: 0.08em;
  text-align: left;
  text-transform: uppercase;
}

/* Motel-sign card: cream name plate, coral border, gold YOUR TURN tab when it's your move */
.active-game-row {
  position: relative;
  display: grid;
  grid-template-columns: 5.5rem minmax(0, 1fr);
  align-items: center;
  gap: 0.7rem;
  padding: 0.6rem 0.7rem;
  border: 2px solid var(--cell-border);
  border-radius: 8px;
  background: var(--surface);
  text-align: left;
  box-shadow: 0.14rem 0.14rem 0 var(--shadow-soft);
  cursor: pointer;
  transition: transform 120ms ease, box-shadow 120ms ease;
}

/* The entire card links into the game (issue #40): a transparent anchor
   stretched over the card. Player-name links sit above it (z-index below) so a
   click on a name still routes to that profile. */
.active-game-open-link {
  position: absolute;
  inset: 0;
  z-index: 1;
  border-radius: inherit;
  font-size: 0;
}

.active-game-open-link:focus-visible {
  outline: 2px solid var(--coral);
  outline-offset: 2px;
}

html[data-theme="dark"] .active-game-open-link:focus-visible {
  outline-color: var(--gold);
}

.active-game-row:hover {
  transform: translateY(-0.08rem);
  box-shadow: 0.2rem 0.24rem 0 var(--shadow-soft);
}

/* A real player-name link outranks the card link so it stays independently
   clickable; empty "Open Spot" pills have no link and fall through to the card
   link, so clicking them still opens the game. */
.active-game-player-list .active-game-player-name a {
  position: relative;
  z-index: 2;
}

/* No per-row "Your Turn" tab — the group heading already says it; the gold
   border/shadow alone marks waiting games. */
.active-game-row.waiting-player {
  border-color: var(--gold-deep);
  background: var(--surface-raised);
  box-shadow: 0.18rem 0.18rem 0 var(--gold-deep);
}

html[data-theme="dark"] .active-game-row.waiting-player {
  border-color: var(--gold);
  box-shadow: 0 0 calc(12px * var(--glow-strength)) var(--gold-glow);
}

.active-game-row.completed-game {
  border-color: var(--cell-border);
  background: var(--surface);
  opacity: 0.82;
}

.active-games-empty {
  display: grid;
  justify-items: start;
  gap: 0.3rem;
  padding: 1rem;
  border: 2px solid var(--cell-border);
  border-radius: 8px;
  background: var(--surface);
  text-align: left;
  box-shadow: 0.18rem 0.18rem 0 var(--gold-glow);
}

.active-games-empty-title {
  margin: 0;
  color: var(--ink);
  font: 900 1.05rem/1.15 Georgia, "Times New Roman", serif;
}

.active-games-empty-copy {
  margin: 0;
  color: var(--ink-muted);
  font: 700 0.9rem/1.35 system-ui, sans-serif;
}

/* Column 1: game ID / Turn / Pool stacked in a fixed-width column so column 2
   (badges + player pills) shares one left edge across every card (issue #40).
   The 5.5rem width clears the widest 5-char code and "Pool 130/136". */
.active-game-id {
  align-self: start;
  display: grid;
  gap: 0.28rem;
  color: var(--ink);
  font: 900 0.95rem/1 system-ui, sans-serif;
  letter-spacing: 0.08em;
}

.active-game-code {
  white-space: nowrap;
}

/* Column 2: mode/theme badges above the player pills. */
.active-game-detail {
  min-width: 0;
  align-self: start;
  display: grid;
  gap: 0.35rem;
}

.active-game-badges {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
}

.game-mode-badge {
  display: inline-flex;
  width: max-content;
  padding: 0.18rem 0.4rem;
  border: 1px solid var(--cell-border);
  border-radius: 999px;
  background: var(--surface-raised);
  color: var(--ink-muted);
  font: 800 0.58rem/1 system-ui, sans-serif;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.game-mode-badge[data-game-mode="competitive"] {
  border-color: var(--hot-accent);
  color: var(--hot-accent);
}

.game-list-mode-badge {
  padding-block: 0.12rem;
}

/* Word-theme chip on a game-list card: same pill shape as the mode badge, in
   the theme (plum/pink) accent so it reads as a different axis from mode. */
.game-theme-badge {
  display: inline-flex;
  width: max-content;
  padding: 0.18rem 0.4rem;
  border: 1px solid var(--theme-accent);
  border-radius: 999px;
  background: var(--surface-raised);
  color: var(--theme-accent-deep);
  font: 800 0.58rem/1 system-ui, sans-serif;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

html[data-theme="dark"] .game-theme-badge {
  color: var(--theme-accent);
}

.game-list-theme-badge {
  padding-block: 0.12rem;
}

.active-game-turn {
  color: var(--teal-deep);
  font: 800 0.78rem/1.25 system-ui, sans-serif;
  letter-spacing: 0;
}

html[data-theme="dark"] .active-game-turn {
  color: var(--cyan-neon);
}

.active-game-pool {
  color: var(--ink-muted);
  font: 800 0.72rem/1.2 system-ui, sans-serif;
  letter-spacing: 0;
}

.active-game-player-list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(7rem, max-content));
  align-items: center;
  gap: 0.35rem;
  min-width: 0;
  letter-spacing: 0;
}

.active-game-player-score {
  display: inline-grid;
  grid-template-columns: minmax(0, 1fr) auto;
  /* center, not baseline: the winner name is an inline-flex with a star, whose
     synthesized baseline differs from plain text and shifted the score down. */
  align-items: center;
  gap: 0.25rem;
  min-width: 7rem;
  padding: 0.18rem 0.45rem;
  border: 1px solid var(--cell-border);
  border-radius: 6px;
  background: var(--surface-raised);
  white-space: nowrap;
}

.active-game-player-name {
  overflow: hidden;
  text-overflow: ellipsis;
}

.active-game-player-points {
  justify-self: end;
  text-align: right;
  font-weight: 900;
}

.active-game-player-score.current-player {
  color: var(--teal-deep);
  font-weight: 900;
  border-color: var(--teal);
  background: var(--cell);
}

html[data-theme="dark"] .active-game-player-score.current-player {
  color: var(--cyan-neon);
}

.active-game-player-score.winner-player {
  color: var(--coral-deep);
  font-weight: 900;
  border-color: var(--gold-deep);
  background: linear-gradient(135deg, var(--gold-wash), var(--surface-raised) 68%);
  box-shadow: 0.1rem 0.1rem 0 var(--gold-deep);
}

html[data-theme="dark"] .active-game-player-score.winner-player {
  color: var(--gold);
  background: linear-gradient(135deg, var(--gold-wash), var(--surface-raised) 68%);
}

.active-game-player-score.conceded-player {
  color: var(--ink-muted);
  border-color: var(--cell-border);
  background: var(--cell);
  text-decoration: line-through;
}

.active-game-player-score.winner-player .active-game-player-name {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  min-width: 0;
}

.active-game-player-score.winner-player .active-game-player-name::before {
  content: "";
  flex: 0 0 auto;
  width: 1rem;
  height: 1rem;
  background-color: var(--gold-deep);
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 1 14 8.5 21.5 6.5 16 12 21.5 17.5 14 15.5 12 23 10 15.5 2.5 17.5 8 12 2.5 6.5 10 8.5Z' fill='%23000'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 1 14 8.5 21.5 6.5 16 12 21.5 17.5 14 15.5 12 23 10 15.5 2.5 17.5 8 12 2.5 6.5 10 8.5Z' fill='%23000'/%3E%3C/svg%3E");
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
}

.page-hero,
.rules-hero {
  display: grid;
  gap: 0.55rem;
  width: 100%;
  padding-bottom: 0.45rem;
  border-bottom: 3px solid var(--cell-border);
}

.page-hero .section-title,
.rules-hero .section-title {
  text-align: left;
}

/* Rules highway: a vertical road runs down the center of the page, signs
   (rules cards) are planted on alternating shoulders and slide in from
   their side of the road as the page scrolls. */
.rules-grid {
  position: relative;
  display: grid;
  grid-template-columns: 1fr;
  gap: 3.75rem 0;
  padding: 0.5rem 0 2.5rem;
}

/* Asphalt strip + dashed centerline, tokens only. Sits behind the cards. */
.rules-grid::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 3rem;
  transform: translateX(-50%);
  background: var(--road-asphalt);
  background-image: linear-gradient(
    var(--road-centerline) 0,
    var(--road-centerline) 50%,
    transparent 50%,
    transparent 100%
  );
  background-repeat: repeat-y;
  background-position: center;
  background-size: 0.2rem 2.25rem;
  box-shadow: 0 0 1.5rem var(--road-centerline-glow);
  border-radius: 999px;
  pointer-events: none;
  z-index: 0;
}

/* Roadside postcard: cream card, coral border, gold drop shadow */
.rules-card {
  position: relative;
  z-index: 1;
  display: grid;
  gap: 0.55rem;
  align-content: start;
  width: min(100%, 22rem);
  padding: 0.85rem;
  border: 2px solid var(--coral);
  border-radius: 8px;
  background: var(--surface);
  box-shadow: 0.18rem 0.18rem 0 var(--gold-glow);
}

html[data-theme="dark"] .rules-card {
  border-color: var(--pink-neon);
  background: var(--surface-raised);
  box-shadow: 0 0 calc(10px * var(--glow-strength)) var(--gold-glow);
}

.rules-card h3 {
  margin: 0;
  color: var(--ink);
  font: 900 1.08rem/1.1 Georgia, "Times New Roman", serif;
}

.rules-card p,
.rules-card ul {
  margin: 0;
  color: var(--ink);
  font-weight: 500;
  line-height: 1.42;
}

.rules-card ul {
  padding-left: 1.1rem;
}

/* Signpost: a single sturdy post planted under each sign. It tucks up
   behind the card (negative z-index inside the card's stacking context)
   so the joint stays hidden even with the card's tilt. */
.rules-card::after {
  content: "";
  position: absolute;
  /* flush below the border: the card's tilt creates a stacking context that
     keeps z-index:-1 pseudos ABOVE the card, so any overlap paints over the
     sign (100% only reaches the INNER border edge). The post rotates with
     the card, so a flush joint stays seamless. */
  top: calc(100% + 2px);
  left: 50%;
  width: 0.7rem;
  height: 2.5rem;
  transform: translateX(-50%);
  background: linear-gradient(90deg, var(--sign-wood-deep), var(--sign-wood) 45%, var(--sign-wood-deep));
  border-radius: 0 0 4px 4px;
  box-shadow: inset 1px 0 0 var(--sheen-soft);
  pointer-events: none;
  z-index: -1;
}

/* Odd cards: left shoulder, slight left-leaning tilt. */
.rules-card:nth-child(odd) {
  justify-self: start;
  margin-left: clamp(0.5rem, 6vw, 3rem);
  rotate: -1.4deg;
}

/* Even cards: right shoulder, slight right-leaning tilt. */
.rules-card:nth-child(even) {
  justify-self: end;
  margin-right: clamp(0.5rem, 6vw, 3rem);
  rotate: 1.4deg;
}

/* Letter-points table sign: bigger diner menu board on two real posts. */
.rules-card:has(.letter-points-table) {
  width: min(100%, 26rem);
}

.rules-card:has(.letter-points-table)::before {
  content: "";
  position: absolute;
  top: calc(100% + 2px);
  left: 20%;
  width: 0.7rem;
  height: 2.5rem;
  transform: translateX(-50%);
  background: linear-gradient(90deg, var(--sign-wood-deep), var(--sign-wood) 45%, var(--sign-wood-deep));
  border-radius: 0 0 4px 4px;
  box-shadow: inset 1px 0 0 var(--sheen-soft);
  pointer-events: none;
  z-index: -1;
}

.rules-card:has(.letter-points-table)::after {
  left: 80%;
}

/* Scroll-in slide: default styles ARE the rest state, so browsers without
   scroll-timeline support (or reduced-motion) simply render signs at rest.
   The animation only pulls FROM an offset TO that same rest state. */
@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {
    .rules-card:nth-child(odd) {
      animation: rules-sign-slide-in-left linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 65%;
    }

    .rules-card:nth-child(even) {
      animation: rules-sign-slide-in-right linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 65%;
    }

    @keyframes rules-sign-slide-in-left {
      from {
        translate: -6rem 0;
        rotate: -8deg;
        opacity: 0;
      }

      to {
        translate: 0 0;
        rotate: -1.4deg;
        opacity: 1;
      }
    }

    @keyframes rules-sign-slide-in-right {
      from {
        translate: 6rem 0;
        rotate: 8deg;
        opacity: 0;
      }

      to {
        translate: 0 0;
        rotate: 1.4deg;
        opacity: 1;
      }
    }
  }
}

/* Narrow viewports: the content column runs nearly full width, so the
   "gutter" ornaments (starbursts / star field) would land on top of the
   panels — hide the scenery, keep Saturn (it hugs the top-right corner). */
@media (max-width: 700px) {
  body::before,
  body::after {
    display: none;
  }
}

/* Mobile: road moves to the left edge, every sign lines up in a single
   column to its right, offsets shrink so nothing can overflow. */
@media (max-width: 700px) {
  .rules-grid {
    gap: 2.75rem 0;
    padding-left: 1.6rem;
  }

  .rules-grid::before {
    left: 0.9rem;
    width: 1.6rem;
    transform: none;
    background-size: 0.14rem 1.6rem;
  }

  /* Leave a real right shoulder: full-width tilted cards otherwise rotate
     their corners past the container edge and get clipped by the section's
     overflow-x: clip. Gentler tilt + 0.85rem right margin keeps every corner
     (and the border glow) inside the viewport. */
  .rules-card,
  .rules-card:nth-child(odd),
  .rules-card:nth-child(even) {
    justify-self: start;
    width: calc(100% - 2.1rem);
    margin-left: 1.25rem;
    margin-right: 0.85rem;
  }

  .rules-card:nth-child(odd) {
    rotate: -0.8deg;
  }

  .rules-card:nth-child(even) {
    rotate: 0.8deg;
  }

  @media (prefers-reduced-motion: no-preference) {
    @supports (animation-timeline: view()) {
      @keyframes rules-sign-slide-in-left {
        from {
          translate: -2.5rem 0;
          rotate: -6deg;
          opacity: 0;
        }
      }

      @keyframes rules-sign-slide-in-right {
        from {
          translate: 2.5rem 0;
          rotate: 6deg;
          opacity: 0;
        }
      }
    }
  }
}

/* Diner menu board: dark header row, cream body rows */
.letter-points-table {
  width: 100%;
  border-collapse: collapse;
  overflow: hidden;
  border: 2px solid var(--sign-face);
  border-radius: 6px;
  background: var(--surface);
  font: 500 0.9rem/1.25 system-ui, sans-serif;
}

.letter-points-table th,
.letter-points-table td {
  padding: 0.32rem 0.48rem;
  border-bottom: 1px solid var(--cell-border);
  font-weight: 500;
  text-align: left;
}

.letter-points-table thead th {
  color: var(--ink-on-dark);
  background: var(--sign-face);
  font: 400 0.76rem/1 "Righteous", "Trebuchet MS", sans-serif;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.letter-points-table tbody th {
  width: 4.4rem;
  color: var(--coral);
  text-align: center;
}

html[data-theme="dark"] .letter-points-table tbody th {
  color: var(--gold);
}

.letter-points-table tbody tr:last-child th,
.letter-points-table tbody tr:last-child td {
  border-bottom: 0;
}

.letter-points-table td {
  color: var(--ink);
}

.changelog-list {
  display: grid;
  gap: 0.85rem;
  width: var(--play-width);
  justify-self: center;
}

/* "What's New" diner menu card */
.changelog-entry {
  display: grid;
  gap: 0.55rem;
  padding: 0.85rem;
  border: 2px solid var(--teal);
  border-radius: 8px;
  background: var(--surface);
  box-shadow: 0.18rem 0.18rem 0 var(--teal-deep);
}

html[data-theme="dark"] .changelog-entry {
  border-color: var(--cyan-neon);
  background: var(--surface-raised);
  box-shadow: 0 0 calc(10px * var(--glow-strength)) var(--teal-glow);
}

.changelog-entry h3,
.changelog-entry p {
  margin: 0;
}

.changelog-entry h3 {
  color: var(--ink);
  font: 900 1.08rem/1.1 Georgia, "Times New Roman", serif;
}

.changelog-entry .changelog-date {
  color: var(--ink-muted);
  font-size: 0.86rem;
  font-weight: 800;
}

.changelog-entry p {
  color: var(--ink);
  font-weight: 400;
  line-height: 1.42;
}

.rules-example,
.rules-board-example {
  --rules-board-cell-size: calc((var(--play-width) - 10px) / 9);
}

.rules-example {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem;
}

.rules-example .board-cell {
  width: var(--rules-board-cell-size);
  flex: 0 0 var(--rules-board-cell-size);
  aspect-ratio: 1;
}

.rules-board-example {
  display: grid;
  grid-template-columns: repeat(4, var(--rules-board-cell-size));
  grid-auto-rows: var(--rules-board-cell-size);
  gap: 2px;
  width: max-content;
  max-width: 100%;
  padding: 5px;
  border-radius: 10px;
  background: var(--board-frame);
}

.rules-board-example .board-cell {
  width: auto;
  flex: initial;
}

.rules-board-example-stack {
  grid-template-columns: repeat(3, var(--rules-board-cell-size));
}

.rules-example-bottom {
  margin-top: auto;
}

.rules-equation {
  color: var(--coral);
  font: 900 0.92rem/1.2 system-ui, sans-serif;
}

html[data-theme="dark"] .rules-equation {
  color: var(--gold);
}

.game-area {
  display: none;
  width: 100%;
  justify-items: center;
  gap: 1rem;
}

body.screen-play .masthead {
  margin-bottom: 0.75rem;
}

body.screen-play:not(.has-player) .masthead {
  margin-bottom: 0;
}

.rules-page,
.changelog-page {
  display: none;
  grid-column: 1 / -1;
  width: 100%;
  max-width: 54rem;
  gap: 1rem;
  text-align: left;
  font: 700 0.98rem/1.45 system-ui, sans-serif;
}

/* The highway's sliding signs animate via translate, which can nudge a sign
   past its own box during the scroll-in; clip locally so it never creates a
   page-level horizontal scrollbar. Scoped to this section only -- never on
   body/html ancestors of the game area. */
.rules-page {
  overflow-x: clip;
}

body.screen-rules .rules-page,
body.screen-changelog .changelog-page {
  margin-top: calc(clamp(1.5rem, 3vw, 2.25rem) - 0.75rem);
}

body.screen-rules .rules-hero,
body.screen-changelog .page-hero {
  width: var(--play-width);
  justify-self: center;
}

body.screen-welcome:not(.has-player) .identity-panel {
  display: grid;
  gap: 0.85rem;
}

body.screen-leaderboard:not(.has-player) .identity-panel {
  display: grid;
  gap: 0.85rem;
}

body.screen-play:not(.has-player) .identity-panel {
  display: grid;
  gap: 0.85rem;
}

body.screen-welcome:not(.has-player) .masthead {
  grid-template-columns: 1fr;
  justify-items: center;
  align-self: start;
}

body.screen-leaderboard:not(.has-player) .masthead,
body.screen-play:not(.has-player) .masthead {
  width: var(--play-width);
  grid-template-columns: 1fr;
  justify-items: center;
  align-self: start;
}

body.screen-welcome:not(.has-player) .brand,
body.screen-welcome:not(.has-player) .game-controls {
  justify-self: center;
}

body.screen-leaderboard:not(.has-player) .brand,
body.screen-play:not(.has-player) .brand,
body.screen-leaderboard:not(.has-player) .game-controls {
  justify-self: center;
}

body.screen-play:not(.has-player) .game-controls {
  justify-self: center;
}

body.screen-welcome:not(.has-player) .brand {
  --brand-scale: clamp(2.2rem, 8.4vw, 4.4rem); /* match privacy/terms sign size */
  margin-bottom: 0.18em;
}

body.screen-leaderboard:not(.has-player) .brand {
  --brand-scale: 1.5rem;
  margin-bottom: 0;
}

body.screen-play:not(.has-player) .brand {
  --brand-scale: 1.5rem;
  margin-bottom: 0;
}

body.screen-welcome:not(.has-player) main {
  align-content: start;
  padding-top: clamp(0.85rem, 2.3vw, 1.55rem);
}

body.screen-leaderboard:not(.has-player) main,
body.screen-play:not(.has-player) main {
  align-content: start;
  gap: 0.75rem;
  padding-top: clamp(0.85rem, 2vw, 1.35rem);
}

body.screen-welcome.welcome-demo .game-area {
  display: grid;
  gap: 1rem;
  margin-top: 1rem;
}

body.screen-welcome.welcome-demo .invite-link-panel,
body.screen-welcome.welcome-demo .rack-controls,
body.screen-welcome.welcome-demo .redraw-confirm,
body.screen-welcome.welcome-demo .pass-confirm,
body.screen-welcome.welcome-demo .game-log,
body.screen-welcome.welcome-demo .concede-game-control,
body.screen-welcome.welcome-demo .winner-banner,
body.screen-welcome.welcome-demo .player-score-list,
body.screen-welcome.welcome-demo #view-pool-button,
body.screen-welcome.welcome-demo .game-sheet {
  display: none;
}

body.screen-welcome.welcome-demo .rack {
  background: color-mix(in srgb, var(--teal) 12%, transparent);
}

body.screen-welcome.welcome-demo .rack-shuffle-button {
  display: grid;
}

body.screen-welcome.welcome-demo .tile-movable {
  cursor: grab;
}

body.screen-welcome.welcome-demo .tile-movable:active {
  cursor: grabbing;
}

body.screen-welcome.welcome-leaderboard .leaderboard-page {
  display: grid;
  margin-top: 1rem;
}

body.screen-welcome.welcome-leaderboard .leaderboard-page .page-hero {
  justify-items: center;
  text-align: center;
}

body.has-player .identity-bar {
  display: flex;
}

body.screen-setup .player-setup {
  display: grid;
}

body.screen-list .active-games,
body.screen-leaderboard .leaderboard-page {
  display: grid;
}

body.screen-rules .rules-page,
body.screen-changelog .changelog-page {
  display: grid;
}

body.screen-reset-password .reset-password-page {
  display: grid;
}

body.screen-profile .profile-page {
  display: grid;
}

body.screen-play .game-area {
  display: grid;
}

.spectator-hero {
  display: none;
  width: var(--play-width);
}

.spectator-title .spectator-eyeglasses-icon {
  color: var(--teal-deep);
}

body.screen-play.spectator-mode .spectator-hero {
  display: grid;
}

.board {
  display: grid;
  grid-template-columns: repeat(9, 1fr);
  grid-template-rows: repeat(9, minmax(0, 1fr));
  width: var(--play-width);
  aspect-ratio: 1;
  background: var(--board-frame);
  border-radius: 10px;
  gap: 2px;
  padding: 5px;
}

.board-cell {
  position: relative;
  display: grid;
  place-items: center;
  min-width: 0;
  min-height: 0;
  overflow: hidden;
  background: var(--cell);
  border: 1px solid var(--cell-border);
  border-radius: 4px;
}

/* Drag destination: Sortable parks its ghost inside the hovered legal cell —
   ring that cell so the drop target reads unmistakably. The extra .board term
   outranks the night bonus-cell glow rules, which would otherwise win the
   box-shadow. Glow term is night-only (--glow-strength is 0 by day). */
.board .board-cell:has(> .sortable-ghost) {
  border-color: var(--placement-accent);
  box-shadow:
    inset 0 0 0 2px var(--placement-accent),
    0 0 calc(8px * var(--glow-strength)) var(--placement-accent-soft);
}

.board-cell > .tile,
.board-cell > .marketplace-item {
  z-index: 3;
}

.board-cell-bonus-doubleLetter {
  background: var(--teal-soft);
  border-color: var(--teal-deep);
  color: var(--tile-ink); /* theme-stable dark ink: AA on the light teal fill */
}

.board-cell-bonus-tripleLetter {
  background: var(--teal-deep);
  border-color: var(--teal-deep);
  color: var(--on-accent-ink);
}

.board-cell-bonus-doubleWord {
  background: var(--gold);
  border-color: var(--gold-deep);
  color: var(--tile-ink); /* theme-stable: --ink flips to cream in dark, cream-on-gold fails */
}

.board-cell-bonus-tripleWord {
  background: var(--coral);
  border-color: var(--coral-deep);
  color: var(--ink-on-dark);
}

.board-cell-start {
  background: var(--gold);
  border-color: var(--gold-deep);
  color: var(--tile-ink); /* theme-stable: --ink flips to cream in dark, cream-on-gold fails */
}

.board-bonus-label {
  position: absolute;
  inset: 0.2rem;
  display: grid;
  align-content: center;
  place-items: center;
  gap: 0.08rem;
  font: 800 clamp(0.44rem, 1.15vw, 0.58rem)/1 system-ui, sans-serif;
  color: currentColor;
  text-align: center;
  text-transform: lowercase;
  pointer-events: none;
  user-select: none;
}

.board-bonus-multiplier,
.board-bonus-scope {
  display: block;
}

.board-start-label {
  position: absolute;
  inset: 0.2rem;
  display: grid;
  place-items: center;
  border-radius: 6px;
  color: var(--coral);
  font: 900 clamp(0.5rem, 1.35vw, 0.68rem)/1 system-ui, sans-serif;
  letter-spacing: 0.02em;
  text-align: center;
  text-transform: uppercase;
  pointer-events: none;
  user-select: none;
}

.board-start-label::before {
  content: "\2605";
  margin-right: 0.15em;
}

/* Bottom dock: sticky at viewport bottom on mobile, "counter edge" teal top border */
.rack-wrap {
  position: sticky;
  /* Only the rack + action buttons pin to the viewport bottom. The
     game/turn/potential/pool stats row is a separate sibling below (see
     .game-state-summary) so it naturally sits below the fold and scrolls in —
     no fragile fixed offset that breaks when tile height changes. */
  bottom: 0;
  z-index: 5;
  width: 100%;
  max-width: var(--play-width);
  display: grid;
  gap: 0.6rem;
  justify-items: start;
  margin-top: 0.25rem;
  padding: 0.6rem clamp(0.5rem, 3vw, 0.85rem) calc(0.6rem + env(safe-area-inset-bottom, 0px));
  border-top: 3px solid var(--teal);
  background: var(--surface);
  box-shadow: 0 -4px 12px var(--shadow-soft);
}

html[data-theme="dark"] .rack-wrap {
  border-top-color: var(--cyan-neon);
  box-shadow: 0 0 calc(14px * var(--glow-strength)) var(--teal-glow);
}

@media (min-width: 1024px) {
  .rack-wrap {
    position: static;
  }
}

/* Wide viewports: the play column stays centered (identical flow to mobile,
   so the board sits on the true page centerline). At >=1280px — when there is
   room for half the board plus a 20rem panel beside it — the Scores & Log
   sheet detaches into a fixed panel floating to the right of the board, and
   its toggle disappears. Between 1024px and 1279px it remains the collapsible
   sheet under the dock. Fixed positioning is measured from the viewport
   centerline, which matches the board's centerline because the play column
   is centered. */
@media (min-width: 1280px) {
  body.screen-play .marketplace-wrap {
    anchor-name: --market-sign;
  }

  body.screen-play #game-sheet {
    position: fixed;
    /* Align the panel's top edge with the market sign. anchor() needs CSS
       anchor positioning; the rem value is the fallback for browsers that
       drop the anchor declaration at parse time. */
    top: 8.25rem;
    top: anchor(--market-sign top);
    left: calc(50vw + var(--play-width) / 2 + 1.75rem);
    width: 20rem;
    /* Content-sized (hugs short logs, so buttons keep their natural size),
       but capped so a long log scrolls INSIDE the panel instead of running
       off the bottom. 17rem ≈ market-sign top (~15.5rem) + bottom gap; the
       panel starts at the sign and ends ~1.5rem above the viewport bottom. */
    max-height: calc(100dvh - 17rem);
    overflow-y: auto;
    opacity: 1;
    padding: 0.85rem;
    z-index: 4;
    border: 2px solid var(--cell-border);
    border-radius: 12px;
    background: var(--surface);
    box-shadow: 0.18rem 0.18rem 0 var(--shadow-soft);
  }

  /* The 20rem side panel only fits ~6 returned tiles beside the label before
     the row wraps mid-way. Give "Returned" its own line so every tile tucks
     beneath it as a single block instead of breaking after the 6th. */
  body.screen-play #game-sheet .game-log-returned-label {
    flex-basis: 100%;
  }

}

.rack {
  position: relative;
  anchor-name: --rack;
  width: 100%;
  min-height: 4.75rem;
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  grid-auto-rows: minmax(0, 1fr);
  gap: clamp(0.35rem, 1.8vw, 0.75rem);
  padding: calc(clamp(0.45rem, 1.8vw, 0.75rem) + 0.42rem) clamp(0.45rem, 1.8vw, 0.75rem) clamp(0.45rem, 1.8vw, 0.75rem);
  border: 2px solid var(--cell-border);
  border-radius: 8px;
  background: var(--cell);
}

body.screen-play.is-my-turn .rack {
  background: var(--cell);
  border-color: var(--teal);
}

.last-turn-notice {
  display: none;
  width: 100%;
  justify-self: center;
  align-items: center;
  justify-content: center;
  gap: 0.45rem;
  min-height: 2.2rem;
  padding: 0.36rem 0.75rem;
  border: 2px solid var(--gold-deep);
  border-radius: 8px;
  background: var(--gold);
  color: var(--ink);
  font: 900 0.9rem/1.15 system-ui, sans-serif;
  letter-spacing: 0.06em;
  text-align: center;
  text-transform: uppercase;
  box-shadow: 0.12rem 0.12rem 0 var(--shadow-soft);
}

html[data-theme="dark"] .last-turn-notice {
  background: var(--sign-face);
  color: var(--gold);
  border-color: var(--gold);
  box-shadow: 0 0 calc(10px * var(--glow-strength)) var(--gold-glow);
}

.last-turn-notice .ww-icon {
  width: 1.15rem;
  height: 1.15rem;
}

body.screen-play.last-turn:not(.game-over) .last-turn-notice {
  display: flex;
}

.marketplace-wrap {
  width: var(--play-width);
  display: grid;
  gap: 0.35rem;
  justify-items: start;
  position: relative;
}

/* MARKET sign: coral post (stacked letters + gold starburst) + dark letter-board holding the tile rack */
.market-sign {
  display: flex;
  align-items: stretch;
  width: 100%;
}

.market-sign-post {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  position: relative;
  padding: 0.6rem 0.4rem 0.5rem;
  border-radius: 8px 0 0 12px;
  background: var(--sign-post);
  box-shadow:
    inset 0 2px 0 var(--sheen-soft),
    0 0 calc(10px * var(--glow-strength)) var(--coral-glow);
  border: 1.5px solid var(--pink-neon);
  border-right: none;
}

html:not([data-theme="dark"]) .market-sign-post {
  border-color: transparent;
}

.market-sign-star {
  position: absolute;
  top: -0.95rem;
  left: 50%;
  transform: translateX(-50%);
  color: var(--gold);
  font-size: 1.4rem;
  line-height: 1;
  text-shadow:
    1px 1px 0 var(--coral-deep),
    0 0 calc(10px * var(--glow-strength)) var(--gold-glow),
    0 0 calc(20px * var(--glow-strength)) var(--gold-glow);
}

.market-sign-letters {
  font-size: 0.72rem;
  font-weight: 400;
  line-height: 1.28;
  text-align: center;
  color: var(--ink-on-dark);
  text-shadow: 1px 1px 0 var(--shade-soft);
}

html[data-theme="dark"] .market-sign-letters {
  color: var(--pink-neon);
  text-shadow:
    0 0 calc(7px * var(--glow-strength)) var(--coral-glow),
    0 0 calc(14px * var(--glow-strength)) var(--coral-glow);
}

.market-sign-board {
  position: relative;
  flex: 1 1 auto;
  min-width: 0;
  padding: 0.5rem 0.5rem 0;
  border-radius: 0 14px 14px 6px;
  background: var(--sign-face);
  box-shadow:
    inset 0 2px 0 var(--sheen-soft),
    0 4px 10px var(--shadow-soft),
    0 0 calc(12px * var(--glow-strength)) var(--teal-glow);
  border: 1.5px solid var(--cyan-neon);
}

html:not([data-theme="dark"]) .market-sign-board {
  border-color: transparent;
}

.market-sign-open-tab {
  position: absolute;
  right: -0.5rem;
  top: -0.65rem;
  z-index: 4;
  padding: 0.16rem 0.5rem;
  border-radius: 999px;
  background: var(--teal);
  color: var(--on-accent-ink);
  font-size: 0.5rem;
  font-weight: 400;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  transform: rotate(6deg);
  box-shadow: 0 2px 0 var(--teal-deep);
  pointer-events: none;
}

@media (max-width: 520px) {
  .market-sign-open-tab {
    right: 0;
  }
}

html[data-theme="dark"] .market-sign-open-tab {
  background: var(--sign-face);
  color: var(--cyan-neon);
  border: 1px solid var(--cyan-neon);
  box-shadow: 0 0 calc(10px * var(--glow-strength)) var(--teal-glow);
  text-shadow: 0 0 calc(6px * var(--glow-strength)) var(--teal-glow);
  animation: market-sign-open-tab-buzz 2600ms ease-in-out infinite;
}

/* The OPEN tab only shows when the market is actually open — renderGame()
   toggles these body classes for the Opening Soon and Closed states. */
body.marketplace-opening-soon .market-sign-open-tab,
body.marketplace-closed .market-sign-open-tab {
  display: none;
}

@media (prefers-reduced-motion: reduce) {
  html[data-theme="dark"] .market-sign-open-tab {
    animation: none;
  }
}

@keyframes market-sign-open-tab-buzz {
  0%, 88%, 100% {
    opacity: 1;
  }

  90% {
    opacity: 0.55;
  }

  92% {
    opacity: 1;
  }

  94% {
    opacity: 0.7;
  }
}

.marketplace {
  position: relative;
  width: 100%;
  min-height: 4.75rem;
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  grid-auto-rows: minmax(0, 1fr);
  gap: clamp(0.35rem, 1.8vw, 0.75rem);
  padding: clamp(0.45rem, 1.8vw, 0.75rem) clamp(0.45rem, 1.8vw, 0.75rem) 1.7rem;
}

.marketplace-closed-sign,
.marketplace-opening-soon-sign {
  position: absolute;
  top: 50%;
  left: 50%;
  z-index: 6;
  display: grid;
  place-items: center;
  min-width: min(12rem, 62%);
  min-height: 2.75rem;
  padding: 0.4rem 1rem;
  border-radius: 6px;
  font: 400 clamp(1rem, 4.6vw, 1.6rem)/1 "Righteous", "Trebuchet MS", sans-serif;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  transform: translate(-50%, -50%) rotate(-5deg);
  pointer-events: none;
}

.marketplace-opening-soon-sign {
  min-width: min(17rem, 84%);
  border: 3px solid var(--coral);
  background: var(--sign-face);
  color: var(--gold);
  box-shadow:
    0.18rem 0.22rem 0 var(--shadow-soft),
    0 0 calc(14px * var(--glow-strength)) var(--gold-glow);
  transform: translate(-50%, -50%) rotate(3deg);
}

.marketplace-opening-soon-sign::before {
  content: "✶ ";
}

.marketplace-closed-sign {
  border: 3px solid var(--coral);
  background: var(--tile-face);
  color: var(--coral);
  box-shadow: 0.18rem 0.22rem 0 var(--shadow-soft);
}

html[data-theme="dark"] .marketplace-opening-soon-sign {
  border-color: var(--cyan-neon);
}

html[data-theme="dark"] .marketplace-closed-sign {
  border-color: var(--pink-neon);
  color: var(--pink-neon);
}

/* Winner banner: neon marquee, keeps confetti + aria behavior */
.winner-banner {
  display: none;
  position: relative;
  width: 100%;
  min-height: 4.75rem;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  grid-auto-rows: minmax(0, 1fr);
  gap: clamp(0.35rem, 1.8vw, 0.75rem);
  padding: calc(clamp(0.45rem, 1.8vw, 0.75rem) + 0.42rem) clamp(0.45rem, 1.8vw, 0.75rem) clamp(0.45rem, 1.8vw, 0.75rem);
  border: 2px solid var(--gold-deep);
  border-radius: 8px;
  background: var(--sign-face);
  box-shadow: 0.18rem 0.18rem 0 var(--shadow-soft);
  overflow: visible;
  text-align: left;
}

html[data-theme="dark"] .winner-banner {
  border-color: var(--pink-neon);
  box-shadow:
    0 0 calc(12px * var(--glow-strength)) var(--coral-glow),
    0 0 calc(20px * var(--glow-strength)) var(--gold-glow);
}

.winner-banner::before {
  content: "Final Result";
  position: absolute;
  top: -0.58rem;
  left: 0.7rem;
  z-index: 2;
  padding: 0.12rem 0.38rem;
  border: 2px solid var(--gold-deep);
  border-radius: 5px;
  background: var(--gold);
  color: var(--ink);
  font: 800 0.72rem/1 system-ui, sans-serif;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

html[data-theme="dark"] .winner-banner::before {
  border-color: var(--pink-neon);
  background: var(--sign-face);
  color: var(--pink-neon);
  box-shadow: 0 0 calc(8px * var(--glow-strength)) var(--coral-glow);
}

.winner-banner-confetti {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}

.winner-banner-confetti-piece {
  position: absolute;
  top: -0.8rem;
  left: var(--confetti-left);
  width: var(--confetti-width, 0.38rem);
  height: var(--confetti-height, 0.62rem);
  border-radius: 2px;
  background: var(--confetti-color);
  opacity: 0.7;
  transform: translateY(-0.8rem) rotate(var(--confetti-rotate, 0deg));
  animation: winner-banner-confetti-fall var(--confetti-duration, 4.6s) linear infinite;
  animation-delay: var(--confetti-delay, 0s);
}

.winner-banner-confetti-piece:nth-child(3n) {
  border-radius: 50%;
}

.winner-banner-confetti-piece:nth-child(4n) {
  height: var(--confetti-width, 0.38rem);
}

.winner-banner-confetti-piece:nth-child(1) {
  --confetti-left: 4%;
  --confetti-color: var(--coral);
  --confetti-delay: -0.6s;
  --confetti-duration: 4.8s;
  --confetti-rotate: 12deg;
}

.winner-banner-confetti-piece:nth-child(2) {
  --confetti-left: 13%;
  --confetti-color: var(--teal);
  --confetti-delay: -2.1s;
  --confetti-duration: 5.4s;
  --confetti-width: 0.3rem;
  --confetti-rotate: -24deg;
}

.winner-banner-confetti-piece:nth-child(3) {
  --confetti-left: 22%;
  --confetti-color: var(--gold);
  --confetti-delay: -1.4s;
  --confetti-duration: 4.4s;
  --confetti-height: 0.42rem;
  --confetti-rotate: 36deg;
}

.winner-banner-confetti-piece:nth-child(4) {
  --confetti-left: 31%;
  --confetti-color: var(--pink-neon);
  --confetti-delay: -3s;
  --confetti-duration: 5.8s;
  --confetti-rotate: 8deg;
}

.winner-banner-confetti-piece:nth-child(5) {
  --confetti-left: 41%;
  --confetti-color: var(--teal-deep);
  --confetti-delay: -1.9s;
  --confetti-duration: 4.9s;
  --confetti-width: 0.32rem;
  --confetti-rotate: -40deg;
}

.winner-banner-confetti-piece:nth-child(6) {
  --confetti-left: 52%;
  --confetti-color: var(--gold);
  --confetti-delay: -0.2s;
  --confetti-duration: 5.5s;
  --confetti-rotate: 20deg;
}

.winner-banner-confetti-piece:nth-child(7) {
  --confetti-left: 63%;
  --confetti-color: var(--coral);
  --confetti-delay: -2.7s;
  --confetti-duration: 4.7s;
  --confetti-width: 0.28rem;
  --confetti-rotate: -16deg;
}

.winner-banner-confetti-piece:nth-child(8) {
  --confetti-left: 73%;
  --confetti-color: var(--cyan-neon);
  --confetti-delay: -1.1s;
  --confetti-duration: 5.9s;
  --confetti-rotate: 44deg;
}

.winner-banner-confetti-piece:nth-child(9) {
  --confetti-left: 84%;
  --confetti-color: var(--gold-deep);
  --confetti-delay: -3.5s;
  --confetti-duration: 5.2s;
  --confetti-height: 0.46rem;
  --confetti-rotate: -28deg;
}

.winner-banner-confetti-piece:nth-child(10) {
  --confetti-left: 94%;
  --confetti-color: var(--pink-neon);
  --confetti-delay: -1.7s;
  --confetti-duration: 4.6s;
  --confetti-rotate: 18deg;
}

@keyframes winner-banner-confetti-fall {
  0% {
    transform: translate3d(-0.18rem, -0.9rem, 0) rotate(var(--confetti-rotate, 0deg));
  }

  45% {
    transform: translate3d(0.22rem, 2.45rem, 0) rotate(calc(var(--confetti-rotate, 0deg) + 110deg));
  }

  100% {
    transform: translate3d(-0.08rem, 6.4rem, 0) rotate(calc(var(--confetti-rotate, 0deg) + 240deg));
  }
}

@media (prefers-reduced-motion: reduce) {
  .winner-banner-confetti-piece {
    animation: none;
    transform: translateY(1.25rem) rotate(var(--confetti-rotate, 0deg));
  }
}

.winner-banner-icon {
  grid-column: 1;
  grid-row: 1;
  place-self: center;
  z-index: 1;
  color: var(--gold);
  width: clamp(2rem, 8vw, 2.7rem);
  height: clamp(2rem, 8vw, 2.7rem);
  filter: drop-shadow(0 0 calc(10px * var(--glow-strength)) var(--gold-glow));
}

.winner-banner-spacer {
  grid-column: 1;
  grid-row: 1;
  width: 100%;
  aspect-ratio: 1;
  visibility: hidden;
  pointer-events: none;
}

.winner-banner-copy {
  grid-column: 2 / -1;
  grid-row: 1;
  align-self: center;
  z-index: 1;
  display: grid;
  gap: 0.2rem;
  min-width: 0;
}

.winner-banner-label {
  color: var(--gold); /* sits on the dark banner face in both themes; coral fails AA there */
  font: 900 0.78rem/1.1 system-ui, sans-serif;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

html[data-theme="dark"] .winner-banner-label {
  color: var(--pink-neon);
}

.winner-banner-names {
  min-width: 0;
  overflow-wrap: anywhere;
  color: var(--ink-on-dark);
  font: 900 clamp(1.1rem, 4.5vw, 1.55rem)/1.1 system-ui, sans-serif;
}

body.game-over .market-sign {
  display: none;
}

body.game-over .winner-banner {
  display: grid;
}

.rack::before {
  position: absolute;
  top: -0.58rem;
  left: 0.7rem;
  z-index: 2;
  content: "Your Tiles";
  color: var(--ink-muted);
  border: 2px solid var(--cell-border);
  border-radius: 5px;
  padding: 0.12rem 0.38rem;
  background: var(--surface-raised);
  font: 800 0.72rem/1 system-ui, sans-serif;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  pointer-events: none;
}

.tile {
  position: relative;
  display: grid;
  place-items: center;
  aspect-ratio: 1;
  border-radius: 22% 22% 9% 9%;
  background: var(--tile-face);
  color: var(--tile-ink);
  font: 800 clamp(1.35rem, 6vw, 2.25rem)/1 Georgia, "Times New Roman", serif;
  box-shadow:
    inset 0 2px 0 var(--tile-top-sheen),
    inset 0 -0.22em 0 var(--tile-bottom-shade),
    0 2px 3px var(--shadow-soft);
  user-select: none;
}

.tile-movable {
  cursor: pointer;
}

.tile-wildcard {
  background: var(--tile-face);
  color: var(--tile-ink);
  box-shadow:
    inset 0 0 0 0.18rem var(--tile-wildcard-ring),
    inset 0 2px 0 var(--tile-top-sheen),
    inset 0 -0.22em 0 var(--tile-bottom-shade),
    0 2px 3px var(--shadow-soft);
}

.tile-wildcard::before {
  content: "";
  position: absolute;
  /* em-based so it scales with the tile; extra bottom clearance keeps the
     dashes out of the 0.22em inset shade band and clear of the point digit */
  inset: 0.3em 0.3em 0.44em;
  border: 1px dashed var(--tile-wildcard-dash);
  border-radius: 5px;
  pointer-events: none;
}

/* The point digit sits where the wild ring's dashes run; a small tile-face
   plate under the digit masks the dash locally so neither fights the other. */
.tile-wildcard .tile-points {
  padding: 0 0.14em;
  border-radius: 4px;
  background: var(--tile-face);
}

.tile-wild-symbol {
  width: clamp(1.2rem, 5vw, 2rem);
  height: clamp(1.2rem, 5vw, 2rem);
  display: block;
  z-index: 1;
  color: var(--coral);
}

.tile-blank {
  background: var(--tile-face);
  color: var(--tile-ink);
  box-shadow:
    inset 0 0 0 2px var(--tile-bottom-shade),
    inset 0 2px 0 var(--tile-top-sheen),
    0 2px 3px var(--shadow-soft);
}

.tile-blank-symbol {
  position: relative;
  width: 42%;
  height: 28%;
  transform: translateY(12%);
}

.tile-blank-symbol::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 42%;
  border: solid currentColor;
  border-width: 0 0.16rem 0.16rem;
  box-shadow: 0 0.08rem 0 var(--tile-bottom-shade);
}

.tile-rainbow {
  background: linear-gradient(
    120deg,
    var(--rainbow-1),
    var(--rainbow-2),
    var(--rainbow-3),
    var(--rainbow-4),
    var(--rainbow-5),
    var(--rainbow-1)
  );
  background-clip: padding-box;
  background-origin: border-box;
  background-repeat: no-repeat;
  background-size: 400% 400%;
  animation: rainbow-tile-flow 7200ms ease-in-out infinite;
  animation-delay: var(--rainbow-animation-delay, 0ms);
  color: var(--on-accent-ink);
  text-shadow: 0 1px 2px var(--shadow-soft);
}

.tile-rainbow .tile-points {
  color: var(--on-accent-ink);
  text-shadow: 0 1px 2px var(--shadow-soft);
}

@media (prefers-reduced-motion: reduce) {
  .tile-rainbow {
    animation: none;
    background-position: 0% 50%;
  }
}

.marketplace-item {
  position: relative;
  z-index: 1;
  display: grid;
  align-content: start;
  min-width: 0;
}

.marketplace-cost-rail {
  position: absolute;
  left: clamp(0.45rem, 1.8vw, 0.75rem);
  right: clamp(0.45rem, 1.8vw, 0.75rem);
  bottom: 0.25rem;
  z-index: 3;
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: clamp(0.35rem, 1.8vw, 0.75rem);
  pointer-events: none;
}

/* hanging price tag: triangle top (stem), rectangular body, punched hole */
.marketplace-tile-cost {
  justify-self: center;
  align-self: end;
  position: relative;
  display: grid;
  /* Digit seats toward the tag bottom, clear of the absolutely-positioned
     hanger diamond (which paints above the element's own text). */
  place-items: end center;
  padding-bottom: 0.14rem;
  width: 1.3rem;
  height: 1.12rem;
  border: 1px solid var(--gold-deep);
  border-radius: 3px;
  background: var(--tile-face);
  color: var(--ink);
  font: 800 0.72rem/1 system-ui, sans-serif;
  opacity: 0; /* hidden until its slot holds a tile — tags hang off letters, not the board */
  box-shadow: 0 0 calc(6px * var(--glow-strength)) var(--gold-glow);
}

html[data-theme="dark"] .marketplace-tile-cost {
  /* Gold tag with dark ink: gold-on-maroon digits were illegible this small. */
  border-color: var(--gold-deep);
  background: var(--gold);
  color: var(--tile-ink);
}

/* Diamond hanger: a rotated square whose two exposed edges carry the border,
   its background masks the body's top border so the outline runs all the way
   around the tag; the punched hole rides its center. */
.marketplace-tile-cost::before {
  content: "";
  position: absolute;
  top: -0.32rem;
  left: 50%;
  width: 0.56rem;
  height: 0.56rem;
  transform: translateX(-50%) rotate(45deg);
  border: 1px solid transparent;
  border-top-color: var(--gold-deep);
  border-left-color: var(--gold-deep);
  border-radius: 2px 0 0 0;
  background:
    radial-gradient(circle 0.09rem at center, var(--sign-face) 0.09rem, transparent 0.13rem),
    var(--tile-face);
}

html[data-theme="dark"] .marketplace-tile-cost::before {
  border-top-color: var(--gold-deep);
  border-left-color: var(--gold-deep);
  background:
    radial-gradient(circle 0.09rem at center, var(--sign-face) 0.09rem, transparent 0.13rem),
    var(--gold);
}

/* Digit rides above the hanger diamond (positioned pseudos paint over the
   element's raw text, so the value needs its own positioned layer). */
.marketplace-tile-cost-value {
  position: relative;
  z-index: 1;
}

/* A few pixels of string tying the tag to its letter above. */
.marketplace-tile-cost::after {
  content: "";
  position: absolute;
  top: -0.78rem;
  left: 50%;
  transform: translateX(-50%);
  width: 2px;
  height: 0.5rem;
  border-radius: 999px;
  background: var(--gold-deep);
}

html[data-theme="dark"] .marketplace-tile-cost::after {
  background: var(--gold);
}

/* Show a tag only when its slot's letter has FINISHED arriving: game.js adds
   .tile-landed to a marketplace item when its enter animation completes (or
   immediately when the tile renders without animating). Cost rail is child 1,
   tile slots are children 2-8. Each tag drops in the moment its own letter
   lands, so timing tracks the real enter queue instead of guessed delays. */
@keyframes market-tag-drop {
  from {
    opacity: 0;
    translate: 0 -0.45rem;
  }

  to {
    opacity: 1;
    translate: 0 0;
  }
}

#marketplace:has(> .marketplace-item:nth-child(2).tile-landed:not(.marketplace-item-empty)) > .marketplace-cost-rail > .marketplace-tile-cost:nth-child(1),
#marketplace:has(> .marketplace-item:nth-child(3).tile-landed:not(.marketplace-item-empty)) > .marketplace-cost-rail > .marketplace-tile-cost:nth-child(2),
#marketplace:has(> .marketplace-item:nth-child(4).tile-landed:not(.marketplace-item-empty)) > .marketplace-cost-rail > .marketplace-tile-cost:nth-child(3),
#marketplace:has(> .marketplace-item:nth-child(5).tile-landed:not(.marketplace-item-empty)) > .marketplace-cost-rail > .marketplace-tile-cost:nth-child(4),
#marketplace:has(> .marketplace-item:nth-child(6).tile-landed:not(.marketplace-item-empty)) > .marketplace-cost-rail > .marketplace-tile-cost:nth-child(5),
#marketplace:has(> .marketplace-item:nth-child(7).tile-landed:not(.marketplace-item-empty)) > .marketplace-cost-rail > .marketplace-tile-cost:nth-child(6),
#marketplace:has(> .marketplace-item:nth-child(8).tile-landed:not(.marketplace-item-empty)) > .marketplace-cost-rail > .marketplace-tile-cost:nth-child(7) {
  opacity: 1;
  animation: market-tag-drop 240ms ease-out both;
}

/* Tiles that were already in place (every re-render marks them
   tile-landed-instant) show their tags immediately with NO drop animation —
   otherwise unrelated re-renders (e.g. dropping a rack tile on the board)
   blink every tag. Only genuinely arriving tiles replay the drop. */
/* The :not() term matches the drop-animation selectors' specificity —
   without it those rules win and the drop replays on every re-render
   (e.g. error messages), blinking all the tags. */
#marketplace:has(> .marketplace-item:nth-child(2).tile-landed-instant:not(.marketplace-item-empty)) > .marketplace-cost-rail > .marketplace-tile-cost:nth-child(1),
#marketplace:has(> .marketplace-item:nth-child(3).tile-landed-instant:not(.marketplace-item-empty)) > .marketplace-cost-rail > .marketplace-tile-cost:nth-child(2),
#marketplace:has(> .marketplace-item:nth-child(4).tile-landed-instant:not(.marketplace-item-empty)) > .marketplace-cost-rail > .marketplace-tile-cost:nth-child(3),
#marketplace:has(> .marketplace-item:nth-child(5).tile-landed-instant:not(.marketplace-item-empty)) > .marketplace-cost-rail > .marketplace-tile-cost:nth-child(4),
#marketplace:has(> .marketplace-item:nth-child(6).tile-landed-instant:not(.marketplace-item-empty)) > .marketplace-cost-rail > .marketplace-tile-cost:nth-child(5),
#marketplace:has(> .marketplace-item:nth-child(7).tile-landed-instant:not(.marketplace-item-empty)) > .marketplace-cost-rail > .marketplace-tile-cost:nth-child(6),
#marketplace:has(> .marketplace-item:nth-child(8).tile-landed-instant:not(.marketplace-item-empty)) > .marketplace-cost-rail > .marketplace-tile-cost:nth-child(7) {
  animation: none;
}

@media (prefers-reduced-motion: reduce) {
  .marketplace-tile-cost {
    animation: none !important;
  }
}

.marketplace-item.tile-movable {
  cursor: pointer;
}

/* Lift market tiles slightly so a visible run of price-tag string meets the
   tile's bottom edge (measured: string top otherwise hides behind the tile). */
.marketplace-item > .tile {
  position: relative;
  top: -0.25rem;
}

.marketplace-item-empty {
  position: relative;
  min-height: 100%;
  border-radius: 7px;
  box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--tile-face) 28%, transparent);
}

html[data-theme="dark"] .marketplace-item-empty {
  box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--ink-on-dark) 28%, transparent);
}

.marketplace-item-empty::after {
  content: "SOLD";
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font: 900 0.5rem/1 system-ui, sans-serif;
  letter-spacing: 0.1em;
  color: var(--gold);
  transform: rotate(-14deg);
}

html[data-theme="dark"] .marketplace-item-empty::after {
  color: var(--cyan-neon);
  text-shadow: 0 0 calc(6px * var(--glow-strength)) var(--teal-glow);
}

.marketplace-item-frame-placeholder {
  visibility: hidden;
  pointer-events: none;
}

.marketplace:has(> .tile.sortable-ghost) .marketplace-item-empty {
  border: 2px solid color-mix(in srgb, var(--ink) 20%, transparent);
  background: color-mix(in srgb, var(--surface-raised) 34%, transparent);
}

/* Hide the drag source's tile only while it sits IN the marketplace — the
   same element (or its clone) placed as a ghost in a board cell must stay
   visible so market drags get the same placement preview as rack drags.
   The cursor-following .sortable-fallback copy is also appended inside
   #marketplace and inherits the class (it clones after onChoose), so it is
   explicitly excluded — hiding it would hide the drag itself. */
.marketplace .marketplace-item-source-empty:not(.sortable-fallback) .tile {
  visibility: hidden;
}

.marketplace > .tile {
  width: 100%;
  max-width: 100%;
  align-self: stretch;
  justify-self: stretch;
}

.marketplace > .tile.sortable-ghost {
  display: none !important;
}

.marketplace > .tile.sortable-drag,
.marketplace > .tile.sortable-fallback {
  width: calc((var(--play-width) - 10px) / 9);
  max-width: calc((var(--play-width) - 10px) / 9);
  align-self: center;
  justify-self: center;
}

.board-cell .marketplace-item {
  width: 100%;
  height: 100%;
  display: grid;
  place-items: center;
  gap: 0;
}

.board-cell .marketplace-tile-cost,
.marketplace-item.sortable-drag .marketplace-tile-cost,
.marketplace-item.sortable-ghost .marketplace-tile-cost {
  display: none;
}

.board-cell .marketplace-item .tile {
  width: calc(100% - 6px);
  max-width: 100%;
  font-size: clamp(0.95rem, 3vw, 1.55rem);
}

.board-cell .marketplace-item .tile-points {
  right: 0.305rem;
  bottom: 0.505rem;
  font-size: clamp(0.42rem, 1.05vw, 0.56rem);
}

.marketplace-item.sortable-drag,
.marketplace-item.sortable-ghost {
  width: calc((var(--play-width) - 10px) / 9);
  height: calc((var(--play-width) - 10px) / 9);
  display: grid;
  place-items: center;
  gap: 0;
  align-content: center;
}

.marketplace-item.sortable-drag .tile,
.marketplace-item.sortable-ghost .tile {
  width: calc(100% - 6px);
  max-width: 100%;
  font-size: clamp(0.95rem, 3vw, 1.55rem);
}

.marketplace-item.sortable-drag .tile-points,
.marketplace-item.sortable-ghost .tile-points {
  right: 0.265rem;
  bottom: 0.245rem;
  font-size: clamp(0.42rem, 1.05vw, 0.56rem);
}

.tile.sortable-drag,
.tile.sortable-chosen,
.tile.sortable-fallback,
.marketplace-item.sortable-drag,
.marketplace-item.sortable-chosen,
.marketplace-item.sortable-fallback,
.marketplace-item.sortable-drag .tile,
.marketplace-item.sortable-chosen .tile,
.marketplace-item.sortable-fallback .tile {
  opacity: 1 !important;
  filter: none !important;
}

.tile.sortable-ghost,
.marketplace-item.sortable-ghost .tile {
  outline: 0;
  background: var(--drag-ghost-veil);
  color: transparent;
  text-shadow: none;
  box-shadow: none;
  opacity: 1;
}

.board-cell > .tile.sortable-ghost,
.board-cell > .marketplace-item.sortable-ghost {
  position: absolute !important;
  inset: 3px !important;
  z-index: 30 !important;
  width: auto;
  height: auto;
  min-width: 0;
  min-height: 0;
  margin: 0 !important;
  pointer-events: none;
  transform: none !important;
}

.board-cell > .tile.sortable-ghost {
  width: auto;
  max-width: 100%;
  font-size: clamp(0.95rem, 3vw, 1.55rem);
}

.board-cell > .tile.sortable-ghost.tile-active-placement,
.board-cell > .tile.sortable-ghost.tile-covering-placement {
  outline: 0;
  box-shadow: none;
}

.board-cell > .marketplace-item.sortable-ghost {
  display: grid;
  place-items: center;
}

.tile.sortable-ghost *,
.marketplace-item.sortable-ghost .tile * {
  visibility: hidden;
}

.marketplace-enter-1,
.marketplace-enter-2,
.marketplace-enter-3,
.marketplace-enter-4 {
  will-change: transform, opacity;
  animation-delay: var(--marketplace-delay, 0ms);
}

.marketplace-enter-1 {
  animation: marketplace-slide-in-low 620ms cubic-bezier(0.18, 0.84, 0.34, 1) both;
}

.marketplace-enter-2 {
  animation: marketplace-slide-in-high 660ms cubic-bezier(0.2, 0.82, 0.32, 1) both;
}

.marketplace-enter-3 {
  animation: marketplace-slide-in-tilt-left 640ms cubic-bezier(0.18, 0.84, 0.34, 1) both;
}

.marketplace-enter-4 {
  animation: marketplace-slide-in-tilt-right 680ms cubic-bezier(0.2, 0.82, 0.32, 1) both;
}

.tile:active {
  cursor: pointer;
}

.tile-active-placement {
  box-shadow:
    0 0 0 2px var(--placement-accent-soft),
    0 0 9px var(--placement-accent-soft),
    inset 0 2px 0 var(--tile-top-sheen);
}

.tile-placement-error {
  animation: tile-flash 420ms ease-in-out 2;
}

.tile-remote-play {
  animation: remote-play-flash 1400ms ease-out 1;
}

@media (prefers-reduced-motion: reduce) {
  .tile-placement-error,
  .tile-remote-play {
    animation: none;
  }
}

.tile-shuffle-1,
.tile-shuffle-2,
.tile-shuffle-3,
.tile-shuffle-4,
.tile-enter-1,
.tile-enter-2,
.tile-enter-3,
.tile-enter-4 {
  position: relative;
  z-index: 5;
  will-change: transform;
  animation-delay: var(--shuffle-delay, 0ms);
}

.tile-enter-pending {
  opacity: 0;
  transform: translate(var(--shuffle-x, 115%), var(--shuffle-y, 0)) rotate(var(--tile-enter-rotation, 0deg));
}

.tile-shuffle-1,
.tile-enter-1 {
  animation: tile-shuffle-swing-left 520ms cubic-bezier(0.22, 0.8, 0.28, 1) both;
}

.tile-shuffle-2,
.tile-enter-2 {
  animation: tile-shuffle-swing-right 560ms cubic-bezier(0.2, 0.78, 0.32, 1) both;
}

.tile-shuffle-3,
.tile-enter-3 {
  animation: tile-shuffle-hop 540ms cubic-bezier(0.2, 0.82, 0.34, 1) both;
}

.tile-shuffle-4,
.tile-enter-4 {
  animation: tile-shuffle-slide 500ms cubic-bezier(0.18, 0.86, 0.34, 1) both;
}

.board .tile-covered-underlay,
.rules-example .tile-covered-underlay,
.rules-board-example .tile-covered-underlay {
  position: absolute;
  top: calc(3px + 0.18rem);
  left: calc(3px - 0.18rem);
  width: calc(100% - 6px);
  z-index: 1;
  opacity: 0.58;
  filter: saturate(0.7);
}

.board .tile-covering-placement,
.rules-example .tile-covering-placement,
.rules-board-example .tile-covering-placement {
  position: absolute;
  top: calc(3px - 0.18rem);
  left: calc(3px + 0.18rem);
  width: calc(100% - 6px);
  z-index: 2;
  box-shadow:
    inset 0 -0.22em 0 var(--tile-bottom-shade),
    -0.2rem 0.2rem 0 var(--shadow-soft);
}

.tile-stack-badge {
  position: absolute;
  top: 0.12rem;
  left: 0.12rem;
  min-width: 1.05rem;
  padding: 0.08rem 0.12rem;
  border-radius: 4px;
  background: var(--teal);
  color: var(--on-accent-ink);
  font: 800 clamp(0.44rem, 1.15vw, 0.58rem)/1 system-ui, sans-serif;
  text-align: center;
}

/* Stacked board cells fan open on hover (desktop) or tap (mobile), revealing
   every covered tile plus any buried bonus. Suppressed while carrying a tile.
   `--stack-fan-x` flips the horizontal component so right-edge columns fan
   up-and-left instead of up-and-right and never run off the board. */
.board .board-cell-stacked {
  --stack-fan-x: 1;
  /* Reveal fan expressed in fractions of a tile so it scales with board size.
     Every tile is splayed by the same step, so gaps are uniform: the bottom
     tile sits one step off its square, each tile one step past the one below,
     and the most-recently-played (top) tile ends up furthest away. The step is
     just large enough to read each covered letter while keeping overlap.
     lift = (level + 1) * step, with level 0 at the bottom. */
  --stack-step: 0.58;
}

.board .board-cell-stacked.stack-fan-left {
  --stack-fan-x: -1;
}

.board .board-cell-stacked .tile {
  transition: transform 180ms ease, opacity 180ms ease, filter 180ms ease, box-shadow 180ms ease;
}

/* Give every tile in a stack the same base position so the splay is uniform.
   The top tile is a .tile-covering-placement, which is otherwise nudged
   up-and-right of the covered tiles -- that extra offset is what made the top
   letter sit too far out. */
.board .board-cell-stacked .tile-covered-underlay,
.board .board-cell-stacked .tile-covering-placement {
  top: 3px;
  left: 3px;
}

/* Revealed: lift the cell out of its clip so the peeled tiles rise above it. */
.board .board-cell-stacked.stack-open,
html:not(.tile-dragging) .board .board-cell-stacked:hover {
  overflow: visible;
  z-index: 20;
}

.board .board-cell-stacked.stack-open .tile,
html:not(.tile-dragging) .board .board-cell-stacked:hover .tile {
  --stack-lift: calc((var(--stack-level, 0) + 1) * var(--stack-step) * 100%);
  transform: translate(
    calc(var(--stack-lift) * var(--stack-fan-x)),
    calc(var(--stack-lift) * -1)
  );
  /* A soft, blurred float shadow -- replaces the covering tile's hard offset
     block shadow, which read as an odd smear once the tiles are lifted apart. */
  box-shadow:
    inset 0 2px 0 var(--tile-top-sheen),
    inset 0 -0.22em 0 var(--tile-bottom-shade),
    0 0.22rem 0.5rem var(--shadow-soft);
}

.board .board-cell-stacked.stack-open .tile-covered-underlay,
html:not(.tile-dragging) .board .board-cell-stacked:hover .tile-covered-underlay {
  opacity: 1;
  filter: none;
}

/* The stack multiplier badge just clutters the splayed letters -- hide it while
   the stack is open (it still marks the collapsed stack). */
.board .board-cell-stacked .tile-stack-badge {
  transition: opacity 180ms ease;
}

.board .board-cell-stacked.stack-open .tile-stack-badge,
html:not(.tile-dragging) .board .board-cell-stacked:hover .tile-stack-badge {
  opacity: 0;
}

/* Buried bonus: sits on the square under the stack (below every tile), exposed
   as the tiles lift away. Colored by the underlying bonus via board-cell-bonus-*. */
.board .board-cell-stacked .board-buried-bonus {
  position: absolute;
  inset: 3px;
  z-index: 0;
  display: grid;
  place-items: center;
  border-radius: 4px;
  font: 800 clamp(0.5rem, 1.4vw, 0.72rem)/1 system-ui, sans-serif;
  opacity: 0;
  transition: opacity 180ms ease;
  pointer-events: none;
}

.board .board-cell-stacked.stack-open .board-buried-bonus,
html:not(.tile-dragging) .board .board-cell-stacked:hover .board-buried-bonus {
  opacity: 1;
}

@keyframes tile-flash {
  0%,
  100% {
    box-shadow:
      inset 0 2px 0 var(--tile-top-sheen),
      inset 0 -0.22em 0 var(--tile-bottom-shade),
      0 2px 3px var(--shadow-soft);
  }

  50% {
    box-shadow:
      0 0 0 3px var(--coral),
      0 0 10px var(--orange-glow),
      inset 0 2px 0 var(--tile-top-sheen);
  }
}

@keyframes remote-play-flash {
  0% {
    transform: scale(0.82);
    box-shadow:
      inset 0 2px 0 var(--tile-top-sheen),
      inset 0 -0.22em 0 var(--tile-bottom-shade),
      0 0 0 0.35rem var(--teal);
  }

  45% {
    transform: scale(1.06);
    box-shadow:
      inset 0 2px 0 var(--tile-top-sheen),
      inset 0 -0.22em 0 var(--tile-bottom-shade),
      0 0 0 0.2rem var(--teal-deep);
  }

  100% {
    transform: scale(1);
    box-shadow:
      inset 0 2px 0 var(--tile-top-sheen),
      inset 0 -0.22em 0 var(--tile-bottom-shade),
      0 2px 3px var(--shadow-soft);
  }
}

@keyframes tile-shuffle-swing-left {
  0% {
    transform: translate(var(--shuffle-x), var(--shuffle-y)) rotate(-10deg);
  }

  52% {
    transform: translate(calc(var(--shuffle-x) * -0.16), calc(var(--shuffle-y) * -0.08)) rotate(7deg);
  }

  100% {
    transform: translate(0, 0) rotate(0deg);
  }
}

@keyframes tile-shuffle-swing-right {
  0% {
    transform: translate(var(--shuffle-x), var(--shuffle-y)) rotate(11deg);
  }

  48% {
    transform: translate(calc(var(--shuffle-x) * -0.14), calc(var(--shuffle-y) * 0.1)) rotate(-8deg);
  }

  100% {
    transform: translate(0, 0) rotate(0deg);
  }
}

@keyframes tile-shuffle-hop {
  0% {
    transform: translate(var(--shuffle-x), var(--shuffle-y)) rotate(-6deg);
  }

  45% {
    transform: translate(calc(var(--shuffle-x) * 0.35), calc(var(--shuffle-y) - 0.55rem)) rotate(8deg);
  }

  100% {
    transform: translate(0, 0) rotate(0deg);
  }
}

@keyframes tile-shuffle-slide {
  0% {
    transform: translate(var(--shuffle-x), var(--shuffle-y)) rotate(5deg);
  }

  58% {
    transform: translate(calc(var(--shuffle-x) * -0.1), calc(var(--shuffle-y) * -0.12)) rotate(-5deg);
  }

  100% {
    transform: translate(0, 0) rotate(0deg);
  }
}


@keyframes marketplace-slide-in-low {
  0% {
    opacity: 0;
    transform: translate(var(--marketplace-enter-x), 0.45rem) rotate(-7deg);
  }

  100% {
    opacity: 1;
    transform: translate(0, 0) rotate(0deg);
  }
}

@keyframes marketplace-slide-in-high {
  0% {
    opacity: 0;
    transform: translate(var(--marketplace-enter-x), -0.4rem) rotate(8deg);
  }

  100% {
    opacity: 1;
    transform: translate(0, 0) rotate(0deg);
  }
}

@keyframes marketplace-slide-in-tilt-left {
  0% {
    opacity: 0;
    transform: translate(var(--marketplace-enter-x), 0) rotate(-13deg);
  }

  58% {
    transform: translate(-0.15rem, 0) rotate(4deg);
  }

  100% {
    opacity: 1;
    transform: translate(0, 0) rotate(0deg);
  }
}

@keyframes marketplace-slide-in-tilt-right {
  0% {
    opacity: 0;
    transform: translate(var(--marketplace-enter-x), 0) rotate(13deg);
  }

  58% {
    transform: translate(0.15rem, 0) rotate(-4deg);
  }

  100% {
    opacity: 1;
    transform: translate(0, 0) rotate(0deg);
  }
}

@keyframes rainbow-tile-flow {
  0% {
    background-position: 0% 50%;
  }

  50% {
    background-position: 100% 50%;
  }

  100% {
    background-position: 0% 50%;
  }
}

.tile-points {
  position: absolute;
  right: 0.475rem;
  bottom: 0.575rem; /* clear of the tile's bottom inset shade band */
  color: var(--tile-points);
  font: 700 clamp(0.58rem, 2.2vw, 0.78rem)/1 system-ui, sans-serif;
}

.board .tile,
.rules-example .tile,
.rules-board-example .tile {
  width: calc(100% - 6px);
  max-width: 100%;
  font-size: clamp(0.95rem, 3vw, 1.55rem);
  cursor: default;
}

.board .tile-blank,
.rules-example .tile-blank,
.rules-board-example .tile-blank {
  background: var(--tile-face);
  box-shadow:
    inset 0 0 0 2px var(--tile-bottom-shade),
    inset 0 2px 0 var(--tile-top-sheen),
    0 2px 3px var(--shadow-soft);
}

.board .tile-movable {
  cursor: pointer;
}

.board .tile-points,
.rules-example .tile-points,
.rules-board-example .tile-points {
  right: 0.265rem;
  bottom: 0.365rem; /* clear of the smaller tiles' inset shade */
  font-size: clamp(0.42rem, 1.05vw, 0.56rem);
}

html.has-stored-player body main,
body.has-player main {
  align-content: start;
  gap: 0.75rem;
  padding-top: clamp(0.85rem, 2vw, 1.35rem);
}

html.has-stored-player body .masthead,
body.has-player .masthead {
  width: var(--play-width);
  row-gap: 0;
  column-gap: 1rem;
}

html.has-stored-player body .brand,
body.has-player .brand {
  --brand-scale: 1.9rem;
  margin-bottom: 0;
}

body.screen-setup.has-player main {
  align-content: start;
  padding-top: clamp(0.85rem, 2vw, 1.35rem);
}

body.screen-setup.has-player .game-controls {
  display: contents;
}

body.screen-setup.has-player .identity-bar {
  justify-self: end;
}

body.screen-setup.has-player .player-setup {
  grid-column: 1 / -1;
  justify-self: center;
  justify-items: center;
  margin-top: clamp(1.5rem, 3vw, 2.25rem);
}

.redraw-tiles-button,
.pass-turn-button,
.concede-game-button {
  display: none;
}

body.screen-play .redraw-tiles-button,
body.screen-play .pass-turn-button,
body.screen-play .concede-game-button {
  display: inline-block;
}

.concede-game-button[hidden] {
  display: none;
}

body.game-over .rack,
body.game-over .rack-shuffle-button,
body.game-over .rack-controls,
body.game-over .redraw-confirm,
body.game-over .pass-confirm,
body.game-over .concede-confirm {
  display: none;
}

body.game-over .redraw-tiles-button,
body.game-over .pass-turn-button,
body.game-over .concede-game-button {
  display: none;
}

.rack-shuffle-button {
  display: none;
  position: absolute;
  /* Vertically centered on the RACK's top border (mirroring the "Your Tiles"
     label), not the dock's. Anchor positioning tracks the rack even when the
     Last Turn notice pushes it down; the plain values are the fallback
     (rack top = wrap's 0.6rem padding, rack right edge = wrap's padding). */
  top: -0.3rem;
  top: calc(anchor(--rack top) - 0.9rem);
  right: calc(clamp(0.5rem, 3vw, 0.85rem) + 0.7rem);
  right: calc(anchor(--rack right) + 0.7rem);
  z-index: 4;
  width: 1.8rem;
  min-width: 1.8rem;
  height: 1.8rem;
  min-height: 1.8rem;
  padding: 0.08rem;
  place-items: center;
  border-width: 2px;
  border-radius: 50%;
  background: var(--teal);
  color: var(--on-accent-ink);
  box-shadow: 0.12rem 0.12rem 0 var(--teal-deep);
}

/* Visual disc stays small (28.8px) to match the rack chrome, but the tappable
   hit-area is expanded to the >=40px touch-target minimum via an invisible
   centered ::before box. */
.rack-shuffle-button::before {
  content: "";
  position: absolute;
  inset: 50% auto auto 50%;
  width: 2.5rem;
  height: 2.5rem;
  transform: translate(-50%, -50%);
}

.rack-shuffle-button:focus-visible {
  outline: 2px solid var(--coral);
  outline-offset: 2px;
}

html[data-theme="dark"] .rack-shuffle-button:focus-visible {
  outline-color: var(--gold);
}

html[data-theme="dark"] .rack-shuffle-button {
  background: var(--sign-face);
  color: var(--cyan-neon);
  border-color: var(--cyan-neon);
  box-shadow: 0 0 calc(8px * var(--glow-strength)) var(--teal-glow);
}

body.last-turn .rack-shuffle-button {
  top: calc(2.2rem + 0.75rem - 0.88rem);
}

body.screen-play .rack-shuffle-button {
  display: grid;
}

body.screen-play.game-over .rack-shuffle-button {
  display: none;
}

.rack-shuffle-button .ww-icon {
  width: 1.08rem;
  height: 1.08rem;
}

.rack-controls {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  gap: 0.5rem;
}

.rack-controls .game-button {
  min-height: 2.5rem;
  padding: 0.55rem 0.95rem;
  font-size: 0.85rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

#finish-placement-button {
  margin-left: auto;
}

/* Confirm dialogs: tilted-sign cards */
.redraw-confirm,
.pass-confirm,
.concede-confirm {
  display: none;
  width: 100%;
  max-width: 24rem;
  justify-self: center;
  justify-items: center;
  gap: 0.55rem;
  padding: 0.75rem;
  border: 2px solid var(--gold-deep);
  border-radius: 8px;
  background: var(--surface-raised);
  color: var(--ink);
  font: 800 0.9rem/1.25 system-ui, sans-serif;
  text-align: center;
  transform: rotate(-1deg);
  box-shadow: 0.18rem 0.22rem 0 var(--shadow-soft);
}

html[data-theme="dark"] .redraw-confirm,
html[data-theme="dark"] .pass-confirm,
html[data-theme="dark"] .concede-confirm {
  background: var(--sign-face);
  border-color: var(--gold);
  color: var(--ink-on-dark);
  box-shadow: 0 0 calc(10px * var(--glow-strength)) var(--gold-glow);
}

body.confirm-redraw .redraw-confirm {
  display: grid;
}

body.confirm-pass .pass-confirm {
  display: grid;
}

body.confirm-concede .concede-confirm {
  display: grid;
}

.redraw-confirm-actions,
.pass-confirm-actions,
.concede-confirm-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.55rem;
}

.concede-game-control {
  display: grid;
  width: 100%;
  justify-items: start;
  gap: 0.55rem;
}

.concede-game-control[hidden] {
  display: none;
}

body.game-over .concede-game-control {
  display: none;
}

body.confirm-redraw #redraw-tiles-button,
body.confirm-pass #redraw-tiles-button,
body.confirm-pass #pass-turn-button,
body.confirm-redraw #pass-turn-button,
body.confirm-concede #redraw-tiles-button,
body.confirm-concede #pass-turn-button,
body.confirm-redraw #concede-game-button,
body.confirm-pass #concede-game-button,
body.confirm-concede #concede-game-button {
  display: none;
}

body.has-active-placement #redraw-tiles-button,
body.has-active-placement #pass-turn-button,
body.has-active-placement .pass-confirm {
  display: none;
}

.placement-action {
  display: none;
}

body.has-active-placement .placement-action {
  display: inline-block;
}

.game-message {
  position: relative;
  /* The callout IS the entire board-to-rack gap: negative block margins
     swallow the 1rem grid gaps (plus the rack's 0.25rem top margin) so the
     visible arrow touches the board above and the rack below with zero air,
     and the reservation is identical when empty (opacity handles hiding) —
     no jumping either way. */
  min-height: 2.6rem;
  width: var(--play-width);
  justify-self: center;
  display: flex;
  align-items: center;
  justify-content: center;
  /* -1rem swallows the grid gap above (board) exactly; the bottom swallows
     the gap + the rack's 0.25rem margin, backed off 1px so the band's own
     bottom border stays visible above the dock edge. Calibrate in LAYOUT
     coordinates (offsetTop), not bounding boxes — transforms inflate rects. */
  margin: -1rem auto calc(-1.25rem + 1px);
  /* plain full-width box (no arrow point): under the sticky dock the band's
     bottom can be covered by the rack edge, which reads fine for a box but
     amputated an arrow tip */
  padding: 0.4rem 0.85rem;
  background: var(--gold);
  color: var(--ink);
  font: 800 0.85rem/1.3 system-ui, sans-serif;
  text-align: center;
  opacity: 0;
  transform: translateY(-0.45rem);
  transition:
    opacity 180ms ease,
    transform 180ms ease;
  pointer-events: none;
}

html[data-theme="dark"] .game-message {
  background: var(--sign-face);
  color: var(--gold);
  box-shadow: 0 0 calc(10px * var(--glow-strength)) var(--gold-glow);
  border: 1px solid var(--gold);
}

.game-message.has-message {
  opacity: 1;
  transform: translateY(0);
}

.game-message.message-exiting {
  opacity: 0;
  transform: translateY(-0.45rem);
}

.game-message.is-error {
  background: var(--coral);
  color: var(--ink-on-dark);
}

html[data-theme="dark"] .game-message.is-error {
  background: var(--sign-face);
  color: var(--coral);
  border-color: var(--coral);
  box-shadow: 0 0 calc(10px * var(--glow-strength)) var(--coral-glow);
}

body.screen-play:not(.is-my-turn) .game-message {
  background: var(--surface-raised);
  color: var(--ink-muted);
}

body.screen-play:not(.is-my-turn) .board {
  opacity: 0.82;
}

body.screen-play.spectator-mode .board {
  opacity: 1;
}

body.screen-play.spectator-mode .market-sign,
body.screen-play.spectator-mode .invite-link-panel,
body.screen-play.spectator-mode .last-turn-notice,
body.screen-play.spectator-mode .rack,
body.screen-play.spectator-mode .rack-shuffle-button,
body.screen-play.spectator-mode .rack-controls,
body.screen-play.spectator-mode .redraw-confirm,
body.screen-play.spectator-mode .pass-confirm,
body.screen-play.spectator-mode .concede-game-control,
body.screen-play.spectator-mode .potential-points-summary,
body.screen-play.spectator-mode #view-pool-button {
  display: none;
}

/* Spectators never see View Pool, so the log needs no separator above it. */
body.screen-play.spectator-mode .game-log {
  border-top: none;
  margin-top: 0;
  padding-top: 0;
}

body.screen-play:not(.is-my-turn) .tile-movable {
  cursor: not-allowed;
}

body.screen-play:not(.is-my-turn) #rack .tile-movable {
  cursor: pointer;
}

.game-button:disabled {
  cursor: not-allowed;
  opacity: 0.58;
  box-shadow: none;
}

/* Score strip: horizontal pill chips, "NOW PLAYING" tag on the active player */
.score-strip {
  width: var(--play-width);
  justify-self: center;
}

/* Always visible: sits in flow below the dock on narrow screens, becomes the
   fixed side panel at >=1280px. */
.game-sheet {
  width: 100%;
  max-width: var(--play-width); /* match the rack/board column */
  justify-self: center;
  margin-inline: auto;
  display: grid;
  gap: 0.75rem;
  padding-top: 0.6rem;
}

/* In-flow (below-dock) sheet wears the same counter treatment as the dock,
   full page width. The >=1280px fixed side panel keeps its own card chrome. */
@media (max-width: 1279.98px) {
  body.screen-play .game-sheet {
    padding: 0.6rem clamp(0.5rem, 3vw, 0.85rem) 0.9rem;
    border-top: 3px solid var(--teal);
    background: var(--surface);
    box-shadow: 0 -4px 12px var(--shadow-soft);
  }

  html[data-theme="dark"] body.screen-play .game-sheet {
    border-top-color: var(--cyan-neon);
    box-shadow: 0 0 calc(14px * var(--glow-strength)) var(--teal-glow);
  }
}

.game-state-panel {
  width: 100%;
  display: grid;
  gap: 0.75rem;
  padding: 0.85rem;
  border: 2px solid var(--cell-border);
  border-radius: 8px;
  background: var(--surface-raised);
  font: 700 0.95rem/1.2 system-ui, sans-serif;
  text-align: left;
}

/* Standalone stats bar: continues the sticky dock's cream counter flush below
   it (the -1rem cancels the .game-area grid gap), so only the rack + buttons
   pin and this row scrolls into view below the fold. */
.game-state-summary {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 0.35rem 0.9rem;
  width: 100%;
  max-width: var(--play-width);
  justify-self: center;
  margin-top: -1rem;
  padding: 0.55rem clamp(0.5rem, 3vw, 0.85rem) calc(0.7rem + env(safe-area-inset-bottom, 0px));
  background: var(--surface);
  font-size: 0.7rem;
}

.potential-points-kicker span {
  display: inline;
}

.game-state-kicker {
  color: var(--ink-muted);
  font: 800 0.66rem/1.2 system-ui, sans-serif;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.game-state-value {
  display: block;
  margin-top: 0.1rem;
  color: var(--ink);
  font-size: 0.85rem;
}

#current-game-mode {
  margin-top: 2px;
}

.game-state-value.negative {
  color: var(--coral);
}

.view-pool-button {
  justify-self: start;
  width: 6.25rem;
  min-height: 2.55rem;
  padding-inline: 0.85rem;
  font-size: 0.85rem;
  white-space: nowrap;
}

@media (max-width: 34rem) {
  .game-state-summary {
    gap: 0.3rem 0.6rem;
  }

  .potential-points-kicker span {
    display: block;
  }
}

.player-score-list {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.4rem;
}

.player-score-row {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.32rem 0.7rem 0.32rem 0.4rem;
  border-radius: 999px;
  background: var(--surface-raised);
  box-shadow: 0 2px 4px var(--shadow-soft);
  font: 700 0.8rem/1.1 system-ui, sans-serif;
}

.player-score-row.current-turn {
  background: var(--sign-face);
  color: var(--gold);
  box-shadow:
    0 0 0 2px var(--gold),
    0 0 calc(10px * var(--glow-strength)) var(--gold-glow);
}

.player-score-row.conceded-player {
  background: var(--surface);
  color: var(--ink-muted);
  box-shadow: none;
  opacity: 0.75;
}

.player-score-name {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  overflow-wrap: anywhere;
}

.conceded-badge {
  display: inline-grid;
  place-items: center;
  padding: 0.14rem 0.42rem;
  border-radius: 999px;
  background: color-mix(in srgb, var(--ink) 12%, transparent);
  color: var(--ink-muted);
  font: 800 0.62rem/1 system-ui, sans-serif;
  text-transform: uppercase;
  vertical-align: middle;
}

.turn-badge {
  display: inline-grid;
  place-items: center;
  padding: 0.1rem 0.3rem;
  border-radius: 4px;
  /* day = dark MARKET board (calm inside the chip); night = electric red + glow */
  background: var(--hot-accent);
  color: var(--on-accent-ink);
  box-shadow: 0 0 calc(8px * var(--glow-strength)) var(--red-glow);
  font: 800 0.55rem/1.2 system-ui, sans-serif;
  letter-spacing: 0.04em;
  vertical-align: middle;
}

.player-score-points {
  font: 800 0.85rem/1 system-ui, sans-serif;
}

.game-log-title {
  margin: 0;
  color: var(--ink-muted);
  font: 800 0.72rem/1.2 system-ui, sans-serif;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.game-log-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
}

.word-score-list {
  position: relative;
  display: flex;
  min-width: 0;
  flex-wrap: wrap;
  gap: 0.45rem;
}

.word-score-item {
  position: static;
  display: inline-grid;
  max-width: 100%;
}

.word-score-disclosure {
  display: inline-flex;
  align-items: baseline;
  max-width: 100%;
  padding: 0.18rem 0.42rem;
  border: 1px solid var(--teal);
  border-radius: 8px;
  background: color-mix(in srgb, var(--teal) 9%, transparent);
  color: var(--ink);
  font: inherit;
  text-align: left;
  cursor: pointer;
  appearance: none;
}

.word-score-disclosure:hover {
  background: color-mix(in srgb, var(--teal) 16%, transparent);
}

.word-score-disclosure:focus-visible {
  outline: 2px solid var(--coral);
  outline-offset: 2px;
}

.word-score-equation {
  display: inline-flex;
  align-items: baseline;
  gap: 0.25rem;
  min-width: 0;
}

.word-score-word {
  min-width: 0;
  overflow-wrap: anywhere;
  font-weight: 800;
}

.word-score-points {
  color: var(--teal-deep);
  font: 900 0.82rem/1 system-ui, sans-serif;
  white-space: nowrap;
}

.word-score-equals {
  color: var(--ink-muted);
  font-weight: 700;
}

.word-score-multiplier {
  display: inline-flex;
  align-items: center;
  padding: 0.08rem 0.28rem;
  border: 1px solid currentColor;
  border-radius: 6px;
  font: 900 0.68rem/1 system-ui, sans-serif;
  white-space: nowrap;
}

.word-score-multiplier-double-word {
  border-color: var(--gold-deep);
  background: var(--gold);
  color: var(--tile-ink);
}

.word-score-multiplier-triple-word {
  border-color: var(--coral);
  background: var(--coral-deep);
  color: var(--ink-on-dark);
}

.word-score-breakdown {
  position: absolute;
  z-index: 12;
  top: calc(100% + 0.35rem);
  left: 0;
  display: grid;
  width: fit-content;
  min-width: min(13rem, 100%);
  max-width: 100%;
  gap: 0.35rem;
  padding: 0.6rem 0.7rem;
  border: 1px solid var(--cell-border);
  border-radius: 8px;
  background: var(--surface-raised);
  color: var(--ink);
  box-shadow: 0 0.45rem 1rem var(--shadow-soft);
  font: 600 0.76rem/1.35 system-ui, sans-serif;
}

.word-score-breakdown[hidden] {
  display: none !important;
}

.word-score-item.score-breakdown-open .word-score-disclosure {
  position: relative;
  z-index: 13;
}

.word-score-breakdown-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 0.75rem;
  align-items: baseline;
}

.word-score-breakdown-label {
  min-width: 0;
  overflow-wrap: anywhere;
}

.word-score-breakdown-result {
  color: var(--teal-deep);
  font-weight: 900;
  white-space: nowrap;
}

.word-score-breakdown-unavailable {
  margin: 0;
  color: var(--ink-muted);
  font-weight: 600;
}

html[data-theme="dark"] .word-score-breakdown {
  border-color: color-mix(in srgb, var(--teal) 55%, var(--cell-border));
  box-shadow: 0 0.45rem 1.2rem rgba(0, 0, 0, 0.55);
}

@media (max-width: 520px) {
  .word-score-list,
  .word-score-item,
  .word-score-disclosure {
    width: 100%;
  }

  .word-score-item {
    grid-template-columns: minmax(0, 1fr);
  }

  .word-score-equation {
    flex-wrap: wrap;
  }

  .word-score-breakdown {
    position: static;
    width: max-content;
    min-width: min(13rem, 100%);
    max-width: 100%;
    margin-top: 0.35rem;
  }
}

.word-score-empty,
.game-log-empty {
  color: var(--ink-muted);
  font-size: 0.85rem;
}

.game-log {
  display: grid;
  gap: 0.55rem;
  margin-top: 0.75rem;
  padding-top: 0.75rem;
  border-top: 2px solid var(--cell-border);
}

.game-log-result {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem 0.5rem;
  align-items: baseline;
  color: var(--ink);
  font: 800 0.86rem/1.25 system-ui, sans-serif;
}

.game-log-result-label {
  color: var(--coral);
  font: 900 0.78rem/1.1 system-ui, sans-serif;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.game-log-result strong {
  min-width: 0;
  overflow-wrap: anywhere;
  color: var(--ink);
  font: inherit;
}

.game-log-list {
  display: grid;
  gap: 0.45rem;
}

.game-log-entry {
  position: relative;
  display: grid;
  gap: 0.4rem;
  padding: 0.55rem 0.65rem;
  border: 1px solid var(--cell-border);
  border-radius: 8px;
  background: var(--surface-raised);
}

/* A log entry showing an open score breakdown or a hover tooltip must paint
   above its sibling entries — without this, the popover slides under the
   next turn's card. */
.game-log-entry:has(.score-breakdown-open),
.game-log-entry:has([data-ww-tooltip]:hover),
.game-log-entry:has([data-ww-tooltip]:focus-visible) {
  z-index: 14;
}

.game-log-entry:has(.game-log-reactions.is-expanded) {
  z-index: 15;
}

.game-log-heading {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: start;
  gap: 0.35rem 0.55rem;
}

.game-log-turn {
  color: var(--ink-muted);
  font: 800 0.72rem/1.2 system-ui, sans-serif;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.game-log-player {
  overflow-wrap: anywhere;
}

/* Per-turn tally, pushed to the right edge of the heading row: points spent
   buying tiles (red, if any) then the words total (teal). */
.game-log-turn-tally {
  justify-self: end;
  align-self: start;
  margin-left: 0;
  display: inline-flex;
  align-items: baseline;
  gap: 0.4rem;
}

.game-log-turn-spent {
  color: var(--hot-accent);
  font: 800 0.8rem/1.2 system-ui, sans-serif;
}

.game-log-turn-total {
  color: var(--teal-deep);
  font: 800 0.8rem/1.2 system-ui, sans-serif;
}

html[data-theme="dark"] .game-log-turn-total {
  color: var(--cyan-neon);
}

/* Net loss on the turn (spent more than scored) reads like the spend. */
.game-log-turn-total.negative {
  color: var(--hot-accent);
}

/* Non-scoring turn label (e.g. Redraw Tiles) shown in the heading's top-right
   slot, where a scoring turn's +total sits. */
.game-log-action-tag {
  justify-self: end;
  align-self: start;
  color: var(--ink-muted);
  font: 800 0.72rem/1.2 system-ui, sans-serif;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  white-space: nowrap;
}

/* Tiles a player handed back on a redraw turn. Only the returned rack is
   shown; the replacement draw stays hidden. */
.game-log-returned-tiles {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.3rem;
}

.game-log-returned-label {
  color: var(--ink-muted);
  font: 800 0.72rem/1.2 system-ui, sans-serif;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin-right: 0.15rem;
}

.game-log-returned-tile {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.3rem;
  height: 1.3rem;
  padding: 0 0.2rem;
  border-radius: 5px;
  background: var(--tile-face);
  color: var(--tile-ink);
  box-shadow:
    inset 0 0 0 1px var(--tile-bottom-shade),
    0 1px 2px var(--shadow-soft);
  font: 800 0.78rem/1 system-ui, sans-serif;
}

.pool-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(4.4rem, 1fr));
  gap: 0.4rem;
}

.pool-summary {
  margin: 0 0 0.65rem;
  color: var(--ink-muted);
  font: 700 0.82rem/1.4 system-ui, sans-serif;
}

.pool-letter {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: baseline;
  gap: 0.35rem;
  min-height: 2.25rem;
  padding: 0.42rem 0.55rem;
  border: 1px solid var(--cell-border);
  border-radius: 8px;
  background: var(--surface-raised);
}

.pool-letter-name {
  color: var(--ink);
  font: 900 1rem/1 system-ui, sans-serif;
}

.pool-blank-icon {
  display: inline-block;
  width: 1.08rem;
  height: 0.62rem;
  border-right: 0.14rem solid currentColor;
  border-bottom: 0.14rem solid currentColor;
  border-left: 0.14rem solid currentColor;
  transform: translateY(0.12rem);
}

.pool-letter-count {
  justify-self: end;
  color: var(--teal-deep);
  font: 800 0.9rem/1 system-ui, sans-serif;
}

@media (max-width: 640px) {
  :root {
    --play-width: min(72vh, calc(100vw - 0.5rem), 560px);
  }

  main {
    width: 100%;
    padding-inline: 0.1875rem;
  }

  html.has-stored-player body .masthead,
  body.has-player .masthead {
    grid-template-columns: minmax(0, 1fr) auto;
    column-gap: 0.45rem;
  }

  html.has-stored-player body .brand,
  body.has-player .brand {
    justify-self: start;
    --brand-scale: clamp(1.15rem, 6.5vw, 1.35rem);
  }

  html.has-stored-player body .game-controls,
  body.has-player .game-controls {
    justify-self: end;
    gap: 0.35rem;
  }

  html.has-stored-player body .identity-current,
  body.has-player .identity-current {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    grid-template-areas:
      "icon name"
      "icon provider";
    align-items: center;
    gap: 0 0.35rem;
    text-align: left;
  }

  html.has-stored-player body .identity-current .ww-icon,
  body.has-player .identity-current .ww-icon {
    grid-area: icon;
  }

  html.has-stored-player body .identity-name,
  body.has-player .identity-name {
    grid-area: name;
    min-width: 0;
    line-height: 1.05;
  }

  html.has-stored-player body .identity-provider,
  body.has-player .identity-provider {
    grid-area: provider;
    min-width: 0;
    line-height: 1.05;
  }
}

@media (max-width: 520px) {

  .masthead {
    grid-template-columns: 1fr;
    justify-items: center;
  }

  .brand,
  .game-controls {
    justify-self: center;
  }

  .brand {
    --brand-scale: clamp(1.1rem, 9.5vw, 1.6rem);
  }

  html.has-stored-player body .masthead,
  body.has-player .masthead {
    grid-template-columns: minmax(0, 1fr) auto;
    column-gap: 0.45rem;
  }

  html.has-stored-player body .brand,
  body.has-player .brand {
    justify-self: start;
    --brand-scale: clamp(1.15rem, 6.5vw, 1.35rem);
  }

  html.has-stored-player body .game-controls,
  body.has-player .game-controls {
    justify-self: end;
    gap: 0.35rem;
  }

  .leaderboard-row {
    grid-template-columns: 1.75rem minmax(0, 1fr) 4rem 3.75rem 2.8rem 3rem;
    gap: 0.2rem;
    padding-inline: 0.4rem;
  }

  .leaderboard-header {
    font-size: 0.55rem;
    letter-spacing: 0.03em;
  }

  body.screen-setup.has-player .identity-bar {
    justify-self: end;
  }

  .board {
    width: var(--play-width);
  }

  .rack {
    min-height: 3.8rem;
  }

}

/* Pixel-7-class widths: letters on unplayed tiles (rack + marketplace rail)
   shrink so the glyph and point digit keep breathing room on ~48px tiles.
   Board tiles already run their own smaller clamp and stay untouched. */
@media (max-width: 480px) {
  .rack .tile,
  .marketplace .marketplace-item .tile {
    font-size: clamp(1rem, 5vw, 1.45rem);
  }

  /* The desktop 0.475rem inset reads oversized on ~48px tiles: hug the
     corner a little closer. */
  .rack .tile .tile-points,
  .marketplace .marketplace-item .tile-points {
    right: 0.3rem;
    bottom: 0.42rem;
  }
}

@media (max-width: 400px) {
  html.has-stored-player body .brand,
  body.has-player .brand {
    --brand-scale: clamp(1.05rem, 6.5vw, 1.15rem);
  }

  html.has-stored-player body .masthead,
  body.has-player .masthead {
    column-gap: 0.3rem;
  }
}

/* Phone landscape: the base --play-width keys off 72vh, which in a ~400px-tall
   landscape viewport squishes the whole play column to under 300px. When the
   viewport is short and wider than tall, size off the width instead so the
   board runs nearly full width (issue #5); the page scrolls vertically. Must
   stay after the max-width:640px override — small landscape phones match both
   queries and this one has to win the --play-width cascade. */
@media (orientation: landscape) and (max-height: 520px) {
  :root {
    --play-width: calc(100vw - 1rem);
  }
}

/* Review mode: the marketplace can't be rewound to a past turn, so blank its
   tiles (keeping the rail height) and float the review banner centered over it. */
.review-banner {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  z-index: 5;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0.5rem 0.75rem;
  max-width: calc(100% - 0.8rem);
  padding: 0.4rem 0.6rem;
  border-radius: 0.6rem;
  background: var(--color-accent, #2b6cb0);
  color: #fff;
  font-weight: 600;
  text-align: center;
  box-shadow: 0 6px 16px var(--shadow-soft, rgba(0, 0, 0, 0.3));
}

.review-banner[aria-hidden="true"] {
  display: none;
}

.review-return-live-button {
  border: 0;
  border-radius: 0.4rem;
  padding: 0.3rem 0.7rem;
  background: rgba(255, 255, 255, 0.22);
  color: #fff;
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}

.review-return-live-button:hover {
  background: rgba(255, 255, 255, 0.35);
}

.review-mode #marketplace {
  visibility: hidden;
}

.review-mode .market-sign-open-tab {
  display: none;
}

.board-review-locked {
  cursor: default;
}

.board-review-locked .tile {
  cursor: default;
}

/* Review mode is read-only, so hide the rack together with all its turn
   controls (shuffle, redraw, pass, reset, finish), and the live game/turn/
   potential/pool stats bar (inaccurate for a past turn). */
.review-mode .rack-wrap,
.review-mode .game-state-summary {
  display: none;
}

/* In review the View Pool button is repurposed into a second Return to Live
   control (the first is in the marketplace banner). Reusing the same button
   keeps the log from jumping; auto width lets the longer label fit. */
.view-pool-button.is-review-exit {
  width: auto;
}

.game-log-entry-interactive {
  cursor: pointer;
}

.leaderboard-recent-reactions {
  display: grid;
  gap: 0.25rem;
  margin: 1rem 0;
}

.leaderboard-recent-reactions-title {
  margin: 0 0 0.2rem;
  color: var(--ink);
  font: 900 0.85rem/1.2 system-ui, sans-serif;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.game-log-entry-interactive:hover {
  background: var(--color-surface-hover, rgba(0, 0, 0, 0.04));
}

.game-log-review-target {
  position: absolute;
  z-index: 0;
  inset: 0;
  width: 100%;
  border: 0;
  border-radius: inherit;
  background: transparent;
  cursor: pointer;
  appearance: none;
}

.game-log-entry-interactive:has(.game-log-review-target:focus-visible) {
  outline: 2px solid var(--coral);
  outline-offset: 2px;
}

.game-log-entry-interactive > .game-log-heading,
.game-log-entry-interactive > .word-score-list,
.game-log-entry-interactive > .game-log-returned-tiles {
  position: relative;
  z-index: 1;
  pointer-events: none;
}

.game-log-entry-reviewable .word-score-disclosure,
.game-log-entry-reviewable .word-score-breakdown {
  pointer-events: auto;
}

.game-log-entry-interactive > .word-score-list:has(.score-breakdown-open) {
  z-index: 3;
}

html[data-theme="dark"] .word-score-points,
html[data-theme="dark"] .word-score-breakdown-result {
  color: var(--cyan-neon);
}

.game-log-entry-reviewing {
  outline: 2px solid var(--color-accent, #2b6cb0);
  outline-offset: -2px;
}

.game-log-reactions {
  position: relative;
  z-index: 2;
  display: grid;
  justify-items: start;
  min-width: 0;
  pointer-events: auto;
}

.game-log-reactions:not(.is-expanded) {
  pointer-events: none;
}

.game-log-reaction-summary {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem;
  min-height: 0;
}

.game-log-reaction-chip {
  color: var(--ink-muted);
  font: 800 0.74rem/1.2 system-ui, sans-serif;
}

html[data-theme="dark"] .game-log-reaction-chip {
  color: var(--ink);
}

.game-log-reaction-details {
  display: none;
  box-sizing: border-box;
  width: calc(100% + 1rem);
  min-width: 0;
  margin: 0 -0.5rem -0.55rem;
  padding: 0 0.65rem 0.55rem;
  border: 0;
  border-radius: 0;
  background: transparent;
}

.game-log-reactions.is-expanded .game-log-reaction-summary {
  display: none;
}

.game-log-reactions.is-expanded .game-log-reaction-details {
  display: grid;
  gap: 0.4rem;
}

.game-log-reaction-log {
  display: grid;
  gap: 0.2rem;
  margin: 0;
  padding: 0;
  list-style: none;
  color: var(--ink);
  font: 700 0.78rem/1.25 system-ui, sans-serif;
}

.game-log-reaction-picker {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(1.8rem, 1fr));
  gap: 0.2rem;
  width: 100%;
  min-width: 0;
}

.game-log-reaction-option {
  min-width: 0;
  padding: 0.25rem 0.1rem;
  border: 1px solid transparent;
  border-radius: 6px;
  background: transparent;
  font-size: 1.1rem;
  cursor: pointer;
}

.game-log-reaction-option:hover,
.game-log-reaction-option:focus-visible {
  background: var(--color-surface-hover, rgba(0, 0, 0, 0.06));
}

.game-log-reaction-option[aria-pressed="true"] {
  border-color: var(--coral);
  background: color-mix(in srgb, var(--coral) 14%, transparent);
}

.game-log-reaction-option:disabled {
  cursor: wait;
  opacity: 0.55;
}

/* ===== Themes (opt-in word packs) ===== */

/* New-game theme picker: mirrors the game-length billboard cards. */
.game-theme-control {
  display: grid;
  gap: 0.5rem;
  justify-items: center;
  font: 800 0.86rem/1 system-ui, sans-serif;
}

.game-theme-control legend {
  color: var(--ink-muted);
  font: 400 0.78rem/1 "Righteous", "Trebuchet MS", sans-serif;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 0 0.4rem;
}

.game-theme-hint {
  margin: 0;
  color: var(--ink-muted);
  font: 400 0.78rem/1.35 system-ui, sans-serif;
  text-align: center;
  max-width: 34ch;
}

.game-theme-options {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.55rem;
}

.game-theme-option {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  min-height: 2.75rem;
  padding: 0.5rem 0.85rem;
  border: 2px solid var(--cell-border);
  border-radius: 8px;
  background: var(--surface);
  box-shadow: 0.14rem 0.14rem 0 var(--shadow-soft);
  cursor: pointer;
  transition: border-color 140ms ease, box-shadow 140ms ease, transform 140ms ease;
}

.game-theme-option:has(input:checked) {
  border-color: var(--theme-accent);
  background: var(--surface-raised);
  box-shadow: 0.18rem 0.18rem 0 var(--theme-accent-deep);
  transform: translateY(-0.08rem);
}

html[data-theme="dark"] .game-theme-option:has(input:checked) {
  border-color: var(--theme-accent);
  box-shadow:
    0.18rem 0.18rem 0 var(--theme-accent-deep),
    0 0 calc(12px * var(--glow-strength)) var(--theme-glow);
}

.game-theme-option input {
  position: absolute;
  inset: 0;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}

.game-theme-option input:focus-visible {
  outline: 2px solid var(--theme-accent);
  outline-offset: 2px;
  opacity: 1;
  appearance: none;
}

.game-theme-copy {
  display: grid;
  gap: 0.12rem;
  text-align: left;
}

.game-theme-name {
  color: var(--ink);
}

.game-theme-detail {
  color: var(--ink-muted);
  font: 400 0.72rem/1 system-ui, sans-serif;
}

/* Theme panel: visible words + hidden counts, above the game log. */
.theme-panel {
  display: grid;
  gap: 0.55rem;
  margin-top: 0.75rem;
  padding-top: 0.75rem;
  border-top: 2px solid var(--cell-border);
}

.theme-panel[hidden] {
  display: none;
}

.theme-panel-header {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
}

.theme-panel-kicker {
  color: var(--ink-muted);
  font: 400 0.72rem/1 "Righteous", "Trebuchet MS", sans-serif;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.theme-panel-title {
  margin: 0;
  color: var(--theme-accent-deep);
  font: 800 1rem/1.2 "Righteous", "Trebuchet MS", sans-serif;
}

html[data-theme="dark"] .theme-panel-title {
  color: var(--theme-accent);
  text-shadow: 0 0 calc(8px * var(--glow-strength)) var(--theme-glow);
}

/* Themed games name their theme between the scoreboard and the marketplace
   (issue #40): a compact themed pill, hidden entirely on unthemed games. */
.game-theme-strip {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 0.45rem;
  width: max-content;
  max-width: 100%;
  margin: 0.15rem auto 0;
  padding: 0.28rem 0.7rem;
  border: 1px solid var(--theme-accent);
  border-radius: 999px;
  background: color-mix(in srgb, var(--theme-accent) 9%, transparent);
}

.game-theme-strip[hidden] {
  display: none;
}

.game-theme-strip-kicker {
  color: var(--ink-muted);
  font: 400 0.68rem/1 "Righteous", "Trebuchet MS", sans-serif;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.game-theme-strip-title {
  color: var(--theme-accent-deep);
  font: 800 0.92rem/1.15 "Righteous", "Trebuchet MS", sans-serif;
  letter-spacing: 0.02em;
}

html[data-theme="dark"] .game-theme-strip-title {
  color: var(--theme-accent);
  text-shadow: 0 0 calc(8px * var(--glow-strength)) var(--theme-glow);
}

.theme-visible-words {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
}

.theme-word-chip {
  padding: 0.18rem 0.42rem;
  border: 1px solid var(--theme-accent);
  border-radius: 8px;
  background: color-mix(in srgb, var(--theme-accent) 9%, transparent);
  color: var(--ink);
  font: 800 0.8rem/1 system-ui, sans-serif;
}

.theme-hidden-words {
  display: grid;
  gap: 0.3rem;
}

.theme-hidden-title {
  margin: 0;
  color: var(--ink-muted);
  font: 400 0.72rem/1 "Righteous", "Trebuchet MS", sans-serif;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.theme-hidden-counts {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem 0.6rem;
}

.theme-hidden-count {
  display: inline-flex;
  align-items: baseline;
  gap: 0.3rem;
  font: 800 0.8rem/1 system-ui, sans-serif;
  color: var(--ink);
}

.theme-hidden-length {
  color: var(--ink-muted);
  font-weight: 400;
}

.theme-hidden-done {
  color: var(--ink-muted);
  font: 400 0.8rem/1.3 system-ui, sans-serif;
}

/* Board tiles that currently spell a visible theme word (presentation only:
   recolors retroactively on reveals, reverts when the word changes). */
.board .tile.tile-theme-word {
  outline: 2px solid var(--theme-accent);
  outline-offset: -2px;
}

html[data-theme="dark"] .board .tile.tile-theme-word {
  outline-color: var(--theme-accent);
  box-shadow: 0 0 calc(10px * var(--glow-strength)) var(--theme-glow);
}

/* Game log: theme-stamped words carry their multiplier chip. */
.word-score-item-theme .word-score-disclosure {
  border-color: var(--theme-accent);
  background: color-mix(in srgb, var(--theme-accent) 9%, transparent);
}

html:not([data-theme="dark"]) .word-score-item-theme .word-score-points {
  color: var(--ink);
}

.word-score-theme-multiplier {
  border-color: var(--theme-accent-deep);
  background: color-mix(in srgb, var(--theme-accent) 16%, transparent);
  color: var(--theme-accent-deep);
  font: 800 0.72rem/1 system-ui, sans-serif;
  white-space: nowrap;
}

html:not([data-theme="dark"]) .word-score-multiplier-visible-theme {
  color: var(--ink);
}

html[data-theme="dark"] .word-score-theme-multiplier {
  color: var(--theme-accent);
}

.word-score-item-theme-hidden .word-score-theme-multiplier {
  padding: 0.08rem 0.28rem;
  border-radius: 6px;
  background: var(--theme-accent-deep);
  color: var(--on-accent-ink);
}

/* Night: the accent pill is light pink neon, so the base dark-mode rule
   (pink text) would paint pink-on-pink — the x3 chip needs dark ink. */
html[data-theme="dark"] .word-score-item-theme-hidden .word-score-theme-multiplier {
  background: var(--theme-accent);
  color: var(--sign-face);
}

/* Themes page: every pack with discoveries, starters, and hidden-word stats. */
.themes-page {
  display: none;
  grid-column: 1 / -1;
  width: 100%;
  max-width: 54rem;
  gap: 1rem;
  text-align: left;
  font: 700 0.98rem/1.45 system-ui, sans-serif;
}

body.screen-themes .themes-page {
  display: grid;
  margin-top: calc(clamp(1.5rem, 3vw, 2.25rem) - 0.75rem);
}

body.screen-themes .page-hero {
  width: var(--play-width);
  justify-self: center;
}

.themes-page-intro {
  margin: 0;
  color: var(--ink-muted);
  font: 400 0.9rem/1.45 system-ui, sans-serif;
}

.themes-page-list {
  display: grid;
  gap: 1rem;
}

.themes-page-card {
  display: grid;
  gap: 0.7rem;
  padding: 1rem 1.15rem;
  border: 2px solid var(--cell-border);
  border-radius: 12px;
  background: var(--surface);
  box-shadow: 0.18rem 0.18rem 0 var(--shadow-soft);
}

.themes-card-heading {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.35rem 0.75rem;
}

.themes-card-title {
  margin: 0;
  color: var(--theme-accent-deep);
  font: 800 1.15rem/1.2 "Righteous", "Trebuchet MS", sans-serif;
}

html[data-theme="dark"] .themes-card-title {
  color: var(--theme-accent);
  text-shadow: 0 0 calc(8px * var(--glow-strength)) var(--theme-glow);
}

.themes-card-progress {
  color: var(--ink-muted);
  font: 400 0.82rem/1 system-ui, sans-serif;
}

.themes-card-label {
  margin: 0;
  color: var(--ink-muted);
  font: 400 0.72rem/1 "Righteous", "Trebuchet MS", sans-serif;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.themes-card-section {
  display: grid;
  gap: 0.35rem;
}

/* Starters were never hidden; render them quieter than discoveries. */
.theme-word-chip-starter {
  border-color: var(--cell-border);
  background: transparent;
  color: var(--ink-muted);
}

.theme-word-chip-discovered {
  cursor: help;
}

/* On-brand hover card for any element carrying data-ww-tooltip — same look
   as the identity account tooltip (ink border, raised face, gold shadow). */
[data-ww-tooltip] {
  position: relative;
  cursor: help;
}

[data-ww-tooltip]::after {
  content: attr(data-ww-tooltip);
  position: absolute;
  bottom: calc(100% + 0.45rem);
  left: 50%;
  z-index: 30;
  width: max-content;
  max-width: min(16rem, 80vw);
  padding: 0.4rem 0.55rem;
  border: 2px solid var(--ink);
  border-radius: 6px;
  background: var(--surface-raised);
  color: var(--ink);
  box-shadow: 0.14rem 0.14rem 0 var(--gold);
  font: 700 0.72rem/1.25 system-ui, sans-serif;
  letter-spacing: normal;
  text-transform: none;
  text-align: left;
  white-space: normal;
  opacity: 0;
  pointer-events: none;
  transform: translate(-50%, 0.2rem);
  transition: opacity 140ms ease, transform 140ms ease;
}

[data-ww-tooltip]:hover::after,
[data-ww-tooltip]:focus-visible::after {
  opacity: 1;
  transform: translate(-50%, 0);
}

/* Player profile: identity card, lifetime stats, head-to-head records, games. */
.profile-card {
  display: grid;
  gap: 0.45rem;
  justify-items: center;
  padding: 0.9rem 0.95rem;
  border: 2px solid var(--cell-border);
  border-radius: 8px;
  background: var(--surface);
  box-shadow: 0.12rem 0.12rem 0 var(--shadow-soft);
  text-align: center;
}

.profile-display-name {
  margin: 0;
  color: var(--hot-accent);
  font: 400 clamp(1.25rem, 3.5vw, 1.7rem)/1.15 "Righteous", "Trebuchet MS", sans-serif;
  letter-spacing: 0.02em;
}

.profile-real-name {
  margin: 0;
  color: var(--ink);
  font: 800 0.98rem/1.3 system-ui, sans-serif;
}

.profile-blurb {
  margin: 0;
  color: var(--ink-muted);
  font: 700 0.92rem/1.4 system-ui, sans-serif;
}

.profile-url,
.profile-url:visited {
  color: var(--teal-deep);
  font: 800 0.9rem/1.3 system-ui, sans-serif;
  text-decoration: none;
  overflow-wrap: anywhere;
}

.profile-url:hover,
.profile-url:focus {
  color: var(--coral-deep);
}

html[data-theme="dark"] .profile-url,
html[data-theme="dark"] .profile-url:visited {
  color: var(--cyan-neon);
}

.profile-account-line {
  margin: 0;
  color: var(--ink-muted);
  font: 700 0.78rem/1.3 system-ui, sans-serif;
  overflow-wrap: anywhere;
}

.profile-edit-button {
  margin-top: 0.25rem;
}

.profile-edit-input {
  width: 100%;
}

.profile-edit-label {
  justify-self: start;
  margin-top: 0.3rem;
  color: var(--ink-muted);
  font: 950 0.62rem/1 system-ui, sans-serif;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.profile-blurb-input {
  resize: vertical;
  font: inherit;
}

.profile-edit-controls {
  display: flex;
  gap: 0.5rem;
  justify-content: center;
}

.profile-form-message {
  margin: 0;
  color: var(--coral-deep);
  font: 700 0.9rem/1.3 system-ui, sans-serif;
}

.profile-form-message:empty {
  display: none;
}

.profile-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(8.8rem, 1fr));
  gap: 0.5rem;
  min-width: 0;
}

.profile-stat-item {
  display: grid;
  gap: 0.22rem;
  min-width: 0;
  padding: 0.6rem 0.65rem;
  border: 2px solid var(--cell-border);
  border-radius: 8px;
  background: var(--surface);
  box-shadow: 0.12rem 0.12rem 0 var(--shadow-soft);
}

.profile-stat-value {
  min-width: 0;
  overflow: hidden;
  color: var(--coral);
  font: 950 1.02rem/1.08 system-ui, sans-serif;
  text-overflow: ellipsis;
  white-space: nowrap;
}

html[data-theme="dark"] .profile-stat-value {
  color: var(--gold);
}

.profile-stat-label {
  color: var(--ink-muted);
  font: 950 0.62rem/1 system-ui, sans-serif;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.profile-stat-detail {
  color: var(--ink-muted);
  font: 700 0.78rem/1.2 system-ui, sans-serif;
}

.profile-section {
  display: grid;
  gap: 0.5rem;
}

.profile-section-title {
  margin: 0.35rem 0 0;
  color: var(--ink-muted);
  font: 950 0.72rem/1 system-ui, sans-serif;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

/* Head-to-head + games render as leaderboard-style tables: tight gap, flat
   bordered rows, zebra striping. */
.profile-opponents,
.profile-games {
  display: grid;
  gap: 0.32rem;
  min-width: 0;
}

.profile-reaction-rows {
  display: grid;
  gap: 0.25rem;
}

.profile-record-row,
.profile-game-row,
.profile-reaction-row {
  display: grid;
  align-items: center;
  gap: 0.5rem;
  min-width: 0;
  min-height: 2.9rem;
  padding: 0.5rem 0.65rem;
  border: 2px solid var(--cell-border);
  border-radius: 8px;
  background: var(--surface);
}

/* Zebra: every other data row (set in JS, so it's independent of the mix of
   <a>/<div> row elements and the header). */
.profile-row-striped {
  background: var(--surface-raised);
}

/* Content-independent column widths so every row (and the header) lines up:
   opponent left, record and games centered, points right. */
.profile-record-row {
  grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr) minmax(0, 0.7fr) minmax(0, 1.2fr);
}

.profile-record-row > :nth-child(1) {
  text-align: left;
}

.profile-record-row > :nth-child(2),
.profile-record-row > :nth-child(3) {
  text-align: center;
}

.profile-record-row > :nth-child(4) {
  text-align: right;
}

.profile-record-header {
  min-height: 2.2rem;
  border-color: transparent;
  background: transparent;
  box-shadow: none;
  padding-top: 0;
  padding-bottom: 0;
  color: var(--ink-muted);
  font: 950 0.62rem/1 system-ui, sans-serif;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.profile-record-row.viewer-record {
  border-color: var(--gold-deep);
  background: var(--gold-wash);
}

.profile-record-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Muted "W-L" format hint appended to the Record column header. */
.profile-record-hint {
  color: var(--ink-muted);
  opacity: 0.7;
  letter-spacing: normal;
}

.profile-game-row {
  grid-template-columns: auto auto minmax(0, 1fr);
}

.profile-reaction-row {
  grid-template-columns: minmax(0, 1fr) minmax(0, 2.75fr) minmax(0, 1fr);
  color: var(--ink);
  font: 700 0.85rem/1.25 system-ui, sans-serif;
}

.profile-reaction-game {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.3rem 0.5rem;
  min-width: 0;
}

.profile-reaction-play {
  min-width: 0;
  overflow-wrap: anywhere;
  font-weight: 900;
  text-align: center;
}

.profile-reaction-play.game-log-returned-tiles {
  gap: 0.2rem;
  justify-content: center;
}

.profile-reaction-counts {
  min-width: 0;
  text-align: right;
  white-space: nowrap;
}

.profile-game-code {
  font: 950 0.9rem/1 "Righteous", "Trebuchet MS", sans-serif;
  letter-spacing: 0.06em;
}

.profile-game-status {
  color: var(--ink-muted);
  font: 800 0.78rem/1.2 system-ui, sans-serif;
  white-space: nowrap;
}

.profile-game-theme {
  display: inline-flex;
  align-items: center;
  padding: 0.08rem 0.32rem;
  border: 1px solid var(--theme-accent);
  border-radius: 6px;
  color: var(--theme-accent-deep);
  background: color-mix(in srgb, var(--theme-accent) 9%, transparent);
  font: 800 0.68rem/1.2 system-ui, sans-serif;
  white-space: nowrap;
}

html[data-theme="dark"] .profile-game-theme {
  color: var(--theme-accent);
}

.profile-game-players {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: 0.22rem 0.4rem;
  min-width: 0;
  color: var(--ink);
  font: 700 0.85rem/1.3 system-ui, sans-serif;
  text-align: right;
}

.profile-game-player {
  white-space: nowrap;
}

.profile-game-player-sep {
  color: var(--ink-muted);
}

/* Standard winner highlight box (matches the game-list winner treatment). */
.profile-game-player.winner-player {
  padding: 0.05rem 0.4rem;
  border: 1px solid var(--gold-deep);
  border-radius: 6px;
  background: linear-gradient(135deg, var(--gold-wash), var(--surface-raised) 68%);
  color: var(--coral-deep);
  font-weight: 900;
}

html[data-theme="dark"] .profile-game-player.winner-player {
  color: var(--gold);
}

.profile-empty {
  padding: 0.6rem 0.65rem;
  color: var(--ink-muted);
  font: 700 0.9rem/1.35 system-ui, sans-serif;
  text-align: center;
}

.profile-player-link,
.profile-player-link:visited,
.profile-game-link,
.profile-game-link:visited {
  color: inherit;
  text-decoration: none;
}

/* Whole-tile links (stat tiles, head-to-head rows, game rows): same hover
   treatment as the leaderboard highlight tiles — teal edge, no underline. */
.profile-tile-link,
.profile-tile-link:visited {
  color: inherit;
  text-decoration: none;
}

.profile-tile-link:hover,
.profile-tile-link:focus-visible {
  border-color: var(--teal);
  box-shadow: 0.16rem 0.16rem 0 var(--teal-glow);
  outline: none;
}

.profile-tile-link:focus-visible {
  outline: 2px solid var(--coral);
  outline-offset: 2px;
}

html[data-theme="dark"] .profile-tile-link:focus-visible {
  outline-color: var(--gold);
}

.profile-player-link:hover,
.profile-player-link:focus,
.profile-game-link:hover,
.profile-game-link:focus {
  color: var(--coral-deep);
}

html[data-theme="dark"] .profile-player-link:hover,
html[data-theme="dark"] .profile-player-link:focus,
html[data-theme="dark"] .profile-game-link:hover,
html[data-theme="dark"] .profile-game-link:focus {
  color: var(--gold);
}

/* The current-turn scoreboard row sits on the dark sign-face, where the coral
   hover is illegible — use the on-dark (near-white) text color instead. Higher
   specificity than both hover rules above, so it wins in either theme. */
.player-score-row.current-turn .profile-player-link:hover,
.player-score-row.current-turn .profile-player-link:focus {
  color: var(--ink-on-dark);
}

/* Keep each emoji/count pair together, but let a long reaction summary gain
   additional lines instead of painting beyond the row on phone widths. */
@media (max-width: 520px) {
  .profile-reaction-counts {
    white-space: normal;
  }
}
