/* The room every table game is played in: structure only. Every color,
   font and edge comes from the tokens a game declares in its own root
   (docs/design-system.md, "The room kit"); the only colors written here
   are black and white shadows and scrims. The card room adds its cards,
   piles and hand in games/static/games/cards/cards.css; a game adds its
   own board in its own stylesheet. */

* { box-sizing: border-box; }
html, body { margin: 0; }
body {
  background: var(--room);
  color: var(--ink);
  font: var(--t-body)/var(--lh-body) var(--ui-font);
  font-variant-numeric: lining-nums;
  -webkit-font-smoothing: antialiased;
  min-height: 100dvh;
}
button, input, select { font: inherit; color: inherit; }
a { color: inherit; }
[hidden] { display: none !important; }
.soft { color: var(--soft); }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
/* (a key cap's letter in its middle in any face: trimmed to the cap height and baseline, padded evenly; house.css, "fine details") */
kbd { font: 700 12px/1 var(--ui-font); padding: 3.5px 5px; border-radius: 4px; border: 1px solid currentColor; margin-left: 2px; text-box: trim-both cap alphabetic; }
h1, h2, h3 { margin: 0; }

/* ── buttons and fields ─────────────────────────────────────────────── */
/* guide:start buttons */
.btn {
  appearance: none; cursor: pointer; display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  background: var(--btn); color: var(--btn-ink); border: var(--btn-edge); border-radius: var(--btn-radius);
  font-weight: var(--btn-weight); padding: 8px var(--btn-pad); min-height: var(--btn-h); line-height: 1.1; text-decoration: none;
  transition: transform .08s;
}
.btn:active { transform: translateY(1px); }
/* Three weights (docs/design-system.md, house rule 2): the one primary is
   filled, a secondary is outlined, a quiet one is underlined words. Danger
   is a secondary in the bad color. */
.btn.alt { background: var(--btn2); color: var(--btn2-ink); border: var(--btn2-edge); }
.btn.danger { background: var(--btn2); color: var(--bad); border: var(--btn2-edge); border-color: var(--bad); }
.btn.quiet { background: transparent; color: var(--ink); border: 0; padding: 6px 10px; min-height: 36px; text-decoration: underline; text-underline-offset: 4px; }
.btn.quiet:hover { text-decoration-thickness: 2px; }
.btn.small { min-height: var(--tool-h); padding: 4px 12px; font-size: var(--t-small); }
.btn.wide { width: 100%; }
.btn.unseen { visibility: hidden; }
/* Disabled reads as "not yet", not as faded-out color that melts into the felt. */
.btn[disabled] { background: transparent; color: var(--soft); border: 2px dashed color-mix(in srgb, var(--soft) 70%, transparent); cursor: default; transform: none; }
/* guide:end buttons */
.btn.slot.hide { visibility: hidden; }
/* a slot asking "…anyway?" before it does something you may regret
   (kit/slots.js confirm): the theme's warning color, same size */
.btn.slot.confirm, .btn.slot.confirm.alt {
  background: var(--confirm, var(--bad)); color: var(--confirm-ink); border-color: var(--confirm, var(--bad));
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--confirm, var(--bad)) 35%, transparent);
}
/* a slot working on it: a sheen passes over it; nothing about it changes size */
.btn.slot.busy { cursor: progress; background-image: linear-gradient(100deg, transparent 30%, color-mix(in srgb, currentColor 22%, transparent) 50%, transparent 70%); background-size: 250% 100%; animation: busy 1s linear infinite; }
@keyframes busy { from { background-position: 100% 0; } to { background-position: -150% 0; } }
@media (prefers-reduced-motion: reduce) { .btn.slot.busy { animation: none; opacity: .7; } }
/* One focus style everywhere, distinct from the yellow that means "picked". */
:is(.btn, .seg button, .recent a, .lognew, .acct a, a.acct, .linkish, a.kept, input, select):focus-visible {
  outline: 2px solid var(--focus, var(--ink)); outline-offset: 3px; box-shadow: 0 0 0 5px var(--room);
}
.field { display: flex; flex-direction: column; gap: var(--s2); }
.field > label, label.field { font-size: var(--t-label); font-weight: 600; color: var(--ink); }
::placeholder { color: var(--soft); opacity: 1; }
.field input, .field select, .input {
  background: var(--panel); border: var(--field-edge); border-radius: var(--btn-radius); color: var(--ink);
  padding: 8px 12px; min-height: 44px; font-size: var(--t-body);
}
.input.code { text-transform: uppercase; letter-spacing: .2em; font-weight: 800; width: 100%; }

/* ── the felt: the table everything sits on ────────────────────────── */
/* The page's skeleton (docs/design-language.md, "Layout and type"): the
   felt sits in a frame, and its words start at the gutter (plus the table
   style's rail); the bar is --bar-h tall at --bar-top. A table game's play
   screen keeps the same gutter, bar and frame as its lobby. */
#app { padding: var(--frame); }
.felt {
  background: var(--table); border: var(--rail); border-radius: var(--rail-radius);
  padding: var(--bar-top) max(calc(var(--gutter) - var(--frame)), env(safe-area-inset-right, 0px)) max(var(--bar-top), env(safe-area-inset-bottom, 0px)) max(calc(var(--gutter) - var(--frame)), env(safe-area-inset-left, 0px)); min-height: calc(100dvh - 2 * var(--frame));
  display: flex; flex-direction: column; gap: 10px;
}
.bar { display: flex; align-items: center; justify-content: space-between; gap: 10px; min-height: var(--bar-h); flex: none; }
.bar .title { font-family: var(--display); font-weight: var(--display-weight); font-size: var(--t-bar); line-height: var(--lh-heading); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.bar .titlerow { flex-wrap: nowrap; min-width: 0; }
.bar .tools { display: flex; gap: var(--s1); flex-wrap: wrap; }
/* The room's own bar (front door, waiting room, watching) keeps to one
   line down to 320px: on the narrowest phones Options is a gear. */
.bar > .roomtools { flex: none; flex-wrap: nowrap; }
.roomtools .btn { white-space: nowrap; }
.optbtn .short, .howbtn .short { display: none; }
@media (max-width: 400px) {
  .optbtn .long { display: none; }
  .optbtn .short { display: inline; font-size: 18px; line-height: 1; }
}
/* (and with the talk's two buttons beside them, How to play is a "?") */
@media (max-width: 360px) {
  .bar:has(> .talk .chatbtn:not([hidden])) .howbtn .long { display: none; }
  .bar:has(> .talk .chatbtn:not([hidden])) .howbtn .short { display: inline; font-size: 18px; line-height: 1; }
}
/* the top bar's tools are quiet: words, so the moves are what stands out;
   every one the same size in every game (--t-tool, --tool-h, --tool-pad) */
.bar .btn.quiet { font-size: var(--t-tool); font-weight: var(--w-tool); padding: 4px var(--tool-pad); min-height: var(--tool-h); }
.bar .btn.stop { min-width: 7.6em; }
.bar .more { display: none; }
/* (the top bar's way up is the house kit's arrow, house.css) */

/* ── seats round the table ──────────────────────────────────────────── */
.seats { display: flex; gap: 8px; flex-wrap: wrap; list-style: none; margin: 0; padding: 0; }
.seat {
  display: flex; align-items: center; gap: 8px; padding: 4px 12px 4px 4px; border-radius: var(--chip-radius);
  background: var(--chip); border: var(--chip-edge); min-height: 44px; position: relative;
}
.seat .face { width: 32px; height: 32px; border-radius: 50%; display: grid; place-items: center; font: 800 12px var(--ui-font); color: var(--seat-ink); flex: none; letter-spacing: -.02em; }
.seat .who { font-size: 13px; line-height: 1.25; display: flex; flex-direction: column; }
.seat .who b { font-weight: 700; }
:is(.seat, .tile) .count { color: var(--soft); }
:is(.seat, .tile) .count.low { color: var(--ink); font-weight: 800; }
/* (yellow is only ever whose turn it is) */
:is(.seat, .tile) .count.low::before { content: '● '; color: var(--bad); }
.seat .tags { display: flex; gap: 4px; flex-wrap: wrap; }
.tag { font: 700 12px/1 var(--ui-font); letter-spacing: .04em; text-transform: uppercase; padding: 4px 6px; border-radius: var(--chip-radius); background: var(--panel); border: 1px solid currentColor; }
.tag.hot { background: var(--turn); color: var(--turn-ink); border-color: var(--turn); }
.seat.turn { outline: 3px solid var(--turn); outline-offset: 2px; }
.seat.away { opacity: .7; }

/* ── seat tiles (kit/seats.js) ──────────────────────────────────────── */
/* One per player. Their size comes from the number of players and the
   window (--cols, --tile-h, set by the game), never from what's in them. */
.tiles { display: grid; grid-template-columns: repeat(var(--cols, 2), minmax(0, 1fr)); grid-auto-rows: var(--tile-h, auto); gap: 10px; }
/* A table ring (kit/seats.js ringSeats): the middle of the table in its
   own cell, and, up to five players, its column only as wide as that. */
.tiles.narrowmid { grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); }
.tiles > .middle { display: grid; place-items: center; min-width: 0; min-height: 0; }
.tile {
  position: relative; min-width: 0; min-height: 0; display: flex; flex-direction: column; gap: 4px;
  padding: 4px 9px 6px; border-radius: 12px; background: var(--panel); border: var(--panel-edge);
}
.tile.turn { outline: 3px solid var(--turn); outline-offset: 2px; }
.tilehead { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: 8px; height: 24px; }
.tilehead .face { position: relative; width: 22px; height: 22px; border-radius: 50%; display: grid; place-items: center; font: 800 11px var(--ui-font); color: var(--seat-ink); letter-spacing: -.02em; }
/* A seat's mark (kit/identity.js) is its face: its own shape in its color,
   not a disc behind the initial. */
.seatlist .seat .face.marked, .seat .face.marked, .tilehead .face.marked { background: none; }
.face > .seatmark { display: block; width: 100%; height: 100%; overflow: visible; }
/* one line: the name gives way (…) before what follows it */
.tilehead .who { min-width: 0; display: flex; align-items: baseline; gap: 8px; font-size: 14px; line-height: 1.25; }
.tilehead .who > * { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; flex: none; }
.tilehead .who > :first-child { flex: 0 1 auto; min-width: 0; }
.tilehead .who > :nth-child(2) { flex: 0 100 auto; min-width: 4em; }
/* the badge spot keeps its width (the game sets it) whether or not it shows anything */
.tilehead .badgeslot { display: flex; justify-content: flex-end; align-items: center; }
.tilebody { flex: 1; min-height: 0; min-width: 0; position: relative; }
/* A note on the tile's top edge ("Just went down"), in the seat's color: it
   takes no space, and the tile takes a tint of the same color (an inset
   line, never the turn ring). */
.tile .ribbon {
  position: absolute; top: 0; right: 12px; transform: translateY(-62%); z-index: 2; pointer-events: none;
  white-space: nowrap; padding: 2px 10px; border-radius: 99px; font: 800 12px/1.25 var(--ui-font); letter-spacing: .03em;
  background: var(--seat); color: var(--seat-ink); box-shadow: 0 2px 8px rgba(0, 0, 0, .35);
}
.tile.ribboned { box-shadow: inset 0 0 0 2px var(--seat); background: color-mix(in srgb, var(--seat) 12%, var(--panel)); }
/* Short tiles: the header in a column beside the body. */
.tiles.dense .tile { flex-direction: row; gap: 8px; }
.tiles.dense .tilehead { width: 100px; height: auto; flex: none; grid-template-columns: auto minmax(0, 1fr); align-items: start; align-content: start; row-gap: 6px; }
.tiles.dense .tilehead .who { flex-direction: column; align-items: stretch; gap: 0; }
.tiles.dense .tilehead .badgeslot { grid-column: 1 / -1; }
.tiles.headonly .tilebody { display: none; }
/* The seat's status, in its reserved spot: the same size whatever it says. */
:is(.seat, .tile) .badge { justify-self: end; min-width: 64px; text-align: center; font: 800 12px/1 var(--ui-font); letter-spacing: .04em; text-transform: uppercase; padding: 4px 6px; border-radius: var(--chip-radius); border: 1px solid currentColor; }
:is(.seat, .tile) .badge.none { visibility: hidden; }
:is(.seat, .tile) .badge.hot { background: var(--turn); color: var(--turn-ink); border-color: var(--turn); }
:is(.seat, .tile) .badge.quiet { color: var(--soft); }
:is(.seat, .tile) button.badge { min-height: 26px; text-decoration: none; color: var(--ink); }
.tile .badgeslot { width: 80px; height: 22px; }
.tile .badge { width: 100%; height: 22px; }
.tile span.badge { display: grid; place-items: center; padding: 0; }
.tile button.badge { min-height: 0; height: 22px; padding: 0 3px; white-space: nowrap; letter-spacing: 0; }
.tiles.dense .tile .badge { width: 100%; }
/* The dealer's mark on a seat's initial: its "D" 12px, as every word on
   the table is (a 13px chip grows to 15px outward, so it covers no more of
   the initial than it did). */
:is(.seat, .tile) .dealer { position: absolute; right: -3px; bottom: -3px; box-shadow: 0 0 0 2px var(--room); width: 15px; height: 15px; border-radius: 50%; background: var(--ink); color: var(--room); font: 800 12px/15px var(--ui-font); text-align: center; }
.tile .dealer { right: -8px; bottom: -7px; }
:is(.seat, .tile) .count { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-size: 12px; }
/* Phones: one row per seat that's down, its header one line of text. */
.tiles.list .tile { padding: 3px 8px 6px; gap: 1px; }
.tiles.list .tile.notdown { display: none; }
.tiles.list .tile.turn { outline-width: 2px; outline-offset: 1px; }
.tiles.list .tilehead { height: auto; min-height: 0; display: block; }
.tiles.list .tilehead :is(.face, .badgeslot) { display: none; }
.tiles.list .who { gap: 8px; font-size: 13px; line-height: 18px; }
.tiles.list .name { color: var(--seat); }
/* ── the roster (kit/roster.js) ─────────────────────────────────────── */
/* Everyone in a strip of fixed cells (--cols × --rows, from the number of
   seats and the width alone), each a mark with one reserved status spot,
   and a name under it when there's room. Nothing in it changes size. */
.roster { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(var(--cols, 1), minmax(44px, 1fr)); gap: var(--s1); }
.rcell { position: relative; display: grid; grid-template-rows: 32px; justify-items: center; align-items: center; min-height: 44px; padding: 6px 2px; border-radius: var(--chip-radius); }
.roster.named .rcell { grid-template-rows: 32px 18px; }
.rcell .rmark { width: 32px; height: 32px; }
.rcell .rmark > .seatmark { display: block; width: 100%; height: 100%; }
.rcell .rstatus { position: absolute; top: 2px; left: calc(50% + 10px); width: 18px; height: 18px; border-radius: 50%; display: grid; place-items: center; font: 800 11px/1 var(--ui-font); background: var(--chip); color: var(--ink); }
.rcell .rstatus:empty { visibility: hidden; }
.rcell[data-status="picked"] .rstatus { background: var(--good); color: var(--room); }
.rcell[data-status="away"] .rmark, .rcell[data-away] .rmark { opacity: .55; }
/* away, beside a ✓ or anything else in the status spot: a hollow ring at the mark's other shoulder */
.rcell[data-away]:not([data-status="away"])::before { content: '◌'; position: absolute; top: 2px; right: calc(50% + 10px); width: 18px; height: 18px; border-radius: 50%; display: grid; place-items: center; font: 800 11px/1 var(--ui-font); background: var(--chip); color: var(--ink); }
.rcell .rname { display: none; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13px; line-height: 18px; }
.roster.named .rcell .rname { display: block; }
.rcell .rpop { position: absolute; top: calc(100% + 2px); left: 50%; transform: translateX(-50%); z-index: 5; white-space: nowrap; padding: 3px 8px; border-radius: 99px; background: var(--sheet); color: var(--ink); border: var(--chip-edge); font-size: 13px; pointer-events: none; }
.rcell:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }

/* ── a countdown (kit/clock.js) ─────────────────────────────────────── */
/* A bar that empties in place, and the seconds beside it in a fixed width. */
.clock { display: inline-flex; align-items: center; gap: var(--s2); }
.clockbar { width: 96px; height: 6px; border-radius: 3px; overflow: hidden; background: color-mix(in srgb, var(--ink) 18%, transparent); }
.clock[hidden] { display: none; }
.clockfill { display: block; height: 100%; background: var(--ink); transform-origin: left center; transition: transform .25s linear; }
@media (prefers-reduced-motion: reduce) { .clockfill { transition: none; } }
.clock.low .clockfill { background: var(--bad); }
.clocktext { min-width: 3ch; font-size: var(--t-note); font-variant-numeric: tabular-nums; color: var(--soft); }

/* Something on its way across the table (kit/motion.js). */
.flying { position: fixed; z-index: 40; pointer-events: none; margin: 0; }
.panel { background: var(--panel); border: var(--panel-edge); border-radius: var(--panel-radius); padding: 10px 12px; }

/* ── sheets: dialogs over the table ─────────────────────────────────── */
.scrim { position: fixed; inset: 0; background: rgba(0, 0, 0, .55); display: grid; place-items: center; padding: 14px; z-index: 50; }
.sheet {
  background: var(--sheet); border: var(--rail); border-radius: var(--rail-radius); color: var(--ink);
  width: min(680px, 100%); max-height: calc(100dvh - 28px); overflow: auto; padding: 18px 20px 0; outline: none;
}
/* a game's clock still running under the sheet: kept in view at its top right */
.sheetclock {
  position: sticky; top: 0; float: right; z-index: 1; margin: 0 -6px 0 var(--s2); padding: 3px 10px; border-radius: 99px;
  background: var(--turn); color: var(--turn-ink); font: 800 13px/1.3 var(--ui-font); font-variant-numeric: tabular-nums;
}
.sheet h2 { font-family: var(--display); font-weight: var(--display-weight); margin: 0 0 var(--s3); font-size: 24px; line-height: 1.2; }
.sheet h3 { font-family: var(--display); font-weight: var(--display-weight); font-size: var(--t-heading); line-height: 1.25; margin: var(--s4) 0 var(--s2); }
:is(.sheet, .house-sheet) p, :is(.sheet, .house-sheet) li { font-size: 15px; }
:is(.sheet, .house-sheet) p.soft { font-size: var(--t-note); }
.sheet .foot {
  position: sticky; bottom: 0; display: flex; justify-content: flex-end; align-items: center; gap: 8px; flex-wrap: wrap;
  margin: 14px -20px 0; padding: 12px 20px 16px; background: var(--sheet); border-top: 1px solid color-mix(in srgb, var(--ink) 15%, transparent);
}
:is(.sheet, .house-sheet) .menu { display: grid; gap: 8px; }
/* The house kit's sheets (house/sheet.js) wear the room's buttons: its ✕ is
   a quiet button without the underline, a finger wide. */
.house-sheet .btn.quiet.house-x { text-decoration: none; padding: 0; min-height: 44px; font-size: 18px; }
/* How to play: two columns' room on a wide screen, its sections kept whole. */
@media (min-width: 900px) {
  .house-sheet.rulessheet .rulesheet { columns: 2; column-gap: var(--s5); }
  .house-sheet.rulessheet .rulesheet > section { break-inside: avoid; }
  .house-sheet.rulessheet .rulesheet > section > h3:first-child { margin-top: 0; }
}
/* one setting pattern (house rule 8): the label and a one-line hint at the
   left, a short choice beside them, a long one (.under) under them */
.option { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: var(--s2) var(--s3); padding: 12px 0; border-bottom: 1px solid color-mix(in srgb, var(--ink) 12%, transparent); }
.option > div:first-child { flex: 1 1 14em; min-width: 0; }
.option b { font-size: var(--t-label); font-weight: 600; }
.option p { margin: 2px 0 0; font-size: var(--t-note); }
.option.under { flex-direction: column; align-items: stretch; }
.option.under > div:first-child { flex: none; }
.option.under > .seg { display: grid; }
.option.under > .seg button, .setting.under > .seg button { min-width: 0; padding-inline: 6px; }
.option > .seg { flex: none; }

/* the score chart at game over (kit/chart.js): lines in seat colors, drawn
   in once; the grid and numbers in the sheet's own ink */
.chart { margin: 2px 0 10px; }
.chart svg { display: block; width: 100%; height: auto; overflow: visible; }
.chart figcaption { font-size: var(--t-note); margin-top: 2px; }
.scorechart .grid { stroke: color-mix(in srgb, var(--ink) 14%, transparent); }
.scorechart .tick { fill: var(--soft); font-family: var(--ui-font); }
.scorechart .endlabel { font-family: var(--ui-font); }
.scorechart .ring { fill: var(--sheet); }
.scorechart.draw .line { stroke-dasharray: 1; animation: chartdraw .9s cubic-bezier(.3, .6, .3, 1) both; }
.scorechart.draw :is(.ring, .endlabel) { animation: chartfade .3s .75s both; }
@keyframes chartdraw { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } }
@keyframes chartfade { from { opacity: 0; } }

/* at game over, beside the heading: whether the game's kept in your
   history (kit/account.js), quietly, on the heading's line */
:is(.sheet, .house-sheet) .overhead { display: flex; justify-content: space-between; align-items: baseline; gap: 4px 14px; flex-wrap: wrap; margin: 0 0 10px; }
:is(.sheet, .house-sheet) .overhead h2 { margin: 0; }
.kept { font-size: var(--t-note); font-weight: 600; white-space: nowrap; }
a.kept { color: var(--ink); text-underline-offset: 3px; }

/* sharing at game over: its buttons on the left of the foot */
.sheet .foot .share { display: flex; gap: 8px; flex-wrap: wrap; margin-right: auto; }
/* on the house's result sheet, Share result gives way to the picture's
   buttons, in its place (room.js shareAction) */
.house-foot .btn.small[data-weight="secondary"] { min-height: 44px; }

.toast {
  position: fixed; left: 50%; top: 42%; transform: translate(-50%, -50%); z-index: 60; pointer-events: none;
  background: var(--sheet); color: var(--ink); border: var(--chip-edge); border-radius: 14px;
  padding: 10px 18px; font-size: 15px; max-width: min(460px, calc(100% - 40px)); text-align: center;
  box-shadow: 0 10px 28px rgba(0, 0, 0, .4); transition: opacity .2s;
}
.toast.going { opacity: 0; }
/* with a sheet open, at the top of the window rather than over the sheet */
body:has(.scrim) .toast { top: calc(12px + env(safe-area-inset-top, 0px)); transform: translate(-50%, 0); }

/* ── lobby screens ──────────────────────────────────────────────────── */
/* House rules: one filled button per screen, headings 20, labels 16
   semibold, hints 14 and one sentence, spaced on 4 · 8 · 16 · 24 · 40. */
.lobby { max-width: var(--page-max); margin: 0 auto; padding: var(--bar-gap) 0 var(--s4); display: flex; flex-direction: column; gap: var(--s3); width: 100%; }
.felt:has(> .lobby) { gap: 0; }
/* The page skeleton (house rule 10): kicker, title, lead, then the page's
   panels; the same roles and sizes as every game's home. */
.kicker { margin: 0; font: var(--w-tool) var(--t-kicker)/1.3 var(--ui-font); letter-spacing: var(--kicker-spacing); text-transform: uppercase; color: var(--soft); }
.lobby .kicker + h1 { margin-top: calc(var(--s2) - var(--s3)); }
.lobby h1 { font-family: var(--display); font-weight: var(--display-weight); font-size: var(--t-display); margin: 0; line-height: var(--lh-display); }
.lobby :is(.lede, .lead) { margin: 0; color: var(--soft); font-size: var(--t-lead); line-height: var(--lh-body); max-width: 38em; }
/* a page's panels: one padding, one radius, one gap between them */
.lobby .panel { padding: var(--panel-pad); border-radius: var(--panel-radius); }
/* Card games are desktop-first (docs/design-system.md): phones get a note. */
.lobby .smallscreen { display: none; margin: 0; font-size: var(--t-note); }
@media (max-width: 640px) { .lobby .smallscreen { display: block; } }
.choices { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: var(--s3); }
.choice { display: flex; flex-direction: column; gap: var(--panel-gap); }
.choice.panel { padding: var(--panel-pad); }
.choice h2 { font: var(--display-weight) var(--t-heading)/var(--lh-heading) var(--display); margin: 0; }
.choice p.soft { margin: 0; font-size: var(--t-note); }
.row { display: flex; gap: var(--s2); align-items: center; flex-wrap: wrap; }
.joinrow { display: grid; grid-template-columns: 1fr auto; gap: var(--s2); }
.bots { display: flex; flex-direction: column; gap: var(--s3); }
/* one setting pattern (house rule 8): the label (16 semibold) and a
   one-line hint at the left; a short choice beside them, its right edge on
   the column's; a long one (.under) under them, the column's full width */
.setting { display: flex; justify-content: space-between; align-items: center; gap: var(--s2) var(--s3); flex-wrap: wrap; }
.setting > div:first-child { flex: 1 1 10em; min-width: 0; }
.setting .label, .namerow label { font-size: var(--t-label); font-weight: 600; color: var(--ink); }
.setting small { display: block; font-size: var(--t-note); margin-top: 2px; }
.setting > .seg, .setting > .stepper { flex: none; }
.setting.under { flex-direction: column; align-items: stretch; }
.setting.under > div:first-child { flex: none; }
.setting.under > .seg { display: grid; }
/* (a setting that draws its own control: the whole width) */
.setting.own { display: block; }
.setting.own > * { min-width: 0; }
/* (many choices, a game's boards or galleries: rows of as many as fit) */
.setting.under.many > .seg { grid-auto-flow: row; grid-template-columns: repeat(auto-fill, minmax(6.4em, 1fr)); }
/* the host's house rules (docs/adr/0021): a quiet line under the settings,
   which is nothing at all when there's nothing to say */
.houserules { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s1) var(--s2); margin-top: var(--s3); }
.houserules:empty { display: none; }
.houserules small { flex: 1 1 12em; font-size: var(--t-note); }
/* a pick's own rows (Mixed: a level per bot), close under it */
.setting + .botlevels { margin-top: calc(var(--s2) - var(--s3)); }
.botlevels { display: flex; flex-direction: column; gap: var(--s1); }
.botlevels .setting .label { font-weight: 400; }
.botlevels .setting > div:first-child { flex: 1 1 4em; }
.botlevels .seg button { min-height: 30px; padding-block: 3px; }
.stepper { display: inline-flex; align-items: center; gap: var(--s2); }
.stepper b { min-width: 1.4em; text-align: center; font-size: 18px; }
.stepper .btn { min-width: 44px; padding: 4px 0; font-size: 20px; line-height: 1; background: transparent; color: var(--ink); border: var(--field-edge); }
.stepper .signicon { display: block; width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; }
/* Choosing isn't doing (house rule 3): a pick is a tint, an inner ring and
   bold, inside a group on the soft line, never the primary fill. Every
   choice in a group is as wide as the widest (bold), so rows line up and
   a pick never nudges its neighbours. */
.seg { display: inline-grid; grid-auto-flow: column; grid-auto-columns: 1fr; gap: 2px; padding: 3px; border: var(--field-edge); border-radius: var(--btn-radius); }
.seg button {
  background: transparent; border: 0; border-radius: max(0px, calc(var(--btn-radius) - 3px)); padding: 6px 12px; min-height: 36px; min-width: 5.2em;
  font-size: 15px; font-weight: 500; cursor: pointer; color: var(--ink); line-height: 1.2;
}
.seg button::after { content: attr(data-label); display: block; height: 0; overflow: hidden; visibility: hidden; font-weight: var(--pick-weight); }
.seg button:hover { background: color-mix(in srgb, currentColor 8%, transparent); }
.seg button[aria-pressed="true"] { background: var(--pick-tint); box-shadow: var(--pick-ring); font-weight: var(--pick-weight); }
/* the sort switch at the table stays compact: each choice its own width,
   every label already semibold, so a pick doesn't widen it */
.seg.small { flex: none; padding: 1px; gap: 0; --pick-weight: 600; }  /* (a .seg's grid: its choices one width, never squeezed under their words) */
@media (max-width: 480px) { .seg.small { display: inline-flex; flex: 0 1 auto; } }  /* (a phone's tool row: each by its words, and it gives way) */
.seg.small button { min-height: 26px; min-width: 0; padding: 2px 10px; font-size: 13px; font-weight: 600; white-space: nowrap; }
.bigcode { font: 900 clamp(34px, 9vw, 52px)/1 var(--ui-font); letter-spacing: .14em; }
.seatlist { display: flex; flex-direction: column; gap: var(--s2); }
.seatlist .seat { border-radius: 12px; display: grid; grid-template-columns: 1fr auto; padding-right: 6px; border: 0; }
.seatlist .seat .face { background: var(--btn); color: var(--btn-ink); }
.seatlist .seat > .row:first-child { flex-wrap: nowrap; min-width: 0; }
@media (max-width: 520px) {
  .seatlist .seat:has(.seg) { grid-template-columns: minmax(0, 1fr); row-gap: 6px; padding-bottom: 6px; }
  .seatlist .seat > .row:last-child { justify-content: space-between; }
  .seatlist .seat > .row:last-child:empty { display: none; }
}
/* Seven or more at the table: two columns of one-line rows (a bot's level
   a compact choice, Remove a ×), so twelve fit in 1280×800. The waiting
   room is that wide from the first seat, so it never jumps as people come. */
@media (min-width: 900px) {
  .seatlist.many { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s2); }
  .seatlist.many .seat { min-height: 44px; padding-right: 4px; }
  .seatlist.many .seat > .row { flex-wrap: nowrap; gap: var(--s1); }
  .seatlist.many .seat .who { flex-wrap: nowrap; min-width: 0; }
  .seatlist.many .seat .who b { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .seatlist.many .seat .who .tag { flex: none; }
  /* (a bot's name keeps its few letters beside its tag and its level) */
  .seatlist.many .seat:has(.seg) .who b { flex: none; max-width: 5.5em; }
  .seatlist.many .seat .swap { min-width: 24px; }
  .seatlist.many .seat .seg { padding: 1px; grid-auto-columns: auto; }
  .seatlist.many .seat .seg button { min-width: 0; min-height: 28px; padding: 2px 6px; font-size: 13px; }
  .seatlist.many .seat .drop { min-width: 32px; min-height: 32px; padding: 0; font-size: 20px; text-decoration: none; color: var(--soft); }
  .seatlist.many .seat .drop:hover { color: var(--ink); }
}
@media (max-width: 899px) { .seatlist .seat .drop { font-size: 0; } .seatlist .seat .drop::after { content: 'Remove'; font-size: var(--t-body); } }
/* One column (phones, tablets): who's at the table comes last, so people
   joining grow the page below everything else rather than push it down. */
@media (max-width: 899px) { .waitgrid .atable { order: 1; } }
/* the host's buttons line up on their left edge, quiet ones too */
.waitgrid .atable > .row > .btn.quiet { padding-inline: 0; }
.seatlist .seat .who { min-width: 0; flex-direction: row; flex-wrap: wrap; align-items: center; gap: 2px 8px; font-size: var(--t-body); }
.seatlist .seat .who b { overflow-wrap: anywhere; }
/* the host seating everyone (kit/seating.js): a quiet ⇅ on each seat,
   tapped once to pick it up and on another to swap; or drag the row */
.seatlist .seat .swap { flex: none; min-width: 32px; min-height: 32px; padding: 0; font-size: 16px; text-decoration: none; color: var(--soft); }
.seatlist .seat .swap:hover, .seatlist .seat .swap[aria-pressed="true"] { color: var(--ink); }
.seatlist .seat[draggable="true"] { cursor: grab; }
.seatlist .seat.dragging { opacity: .5; }
.seatlist .seat.picked, .seatlist .seat.dropping { outline: 2px dashed var(--turn); outline-offset: 2px; }
.seatlist.picking .seat:not(.picked) .swap { color: var(--ink); }
.beside { margin: 0; font-weight: 600; }
.beside:empty { display: none; }
/* what the room floats at a table (kit/room.js placeFloat): the host's offer
   of a bot for someone who keeps running out of time, and the seat bar.
   Never over the board (a seat, a score strip, a pile), never in the
   dock's flow (it would grow the dock and push the board out of view):
   - .ondock: Take my seat back lies over the dock, the dock's own size,
     while a bot plays your seat (the dock's controls have nothing to do);
   - .inbar: the host's tools sit in the top bar's empty middle, in a line;
   - .inbar.tight: where the bar has no room (a phone), over its title,
     one at a time. */
.roomfloat { position: fixed; z-index: 40; display: grid; gap: var(--s1); pointer-events: none; }
.roomfloat:empty { display: none; }
.roomfloat > * {
  pointer-events: auto; max-width: 100%; box-sizing: border-box; border-radius: 12px; background: var(--sheet); color: var(--ink);
  border: 1px solid color-mix(in srgb, var(--ink) 16%, transparent); box-shadow: 0 8px 28px rgba(0, 0, 0, .35); font-size: var(--t-note);
}
.offer { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s1) var(--s2); padding: 8px 10px 8px 14px; }
.offer p { margin: 0; }
.offer .row { flex-wrap: nowrap; gap: var(--s1); }
.seatbar { display: flex; flex-direction: column; gap: 6px; }
.seatbar .seatrow { display: flex; align-items: center; justify-content: space-between; gap: var(--s2); min-width: 0; }
.seatbar .seatnote { min-width: 0; flex: 1; font-size: var(--t-note); overflow-wrap: anywhere; }
.seatbar .btn { flex: none; min-height: 44px; }
/* (a game's own place for it, seatBarIn, shows only the button for your seat) */
.seatbar .seatrow.mine .seatnote { display: none; }
.seatbar .seatrow.mine .btn { flex: 1; }
@media (max-height: 520px) { .seatbar { flex-direction: row; flex-wrap: wrap; } }

/* over the dock: the same box, saying what the dock would ("A bot is
   playing for you.") and the way back, in the middle */
.roomfloat.ondock > .seatbar { height: 100%; justify-content: center; padding: 8px var(--s3); border-radius: var(--dock-radius, 14px); box-shadow: none; }
.roomfloat.ondock .seatrow.mine { justify-content: center; gap: var(--s3); flex-wrap: nowrap; }
.roomfloat.ondock .seatrow.mine .seatnote { display: block; flex: 0 1 auto; font-size: var(--t-lead, 16px); font-weight: 600; overflow-wrap: normal; }
.roomfloat.ondock .seatrow.mine .btn { flex: none; min-width: min(260px, 50%); }
/* (a phone's dock may be one row tall: the words wrap beside the button) */
@media (max-width: 560px) {
  .roomfloat.ondock > .seatbar { padding: 6px 12px; }
  .roomfloat.ondock .seatrow.mine { gap: var(--s2); }
  .roomfloat.ondock .seatrow.mine .seatnote { font-size: var(--t-note); line-height: 1.25; }
  .roomfloat.ondock .seatrow.mine .btn { min-width: 0; }
}
.roomfloat.ondock > .offer { display: none; } /* (the host's offer waits for the seat back) */

/* in the top bar: centered on its middle, in the bar's own ink, no panel */
.roomfloat.inbar { translate: -50% -50%; width: max-content; max-width: calc(100vw - 24px); }
.roomfloat.inbar > * { background: transparent; border: 0; box-shadow: none; padding: 0; }
.roomfloat.inbar > .seatbar { flex-direction: row; flex-wrap: nowrap; gap: var(--s3); }
.roomfloat.inbar .offer { flex-wrap: nowrap; }
.roomfloat.inbar :is(.seatnote, .offer p) { flex: 0 1 auto; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; overflow-wrap: normal; }
/* over the title (a phone): a panel the bar's height, the one most to hand */
.roomfloat.inbar.tight { translate: 0 -50%; }
.roomfloat.inbar.tight > * { background: var(--sheet); padding: 0 0 0 10px; border-radius: 10px; min-width: 0; }
.roomfloat.inbar.tight > * + *, .roomfloat.inbar.tight .seatrow + .seatrow { display: none; }
.roomfloat.inbar.tight .seatrow, .roomfloat.inbar.tight .offer { gap: var(--s1); min-width: 0; }
.roomfloat.inbar.tight :is(.seatnote, .offer p) { flex: 1 1 auto; }
.roomfloat.inbar.tight .btn { padding-inline: 10px; }
.roomfloat.inbar.tight .offer .btn.quiet { padding-inline: 8px; }
/* who's watching (a count, never names), and who's waiting to sit in:
   quiet, and nothing at all when there's no one */
.watchers { margin: 0; font-size: var(--t-note); }
.watchers:empty, .watchbar:empty { display: none; }
.watchbar { display: inline-flex; align-items: center; flex-wrap: wrap; gap: 0 var(--s1); font-size: var(--t-note); color: var(--soft); }
.watchbar.watching { color: var(--ink); }
.watchbar .btn { margin-left: var(--s1); }
/* In a top bar's tools it floats to their left, taking no room of its own,
   so someone starting to watch never moves the tools (or the table). */
.bar .tools { position: relative; }
.bar .tools > .watchbar { position: absolute; right: 100%; top: 50%; transform: translateY(-50%); margin-right: var(--s2); flex-wrap: nowrap; white-space: nowrap; }
.presence { font: 700 12px var(--ui-font); color: var(--soft); }
.presence::before { content: '●'; margin-right: 3px; color: var(--soft); }
.presence.on::before { color: var(--good); }
.recent { display: flex; flex-direction: column; gap: var(--s2); }
.recent > .soft { font-size: var(--t-label); font-weight: 600; color: var(--ink); }
.recent a small { font-size: var(--t-note); }
/* (where it stands keeps to the right of the table's name; where there's no
   room beside it, it goes under, at the right, and a long one ("A bot's
   playing for you · take your seat back") wraps there rather than running
   out of the row: its arrow is kept with its last word, room.js) */
.recent a > .soft:last-child { margin-left: auto; min-width: 0; text-align: right; }
.recent a > span:first-child { min-width: 0; }
.recent a { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: baseline; gap: 2px var(--s2); text-decoration: none; padding: 10px 12px; border-radius: 10px; background: var(--chip); border: var(--chip-edge); }
/* each row's quiet ×, beside it rather than in it (a link can't hold a button) */
.recent .rrow { display: flex; align-items: stretch; gap: var(--s1); }
.recent .rrow a { flex: 1; min-width: 0; }
.recent .forget { flex: none; min-width: 44px; min-height: 0; padding: 0; font-size: 22px; line-height: 1; text-decoration: none; color: var(--soft); border-radius: 10px; }
.recent .forget:hover { color: var(--ink); background: var(--chip); }
/* (the × is drawn, house/nav.js closeIcon(), so it sits in the middle of its button in any face) */
.recent .forget svg.house-close { width: 20px; height: 20px; }
/* the lobby's top: the blurb with the account line at its right (under it
   when there's no room), and your name on one row */
.ledeline { display: flex; justify-content: space-between; align-items: baseline; gap: var(--s1) 18px; flex-wrap: wrap; }
.ledeline .acctline { margin: 0; }
.namerow { display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: center; gap: var(--s3); }
@media (min-width: 900px) {
  .lobby.waiting { max-width: var(--page-max-wide); }
  .choices { grid-template-columns: minmax(0, 3fr) minmax(0, 2fr); }
  .waitgrid { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); grid-template-rows: auto 1fr; grid-template-areas: "seats code" "seats settings"; }
  .waitgrid .atable { grid-area: seats; }
  .waitgrid .invite { grid-area: code; }
  .waitgrid .tsettings { grid-area: settings; }
}
.choicehead { display: flex; justify-content: space-between; align-items: center; gap: var(--s2); flex-wrap: wrap; }
/* the waiting room: who's at the table (and Deal) beside the code and the settings */
.waitgrid { display: grid; gap: var(--s3); align-items: start; }
.waitside { display: flex; flex-direction: column; gap: var(--s3); min-width: 0; }
.waitgrid .link { word-break: break-all; font-size: 13px; }
.waitgrid .setting:not(.under) > div:first-child { flex-basis: 6em; }
.waitgrid .setting:not(.under) > .seg button { min-width: 4.4em; padding-inline: 8px; }
/* signing in (kit/account.js): a quiet line by the name field, or in its
   place once you're signed in */
.fieldhead { display: flex; justify-content: space-between; align-items: baseline; gap: var(--s1) 12px; flex-wrap: wrap; }
.acct { font-size: var(--t-note); color: var(--soft); }
.acct a, a.acct { color: var(--ink); text-underline-offset: 3px; }
.acct b { color: var(--ink); font-size: var(--t-body); }
.linkish { appearance: none; background: none; border: 0; padding: 0; color: var(--ink); text-decoration: underline; text-underline-offset: 3px; cursor: pointer; font-size: inherit; }
.field.whoami { margin: 0; flex-direction: row; align-items: center; min-height: 44px; }
/* the page's foot (house rule 10): the copyright at the right */
.foot-links { display: flex; justify-content: flex-end; gap: 12px; flex-wrap: wrap; font-size: 13px; color: var(--soft); padding: 8px 2px 4px; }
.foot-links a { color: var(--soft); }

/* ── the game log ───────────────────────────────────────────────────── */
/* (opaque, the sheet's own color: a drawer over a busy table, or Chat over
   the cards, reads the same whatever's under it, with no blur to lean on) */
.gamelog {
  background: var(--sheet); color: var(--ink);
  border: 1px solid color-mix(in srgb, var(--ink) 16%, transparent); border-radius: 12px;
  font: 13px/1.45 var(--ui-font); display: flex; flex-direction: column; position: relative; min-height: 0;
}
.gamelog .loghead { display: flex; align-items: center; gap: 4px; padding: 4px 4px 4px 12px; flex: none; }
.gamelog .loghead b { font-size: 12px; letter-spacing: .06em; text-transform: uppercase; color: var(--soft); flex: 1; }
.gamelog .loghead .btn { min-height: 32px; padding: 2px 8px; }
.gamelog .logclose { text-decoration: none; font-size: 15px; min-width: 32px; }
.gamelog .loglines { list-style: none; margin: 0; padding: 0 12px 10px; overflow-y: auto; scrollbar-width: thin; min-height: 0; flex: 1; }
.gamelog .lognew { position: absolute; bottom: 10px; left: 50%; transform: translateX(-50%); border: 0; border-radius: 99px; padding: 6px 12px; background: var(--btn); color: var(--btn-ink); font-weight: 700; cursor: pointer; }
.loglines li { padding: 2px 0; }
.loglines li.end { padding-bottom: 6px; margin-bottom: 4px; border-bottom: 1px solid color-mix(in srgb, var(--ink) 9%, transparent); }
.loglines li.quiet { color: var(--soft); }
.loglines li.key, .loglines li.big { font-weight: 600; }
.loglines li.result { margin: 6px 0; padding: 6px 8px; border-radius: 6px; background: color-mix(in srgb, var(--turn) 14%, transparent); font-weight: 600; }
.loglines li.result .scores { display: flex; flex-wrap: wrap; gap: 2px 10px; font-weight: 400; margin-top: 2px; }
.loglines li.head { margin: 12px 0 4px; padding: 4px 8px; border-radius: 6px; background: color-mix(in srgb, var(--ink) 9%, transparent); font-weight: 700; }
.loglines li.head:first-child { margin-top: 0; }
.loglines li.head small { font-size: 12px; font-weight: 400; color: var(--soft); }
.loglines .who { font-weight: 700; }

/* ── a splash at the start of a round (kit/intro.js) ────────────────── */
/* Over everything but sheets and toasts, and never in the way of a click. */
.intro { position: fixed; inset: 0; z-index: 45; pointer-events: none; background: color-mix(in srgb, var(--room) 42%, transparent); }
.introcard {
  position: fixed; transform: translate(-50%, -50%); width: max-content; max-width: min(620px, calc(100vw - 24px));
  background: var(--table); border: var(--rail); border-radius: var(--rail-radius); color: var(--ink);
  padding: 20px 30px 26px; text-align: center; box-shadow: 0 26px 70px rgba(0, 0, 0, .55), 0 0 0 1px rgba(0, 0, 0, .25);
}
/* Where the splash went lights up once: a highlight behind it, which reads
   in every style (and nothing about it is clipped or moves anything). */
.pulse { animation: pulse 1.2s ease-out; }
@keyframes pulse {
  20%, 45% {
    background-color: color-mix(in srgb, var(--turn) 32%, transparent);
    box-shadow: 0 0 0 4px color-mix(in srgb, var(--turn) 32%, transparent), 0 0 18px 4px color-mix(in srgb, var(--turn) 45%, transparent);
  }
}

@media (max-width: 640px) {
  /* (the felt is the screen: no frame, no rail; the gutter is --gutter's) */
  .felt { border-radius: 0; border: 0; }
  .seg button { min-width: 4.2em; padding-inline: 8px; }
  /* (a choice that wraps under its label never runs past the panel's edge) */
  .setting > .seg { max-width: 100%; }
  .setting > .seg button { min-width: 0; }
}
/* the narrowest phones: choices give up their spare width ("Medium" fits) */
@media (max-width: 360px) {
  .seg button { min-width: 0; padding-inline: 4px; font-size: 14px; }
}
/* A finger's reach on a touch screen (docs/design-language.md, "Fine
   details"): a quiet button, a choice and a stepper are 44px tall; what's
   drawn smaller to fit (a link in a line, the bar's
   title, the sort switch, the bar's ⋯, a crowded waiting room's bot
   levels, a dock's moves on a phone on its side) reaches 44px round its
   middle without growing (house.css's .house-reach, for the room's own
   pieces). */
@media (pointer: coarse) {
  .btn.quiet, .seg:not(.small) button, .stepper .btn { min-height: 44px; }
  .roomtools .btn, .seg button, .seg.small button, .setting > .seg button { min-width: 44px; }
  :where(.acct a, a.acct, a.kept, .titlebtn, .seg.small button, .botlevels .seg button, .seatlist.many .seat .seg button, .bar .btn.more, .dock .btn) { position: relative; }
  :where(.acct a, a.acct, a.kept, .titlebtn, .seg.small button, .botlevels .seg button, .seatlist.many .seat .seg button, .bar .btn.more, .dock .btn)::before {
    content: ''; position: absolute; left: 50%; top: 50%; width: max(100%, 44px); height: max(100%, 44px); translate: -50% -50%;
  }
  /* (the bar's ⋯ over what's under the bar on a phone on its side) */
  .bar .btn.more { z-index: 1; }
  /* (the bar's title button clips its words, and Safari has no overflow-clip-margin: its reach is padding that layout gives back, so it's a 44px target there too) */
  .bar button.titlebtn { overflow: hidden; padding-block: 13px; margin-block: -13px; }
}
@media (prefers-reduced-motion: reduce) {
  .toast { transition: none; animation: none; }
  .scorechart.draw :is(.line, .ring, .endlabel) { animation: none; }
}

/* ── talk at a table (kit/talk.js, docs/adr/0052) ──────────────────────── */
/* In the top bar, after the game's tools (on a phone, beside the ⋯): the
   smiley and, when the host has chat on, the speech bubble. Everything
   after the title keeps to the right, together, whether the tools show or
   not. */
.bar:has(> .talk:not([hidden])) > :first-child { margin-right: auto; }
.bar > .talk { display: flex; flex: none; gap: var(--s1); align-items: center; }
.bar > .talk[hidden], .talk .talkbtn[hidden] { display: none; }
.bar .talk .talkbtn { position: relative; min-width: var(--tool-h); padding-inline: 6px; text-decoration: none; }
.talk .talkbtn .house-glyph { width: 22px; height: 22px; vertical-align: middle; }
.talk .talkbtn.on { background: var(--pick-tint); box-shadow: var(--pick-ring); }
/* the unread count: a small round tag on the bubble's corner (and the Chat tab's) */
.talkbadge {
  display: inline-grid; place-items: center; min-width: 18px; height: 18px; padding: 0 5px; border-radius: 99px;
  background: var(--turn); color: var(--turn-ink); font: 700 11px/1 var(--ui-font);
}
.talkbadge[hidden] { display: none; }
.talk .talkbadge { position: absolute; top: -4px; right: -6px; pointer-events: none; }
/* On a phone the bar has room for one: with both, Chat is the tray's last
   row, and the smiley carries its count. A title they crowd takes two
   lines rather than being cut off. */
.talk .emotebtn .talkbadge, .emotetray .traychat { display: none; }
@media (max-width: 640px) {
  .talk.both .chatbtn { display: none; }
  .talk.both .emotebtn .talkbadge:not([hidden]) { display: inline-grid; }
  .emotetray.chat .traychat { display: flex; }
}
@media (max-width: 400px) {
  .bar:has(> .talk:not([hidden])) .titlerow :is(.title, .titlebtn) {
    white-space: normal; line-height: 1.15; overflow: visible; text-wrap: balance;
  }
}
.emotetray .traychat { grid-column: 1 / -1; justify-content: center; align-items: center; gap: 6px; min-height: 44px; }
.emotetray .traychat .house-glyph { width: 20px; height: 20px; }
.traychat .talkbadge { margin-left: 2px; }
.chattab .talkbadge { margin-left: 6px; }
/* the tray of emotes, just under the smiley: four across */
.emotetray {
  position: fixed; z-index: 60; display: grid; grid-template-columns: repeat(4, 48px); gap: 4px; padding: 6px;
  border-radius: 14px; background: var(--sheet); color: var(--ink);
  border: 1px solid color-mix(in srgb, var(--ink) 16%, transparent); box-shadow: 0 8px 28px rgba(0, 0, 0, .35);
}
.emotetray[hidden] { display: none; }
.emotepick { width: 48px; height: 48px; display: grid; place-items: center; border: 0; border-radius: 10px; background: transparent; font-size: 26px; line-height: 1; cursor: pointer; }
.emotepick:hover { background: var(--pick-tint); }
.emotepick:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
/* the emotes floating up: over everything, taking no press, rising from the
   bottom's left side and fading as they go (--m-emote) */
.emotefloat { position: fixed; inset: 0; z-index: 75; pointer-events: none; overflow: hidden; }
.emote {
  position: absolute; bottom: calc(12px + env(safe-area-inset-bottom, 0px)); display: flex; flex-direction: column; align-items: center; gap: 2px;
  animation: talk-rise var(--m-emote) var(--ease-out) both;
}
.emote .emoteface { font-size: 40px; line-height: 1.1; }
.emote .emotewho {
  display: inline-flex; align-items: center; gap: 4px; max-width: 140px; padding: 2px 8px 2px 3px; border-radius: 99px;
  background: var(--sheet); color: var(--ink); font: 600 12px/1.3 var(--ui-font); box-shadow: 0 2px 8px rgba(0, 0, 0, .25);
}
.emote .emotewho span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.emote .emotewho svg { flex: none; }
@keyframes talk-rise {
  0% { opacity: 0; transform: translateY(20px) scale(.8); }
  10% { opacity: 1; transform: translateY(0) scale(1); }
  70% { opacity: 1; }
  100% { opacity: 0; transform: translateY(-55vh); }
}
/* Less motion: it shows where it starts, and fades (as a toast would). */
.emote.still { animation: talk-still var(--m-emote) linear both; }
@keyframes talk-still { 0%, 100% { opacity: 0; } 5%, 95% { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .emote { animation-name: talk-still; } }
/* Chat: a tab of the game log (kit/log.js), or a drawer of its own */
.gamelog .logtabs { display: flex; gap: 2px; flex: 1; min-width: 0; }
.gamelog .logtab {
  border: 0; background: transparent; color: var(--soft); font: 700 12px/1 var(--ui-font); letter-spacing: .06em; text-transform: uppercase;
  padding: 6px 8px; min-height: 32px; border-radius: 8px; cursor: pointer; display: inline-flex; align-items: center;
  min-width: 4.75em; justify-content: center;  /* (Log and Chat, with its count, one width: equal choices are equal) */
}
.gamelog .logtab[aria-selected="true"] { color: var(--ink); background: var(--pick-tint); box-shadow: var(--pick-ring); }
.gamelog .loglines[hidden], .chatpane[hidden] { display: none; }
.chatpane { display: flex; flex-direction: column; min-height: 0; flex: 1; }
.chatlines { list-style: none; margin: 0; padding: 0 12px 6px; overflow-y: auto; scrollbar-width: thin; min-height: 0; flex: 1; }
.chatlines li { padding: 3px 0; overflow-wrap: anywhere; }
.chatlines .who { font-weight: 700; }
.chatempty { margin: 0; padding: 4px 12px 10px; color: var(--soft); flex: 1; }
.chatempty[hidden], .chatform[hidden] { display: none; }
.chatform { display: flex; gap: var(--s1); padding: 8px; border-top: 1px solid color-mix(in srgb, var(--ink) 12%, transparent); flex: none; }
.chatinput {
  flex: 1; min-width: 0; min-height: 40px; padding: 6px 10px; border-radius: 8px; font: 16px/1.3 var(--ui-font);
  color: var(--ink); background: var(--panel); border: var(--field-edge);
}
.chatform .btn { flex: none; min-height: 40px; }
.talkdrawer {
  position: fixed; z-index: 30; right: 16px; width: min(340px, calc(100vw - 32px));
  box-shadow: -10px 10px 30px rgba(0, 0, 0, .35);
}
.talkdrawer[hidden] { display: none; }
@media (pointer: coarse) {
  .chatinput, .chatform .btn { min-height: 44px; }
  .gamelog .logtab, .gamelog .loghead .btn { min-height: 44px; }
  .gamelog .loghead .logclose { min-width: 44px; }
  /* (a phone on its side draws the bar's tools shorter: the talk's reach a finger round) */
  .bar .talk .talkbtn { z-index: 1; }
  .bar .talk .talkbtn::before { content: ''; position: absolute; left: 50%; top: 50%; width: max(100%, 44px); height: max(100%, 44px); translate: -50% -50%; }
}
