/* Family Uno Spin — big, warm, and readable first. */

:root {
  --bg: #1d3a2f;            /* card-table green, deep and calm */
  --bg-panel: #16302656;
  --panel: #f7f2e7;
  --ink: #22221d;
  --ink-invert: #fdfbf4;
  --accent: #ff9f1c;
  --accent-ink: #3a2500;
  /* Classic Uno palette (CC0 Wikimedia deck) */
  --red: #ff5555;
  --yellow: #ffaa00;
  --green: #55aa55;
  --blue: #5555ff;
  --card-face: #ffffff;
  --shadow: 0 6px 18px rgba(0, 0, 0, 0.35);
  --radius: 18px;
  --font: "Avenir Next", "Segoe UI", system-ui, -apple-system, sans-serif;
  font-size: 20px;
}
html[data-textsize="2"] { font-size: 24px; }
html[data-textsize="3"] { font-size: 29px; }

html[data-contrast="high"] {
  --bg: #000000;
  --bg-panel: #000000cc;
  --panel: #ffffff;
  --ink: #000000;
  --ink-invert: #ffffff;
  --accent: #ffb700;
  --red: #ff3b30;
  --yellow: #ffd60a;
  --green: #34c759;
  --blue: #409cff;
  --shadow: 0 0 0 3px #ffffff;
}

* { box-sizing: border-box; }
[hidden] { display: none !important; }
html, body { margin: 0; padding: 0; }
body {
  font-family: var(--font);
  background: var(--bg);
  background-image: radial-gradient(ellipse at 50% -10%, #ffffff14, transparent 60%);
  color: var(--ink-invert);
  height: 100vh;
  height: 100dvh;
  display: flex;
  flex-direction: column;
  -webkit-font-smoothing: antialiased;
}
/* The game table sizes itself to the window, so the page owns its own scrolling. */
#main { flex: 1; min-height: 0; display: flex; flex-direction: column; }
html[data-contrast="high"] body { background-image: none; }

button {
  font-family: inherit;
  font-size: 1rem;
  cursor: pointer;
  border: none;
  border-radius: var(--radius);
  min-height: 3rem;
  padding: 0.5rem 1.1rem;
  touch-action: manipulation;
}
button:focus-visible, a:focus-visible, input:focus-visible {
  outline: 4px solid var(--accent);
  outline-offset: 2px;
}
button:disabled { opacity: 0.45; cursor: default; }

.sr-only {
  position: absolute; width: 1px; height: 1px;
  clip-path: inset(50%); overflow: hidden; white-space: nowrap;
}
.skip-link {
  position: absolute; left: -999px; top: 0; z-index: 100;
  background: var(--accent); color: var(--accent-ink);
  padding: 0.6rem 1rem; border-radius: 0 0 var(--radius) 0;
}
.skip-link:focus { left: 0; }

/* ---------- Top bar ---------- */
#topbar {
  display: flex; justify-content: space-between; align-items: center;
  padding: 0.4rem 0.8rem; gap: 0.5rem; flex-wrap: wrap;
}
.topbar-left { display: flex; align-items: center; gap: 0.5rem; min-width: 0; }
#table-name-badge {
  font-weight: 800; font-size: 1.05rem;
  background: var(--bg-panel); border-radius: 10px; padding: 0.35rem 0.7rem;
  border: 2px solid #ffffff33;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
#table-name-badge:empty { display: none; }
.chip {
  background: #ffffff22; color: var(--ink-invert);
  border: 2px solid #ffffff44; border-radius: 999px;
  min-height: 2.6rem; padding: 0.2rem 0.9rem; font-weight: 700;
}
.chip[aria-pressed="true"] { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); }
.chip .plus { font-size: 0.8em; vertical-align: super; }

/* ---------- Screens ---------- */
.screen { max-width: 64rem; margin: 0 auto; padding: 1rem; flex: 1; min-height: 0; overflow-y: auto; width: 100%; }
.center { text-align: center; }

.title {
  text-align: center; font-size: 2.6rem; font-weight: 900; margin: 1.2rem 0 0.2rem;
  text-shadow: 0 3px 0 #00000055;
}
.title .spin-word { color: var(--accent); }
.subtitle { text-align: center; font-size: 1.1rem; margin: 0 0 1.5rem; opacity: 0.9; }

.bigbtn {
  display: block; width: 100%; max-width: 30rem; margin: 0.7rem auto;
  font-size: 1.35rem; font-weight: 800; min-height: 4.2rem;
  background: var(--accent); color: var(--accent-ink); box-shadow: var(--shadow);
}
.bigbtn.secondary { background: var(--panel); color: var(--ink); }
.bigbtn:not(:disabled):active { transform: translateY(2px); }

.panel {
  background: var(--panel); color: var(--ink);
  border-radius: var(--radius); box-shadow: var(--shadow);
  padding: 1.2rem; max-width: 34rem; margin: 1rem auto;
}
.panel h2 { margin-top: 0; }
.field { margin: 0.9rem 0; }
.field label { display: block; font-weight: 700; margin-bottom: 0.35rem; }
.field input {
  width: 100%; font-size: 1.4rem; padding: 0.6rem 0.8rem;
  border: 3px solid #999; border-radius: 12px; font-family: inherit;
}
.field input:focus { border-color: var(--blue); }

.avatar-grid { display: flex; flex-wrap: wrap; gap: 0.45rem; }
.avatar-grid button {
  font-size: 1.7rem; width: 3.2rem; min-height: 3.2rem; padding: 0;
  background: #eee; border: 3px solid transparent; border-radius: 12px;
}
.avatar-grid button[aria-pressed="true"] { border-color: var(--blue); background: #d7e7ff; }

.error-note { color: #b00020; font-weight: 700; min-height: 1.4em; }
html[data-contrast="high"] .error-note { color: #d00030; }

/* ---------- The gate ----------
   One password for the whole family, checked on the server. Deliberately bare:
   there is nothing to look at here but the one box. */
.gate-wrap { max-width: 26rem; margin: 6vh auto 0; text-align: center; }
.gate-mark { font-size: 4rem; line-height: 1; }
.gate-title { font-size: 1.9rem; font-weight: 900; margin: 0.6rem 0 0.2rem; }
.gate-title .spin-word { color: var(--accent); }
.gate-sub { opacity: 0.85; margin: 0 0 1.4rem; line-height: 1.4; }
.gate-wrap .field input {
  text-align: center; letter-spacing: 0.12em;
}
.gate-wrap .error-note { color: var(--red); }
.gate-foot { margin-top: 1.4rem; opacity: 0.6; font-size: 0.85rem; line-height: 1.5; }

/* ---------- Who are you ---------- */
.who-title { font-size: 1.9rem; font-weight: 900; text-align: center; margin: 3vh 0 0.3rem; }
.who-sub { text-align: center; opacity: 0.85; margin: 0 0 1.2rem; line-height: 1.5; }
.who-grid { display: grid; gap: 0.8rem; grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr)); }
/* First run: the lone "I'm new here" tile shouldn't stretch the full width. */
.who-grid:has(> :only-child) { max-width: 16rem; margin: 0 auto; }
.who-tile {
  background: var(--bg-panel); border: 3px solid #ffffff2e; border-radius: var(--radius);
  color: var(--ink-invert); min-height: 8.5rem;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 0.3rem;
}
.who-tile:hover, .who-tile:focus-visible { border-color: var(--accent); background: #ffffff14; }
.who-tile .face { font-size: 2.8rem; line-height: 1; }
.who-tile .nm { font-weight: 800; font-size: 1.05rem; }
.who-tile .last { font-size: 0.75rem; opacity: 0.65; font-weight: 600; }
.who-tile.new { border-style: dashed; }

.new-wrap { max-width: 30rem; margin: 0 auto; }
.face-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(3.6rem, 1fr)); gap: 0.4rem; }
.face-grid button {
  min-height: 3.4rem; font-size: 1.9rem; padding: 0;
  background: var(--bg-panel); border: 3px solid #ffffff2e; border-radius: 14px;
}
.face-grid button[aria-pressed="true"] { border-color: var(--accent); background: #ff9f1c2e; }
/* Faces already spoken for are dimmed, not blocked — two cousins may both want 🐱. */
.face-taken { opacity: 0.42; }

/* ---------- The foyer ----------
   Every table the family has going. The one that wants you most — your turn,
   your lobby — spans the full width so it answers "is anything waiting for me?"
   before a word has been read. */
#screen-foyer { max-width: 52rem; }
.foyer-head { display: flex; align-items: center; gap: 0.7rem; flex-wrap: wrap; margin-bottom: 1rem; }
.foyer-head h1 { font-size: 1.6rem; font-weight: 900; margin: 0; flex: 1; min-width: 8rem; }
.me-chip {
  display: inline-flex; align-items: center; gap: 0.4rem;
  background: var(--bg-panel); border: 2px solid #ffffff2e; border-radius: 999px;
  padding: 0.25rem 0.5rem 0.25rem 0.55rem; font-weight: 800; font-size: 0.9rem;
}
.me-chip .face { font-size: 1.4rem; }
.me-chip .chiplet {
  min-height: 2rem; padding: 0.1rem 0.7rem; font-size: 0.78rem; font-weight: 800;
  background: #ffffff1f; color: var(--ink-invert); border-radius: 999px;
  border: 2px solid #ffffff33;
}

.rooms { display: grid; gap: 0.7rem; grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr)); }
.rooms[data-hero="1"] .room[data-hero="1"] { grid-column: 1 / -1; }
.room {
  background: var(--bg-panel); border: 3px solid #ffffff2e; border-radius: var(--radius);
  padding: 0.75rem 0.85rem; display: flex; flex-direction: column; gap: 0.5rem; text-align: left;
}
.room[data-mine="1"] { border-color: var(--accent); background: #ff9f1c1f; }
.room[data-locked="1"] { opacity: 0.62; }
.room[data-state="finished"] { opacity: 0.75; }
.room-main { display: flex; flex-direction: column; gap: 0.45rem; }
.room-name { font-weight: 900; font-size: 1.15rem; line-height: 1.2; display: flex; gap: 0.4rem; align-items: baseline; }
.room-name .wheel { font-size: 1rem; flex: none; }
.rooms[data-hero="1"] .room[data-hero="1"] .room-name { font-size: 1.7rem; }

.seats { display: flex; flex-wrap: wrap; gap: 0.35rem; }
.seat {
  display: inline-flex; align-items: center; gap: 0.25rem;
  background: #ffffff14; border-radius: 999px; padding: 0.15rem 0.55rem 0.15rem 0.35rem;
  font-size: 0.82rem; font-weight: 700; white-space: nowrap;
}
.seat .face { font-size: 1.1rem; }
.seat[data-turn="1"] { background: var(--accent); color: var(--accent-ink); }
.seat[data-waiting="1"] { opacity: 0.6; border: 2px dashed #ffffff44; }
/* A ten-player table would otherwise stretch its card twice as tall as the rest. */
.seat.more { background: none; opacity: 0.7; font-weight: 800; }

.room-status { font-size: 0.88rem; font-weight: 700; opacity: 0.85; line-height: 1.35; }
.room-status .live { color: var(--accent); }
.room-cta {
  margin-top: auto; width: 100%; min-height: 3rem; font-weight: 900; font-size: 1rem;
  background: var(--accent); color: var(--accent-ink); border-radius: 12px;
}
.room-cta.secondary { background: #ffffff1f; color: var(--ink-invert); border: 2px solid #ffffff33; }
.room-cta:disabled { background: #ffffff14; color: var(--ink-invert); border: 2px solid #ffffff22; }
.new-table { background: var(--panel); color: var(--ink); margin-top: 1rem; }
.empty-note {
  text-align: center; opacity: 0.8; padding: 2rem 1rem; line-height: 1.6;
  border: 3px dashed #ffffff2e; border-radius: var(--radius);
}

/* ---------- Lobby ---------- */
.lobby-players { list-style: none; padding: 0; max-width: 30rem; margin: 1rem auto; }
.lobby-players li {
  display: flex; align-items: center; gap: 0.8rem; font-size: 1.3rem;
  background: var(--bg-panel); border: 2px solid #ffffff2e; border-radius: 14px;
  padding: 0.55rem 0.9rem; margin: 0.45rem 0;
}
.lobby-players .avatar { font-size: 1.8rem; }

/* ---------- The game: a table, and a drawer ----------
   The table fills the screen — everyone seated in play order, the piles on the
   felt in the middle, the wheel taking their place when somebody spins. Your
   own cards are a drawer along the bottom edge, whose handle carries the order
   of play so the sequence is readable without opening anything. */
#screen-game { max-width: none; padding: 0; display: flex; flex-direction: column; min-height: 0; overflow: hidden; }
.table-stage { flex: 1; min-height: 0; position: relative; overflow: hidden; --peek: 4.8rem; --pile-cw: 5.4rem; }

.ring-wrap {
  position: absolute; inset: 0; display: grid; place-items: center;
  padding: 0.7rem 0.7rem calc(var(--peek) + 0.5rem);
}
.ring { position: relative; width: min(100%, 44rem); aspect-ratio: 1.06; max-height: 100%; }
.ring .arcs { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; pointer-events: none; }
/* Scoped to the arcs themselves. A bare `.arcs path` also matches the paths
   inside <marker>, and `fill: none` there makes the arrowheads disappear. */
.ring .arcs > path,
.ring .arcs > .dim-arcs > path { fill: none; stroke: #fff; stroke-width: 2.5; }
/* Faded as a group, so an arrowhead lying on its own arc does not double up. */
.ring .arcs .dim-arcs { opacity: 0.22; }
.ring .arcs > path.hot { stroke: var(--accent); stroke-width: 4; }

.felt {
  position: absolute; inset: 26%; border-radius: 50%;
  background: radial-gradient(circle at 50% 32%, #2f6350, #1a3a2d 72%);
  border: 3px solid #ffffff1f; box-shadow: inset 0 8px 30px #0007;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 0.45rem;
  padding: 0.6rem; text-align: center;
}
.felt-status { font-weight: 900; font-size: 0.95rem; line-height: 1.25; }
.felt-status.landed {
  background: var(--accent); color: var(--accent-ink);
  border-radius: 10px; padding: 0.2rem 0.6rem; font-size: 1.05rem;
}
/* A reversal is the move people kept missing, so it is the loudest thing the
   felt ever says while the ring is busy turning itself around underneath it. */
.felt-status.turnaround {
  background: var(--accent); color: var(--accent-ink);
  border-radius: 12px; padding: 0.3rem 0.8rem; font-size: 1.35rem;
  animation: wildpop 0.4s ease-out;
}
.ring.reversing .arcs { filter: drop-shadow(0 0 6px #ff9f1ccc); }
.felt-status.wild {
  background: linear-gradient(90deg, var(--red), var(--yellow), var(--green), var(--blue), var(--red));
  background-size: 300% 100%; color: #fff; -webkit-text-stroke: 1px #0006;
  animation: wildrun 0.9s linear infinite, wildpop 0.45s ease-out;
}
.felt-sub { font-size: 0.76rem; opacity: 0.82; font-weight: 700; line-height: 1.3; }
.felt-piles { display: flex; gap: 0.9rem; align-items: flex-start; }
.felt .pile-slot { position: relative; }
.felt .card { width: var(--pile-cw); height: calc(var(--pile-cw) * 1.5); }
.felt .pile-label { font-size: 0.68rem; font-weight: 800; opacity: 0.85; margin-top: 0.2rem; }
/* The draw pile is a card, not a button — without this it inherits the global
   button padding and min-height and balloons. */
.draw-pile-btn { background: none; padding: 0; border-radius: 14px; position: relative; min-height: 0; }
.draw-pile-btn:not(:disabled):hover .card { transform: translateY(-4px); }

/* Current color rides on the corner of the discard pile: it is a fact about
   that card, and it costs the felt no room of its own. */
.color-pip {
  position: absolute; right: -0.45rem; top: calc(var(--pile-cw) * 1.5 - 1.6rem);
  width: 2.1rem; height: 2.1rem; border-radius: 50%; border: 3px solid #fff;
  display: flex; align-items: center; justify-content: center; font-size: 1rem;
  box-shadow: var(--shadow); z-index: 2;
}
/* ---------- The color bloom ----------
   A wild asks the felt, because the felt is what carries the color in play.
   Overhangs by 2px on every side: at inset 0 it sits inside the felt's own
   border and leaves a hairline of table showing round the edge. */
.color-bloom {
  position: absolute; inset: -2px; border-radius: 50%; overflow: hidden;
  display: grid; grid-template-columns: 1fr 1fr; z-index: 8;
  animation: bloomin 0.35s cubic-bezier(0.2, 0.9, 0.2, 1);
}
@keyframes bloomin { from { transform: scale(0.4); opacity: 0; } to { transform: none; opacity: 1; } }
.color-bloom button {
  border: none; border-radius: 0; min-height: 0; padding: 0.3rem;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 0.1rem;
  color: #fff; font-weight: 900; text-shadow: 0 2px 4px #0007;
  box-shadow: inset 0 0 0 2px #ffffff33;
}
.color-bloom button:hover { filter: brightness(1.18); }
/* The middle of a quadrant is a long way out toward the rim, so a label centered
   in its cell reads as stuck to the edge. Padding the two outer sides pulls
   each one back in, and the four then read as one dial. */
.color-bloom button:nth-child(1) { padding: 1.7rem 0.3rem 0.3rem 1.7rem; }
.color-bloom button:nth-child(2) { padding: 1.7rem 1.7rem 0.3rem 0.3rem; }
.color-bloom button:nth-child(3) { padding: 0.3rem 0.3rem 1.7rem 1.7rem; }
.color-bloom button:nth-child(4) { padding: 0.3rem 1.7rem 1.7rem 0.3rem; }
.color-bloom .shape { font-size: 2.2rem; line-height: 1; }
.color-bloom .nm { font-size: 0.72rem; letter-spacing: 0.04em; }
.color-bloom .c-red { background: var(--red); }
.color-bloom .c-yellow { background: var(--yellow); }
.color-bloom .c-green { background: var(--green); }
.color-bloom .c-blue { background: var(--blue); }
.bloom-hub {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  background: #14281f; color: #fff; border: 3px solid #fff; border-radius: 999px;
  padding: 0.35rem 0.9rem; font-weight: 900; font-size: 0.8rem; letter-spacing: 0.03em;
  z-index: 2; pointer-events: none; white-space: nowrap; box-shadow: var(--shadow);
}
/* Kept off the felt, above the drawer's peek, so the four quarters stay whole. */
.bloom-cancel {
  position: absolute; left: 50%; transform: translateX(-50%);
  bottom: calc(var(--peek) + 0.7rem); z-index: 25;
  min-height: 2.8rem; padding: 0.3rem 1.1rem; font-weight: 800; font-size: 0.95rem;
  background: var(--panel); color: var(--ink); box-shadow: var(--shadow);
}
/* The felt takes the color it was just given — the payoff for asking here. */
.felt.washing::after {
  content: ''; position: absolute; inset: 0; border-radius: 50%;
  background: var(--wash); animation: wash 0.9s ease-out forwards; pointer-events: none;
}
@keyframes wash { from { opacity: 0.85; } to { opacity: 0; } }

.wheel-slot { position: relative; width: 13rem; max-width: 66%; }
.wheel-slot svg { display: block; width: 100%; height: auto; }

/* While the wheel is out there is nothing else to look at, so the table steps
   back and the wheel takes the whole ring instead of squeezing into the felt. */
.ring.spinning .arcs,
.ring.spinning .ring-seat { opacity: 0; pointer-events: none; }
.ring.spinning .arcs,
.ring.spinning .ring-seat,
.ring .felt { transition: opacity 0.35s ease, inset 0.35s ease; }
.ring.spinning .felt {
  inset: 4%; background: none; border-color: transparent; box-shadow: none;
}
.ring.spinning .wheel-slot { width: 84%; max-width: none; }
.ring.spinning .felt-status { font-size: 1.15rem; }

/* The hub is the button: it sits exactly where the wheel's own center is, so
   pressing the middle of the wheel is what spins it. */
.spin-hub {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  width: 21%; aspect-ratio: 1; min-height: 0; padding: 0; border-radius: 50%;
  background: #26251f; color: #fff; border: 3px solid #fff;
  font-weight: 900; font-size: 0.8rem; letter-spacing: 0.02em;
  box-shadow: 0 0 0 0 #ff9f1c88; animation: hubpulse 1.4s ease-out infinite;
  z-index: 3;
}
.spin-hub:not(:disabled):hover { background: var(--accent); color: var(--accent-ink); }
.spin-hub:disabled { animation: none; opacity: 0.6; }
@keyframes hubpulse {
  0% { box-shadow: 0 0 0 0 #ff9f1cbb; }
  70% { box-shadow: 0 0 0 1.2rem #ff9f1c00; }
  100% { box-shadow: 0 0 0 0 #ff9f1c00; }
}

/* UNO SPIN is raced on the wheel itself, so the hub you press to spin it is the
   one everybody slams. No countdown ring: the race waits to be claimed. */
.race-hub {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  width: 30%; aspect-ratio: 1; min-height: 0; padding: 0; border-radius: 50%;
  background: var(--red); color: #fff; border: 4px solid #fff;
  font-weight: 900; font-size: 0.9rem; line-height: 1.1; z-index: 4;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  animation: racepulse 0.9s ease-out infinite;
}
.race-hub:disabled { animation: none; opacity: 0.6; }
@keyframes racepulse {
  0% { box-shadow: 0 0 0 0 #ff5555cc; }
  70% { box-shadow: 0 0 0 2rem #ff555500; }
  100% { box-shadow: 0 0 0 0 #ff555500; }
}

/* SHOW HAND: fanned between their seat and the felt, and left there while they
   play, because playing on is the rest of the rule. */
.shown-fan {
  position: absolute; transform: translate(-50%, -50%);
  display: flex; z-index: 6; pointer-events: none;
}
.shown-fan .card { width: 2rem; height: 3rem; }
/* Set per fan by fanStep(): the more cards there are, the more they overlap, so
   a twenty-card hand stays the same width as a five-card one. */
.shown-fan .card + .card { margin-left: var(--fan-step, -1.3rem); }
.shown-fan .fan-label {
  position: absolute; left: 50%; top: -1.1rem; transform: translateX(-50%);
  background: #14281f; border: 2px solid #ffffff66; border-radius: 999px;
  padding: 0.05rem 0.45rem; font-size: 0.6rem; font-weight: 900; white-space: nowrap;
}

/* Seats sit on the ring. Tapping one waves; tapping somebody caught on one card
   without shouting UNO catches them, which is as close to reaching across the
   table as a screen gets. */
.ring-seat {
  position: absolute; width: 6.2rem; margin-left: -3.1rem; margin-top: -2.7rem;
  display: flex; flex-direction: column; align-items: center; gap: 0.05rem;
  background: #14281f; border: 3px solid #ffffff2e; border-radius: 14px;
  padding: 0.3rem 0.25rem; color: var(--ink-invert); font: inherit; text-align: center;
  min-height: 0;
  transition: transform 0.3s ease, border-color 0.3s, background 0.3s, box-shadow 0.3s;
}
.ring-seat .face { font-size: 1.6rem; line-height: 1; }
.ring-seat .nm { font-weight: 800; font-size: 0.76rem; max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ring-seat .cards { font-size: 0.7rem; opacity: 0.8; font-weight: 700; }
.ring-seat .localtime { font-size: 0.62rem; opacity: 0.6; font-weight: 700; }
.ring-seat .localtime:empty { display: none; }
.ring-seat .presence {
  position: absolute; top: 0.25rem; right: 0.3rem;
  width: 0.6rem; height: 0.6rem; border-radius: 50%; background: #ffffff33;
}
.ring-seat .presence.online { background: #3ddc84; }
.ring-seat.turn { border-color: var(--accent); background: #3a2f14; box-shadow: 0 0 0 4px #ff9f1c33; transform: scale(1.08); }
/* The light that runs round the ring when play turns around. */
.ring-seat.lit {
  border-color: #fff; background: var(--accent); color: var(--accent-ink);
  box-shadow: 0 0 0 8px #ff9f1c44; transform: scale(1.16);
}
.ring-seat.me { border-color: #ffffff88; }
.ring-seat.uno { border-color: var(--red); }
.ring-seat.away { opacity: 0.58; }
.ring-seat.catchable {
  border-color: var(--red); background: #4a1f1f;
  animation: catchpulse 1.1s ease-in-out infinite;
}
.ring-seat.catchable .cards { color: #ffd0d0; font-weight: 900; }
@keyframes catchpulse { 50% { box-shadow: 0 0 0 6px #ff555544; } }

/* Your own seat when you are down to one card and have not said it. You always
   sit at the bottom of the ring, so it grows UPWARDS out of the seat — the
   extra negative margin-top is what keeps it clear of the drawer's peek.
   There is no countdown on purpose: the catch window is not clocked. */
.ring-seat.shout {
  z-index: 12; width: 7.6rem; height: 7.6rem;
  margin-left: -3.8rem; margin-top: -5.6rem;
  border-radius: 50%; background: var(--red); border-color: #fff;
  justify-content: center; gap: 0.1rem; overflow: visible;
  animation: shoutpop 0.35s cubic-bezier(0.2, 1.4, 0.4, 1),
             shoutpulse 1.8s ease-out 0.35s infinite;
}
.ring-seat.shout .shout-word { font-size: 1.3rem; font-weight: 900; letter-spacing: 0.02em; }
.ring-seat.shout .shout-hint { font-size: 0.62rem; font-weight: 800; opacity: 0.85; }
@keyframes shoutpop { from { transform: scale(0.5); } to { transform: scale(1); } }
@keyframes shoutpulse {
  0% { box-shadow: 0 0 0 0 #ff5555bb; }
  70% { box-shadow: 0 0 0 1.2rem #ff555500; }
  100% { box-shadow: 0 0 0 0 #ff555500; }
}

.ring-token {
  position: absolute; width: 1.9rem; height: 2.8rem; margin-left: -0.95rem; margin-top: -1.4rem;
  border-radius: 5px; background: linear-gradient(150deg, #d43c3c, #a52929);
  border: 2px solid #fff; box-shadow: var(--shadow); z-index: 5;
  display: grid; place-items: center; font-size: 0.68rem; font-weight: 900; color: #fff;
}

.scrim {
  position: absolute; inset: 0; background: #0007; opacity: 0; pointer-events: none;
  transition: opacity 0.35s ease; z-index: 20;
}
.scrim.on { opacity: 1; pointer-events: auto; }

/* ---------- The drawer ----------
   Sized to the cards it holds, so a small hand is short and tidy and the table
   stays visible behind it; past the cap the hand scrolls instead. */
.drawer {
  position: absolute; left: 0; right: 0; bottom: 0;
  height: auto; max-height: min(62%, 30rem);
  background: linear-gradient(180deg, #21473a 0%, #16302a 100%);
  border-top: 3px solid #ffffff33; border-radius: 20px 20px 0 0;
  box-shadow: 0 -14px 40px #0008;
  display: flex; flex-direction: column;
  transform: translateY(calc(100% - var(--peek)));
  transition: transform 0.38s cubic-bezier(0.2, 0.85, 0.25, 1);
  z-index: 30; touch-action: none;
}
.drawer.open { transform: translateY(0); }
.drawer.dragging { transition: none; }
.drawer.mine { border-top-color: var(--accent); }

.handle {
  flex: none; cursor: grab; user-select: none; padding: 0.3rem 0.7rem 0.45rem;
  display: flex; flex-direction: column; gap: 0.25rem; min-height: var(--peek);
}
.grip { width: 3.2rem; height: 0.3rem; border-radius: 999px; background: #ffffff55; margin: 0.1rem auto 0.15rem; }
.handle-row { display: flex; align-items: center; gap: 0.6rem; }
.handle-label { font-weight: 900; font-size: 0.95rem; white-space: nowrap; }
.handle-label .hint2 { font-weight: 700; opacity: 0.55; font-size: 0.8rem; margin-left: 0.35rem; }
.drawer.mine .handle-label { color: var(--accent); }

.order-strip { display: flex; align-items: center; gap: 0.22rem; overflow-x: auto; margin-left: auto; }
.order-strip::-webkit-scrollbar { height: 0; }
.order-strip .who {
  display: inline-flex; align-items: center; gap: 0.22rem; white-space: nowrap;
  background: #ffffff14; border-radius: 999px; padding: 0.12rem 0.5rem 0.12rem 0.28rem;
  font-weight: 800; font-size: 0.78rem;
}
.order-strip .who.turn { background: var(--accent); color: var(--accent-ink); }
.order-strip .who .face { font-size: 1rem; }
.order-strip .arrow { opacity: 0.45; font-weight: 900; font-size: 0.8rem; }

.drawer-body { flex: 0 1 auto; min-height: 0; display: flex; flex-direction: column; gap: 0.5rem; padding: 0 0.8rem 0.8rem; }
/* The scrolling box clips anything drawn outside a card, so the playable ring
   needs its own room inside the padding. */
.hand-scroll {
  flex: 0 1 auto; min-height: 0; overflow-y: auto;
  display: flex; flex-wrap: wrap; gap: 0.5rem; align-content: flex-start;
  padding: 5px; margin: -5px -5px 0;
}
.hand-card { background: none; padding: 0; border-radius: 12px; min-height: 0; }
.hand-card .card { width: var(--hand-cw, 5.4rem); height: calc(var(--hand-cw, 5.4rem) * 1.5); transition: transform 0.15s ease; }
.hand-card.playable .card { outline: 3px solid var(--accent); outline-offset: 2px; border-radius: 8px; }
.hand-card.unplayable { opacity: 0.42; cursor: default; }
.hand-card.just-drawn .card { outline: 3px dashed #fff; outline-offset: 2px; }
.hand-card:not(:disabled):hover .card { transform: translateY(-6px); }

/* ---------- The drawer, asked a question ----------
   Three of the wheel's spaces are about your own cards, so they are answered
   here. The hand sorts itself into piles and you tap the one you want rid of;
   the count is never written down, because the cards are lying there. */
.hand-group {
  display: flex; flex-direction: column; align-items: center; gap: 0.3rem;
  background: #00000033; border: 3px solid #ffffff26; border-radius: 16px;
  padding: 0.45rem 0.5rem 0.55rem; min-height: 0;
  /* Buttons do not inherit color, and this drawer is dark. */
  color: var(--ink-invert);
  transition: transform 0.18s ease, border-color 0.18s, background 0.18s;
}
button.hand-group:hover, button.hand-group:focus-visible {
  border-color: var(--accent); background: #ff9f1c22; transform: translateY(-4px);
}
/* The cards the question cannot touch: a Wild when it asks for a number, a
   Skip when it asks for a color. Not on offer — but still yours, and still
   lying in the drawer, rather than disappearing while you are being asked
   about the hand they are part of. */
.hand-group.stays { border-style: dashed; opacity: 0.55; }
.hand-group.stays .group-head { font-weight: 800; opacity: 0.85; }
.hand-group.stays .card { filter: grayscale(0.45); }
.hand-group .group-head { font-weight: 900; font-size: 0.85rem; letter-spacing: 0.03em; }
.hand-group .group-cards { display: flex; }
/* Overlapped like a real pile, so a big group stays the size of a target —
   but not so far that you cannot count them, which is the point. */
.hand-group .group-cards .card { width: 3.4rem; height: 5.1rem; }
.hand-group .group-cards .card + .card { margin-left: -1.5rem; }

/* ALMOST UNO: the two you keep rise out of the drawer, so kept-versus-doomed
   is physical position rather than a pressed state somebody has to squint at. */
.keep-shelf {
  flex: none; display: flex; gap: 0.5rem; align-items: center; justify-content: center;
  min-height: 6.2rem; border-bottom: 3px dashed #ffffff33; margin-bottom: 0.4rem;
  padding: 0.2rem 0 0.5rem;
}
.keep-shelf .shelf-hint { font-weight: 800; font-size: 0.85rem; opacity: 0.6; }
.shelf-go { display: flex; flex-direction: column; align-items: flex-start; gap: 0.25rem; margin-left: 0.6rem; }
.shelf-go .act {
  min-height: 3rem; padding: 0.4rem 1rem; font-weight: 900; font-size: 1rem;
  background: var(--red); color: #fff; border-radius: 12px;
}
.hand-card.kept .card { outline: 3px solid #3ddc84; outline-offset: 2px; border-radius: 8px; }
.hand-card.doomed { opacity: 0.4; }
.hand-card.doomed .card { filter: grayscale(0.6); }

.drawer-foot { flex: none; display: flex; gap: 0.4rem; align-items: center; flex-wrap: wrap; }
.drawer-foot .act {
  min-height: 2.7rem; padding: 0.3rem 0.9rem; font-weight: 900; font-size: 0.92rem;
  background: var(--panel); color: var(--ink); border-radius: 10px;
}
.drawer-foot .act.primary { background: var(--accent); color: var(--accent-ink); }
.drawer-foot .act.danger { background: var(--red); color: #fff; }
.drawer-foot .score { font-weight: 900; opacity: 0.85; }
.drawer-foot .reacts { margin-left: auto; display: flex; gap: 0.2rem; }
.drawer-foot .reacts button {
  min-height: 2.5rem; min-width: 2.5rem; padding: 0; font-size: 1.15rem;
  background: #ffffff14; border-radius: 10px;
}
/* Granny's own button. It is not a reaction and should not look like one. */
.drawer-foot .reacts .granny { background: #ffffff26; border: 2px solid #ffffff3a; }


/* ---------- Reactions ---------- */
.reactions-bar { display: flex; flex-wrap: wrap; gap: 0.35rem; flex: none; }
.reactions-bar button {
  font-size: 1.2rem; min-width: 2.4rem; min-height: 2.4rem; padding: 0.15rem;
  background: #ffffff22; border: 2px solid #ffffff44; border-radius: 10px;
}
.reactions-bar button:hover { background: #ffffff3a; }

/* Card flights — clones animating between table positions */
#flight-layer { position: fixed; inset: 0; pointer-events: none; overflow: hidden; z-index: 70; }
.card.flight { position: fixed; margin: 0; }

/* Discard pile rendered as a small stack; each card keeps a fixed tilt */
.discard-stack { position: relative; width: var(--pile-cw); height: calc(var(--pile-cw) * 1.5); }
.discard-stack .card { position: absolute; inset: 0; transform: rotate(var(--rot, 0deg)); }

/* Floating emoji */
#float-layer { position: fixed; inset: 0; pointer-events: none; overflow: hidden; z-index: 60; }
.floater {
  position: absolute; bottom: -3rem; font-size: 3rem;
  animation: floatUp 3.4s ease-out forwards;
}
.floater .who {
  display: block; font-size: 0.85rem; font-weight: 800; text-align: center;
  color: #fff; text-shadow: 0 1px 3px #000;
}
@keyframes floatUp {
  0% { transform: translateY(0) scale(0.8); opacity: 0; }
  10% { opacity: 1; }
  100% { transform: translateY(-85vh) scale(1.25); opacity: 0; }
}

/* ---------- Overlay ---------- */
.overlay {
  position: fixed; inset: 0; background: #000000b8; z-index: 50;
  display: flex; align-items: center; justify-content: center; padding: 1rem;
  overflow-y: auto;
}
.overlay-card {
  background: var(--panel); color: var(--ink); border-radius: 22px;
  padding: 1.4rem; max-width: 36rem; width: 100%; box-shadow: var(--shadow);
  text-align: center; max-height: 92vh; overflow-y: auto;
}
.overlay-card h2 { font-size: 1.7rem; margin: 0 0 0.6rem; }
.overlay-card .cards-row { display: flex; flex-wrap: wrap; gap: 0.5rem; justify-content: center; margin: 0.8rem 0; }
.overlay-card .cards-row .card { width: 5.2rem; height: 7.8rem; }
.overlay-card .cards-row button.pick { background: none; border: none; padding: 0; border-radius: 14px; }
.overlay-card .cards-row button.pick[aria-pressed="true"] .card {
  box-shadow: 0 0 0 5px var(--blue); border-radius: 10%/6.6%; transform: translateY(-6px);
}

.color-choices { display: grid; grid-template-columns: 1fr 1fr; gap: 0.7rem; margin-top: 0.8rem; }
.color-choices button {
  font-size: 1.35rem; font-weight: 900; min-height: 4.6rem; color: #fff; border: 4px solid #fff;
}
.color-choices .c-red { background: var(--red); }
.color-choices .c-yellow { background: var(--yellow); color: #241a00; }
.color-choices .c-green { background: var(--green); }
.color-choices .c-blue { background: var(--blue); }


/* ---------- The wheel ----------
   Sizing lives with the table above, since the wheel is part of the felt. */
.wheel-slot #wheel-svg { width: 100%; height: auto; }
.wheel-pointer {
  position: absolute; top: -0.9rem; left: 50%; transform: translateX(-50%);
  font-size: 1.7rem; z-index: 2; filter: drop-shadow(0 2px 2px #0008);
}
#wheel-svg { width: 100%; height: auto; display: block; transition: transform 4s cubic-bezier(0.12, 0.6, 0.08, 1); }
.spin-result {
  font-size: 1.9rem; font-weight: 900; margin: 0.6rem 0; min-height: 2.4rem; color: var(--accent-ink);
  background: var(--accent); border-radius: 14px; padding: 0.4rem 0.6rem;
}
/* UNO SPIN is the wildest space on the wheel and should look it. */
.spin-result.wild {
  background: linear-gradient(90deg, var(--red), var(--yellow), var(--green), var(--blue), var(--red));
  background-size: 300% 100%; color: #fff; -webkit-text-stroke: 1px #0006;
  animation: wildrun 0.9s linear infinite, wildpop 0.45s ease-out;
}
@keyframes wildrun { to { background-position: 300% 0; } }
@keyframes wildpop { from { transform: scale(0.6); } to { transform: scale(1); } }

/* ---------- Seating, set between rounds ----------
   The ring above the list is the table itself: you at the bottom, play running
   round it the way the arrow points. Without it a family had a list with two
   ends and a table with none, and arranged themselves backwards. */
.seating { margin: 0.6rem auto; max-width: 30rem; }
.mini-ring {
  position: relative; width: min(100%, 19rem); aspect-ratio: 1; margin: 0 auto 0.8rem;
  border: 3px dashed #ffffff2e; border-radius: 50%;
}
.mini-hub {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  display: flex; flex-direction: column; align-items: center; gap: 0.1rem;
  color: var(--ink-invert); text-align: center;
}
.mini-hub .turn-arrow { font-size: 2.2rem; line-height: 1; color: var(--accent); }
.mini-hub small { font-size: 0.62rem; font-weight: 800; opacity: 0.7; }
.mini-seat {
  position: absolute; transform: translate(-50%, -50%); width: 4.3rem;
  display: flex; flex-direction: column; align-items: center; gap: 0.05rem;
  background: #14281f; border: 3px solid #ffffff2e; border-radius: 12px;
  padding: 0.2rem 0.15rem; text-align: center;
  transition: left 0.35s cubic-bezier(0.2, 0.9, 0.2, 1), top 0.35s cubic-bezier(0.2, 0.9, 0.2, 1);
}
.mini-seat.me { border-color: var(--accent); background: #3a2f14; }
.mini-seat .face { font-size: 1.4rem; line-height: 1; }
.mini-seat .nm { font-size: 0.62rem; font-weight: 800; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mini-seat .pos {
  position: absolute; top: -0.55rem; left: -0.45rem;
  width: 1.35rem; height: 1.35rem; border-radius: 50%;
  background: var(--accent); color: var(--accent-ink);
  font-size: 0.72rem; font-weight: 900; display: grid; place-items: center;
}
/* Inside the round-end card the panel is light, so the ring has to be too. */
.overlay-card .mini-ring { border-color: #00000026; }
.overlay-card .mini-hub { color: var(--ink); }
.overlay-card .mini-seat { background: #fff; border-color: #00000026; color: var(--ink); }
.overlay-card .mini-seat.me { background: #fff3d6; border-color: var(--accent); }

.seat-editor { list-style: none; padding: 0; margin: 0.6rem auto; max-width: 30rem; }
.seat-editor li[data-mine="1"] { border-color: var(--accent); }
.seat-editor li {
  display: flex; align-items: center; gap: 0.6rem; margin: 0.35rem 0;
  background: var(--bg-panel); border: 2px solid #ffffff2e; border-radius: 14px;
  padding: 0.45rem 0.6rem;
}
.seat-editor .pos {
  width: 1.9rem; height: 1.9rem; border-radius: 50%; flex: none;
  background: #ffffff1f; border: 2px solid #ffffff44;
  font-weight: 900; font-size: 0.85rem; display: grid; place-items: center;
}
.seat-editor .face { font-size: 1.6rem; }
.seat-editor .nm { flex: 1; font-weight: 800; text-align: left; min-width: 0; }
.seat-editor .move {
  min-height: 2.6rem; min-width: 2.9rem; font-size: 1.2rem; font-weight: 900;
  background: var(--panel); color: var(--ink); border-radius: 10px;
}
.seat-editor .move:disabled { opacity: 0.3; }

/* ---------- War, fought on the ring ----------
   Each seat lays its cards down between itself and the felt. A seat knocked
   out keeps its cards on the table and dims, so you can see who you beat. */
.war-hold {
  position: absolute; transform: translate(-50%, -50%);
  display: flex; gap: 0.14rem; z-index: 6; pointer-events: none;
  transition: opacity 0.45s ease, filter 0.45s ease;
}
.war-hold .card {
  width: 2.5rem; height: 3.75rem;
  animation: warlay 0.42s cubic-bezier(0.2, 0.9, 0.2, 1);
}
.war-hold.out { opacity: 0.32; filter: grayscale(0.7); }
@keyframes warlay {
  from { transform: translateY(-1.2rem) rotateX(85deg); opacity: 0; }
  to { transform: none; opacity: 1; }
}
.ring-seat.out { opacity: 0.45; transform: scale(0.92); }
.ring-seat.won {
  border-color: var(--accent); background: #3a2f14;
  box-shadow: 0 0 0 6px #ff9f1c55; transform: scale(1.14);
}

@media (prefers-reduced-motion: reduce) {
  .spin-result.wild { animation: none; }
  .spin-hub { animation: none; }
  .ring.spinning .arcs, .ring.spinning .ring-seat, .ring .felt { transition: none; }
  .war-hold .card { animation: none; }
  .war-hold { transition: none; }
  .ring-seat.catchable { animation: none; }
  .ring-seat.shout { animation: none; }
  .color-bloom { animation: none; }
  .felt.washing::after { animation: none; opacity: 0; }
  .ring-seat { transition: none; }
}
.scores-table { width: 100%; border-collapse: collapse; font-size: 1.15rem; margin: 0.8rem 0; }
.scores-table th, .scores-table td { padding: 0.45rem 0.6rem; border-bottom: 2px solid #ddd; text-align: left; }
.scores-table .winner-row { background: #fff3d6; font-weight: 800; }

#toast {
  position: fixed; bottom: 1.2rem; left: 50%; transform: translateX(-50%);
  background: var(--red); color: #fff; font-weight: 800; font-size: 1.1rem;
  padding: 0.8rem 1.3rem; border-radius: 14px; z-index: 80; box-shadow: var(--shadow);
  max-width: min(92vw, 30rem); text-align: center;
}
/* Not everything worth saying is bad news — good news shouldn't arrive in red. */
#toast[data-kind="good"] { background: var(--accent); color: var(--accent-ink); }

.help-list { text-align: left; font-size: 1.02rem; line-height: 1.5; }
.help-list dt { font-weight: 800; margin-top: 0.7rem; }
.help-list dd { margin-left: 0; }

@media (prefers-reduced-motion: reduce) {
  .floater { animation-duration: 0.01s; }
  .race-hub { animation: none; }
  #wheel-svg { transition-duration: 0.5s; }
  .hand-card .card { transition: none; }
}

/* ---------- Wide and short: the drawer stops being a drawer ----------
   On a phone turned sideways, on a laptop, on a tablet in landscape, a sheet
   along the bottom edge covers the very thing it is played on: the table gets
   cut in half, and every move out on the felt costs two presses — one to get
   the cards out of the way and one to make the move.
   So when the window is wider than it is tall, the cards stand beside the table
   instead of over it. Always open, nothing to pull, and the ring keeps the rest
   of the window to itself. */
@media (min-aspect-ratio: 5/4) and (min-width: 620px) {
  .table-stage { --peek: 0.6rem; --dock: min(38%, 22rem); }
  .ring-wrap { padding: 0.5rem calc(var(--dock) + 0.6rem) 0.5rem 0.6rem; }
  .drawer {
    top: 0; bottom: 0; left: auto; right: 0; width: var(--dock);
    max-height: none;
    /* Docked, it is furniture: it never slides, so it never has to be put back
       either — setDrawer(false) has nothing to hide. */
    transform: none !important; transition: none;
    border-top: none; border-left: 3px solid #ffffff33;
    border-radius: 20px 0 0 20px;
    box-shadow: -14px 0 40px #0008;
    touch-action: auto;
  }
  .drawer.mine { border-top-color: transparent; border-left-color: var(--accent); }
  .handle { cursor: default; min-height: 0; padding: 0.55rem 0.7rem 0.3rem; }
  .grip { display: none; }
  .handle-row { flex-wrap: wrap; gap: 0.3rem 0.6rem; }
  .order-strip { margin-left: 0; width: 100%; }
  .drawer-body { flex: 1 1 auto; }
  .hand-scroll { flex: 1 1 auto; }
  /* Nothing to dismiss means nothing to dim. */
  .scrim { display: none; }
  /* Centered over the table it belongs to, not over the whole window. */
  .bloom-cancel { bottom: 0.8rem; left: calc((100% - var(--dock)) / 2); }
}

/* Narrow windows and phones. The table needs no rearranging — the ring shrinks
   to fit and the drawer already caps itself — only a little more breathing room
   and a taller handle for thumbs. */
@media (max-width: 860px) {
  .table-stage { --peek: 5.2rem; }
  .ring-wrap { padding: 0.4rem 0.4rem calc(var(--peek) + 0.4rem); }
  .handle-label { font-size: 0.88rem; }
}

@media (max-width: 640px) {
  :root { font-size: 18px; }
  html[data-textsize="2"] { font-size: 21px; }
  html[data-textsize="3"] { font-size: 25px; }
  .ring-seat { width: 5rem; margin-left: -2.5rem; margin-top: -2.3rem; }
  .ring-seat .face { font-size: 1.35rem; }
  .table-stage { --pile-cw: 4.2rem; }
}
