/* KaBoomz — shared brand styles (DESIGN.md: fun, colourful, Kahoot-like;
   purple/magenta stage, multicolour tiles, big type, mobile-first). */

:root {
  /* ================================================================
     SLICE 4/5 - semantic visual vocabulary.
     Four groups; the category decides whether a theme may touch it.
     The machine-readable allowlist is src/css/themeable-tokens.json
     (themes are ENFORCED against it - see the slice 5 allowlist test).

     THEMEABLE           a theme may change freely. The values below are
                         the DEFAULT theme (house identity); a theme
                         layer ([data-skin="..."]) overrides them.
     THEMEABLE-OPTIONAL  bomb/fire illustration colours: themes MAY
                         override, but the defaults serve as fallback -
                         a theme that leaves them alone inherits the
                         classic bomb (same fallback pattern as audio).
     FIXED SEMANTIC      meaning is tied to the value (third-party brand
                         marks such as the Google G). Never themed.
     GAMEPLAY IDENTITY   how the game communicates: answer letters A-F
                         and the podium medals. An emcee says "tap the
                         yellow one" out loud - a theme must never
                         recolour these.
     ================================================================ */

  /* ---------- THEMEABLE: stage background ---------- */

  --color-background: #7c3aed;
  --color-background-mid: #4c1d95;
  --color-background-deep: #2e1065;
  --gradient-stage:
    radial-gradient(circle at 15% 15%, rgba(236, 72, 153, 0.35) 0%, transparent 45%),
    radial-gradient(circle at 85% 85%, rgba(124, 58, 237, 0.45) 0%, transparent 50%),
    linear-gradient(160deg, var(--color-background) 0%, var(--color-background-mid) 45%, var(--color-background-deep) 100%);
  --gradient-stage-base: linear-gradient(160deg, var(--color-background) 0%, var(--color-background-mid) 45%, var(--color-background-deep) 100%);
  --gradient-surface: linear-gradient(180deg, rgba(46, 16, 101, 0) 0%, rgba(46, 16, 101, 0.9) 30%);

  /* ---------- THEMEABLE: text ----------
     THE ONE PROPERTY a theme changes for text: --text-rgb. Every grade
     below derives from it (alpha applied here, base colour applied at
     the usage sites would break light themes — muted text must dim
     whatever colour the theme picks). The grades are preserved exactly
     as found; consolidating them is a separate owner decision. */

  --text-rgb: 255 255 255;
  --color-text: rgb(var(--text-rgb));
  --color-text-strong: rgb(var(--text-rgb) / 0.9);
  --color-text-soft: rgb(var(--text-rgb) / 0.85);
  --color-text-muted: rgb(var(--text-rgb) / 0.8);
  --color-text-quiet: rgb(var(--text-rgb) / 0.75);
  --color-text-hint: rgb(var(--text-rgb) / 0.72);
  --color-text-faded: rgb(var(--text-rgb) / 0.7);
  --color-text-faint: rgb(var(--text-rgb) / 0.65);
  --color-text-placeholder: rgb(var(--text-rgb) / 0.6);
  --color-text-dim: rgb(var(--text-rgb) / 0.55);

  /* ---------- THEMEABLE: surfaces and borders ----------
     --surface-rgb is the ONE property a theme changes for cards/panels:
     every translucent surface, border and hover derives from it. */

  --surface-rgb: 255 255 255;
  --color-surface-faint: rgb(var(--surface-rgb) / 0.06);
  --color-surface: rgb(var(--surface-rgb) / 0.08);
  --color-surface-control: rgb(var(--surface-rgb) / 0.1);
  --color-surface-input: rgb(var(--surface-rgb) / 0.12);
  --color-surface-raised: rgb(var(--surface-rgb) / 0.14);
  --color-surface-track: rgb(var(--surface-rgb) / 0.15);
  --color-surface-raised-2: rgb(var(--surface-rgb) / 0.16);
  --color-surface-focus: rgb(var(--surface-rgb) / 0.18);
  --color-surface-hover: rgb(var(--surface-rgb) / 0.24);
  --color-surface-ctrl-hover: rgb(var(--surface-rgb) / 0.3);
  --color-surface-solid: rgb(var(--surface-rgb));
  --color-border-soft: rgb(var(--surface-rgb) / 0.15);
  --color-border: rgb(var(--surface-rgb) / 0.18);
  --color-border-subtle: rgb(var(--surface-rgb) / 0.2);
  --color-border-row: rgb(var(--surface-rgb) / 0.22);
  --color-border-muted: rgb(var(--surface-rgb) / 0.25);
  --color-border-input: rgb(var(--surface-rgb) / 0.3);
  --color-border-strong: rgb(var(--surface-rgb) / 0.35);

  /* ---------- THEMEABLE: accent family ---------- */

  --color-primary: #facc15;
  --color-on-primary: #1f1235;
  --color-accent: #facc15;
  --color-accent-shadow: #db2777;
  --color-accent-2: #22d3ee;
  --color-secondary: #fb923c;
  --color-focus: #facc15;
  --color-surface-inverse: #1f1235;

  --success-rgb: 74 222 128;
  --success-deep-rgb: 22 163 74;
  --color-success: rgb(var(--success-rgb));
  --color-success-soft: rgb(var(--success-rgb) / 0.16);
  --selection-rgb: 250 204 21;
  --color-selection-soft: rgb(var(--selection-rgb) / 0.25);

  /* the five brand colours: reflex tap tiles and lobby feed chips */

  --palette-1: #facc15;
  --palette-2: #ec4899;
  --palette-3: #22d3ee;
  --palette-4: #fb923c;
  --palette-5: #4ade80;

  /* ---------- THEMEABLE: scrims (overlay dims) ---------- */

  --scrim-rgb: 31 18 53;          /* ink-based scrims */
  --stage-scrim-rgb: 46 16 101;   /* stage purple-based scrims */
  --color-scrim-stage: rgb(var(--stage-scrim-rgb) / 0.55);
  --color-scrim-stage-deep: rgb(var(--stage-scrim-rgb) / 0.94);
  --color-scrim-ink: rgb(var(--scrim-rgb) / 0.55);
  --color-scrim-ink-soft: rgb(var(--scrim-rgb) / 0.6);
  --color-scrim-modal: rgb(var(--scrim-rgb) / 0.7);
  --color-scrim-card: rgb(var(--scrim-rgb) / 0.78);
  --color-kick: rgb(var(--scrim-rgb) / 0.18);
  --color-kick-hover: rgb(var(--scrim-rgb) / 0.32);

  /* ---------- THEMEABLE: button gradients ---------- */

  --gradient-cta: linear-gradient(180deg, #ec4899, #db2777);
  --gradient-primary: linear-gradient(180deg, #22d3ee, #0891b2);
  --gradient-success: linear-gradient(180deg, rgb(var(--success-rgb)), rgb(var(--success-deep-rgb)));

  /* ---------- THEMEABLE: type, radii, borders, shadows ---------- */

  --font-body: 'Segoe UI', 'Trebuchet MS', system-ui, -apple-system, sans-serif;
  --font-display: 'Segoe UI', 'Trebuchet MS', sans-serif;
  --radius-card: 1.25rem;
  --radius-button: 1rem;
  --radius-pill: 999px;
  --radius-panel: 1.5rem;
  --radius-tile: 0.9rem;
  --radius-row: 0.8rem;
  --radius-tile-small: 0.7rem;
  --radius-chip: 0.75rem;
  --radius-input: 0.6rem;
  --radius-letter: 0.5rem;
  --border-width-card: 2px;
  --border-width-input: 3px;
  --shadow-button: 0 4px 0 rgb(var(--scrim-rgb) / 0.45);
  --shadow-button-pressed: 0 1px 0 rgb(var(--scrim-rgb) / 0.45);
  --shadow-chip: 0 5px 0 rgb(var(--scrim-rgb) / 0.45);
  --shadow-raised: 0 6px 20px rgba(0, 0, 0, 0.4);
  --shadow-text-glow: 0 3px 14px rgb(var(--scrim-rgb) / 0.5);
  --shadow-brand: 3px 3px 0 var(--color-accent-shadow), 6px 6px 0 rgb(var(--scrim-rgb) / 0.35);
  --shadow-brand-small: 2px 2px 0 var(--color-accent-shadow);
  --shadow-brand-single: 3px 3px 0 var(--color-accent-shadow);
  --shadow-pop: 4px 4px 0 var(--color-accent-shadow);
  --shadow-pop-ink: 4px 4px 0 #1f1235;

  /* ---------- THEMEABLE-OPTIONAL: the bomb and its fire ----------
     The bomb appears identically in every game (brand consistency) but
     a theme may replace its look; defaults are the fallback. */

  --bomb-body: #312e81;
  --bomb-edge: #1e1b4b;
  --bomb-cap: #475569;
  --bomb-fuse: #d6b077;
  --bomb-highlight: rgb(255 255 255 / 0.22);
  --bomb-fuse-base: rgb(255 255 255 / 0.18);
  --fire-red: #ef4444;
  --fire-orange: #fb923c;
  --fire-yellow: #facc15;
  --fire-shadow: #db2777;

  /* ---------- THEMEABLE: danger family (Slice 5) ----------
     The danger BASE is themeable; all seven roles follow it. The four
     lighter grades each carry their OWN base triplet: they are lighter
     than the base, not more transparent, so an alpha ladder cannot
     express them (lower alpha blends toward the stage), and a
     relative-colour derivation would need Chrome 119+ while leaving
     the literal on older devices - a theme would move three grades and
     leave four behind. Explicit per-grade bases work everywhere and
     match the allowlist principle: a theme declares what it wants.
     A theme must set ALL FIVE danger bases together, or it reproduces
     the partial-application defect this family exists to remove. */

  --danger-rgb:            239 68 68;
  --danger-text-rgb:       248 113 113;
  --danger-soft-rgb:       254 202 202;
  --danger-text-soft-rgb:  252 165 165;
  --danger-text-pale-rgb:  253 164 175;

  --color-danger:            rgb(var(--danger-rgb));
  --color-danger-text:       rgb(var(--danger-text-rgb));
  --color-danger-soft:       rgb(var(--danger-soft-rgb));
  --color-danger-text-soft:  rgb(var(--danger-text-soft-rgb));
  --color-danger-text-pale:  rgb(var(--danger-text-pale-rgb));
  --color-danger-wash:       rgb(var(--danger-rgb) / 0.18);
  --color-danger-border:     rgb(var(--danger-rgb) / 0.55);

  /* ---------- GAMEPLAY IDENTITY: medals ---------- */

  --medal-gold: #facc15;
  --medal-silver: #cbd5e1;
  --medal-bronze: #d97706;

  /* ---------- FIXED SEMANTIC: the Google G ----------
     Google's brand guidelines require these EXACT colours — they are
     not a style choice. Do not "improve" them. */

  --g-logo-blue: #4285F4;
  --g-logo-red: #EA4335;
  --g-logo-yellow: #FBBC05;
  --g-logo-green: #34A853;

  /* ---------- GAMEPLAY IDENTITY: quiz answer letters ----------
     The letter is the identity, the colour is part of how the game is
     called out loud ("tap the yellow one"). A theme must never change
     these. */

  --answer-a: #22d3ee;
  --answer-b: #ec4899;
  --answer-c: #4ade80;
  --answer-d: #facc15;
  --answer-e: #fb923c;
  --answer-f: #3b82f6;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  min-height: 100%;
}

body {
  font-family: var(--font-body);
  background: var(--gradient-stage);
  background-attachment: fixed;
  color: var(--color-text);
  -webkit-font-smoothing: antialiased;
}

.hidden { display: none !important; }

/* ---------- brand ---------- */

.brand {
  font-size: clamp(3rem, 12vw, 5.5rem);
  font-weight: 900;
  letter-spacing: -0.02em;
  text-align: center;
  color: var(--color-accent);
  text-shadow: var(--shadow-brand);
  transform: rotate(-2deg);
}

.brand-small {
  font-size: clamp(1.6rem, 4vw, 2.4rem);
  text-shadow: var(--shadow-brand-small);
  transform: none;
  text-align: left;
}

.brand-tag {
  text-align: center;
  font-size: 1rem;
  letter-spacing: 0.35em;
  text-transform: uppercase;
  color: var(--color-text-quiet);
  margin-top: 0.25rem;
}

/* ---------- layout ---------- */

.player #app {
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.25rem;
}

.view {
  width: 100%;
  max-width: 26rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.25rem;
  text-align: center;
}

/* ---------- join form ---------- */

.join-form {
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.field {
  font-size: 1.15rem;
  padding: 1rem 1.1rem;
  border: var(--border-width-input) solid var(--color-border-strong);
  border-radius: var(--radius-button);
  background: var(--color-surface-input);
  color: var(--color-text);
  width: 100%;
  outline: none;
  min-height: 3.5rem;
}

.field::placeholder { color: var(--color-text-placeholder); }
.field:focus { border-color: var(--color-focus); background: var(--color-surface-focus); }

.pin-field {
  text-align: center;
  font-size: 2rem;
  font-weight: 800;
  letter-spacing: 0.6em;
  text-indent: 0.6em;
}

.join-row { display: flex; gap: 0.75rem; }
.join-row .btn { flex: 1; }

.form-error {
  margin: 0;
  color: var(--color-danger-soft);
  font-weight: 600;
  min-height: 1.4em;
}

/* ---------- buttons ---------- */

.btn {
  font-size: 1.05rem;
  font-weight: 800;
  border: none;
  border-radius: var(--radius-button);
  padding: 0.95rem 1.4rem;
  min-height: 3.5rem;
  cursor: pointer;
  color: var(--color-on-primary);
  background: var(--color-primary);
  box-shadow: var(--shadow-button);
  transition: transform 0.06s ease, box-shadow 0.06s ease, filter 0.12s ease;
}

.btn:active {
  transform: translateY(3px);
  box-shadow: var(--shadow-button-pressed);
}

.btn:disabled { filter: grayscale(0.8); opacity: 0.55; cursor: default; }

.btn.join-btn { background: var(--gradient-cta); color: var(--color-text); flex: 2; }
.btn.surprise { background: var(--color-secondary); }
.btn.ghost { background: var(--color-surface-raised); color: var(--color-text); box-shadow: none; }
.btn.danger { background: var(--color-danger); color: var(--color-text); }
.btn.primary { background: var(--gradient-primary); color: var(--color-text); }
.btn.start-activity { width: 100%; background: var(--gradient-success); color: var(--color-text); }

/* ---------- idle / status screens ---------- */

.idle-nick {
  font-size: 2rem;
  font-weight: 800;
  background: var(--color-primary);
  color: var(--color-on-primary);
  padding: 0.5rem 1.4rem;
  border-radius: var(--radius-pill);
  box-shadow: var(--shadow-chip);
  max-width: 100%;
  overflow-wrap: anywhere;
}

.idle-waiting {
  font-size: 1.15rem;
  color: var(--color-text-soft);
  animation: pulse 2.2s ease-in-out infinite;
}

.idle-result {
  font-size: 1.05rem;
  font-weight: 700;
  background: var(--color-surface-raised);
  border: var(--border-width-card) solid var(--color-border-input);
  padding: 0.7rem 1.2rem;
  border-radius: var(--radius-button);
}

.status-text { font-size: 1.2rem; margin: 0.5rem 0; }

.activity-info {
  font-size: 1.6rem;
  font-weight: 800;
  background: var(--color-surface-raised);
  border: var(--border-width-input) solid var(--color-border-strong);
  border-radius: var(--radius-panel);
  padding: 2rem 1.5rem;
  width: 100%;
  animation: pulse 1.6s ease-in-out infinite;
}

/* Activity modules render inside this mount; it must take the full
   column width even though the surrounding view centers its children. */
#activity-mount { width: 100%; }

@keyframes pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.65; }
}

/* ---------- loading / reconnect / toast ---------- */

.loading {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--gradient-stage-base);
  z-index: 50;
}

.loading-brand {
  font-size: 3rem;
  font-weight: 900;
  color: var(--color-accent);
  text-shadow: var(--shadow-brand-single);
  animation: bounce 0.9s ease-in-out infinite;
}

@keyframes bounce {
  0%, 100% { transform: translateY(0) scale(1); }
  50% { transform: translateY(-14px) scale(1.06); }
}

.reconnect-banner {
  position: fixed;
  top: 0.75rem;
  left: 50%;
  transform: translateX(-50%);
  background: var(--color-surface-inverse);
  color: var(--color-accent);
  font-weight: 700;
  padding: 0.5rem 1.2rem;
  border-radius: var(--radius-pill);
  z-index: 60;
}

/* Host-absence warning. Never shown together with .reconnect-banner:
   player.js guarantees the player's own "Reconnecting…" wins. */
.host-banner {
  position: fixed;
  top: 0.75rem;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.1rem;
  background: var(--color-surface-inverse);
  border: var(--border-width-card) solid var(--color-focus);
  color: var(--color-accent);
  font-weight: 700;
  padding: 0.6rem 1.4rem;
  border-radius: var(--radius-button);
  z-index: 60;
  text-align: center;
}

.host-banner-title { font-size: 1rem; }

.host-banner-sub {
  font-size: 0.85rem;
  color: var(--color-text-soft);
  font-weight: 500;
}

/* Deliberately non-prominent Leave Game escape hatch. */
.leave-btn {
  position: fixed;
  bottom: 0.75rem;
  left: 50%;
  transform: translateX(-50%);
  background: none;
  border: none;
  color: var(--color-text-dim);
  font-size: 0.85rem;
  font-weight: 600;
  text-decoration: underline;
  padding: 0.6rem 1rem;
  cursor: pointer;
  z-index: 40;
}

.status-sub {
  font-size: 1rem;
  color: var(--color-text-soft);
  margin: 0;
}

.toast {
  position: fixed;
  bottom: 1.25rem;
  left: 50%;
  transform: translateX(-50%);
  max-width: min(90vw, 30rem);
  background: var(--color-surface-inverse);
  color: var(--color-text);
  font-weight: 600;
  padding: 0.8rem 1.3rem;
  border-radius: var(--radius-pill);
  z-index: 70;
  text-align: center;
  box-shadow: var(--shadow-raised);
}

/* ---------- host page ---------- */

.host-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.9rem 1.25rem;
  border-bottom: var(--border-width-card) solid var(--color-border-soft);
}

.host-tools { display: flex; gap: 0.6rem; }
.host-tools .btn { font-size: 0.9rem; padding: 0.55rem 1rem; min-height: 2.6rem; }

.host-auth-error {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.9rem;
  background: var(--color-danger-wash);
  border: var(--border-width-card) solid var(--color-danger-border);
  border-radius: var(--radius-card);
  padding: 1.4rem;
  text-align: center;
  font-weight: 700;
}

.host-signin {
  display: flex;
  justify-content: center;
  padding: 1rem 0;
}

.host-signin-box {
  width: 100%;
  max-width: 24rem;
  background: var(--color-surface);
  border: var(--border-width-card) solid var(--color-border);
  border-radius: var(--radius-panel);
  padding: 1.6rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
}

.host-signin-form {
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

/* Self-serve auth panels (slice 1). All panels live inside #host-signin
   and reuse the box/field/button/form-error classes above — no new UI
   system. Only one panel is visible at a time (host-auth.js). */

.host-auth-panel {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.75rem;
}

.host-auth-title {
  margin: 0;
  font-size: 1.2rem;
  font-weight: 800;
  color: var(--color-accent);
  text-align: center;
}

.host-auth-copy {
  margin: 0;
  font-size: 0.95rem;
  color: var(--color-text-soft);
  text-align: center;
  line-height: 1.45;
}

.host-auth-copy strong {
  color: var(--color-text);
  overflow-wrap: anywhere;
}

/* Quieter second line under a sign-in error: guidance, not alarm. */
.host-auth-hint {
  margin: -0.25rem 0 0;
  font-size: 0.85rem;
  color: var(--color-text-hint);
  line-height: 1.45;
}

.host-auth-hint .host-auth-link { font-size: 0.85rem; }

.host-auth-divider {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  width: 100%;
  color: var(--color-text-dim);
  font-size: 0.8rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.15em;
}

.host-auth-divider::before,
.host-auth-divider::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--color-border-muted);
}

.host-provider-row {
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.host-provider-btn {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  background: var(--color-surface-solid);
  color: var(--color-on-primary);
  box-shadow: none;
}

.host-provider-btn svg { flex: none; }

/* Google G fills (the tokens live in :root under FIXED SEMANTIC —
   brand-guideline colours, applied here so no JS carries hex). */
.g-logo-blue { fill: var(--g-logo-blue); }
.g-logo-red { fill: var(--g-logo-red); }
.g-logo-yellow { fill: var(--g-logo-yellow); }
.g-logo-green { fill: var(--g-logo-green); }

.host-provider-btn:disabled {
  filter: grayscale(0.9);
  opacity: 0.45;
  cursor: not-allowed;
}

.host-auth-links {
  display: flex;
  gap: 1rem;
  flex-wrap: wrap;
  justify-content: center;
}

.host-auth-link {
  background: none;
  border: none;
  color: var(--color-accent);
  font-size: 0.9rem;
  font-weight: 700;
  text-decoration: underline;
  cursor: pointer;
  padding: 0.25rem;
}

.host-field-hint {
  margin: -0.25rem 0 0;
  font-size: 0.8rem;
  color: var(--color-text-faint);
  width: 100%;
}

.host-auth-connecting {
  margin: 0;
  font-size: 1.15rem;
  font-weight: 700;
  color: var(--color-text);
  animation: pulse 1.6s ease-in-out infinite;
}

.host-main {
  max-width: 56rem;
  margin: 0 auto;
  padding: 1rem 1.25rem 1rem;
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

/* A running activity owns the whole projector viewport (core adds
   game-running to <body> while an activity is on screen): the page locks
   to exactly one screen — no scrolling mid-game. Setup, sign-in and the
   holding lobby may scroll normally. */
body.host.game-running {
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

body.host.game-running .host-top { flex: none; }

body.host.game-running .host-main {
  flex: 1;
  min-height: 0;
  overflow: hidden;
  width: 100%;       /* the classic 56rem game column, exactly as before */
  max-width: 56rem;
}

body.host.game-running #host-main-ui {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

body.host.game-running #activity-mount {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

/* Full-page holding lobby (Kahoot-style): shown after the host presses
   Start on the setup screen, until the game actually begins. */

.lobby-stage {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  height: calc(100dvh - 8rem);
  min-height: 0;
}

.lobby-start {
  flex: none;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.45rem;
}

.lobby-start-btns {
  display: flex;
  gap: 0.75rem;
  flex-wrap: wrap;
  justify-content: center;
  width: 100%;
}

.lobby-start-btns .btn { flex: 1; max-width: 20rem; }

.lobby-hint {
  margin: 0;
  color: var(--color-text-muted);
  font-size: 0.95rem;
  text-align: center;
  max-width: 30rem;
}

/* Kahoot-style join lobby: instructions on top, PIN as huge plain digits
   (no box, like Kahoot), QR code with a scan hint, player count, then the
   names as they join. Everything fits on one screen — no scrolling. */

.lobby-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.6rem;
}

.lobby-instructions {
  font-size: clamp(1rem, 2.4vw, 1.35rem);
  font-weight: 800;
  text-align: center;
  color: var(--color-text);
  letter-spacing: 0.01em;
}

.lobby-instructions .join-domain { color: var(--color-accent); }

.pin {
  display: inline-block;
  font-size: clamp(2.6rem, 8.5vh, 5.5rem);
  font-weight: 900;
  letter-spacing: 0.1em;
  line-height: 1;
  color: var(--color-text);
  text-shadow: var(--shadow-text-glow);
  font-variant-numeric: tabular-nums;
  text-align: center;
}

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

.lobby-join {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.55rem;
}

.qr-caption {
  font-size: 0.9rem;
  font-weight: 700;
  color: var(--color-text-muted);
}

.qr-box {
  background: var(--color-surface-solid);
  border-radius: var(--radius-button);
  padding: 0.45rem;
  line-height: 0;
}

.qr-box svg { display: block; }

.lobby-stats { text-align: center; }

.count-label {
  font-size: 0.8rem;
  font-weight: 800;
  letter-spacing: 0.3em;
  color: var(--color-text-faded);
}

.count {
  font-size: clamp(3.5rem, 10vw, 5.5rem);
  font-weight: 900;
  line-height: 1.05;
  color: var(--color-success);
  font-variant-numeric: tabular-nums;
}

.join-url {
  font-size: 0.85rem;
  color: var(--color-text-quiet);
  max-width: 16rem;
  overflow-wrap: anywhere;
}

/* Short projectors (720p-class): reclaim vertical space for the join
   feed so more name rows are visible. The PIN stays huge, the QR and
   Start button keep their place, and the page still fits without a
   scrollbar (verified 1024x768 and 1280x720). Placed AFTER the rules it
   overrides so it actually wins. */
@media (max-height: 800px) {
  .pin { font-size: clamp(2.4rem, 7vh, 5.5rem); }
  .lobby-card { gap: 0.4rem; }
  .lobby-stage { gap: 0.45rem; }
}

/* names: live join feed — newest at the TOP, older names pushed down, the
   oldest visible one exits at the bottom. Display-only window over the
   server's participant list (most recent 50, oldest first): the feed shows
   the newest `capacity` rows, newest first. Rows are absolutely positioned
   (top = row * pitch) and move with plain CSS transitions, so a join is
   one continuous stream: the newest chip slides into the top slot, every
   kept chip glides one row down, and the oldest row slides out below the
   visible area while fading. The first render after a load/reset is a
   static snapshot (no join animation for names that were already there). */

.lobby-card { flex: none; }

.names-box {
  flex: 1;
  min-height: 0;
  overflow: hidden;
}

.names {
  position: relative;
  height: 100%;
  overflow: hidden;
}

.feed-name {
  position: absolute;
  left: 0;
  width: fit-content;
  max-width: 100%;
  display: flex;
  align-items: center;
  gap: 0.35rem;
  height: 2.35rem;
  margin-bottom: 0.5rem; /* row pitch = 2.85rem (JS measures it) */
  padding: 0 0.55rem 0 0.9rem;
  border-radius: var(--radius-pill);
  font-weight: 700;
  font-size: 0.95rem;
  color: var(--color-on-primary);
  box-sizing: border-box;
  transition: top 0.35s cubic-bezier(0.22, 0.61, 0.36, 1), opacity 0.35s ease;
}

/* Participant colour comes from a stable hash of the participant id
   (feed-c0..feed-c4, added in JS) — the same player keeps the same colour
   when rows move, when others join, and across kicks/rejoins. Never
   nth-child: DOM order is not visual order in the feed. */
.feed-name.feed-c0 { background: var(--palette-1); }
.feed-name.feed-c1 { background: var(--palette-2); }
.feed-name.feed-c2 { background: var(--palette-3); }
.feed-name.feed-c3 { background: var(--palette-4); }
.feed-name.feed-c4 { background: var(--palette-5); }

/* Static snapshot (initial render / reload / capacity growth): no motion. */
.feed-name.feed-static { transition: none; }

/* Entry: a genuinely new joiner slides down into the top slot. */
.feed-name.feed-entrant { animation: feed-in 0.35s ease; }

/* Exit: the oldest visible row slides out below the visible area and
   fades (top + opacity transitions); it stays on top of the others while
   it leaves, and its removal never reflows the remaining list. */
.feed-name.feed-exit {
  z-index: 1;
  opacity: 0;
  pointer-events: none;
}

@keyframes feed-in {
  from { transform: translateY(-1.4rem); opacity: 0; }
  to   { transform: translateY(0); opacity: 1; }
}

.name-chip-label { max-width: 11rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.kick-btn {
  border: none;
  background: var(--color-kick);
  color: var(--color-on-primary);
  width: 1.7rem;
  height: 1.7rem;
  min-width: 1.7rem;
  border-radius: var(--radius-pill);
  font-size: 1rem;
  font-weight: 900;
  line-height: 1;
  cursor: pointer;
}

.kick-btn:hover { background: var(--color-kick-hover); }

/* activity panel (placeholder until Phase 2) */

.activity-panel {
  background: var(--color-surface);
  border: var(--border-width-card) solid var(--color-border);
  border-radius: var(--radius-panel);
  padding: 1.25rem 1.5rem;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  font-size: 1.15rem;
}

.activity-type { font-weight: 900; color: var(--color-accent); }

.activity-controls { display: flex; gap: 0.75rem; margin-top: 0.4rem; }
.activity-controls .btn { flex: 1; }

/* ---------- dashboard (Slice 2) ----------
   The signed-in shell: nav + workspace. The workspace shows a list view
   OR (when an activity's setup screen is open) the Save/Save & Launch
   chrome above the shared #activity-mount. Additive only — the player
   site never renders this. */

.dashboard {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  width: 100%;
}

.db-nav {
  display: flex;
  gap: 0.4rem;
  flex-wrap: wrap;
}

.db-tab {
  background: var(--color-surface-control);
  border: var(--border-width-card) solid var(--color-border);
  border-radius: var(--radius-pill);
  color: var(--color-text);
  font-size: 0.95rem;
  font-weight: 700;
  padding: 0.5rem 1.1rem;
  cursor: pointer;
}

.db-tab.active {
  background: var(--color-primary);
  color: var(--color-on-primary);
  border-color: var(--color-primary);
}

.db-tab.disabled {
  opacity: 0.45;
  filter: grayscale(0.9);
  cursor: not-allowed;
}

.db-workspace {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  width: 100%;
}

.db-view {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  width: 100%;
}

.db-title {
  margin: 0;
  font-size: 1.4rem;
  font-weight: 800;
  color: var(--color-accent);
}

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

.db-section-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
}

.db-section-title { margin: 0; font-size: 1rem; font-weight: 800; color: var(--color-text); }

.db-card {
  background: var(--color-surface);
  border: var(--border-width-card) solid var(--color-border);
  border-radius: var(--radius-card);
  padding: 1rem 1.2rem;
}

.db-rejoin {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  border-color: var(--color-focus);
  flex-wrap: wrap;
}

.db-rejoin-title { font-weight: 800; font-size: 1.05rem; }

.db-rejoin-sub { font-size: 0.85rem; color: var(--color-text-quiet); margin-top: 0.2rem; }

.db-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  background: var(--color-surface);
  border: var(--border-width-card) solid var(--color-border);
  border-radius: var(--radius-button);
  padding: 0.75rem 1rem;
  flex-wrap: wrap;
}

.db-row-main { min-width: 0; }

.db-row-title {
  font-weight: 800;
  overflow-wrap: anywhere;
}

.db-row-sub { font-size: 0.85rem; color: var(--color-text-faded); }

.db-row-actions { display: flex; gap: 0.45rem; flex-wrap: wrap; }
.db-row-actions .btn { font-size: 0.85rem; padding: 0.5rem 0.9rem; min-height: 2.4rem; }

.db-empty {
  color: var(--color-text-faded);
  font-size: 0.95rem;
  padding: 0.5rem 0;
}

.db-chips { display: flex; gap: 0.45rem; flex-wrap: wrap; }

.db-chip {
  background: var(--color-surface-control);
  border: var(--border-width-card) solid var(--color-border);
  border-radius: var(--radius-pill);
  color: var(--color-text);
  font-size: 0.9rem;
  font-weight: 700;
  padding: 0.4rem 1rem;
  cursor: pointer;
}

.db-chip.active {
  background: var(--color-primary);
  color: var(--color-on-primary);
  border-color: var(--color-primary);
}

.db-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(12rem, 1fr));
  gap: 0.75rem;
}

.db-tile {
  background: var(--color-surface);
  border: var(--border-width-card) solid var(--color-border);
  border-radius: var(--radius-card);
  padding: 1.2rem 1rem;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  transition: border-color 0.12s ease, background 0.12s ease;
}

.db-tile:hover { border-color: var(--color-focus); background: var(--color-surface-raised); }

.db-tile-label { font-weight: 800; font-size: 1.05rem; }

.db-tile-cats { font-size: 0.8rem; color: var(--color-text-faint); }

.db-setup-chrome {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  background: var(--color-surface);
  border: var(--border-width-card) solid var(--color-border);
  border-radius: var(--radius-card);
  padding: 0.9rem 1.1rem;
}

.db-title { font-size: 1.05rem; }

/* Owner change: Save/Exit ride at the BOTTOM of the editor page — the
   host finishes the questions and saves right there, sticky so a long
   quiz never makes them scroll back up. */
.db-setup-actions {
  position: sticky;
  bottom: 0;
  z-index: 30;
  display: flex;
  gap: 0.6rem;
  padding: 0.6rem 0;
  background: var(--gradient-surface);
}

.db-setup-actions .btn { flex: 1; max-width: 14rem; }

@media (max-width: 480px) {
  .db-setup-actions .btn { max-width: none; }
}

/* ---------- small screens ---------- */

/* Slice 5: the saved-game theme selector in the editor chrome. */
.db-skin-field {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  font-size: 0.9rem;
  font-weight: 700;
  color: var(--color-text-soft);
}
.db-skin-select {
  font-size: 1rem;
  font-weight: 700;
  padding: 0.5rem 0.6rem;
  border-radius: var(--radius-input);
  border: var(--border-width-card) solid var(--color-border-input);
  background: var(--color-surface-control);
  color: var(--color-text);
  min-height: 2.6rem;
}
.db-skin-select option { color: var(--color-on-primary); }

@media (max-width: 480px) {
  .host-tools .btn { padding: 0.5rem 0.75rem; }
  .lobby-row { gap: 1rem; }
  .qr-box { padding: 0.45rem; }
}

/* ---------- shared bomb countdown (DESIGN.md C5) ----------
   One implementation for every activity's host screen (activities/
   shared/bomb.js). Token-driven only — no hex values outside :root. */

.kb-bomb {
  position: relative;
  width: 100%;
  max-width: min(24rem, 42vh);
}

.kb-bomb svg { width: 100%; display: block; }

.kb-body { fill: var(--bomb-body); stroke: var(--bomb-edge); stroke-width: 4; }
.kb-highlight { fill: var(--bomb-highlight); }
.kb-cap { fill: var(--bomb-cap); }
.kb-fuse-base { fill: none; stroke: var(--bomb-fuse-base); stroke-width: 7; stroke-linecap: round; }
.kb-fuse { fill: none; stroke: var(--bomb-fuse); stroke-width: 7; stroke-linecap: round; }

.kb-number {
  font-size: 74px;
  font-weight: 900;
  fill: var(--fire-yellow);
  stroke: var(--fire-shadow);
  stroke-width: 3;
  paint-order: stroke;
  font-family: var(--font-display);
}

.kb-spark { transform-box: fill-box; transform-origin: center; }
.kb-spark-red { fill: var(--fire-red); }
.kb-spark-orange { fill: var(--fire-orange); }
.kb-spark-yellow { fill: var(--fire-yellow); }

/* the explosion that replaces the bomb at GO:
   3-2-1, the bomb disappears, the explosion pops in its place with
   "KaBoomz!" in the middle — its own beat before the round starts. */

.kb-explosion {
  position: relative;
  width: 100%;
  max-width: min(24rem, 42vh);
  animation: kb-explosion-pop 0.8s ease-out both;
}

.kb-explosion svg { width: 100%; display: block; }

.kb-burst-red { fill: var(--fire-red); }
.kb-burst-yellow { fill: var(--fire-yellow); opacity: 0.9; }
.kb-burst-gold { fill: var(--fire-yellow); opacity: 0.85; }
.kb-burst-amber { fill: var(--fire-orange); opacity: 0.85; }

.kb-explosion-text {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: clamp(2rem, 7vw, 3.6rem);
  font-weight: 900;
  color: var(--fire-yellow);
  text-shadow: var(--shadow-pop);
  animation: kb-explosion-text 0.8s ease-out both;
}

@keyframes kb-explosion-pop {
  0% { opacity: 0; transform: scale(0.3); }
  35% { opacity: 1; transform: scale(1.12); }
  70% { transform: scale(1); }
  100% { opacity: 1; transform: scale(1); }
}

@keyframes kb-explosion-text {
  0% { opacity: 0; transform: scale(0.2); }
  30% { opacity: 1; transform: scale(1.3); }
  60% { transform: scale(1); }
  100% { opacity: 1; transform: scale(1); }
}

/* ---------- shared ranked leaderboard + podium (Slice 4) ----------
   ONE implementation for every activity's host screen (activities/
   shared/leaderboard.js + these rules). Reflex and Quiz both render
   rows with the .rh-lb-* classes; Quiz additionally uses the .qh-lb-*
   scoreboard shell. The staged reveal choreography classes are shared
   too. Token-driven only — no hex values outside :root. */

/* leaderboard — fits the remaining viewport height */

.rh-lb {
  position: relative;
  width: 100%;
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.rh-lb-title {
  flex: none;
  font-size: 1.35rem;
  font-weight: 900;
  color: var(--color-accent);
  text-align: center;
}

.rh-lb-rows {
  flex: 1;
  min-height: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.rh-lb-row {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  align-items: center;
  gap: 0.7rem;
  background: var(--color-surface-input);
  border: var(--border-width-card) solid var(--color-border-row);
  border-radius: var(--radius-row);
  padding: 0.3rem 0.9rem;
  font-size: 1.05rem;
  font-weight: 700;
}

.rh-lb-row .lb-rank {
  font-weight: 900;
  color: var(--color-accent);
  min-width: 2.2ch;
  text-align: center;
}

.rh-lb-row .lb-name {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--color-text);
  font-weight: 800;
}

/* prominent total, secondary per-round/per-question value */
.rh-lb-row .lb-time {
  font-variant-numeric: tabular-nums;
  font-weight: 900;
  color: var(--color-text);
  font-size: 1.15rem;
}

.rh-lb-row .lb-round {
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  font-size: 0.95rem;
  color: var(--color-text-quiet);
  min-width: 4.4ch;
  text-align: right;
}

/* movement indicators: green up, red down, grey unchanged/NEW.
   NOTE: the down-arrow red is #ef4444 for BOTH activities. Reflex's own
   stylesheet carried a brighter #f87171 but the identical selector in
   quiz.css loaded after it, so the danger red won everywhere at runtime
   (recorded in SLICE4_AUDIT §5.1 — the source-level divergence was
   dead code; the rendered value is preserved here). */
.rh-lb-row .lb-arrow {
  min-width: 3ch;
  text-align: right;
  font-weight: 900;
  color: var(--color-text-dim);
}
.rh-lb-row .lb-arrow.up { color: var(--color-success); }
.rh-lb-row .lb-arrow.down { color: var(--color-danger); }
.rh-lb-row .lb-arrow.new { font-size: 0.8rem; letter-spacing: 0.08em; }
/* ---- staged suspense reveal ---- */

/* stage 2: new round values pop in while players sit in their old spots */
.rh-lb-row .lb-round {
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.35s ease, transform 0.35s ease;
}
.rh-lb-rows.lb-times .lb-round { opacity: 1; transform: none; }

/* stage 4: movement indicators pop in */
.rh-lb-row .lb-arrow {
  opacity: 0;
  transform: scale(0.5);
  transition: opacity 0.25s ease, transform 0.25s ease;
}
.rh-lb-rows.lb-arrows .lb-arrow { opacity: 1; transform: none; }

/* stage 5: physical FLIP shuffle */
.rh-lb-row.lb-shuffle {
  transition: transform 1.4s cubic-bezier(0.22, 0.8, 0.35, 1), opacity 1.1s ease;
}

/* new entrants rise in; departing players slide down and fade */
.rh-lb-row.lb-entrant { opacity: 0; transform: translateY(26px) scale(0.96); }
.rh-lb-row.lb-entrant.lb-shuffle { opacity: 1; transform: translateY(0) scale(1); }
/* departing rows stay VISIBLE at INVERT, then the PLAY phase fades them
   while they physically slide down — never born invisible */
.rh-lb-row.lb-exit { opacity: 1; }
.rh-lb-row.lb-exit.lb-shuffle { opacity: 0; }

/* settle: collapse departing rows out of the layout before removal so the
   remaining rows grow smoothly instead of jolting */
.rh-lb-row.lb-collapse {
  flex: 0 0 auto;
  max-height: 0;
  overflow: hidden;
  padding-top: 0;
  padding-bottom: 0;
  border-width: 0;
  opacity: 0;
  transition: max-height 0.3s ease, padding 0.3s ease, border-width 0.3s ease;
}

/* zero-standings reveal (everyone kicked): a quiet empty state, no fake data */
.rh-lb-empty {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.1rem;
  font-weight: 700;
  color: var(--color-text-quiet);
  text-align: center;
}

/* round 1 cascade */
.rh-lb-row.lb-cascade { animation: rb-cascade 0.5s ease both; }
@keyframes rb-cascade {
  from { transform: translateY(-14px); opacity: 0; }
  to { transform: translateY(0); opacity: 1; }
}

/* quiz's scoreboard shell (its own title card + rows container) */
.qh-lb {
  position: relative;
  width: 100%;
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.qh-lb-title {
  flex: none;
  font-size: 1.35rem;
  font-weight: 900;
  color: var(--color-accent);
  text-align: center;
  background: var(--color-surface);
  border: var(--border-width-card) solid var(--color-border);
  border-radius: var(--radius-tile);
  padding: 0.55rem 1rem;
}

.qh-instruction {
  flex: none;
  text-align: center;
  color: var(--color-text-soft);
  font-weight: 600;
}

.qh-lb-rows {
  flex: 1;
  min-height: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.qh-lb-empty {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.1rem;
  font-weight: 700;
  color: var(--color-text-quiet);
  text-align: center;
}

/* podium (C8) */

.rh-podium-title {
  font-size: 1.35rem;
  font-weight: 900;
  color: var(--color-accent);
}

.podium-stage {
  width: 100%;
  max-width: 40rem;
  flex: 1;
  min-height: 0;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  gap: 0.8rem;
}

.podium-slot {
  flex: 1;
  max-width: 14rem;
  border-radius: var(--radius-tile) var(--radius-tile) 0 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  gap: 0.35rem;
  padding: 1rem 0.5rem 0;
  font-weight: 900;
  color: var(--color-on-primary);
  animation: rb-podium 0.7s ease both;
}

.podium-slot .ps-name { font-size: 1.15rem; overflow-wrap: anywhere; }
.podium-slot .ps-time { font-size: 1rem; font-variant-numeric: tabular-nums; }
.podium-slot .ps-place { font-size: 0.85rem; text-transform: uppercase; letter-spacing: 0.2em; }

.podium-slot.first { height: min(13.5rem, 30vh); background: var(--medal-gold); animation-delay: 0.15s; }
.podium-slot.second { height: min(10.5rem, 24vh); background: var(--medal-silver); animation-delay: 0s; }
.podium-slot.third { height: min(8rem, 19vh); background: var(--medal-bronze); color: var(--color-text); animation-delay: 0.3s; }

@keyframes rb-podium {
  from { transform: translateY(40px); opacity: 0; }
  to { transform: translateY(0); opacity: 1; }
}

/* ---------- hover states (W5) ----------
   Every action button gets a visible shift on hover, so it is always
   obvious what is being pointed at. :active keeps its press-down feel. */

.btn:not(:disabled):hover {
  filter: brightness(1.12);
  transform: translateY(-1px);
}

/* While pressed, the press-down beat wins over the hover lift. */
.btn:not(:disabled):active { transform: translateY(3px); }

.btn.ghost:not(:disabled):hover { background: var(--color-surface-hover); }

.db-tab:not(:disabled):hover { border-color: var(--color-focus); }
.db-chip:hover { border-color: var(--color-focus); }
.host-auth-link:hover { color: var(--color-text); }

/* ---------- podium menu + session summary (W8, both activities) ---------- */

.podium-menu-btn.active {
  background: var(--color-primary);
  color: var(--color-on-primary);
  box-shadow: none;
}

.summary-box {
  width: 100%;
  max-width: 30rem;
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
  overflow-y: auto;
  max-height: 100%;
}

.summary-title {
  flex: none;
  font-size: 1.35rem;
  font-weight: 900;
  color: var(--color-accent);
  text-align: center;
}

.summary-row {
  flex: none;
  display: flex;
  align-items: center;
  gap: 0.7rem;
  background: var(--color-surface-input);
  border: var(--border-width-card) solid var(--color-border-row);
  border-radius: var(--radius-row);
  padding: 0.5rem 0.9rem;
  font-size: 1.05rem;
  font-weight: 700;
}

.summary-row .lb-rank {
  font-weight: 900;
  color: var(--color-accent);
  min-width: 2.2ch;
  text-align: center;
}

.summary-row .lb-name {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--color-text);
  font-weight: 800;
}

.summary-row .lb-time {
  font-variant-numeric: tabular-nums;
  font-weight: 900;
  color: var(--color-text);
  font-size: 1.05rem;
}

/* ---------- W4: Saved Games cards (actions reveal on hover) ---------- */

.db-card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
  gap: 0.75rem;
}

.db-game-card {
  position: relative;
  min-height: 8rem;
  background: var(--color-surface);
  border: var(--border-width-card) solid var(--color-border);
  border-radius: var(--radius-card);
  padding: 1rem 1.1rem;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 0.3rem;
  overflow: hidden;
}

.db-card-main { min-width: 0; }

.db-card-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  justify-content: center;
  gap: 0.55rem;
  padding: 1rem 1.1rem;
  background: var(--color-scrim-card);
  opacity: 0;
  transition: opacity 0.15s ease;
}

.db-card-overlay .btn { width: 100%; }

.db-game-card:hover .db-card-overlay,
.db-game-card:focus-within .db-card-overlay { opacity: 1; }

.db-card-minor {
  display: flex;
  gap: 0.9rem;
  justify-content: center;
  margin-top: 0.15rem;
}

.db-card-minor .host-auth-link { font-size: 0.8rem; }

/* Touch devices have no hover: the actions stay visible. */
@media (hover: none) {
  .db-card-overlay { position: static; opacity: 1; background: none; padding: 0.75rem 0 0; }
  .db-game-card { justify-content: flex-start; }
}

/* ---------- W1: "Your quiz is ready" modal ---------- */

.db-ready-modal {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--color-scrim-modal);
  z-index: 80;
  padding: 1.25rem;
}

.db-ready-box {
  width: 100%;
  max-width: 22rem;
  background: var(--color-surface-control);
  border: var(--border-width-card) solid var(--color-border-muted);
  border-radius: var(--radius-panel);
  padding: 1.6rem 1.4rem;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 1rem;
}

.db-ready-title {
  margin: 0;
  font-size: 1.5rem;
  font-weight: 900;
  color: var(--color-accent);
  text-align: center;
}

.db-ready-hostlive {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.2rem;
}

.db-ready-sub {
  font-size: 0.85rem;
  font-weight: 700;
  opacity: 0.9;
}

.db-ready-row {
  display: flex;
  gap: 0.6rem;
}

.db-ready-row .btn { flex: 1; }

/* ---------- toggle switches (the quiz editor's player-screen settings
   and any future switch UI share these) ---------- */

.vis-toggle {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  cursor: pointer;
  font-size: 0.85rem;
  font-weight: 700;
  color: var(--color-text-strong);
}

.vis-toggle input {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
}

.vis-switch {
  flex: none;
  width: 2.4rem;
  height: 1.35rem;
  border-radius: var(--radius-pill);
  background: var(--color-border-muted);
  border: var(--border-width-card) solid var(--color-border-strong);
  position: relative;
  transition: background 0.15s ease;
}

.vis-switch::after {
  content: '';
  position: absolute;
  top: 0.12rem;
  left: 0.14rem;
  width: 0.95rem;
  height: 0.95rem;
  border-radius: var(--radius-pill);
  background: var(--color-surface-solid);
  transition: transform 0.15s ease;
}

.vis-toggle input:checked + .vis-switch {
  background: var(--color-success);
  border-color: var(--color-success);
}

.vis-toggle input:checked + .vis-switch::after {
  transform: translateX(1rem);
}

.vis-toggle input:focus-visible + .vis-switch { outline: var(--border-width-card) solid var(--color-focus); }

/* ---------- /play empty state (W1) ---------- */

.play-empty {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.8rem;
  text-align: center;
  padding: 2rem 1.25rem;
}

.play-empty-title {
  font-size: 1.6rem;
  font-weight: 900;
  color: var(--color-accent);
}

.play-empty-sub {
  font-size: 1rem;
  color: var(--color-text-soft);
  max-width: 26rem;
}
