/*
 * Styles for the party hub and the ten games under it.
 *
 * Designed for the object it actually runs on: a phone lying face up in the
 * middle of a table in a dim room, read by people who are not holding it. That
 * drives most of what is here — one idea per screen, type large enough to read
 * across a sofa, and tap targets big enough that a thumb reaching over a coffee
 * table cannot miss.
 *
 * Everything is derived from one number. Each page sets `--hue` on <body> and
 * the accent, the glow behind it, the cards and the buttons all follow, which is
 * what stops ten pages built from one kernel reading as one page. Nothing here
 * is loaded over the network: no web fonts, no images, no icon set. The pages
 * have to render instantly on a bad connection and work off a file:// URL.
 */

:root {
  --hue: 265;
  --bg: #0c0a14;
  --ink: #f6f4ff;
  --good: #2fd6a4;
  --bad: #ff5d73;
  --radius: 18px;
  --radius-lg: 24px;
  color-scheme: dark;
}

/*
 * The hue-derived tokens are declared everywhere `--hue` is set, and that is not
 * a tidiness choice — it is the only thing that works.
 *
 * A custom property is resolved in the scope it is DECLARED in, not the scope it
 * is used from. Declaring `--accent: hsl(var(--hue) ...)` once on :root meant
 * every page computed its accent from the :root fallback of 265, so ten games
 * with ten hues rendered ten violet buttons on top of ten correctly coloured
 * backgrounds. Repeating the block for each element that sets a hue of its own
 * is what makes the derivation actually derive.
 */
:root,
body,
.game-card {
  --bg-lift: hsl(var(--hue) 22% 13%);
  --bg-card: hsl(var(--hue) 24% 15%);
  --line: hsl(var(--hue) 30% 100% / 0.12);
  --line-strong: hsl(var(--hue) 60% 70% / 0.35);
  --ink-dim: hsl(var(--hue) 20% 72%);
  --accent: hsl(var(--hue) 90% 72%);
  --accent-deep: hsl(var(--hue) 80% 58%);
  --on-accent: hsl(var(--hue) 60% 10%);
}

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

/*
 * The app hides screens by writing `hidden`, and every one of them carries a
 * `display` of its own — which beats the browser's own `[hidden] {display:none}`
 * outright, because any author rule outranks the user-agent stylesheet no matter
 * how specific. Without this line every screen renders at once, stacked, and the
 * page looks like the whole game printed onto one sheet.
 */
[hidden] {
  display: none !important;
}

body {
  font-family: 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  background: var(--bg);
  color: var(--ink);
  line-height: 1.5;
  min-height: 100vh;
  min-height: 100dvh;
  -webkit-text-size-adjust: 100%;
  /*
   * Declared once here, because `overflow-wrap` inherits and every screen is
   * full of text somebody typed or a name the hub generated. `anywhere` rather
   * than `break-word`, and the difference is the whole point: only `anywhere`
   * shrinks an element's min-content width. A flex or grid item — including a
   * plain wrapper <div> holding two buttons — is sized to its longest
   * unbreakable word, so with `break-word` the text wrapped and the box around
   * it was still 63px too wide.
   */
  overflow-wrap: anywhere;
}

/*
 * The glow. Fixed rather than scrolled, so a long catalogue does not drag the
 * light off the top of the page, and behind everything so no stacking context
 * has to know about it.
 */
body::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: -2;
  background:
    radial-gradient(90% 55% at 50% -10%, hsl(var(--hue) 70% 30% / 0.55) 0%, transparent 70%),
    radial-gradient(70% 50% at 100% 100%, hsl(calc(var(--hue) + 40) 65% 25% / 0.35) 0%, transparent 65%),
    var(--bg);
}

/*
 * A film of grain over the whole page. Flat dark gradients band badly on phone
 * screens — you can see the steps in the glow above — and a little noise breaks
 * the bands up. Generated by the browser from an inline SVG filter rather than
 * fetched, because the pages have to work with no network at all.
 */
body::after {
  content: '';
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  opacity: 0.4;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='3'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='0.055'/%3E%3C/svg%3E");
}

main {
  max-width: 34rem;
  margin: 0 auto;
  padding: 1.25rem 1.25rem calc(2rem + env(safe-area-inset-bottom));
}

/* One screen at a time. Everything else carries [hidden]. */
.screen {
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
  align-items: stretch;
  min-height: calc(100dvh - 6rem);
  justify-content: center;
  text-align: center;
}

/* Type -------------------------------------------------------------------- */

.title {
  font-size: clamp(2.1rem, 9.5vw, 3rem);
  font-weight: 850;
  letter-spacing: -0.035em;
  line-height: 1.02;
  /* A gradient wash rather than flat white: the same trick as the glow, at the
     size where a phone screen can actually show the difference. */
  background: linear-gradient(165deg, var(--ink) 20%, var(--accent) 130%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.title.xl {
  font-size: clamp(3rem, 16vw, 4.5rem);
}

.slash {
  color: var(--accent);
  -webkit-text-fill-color: var(--accent);
  padding: 0 0.12em;
}

/* Only on the landing page's oversized wordmark, where "games" wants its own
   line. The game titles use the same span inline — "Good Take / Bad Take" reads
   as nonsense with the slash stranded on a line of its own. */
.title.xl .slash {
  display: block;
  padding: 0;
}

.kicker {
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--accent);
}

.lede {
  color: var(--ink-dim);
  font-size: 1rem;
  max-width: 28rem;
  margin: 0 auto;
}

.eyebrow {
  color: var(--accent);
  font-weight: 750;
  letter-spacing: -0.01em;
  font-size: 1.1rem;
}

.label {
  color: var(--ink-dim);
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  font-weight: 650;
}

.ask {
  font-size: clamp(1.5rem, 6.5vw, 2rem);
  font-weight: 800;
  letter-spacing: -0.025em;
}

.category {
  font-size: clamp(2.25rem, 11vw, 3.25rem);
  font-weight: 850;
  letter-spacing: -0.035em;
  line-height: 1.03;
}

.scope {
  color: var(--ink-dim);
  font-size: 0.98rem;
}

.footnote {
  color: hsl(var(--hue) 15% 58%);
  font-size: 0.8rem;
}

.counter {
  color: var(--ink-dim);
  font-size: 0.8rem;
  text-align: right;
}

.error {
  color: var(--bad);
  font-size: 0.92rem;
  font-weight: 600;
}

/* Buttons ----------------------------------------------------------------- */

button {
  font: inherit;
  border: 0;
  border-radius: var(--radius);
  cursor: pointer;
  color: var(--ink);
  /* 3.25rem clears the 44px tap target on every phone this will see. */
  min-height: 3.25rem;
  padding: 0.75rem 1.25rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  transition: transform 0.09s ease, filter 0.15s ease, opacity 0.15s ease;
}

button:active {
  transform: translateY(1px) scale(0.99);
}

button:disabled {
  opacity: 0.38;
  cursor: default;
}

button:focus-visible,
a:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

.primary {
  background: linear-gradient(160deg, var(--accent) 0%, var(--accent-deep) 100%);
  color: var(--on-accent);
  box-shadow: 0 10px 30px -12px hsl(var(--hue) 80% 50% / 0.8);
}

.big {
  font-size: 1.15rem;
  min-height: 3.6rem;
}

.ghost {
  background: hsl(var(--hue) 30% 100% / 0.04);
  border: 1px solid var(--line);
  color: var(--ink-dim);
  font-weight: 650;
}

.ghost.tight {
  min-height: 2.5rem;
  padding: 0.4rem 0.9rem;
  font-size: 0.85rem;
}

.tiny {
  min-height: 2.25rem;
  padding: 0.35rem 0.7rem;
  font-size: 0.8rem;
  background: var(--bg-lift);
  border: 1px solid var(--line);
}

.tiny.danger {
  background: var(--bad);
  color: #2a0a11;
}

.danger-btn {
  background: var(--bad);
  color: #2a0a11;
}

/* Choosing a room --------------------------------------------------------- */

.room-picker {
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
  text-align: center;
}

.room-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0.7rem;
}

/*
 * Deliberately the biggest thing on the page. It is the only question the hub
 * ever asks, it is asked once, and it is asked of somebody holding a phone at
 * arm's length with the lights down.
 */
.room-size {
  aspect-ratio: 1;
  min-height: 0;
  font-size: clamp(1.8rem, 9vw, 2.6rem);
  font-weight: 850;
  background:
    linear-gradient(160deg, hsl(var(--hue) 40% 22%) 0%, hsl(var(--hue) 35% 15%) 100%);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  color: var(--ink);
}

.room-size:active {
  background: linear-gradient(160deg, var(--accent) 0%, var(--accent-deep) 100%);
  color: var(--on-accent);
}

.room-chosen {
  display: flex;
  align-items: center;
  gap: 0.8rem;
  padding: 0.75rem 0.9rem;
  border-radius: var(--radius);
  background: var(--bg-lift);
  border: 1px solid var(--line);
}

.room-badge {
  display: flex;
  flex-direction: column;
  align-items: center;
  line-height: 1;
  flex: 0 0 auto;
}

.room-badge b {
  font-size: 1.9rem;
  font-weight: 850;
  color: var(--accent);
}

.room-badge span {
  font-size: 0.62rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-dim);
}

.room-names {
  flex: 1;
  min-width: 0;
  color: var(--ink-dim);
  font-size: 0.9rem;
}

/* Setup, for a game opened without a room ---------------------------------- */

.players {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.player-row {
  display: flex;
  gap: 0.5rem;
}

.player-name {
  flex: 1;
  font: inherit;
  font-size: 1.05rem;
  padding: 0.85rem 1rem;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  background: var(--bg-lift);
  color: var(--ink);
  min-width: 0;
}

.player-name::placeholder {
  color: hsl(var(--hue) 15% 55%);
}

.player-drop {
  flex: 0 0 3rem;
  background: transparent;
  border: 1px solid var(--line);
  color: var(--ink-dim);
  font-size: 1.25rem;
  padding: 0;
}

.note-input {
  font: inherit;
  font-size: 1rem;
  padding: 0.8rem 1rem;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  background: var(--bg-lift);
  color: var(--ink);
  width: 100%;
  text-align: center;
}

.note-input::placeholder {
  color: hsl(var(--hue) 15% 55%);
}

/* Taking the room's tally -------------------------------------------------- */

/*
 * One button per possible count, so recording a vote the room already cast is a
 * single tap. auto-fit rather than a fixed column count because the range is
 * 0..(players-1): three players make three buttons and twelve make thirteen, and
 * both have to stay thumb-sized without the grid being told which case it is in.
 */
.tally-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(4rem, 1fr));
  gap: 0.6rem;
}

.tally {
  min-height: 4rem;
  min-width: 0;
  font-size: 1.5rem;
  font-weight: 800;
  background: var(--bg-lift);
  border: 1px solid var(--line);
  color: var(--ink);
}

.tally:active {
  background: linear-gradient(160deg, var(--accent), var(--accent-deep));
  color: var(--on-accent);
}

/* The shared "three, two, one" beat, big enough to read across a room. */
.countdown {
  min-height: 5rem;
  font-size: 2rem;
  font-weight: 850;
  letter-spacing: 0.04em;
  background: hsl(var(--hue) 60% 60% / 0.06);
  border: 2px dashed var(--line-strong);
  color: var(--accent);
}

.countdown:disabled {
  opacity: 1;
  border-style: solid;
  background: hsl(var(--hue) 70% 55% / 0.14);
}

/* Picking a person, and marking several ------------------------------------ */

/*
 * Names, not numbers, so the grid has to cope with "Al" beside "Player C".
 * auto-fit with a floor rather than a fixed column count: three players get
 * three wide buttons, twelve get a dense grid, and neither needs its own rule.
 */
.pick-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(7.5rem, 1fr));
  gap: 0.6rem;
}

.pick {
  min-height: 3.5rem;
  /*
   * A grid item defaults to `min-width: auto`, which is its longest unbreakable
   * word — so an 18-character name in a room of twelve made the grid wider than
   * the phone and scrolled the whole page sideways. `anywhere` is what lets the
   * name break for that measurement; `break-word` alone does not affect
   * intrinsic sizing, which is why the rule on body was not enough on its own.
   */
  min-width: 0;
  overflow-wrap: anywhere;
  font-size: 1.05rem;
  font-weight: 700;
  background: var(--bg-lift);
  border: 1px solid var(--line);
  color: var(--ink);
}

.pick:active {
  background: linear-gradient(160deg, var(--accent), var(--accent-deep));
  color: var(--on-accent);
}

/* Set apart, because "the room split" is an outcome and not a player. */
.pick.nobody {
  grid-column: 1 / -1;
  background: transparent;
  border-style: dashed;
  color: var(--ink-dim);
}

/* Chosen, in a multi-select. Colour alone would not survive a colourblind
   reader or a bright room, so the border thickens too. */
.pick.on {
  background: linear-gradient(160deg, var(--accent), var(--accent-deep));
  color: var(--on-accent);
  border-color: var(--ink);
  border-width: 2px;
}

/* The list you have to remember ------------------------------------------- */

/*
 * Numbered, because position is one of the hooks people use to hold a list, and
 * spaced out so the eye can group them. Two columns once there are enough to
 * need them — a vertical list of ten runs off a short phone.
 */
.recall-list {
  list-style: decimal inside;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
  gap: 0.45rem 1rem;
  text-align: left;
  padding: 1rem 1.1rem;
  border-radius: var(--radius);
  background: var(--bg-lift);
  border: 1px solid var(--line);
}

.recall-item {
  font-size: 1.2rem;
  font-weight: 700;
  letter-spacing: -0.01em;
}

.recall-item::marker {
  color: var(--ink-dim);
  font-weight: 500;
  font-size: 0.85rem;
}

/* Clocks ------------------------------------------------------------------- */

/*
 * Read from across a table by somebody who is not holding the phone, which is
 * the whole point of it being on the table. Tabular figures so the width does
 * not jitter as the digits change.
 */
.clock {
  font-size: clamp(3.5rem, 18vw, 5.5rem);
  font-weight: 850;
  line-height: 1;
  letter-spacing: -0.035em;
  font-variant-numeric: tabular-nums;
  text-shadow: 0 0 40px hsl(var(--hue) 90% 60% / 0.25);
}

.clock.out {
  color: var(--bad);
  text-shadow: 0 0 40px hsl(352 90% 60% / 0.35);
}

/* The letter in Alphabet Categories: one character, as big as it will go. */
.letter {
  font-size: clamp(4rem, 24vw, 7rem);
  font-weight: 850;
  line-height: 1;
  color: var(--accent);
  text-shadow: 0 0 50px hsl(var(--hue) 90% 60% / 0.35);
}

/*
 * The one big line on every game screen.
 *
 * It holds anything from "Sports" to a twelve-word accusation, so it comes in
 * two sizes and the page picks one by length. A single clamp cannot do this: set
 * it for the sentence and the one-word categories look apologetic; set it for
 * the word and the sentences wrap five times.
 */
.headline {
  font-size: clamp(1.5rem, 6.2vw, 2rem);
  font-weight: 800;
  letter-spacing: -0.025em;
  line-height: 1.2;
}

.headline.short {
  font-size: clamp(2.25rem, 11vw, 3.25rem);
  font-weight: 850;
  letter-spacing: -0.035em;
  line-height: 1.03;
}

/* A statement to argue over, which reads as a sentence rather than a label. */
.statement {
  font-size: clamp(1.5rem, 6.5vw, 2rem);
  font-weight: 750;
  line-height: 1.25;
  letter-spacing: -0.02em;
}

.side-for,
.side-against {
  font-weight: 700;
  padding: 0.65rem 1rem;
  border-radius: 14px;
  border: 1px solid var(--line);
}

.side-for {
  color: var(--good);
  background: hsl(162 70% 45% / 0.08);
}

.side-against {
  color: var(--bad);
  background: hsl(352 90% 65% / 0.08);
}

/* A number too big to lay out as buttons ----------------------------------- */

.stepper {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1rem;
}

.step {
  flex: 0 0 4.5rem;
  min-height: 4.5rem;
  font-size: 2rem;
  background: var(--bg-lift);
  border: 1px solid var(--line);
}

.step-value {
  font-size: clamp(3rem, 16vw, 4.5rem);
  font-weight: 850;
  min-width: 4rem;
  font-variant-numeric: tabular-nums;
  color: var(--accent);
}

/* Quoting a take back ------------------------------------------------------ */

.take {
  font-size: clamp(1.4rem, 6.5vw, 1.9rem);
  font-weight: 650;
  line-height: 1.3;
  letter-spacing: -0.015em;
  padding: 1.25rem;
  border-radius: var(--radius);
  background: var(--bg-lift);
  border: 1px solid var(--line);
  /*
   * The take scrolls inside its own box rather than growing the screen, because
   * on a 320px phone the longest one the game accepts pushed "Bad take" off the
   * bottom while "Good take" stayed in view. That is not a layout blemish, it is
   * a thumb on the scales: the vote that needs no scrolling is the vote that
   * gets cast.
   */
  max-height: 32vh;
  overflow-y: auto;
}

.take.small {
  font-size: 1.05rem;
  font-weight: 500;
  color: var(--ink-dim);
  padding: 0.85rem 1rem;
}

/* The reveal --------------------------------------------------------------- */

.verdict {
  font-size: clamp(1.85rem, 8.5vw, 2.6rem);
  font-weight: 850;
  letter-spacing: -0.03em;
  line-height: 1.05;
}

.split-bar {
  display: flex;
  height: 1.6rem;
  border-radius: 999px;
  overflow: hidden;
  background: var(--bg-lift);
  border: 1px solid var(--line);
}

.split-fill {
  transition: width 0.35s cubic-bezier(0.2, 0.8, 0.2, 1);
}

.split-fill.good {
  background: linear-gradient(90deg, hsl(162 70% 45%), var(--good));
}

.split-fill.bad {
  background: linear-gradient(90deg, var(--bad), hsl(352 90% 68%));
}

.split-legend {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  margin-top: 0.6rem;
  font-size: 0.85rem;
  color: var(--ink-dim);
}

.side {
  text-align: left;
  flex: 1;
  min-width: 0;
}

.side.right {
  text-align: right;
}

.side b {
  font-size: 1.5rem;
  color: var(--ink);
}

.chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
  margin-top: 0.4rem;
}

.side.right .chips {
  justify-content: flex-end;
}

.chip {
  background: var(--bg-lift);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 0.15rem 0.6rem;
  font-size: 0.8rem;
  color: var(--ink);
}

.points {
  font-size: 1.2rem;
  font-weight: 750;
  color: var(--accent);
}

.scores {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}

.scores li {
  display: flex;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.65rem 0.95rem;
  border-radius: 14px;
  background: var(--bg-lift);
  border: 1px solid var(--line);
}

/* Same flex measurement problem as .pick: without this the name sets the row's
   minimum width and a long one pushes the scoreboard off the screen. */
.scores li span {
  min-width: 0;
  overflow-wrap: anywhere;
}

.scores li b {
  font-variant-numeric: tabular-nums;
}

.big-scores li:first-child {
  border-color: var(--line-strong);
  background: linear-gradient(160deg, hsl(var(--hue) 45% 22%), var(--bg-lift));
}

.big-scores li:first-child b {
  color: var(--accent);
}

.best {
  margin-top: 0.5rem;
  color: var(--ink-dim);
  font-size: 0.9rem;
}

.best blockquote {
  color: var(--ink);
  font-size: 1.1rem;
  font-weight: 650;
  margin: 0.4rem 0 0.2rem;
}

.best cite {
  font-style: normal;
  color: var(--ink-dim);
}

.over-best-label {
  text-transform: uppercase;
  letter-spacing: 0.1em;
  font-size: 0.72rem;
  color: var(--accent);
}

/* Top bar ------------------------------------------------------------------ */

.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  max-width: 34rem;
  margin: 0 auto;
  padding: calc(0.75rem + env(safe-area-inset-top)) 1.25rem 0;
}

.topbar-back {
  color: var(--ink-dim);
  text-decoration: none;
  font-size: 0.85rem;
  font-weight: 650;
}

.topbar-quit {
  background: transparent;
  border: 1px solid var(--line);
  color: var(--ink-dim);
  min-height: 2.25rem;
  padding: 0.3rem 0.8rem;
  font-size: 0.8rem;
  font-weight: 650;
}

.topbar-confirm {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.8rem;
  color: var(--ink-dim);
}

/* The hub and the catalogue ------------------------------------------------ */

/*
 * The hub scrolls, unlike a game screen — ten cards is a list, not a screen — so
 * it opts out of the full-height centring the game screens use.
 */
.hub-screen {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  padding: 1.25rem 0 0;
}

.hub-head {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  text-align: center;
}

.hub-head .topbar-back {
  align-self: flex-start;
}

.hub-note {
  color: var(--ink-dim);
  font-size: 0.92rem;
  border-left: 2px solid var(--accent);
  padding-left: 0.9rem;
  text-align: left;
}

.hub-heading {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--ink-dim);
  font-weight: 700;
  margin-top: 0.5rem;
}

.hub-grid {
  display: grid;
  gap: 0.75rem;
}

/*
 * Each card carries the hue of the game it opens, so the list reads as ten
 * things rather than one list — and the page you land on is the colour of the
 * card you pressed.
 */
.game-card {
  display: block;
  position: relative;
  text-align: left;
  text-decoration: none;
  color: inherit;
  background: linear-gradient(160deg, var(--bg-card), hsl(var(--hue) 20% 11%));
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: 1.1rem 1.1rem 1.1rem 1.35rem;
  overflow: hidden;
  transition: transform 0.12s ease, border-color 0.15s ease;
}

/* The spine: the only part of a card that is unmistakably one game's colour. */
.game-card::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 4px;
  background: linear-gradient(180deg, var(--accent), var(--accent-deep));
}

.game-card:active {
  transform: scale(0.985);
  border-color: var(--line-strong);
}

.game-card h3 {
  font-size: 1.3rem;
  font-weight: 800;
  letter-spacing: -0.025em;
  line-height: 1.12;
}

.game-card p {
  color: var(--ink-dim);
  font-size: 0.93rem;
  margin: 0.45rem 0 0.7rem;
}

/* A game the room is too small for. Still openable — it explains itself when
   you get there — but visibly not on offer. */
.game-card.locked {
  opacity: 0.42;
}

.game-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
}

.meta-pill {
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  padding: 0.2rem 0.6rem;
  border-radius: 999px;
  background: hsl(var(--hue) 70% 60% / 0.14);
  color: var(--accent);
  border: 1px solid hsl(var(--hue) 70% 60% / 0.22);
}

.meta-pill.lead {
  background: linear-gradient(160deg, var(--accent), var(--accent-deep));
  color: var(--on-accent);
  border-color: transparent;
}

.meta-pill.hand {
  background: hsl(var(--hue) 10% 60% / 0.1);
  color: var(--ink-dim);
  border-color: var(--line);
}

.catalog-link {
  display: block;
  margin-top: 0.9rem;
  text-align: center;
  color: var(--accent);
  text-decoration: none;
  font-weight: 700;
  font-size: 0.95rem;
}

/* Two columns of cards once there is room for them, which there is not on a
   phone — and the hub is mostly read on a phone. */
@media (min-width: 46rem) {
  .hub-grid {
    grid-template-columns: 1fr 1fr;
  }

  main {
    max-width: 48rem;
  }

  body.game main {
    max-width: 34rem;
  }

  .room-grid {
    grid-template-columns: repeat(6, 1fr);
  }
}

/*
 * Short phones. The tally screen is the one that has to fit without scrolling:
 * a room of twelve is thirteen buttons plus the countdown, and on a 568px-tall
 * screen at full height they do not fit. They shrink here rather than wrap into
 * a scroll, because a count nobody can see all of is a count somebody mistaps.
 */
@media (max-height: 600px) {
  .tally {
    min-height: 3.25rem;
  }

  .pick {
    min-height: 3rem;
  }

  .countdown {
    min-height: 3.75rem;
  }

  .clock {
    font-size: clamp(2.75rem, 14vw, 4rem);
  }

  .screen {
    gap: 0.7rem;
  }
}

@media (prefers-reduced-motion: reduce) {
  button,
  .game-card,
  .split-fill {
    transition: none;
  }
}

/* The ?debug swap readout. Deliberately plain: it is an instrument, not a screen. */
.swaps {
  margin: 1rem;
  padding: 0.75rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--bg-lift);
  color: var(--ink-dim);
  font: 12px/1.5 ui-monospace, SFMono-Regular, Menlo, monospace;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  max-height: 40vh;
  overflow-y: auto;
}
