/* Local palette: one-off colors for this page, named by role. Global tokens live in style.css. */
:root {
  --gm-game-stage-bg: #1d1438;
  --gm-hs-table-rank: #e4e1ef;
  --gm-hs-table-rank-2: #f2bd8c;
  --gm-medal-edge: #b9b0d0;
  --gm-medal-bg: #e79a5c;
  --gm-medal-bg-2: #d9deea;
}
/* Bubble Arcade: arcade cards, the canvas stage and the luck games' card (their own styles are in luck.css). Built on style.css tokens. */
.game-grid { display: grid; gap: 16px; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); }
.game-card {
  display: grid; align-content: start; gap: 4px;
  padding: 12px; background: var(--tint);
  border: 2px solid var(--ink); border-radius: var(--r-tile); box-shadow: var(--shadow-sm);
}
.game-card h3 { margin: 6px 0 0; }
.game-card h3 a { color: var(--ink); text-decoration: none; }
.game-card p { margin: 0; font-size: var(--fs-sm); }
.game-card .btn-row { margin-top: 6px; }
.game-meta { display: flex; flex-wrap: wrap; gap: 4px; }
.game-thumb {
  display: block; width: 100%; height: auto; aspect-ratio: 2; overflow: hidden;
  border: 2px solid var(--ink); border-radius: var(--r-sm);
  background: var(--paper);
  transition: transform .15s var(--ease-out);
}
.game-thumb > :is(svg, img) { aspect-ratio: 2; min-height: 0; }
.game-thumb * { animation: none !important; } /* Quiet catalog previews; the destination banner keeps its motion. */
@media (hover: hover) and (pointer: fine) { .game-card a:hover .game-thumb { transform: rotate(-1.5deg) scale(1.02); } }

@media (max-width: 560px) { /* thumb beside the title on phones, so the arcade isn't a column of giant pictures */
  .game-card { grid-template-columns: 96px minmax(0, 1fr); column-gap: 12px; }
  .game-card > a:first-child { grid-row: span 2; }
  .game-card h3 { margin-top: 0; text-align: center; align-self: center; }
  .game-card > .game-meta, .game-card > .btn-row { grid-column: 1 / -1; }
}

.game-page { display: grid; grid-template-columns: minmax(0, 1fr); gap: 12px; } /* minmax: a long café pick can't widen the page */
.game-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 18px; font-weight: 700; }
.game-bar #g-score { font: 700 1.4rem var(--display); color: var(--land-accent); font-variant-numeric: tabular-nums; }
.game-bar label { display: flex; align-items: center; gap: 8px; min-width: 0; }
.game-bar select { width: auto; min-width: 0; margin: 0; }
.game-sound { display: flex; gap: 8px; margin-left: auto; } /* Sound + Music stay a pair at the bar's end */
/* The cabinet: the canvas sits in a land-tinted frame so it reads as the page's centerpiece, not a box off to one side */
.game-stage {
  display: grid; place-items: center; padding: clamp(10px, 3vw, 26px);
  border: 2px solid var(--ink); border-radius: var(--r-card);
  background:
    radial-gradient(circle at 8% 18%, #fff 0 2px, transparent 3px),
    radial-gradient(circle at 93% 80%, #fff 0 2px, transparent 3px),
    linear-gradient(150deg, var(--land-from), var(--land-to));
}
/* The ink edge is a box-shadow ring, not a border: host.js maps pointers with getBoundingClientRect(),
   and a border would sit inside that box and skew every click by its width. The height term keeps the whole
   board on screen on a landscape phone; aspect-ratio keeps it 4:3, so the mapping stays uniform. */
.game-stage canvas {
  width: min(100%, 960px); height: auto; aspect-ratio: 4 / 3; display: block;
  border: 0; border-radius: 16px; box-shadow: 0 0 0 var(--line) var(--ink), 6px 6px 0 var(--line) var(--ink);
  background: var(--gm-game-stage-bg); touch-action: none; cursor: pointer;
}
/* Phones: the frame gives its padding to the board, which is drawn at 640 wide and shrinks every tap target with it */
@media (max-width: 560px) { .game-stage { margin-inline: -10px; padding: 6px; } }
/* The board and its card share one grid cell, so a tall card (a phone's title screen) grows the stage instead of scrolling */
.game-stage { grid-template-columns: minmax(0, 1fr); } /* a long café pick in the card can't widen the stage */
.game-stage > *, .game-stage::after { grid-area: 1 / 1; }
.game-stage:has(> .g-card[hidden]) { touch-action: none; user-select: none; -webkit-user-select: none; -webkit-touch-callout: none; } /* mid-run: no scroll, zoom or text selection */
/* The cheering pet off the board (kit.js), in the player's spare room: under the board, up a wide side gutter, or in the side column */
.game-player { position: relative; }
/* Double-tapping the board or its controls must not select text or open the Copy / Look up menu; typed fields stay selectable */
.game-player { user-select: none; -webkit-user-select: none; -webkit-touch-callout: none; touch-action: manipulation; }
.game-player :where(input, textarea) { user-select: text; -webkit-user-select: text; }
.g-cheer { position: absolute; z-index: 2; display: flex; align-items: flex-end; gap: 6px; pointer-events: none; animation: pop-in .25s var(--ease-out); }
.g-cheer[hidden] { display: none; }
.g-cheer.is-side { flex-direction: column; align-items: flex-start; }
.g-cheer img { width: 64px; height: 64px; flex: none; }
.g-cheer p { margin: 0 0 24px; max-width: 15rem; padding: 6px 12px; background: var(--card); border: var(--line) solid var(--ink); border-radius: var(--r-tile); font: 700 var(--fs-sm) var(--display); line-height: 1.25; }
.g-cheer.is-side p { margin: 0; }
.g-cheer.is-small img { width: 48px; height: 48px; }
.g-cheer.is-small p { padding: 4px 8px; font-size: var(--fs-xs); }

/* ---------- Title, pause and game-over cards (host.js) ---------- */
.g-card {
  align-self: stretch; justify-self: stretch; z-index: 1; display: grid; grid-template-columns: minmax(0, 1fr); place-items: center; min-width: 0; min-height: 0; overflow: auto;
  padding: 12px; border-radius: 16px; background: color-mix(in srgb, var(--ink) 42%, transparent); overscroll-behavior: contain;
}
.g-card[hidden] { display: none; }
.g-panel {
  display: grid; grid-template-columns: minmax(0, 1fr); gap: 10px; justify-items: center; width: min(100%, 32rem); padding: 16px 18px; text-align: center;
  background: var(--card); border: var(--line) solid var(--ink); border-radius: var(--r-card); box-shadow: var(--shadow);
  animation: g-pop .22s var(--ease-out);
}
/* The card must show even when it pops up on an idle page: shell.js's battery pauses every animation after 20 s with no
   input (html.anim-paused), which froze the old opacity-0 pop-in at its first frame on a run that ended on its own.
   So the pop starts from a visible card, and the battery leaves it running. */
@keyframes g-pop { from { transform: scale(.92); } }
.anim-paused .g-panel, .anim-off .g-panel { animation-play-state: running !important; }
.g-panel > * { margin: 0; max-width: 100%; }
.g-panel [hidden] { display: none; }
.g-card.is-loud .g-panel { box-shadow: 0 0 0 4px var(--sun), var(--shadow); }
.g-title { font-size: 1.45rem; line-height: 1.15; }
.g-who { display: flex; align-items: center; justify-content: center; gap: 12px; }
.g-pet { display: block; width: 88px; height: 88px; flex: none; animation: bob 1.1s ease-in-out infinite alternate; }
/* The pet inside is the /art/pet picture put inline (host.js cardPet()): drawn like the <img> it replaced, clipped to its
   box, glinting but not breathing or blinking (the picture never did) */
.g-pet > :is(svg, img) { display: block; width: 100%; height: 100%; max-width: none; overflow: hidden; }
.g-pet :is(.pet-idle, .pet-eyes) { animation: none; }
.g-card[data-state="paused"] .g-pet { animation: none; }
.g-lines { display: grid; gap: 4px; justify-items: start; text-align: left; min-width: 0; }
.g-lines p { margin: 0; }
.g-score { display: flex; align-items: baseline; gap: 8px; }
.g-score span { color: var(--muted); font-weight: 700; }
.g-score b { font: 700 2rem/1 var(--display); color: var(--pink); font-variant-numeric: tabular-nums; }
.g-tags { display: flex; flex-wrap: wrap; gap: 6px; color: var(--muted); font-weight: 700; }
.g-say { font-size: var(--fs-sm); }
.g-say b::after { content: ':'; }
.g-medals { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; }
.g-medals .medal-chip.now { box-shadow: 0 0 0 3px var(--sun); animation: pop-in .4s var(--ease-out) .3s both; }
.g-next { display: grid; gap: 4px; width: min(100%, 20rem); font-weight: 700; font-size: var(--fs-sm); }
.g-bar { display: block; height: 14px; overflow: hidden; border: 2px solid var(--ink); border-radius: 999px; background: var(--tint-2); }
.g-bar i { display: block; height: 100%; width: calc(var(--p, 0) * 100%); background: var(--sun); transition: width .8s var(--ease-out) .15s; }
.g-pay { font-weight: 600; }
.g-rival { padding: 6px 12px; border-radius: var(--r-sm); background: var(--hi-soft); font-weight: 700; }
/* Game-over faces (host.js): one tap says how the run felt, then "Tell us more" opens the feedback sheet. */
.g-faces { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 8px 12px; font-weight: 700; }
.g-faces[hidden] { display: none; }
.g-face { display: grid; place-items: center; width: 48px; height: 48px; padding: 0; cursor: pointer; background: none; border: 0; border-radius: 50%; color: var(--sun-soft); }
.g-face[data-face="1"] { color: var(--sky-soft); }
.g-face[data-face="3"] { color: var(--sun); }
.g-face:hover svg { transform: scale(1.1); }
.g-face svg { transition: transform .15s var(--ease-out); }
.g-face:focus-visible { outline: 3px solid var(--ink); outline-offset: 2px; box-shadow: 0 0 0 8px var(--sky); }
.g-picks { display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: 12px 16px; font-weight: 700; }
.g-picks label { display: inline-flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: 8px; min-width: 0; max-width: 100%; }
.g-picks select { width: auto; min-width: 0; max-width: 100%; margin: 0; text-overflow: ellipsis; }
.g-how { display: grid; gap: 8px; justify-items: center; width: 100%; }
.g-how details { width: 100%; text-align: left; }
.g-how summary { width: fit-content; margin-inline: auto; font-weight: 800; cursor: pointer; }
.g-how details p { margin: 8px 0 0; font-size: var(--fs-sm); }
.g-goal { margin: 0; }
.g-goal b, .game-how .g-goal b { margin-right: 6px; padding: 0 8px; border: 2px solid var(--ink); border-radius: 999px; background: var(--sun); font: 700 var(--fs-xs) var(--display); }
.g-rows { display: grid; gap: 8px; width: fit-content; max-width: 100%; margin: 0; padding: 0; list-style: none; text-align: left; }
.g-rows li { display: grid; grid-template-columns: 6rem minmax(0, 1fr); align-items: center; gap: 10px; font-weight: 600; }
.g-keys { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 4px; }
.g-keys svg { width: 28px; height: 28px; fill: none; stroke: var(--ink); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.g-rows kbd { min-width: 2em; padding: 2px 6px; text-align: center; font: 700 var(--fs-xs) var(--display); background: var(--card); border: 2px solid var(--ink); border-radius: 6px; box-shadow: 0 2px 0 var(--ink); }
.g-mode { color: var(--muted); font-size: var(--fs-sm); font-weight: 700; }
.g-actions { justify-content: center; }
/* Start buttons: glowing gold "Play for Glimmers" beside a plain "Just for fun" */
.g-actions > [data-go], .g-actions > [data-fun] { min-height: 52px; }
/* The glow pulses on the GPU: the button keeps the small glow, and a copy of its outline (::after, the gloss is ::before)
   carrying the big glow fades in and out. It used to animate box-shadow, a main-thread repaint every frame while on
   screen, which on a still game's card was the only thing drawing (about 100 paints a second). The copy sits at z-index -1
   inside the button row (isolated), so like the old glow it paints under the button's own hard shadow and under the next
   button, and over the panel's text. Pressed, disabled and reduce-motion looks are as before: the old animation outranked
   .btn:active and .btn:disabled, and under body.reduce-motion the button had .btn's plain shadow. */
.g-actions { isolation: isolate; }
.btn-gold { background: var(--sun); color: var(--ink); font-weight: 800; }
.btn-gold, .btn-gold:is(:active, :disabled) { box-shadow: var(--shadow-sm), 0 0 6px 1px var(--sun-glow); }
.btn-gold::after {
  content: ''; position: absolute; z-index: -1; inset: calc(-1 * var(--line)); border-radius: inherit; pointer-events: none; opacity: 0;
  box-shadow: 0 0 18px 6px var(--sun-glow);
  animation: gold-glow 2.4s ease-in-out infinite;
}
@keyframes gold-glow { 50% { opacity: 1; } }
/* .btn:hover's filter makes the button its own stacking context, which lifts the copy above the button's hard shadow:
   on hover the copy repeats that shadow over its glow (ink over ink, so the fade never shows) */
@media (hover: hover) and (pointer: fine) { .btn-gold:hover::after { box-shadow: var(--shadow-sm), 0 0 18px 6px var(--sun-glow); } }
.reduce-motion .btn-gold { box-shadow: 0 4px 0 var(--ink); }
.reduce-motion .btn-gold:active { box-shadow: 0 1px 0 var(--ink); }
@media (prefers-reduced-motion: reduce) {
  .btn-gold, .reduce-motion .btn-gold { box-shadow: var(--shadow-sm), 0 0 12px 3px var(--sun-glow); }
  .btn-gold:active, .reduce-motion .btn-gold:active { box-shadow: 0 1px 0 var(--ink); }
  .btn-gold:disabled, .reduce-motion .btn-gold:disabled { box-shadow: 0 4px 0 var(--ink); }
  .btn-gold::after { display: none; }
}
.g-foot { color: var(--muted); font-size: var(--fs-sm); }
.g-foot:empty { display: none; }
@media (max-width: 560px) {
  .g-card { padding: 8px; }
  .g-panel { padding: 14px 12px; gap: 12px; }
  .g-actions > :is([data-go], [data-fun]) { flex: 1 1 100%; }
  .g-actions > :not([data-go], [data-fun]) { flex: 1 1 0; }
  .g-faces > span { flex: 1 1 100%; } /* the question on its own line, the three faces in a row under it */
}
@media (max-height: 600px) and (orientation: landscape) {
  .g-panel { grid-template-columns: repeat(2, minmax(0, 1fr)); width: min(100%, 48rem); gap: 8px 16px; padding: 12px 16px; }
  .g-title, .g-how, .g-actions, .g-foot { grid-column: 1 / -1; }
  .g-card { place-items: safe center; padding: 6px; }
  .g-pet { width: 56px; height: 56px; }
  .g-title { font-size: 1.15rem; }
  .g-score b { font-size: 1.5rem; }
  .g-say, .g-rival, .g-pay, .g-next { font-size: var(--fs-xs); }
  .g-medals { gap: 4px; }
  .g-medals .medal-chip { padding: 1px 8px 1px 4px; font-size: var(--fs-xs); }
  .g-actions .btn { min-height: 44px; padding-block: 6px; }
}
/* The page's how-to, folded (the start card already shows the goal): the card's rows, the story, the full rules, the pay */
.game-how .g-rows { margin: 10px 0; }
.game-how > summary { font: 700 1.2rem var(--display); cursor: pointer; width: fit-content; }
/* /games hub: medals, energy, tickets and the house rule, folded under the one-line lede (.ah-how) */
.g-rules { margin: 8px 0 0; padding: 0; list-style: none; display: grid; gap: 4px; font-size: var(--fs-sm); text-align: left; }

/* Dedicated play view: the board owns the space, with controls outside the artwork. */
.game-player { display: grid; gap: 12px; min-width: 0; }
.player-toolbar { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.player-toolbar strong { margin-right: auto; font-family: var(--display); }
.player-score { white-space: nowrap; font-variant-numeric: tabular-nums; }
.player-toolbar .btn { min-height: 44px; }
.player-field { display: grid; grid-template-columns: minmax(0, 1fr); gap: 12px; min-width: 0; min-height: 0; }
.player-controls { display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; align-content: center; }
.player-control { min-width: 64px; min-height: 54px; flex: 1 1 80px; max-width: 200px; touch-action: none; user-select: none; -webkit-user-select: none; -webkit-touch-callout: none; }
.player-control.is-held, .player-control[aria-pressed="true"] { background: var(--pick); box-shadow: none; transform: translateY(2px); }
.player-hint { margin: 0; color: var(--muted); font-size: 1rem; }
.game-player [hidden] { display: none; }
.game-view-open { overflow: hidden; }
.game-dialog {
  position: fixed; inset: var(--player-top, 0px) 0 auto; margin: 0;
  width: 100%; max-width: none; height: var(--player-height, 100dvh); max-height: none;
  padding: max(8px, env(safe-area-inset-top)) max(6px, env(safe-area-inset-right)) max(8px, env(safe-area-inset-bottom)) max(6px, env(safe-area-inset-left));
  border: 0; background: var(--paper); color: var(--ink); overscroll-behavior: contain; touch-action: manipulation; /* no double-tap zoom */
}
.game-dialog::backdrop { background: var(--ink); }
.game-dialog .game-player { height: 100%; display: flex; flex-direction: column; gap: 8px; }
.game-dialog .player-toolbar { flex: none; }
.game-dialog .player-field { flex: 1; grid-template-rows: minmax(0, 1fr) auto; }
.game-dialog .game-stage { min-width: 0; min-height: 0; margin: 0; padding: 2px; border: 0; overflow: hidden; border-radius: var(--r-sm); }
.game-dialog canvas { max-width: none; flex: none; border-radius: 8px; box-shadow: 0 0 0 2px var(--ink); }
.game-dialog .g-card { border-radius: var(--r-sm); }
/* A card taller than the stage scrolls (the game-over card is ~780px; an iPhone in Home Screen mode leaves ~720 after
   the notch and home bar), so its buttons stay pinned to the bottom edge instead of sitting cut off below it. */
.game-dialog .g-actions { order: 1; position: sticky; bottom: 0; z-index: 1; padding-block: 8px; background: var(--card); } /* order: below the "tap anywhere" line */
.game-dialog .player-hint { display: none; } /* the start card shows the controls */
.game-dialog .player-input { flex: none; align-self: center; width: min(100%, 640px); margin: 0; font-size: 1rem; }
.game-dialog .game-send { flex: none; max-height: 28%; overflow: auto; padding: 8px 12px; }
.game-dialog .game-send [data-result] { font-size: 1rem; }
.game-dialog .send-pet { width: 48px; height: 48px; }
.game-dialog #g-again { display: none; } /* the toolbar always offers replay */
@media (max-width: 560px) {
  .player-toolbar strong { width: 100%; }
  .player-toolbar .btn { padding-inline: 12px; }
  .player-score { margin-right: auto; }
  .game-dialog .player-toolbar strong { width: auto; flex: 1; }
  .game-dialog .player-score { margin: 0; }
  .game-dialog #player-expand { margin-left: auto; }
  .game-dialog .player-control { min-height: 56px; }
}
.player-back-icon { display: none; }
/* Portrait: one 44px bar (name, score, Pause, a close icon) over the board. Mid-run the buttons sit in one thin strip
   laid over the bottom of the stage; the strip itself lets touches through to the stage, so host.js steers from it
   like the old pad (a drag stays one pointer-captured gesture across board and strip). host.js's tall-field height
   assumes this bar and strip: 160px with the dialog padding. */
@media (orientation: portrait) {
  .game-dialog .player-toolbar { flex-wrap: nowrap; min-height: 44px; }
  .game-dialog .player-toolbar strong { flex: 1; width: auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .game-dialog .player-score { margin: 0; }
  .game-dialog #player-expand { margin: 0; flex: none; width: 44px; padding: 0; }
  .game-dialog #player-expand > .player-back-icon { display: block; width: 20px; height: 20px; }
  .game-dialog #player-expand > .player-back-text { display: none; }
  .game-dialog .player-field { grid-template-rows: minmax(0, 1fr); --strip: 88px; }
  .game-dialog .player-field:has(> .player-controls:not([hidden])) > .game-stage:has(> .g-card[hidden]) { padding-bottom: var(--strip); }
  .game-dialog .player-field:has(> .game-stage > .g-card:not([hidden])) > .player-controls { display: none; } /* cards get the whole stage */
  .game-dialog .player-field > .game-stage { grid-area: 1 / 1; }
  .game-dialog .player-controls { grid-area: 1 / 1; align-self: end; z-index: 1; height: var(--strip); padding: 8px 2px 12px; flex-wrap: nowrap; gap: 8px; pointer-events: none; }
  .game-dialog .player-control { pointer-events: auto; order: 1; flex: 1 1 0; min-width: 44px; max-width: 120px; min-height: 44px; height: 100%; padding: 4px; font-size: var(--fs-sm); }
  .game-dialog .player-control[data-key="ArrowLeft"] { order: -1; }
  .game-dialog .player-control[data-key="ArrowRight"] { order: 2; }
  /* Drag-to-steer games: arrows at the two ends, specials by the right thumb, and the gap is the pad */
  .game-dialog .game-stage[data-pad] ~ .player-controls > .player-control { flex: 0 1 72px; }
  .game-dialog .game-stage[data-pad] ~ .player-controls::before {
    content: 'Touch here too'; order: 0; flex: 1 1 0; align-self: center; min-width: 0; text-align: center;
    color: #fff; font: 700 var(--fs-xs) var(--display); opacity: .85; text-shadow: 0 1px 0 var(--ink), 0 -1px 0 var(--ink), 1px 0 0 var(--ink), -1px 0 0 var(--ink);
  }
  .game-dialog .game-stage[data-pad] ~ .player-controls:has(> :nth-child(4))::before { content: ''; } /* too many buttons for words */
  /* Typing games: the book is width-bound, so the spare height gives the six word buttons two roomy rows */
  .game-dialog .player-field:has(+ .player-input) { --strip: 112px; }
  .game-dialog .player-field:has(+ .player-input) > .player-controls { flex-wrap: wrap; row-gap: 12px; align-content: stretch; padding-top: 4px; padding-bottom: 8px; }
  .game-dialog .player-field:has(+ .player-input) .player-control { flex-basis: 30%; max-width: none; height: auto; }
}
/* Short landscape (a phone on its side): the board gets the full height; toolbar and pads share a side column */
@media (orientation: landscape) and (max-height: 600px) {
  .game-dialog .game-player { display: grid; grid-template-columns: minmax(0, 1fr) 176px; grid-template-rows: auto minmax(0, 1fr); gap: 8px 12px; }
  .game-dialog .player-field { display: contents; }
  .game-dialog .game-stage { grid-column: 1; grid-row: 1 / -1; }
  .game-dialog .player-toolbar { grid-column: 2; grid-row: 1; flex-direction: column; align-items: stretch; flex-wrap: nowrap; gap: 8px; }
  .game-dialog .player-toolbar > * { margin: 0; }
  .game-dialog .player-toolbar strong { display: none; }
  .game-dialog .player-score { text-align: center; }
  .game-dialog .player-controls { grid-column: 2; grid-row: 2; gap: 12px; align-content: end; overflow: auto; }
  .game-dialog .player-control { min-width: 64px; min-height: 52px; flex-basis: 68px; padding: 6px; }
  .game-dialog :is(.player-input, .game-send) { grid-column: 1 / -1; }
}
.game-send { display: grid; gap: 8px; justify-items: start; background: var(--hi); border: var(--line) solid var(--ink); border-radius: var(--r-tile); padding: 14px 18px; box-shadow: var(--shadow-sm); }
.game-send[hidden] { display: none; } /* display: grid would otherwise beat the hidden attribute */
.game-send p { margin: 0; font-weight: 700; }
.game-send [data-result] { font: 600 1.15rem var(--display); }
.game-how { max-width: 70ch; }

/* High scores: numbers line up on the right; the podium gets gold, silver and bronze coins */
.hs-table :is(th, td):nth-child(n+3) { text-align: right; }
.hs-table :is(th, td):first-child { width: 1%; text-align: center; }
.hs-table td:nth-child(2) { overflow-wrap: anywhere; } /* long usernames wrap instead of pushing the page sideways on phones */
.rank { display: inline-grid; place-items: center; min-width: 30px; height: 30px; font: 700 1rem var(--display); }
.hs-table tbody tr:nth-child(-n+3) .rank { border: 2px solid var(--ink); border-radius: 50%; background: var(--rank, var(--sun)); box-shadow: 0 2px 0 var(--ink); }
.hs-table tbody tr:nth-child(2) { --rank: var(--gm-hs-table-rank); }
.hs-table tbody tr:nth-child(3) { --rank: var(--gm-hs-table-rank-2); }

.luck { display: grid; gap: 14px; }
.luck details summary { cursor: pointer; font-weight: 800; width: fit-content; }
.tweak { margin: 0; }

/* Pet energy: pips on each game's bar (the /games header draws tokens instead, .ah-tray) */
.energy-pips { display: inline-flex; gap: 3px; }
.energy-pips i { width: 12px; height: 18px; border: 2px solid var(--ink); border-radius: 4px; background: var(--tint-2); }
.energy-pips i.on { background: var(--lime); }
.g-energy { display: inline-flex; align-items: center; gap: 6px; font-weight: 700; }

/* The typing games' real text box (Letter Lanterns, Word Scramble) under the canvas, so phones get their keyboard. 16px+ stops iOS zooming in. */
.game-page .game-input { width: min(100%, 640px); justify-self: center; margin: 0; font: 700 1.2rem var(--display); text-align: center; text-transform: lowercase; }

/* House rule of the day: a spotlight card on /games, a gold ring on its arcade card, a note on its page */
.pill-hot { background: var(--sun); font-weight: 800; }
.game-card.is-featured { background: var(--hi); box-shadow: 0 0 0 3px var(--sun), var(--shadow-sm); }
.featured-game { display: grid; grid-template-columns: minmax(0, 220px) minmax(0, 1fr); gap: 18px; align-items: center; background: var(--hi-soft); }
.featured-game h2 { margin: 6px 0 4px; }
.featured-game h2 a { color: var(--ink); text-decoration: none; }
.featured-game p { margin: 0 0 8px; }
@media (max-width: 560px) { .featured-game { grid-template-columns: 96px minmax(0, 1fr); gap: 12px; align-items: start; } }
.featured-note { margin: 0; display: flex; flex-wrap: wrap; align-items: center; gap: 8px; font-weight: 700; }

/* Tickety's Prize Counter */
.ticket-pill { background: var(--land-from); font-weight: 800; font-variant-numeric: tabular-nums; }
.prize-shelf { display: grid; gap: 14px; grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); }
.prize {
  display: grid; grid-template-rows: auto auto 1fr auto auto; justify-items: center; gap: 6px; text-align: center; padding: 12px 10px;
  background: var(--card); border: 2px solid var(--ink); border-radius: var(--r-tile); box-shadow: var(--shadow-sm);
}
.prize small { color: var(--muted); font-size: var(--fs-sm); line-height: 1.3; }
.prize form { margin: 0; }
.prize.owned { background: var(--hi); }

/* Medals: three dots lit up to your best (cards), chips with the targets (game page) */
.medal-row { display: inline-flex; gap: 3px; align-items: center; padding: 3px 6px; background: var(--card); border: 2px solid var(--ink); border-radius: 999px; }
.medal { width: 14px; height: 14px; border-radius: 50%; border: 2px dashed var(--gm-medal-edge); background: var(--paper); flex: none; }
.medal.lit { border: 2px solid var(--ink); box-shadow: inset 0 -2px 0 rgb(0 0 0 / .15); }
.medal.m1.lit { background: var(--gm-medal-bg); }
.medal.m2.lit { background: var(--gm-medal-bg-2); }
.medal.m3.lit { background: var(--sun); }
.game-medals { margin: 0; display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; }
.medal-chip { display: inline-flex; align-items: center; gap: 6px; padding: 3px 12px 3px 6px; border: 2px solid var(--ink); border-radius: 999px; background: var(--card); font-size: var(--fs-sm); }
.medal-chip.lit { background: var(--hi); }
.medal-chip .medal { width: 18px; height: 18px; }
.medal-chip .medal-pay { color: var(--muted); font-weight: 600; }
.game-bar [hidden] { display: none; }

/* The result box wears the land colors and the pet; a medal run gets a medal-colored ring */
.game-send { grid-template-columns: auto minmax(0, 1fr); align-items: center; column-gap: 14px;
  background: linear-gradient(120deg, var(--hi) 55%, color-mix(in srgb, var(--land-from) 35%, var(--hi))); }
.send-pet { width: 72px; height: 72px; }
.game-send[data-medal="bronze"] { box-shadow: 0 0 0 4px var(--gm-medal-bg), var(--shadow-sm); }
.game-send[data-medal="silver"] { box-shadow: 0 0 0 4px var(--gm-medal-bg-2), var(--shadow-sm); }
.game-send[data-medal="gold"] { box-shadow: 0 0 0 4px var(--sun), var(--shadow-sm); }

/* House rule of the day, loud: thumb, pitch, and your pet cheering it on */
.featured-game { grid-template-columns: minmax(0, 200px) minmax(0, 1fr) minmax(0, 280px); position: relative; overflow: hidden;
  background: radial-gradient(circle at 92% 12%, #fff 0 3px, transparent 4px), radial-gradient(circle at 40% 90%, #fff 0 2px, transparent 3px),
    linear-gradient(135deg, var(--hi-soft), hsl(var(--h) 95% 90%)); box-shadow: 0 0 0 4px var(--sun), var(--shadow); } /* style-ok: color computed from a per-element custom property */
.featured-game h2 { font-size: 1.8rem; }
.fg-pet { align-self: center; }
.fg-pet .speech { font-size: var(--fs-sm); }
@media (max-width: 860px) { .featured-game { grid-template-columns: minmax(0, 180px) minmax(0, 1fr); } .fg-pet { grid-column: 1 / -1; } }
@media (max-width: 560px) {
  .featured-game { grid-template-columns: 96px minmax(0, 1fr); }
  .featured-game .fg-body { display: contents; }
  .featured-game .fg-thumb { grid-row: span 2; }
  .featured-game .fg-body > :not(.pill-hot, h2) { grid-column: 1 / -1; }
  .fg-pet { flex-direction: row; align-items: center; }
  .fg-pet svg { width: 80px; height: 80px; }
  /* phones: the house-rule card is one centered column (thumb, pill, name, text, medals, button, pet) */
  .featured-game { grid-template-columns: minmax(0, 1fr); justify-items: center; text-align: center; }
  .featured-game .fg-thumb { grid-row: auto; width: 140px; }
  .featured-game .btn-row { justify-content: center; }
  .fg-pet { flex-direction: column; }
}

/* Mobile sweep: centered result and prize-counter blocks, a tablet prize grid with no orphan row, high-score names that get the width */
.hs-table :is(th, td):nth-child(2) { width: 99%; } /* the player column soaks up the slack so names wrap at word ends, not letter by letter */
@media (min-width: 561px) and (max-width: 1100px) { .prize-shelf { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
@media (max-width: 560px) {
  .prize-shelf { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
  .prize { padding: 12px 8px; }
  .prize .btn { padding-inline: 8px; white-space: nowrap; font-size: .9rem; }
  .hs-table :is(th, td) { padding: 8px 6px; }
  /* result block: pet above, text and the replay button centered under it (the play dialog keeps its compact row) */
  .game-page .game-send { grid-template-columns: minmax(0, 1fr); justify-items: center; text-align: center; row-gap: 8px; }
  .game-page .game-send .btn-row { justify-content: center; }
  .game-page .game-send .btn-row .btn { width: 100%; }
}
@media (min-width: 561px) { .game-send { justify-content: center; text-align: left; } }
/* Tickety's counter: the keeper and the ticket line sit centered under the banner */
.prize-counter { text-align: center; }
.prize-counter .keeper { justify-content: center; text-align: left; }
@media (min-width: 768px) { .prize-counter { text-align: left; } .prize-counter .keeper { justify-content: flex-start; } } /* tablet and up: keeper and ticket line sit left like every other keeper head */

/* Phones: 12px between stacked rows in the touch-control grid and the game bar (was 10px) */
@media (max-width: 767px) { .player-controls { gap: 12px; } .game-bar { row-gap: 12px; } }
@media (max-width: 400px) { .prize form { width: 100%; } .prize .btn { width: 100%; min-width: 0; padding-inline: 4px; font-size: .85rem; } } /* 320: "Need 450 more" fits its half-width card */

/* Phones: the link pairs under game titles sit centered as an even-width pair */
@media (max-width: 767px) { .game-links { justify-content: center; width: 100%; } .game-links > .btn { flex: 1 1 0; max-width: 200px; } .head-row + .game-pills { margin-top: 12px; } }
@media (max-width: 767px) {
  .game-links.game-pills > .pill { flex: 0 1 auto; max-width: none; }
  .game-bar, .game-medals { justify-content: center; text-align: center; gap: 12px; }
  .game-sound { flex: 1 0 100%; justify-content: center; gap: 12px; margin-left: 0; } /* their own centered row, an even pair like .game-links */
  .game-sound > .btn { flex: 1 1 0; max-width: 200px; }
  .game-page .player-toolbar strong { display: none; } /* the h1 right above already names the game; the play view keeps it */
}
@media (max-width: 767px) { .luck > .tweak, .luck > .lede, .luck > .hint, .luck form > span.muted:last-child { text-align: center; flex: 1 0 100%; } } /* short status lines under the centered keeper and pool */

/* Wide desktops: five cards across the Arcade rows (a five-game row no longer leaves one orphan). */
@media (min-width: 1700px) { .game-grid { grid-template-columns: repeat(auto-fill, minmax(196px, 1fr)); } }

/* /games header: one card. Title, lede and a link-style How it works fold on the left; on the right the token booth
   (striped awning, the Glimling's face and line at the window, a counter with the token tray and the ticket slot). */
.ah-cols { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 420px); gap: 18px 32px; align-items: center; margin-top: 16px; }
.ah-cols.is-solo { grid-template-columns: minmax(0, 1fr); }
.ah-title h1 { margin-top: 0; }
.ah-lede { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 14px; }
.ah-lede .lede { margin: 0; }
.ah-how { max-width: 60ch; }
.ah-how[open] { flex-basis: 100%; }
.ah-how > summary { display: inline-flex; align-items: center; gap: 4px; min-height: 44px; cursor: pointer; list-style: none; color: var(--link); font-weight: 700; text-decoration: underline; text-underline-offset: 3px; }
.ah-how > summary::-webkit-details-marker { display: none; }
.ah-how > summary::after { content: ''; width: 6px; height: 6px; margin-left: 4px; border: solid currentColor; border-width: 0 2px 2px 0; transform: rotate(45deg) translateY(-2px); }
.ah-how[open] > summary::after { transform: rotate(-135deg) translate(-2px, 0); }
@media (hover: hover) and (pointer: fine) { .ah-how > summary:hover { text-decoration-thickness: 2px; } }
.ah-how .g-rules { margin: 0 0 4px; padding: 10px 14px; gap: 6px; background: var(--tint); border-radius: var(--r-sm); }

.ah-booth { position: relative; display: grid; gap: 12px; padding: 0 16px 16px; background: var(--sky-soft); border: var(--line) solid var(--ink); border-radius: var(--r-tile); overflow: hidden; }
.ah-booth.is-napping { background: var(--hi-soft); }
.ah-awning { height: 24px; margin: 0 -16px; border-bottom: var(--line) solid var(--ink);
  background: repeating-linear-gradient(90deg, var(--pink) 0 28px, var(--card) 28px 56px); }
.ah-window { display: flex; justify-content: center; }
.ah-say { display: flex; align-items: center; gap: 10px; min-width: 0; }
.ah-say .pet-face { flex: none; }
.ah-bub { position: relative; margin: 0; padding: 6px 12px; background: var(--card); border: 2px solid var(--ink); border-radius: var(--r-tile); font-size: var(--fs-sm); line-height: 1.35; }
.ah-bub::before { content: ''; position: absolute; left: -10px; top: calc(50% - 8px); border: 8px solid transparent; border-right-color: var(--ink); border-left: 0; }
.ah-bub b { margin-right: 2px; }
.ah-say:is(.is-nap, .is-tired) .ah-bub { color: var(--muted); }
.ah-nopet { margin: 0; }
.ah-counter { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 12px 16px; align-items: center; padding: 12px; background: var(--card); border: 2px solid var(--ink); border-radius: var(--r-sm); box-shadow: var(--shadow-sm); }
.ah-tokens { display: grid; gap: 6px; justify-items: start; }
.ah-meter { margin: 0; display: flex; flex-wrap: wrap; align-items: center; gap: 4px 10px; }
.ah-count { font-weight: 700; font-variant-numeric: tabular-nums; }
.ah-next { margin: 0; font-size: var(--fs-sm); }
.ah-tray { display: inline-flex; gap: 6px; padding: 6px 8px; background: var(--tint-2); border: 2px solid var(--ink); border-radius: 999px; }
.ah-tray i { width: 24px; height: 24px; border-radius: 50%; border: 2px dashed color-mix(in srgb, var(--ink) 35%, transparent); }
.ah-tray i.on { border: 2px solid var(--ink); background: radial-gradient(circle at 34% 30%, #fff 0 3px, transparent 4px), radial-gradient(circle, var(--sun) 0 6px, var(--sun-glow) 7px 8px, var(--sun) 9px); }
/* The ticket spool: a dark slot, a striped strip of tickets, and the front ticket with the count, tilted as if just spat out */
.ah-spool { display: grid; justify-items: center; min-width: 150px; padding-bottom: 6px; color: var(--ink); text-decoration: none; font-family: var(--display); line-height: 1.15; }
.ah-slot { position: relative; z-index: 1; width: 100%; height: 10px; background: var(--ink); border-radius: 999px; }
.ah-tail { width: calc(100% - 24px); height: 20px; margin-top: -4px; border-inline: 2px solid var(--ink);
  background: repeating-linear-gradient(180deg, var(--sun) 0 8px, var(--ink) 8px 10px); }
.ah-front { display: grid; justify-items: center; width: calc(100% - 24px); padding: 6px 8px 8px; background: var(--sun);
  border: 2px solid var(--ink); border-top-style: dashed; border-radius: 0 0 var(--r-sm) var(--r-sm); box-shadow: var(--shadow-sm);
  transform: rotate(-4deg); transform-origin: 50% 0; transition: transform .12s var(--ease-out); }
.ah-front b { font-size: 1.45rem; font-variant-numeric: tabular-nums; }
.ah-trade { font-size: var(--fs-xs); font-weight: 600; }
@media (hover: hover) and (pointer: fine) { .ah-spool:hover { color: var(--ink); } .ah-spool:hover .ah-front { transform: rotate(0) translateY(4px); } }
.ah-spool:active .ah-front { transform: rotate(0) translateY(6px); box-shadow: none; }
@media (prefers-reduced-motion: reduce) { .ah-spool:is(:hover, :active) .ah-front { transform: rotate(-4deg); } }
.ah-acts { margin: 0; }
@media (max-width: 767px) {
  .ah-cols { grid-template-columns: minmax(0, 1fr); margin-top: 8px; }
  .ah-title { text-align: center; }
  .ah-lede { justify-content: center; text-align: center; }
  .ah-how .g-rules { text-align: left; }
  .ah-counter { grid-template-columns: minmax(0, 1fr); justify-items: center; }
  .ah-tokens { justify-items: center; text-align: center; }
  .ah-meter { justify-content: center; }
  .ah-spool { width: min(100%, 240px); }
  .ah-front { transform: rotate(-2deg); }
  /* The first button (the extra-run token, else wake or nap) takes the full row; the shared phone rule would halve it */
  .ah-booth .ah-acts.btn-row > form:first-child { flex-basis: 100%; }
}

/* "Elsewhere in Glimmeria" (games.js ELSEWHERE): games out in the lands, one link row each with its land and a plain line */
.ew-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 12px; }
@media (min-width: 768px) { .ew-list { grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); } }
.ew-row {
  display: grid; grid-template-columns: 48px minmax(0, 1fr); align-items: center; gap: 12px; height: 100%; box-sizing: border-box; padding: 10px 14px;
  border: 2px solid var(--ink); border-radius: var(--r-tile); background: var(--card); box-shadow: var(--shadow-sm); color: var(--ink); text-decoration: none;
}
@media (hover: hover) and (pointer: fine) { .ew-row:hover { box-shadow: var(--shadow-lift); background: var(--hi-soft); } }
.ew-art { line-height: 0; }
.ew-art svg { width: 48px; height: 48px; }
.ew-text { display: grid; gap: 2px; min-width: 0; }
.ew-text b { font: 600 1rem/1.2 var(--display); }
.ew-where { font: 700 var(--fs-xs) var(--display); color: var(--muted); }
.ew-line { font-size: var(--fs-sm); line-height: 1.3; }
