/* Mimic Mayhem. All motion lives in src/anim.js (GSAP); CSS only describes states. */

@font-face {
  font-family: "Cinzel";
  src: url("fonts/cinzel-latin-ext.woff2") format("woff2");
  font-weight: 800;
  font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Cinzel";
  src: url("fonts/cinzel-latin.woff2") format("woff2");
  font-weight: 800;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Alegreya Sans";
  src: url("fonts/alegreya-sans-500-latin-ext.woff2") format("woff2");
  font-weight: 500;
  font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Alegreya Sans";
  src: url("fonts/alegreya-sans-500-latin.woff2") format("woff2");
  font-weight: 500;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Alegreya Sans";
  src: url("fonts/alegreya-sans-700-latin-ext.woff2") format("woff2");
  font-weight: 700;
  font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Alegreya Sans";
  src: url("fonts/alegreya-sans-700-latin.woff2") format("woff2");
  font-weight: 700;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Alegreya Sans";
  src: url("fonts/alegreya-sans-800-latin-ext.woff2") format("woff2");
  font-weight: 800;
  font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Alegreya Sans";
  src: url("fonts/alegreya-sans-800-latin.woff2") format("woff2");
  font-weight: 800;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* Arcane (Ernest's pick, 2026-10-21): deep dungeon purple and gold, from the card back and the logo.
   Red stays only for danger: --red and the COUNTERED! stamp's --nope. */
:root {
  --bg: #110b18;
  --raise: #1c1426;
  --raise-2: #281d36; /* a picked chip and the note under it, inside the raised panel */
  --edge: #4a3866; /* the quiet outline of fields and choices; the picked one turns --accent */
  --line: #8a62c9;
  --text: #fbf6ff;
  --muted: #e2d6f0;
  --accent: #fad46a; /* the lightest gold that keeps 4.5:1 on every painted table (tools/backdrop-contrast.mjs) */
  --accent-hi: #fde08e; /* --accent under the pointer */
  --accent-ink: #24142f;
  --red: #d8261f;
  --nope: #c81e1e;
  --ink: #1e1228;
  --back: #3a1f52; /* the card back: purple with a gold frame (art.js), also on the seats' little backs */
  --back-trim: #e0b54a;
  --scrim: rgba(13, 8, 19, .62); /* the backdrop's dark layer; tools/backdrop-contrast.mjs assumes this */
  --display: "Cinzel", "Trajan Pro", Georgia, serif;
  --body: "Alegreya Sans", system-ui, sans-serif;
  --cw: clamp(64px, 17.5vw, 104px); /* hand card width */
  --radius: 12px;
  /* film grain, like the paintings': on the card faces and over the table */
  --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .55 0'/%3E%3C/filter%3E%3Crect width='120' height='120' filter='url(%23n)' opacity='.22'/%3E%3C/svg%3E");
  color-scheme: dark;
}

*, *::before, *::after { box-sizing: border-box; }
html, body { height: 100%; }
html { overflow-x: hidden; }
#app { position: relative; z-index: 1; overflow-x: clip; }
body {
  margin: 0;
  /* dark, with a faint warm glow behind the logo (a full red screen was hard on the eyes); the game screen covers it with a backdrop */
  background: radial-gradient(90% 60% at 50% 18%, #3a1f52 0%, #1a1124 45%, var(--bg) 100%) fixed, var(--bg);
  color: var(--text);
  font-family: var(--body);
  font-weight: 500;
  font-size: 16px;
  line-height: 1.4;
  -webkit-tap-highlight-color: transparent;
  overflow-x: hidden;
}
button, input { font: inherit; color: inherit; }
button { cursor: pointer; }
[hidden] { display: none !important; }
:focus-visible { outline: 3px solid var(--accent); outline-offset: 3px; }
svg { display: block; }

/* ---------- backdrop: a table scene behind the game, with a dark layer so the text stays readable ---------- */
.backdrop { position: fixed; inset: 0; z-index: 0; overflow: hidden; pointer-events: none; background: var(--bg); }
.bd-surface { position: absolute; inset: 0; width: 100%; height: 100%; }
.bd-prop { position: absolute; }
.bd-prop svg { width: 100%; height: auto; }
.bd-prop.wide svg { height: 100%; }
.bd-photo img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
/* fx.js's two Pixi canvases: the painted table that ripples and twists (under the dark layer), and the
   light, fire and sparks over the table (#fx; over the result pop-up while the win's coins fall) */
.backdrop canvas, .fx > canvas, .fx-win-layer > canvas { position: fixed; inset: 0; width: 100%; height: 100%; pointer-events: none; }
/* Lit like a lamp hangs over the table: darker towards the edges, and grain over all of it.
   Nothing here is lighter than --scrim, so tools/backdrop-contrast.mjs holds everywhere. */
.backdrop::after {
  content: ""; position: absolute; inset: 0;
  background:
    var(--grain) 0 0 / 120px,
    radial-gradient(ellipse 85% 80% at 50% 50%, transparent 30%, rgba(13, 8, 19, .62)),
    var(--scrim);
}

.screen { min-height: 100dvh; width: 100%; max-width: 1040px; margin-inline: auto; padding: 0 16px; }

/* ---------- buttons ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 48px; padding: 8px 22px; border-radius: 999px;
  border: 3px solid var(--ink); font-family: var(--display); font-size: 1.15rem; letter-spacing: .02em;
  white-space: nowrap; line-height: 1.1;
}
.btn .nw { white-space: nowrap; }
.btn-primary { background: var(--accent); color: var(--accent-ink); box-shadow: 0 4px 0 var(--ink); }
.btn-primary:hover { background: var(--accent-hi); }
.btn-ghost { background: transparent; color: var(--text); border-color: var(--muted); }
.btn-ghost:hover { background: rgba(255, 246, 229, .08); }
.btn-action { background: #fff6e5; color: var(--ink); box-shadow: 0 4px 0 var(--ink); }
.btn-action:hover { background: #ffffff; }
.btn-nope { background: var(--nope); color: #fff; box-shadow: 0 5px 0 var(--ink); font-size: 1.6rem; min-height: 60px; padding-inline: 30px; }
.btn-big { min-height: 58px; font-size: 1.5rem; padding-inline: 40px; }
.btn:disabled { opacity: .45; cursor: not-allowed; box-shadow: none; }
.icon-btn {
  width: 44px; height: 44px; border-radius: 50%; display: inline-grid; place-items: center;
  background: rgba(18, 11, 10, .72); border: 2px solid rgba(255, 248, 239, .2); color: var(--text);
}
.icon-btn:hover { background: var(--bg); border-color: rgba(255, 248, 239, .45); }
.icon-btn svg { width: 22px; height: 22px; }
/* body is the page's scroller (html's overflow-x stops it passing to the window), so body is also the
   gear's containing block: it scrolls away with the menu instead of floating over the panel */
body { position: relative; }
/* the menus' scene: the treasure vault, painted, under a dark layer that keeps every word readable
   (the game screen's own backdrop covers it) */
body::before {
  --vault: url("img/backdrops/vault-wide.webp");
  content: ""; position: fixed; inset: 0; z-index: 0; pointer-events: none;
  background:
    var(--grain) 0 0 / 120px,
    radial-gradient(ellipse 80% 75% at 50% 45%, rgba(13, 8, 19, .5), rgba(13, 8, 19, .86)),
    linear-gradient(rgba(13, 8, 19, .38), rgba(13, 8, 19, .38)),
    var(--vault) center / cover no-repeat,
    var(--bg);
}
@media (orientation: portrait) { body::before { --vault: url("img/backdrops/vault-tall.webp"); } }
.menu-settings { position: absolute; z-index: 30; top: max(12px, env(safe-area-inset-top)); right: max(16px, env(safe-area-inset-right)); }

/* ---------- start screen ---------- */
.start { display: flex; flex-direction: column; align-items: center; padding-top: 24px; padding-bottom: 32px; text-align: center; }
.start-brand { display: flex; flex-direction: column; align-items: center; }
/* the chest in a gold ring: ink border, gold outline over an ink rim */
.start-art {
  width: min(128px, 34vw); aspect-ratio: 1; border-radius: 50%; overflow: hidden;
  border: 5px solid var(--ink); outline: 6px solid var(--accent); outline-offset: 0; box-shadow: 0 0 0 10px var(--ink);
}
.start-art svg, .start-art img { display: block; width: 100%; height: 100%; object-fit: cover; }
.logo {
  font-family: var(--display); font-weight: 400; font-size: clamp(2.4rem, 10vw, 4.6rem); line-height: 1.05; margin: 18px 0 4px;
  color: var(--accent); -webkit-text-stroke: 2px var(--ink); paint-order: stroke fill; text-shadow: 0 5px 0 var(--ink);
}
.logo span { color: var(--text); }
.tagline { margin: 0 0 20px; color: var(--muted); font-size: 1.1rem; font-weight: 700; }
.setup {
  container: setup / inline-size;
  width: 100%; max-width: 440px; display: flex; flex-direction: column; gap: 14px; align-items: stretch;
  background: var(--raise); border: 2px solid #3a2a27; border-radius: 22px; padding: 18px; box-shadow: 0 12px 32px rgba(0, 0, 0, .45);
}
.field { border: 0; margin: 0; padding: 0; min-width: 0; text-align: left; display: flex; flex-direction: column; gap: 6px; }
.field-label { font-weight: 700; color: var(--muted); padding: 0; font-size: .95rem; }
.field input[type="text"] {
  min-height: 48px; border-radius: 12px; border: 2px solid var(--edge); background: var(--bg); padding: 8px 14px; font-size: 1.05rem;
}
.field input[type="text"]:focus { border-color: var(--accent); outline: none; }
.field input[type="text"]::placeholder { color: #b3a39c; }
/* bot level and game speed side by side once the panel has room */
.field-row { display: grid; gap: 14px; }
@container setup (min-width: 380px) { .field-row { grid-template-columns: minmax(0, 3fr) minmax(0, 2fr); gap: 10px; } }
.seg { display: flex; gap: 4px; background: var(--bg); border: 2px solid var(--edge); border-radius: 14px; padding: 4px; }
.seg label { flex: 1; position: relative; }
.seg input { position: absolute; inset: 0; opacity: 0; margin: 0; cursor: pointer; }
.seg span { display: grid; place-items: center; min-height: 42px; border-radius: 10px; font-weight: 700; white-space: nowrap; padding: 0 6px; }
.seg input:checked + span { background: var(--accent); color: var(--accent-ink); }
.seg input:focus-visible + span { outline: 3px solid var(--accent); outline-offset: 2px; }
.setup .btn-primary { margin-top: 4px; }
.mode-fields { display: flex; flex-direction: column; gap: 14px; }

/* the two faces of the start screen (main.js showStartView) */
.start[data-view="title"] .setup, .start[data-view="setup"] .title-menu { display: none; }
.start[data-view="title"] { justify-content: center; }
.title-menu { display: flex; flex-direction: column; gap: 12px; width: 100%; max-width: 380px; margin-top: 8px; }
.title-menu > .btn-big { width: 100%; }
.title-menu > .btn-ghost { background: rgba(17, 11, 24, .6); } /* readable over the painting */
.title-menu > .btn-ghost:hover { background: rgba(40, 29, 54, .9); }
.title-menu .profile-bar { margin-top: 10px; flex-direction: column; align-items: stretch; padding: 12px; background: rgba(28, 20, 38, .86); border: 2px solid var(--edge); }
.profile-btns { display: flex; gap: 8px; }
.profile-btns .btn { flex: 1 1 0; padding-inline: 10px; }
.title-menu .profile-text { text-align: center; flex: none; }
/* only when the browser offers it: a plain link, so the menu keeps its one loud button */
.title-menu .btn-install {
  align-self: center; min-height: 40px; border: 0; padding-block: 4px; color: var(--accent); background: none;
  font-family: var(--body); font-weight: 800; font-size: 1rem; text-decoration: underline; text-underline-offset: 3px;
}
.title-menu .btn-install:hover { background: none; color: var(--accent-hi); }
.setup-head { display: flex; align-items: center; gap: 12px; }
.setup-head .icon-btn { flex: none; background: var(--bg); border-color: var(--edge); }
.setup-head .icon-btn:hover { border-color: var(--muted); }
.setup-title { margin: 0; font-family: var(--display); font-weight: 400; font-size: clamp(1.15rem, 5.4vw, 1.45rem); line-height: 1.1; color: var(--accent); text-align: left; }
/* the table's options, folded into one line that says what's picked */
.table-opts { border: 2px solid var(--edge); border-radius: 14px; }
.table-opts summary {
  display: flex; align-items: center; gap: 4px 12px; flex-wrap: wrap; min-height: 52px; padding: 8px 42px 8px 14px;
  position: relative; list-style: none; cursor: pointer; text-align: left; border-radius: 12px;
}
.table-opts summary::-webkit-details-marker { display: none; }
.table-opts summary::after {
  content: ""; position: absolute; right: 18px; top: 50%; width: 9px; height: 9px; margin-top: -7px;
  border-right: 2.5px solid var(--muted); border-bottom: 2.5px solid var(--muted); transform: rotate(45deg);
}
.table-opts[open] summary::after { margin-top: -2px; transform: rotate(-135deg); }
.table-opts summary:hover { background: rgba(255, 246, 229, .05); }
.table-opts summary:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }
.table-opts-label { font-weight: 700; color: var(--muted); font-size: .95rem; }
.table-opts-now { font-weight: 800; }
.table-opts-body { display: flex; flex-direction: column; gap: 14px; padding: 2px 12px 14px; }
/* one column: the setup has the screen to itself, below the gear */
@media (max-width: 1023px), (max-height: 639px) {
  .start[data-view="setup"] .start-brand { display: none; }
  .start[data-view="setup"] { padding-top: 68px; }
}
/* a short wide window (a phone on its side, CrazyGames' 800×450): the title beside the menu, all on one screen */
@media (min-width: 700px) and (max-height: 639px) and (orientation: landscape) {
  .start[data-view="title"] {
    display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 360px); align-items: center; justify-content: center;
    column-gap: clamp(28px, 5vw, 64px); max-width: 960px; padding-block: 16px;
    padding-right: max(68px, env(safe-area-inset-right) + 56px); /* the menu stays clear of the gear */
  }
  .start[data-view="title"] .start-art { width: min(120px, 24vh); }
  .start[data-view="title"] .logo { font-size: clamp(2.4rem, 11vh, 3.4rem); margin-top: 12px; }
  .start[data-view="title"] .tagline { margin: 6px 0 0; }
  .start[data-view="title"] .title-menu { margin-top: 0; gap: 10px; }
  .start[data-view="title"] .title-menu > .btn-big { min-height: 50px; font-size: 1.3rem; }
  .start[data-view="title"] .profile-bar { margin-top: 4px; padding: 10px; gap: 8px; }
}
.online-note { margin: 2px 0 0; color: var(--muted); text-align: left; }
.or { display: flex; align-items: center; gap: 10px; margin: 4px 0 -2px; color: var(--muted); font-weight: 700; font-size: .95rem; }
.or::before, .or::after { content: ""; flex: 1; height: 2px; background: #3a2a27; }
.join-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 10px; align-items: end; }
.field input.code-input { font-family: var(--display); font-size: 1.5rem; letter-spacing: .3em; text-transform: uppercase; padding-block: 4px; }
.field input.code-input::placeholder { letter-spacing: .3em; color: #8f7f78; }
.form-msg { margin: 0; min-height: 1.4em; color: var(--accent); font-weight: 700; }
.form-msg:empty { display: none; }

/* ---------- online lobby ---------- */
.lobby { display: flex; flex-direction: column; align-items: center; padding-top: 68px; padding-bottom: 32px; text-align: center; } /* room for the sound button */
.lobby-box { max-width: 480px; }
/* phones: the two columns melt into one list, players before the host's settings */
.lobby-col { display: contents; }
.host-controls { order: 1; }
.lobby-wait, .lobby-col > .btn { order: 2; }
.lobby-kicker { margin: 0; color: var(--muted); font-weight: 700; }
.room-code {
  margin: -4px 0 0; font-family: var(--display); font-size: clamp(3.2rem, 16vw, 4.6rem); line-height: 1.05; letter-spacing: .14em; padding-left: .14em;
  color: var(--accent); -webkit-text-stroke: 2px var(--ink); paint-order: stroke fill; text-shadow: 0 4px 0 var(--ink);
}
.lobby-note { margin: 0; color: var(--muted); }
.lobby-share { display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; }
.lobby-share .btn { flex: 1 1 0; min-width: max-content; margin-top: 0; padding-inline: 14px; } /* equal widths; wraps only when they don't fit */
.lobby-head { margin: 8px 0 0; font-family: var(--display); font-weight: 400; font-size: 1.3rem; text-align: left; }
.lobby-head span { color: var(--muted); font-family: var(--body); font-weight: 700; font-size: 1rem; }
.lobby-seats { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
@media (min-width: 560px) { .lobby-seats:has(> :nth-child(7)) { grid-template-columns: 1fr 1fr; } } /* a big room: two columns */
.lobby-seat { display: flex; align-items: center; gap: 12px; min-height: 60px; padding: 6px 10px; border-radius: 14px; background: var(--bg); border: 2px solid #3a2a27; text-align: left; }
.lobby-seat .seat-avatar { width: 46px; flex: none; }
.lobby-seat.empty { border-style: dashed; background: transparent; }
.lobby-seat.empty .seat-avatar { aspect-ratio: 1; border-radius: 50%; border: 2px dashed #5a4642; width: 40px; margin-inline: 3px; }
.lobby-seat.empty .lobby-name { color: #b3a39c; font-weight: 600; }
.lobby-seat.away .seat-avatar { opacity: .45; }
.lobby-who { display: flex; flex-direction: column; min-width: 0; flex: 1; line-height: 1.2; }
.lobby-name { font-weight: 800; font-size: 1.05rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lobby-tag { color: var(--muted); font-weight: 600; font-size: .9rem; }
.lobby-tag:empty { display: none; }
.btn-small { min-height: 44px; padding: 4px 16px; font-size: 1rem; border-width: 2px; }
.host-controls { display: flex; flex-direction: column; gap: 12px; padding-top: 4px; }
.lobby-wait { margin: 4px 0 0; color: var(--text); font-weight: 600; }
.lobby-box .btn-big { margin-top: 0; }

/* connection lost: a small notice at the top until it's back */
.net-note {
  position: fixed; z-index: 60; top: max(10px, env(safe-area-inset-top)); left: 50%; transform: translateX(-50%); margin: 0;
  max-width: calc(100vw - 32px); padding: 8px 16px; border-radius: 999px; background: var(--accent); color: var(--accent-ink);
  border: 2px solid var(--ink); font-weight: 800; box-shadow: 0 6px 18px rgba(0, 0, 0, .45); text-align: center;
}

/* ---------- game screen ---------- */
.game { display: grid; grid-template-rows: auto auto 1fr auto auto auto; height: 100dvh; min-height: 560px; padding-bottom: max(8px, env(safe-area-inset-bottom)); }
.bar { display: flex; align-items: center; gap: 8px; padding: 8px 0 4px; min-width: 0; } /* a long turn chip trims instead of widening the grid */
.bar-right { display: flex; gap: 6px; margin-left: auto; }
/* the quick reactions (online): a box of one-liners dropping from the top bar, over the table */
.emote-panel {
  position: fixed; z-index: 30; top: calc(max(8px, env(safe-area-inset-top)) + 56px); right: max(12px, env(safe-area-inset-right));
  width: min(340px, calc(100vw - 24px)); display: grid; grid-template-columns: 1fr 1fr; gap: 8px; padding: 10px;
  background: var(--raise); border: 3px solid var(--ink); border-radius: 18px; box-shadow: 0 14px 34px rgba(0, 0, 0, .55);
}
.emote-chip {
  min-height: 44px; padding: 6px 10px; border-radius: 999px; border: 2px solid rgba(255, 236, 210, .25);
  background: rgba(255, 246, 229, .08); color: var(--text); font: 800 1rem/1.15 var(--body); cursor: pointer;
}
.emote-chip:hover, .emote-chip:focus-visible { background: #fff6e5; color: var(--ink); border-color: var(--ink); outline: none; }
.emote-chip:active { transform: scale(.96); }
.turn-chip { margin: 0; min-width: 0; font-family: var(--display); font-size: 1.05rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: var(--muted); }
.turn-chip.mine { color: var(--accent); }

/* --cols seats a row; wrapping rows centred, so a shorter last row sits in the middle (Ernest, 2026-10-17) */
.seats {
  --gap: 8px; list-style: none; width: 100%; margin: 0 auto; padding: 6px 0 0; display: flex; flex-wrap: wrap; justify-content: center; gap: var(--gap);
  max-width: calc(var(--cols, 2) * 132px + (var(--cols, 2) - 1) * var(--gap)); /* never more than --cols a row */
}
.seats > .seat { flex: none; width: min(132px, calc((100% - (var(--cols, 2) - 1) * var(--gap)) / var(--cols, 2) - .1px)); }
/* 6 to 9 others (a 7 to 10 player game): two rows of smaller seats */
.seats.many { --gap: 6px; row-gap: 4px; --avw: clamp(36px, 10.5vw, 54px); }
.seats.many .seat { padding: 3px 2px 5px; gap: 0; }
.seats.many .seat-avatar { width: var(--avw); }
.seats.many .seat-name { font-size: .8rem; }
.seats.many .seat-meta { font-size: .74rem; }
.seat { position: relative; display: flex; flex-direction: column; align-items: center; gap: 2px; padding: 6px 4px 8px; border-radius: 16px; background: rgba(18, 11, 10, .6); border: 2px solid transparent; min-width: 0; }
.seat.turn { border-color: var(--accent); background: rgba(40, 30, 10, .78); }
.seat.out { opacity: .55; }
.seat.away .seat-avatar { opacity: .45; } /* online: their phone lost its connection */
.seat.out .seat-avatar { filter: grayscale(1); }
/* will-change: the pulse (anim.js glow()) changes only its opacity on its own layer; repainting the blurred
   shadow every frame, under a Pixi effect, dropped Sugod! to 30 fps (2026-10-20) */
.seat-glow { position: absolute; inset: -6px; border-radius: 20px; box-shadow: 0 0 22px 4px rgba(255, 210, 63, .55); opacity: 0; pointer-events: none; will-change: opacity; }
.seat-avatar { width: clamp(46px, 13vw, 64px); aspect-ratio: 8 / 7; }
.seat-avatar svg { width: 100%; height: 100%; }
/* painted portraits: a round frame as tall as the box (8:7), so swapping a drawing for a picture moves nothing */
.seat-avatar { display: block; }
.portrait { display: block; width: 87.5%; aspect-ratio: 1; margin: 0 auto; border-radius: 50%; object-fit: cover; border: 2px solid var(--ink); box-shadow: 0 0 0 2px var(--text); background: var(--raise); }
.portrait.out { filter: grayscale(1); }
.seat-name { font-weight: 800; font-size: .92rem; max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.seat-meta { display: inline-flex; align-items: center; gap: 4px; font-size: .82rem; color: var(--muted); white-space: nowrap; }
/* a signed-in player's Barkada rank (src/medals.js) under their name */
.seat-rank, .me-rank { font-size: .7rem; font-weight: 800; color: var(--accent); line-height: 1.1; max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; letter-spacing: .01em; }
.seats.many .seat-rank { font-size: .62rem; }
.me-rank { padding: 1px 8px 2px; border-radius: 999px; background: rgba(255, 210, 63, .14); }
.mini-card { width: 11px; height: 15px; border-radius: 3px; background: var(--back); border: 2px solid var(--ink); box-shadow: inset 0 0 0 1.5px var(--back-trim); flex: none; }
.seat-think { position: absolute; top: 2px; right: 6px; font-family: var(--display); color: var(--accent); font-size: 1.1rem; opacity: 0; }
.seat.pickable { border-color: var(--accent); cursor: pointer; }
.seat-hand { display: none; } /* the held fan only shows on the desktop table */

/* No mat under the piles (Ernest, 2026-10-17: the banig came out; the painted tables carry the scene) */
/* Phones and tablets: the table row takes what's left of the screen, and the piles grow into it on a
   tall phone (a container query on the row's height) instead of floating small in an empty middle
   (Ernest, 2026-10-19). --pw is the pile width; the desktop table sets its own --pile-w. */
.table {
  display: flex; align-items: center; justify-content: center; gap: clamp(28px, 8vw, 80px); padding: 8px 0;
  min-height: calc(var(--cw) * 1.61 + 64px); /* the smallest pile plus its labels: size containment would otherwise let the row collapse */
  container-type: size; --note: 0px;
  /* never wider than the row can hold: two piles, the gaps and the Ikot/Higop column when it's shown */
  --pw: clamp(calc(var(--cw) * 1.15), min(31vw, calc((100cqh - 64px) * 5 / 7), calc((100cqw - var(--note) - 2 * clamp(28px, 8vw, 80px)) / 2)), 168px);
}
.table:has(.pile-note:not([hidden])) { --note: 112px; }
.pile { display: flex; flex-direction: column; align-items: center; gap: 6px; }
.pile-label { margin: 0; font-size: .85rem; color: var(--muted); white-space: nowrap; text-align: center; }
.pile-label .nowrap { white-space: nowrap; }
.deck, .discard { position: relative; width: var(--pw); aspect-ratio: 5 / 7; border-radius: var(--radius); }
.deck { padding: 0; border: 0; background: none; }
.deck:disabled { cursor: default; }
.deck .card { position: absolute; inset: 0; width: 100%; }
/* will-change: the deck and its three cards each keep a layer, so the Katomik spin, the shuffle and the
   shakes move them rather than repainting the glowing stack every frame (about 200 times a Katomik) */
.deck, .deck .card { will-change: transform; }
.deck .card:nth-child(1) { transform: translate(5px, 5px); }
.deck .card:nth-child(2) { transform: translate(2.5px, 2.5px); }
.deck.can-draw .card:last-child { box-shadow: 0 0 0 4px var(--accent), 0 0 24px 6px rgba(255, 210, 63, .5); }
/* empty: a faint card outline with a closed chest in it; the top card covers both */
.discard {
  border: 2px dashed rgba(255, 236, 210, .32); padding: 0; color: inherit; font: inherit; cursor: pointer;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='rgba(255,236,210,.2)'%3E%3Cpath d='M3.5 10.5C3.5 6.6 6.8 5 12 5s8.5 1.6 8.5 5.5z'/%3E%3Crect x='3.5' y='11.5' width='17' height='8' rx='1'/%3E%3Crect x='10.4' y='9.6' width='3.2' height='4.2' rx='.8' fill='rgba(255,236,210,.32)'/%3E%3C/svg%3E") 50% 50% / 40% no-repeat, rgba(0, 0, 0, .18);
}
.discard:disabled { cursor: default; }
.discard .card { position: absolute; inset: -2px; width: calc(100% + 4px); }
/* Danger meter under the deck: a fixed green-to-red track, uncovered from the left as the risk grows. */
.risk {
  position: relative; display: block; width: var(--pw); height: 8px; border-radius: 6px; overflow: hidden;
  border: 2px solid var(--ink); background: linear-gradient(90deg, #3fbf6a, var(--accent) 45%, #ff7a1f 70%, var(--nope)); margin-top: 4px;
}
.risk-cover { position: absolute; inset: 0; background: #1a100e; transform-origin: right center; }

.status { min-height: 52px; display: flex; align-items: center; justify-content: center; text-align: center; padding: 4px 8px; font-size: 1rem; color: var(--text); }
/* The story line sits on its own dark plate so it reads on every painted table and doesn't float loose. */
.status > span {
  display: inline-block; padding: 6px 14px; border-radius: 12px; line-height: 1.3;
  background: rgba(31, 22, 21, .84); border: 1.5px solid rgba(184, 70, 58, .55); box-shadow: 0 4px 14px rgba(0, 0, 0, .35);
}
.status b { color: var(--accent); font-weight: 800; }
.status .rule { color: var(--muted); }

/* Card info: what the selected, hovered or last-played card does. On phones it takes the status line's place. */
.story { display: grid; min-width: 0; }
.game.has-info .status { display: none; }
.card-info {
  display: flex; align-items: center; gap: 10px; margin: 2px 0 6px; padding: 8px 12px 8px 10px; text-align: left;
  background: var(--raise); border: 2px solid var(--line); border-radius: 12px;
}
.card-info.tip { display: none; }
/* a capped info whose text scrolls: a fade at its foot says there's more (`more` is set by infoMore() in ui.js) */
.card-info.more { flex-wrap: wrap; }
.card-info.more::after {
  content: ""; flex: 0 0 100%; position: sticky; bottom: -8px; display: block; height: 20px; margin: -20px -12px -8px -10px;
  background: linear-gradient(rgba(31, 22, 21, 0), var(--raise) 85%); pointer-events: none;
}
.info-card { flex: none; }
.info-card .card { --cw: 46px; border-width: 2px; box-shadow: none; }
.info-card .card .card-name { display: none; } /* beats .card-name.long, which sets display */
.info-card .card-art { margin: 6%; border-width: 1px; border-radius: 5px; }
.info-card .card-icon, .info-card .card-pack, .seat-marked .card-icon, .seat-marked .card-pack { display: none; } /* too small to read */
.info-body { min-width: 0; }
.info-name { margin: 0; font-family: var(--display); font-size: 1.15rem; line-height: 1.1; color: var(--accent); }
.info-text { margin: 2px 0 0; font-size: .9rem; line-height: 1.3; color: var(--text); }
.info-how { margin: 4px 0 0; font-size: .82rem; line-height: 1.25; color: var(--muted); }
.info-how:empty { display: none; }

.actions { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; min-height: 56px; align-items: center; padding: 2px 0 6px; }

.me { position: relative; }
.me-tag { display: flex; justify-content: center; align-items: center; gap: 8px; font-weight: 800; font-size: .95rem; color: var(--muted); }
.me-tag .seat-avatar { width: 34px; }
.me-tag.turn { color: var(--accent); }
.me-count { margin-left: -4px; } /* the tag's gap plus the dot's own space was a double space */
.me-count::before { content: "· "; }
.hand { position: relative; height: calc(var(--cw) * 1.4 + 44px); margin-top: 4px; touch-action: manipulation; }
.hand .card { position: absolute; left: 0; bottom: 18px; transform-origin: 50% 120%; }
.hand.two-rows { height: calc(var(--cw) * 1.4 + 44px + var(--raise)); } /* a big hand in two rows (anim.js layoutHand) */
.hand .card.selected { box-shadow: 0 0 0 4px var(--accent), 0 8px 18px rgba(0, 0, 0, .4); }
.hand .card.match { box-shadow: 0 0 0 3px #fff6e5; }
.hand-empty { position: absolute; inset: 0; display: grid; place-items: center; color: var(--muted); }

/* ---------- cards ---------- */
/* Printed like a real card: a dark keyline with a thin light rule inside it (the back has the same),
   paper grain, light from the top, the name on a darker plate, the picture in a window with a soft
   inner shadow, the type's icon top-left and an expansion's mark bottom-right.
   --band is the plate and icon colour: the card's colour darkened, or a cat's own colour (cards.js). */
.card {
  --c: #f4e3c1; --k: var(--ink);
  --band: color-mix(in srgb, var(--c) 58%, #120a08); --bt: #fff8ef; --rule: rgba(255, 248, 239, .5);
  --r: clamp(7px, calc(var(--cw) * .1), 20px);
  position: relative; width: var(--cw); aspect-ratio: 5 / 7; border-radius: var(--r); padding: 0;
  background: var(--grain) 0 0 / 120px, linear-gradient(170deg, rgba(255, 250, 240, .2), rgba(255, 250, 240, 0) 36%, rgba(0, 0, 0, .14)), var(--c);
  color: var(--k); border: 3px solid var(--ink);
  display: flex; flex-direction: column; overflow: hidden; text-align: left;
  box-shadow: 0 4px 10px rgba(0, 0, 0, .35);
}
.card:not(.back)::before {
  content: ""; position: absolute; inset: calc(var(--cw) * .022); border-radius: calc(var(--r) * .75);
  border: max(1px, calc(var(--cw) * .012)) solid var(--rule); pointer-events: none;
}
.card-name {
  position: relative; flex: none; margin: 5.5% 5.5% 3%; padding: 3.5% 5% 3%;
  border-radius: calc(var(--r) * .45); background: var(--band); color: var(--bt);
  box-shadow: inset 0 -2px 0 rgba(0, 0, 0, .25), 0 1px 0 rgba(255, 250, 240, .2);
  font-family: var(--display); font-size: calc(var(--cw) * .13); line-height: 1.05; text-shadow: 0 1px 0 rgba(0, 0, 0, .35);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.card-name.long { white-space: normal; font-size: calc(var(--cw) * .108); display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; hyphens: manual; }
.card-name.tight { font-size: calc(var(--cw) * .11); } /* Earthquake, Gold Coins: one line, a little smaller */
.card-art { position: relative; flex: 1; margin: 0 5.5% 5.5%; border-radius: calc(var(--r) * .45); overflow: hidden; border: 2px solid var(--ink); min-height: 0; background: #fff; }
.card-art::after { content: ""; position: absolute; inset: 0; border-radius: inherit; box-shadow: inset 0 2px 8px rgba(0, 0, 0, .35); pointer-events: none; }
.card-art > svg { width: 100%; height: 100%; }
.card-art .painted { display: block; width: 100%; height: 100%; object-fit: cover; }
.card-icon, .card-pack {
  position: absolute; z-index: 1; display: block; aspect-ratio: 1; border-radius: 50%;
  border: max(1.5px, calc(var(--cw) * .014)) solid var(--ink); box-shadow: 0 1px 3px rgba(0, 0, 0, .45);
}
.card-icon { left: 5%; top: 5%; width: calc(var(--cw) * .23); padding: calc(var(--cw) * .032); background: var(--band); color: var(--bt); }
.card-pack { right: 5%; bottom: 5%; width: calc(var(--cw) * .19); padding: calc(var(--cw) * .026); background: #1a1112; color: #fff8ef; }
.card-icon svg, .card-pack svg { width: 100%; height: 100%; }
/* Foil on the bomb and the Higop, only in the peeks (anim.js shine()): a light band that GSAP sweeps across,
   and a lit edge on the Higop. Without motion the band stays hidden and only the edge shows. The bomb keeps
   its own dark frame, the same as everywhere else (Ernest, 2026-10-19: no gold edge). */
.card.shiny[data-type="higop"], .modal-cards .card.shiny[data-type="higop"] { --shine: #7df4ff; box-shadow: 0 0 0 2px var(--shine), 0 0 16px 4px color-mix(in srgb, var(--shine) 55%, transparent), 0 4px 10px rgba(0, 0, 0, .35); } /* cyan, not lilac: the Silipin view's own glow is purple */
.card-shine {
  position: absolute; top: -20%; bottom: -20%; left: 32%; width: 36%; z-index: 2; pointer-events: none; opacity: 0;
  background: linear-gradient(90deg, rgba(255, 255, 255, 0), rgba(255, 250, 230, .5) 50%, rgba(255, 255, 255, 0));
}
.card.back { background: var(--back); }
.card.back .card-art { margin: 0; border: 0; border-radius: 0; background: none; } /* the back's SVG draws its own frame */
.card.back .card-art::after { content: none; }
/* Ernest's painted back (src/art.js): the seats' tiny backs use it too */
.painted-back .mini-card { background: var(--back-img) center / cover, var(--back); box-shadow: none; }

.card.big { --cw: min(200px, 46vw); }
.card.big .card-text { font-size: .86rem; line-height: 1.25; padding: 0 7% 7%; font-weight: 600; flex: none; }
.card.big .card-art { flex: none; aspect-ratio: 1; }

/* ---------- Ayoko! prompt ---------- */
.nope-prompt {
  position: fixed; left: 50%; top: 42%; transform: translate(-50%, -50%); z-index: 40;
  width: min(360px, calc(100vw - 32px)); background: var(--raise); border: 3px solid var(--ink); border-radius: 22px;
  padding: 16px; text-align: center; box-shadow: 0 0 0 4px var(--nope), 0 20px 50px rgba(0, 0, 0, .55);
}
.nope-what { margin: 0 0 12px; font-weight: 700; }
.nope-none { display: block; margin-top: 4px; color: var(--muted); font-weight: 600; }
.nope-row { display: flex; gap: 10px; justify-content: center; align-items: center; }
.nope-timer { height: 8px; border-radius: 4px; background: rgba(255, 246, 229, .15); margin-top: 14px; overflow: hidden; }
.nope-timer span { display: block; height: 100%; background: var(--accent); transform-origin: left center; }

/* ---------- effects layer ---------- */
.fx { position: fixed; inset: 0; pointer-events: none; z-index: 50; overflow: hidden; }
/* Every effect part on its own layer, drawn once and then only moved and faded. Otherwise each flash, dim,
   ray and slash that changed repainted the whole full-screen effects layer every frame: 130 to 550 full
   repaints per Sugod, Higop or Laban Tayo!, at 3.5× on a phone (Pixel 7 Pro). The flying cards (.fly)
   and the rings grow, and a layer kept for a transform would be scaled up blurry, so theirs is kept for
   opacity only (the browser still redraws them sharp at a new size). */
.fx > :not(canvas, .fly, .fx-ring, .fx-glowring, .fx-runes) { will-change: transform, opacity; }
.fx > :is(.fly, .fx-ring, .fx-glowring) { will-change: opacity; }
/* The game screen is its own layer, so the screen shakes (Sugod!, the bomb, Laban Tayo!) only move it,
   instead of repainting the whole table when the shake starts and again when it ends. Only while the
   table shows: it changes what position: fixed is measured against. */
#app:has(#game:not([hidden])) { will-change: transform; }
.fx .fly { position: fixed; }
.fx .fly .card { --cw: 100px; }
/* Words always read over the cards and paws moving under them (anim.js gives those z-index 2–5). */
.fx-banner, .fx-stamp, .fx-arrow, .fx-say { z-index: 10; }
.fx-banner {
  position: fixed; left: 50%; top: 38%;
  font-family: var(--display); font-size: clamp(2rem, 9vw, 4rem); line-height: 1.05; text-align: center; white-space: nowrap;
  color: var(--accent); text-shadow: 0 4px 0 var(--ink), 0 0 30px rgba(0, 0, 0, .5); -webkit-text-stroke: 2px var(--ink); paint-order: stroke fill;
  will-change: transform; /* drawn once and scaled: the slam from 3.4× redrew the blurred shadow and the masked band every frame (Katomik's last stutter) */
}
.fx-banner small { display: block; font-size: .45em; color: var(--text); -webkit-text-stroke: 1px var(--ink); paint-order: stroke fill; }
/* A dark band across the screen behind every banner, fading out at the ends. */
.fx-banner::before {
  content: ""; position: absolute; z-index: -1; left: 50%; top: -.2em; bottom: -.2em; width: 100vw; transform: translateX(-50%);
  background: rgba(13, 8, 19, .84); border-block: 4px solid var(--accent);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 18%, #000 82%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 18%, #000 82%, transparent);
}
.fx-stamp {
  /* sized so "COUNTERED! ×2" fits a phone's width; stamp() also keeps it inside the viewport (Ernest, 2026-10-19: it was cut off) */
  position: fixed; font-family: var(--display); font-size: clamp(1.4rem, 6.2vw, 3.2rem); color: #fff; background: var(--nope);
  border: 5px solid var(--ink); border-radius: 14px; padding: 4px 18px; line-height: 1.05; white-space: nowrap; box-shadow: 0 6px 0 var(--ink);
}
.fx-flash { position: fixed; inset: 0; background: #fff3b0; opacity: 0; }
.fx-arrow { position: fixed; font-family: var(--display); color: var(--accent); font-size: 2.6rem; -webkit-text-stroke: 2px var(--ink); paint-order: stroke fill; }
/* A speech bubble over an avatar (say() in anim.js), tail pointing down at the cat */
.fx-say {
  position: fixed; font-family: var(--display); font-size: clamp(1.1rem, 3.6vw, 1.6rem); line-height: 1.1; white-space: nowrap;
  color: var(--ink); background: var(--accent); border: 3px solid var(--ink); border-radius: 14px; padding: 4px 14px 5px; box-shadow: 0 4px 0 var(--ink);
}
.fx-say::after {
  content: ""; position: absolute; left: 50%; bottom: -11px; width: 14px; height: 14px; transform: translateX(-50%) rotate(45deg);
  background: var(--accent); border: solid var(--ink); border-width: 0 3px 3px 0;
}
/* a quick reaction (online): cream, so it never reads as the game's own yellow callouts */
.fx-say.emote { z-index: 12; font-family: var(--body); font-weight: 800; font-size: clamp(1rem, 3.2vw, 1.3rem); background: #fff6e5; padding: 5px 12px 6px; }
.fx-say.emote::after { background: #fff6e5; }
.fx-paw { position: fixed; pointer-events: none; }
.fx-paw svg { width: 100%; height: auto; }
/* You won: coins on their own layer above the result pop-up (.modal is z-index 60), so the scrim never dims them */
.fx-win-layer { position: fixed; inset: 0; z-index: 70; pointer-events: none; overflow: hidden; }
.fx-coin {
  position: absolute; left: 0; top: 0; border-radius: 50%; will-change: transform;
  background: radial-gradient(circle at 38% 34%, #fff6c8 0 8%, #ffd23f 26%, #e0a21c 58%, #a8700e 80%);
  box-shadow: inset 0 0 0 2px rgba(255, 236, 160, .7), inset 0 0 0 4px #b07812, 0 0 0 1.5px rgba(43, 26, 18, .8);
}
/* Silipin ang Future: a crystal-ball glow sized from the deck (anim.js crystal()) */
.fx-glowball { position: fixed; border-radius: 50%; background: radial-gradient(circle, rgba(200, 245, 255, .95) 0%, rgba(155, 231, 255, .8) 18%, rgba(160, 110, 255, .6) 42%, rgba(123, 63, 196, 0) 70%); }
.fx-glowcore { position: fixed; border-radius: 50%; background: radial-gradient(circle, #fff 0%, rgba(214, 248, 255, .9) 35%, rgba(155, 231, 255, 0) 70%); }
.fx-glowring { position: fixed; border-radius: 50%; border: 4px solid rgba(190, 240, 255, .95); box-shadow: 0 0 22px 6px rgba(160, 110, 255, .8), inset 0 0 16px rgba(155, 231, 255, .8); }
.fx-sparkle { position: fixed; background: #f4fbff; clip-path: polygon(50% 0, 60% 40%, 100% 50%, 60% 60%, 50% 100%, 40% 60%, 0 50%, 40% 40%); }
/* Sneak (anim.js sneak()): the room dims at the edges, the title tiptoes, glowing boot prints creep past
   the deck. Sanctuary: a warm glow, a dome of golden light over the seat and gold motes. */
.fx-flash.shadow { background: radial-gradient(ellipse at center, rgba(8, 10, 24, 0) 35%, rgba(8, 10, 24, .7)); }
.fx-flash.holy { background: radial-gradient(ellipse at center, rgba(255, 216, 107, .18), rgba(60, 36, 8, .55)); }
.fx-banner.sneak { color: #9cc2ff; }
.fx-banner.sneak::before { border-color: #4f7fd8; }
.fx-banner.sanctuary { color: #ffd86b; }
.fx-banner.sanctuary::before { border-color: #c9a23a; }
.fx-step { position: fixed; z-index: 4; filter: drop-shadow(0 0 6px rgba(156, 194, 255, .9)); }
.fx-step svg { width: 100%; height: auto; display: block; }
.fx-dome {
  position: fixed; z-index: 4; border-radius: 50%; border: 3px solid rgba(255, 232, 160, .9);
  background: radial-gradient(circle, rgba(255, 240, 190, .05) 40%, rgba(255, 216, 107, .45) 64%, rgba(255, 216, 107, 0) 72%);
  box-shadow: 0 0 26px rgba(255, 200, 80, .75), inset 0 0 22px rgba(255, 220, 130, .6);
}
.fx-sparkle.gold { background: #ffe08a; }
/* The scouting effects (anim.js spyglass(), lantern(), hawk()): drawings in stacked layers (art.js) that
   move on their own, so each layer is its own finished picture the browser only shifts. */
.fx-spyglass, .fx-lantern, .fx-hawk { position: fixed; pointer-events: none; }
.fx-part { position: absolute; inset: 0; will-change: transform; }
.fx-part svg { width: 100%; height: 100%; display: block; }
.fx-spyglass { filter: drop-shadow(0 6px 5px rgba(0, 0, 0, .45)); }
.fx-lantern { filter: drop-shadow(0 0 14px rgba(255, 190, 80, .8)); }
/* Scout's lens sweeping the deck: a brass rim round bright glass */
.fx-lens {
  position: fixed; z-index: 4; border-radius: 50%; border: 5px solid #c9a23a;
  background: radial-gradient(circle at 34% 30%, rgba(255, 255, 255, .6) 0 7%, rgba(220, 245, 255, .2) 20%, rgba(155, 231, 255, .08) 62%);
  box-shadow: 0 0 0 3px #2b1a12, 0 0 20px rgba(255, 230, 150, .7), inset 0 0 18px rgba(155, 231, 255, .55);
}
/* the Lantern's light on the deck */
.fx-lightpool { position: fixed; z-index: 3; border-radius: 50%; background: radial-gradient(closest-side, rgba(255, 214, 120, .5), rgba(255, 170, 60, .22) 55%, rgba(255, 150, 40, 0)); }
/* the hawk's shadow on the table */
.fx-hawk-shadow { position: fixed; z-index: 5; border-radius: 50%; background: radial-gradient(closest-side, rgba(0, 0, 0, .45), rgba(0, 0, 0, 0)); }
/* Escape Rope: the Mimic watches a swinging rope, snaps at it and misses, and sulks */
/* A soft shadow under the Mimic rather than a drop-shadow filter: the lid and eyes move every frame,
   and the filter blurred the whole Mimic again each time (about 500 redraws a scene). */
.fx-mimic { position: fixed; }
.fx-mimic::before { content: ""; position: absolute; z-index: -1; left: 12%; right: 12%; bottom: -2%; height: 18%; border-radius: 50%; background: radial-gradient(closest-side, rgba(0, 0, 0, .55), rgba(0, 0, 0, 0)); }
.fx-mimic svg { width: 100%; height: 100%; display: block; }
/* the Mimic's moving parts are stacked layers (art.js mimicParts), moved by transform and opacity only */
.fx-mimic .tc-layer { position: absolute; inset: 0; will-change: transform; }
.fx-mimic .tc-lid { transform-origin: 50% 51%; }
.fx-rope { position: fixed; }
.fx-rope svg { width: 100%; height: auto; display: block; }
.fx-puff { position: fixed; border-radius: 50%; background: radial-gradient(circle at 40% 45%, rgba(235, 230, 225, .95), rgba(170, 160, 155, .75) 45%, rgba(120, 110, 105, 0) 70%); }
/* The Earthquake (anim.js rubble()): grey-brown stones, lit from the top left */
.fx-stone {
  position: fixed; left: 0; top: 0; border-radius: 42% 58% 50% 46% / 50% 44% 56% 50%;
  background: radial-gradient(circle at 35% 30%, #c4ad8e, #8a7560 45%, #4e4034); box-shadow: 0 0 0 1.5px rgba(20, 12, 8, .75), 0 3px 4px rgba(10, 6, 4, .55);
}
/* Counterspell (anim.js runes()): a ring of runes under the stamp; gold for the Bard */
.fx-runes {
  position: fixed; border-radius: 50%; will-change: transform, opacity;
  border: 3px dashed rgba(196, 150, 255, .95); outline: 2px solid rgba(160, 110, 255, .55); outline-offset: 7px;
  box-shadow: 0 0 26px 6px rgba(140, 80, 240, .55), inset 0 0 22px 4px rgba(160, 110, 255, .5);
}
.fx-runes::after { content: ""; position: absolute; inset: 18%; border-radius: 50%; border: 2px dotted rgba(220, 190, 255, .9); }
.fx-runes.bard { border-color: rgba(255, 216, 107, .95); outline-color: rgba(201, 162, 58, .6); box-shadow: 0 0 26px 6px rgba(255, 190, 60, .5), inset 0 0 22px 4px rgba(255, 210, 63, .45); }
.fx-runes.bard::after { border-color: rgba(255, 236, 170, .9); }
/* A Mimic's bite (anim.js eaten()): a red flash as it snaps shut */
.fx-flash.red { background: radial-gradient(ellipse at center, rgba(255, 90, 40, .55), rgba(150, 10, 6, .95)); }
/* Taunt (anim.js taunt()): a warm flash, a wagging title and a pointing glove; the ring pops on each poke */
.fx-flash.taunt { background: radial-gradient(ellipse at center, rgba(255, 160, 74, .3), rgba(120, 50, 10, .85)); }
.fx-banner.taunt { color: #ffa04a; }
.fx-banner.taunt::before { border-color: #b8520e; }
.fx-glove { position: fixed; pointer-events: none; }
.fx-glove svg { width: 100%; height: auto; display: block; }
.fx-ring { position: fixed; width: 120px; height: 120px; margin: -60px 0 0 -60px; border-radius: 50%; border: 6px solid #ff8a1f; box-shadow: 0 0 24px rgba(255, 138, 31, .8), inset 0 0 18px rgba(255, 210, 63, .7); }

/* ---------- battle embers (src/embers.js) ---------- */
/* The sparks fly above the table, below the Ayoko! prompt, the effects and dialogs; the glow (the
   hearth) sits right after the backdrop, under the table, so it never tints names and counts. */
.embers { position: fixed; inset: 0; z-index: 35; pointer-events: none; overflow: hidden; opacity: 0; }
.embers-hearth { z-index: 0; }
/* will-change: the glow flickers all through the battle; without its own layer each change repainted the
   whole backdrop (about 1000 full-screen repaints in 5 seconds) */
.embers-glow {
  position: absolute; inset: 0; opacity: 0; will-change: opacity;
  /* strongest in the corners and up the sides; light at the bottom middle, where the hand is */
  background:
    radial-gradient(ellipse 36% 34% at 0 100%, rgba(255, 96, 24, .42), rgba(255, 96, 24, 0)),
    radial-gradient(ellipse 36% 34% at 100% 100%, rgba(255, 96, 24, .42), rgba(255, 96, 24, 0)),
    linear-gradient(90deg, rgba(216, 38, 31, .55), rgba(216, 38, 31, 0) 12%, rgba(216, 38, 31, 0) 88%, rgba(216, 38, 31, .55)),
    linear-gradient(0deg, rgba(255, 96, 24, .4), rgba(255, 96, 24, 0) 8%),
    linear-gradient(180deg, rgba(150, 16, 10, .45), rgba(150, 16, 10, 0) 10%);
}
/* the flicker stays on the side edges: the corners hold my seat's name and count on desktop */
.embers-flicker {
  background: linear-gradient(90deg, rgba(255, 140, 40, .45), rgba(255, 140, 40, 0) 6%, rgba(255, 140, 40, 0) 94%, rgba(255, 140, 40, .45));
}
.ember { position: absolute; border-radius: 50%; background: radial-gradient(circle, #ffe9a8 0 22%, #ffa53a 40%, rgba(255, 90, 24, .55) 56%, rgba(255, 70, 20, 0) 72%); }
.ember.hot { background: radial-gradient(circle, #fff 0 24%, #ffe27a 42%, rgba(255, 138, 31, .5) 58%, rgba(255, 138, 31, 0) 72%); }

/* ---------- modal ---------- */
.modal { position: fixed; inset: 0; z-index: 60; display: grid; place-items: center; padding: 16px; }
.modal-scrim { position: absolute; inset: 0; background: rgba(8, 4, 3, .74); }
.modal-box {
  position: relative; width: min(560px, 100%); max-height: calc(100dvh - 32px); overflow: auto;
  background: var(--raise); border: 3px solid var(--ink); border-radius: 22px; padding: 20px; box-shadow: 0 24px 60px rgba(0, 0, 0, .6);
  text-align: center; /* Ernest, 2026-10-17: pop-ups read centred */
}
/* long reading stays left-aligned: How to play and the game log */
.modal-box:has(.rules), .modal-box:has(.log-list) { text-align: left; }
.modal-title { font-family: var(--display); font-weight: 400; font-size: 1.7rem; line-height: 1.1; margin: 0 0 12px; color: var(--accent); }
.modal-body p { margin: 0 0 12px; }
.modal-row { display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; margin-top: 14px; }
.modal-cards { display: flex; flex-wrap: wrap; justify-content: center; gap: 10px; }
.modal-cards .slot { display: flex; flex-direction: column; align-items: center; gap: 4px; font-weight: 700; font-size: .9rem; color: var(--muted); }
.modal-cards .card { --cw: clamp(78px, 24vw, 112px); }
/* pause / settings: over any open pop-up (.modal is 60), under the win's coins (70) */
.pause { z-index: 65; }
.pause-box { width: min(400px, 100%); }
.volume { display: grid; grid-template-columns: 1fr auto; gap: 6px 12px; align-items: center; text-align: left; margin: 4px 0 6px; }
.volume label { font-weight: 800; }
.volume output { justify-self: end; font-variant-numeric: tabular-nums; color: var(--muted); font-weight: 700; }
.volume input[type="range"] { grid-column: 1 / -1; width: 100%; height: 44px; margin: 0 0 8px; accent-color: var(--accent); cursor: pointer; }
.volume .mute-switch { min-height: 44px; display: flex; align-items: center; margin-bottom: 6px; cursor: pointer; }
.volume.muted input[type="range"], .volume.muted output { opacity: .4; }
.anim-setting { border-top: 2px solid rgba(255, 236, 210, .12); padding-top: 12px; margin-top: 0; }
.anim-setting .mute-switch { margin-bottom: 0; }
.anim-note { grid-column: 1 / -1; margin: -2px 0 4px; font-size: .85rem; line-height: 1.3; color: var(--muted); }
/* phone landscape: the sound on the left, the animations and the button on the right, so it fits without scrolling */
@media (orientation: landscape) and (max-height: 600px) {
  .pause-box {
    width: min(660px, 100%); display: grid; grid-template-columns: 1fr 1fr; column-gap: 22px; align-items: start;
    grid-template-areas: "title title" "sound anim" "sound go"; grid-template-rows: auto auto 1fr;
  }
  .pause-box > .modal-title { grid-area: title; margin-bottom: 6px; }
  .pause-box > #volume { grid-area: sound; margin: 0; }
  .pause-box > .anim-setting { grid-area: anim; border-top: 0; padding: 8px 0 0 20px; border-left: 2px solid rgba(255, 236, 210, .12); margin: 0; }
  .pause-box > .modal-row { grid-area: go; align-self: end; margin-top: 8px; }
  .pause-box .volume input[type="range"] { height: 34px; margin-bottom: 2px; }
}
/* the mute switch: a pill with a sliding knob, yellow when on */
.switch {
  appearance: none; width: 56px; height: 32px; margin: 0 0 6px; border-radius: 999px; position: relative; cursor: pointer;
  background: rgba(255, 248, 239, .15); border: 2px solid rgba(255, 248, 239, .35); transition: background .15s, border-color .15s;
}
.switch::before { content: ""; position: absolute; top: 3px; left: 3px; width: 22px; height: 22px; border-radius: 50%; background: var(--text); transition: transform .15s; }
.switch:checked { background: var(--accent); border-color: var(--ink); }
.switch:checked::before { transform: translateX(24px); background: var(--ink); }
.switch:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }
.pick-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(84px, 1fr)); gap: 10px; justify-items: center; }
.pick-grid .card { --cw: 84px; }
.pick-grid .card[aria-pressed="true"] { box-shadow: 0 0 0 4px var(--accent); }
/* A pair: the target's cards face down in an even fan, like a held hand (the arc is set in ui.js) */
/* One row: the overlap grows with the count (--n, set in ui.js) so any hand fits the dialog. */
/* The side padding keeps the tilted end cards inside the dialog. */
.steal-fan {
  --cw: 76px; display: flex; justify-content: center;
  padding: 22px calc(var(--cw) * .45) max(30px, calc(14px + var(--dy, 0px) + var(--cw) * .5 * var(--sin, 0))); /* room for the lowest end card */
}
.steal-fan .card { flex: none; position: relative; }
.steal-fan .card + .card { margin-left: min(-8px, calc((100% - var(--cw) * var(--n)) / (var(--n) - 1))); }
.target-list { display: grid; gap: 8px; }
.target {
  display: flex; align-items: center; gap: 12px; width: 100%; min-height: 60px; padding: 6px 14px; border-radius: 14px;
  background: rgba(255, 246, 229, .07); border: 2px solid var(--line); text-align: left; font-weight: 800;
}
.target:hover { border-color: var(--accent); }
.target .seat-avatar { width: 46px; }
.target small { margin-left: auto; color: var(--muted); font-weight: 600; white-space: nowrap; }
.pos-control { display: flex; flex-direction: column; gap: 10px; }
.pos-control input[type="range"] { width: 100%; accent-color: var(--accent); height: 32px; }
.pos-readout { font-family: var(--display); font-size: 1.4rem; text-align: center; color: var(--text); margin: 0; }
.pos-quick { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; }
.pos-quick .btn { min-height: 40px; font-size: 1rem; padding-inline: 14px; }
/* The one modal box is reused by every pop-up, so the rules size comes from its content, not a class that would stay on */
.modal-box:has(.rules) { width: min(720px, 100%); }
.rules h3 { font-family: var(--display); font-weight: 400; font-size: 1.2rem; line-height: 1.1; margin: 18px 0 6px; color: var(--accent); }
.rules ol { padding-left: 1.3em; margin: 0 0 8px; }
.rules li { margin-bottom: 6px; }
.rule-cards { display: grid; gap: 10px; }
.rules .rules-credit { margin: 22px 0 4px; font-size: 0.875rem; color: var(--muted); }
.rules-credit a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }
.rule-card { display: grid; grid-template-columns: 64px minmax(0, 1fr); gap: 12px; align-items: center; }
.rule-card .card { --cw: 64px; }
.rule-head { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; margin-bottom: 2px; }
.rule-card .rule-name { font-family: var(--display); font-weight: 400; font-size: 1.1rem; line-height: 1.1; }
/* how many copies are in the deck */
.rule-count {
  padding: 1px 8px; border-radius: .8em; border: 1.5px solid var(--line); color: var(--text);
  font-size: .78rem; font-weight: 800;
  /* a long count ("1 bawat player + 2 (6 lang pag 5 players…") wraps: on one line it widened the list past a phone's pop-up */
}
.rule-card .rule-text { color: var(--muted); font-size: .92rem; }
/* tabs (the profile dialogs) */
.rules-tabs { display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 12px; }
.rules-tabs button {
  min-height: 40px; padding: 0 14px; border-radius: 999px; border: 2px solid var(--line); background: transparent;
  color: var(--text); font-weight: 800; font-size: .95rem;
}
.rules-tabs button[aria-selected="true"] { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.rules-tabs button:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }
@media (max-width: 559px) { .tab-long { display: none; } } /* three tabs fit one line on a phone */

/* ---------- choice chips: game mode and hero, on the start screen and in the lobby ----------
   A row of chips with the picked one's note under it: each note follows its chip in the markup,
   only the checked chip's note shows, and `order` moves it below the row. */
.chips { display: flex; flex-wrap: wrap; justify-content: center; gap: 6px; container-type: inline-size; }
.chip {
  --n: 4; flex: 0 0 calc((100% - (var(--n) - 1) * 6px) / var(--n)); min-width: 0;
  position: relative; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 5px;
  min-height: 74px; padding: 10px 4px 8px; border-radius: 14px; border: 2px solid var(--edge); background: var(--bg);
  text-align: center; cursor: pointer;
}
.chip input { position: absolute; inset: 0; opacity: 0; margin: 0; cursor: pointer; }
.chip > b { font-family: var(--display); font-weight: 400; font-size: .98rem; letter-spacing: .02em; line-height: 1.1; }
.chip .hero-mark { font-size: 1.2rem; }
.chip:hover { border-color: var(--muted); }
.chip:has(input:checked) { border-color: var(--accent); background: var(--raise-2); }
.chip:has(input:checked) > b { color: var(--accent); }
.chip:has(input:focus-visible) { outline: 3px solid var(--accent); outline-offset: 2px; }
.chip:has(input:disabled) { opacity: .4; cursor: not-allowed; border-color: var(--edge); }
.chip:has(input:disabled) input { cursor: not-allowed; }
/* all seven in one row once there's room: each as wide as its name needs, sharing out the rest. Below
   that, four and three of the same width (Cinzel is wide: at 400px the Bard wrapped alone and stretched
   across the panel, Ernest 2026-10-21) */
@container (min-width: 620px) {
  .heroes > .chip { flex: 1 1 0; min-width: min-content; padding-inline: 4px; min-height: 66px; }
  .heroes > .chip > b { font-size: .84rem; }
}
/* a 360px phone: "Random" ran past its chip's edges */
@container (max-width: 300px) { .heroes > .chip > b { font-size: .8rem; letter-spacing: 0; } }
/* the modes: two wide chips, the hearts over the name on a phone and beside it on a wider panel */
.modes > .chip { --n: 2; gap: 3px; min-height: 60px; }
.modes > .chip > b { font-size: 1.1rem; }
@container (min-width: 400px) { .modes > .chip { flex-direction: row; gap: 10px; min-height: 54px; } }
.chip-hearts { display: inline-flex; gap: 3px; }
.chip-hearts .heart { font-size: 1.05rem; }
.chip-note {
  display: none; order: 1; flex: 1 0 100%; margin: 2px 0 0; padding: 10px 14px; border-radius: 12px;
  background: var(--raise-2); color: var(--muted); font-size: .92rem; line-height: 1.35; text-align: left;
}
.chip-note b { color: var(--text); font-weight: 800; }
.chip:has(input:checked) + .chip-note { display: block; }
/* Tap-the-card dialogs (the Lantern): the cards side by side */
.tap-pair { display: flex; justify-content: center; gap: clamp(14px, 5vw, 36px); margin: 4px 0 12px; }
/* Tap-the-card choices (ui.js tapCard()): each card and its caption is one button that lifts and glows */
.pick-card {
  --cw: clamp(104px, 30vw, 150px);
  display: flex; flex-direction: column; align-items: center; justify-content: space-between; gap: 8px; padding: 6px; border: 0; border-radius: 14px;
  background: none; color: var(--text); font: inherit; cursor: pointer; transition: transform .15s ease; touch-action: manipulation;
}
.pick-card .card { transition: box-shadow .15s ease; }
.pick-cap { font-family: var(--display); font-size: clamp(.95rem, 3.6vw, 1.1rem); line-height: 1.15; text-align: center; color: var(--accent); max-width: calc(var(--cw) + 20px); }
@media (hover: hover) { .pick-card:hover { transform: translateY(-6px); } .pick-card:hover .card { box-shadow: 0 0 0 4px var(--accent), 0 10px 24px rgba(0, 0, 0, .5); } }
.pick-card:active { transform: scale(.96); }
.pick-card:focus-visible { outline: none; }
.pick-card:focus-visible .card { box-shadow: 0 0 0 4px var(--accent), 0 0 0 7px var(--ink); }
/* The Lantern's "send it to the bottom": a short stack of backs with the card peeking out from under it */
.pick-deck { position: relative; display: block; width: var(--cw); aspect-ratio: 5 / 7; margin-bottom: 18px; }
.pick-deck .card { position: absolute; inset: 0; width: 100%; }
.pick-deck:has(.on-bottom) { margin-bottom: 44px; }
.pick-deck .card.on-bottom { transform: translate(-6px, 34px) rotate(-6deg); }
.pick-deck .card:nth-child(2) { transform: translate(10px, 8px) rotate(6deg); }
.pick-deck .card:nth-child(3) { transform: translateY(4px); }
.pick-card:focus-visible .pick-deck .card:not(.on-bottom), .pick-card:hover .pick-deck .card:not(.on-bottom) { box-shadow: none; }

@media (max-width: 759px) {
  /* the moves stay on one line (a second line of buttons pushed my tag under them on a short phone);
     a long label wraps inside its own button instead */
  .actions { flex-wrap: nowrap; align-items: stretch; gap: 6px; }
  .actions .btn { flex: 0 1 auto; min-width: 0; white-space: normal; text-align: center; padding-inline: 16px; }
  .actions .btn-primary { flex-shrink: 0; white-space: nowrap; } /* "Mag-draw" broke at its hyphen */
  .actions:has(> :nth-child(3)) { gap: 5px; }
  .actions:has(> :nth-child(3)) .btn { font-size: .95rem; padding-inline: 12px; }
  .actions:has(> :nth-child(3)) .btn-more { display: none; } /* "I-play": the card info above names the card */
  /* I-play, pair, 3 of a kind and draw: still one row, each label on up to two lines. Two rows of buttons
     made the column taller than the screen, and the grid then squeezed the row so the second one ran
     over my tag (check:ui, 2026-10-20). */
  .actions:has(> :nth-child(4)) { gap: 4px; }
  /* Cinzel is wide: "PICKPOCKET" alone took 107px at .86rem, and the four pushed the page off a 390px phone
     (check:ui, 2026-10-21), so they shrink a little more and "Open a chest" may wrap too */
  .actions:has(> :nth-child(4)) .btn { font-size: .78rem; padding-inline: 6px; letter-spacing: 0; line-height: 1.15; min-width: min-content; }
  .actions:has(> :nth-child(4)) .btn-primary { white-space: normal; }
  /* A long card info (Laban Tayo!, the Mabait, a Ligaw) pushed a tall phone's hand 27px off the bottom:
     the piles may shrink further to make room, and past what's left (~600px goes to the rest of a
     10-player table) the info scrolls, with a fade at its foot (.more, set in ui.js). */
  .table {
    min-height: calc(var(--cw) * 1.12 + 56px);
    --pw: clamp(calc(var(--cw) * .8), min(31vw, calc((100cqh - 64px) * 5 / 7), calc((100cqw - var(--note) - 2 * clamp(28px, 8vw, 80px)) / 2)), 168px);
  }
  .card-info { max-height: max(88px, calc(100dvh - 600px)); overflow-y: auto; overscroll-behavior: contain; }
}
/* Turns owed after a Taunt (Ernest, 2026-10-19: make it stand out): a red pill */
.seat-turns {
  display: inline-flex; align-items: baseline; gap: .25em; padding: .12em .7em .14em .55em; border-radius: 999px;
  background: var(--red); color: #fff; border: 2px solid var(--ink); box-shadow: 0 3px 0 var(--ink), 0 0 16px 3px rgba(216, 38, 31, .6);
  font-family: var(--display); font-size: clamp(.82rem, 2.7vw, 1.1rem); line-height: 1.2; letter-spacing: .03em; text-transform: uppercase; white-space: nowrap; position: relative; z-index: 2;
}
.seat-turns[hidden] { display: none; }
.seat-turns b { font-weight: 400; font-size: 1.35em; line-height: 1; }
.me-tag .seat-turns { margin-left: 4px; }
/* A hero's mark (src/art.js heroIcon) in the hero's colour, and its name; dim and struck once the power is used */
.seat-hero { display: inline-flex; align-items: center; flex: none; }
.seat-hero:empty { display: none; }
/* On a seat the mark stands in for the little card in the count's line ("⚔ 7 cards"); the desktop table
   gives it a line of its own with the hero's name. It used to sit on the portrait's corner and covered
   the ring and the held cards (Ernest, 2026-10-22). The hearts stay on the portrait's upper-right. */
.seat-meta .hero-mark { font-size: .82em; }
.seat-hero:not(:empty) + .mini-card { display: none; }
/* Sized from the portrait's own width (cqw), so they fit a 32px landscape cat and a 200px desktop one alike. */
.seats .seat-avatar, .me-tag .seat-avatar { position: relative; container-type: inline-size; }
.seat-face { display: block; width: 100%; height: 100%; }
.seat-avatar > .seat-hearts {
  position: absolute; right: -6px; top: -4px; z-index: 1; padding: 2px 3px; border-radius: 999px;
  background: rgba(18, 11, 10, .85); font-size: max(7px, min(17cqw, 1.1rem));
}
.me-tag .seat-avatar > .seat-hearts { font-size: max(10px, min(17cqw, 1.1rem)); } /* my own hearts stay easy to count */
.seat-avatar .heart svg { width: 100%; height: auto; }
.seat-heroname { display: none; }
.seat-heroname, .me-heroname { align-items: center; gap: .35em; max-width: 100%; font-weight: 800; color: var(--muted); }
.me-heroname { display: inline-flex; font-size: .8rem; }
.me-heroname .hero-mark { font-size: 1.15em; }
@media (max-width: 379px) { .me-heroname .hero-name { display: none; } } /* a 360px row has room for the mark only */
/* A power still to use glows in its hero's colour, lightened so the dark ones (Rogue, Wizard) show on the
   table; mine breathes on my turn (Ernest, 2026-10-22). The breath is a separate ring that changes only
   its opacity on its own layer, so it costs no repaint. */
.hero-mark {
  position: relative; display: inline-grid; place-items: center; flex: none; width: 1.7em; height: 1.7em; border-radius: 50%;
  background: var(--hero); color: #fff; border: 2px solid var(--ink);
  box-shadow: 0 2px 0 var(--ink), 0 0 .5em .22em color-mix(in srgb, var(--hero) 35%, #ffe08a);
}
.hero-mark svg { width: 62%; height: 62%; }
.hero-mark.spent { background: #4a3c38; color: #a89890; box-shadow: none; }
.me-tag.turn .hero-mark:not(.spent)::after {
  content: ""; position: absolute; inset: -2px; border-radius: 50%; pointer-events: none;
  box-shadow: 0 0 .7em .3em color-mix(in srgb, var(--hero) 35%, #ffe9a8);
  opacity: 0; will-change: opacity; animation: power-breathe 1.3s ease-in-out infinite alternate;
}
@keyframes power-breathe { to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .me-tag.turn .hero-mark:not(.spent)::after { animation: none; opacity: .8; } }
.hero-mark.big { font-size: 1.6rem; }
.hero-name { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.hero-mark.spent + .hero-name { text-decoration: line-through; text-decoration-thickness: 1.5px; }
/* Adventure mode's hearts, under the count */
.seat-hearts { display: inline-flex; gap: 2px; }
.seat-hearts:empty { display: none; }
.heart { display: block; width: 1em; font-size: .95rem; line-height: 0; }
.heart svg { width: 100%; height: auto; }
.heart.lost { opacity: .3; filter: grayscale(1); }
/* the hero power button, and the Bard's Distraction in the counter prompt */
.btn-power { background: #6c3fc4; color: #fff; box-shadow: 0 4px 0 var(--ink); }
.btn-power:hover { background: #7d52d6; }
/* "Use a power?" */
.power-ask { text-align: center; }
.power-ask .hero-mark { margin: 0 auto 8px; }
.power-note { color: var(--muted); font-size: .92rem; }
.rule-hero .hero-mark.big { margin: 0 auto; font-size: 1.9rem; }
.fx-dim { position: fixed; inset: 0; background: radial-gradient(circle at var(--x) var(--y), rgba(8, 8, 12, 0) 0, rgba(8, 8, 12, .15) 90px, rgba(8, 8, 12, .82) 340px); }
.log-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column-reverse; gap: 6px; }
.log-list li { padding: 6px 10px; border-radius: 10px; background: rgba(255, 246, 229, .06); }
.log-list li.mine { background: rgba(255, 210, 63, .13); box-shadow: inset 0 0 0 1px rgba(255, 210, 63, .28); }
.result { text-align: center; }
.result .seat-avatar { width: 120px; margin: 0 auto 4px; }
.result .modal-title { font-size: 2.4rem; }
.result-saved { color: var(--accent); font-weight: 700; font-size: .95rem; }
/* this game's XP, rank and new medals, filled in when the profiles server answers (Barkada.fillProgress) */
.result-progress { margin: 4px auto 14px; max-width: 360px; padding: 12px 14px; border-radius: 16px; background: var(--bg); text-align: left; }
.prog-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.prog-xp { font-family: var(--display); font-weight: 400; font-size: 1.5rem; color: #6fe08f; -webkit-text-stroke: 1px var(--ink); paint-order: stroke fill; }
.prog-xp.lost { color: #ff8a7a; }
.prog-move { margin: 8px 0 0; font-weight: 800; }
.prog-move.up { color: var(--accent); }
.prog-move.down { color: var(--muted); }
.prog-new { margin: 12px 0 6px; font-family: var(--display); font-size: 1.2rem; color: var(--accent); }
.prog-medals { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.prog-medals li { display: flex; align-items: center; gap: 10px; }
.prog-medals li > span:last-child { display: flex; flex-direction: column; line-height: 1.2; }
.prog-medals small { color: var(--muted); font-size: .85rem; }

/* ---------- ranks and medals ---------- */
.rank-badge {
  display: inline-flex; align-items: center; gap: 6px; padding: 2px 10px 3px 3px; border-radius: 999px; vertical-align: middle;
  background: #2e211f; border: 2px solid var(--accent); color: var(--text); font-weight: 800; font-size: .9rem; line-height: 1.2; white-space: nowrap;
}
.rank-badge i {
  display: grid; place-items: center; width: 1.6em; height: 1.6em; border-radius: 50%; font-style: normal;
  background: var(--accent); color: var(--accent-ink); font-family: var(--display); font-weight: 400; font-size: .85rem;
}
/* the top three ranks get a hotter ring */
.rank-badge[data-rank="7"], .rank-badge[data-rank="8"], .rank-badge[data-rank="9"] { border-color: #ff7a1f; box-shadow: 0 0 10px rgba(255, 122, 31, .45); }
.profile-text .rank-badge { font-size: .8rem; }
.xp-bar { height: 12px; margin-top: 10px; border-radius: 999px; background: #3a2a27; border: 2px solid var(--ink); overflow: hidden; }
.xp-bar i { display: block; height: 100%; background: linear-gradient(90deg, #ff7a1f, var(--accent)); border-radius: inherit; }
.xp-label { display: block; margin-top: 4px; color: var(--muted); font-size: .85rem; }
.stats-rank { margin-top: 10px; }
.medals-count { margin: 0 0 4px; color: var(--muted); }
.medals-count b { color: var(--accent); font-size: 1.1rem; }
.medal-group { margin: 12px 0 6px; color: var(--muted); font-size: .8rem; font-weight: 800; text-transform: uppercase; letter-spacing: .08em; }
.medal-list { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 6px; }
.medal { display: flex; align-items: center; gap: 10px; padding: 6px 10px; border-radius: 12px; background: var(--bg); }
.medal.locked .medal-text { opacity: .6; }
.medal-icon { flex: none; width: 30px; }
.medal-svg { display: block; width: 100%; height: auto; }
.medal-text { display: flex; flex-direction: column; line-height: 1.2; min-width: 0; }
.medal-text small { color: var(--muted); font-size: .82rem; }
.medal-text em { font-style: normal; font-weight: 800; font-size: .78rem; color: var(--accent); }

/* ---------- Barkada profile and leaderboard ---------- */
.profile-bar {
  display: flex; align-items: center; flex-wrap: wrap; gap: 8px 12px; padding: 10px 10px 10px 14px;
  border-radius: 14px; background: var(--raise-2);
}
.profile-text { flex: 1 1 200px; margin: 0; text-align: left; color: var(--muted); font-size: .92rem; line-height: 1.3; }
.profile-text b { color: var(--accent); }
.modal-box:has(.board), .modal-box:has(.profile-form) { text-align: left; }
.profile-form { display: flex; flex-direction: column; gap: 12px; }
.profile-form .rules-tabs { margin: 0; }
.profile-form p { margin: 0; } /* the form's gap spaces it, not .modal-body p */
.profile-help { color: var(--muted); }
.field input[type="password"] {
  min-height: 48px; border-radius: 12px; border: 2px solid var(--line); background: var(--bg); padding: 8px 14px; font-size: 1.05rem;
}
.field input.pin-input { max-width: 170px; font-family: var(--display); font-size: 1.5rem; letter-spacing: .4em; padding-block: 4px; }

.board-note { margin: 0 0 10px; color: var(--muted); font-size: .95rem; }
.board-list { display: flex; flex-direction: column; gap: 4px; }
.board-row {
  display: grid; grid-template-columns: 2em minmax(0, 1fr) repeat(3, 4.4em); align-items: center; gap: 8px;
  width: 100%; min-height: 44px; padding: 6px 12px; border-radius: 12px; border: 2px solid transparent;
  background: var(--bg); color: var(--text); font: inherit; text-align: left; cursor: pointer;
}
.board-row:hover { border-color: var(--line); }
.board-row:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }
.board-row.is-me { border-color: var(--accent); }
.board-head { background: transparent; min-height: 0; padding-block: 0; color: var(--muted); font-weight: 800; font-size: .85rem; cursor: default; }
.board-head:hover { border-color: transparent; }
.board-row > span:nth-child(n + 3) { text-align: right; font-variant-numeric: tabular-nums; font-weight: 800; }
.board-row small { color: var(--muted); font-weight: 600; }
.board-rank { color: var(--muted); font-weight: 800; }
.board-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 800; }
.board-who { display: flex; flex-direction: column; min-width: 0; line-height: 1.15; }
.board-row .board-title { color: var(--accent); font-size: .76rem; font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.board-back { margin-bottom: 10px; }

.stats-name { margin: 0; font-family: var(--display); font-weight: 400; font-size: 1.6rem; line-height: 1.1; color: var(--accent); }
.stats-since { margin: 2px 0 0; color: var(--muted); font-size: .9rem; }
.stats-card h4 { margin: 16px 0 6px; font-family: var(--display); font-weight: 400; font-size: 1.05rem; letter-spacing: .02em; }
.stats-bigs { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; margin-top: 12px; }
.stat-big { background: var(--bg); border-radius: 14px; padding: 10px 6px; text-align: center; }
.stat-big b { display: block; font-family: var(--display); font-weight: 400; font-size: 1.8rem; line-height: 1; color: var(--accent); }
.stat-big span { display: block; margin-top: 4px; color: var(--muted); font-size: .82rem; font-weight: 700; line-height: 1.15; }
.stats-line { margin: 0; }
.stats-levels { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.stats-levels div { display: flex; justify-content: space-between; align-items: baseline; gap: 6px; background: var(--bg); border-radius: 12px; padding: 8px 12px; }
.stats-levels span { color: var(--muted); font-weight: 700; }
.stats-levels b, .stats-list dd { font-variant-numeric: tabular-nums; }
.stats-levels small { color: var(--muted); font-weight: 600; }
.stats-list { display: grid; grid-template-columns: 1fr 1fr; gap: 0 18px; margin: 0; }
.stats-list div { display: flex; justify-content: space-between; gap: 10px; padding: 5px 0; border-bottom: 1px solid rgba(255, 248, 239, .1); }
.stats-list dt { color: var(--muted); }
.stats-list dd { margin: 0; font-weight: 800; }
.stats-extra { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 16px; }
.stats-fav { display: flex; align-items: center; gap: 12px; background: var(--bg); border-radius: 14px; padding: 10px 12px; }
.stats-fav-card .card { --cw: 74px; }
.stats-rivals { display: grid; gap: 8px; }
.stats-fav p, .stats-rivals p { margin: 0; display: flex; flex-direction: column; line-height: 1.2; }
.stats-rivals p { background: var(--bg); border-radius: 14px; padding: 8px 12px; }
.stats-fav span, .stats-rivals span { color: var(--muted); font-size: .85rem; font-weight: 700; }
.stats-fav b, .stats-rivals b { font-size: 1.1rem; }
.stats-fav small, .stats-rivals small { color: var(--muted); }
@media (max-width: 559px) {
  .board-row { grid-template-columns: 1.6em minmax(0, 1fr) repeat(3, 3.3em); gap: 6px; padding-inline: 8px; }
  .stats-bigs { grid-template-columns: 1fr 1fr; }
  .stats-list, .stats-extra { grid-template-columns: 1fr; }
  .stats-levels div { flex-direction: column; align-items: flex-start; gap: 0; }
}
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.noscript { padding: 24px; text-align: center; }

@media (min-width: 760px) {
  :root { --cw: clamp(80px, min(8.5vw, 13.5vh), 124px); }
  .start-art { width: 156px; }
  .start { padding-top: 36px; }
  .bar { padding-top: 14px; }
  .status { font-size: 1.08rem; }
}
/* ---------- desktop table (after Exploding Kittens 2's layout) ----------
   Full screen instead of a column: the cats sit in an arc across the top holding their cards,
   the piles are big in the middle with the story on the left and your moves on the right,
   and you sit in the bottom-left corner behind a large hand. Sizes follow the window's height first. */
@media (min-width: 1024px) and (min-height: 640px) {
  :root {
    --cw: clamp(100px, min(9.5vw, 17.5vh), 230px);
    /* what's left after the cats and the hand, with room for a two-line Markado pill on a seat and a
       marked card standing up out of the fan (at -95px "Bomba: 50%" sat under them, check:ui 2026-10-20) */
    --pile-w: clamp(96px, min(12vw, 30vh - 115px), 300px);
    --av: clamp(84px, min(8.5vw, 14.5vh), 210px);
  }
  /* a hand big enough for two rows (20-odd cards at 1024px): the raised back row takes its height from the piles */
  .game:has(.hand.two-rows) { --pile-w: clamp(84px, min(12vw, 30vh - 115px - var(--cw) * .42), 300px); }

  /* start screen: the chest, title and tagline on the left; on the right, the menu or the setup panel */
  .start.screen {
    max-width: 1140px; display: grid; grid-template-columns: minmax(0, 1fr) minmax(420px, 480px);
    grid-template-areas: "brand side";
    align-items: center; column-gap: clamp(40px, 6vw, 100px); padding-block: 24px;
  }
  .start-brand { grid-area: brand; }
  .start-art { width: clamp(200px, 19vw, 270px); }
  .logo { font-size: clamp(3.8rem, 5.4vw, 5.6rem); margin-top: 28px; }
  .tagline { font-size: 1.3rem; margin: 14px 0 0; }
  .title-menu { grid-area: side; justify-self: center; max-width: 400px; margin-top: 0; gap: 14px; }
  .title-menu > .btn-big { min-height: 64px; font-size: 1.6rem; }
  .setup { grid-area: side; max-width: none; gap: 12px; border-radius: 26px; padding: 20px 22px 18px; }
  .setup .mode-fields { gap: 12px; }

  /* lobby: room code, share and the host's settings on the left, the players and Simulan on the right */
  .lobby.screen { justify-content: center; padding-block: 40px; }
  .lobby-box {
    max-width: 940px; display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr); column-gap: clamp(28px, 3.5vw, 48px);
    align-items: start; padding: 32px;
  }
  .lobby-col { display: flex; flex-direction: column; gap: 14px; }
  .lobby-head { margin-top: 0; }

  /* game screen */
  /* clip: a card dealt or lifted past the bottom edge must not flash a scrollbar and reflow the table */
  .game.screen { max-width: none; padding-inline: clamp(20px, 2.5vw, 48px); overflow: clip; }
  .game {
    grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
    grid-template-rows: auto auto minmax(0, 1fr) auto;
    grid-template-areas: "bar bar bar" "seats seats seats" "status table actions" "me me me";
    column-gap: clamp(28px, 3.5vw, 72px);
  }
  .bar { grid-area: bar; padding-top: 14px; }
  .icon-btn { width: 52px; height: 52px; }
  .icon-btn svg { width: 26px; height: 26px; }
  .turn-chip { font-size: 1.45rem; }

  .seats { grid-area: seats; display: flex; flex-wrap: nowrap; justify-content: space-evenly; gap: 16px; padding: 0; max-width: none; margin: 0; }
  .seats > .seat {
    flex: 0 1 230px; width: auto; gap: 0; padding: 8px 12px 12px; border-radius: 24px; background: transparent;
    margin-top: calc(var(--off, 0) * clamp(0px, 7vh - 36px, 42px)); /* the ends sit lower, so the row curves round the table */
  }
  .seat.turn { background: rgba(40, 30, 10, .55); }
  /* a 7 to 10 player game: one row still, with the cats shrunk to fit across */
  .seats.many { gap: 6px; --av: min(clamp(84px, min(8.5vw, 14.5vh), 210px), calc((100vw - 120px) / var(--n) - 24px)); }
  .seats.many .seat { padding: 6px 2px 10px; gap: 0; }
  .seats.many .seat-avatar { width: var(--av); }
  .seats.many .seat-name { font-size: clamp(.95rem, 1.1vw, 1.25rem); }
  .seats.many .seat-heroname { font-size: clamp(.92rem, .6rem + .5vw, 1.25rem); }
  .seats.many .seat-meta { font-size: .9rem; padding: 0 8px; }
  /* the Markado pill scales with the cats: at 1024px with 10 players a full-size pill cut its name
     ("Ayok", "Pusan") and stood on the deck, and at 1366px "Mingming" lost its last letter. .135 of a
     cat fits the longest one-word name ("Pagpalitin") with the eye and a "+1". */
  .seats.many .seat-mark { font-size: clamp(.7rem, calc(var(--av) * .135), 1.05rem); }
  .seat-glow { border-radius: 28px; }
  /* the names were big in Cinzel and the hero line under them tiny in Alegreya's small letters (Ernest,
     2026-10-22): the names came down and the hero line, now with its glowing mark, went up */
  .seat-name { order: -1; font-family: var(--display); font-weight: 400; font-size: clamp(1.1rem, 1.3vw, 1.5rem); line-height: 1.1; margin-bottom: 4px; }
  .seat.turn .seat-name { color: var(--accent); }
  .seat-heroname { display: inline-flex; order: -1; margin: 0 0 8px; font-size: clamp(1.02rem, .68rem + .55vw, 1.4rem); }
  .seat-heroname .hero-mark { font-size: 1.1em; }
  .seat-meta .seat-hero { display: none; }
  .seat-avatar { width: var(--av); }
  .portrait { border-width: 4px; box-shadow: 0 0 0 3px var(--text), 0 8px 18px rgba(0, 0, 0, .45); }
  .seat-think { font-size: 2.2rem; top: 0; right: 10px; }
  .seat-hand { display: block; position: relative; z-index: 1; width: var(--av); height: calc(var(--av) * .42); margin-top: calc(var(--av) * -.2); }
  .seat-hand i {
    position: absolute; left: 50%; bottom: 0; width: calc(var(--av) * .3); aspect-ratio: 5 / 7; margin-left: calc(var(--av) * -.15);
    border-radius: 6px; border: 2px solid var(--ink); transform-origin: 50% 150%; transform: rotate(var(--r, 0deg));
    /* a tiny card back, purple with a gold frame like the real one: two lines stand in for the wordmark */
    background: linear-gradient(var(--accent), var(--accent)) 50% 40% / 66% 9% no-repeat, linear-gradient(var(--text), var(--text)) 50% 60% / 50% 12% no-repeat, var(--back);
    box-shadow: inset 0 0 0 2px var(--back), inset 0 0 0 3.5px var(--back-trim);
  }
  .painted-back .seat-hand i:not(.god) { background: var(--back-img) center / cover, var(--back); box-shadow: none; }
  /* the Pusang Mabait's back: gold over the Masama's dark red, split by a light seam */
  .seat-hand i.god {
    background: linear-gradient(150deg, #f2cf5b 0 46%, #fff8ef 46% 54%, #3a0d10 54%);
    box-shadow: inset 0 0 0 3.5px var(--text), 0 0 10px 2px rgba(255, 210, 63, .7);
  }
  .seat-meta {
    position: relative; z-index: 2; margin-top: -6px; padding: 0 12px; border-radius: 999px;
    background: var(--accent); color: var(--accent-ink); border: 2px solid var(--ink); font-weight: 800; font-size: 1rem;
  }
  .seat-meta .mini-card { display: none; }
  .seat.out .seat-meta { background: #e0d2cb; }  .table { grid-area: table; position: relative; gap: clamp(32px, 4vw, 76px); padding: 0; }
  .pile { gap: 8px; }
  .table { container-type: normal; min-height: 0; } /* the desktop table sizes its own piles (--pile-w) */
  .deck, .discard { width: var(--pile-w); border-radius: 16px; }
  .deck .card:nth-child(1) { transform: translate(8px, 8px); }
  .deck .card:nth-child(2) { transform: translate(4px, 4px); }
  .risk { width: var(--pile-w); height: 12px; margin-top: 8px; }
  .pile-label { font-size: 1.1rem; }
  .pile-note { font-size: clamp(1.05rem, calc(var(--pile-w) * .12), 1.4rem); gap: 16px; margin: 0 -14px; }

  /* the foot's padding: my portrait stands a little above its row, into the info's (1024×640) */
  .story { grid-area: status; display: flex; flex-direction: column; justify-content: center; align-items: flex-end; gap: 18px; min-height: 0; padding-bottom: 10px; }
  /* the boxes sit on the right, their text centred (Ernest, 2026-10-20) */
  .status { justify-content: flex-end; text-align: center; min-height: 0; padding: 0; font-size: clamp(1.12rem, 1.3vw, 1.4rem); line-height: 1.35; }
  .status > span { max-width: 19em; }
  /* a long effect (Laban Tayo!) on a short desktop ran under my cat and the hand: it scrolls in its space */
  .card-info {
    width: min(100%, 25em); margin: 0; padding: clamp(10px, 1.6vh, 16px) 18px clamp(10px, 1.6vh, 16px) 14px; gap: clamp(12px, 1.2vw, 18px);
    max-height: 100%; overflow-y: auto; overscroll-behavior: contain;
  }
  .card-info.more::after { bottom: calc(-1 * clamp(10px, 1.6vh, 16px)); margin: -20px -18px calc(-1 * clamp(10px, 1.6vh, 16px)) -14px; }
  .card-info.tip {
    display: block; width: auto; max-width: 19em; padding: 6px 14px; text-align: center;
    background: rgba(31, 22, 21, .84); border: 1.5px solid rgba(184, 70, 58, .55); box-shadow: 0 4px 14px rgba(0, 0, 0, .35);
  }
  .card-info.tip .info-text { color: var(--muted); font-size: 1rem; }
  .info-card .card { --cw: clamp(44px, min(5vw, 7vh - 4px), 88px); }
  .info-name { font-size: clamp(1.2rem, min(1.5vw, 2.6vh), 1.7rem); }
  .info-text { font-size: clamp(1.02rem, min(1.25vw, 1.8vh + .2rem), 1.3rem); margin-top: 4px; }
  .info-how { font-size: clamp(.92rem, min(1.1vw, 1.6vh + .15rem), 1.15rem); margin-top: 6px; }
  .actions { grid-area: actions; flex-direction: column; flex-wrap: nowrap; align-items: flex-start; justify-content: center; gap: 12px; min-height: 0; padding: 0; }
  .actions .btn { min-height: 58px; font-size: 1.35rem; padding-inline: 30px; max-width: 100%; white-space: normal; } /* "Wala sa mat ang Pusang Mabait" ran off a 1024px screen */
  /* four moves in the column: smaller, or on a 640px-high screen they stood up into the cats' row */
  .actions:has(> :nth-child(4)) { gap: 6px; }
  .actions:has(> :nth-child(4)) .btn { min-height: 42px; font-size: 1.05rem; padding-inline: 20px; }

  .me { grid-area: me; --me-w: calc(var(--av) * 1.45 + 20px); display: grid; grid-template-columns: var(--me-w) minmax(0, 1fr) var(--me-w); align-items: end; }
  .me-tag { grid-column: 1; grid-row: 1; flex-direction: column; gap: 0; padding-bottom: 22px; }
  .me-tag .seat-avatar { width: calc(var(--av) * 1.1); }
  .me-heroname { margin-top: 6px; font-size: clamp(1.02rem, .68rem + .55vw, 1.4rem); }
  .me-name {
    max-width: var(--me-w); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; margin-top: -10px; padding: 3px 16px;
    background: var(--bg); color: var(--text); border: 2px solid var(--ink); border-radius: 10px; transform: rotate(-3deg);
    font-family: var(--display); font-weight: 400; font-size: clamp(1.1rem, 1.3vw, 1.4rem); line-height: 1.2;
  }
  .me-tag.turn .me-name { background: var(--accent); color: var(--accent-ink); }
  .me-count { margin: 6px 0 0; font-size: 1rem; }
  .me-count::before { content: none; }
  .hand { grid-column: 2; grid-row: 1; margin-top: 0; height: calc(var(--cw) * 1.4 + 30px); }
  .hand.two-rows { height: calc(var(--cw) * 1.4 + 30px + var(--raise)); }
  .hand .card { bottom: 12px; }

  /* dialogs, prompt and effects scale up with the table */
  .modal-box { width: min(620px, 100%); padding: 28px; }
  .modal-title { font-size: 2.1rem; }
  .modal-body { font-size: 1.08rem; }
  .rule-card { grid-template-columns: 84px 1fr; }
  .rule-card .card { --cw: 84px; }
  .rule-card .rule-name { font-size: 1.3rem; }
  .rule-card .rule-text { font-size: 1rem; }
  /* How to play is a landscape sheet: the basics on the left, the cards in two columns on the right */
  .modal-box:has(.rules) { width: min(1240px, 100%); }
  .rules {
    display: grid; column-gap: 44px;
    grid-template-columns: minmax(260px, .7fr) 2fr; grid-template-rows: auto 1fr;
    grid-template-areas: "how deck" "credit deck";
  }
  .rules-how { grid-area: how; }
  .rules-deck { grid-area: deck; }
  .rules-deck h3 { margin-top: 0; }
  .rules .rules-credit { grid-area: credit; align-self: end; margin: 18px 0 0; }
  .rule-cards { grid-template-columns: 1fr 1fr; gap: 14px 28px; }
  .rule-card { grid-template-columns: 72px 1fr; }
  .rule-card .card { --cw: 72px; }
  .pick-grid { grid-template-columns: repeat(auto-fill, minmax(116px, 1fr)); gap: 14px; }
  .pick-grid .card { --cw: 116px; }
  .steal-fan, .steal-marked { --cw: 112px; }
  .modal-cards .card { --cw: 150px; }
  /* Silipin ang Future: the cards you saw glow like the crystal ball (Ernest: a stronger glow on desktop) */
  .modal-cards .card { box-shadow: 0 0 0 3px #c9b0ff, 0 0 30px 10px rgba(160, 110, 255, .7), 0 0 70px 18px rgba(155, 231, 255, .3); }
  .modal-cards { padding: 18px 0 6px; }
  /* Silipin ×5: wide enough for all five cards in one row */
  .modal-box:has(.modal-cards > :nth-child(4)) { width: min(880px, 100%); }
  .seat-marked .card { --cw: 44px; }
  .card.big { --cw: 250px; }
  .card.big .card-text { font-size: 1rem; }
  .target { min-height: 72px; font-size: 1.15rem; }
  .target .seat-avatar { width: 58px; }
  .nope-prompt { width: 460px; padding: 22px; top: calc(100dvh - var(--cw) * .95); } /* over the hand, so the played card stays in view */
  .nope-what { font-size: 1.2rem; }
  .btn-nope { font-size: 2.1rem; min-height: 74px; padding-inline: 40px; }
  .fx-banner { font-size: clamp(4rem, 6.5vw, 7.2rem); }
  .fx-stamp { font-size: 4.2rem; }
}
/* Bigger pop-ups on big screens (Ernest, 2026-10-20: "too small" on desktop; at 1920×1080 the Future cards
   were smaller than the hand's). zoom scales the whole box (text, cards, buttons, gaps) by --mz, so the
   limits that come from the screen are divided by it: the zoomed box still fits inside the screen. */
/* (A browser without zoom keeps --mz at 1, so its limits aren't shrunk for nothing.) */
.modal-box { --mz: 1; zoom: var(--mz); }
@media (min-width: 1024px) and (min-height: 640px) {
  .modal-box { width: min(620px, (100vw - 32px) / var(--mz)); max-height: calc((100dvh - 32px) / var(--mz)); }
  .modal-box:has(.rules) { width: min(1240px, (100vw - 32px) / var(--mz)); }
  .modal-box:has(.modal-cards > :nth-child(4)) { width: min(880px, (100vw - 32px) / var(--mz)); }
}
@supports (zoom: 2) {
  @media (min-width: 1280px) and (min-height: 760px) { .modal-box { --mz: 1.15; } }
  @media (min-width: 1600px) and (min-height: 880px) { .modal-box { --mz: 1.3; } }
  @media (min-width: 1900px) and (min-height: 1000px) { .modal-box { --mz: 1.45; } }
  @media (min-width: 2400px) and (min-height: 1300px) { .modal-box { --mz: 1.8; } }
}
/* A short desktop (1024×640): three full-size moves stood up into a two-line Markado pill above them */
@media (min-width: 1024px) and (min-height: 640px) and (max-height: 799px) {
  .actions { gap: 8px; }
  .seat-heroname { margin-bottom: 4px; }
  .seat-heroname .hero-mark { font-size: .9em; }
  .actions .btn { min-height: 46px; font-size: 1.2rem; padding-inline: 22px; }
  .actions:has(> :nth-child(4)) { gap: 5px; }
  .actions:has(> :nth-child(4)) .btn { min-height: 42px; font-size: 1.16rem; padding-inline: 20px; }
}
/* A small desktop (1024×640): the hero line with its mark made the middle seat's count stand on the deck */
@media (min-width: 1024px) and (max-width: 1279px) and (min-height: 640px) and (max-height: 799px) {
  .seat-heroname, .seats.many .seat-heroname { margin: -2px 0 1px; font-size: .88rem; }
  .seat-name { margin-bottom: 2px; }
  .seat-heroname .hero-mark { font-size: .78em; }
}
/* Tall desktops have room for the story and the card info together; shorter ones swap them like phones. */
@media (min-width: 1024px) and (min-height: 800px) {
  .game.has-info .status { display: flex; }
}
/* The small labels grow with the screen (Ernest, 2026-10-20: "some font sizes are too small" at 1920×1080).
   Each keeps its old size at 1024px and is about a fifth bigger at 1920px: card counts, ranks, the pile
   labels, the hover tip and the line under the "BULAG KA!" band. */
@media (min-width: 1024px) and (min-height: 640px) {
  .seat-meta, .me-count, .card-info.tip .info-text { font-size: clamp(1rem, .75rem + .4vw, 1.3rem); }
  .seats.many .seat-meta { font-size: clamp(.9rem, .7rem + .3vw, 1.15rem); }
  .seat-rank, .me-rank { font-size: clamp(.78rem, .55rem + .35vw, 1.05rem); }
  .seats.many .seat-rank { font-size: clamp(.7rem, .5rem + .3vw, .92rem); }
  .pile-label { font-size: clamp(1.1rem, .85rem + .4vw, 1.45rem); }
  .hand.blind::after { font-size: clamp(.95rem, .7rem + .4vw, 1.25rem); }
}
@media (max-height: 700px) and (max-width: 759px) {
  :root { --cw: clamp(58px, 15vw, 84px); }
  .seat-avatar { width: 42px; }
  /* a 10-player game with a two-row hand must still fit a 667px phone: the piles may shrink further,
     and the story line and the space under the hand get tighter */
  /* The card info used to grow up over the piles here, and a second row of buttons pushed my tag under
     them (Ernest, 2026-10-20: overlapping on phones). Now everything keeps its own space: the info sits
     in the story's row and the piles (the row's flexible 1fr) shrink to make room, down to ~.8 of a
     hand card; the seats, the Ikot/Higop badges and the info are a little tighter to leave them more. */
  .table {
    min-height: calc(var(--cw) * 1.12 + 56px); padding: 4px 0;
    --pw: clamp(calc(var(--cw) * .8), min(31vw, calc((100cqh - 56px) * 5 / 7), calc((100cqw - var(--note) - 2 * clamp(28px, 8vw, 80px)) / 2)), 168px);
  }
  .pile { gap: 4px; }
  .pile-note { font-size: .76rem; gap: 6px; }
  .pile-note > span { padding: 3px 8px 3px 6px; }
  .seats.many { row-gap: 3px; padding-top: 4px; }
  .seats.many .seat { padding: 2px 2px 4px; }
  .seats.many .seat-name, .seats.many .seat-meta { line-height: 1.2; }
  .status { min-height: 44px; }
  .bar { padding: 5px 0 2px; }
  .hand { height: calc(var(--cw) * 1.4 + 26px); }
  .hand.two-rows { height: calc(var(--cw) * 1.4 + 26px + var(--raise)); }
  .hand .card { bottom: 8px; }
  /* short phones: the card info keeps just the name and effect, run together, so it's two or three
     lines tall (five for a cat's long text). Past what the screen leaves it (the bar, a 10-player seat
     block, the smallest piles, a row of two-line moves and my hand take ~540px) it scrolls rather than
     push the hand off the bottom. */
  .info-card, .info-how { display: none; }
  .card-info { display: block; padding: 6px 12px; margin: 0 0 4px; max-height: max(64px, calc(100dvh - 545px)); overflow-y: auto; overscroll-behavior: contain; }
  /* a two-row hand is ~40px taller: the info gives that up (10 players, 14 cards and Tuyo's text ran 8px past 667) */
  .game:has(.hand.two-rows) .card-info { max-height: max(56px, calc(100dvh - 590px)); }
  .card-info.more::after { bottom: -6px; margin: -20px -12px -6px; }
  .info-name, .info-text { display: inline; }
  .info-name { font-size: 1rem; margin-right: .4em; }
  .info-text { font-size: .86rem; line-height: 1.22; }
}
/* ---------- phone landscape ----------
   The phone column is ~800px tall and put the deck and hand below the fold on a 390px-high screen.
   A small version of the desktop table instead: every cat in one row along the top, the story, piles
   and moves side by side in the middle, and my tag beside the hand at the bottom. */
@media (orientation: landscape) and (max-height: 600px) {
  :root { --cw: clamp(50px, 15vh, 80px); }
  .game.screen { max-width: none; padding-inline: max(16px, env(safe-area-inset-left)) max(16px, env(safe-area-inset-right)); }
  .game {
    min-height: 0;
    /* the story gets the wider side: a card's effect can run to 130 letters */
    grid-template-columns: minmax(0, 1.4fr) auto minmax(132px, 1fr);
    grid-template-rows: auto auto minmax(0, 1fr) auto;
    grid-template-areas: "bar bar bar" "seats seats seats" "status table actions" "me me me";
    column-gap: clamp(12px, 2.4vw, 40px);
  }
  .bar { grid-area: bar; padding: 4px 0 2px; }

  /* all the cats in one row, small; a mark's pill sits on the portrait so the row never grows */
  .seats, .seats.many {
    grid-area: seats; --avw: clamp(28px, 8.5vh, 40px); flex-wrap: nowrap; justify-content: center; gap: 6px;
    max-width: none; padding-top: 2px;
  }
  .seats > .seat { flex: 0 1 104px; width: auto; padding: 3px 2px 4px; gap: 0; }
  .seats .seat-avatar, .seats.many .seat-avatar { width: var(--avw); }
  .seats .seat-name, .seats.many .seat-name { font-size: .78rem; line-height: 1.2; }
  .seats .seat-meta, .seats.many .seat-meta { font-size: .72rem; line-height: 1.2; }
  .seats .seat-marked, .seats.many .seat-marked { position: absolute; z-index: 2; left: auto; right: 1px; top: calc(3px + var(--avw) * .875); transform: translateY(-100%); }
  .seats .seat-mark, .seats.many .seat-mark { flex-direction: row; gap: .2em; font-size: .74rem; padding: .08em .45em .08em .35em; box-shadow: 0 2px 0 var(--ink), 0 0 10px 2px rgba(255, 176, 46, .6); }
  .seats .seat-mark b, .seats .seat-mark em { display: none; }
  .seats .seat-mark::after { content: attr(data-n); }
  .seats .seat-mark svg { width: 1.25em; }
  .seats .seat.marked.blind .seat-avatar::after { top: 14%; }
  .seat-turns { font-size: .72rem; }

  /* not a size container here: its grid column is "auto", and containment would make that 0 wide.
     The piles get what the height leaves: the bar, the seat row and the hand take ~235px, the labels ~48px. */
  .table {
    grid-area: table; padding: 4px 0; gap: clamp(20px, 4vw, 44px); container-type: normal; min-height: 0;
    --pw: clamp(calc(var(--cw) * .95), calc((100dvh - 290px) / 1.4), 150px);
  }
  /* a two-row hand is taller by its raise (anim.js: max(40px, .42 of a card's height)), and the piles
     stood up into the cats' row: they give up that height */
  .game:has(.hand.two-rows) .table { --pw: clamp(calc(var(--cw) * .7), calc((100dvh - 290px - max(40px, var(--cw) * .59)) / 1.4), 150px); }
  .pile { gap: 4px; }
  .pile-label { font-size: .78rem; line-height: 1.2; white-space: normal; max-width: calc(var(--pw) + 40px); } /* "40 cards · Bomba: 23%" in two lines keeps the table narrow */
  .pile-note { font-size: .74rem; gap: 6px; }
  .pile-note > span { padding: 3px 8px 3px 6px; }

  /* the story on the left of the piles, the moves on their right */
  .story { grid-area: status; position: static; min-height: 0; display: flex; flex-direction: column; justify-content: center; align-items: flex-end; }
  /* the box on the right, its text centred like the desktop's (Ernest, 2026-10-20) */
  .status { min-height: 0; padding: 0; justify-content: flex-end; text-align: center; font-size: .92rem; }
  .card-info { position: static; width: min(100%, 22em); max-height: 100%; overflow: auto; margin: 0; padding: 6px 10px; box-shadow: none; }
  .info-card, .info-how { display: none; }
  .info-name { font-size: .98rem; }
  .info-text { font-size: .8rem; line-height: 1.22; }
  .actions { grid-area: actions; flex-direction: column; flex-wrap: nowrap; align-items: flex-start; justify-content: center; gap: 6px; min-height: 0; padding: 0; }
  .actions .btn { min-height: 44px; font-size: 1rem; padding-inline: 18px; max-width: 100%; white-space: normal; } /* "I-play: Silipin ang Future ×5" ran off the edge */
  /* three or four moves: two to a row (stacked, they stood up into the cats' row), "I-play" without the
     card's name (the info names it), and with three, "Mag-draw" across the bottom */
  .actions:has(> :nth-child(3)) { display: grid; grid-template-columns: repeat(2, minmax(0, auto)); align-content: center; justify-content: start; gap: 5px; }
  .actions:has(> :nth-child(3)) .btn { min-height: 36px; font-size: .84rem; padding-inline: 10px; line-height: 1.15; text-align: center; justify-content: center; }
  /* in Cinzel "PICKPOCKET" ran 22px into "RANSOM" beside it (check:ui, 2026-10-21) */
  .actions:has(> :nth-child(4)) .btn { font-size: .72rem; padding-inline: 4px; letter-spacing: 0; }
  .actions:has(> :nth-child(3)) .btn-more { display: none; }
  .actions:has(> :nth-child(3)):not(:has(> :nth-child(4))) .btn-primary { grid-column: 1 / -1; }

  /* my tag on the left of the hand, an empty column of the same width on its right to keep the hand centred */
  .me { grid-area: me; display: grid; grid-template-columns: 112px minmax(0, 1fr) 112px; align-items: end; }
  .me-tag { grid-column: 1; grid-row: 1; flex-direction: column; gap: 0; padding-bottom: 10px; font-size: .82rem; line-height: 1.2; text-align: center; }
  .me-tag .seat-avatar { width: 34px; }
  .me-name { max-width: 112px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .me-count { margin: 0; }
  .me-count::before { content: none; }
  .me-tag .seat-turns { margin: 2px 0 0; }
  /* the column has no line to spare: the mark stands just left of the 34px portrait */
  .me-tag { position: relative; }
  .me-heroname { position: absolute; right: calc(50% + 21px); top: 6px; font-size: .78rem; }
  .me-heroname .hero-name { display: none; }
  .hand { grid-column: 2; grid-row: 1; margin-top: 0; height: calc(var(--cw) * 1.4 + 22px); }
  .hand.two-rows { height: calc(var(--cw) * 1.4 + 22px + var(--raise)); }
  .hand .card { bottom: 8px; }
  .hand .mark-tag { font-size: 13px; padding: .3em; }
  .hand .mark-tag span { display: none; }
  .hand .mark-tag svg { width: 1.5em; }
  .hand.blind::after { display: none; } /* the "BULAG KA!" band says it; the long line has no room */

  /* the Ayoko! prompt over the hand's top edge, so the played card stays in view */
  .nope-prompt { top: auto; bottom: 8px; transform: translateX(-50%); padding: 10px 14px; }
  .nope-what { margin-bottom: 8px; }
  .btn-nope { font-size: 1.3rem; min-height: 50px; }
}
