﻿/* ════════════════════════════════════════════════════════════
   SHADOW SALOON - Main Stylesheet
   Western-Noir Theme
════════════════════════════════════════════════════════════ */

:root {
  /* ── Raw palette: theme-INDEPENDENT constants. Never switch with the theme.
     Used by the deliberately fixed-dark artwork surfaces (spotlight banner,
     intro windows, dice/action cinemas, card backs, chat paper) and by fixed
     gold gradients (buttons, avatars). ── */
  --raw-ink:        #0d0a07;
  --raw-gold:       #c8922a;
  --raw-gold-light: #e8b84b;
  --raw-amber:      #d4620a;
  --raw-parchment:  #e8d5b0;
  --raw-smoke:      #a89784;
  --raw-old-paper:  #c9b48a;
  --raw-border:     rgba(200, 146, 42, .22);
  --raw-surface-1:        rgba(8, 5, 2, .65);
  /* Currently unreferenced since SS-0336 (the dark --surface-1-strong is now a
     literal "raised" value, not this alias). Kept as a raw-palette reference. */
  --raw-surface-1-strong: rgba(8, 5, 2, .88);
  --raw-surface-2:        rgba(200, 146, 42, .08);
  --raw-scrim:            rgba(8, 5, 2, .85);

  /* ── Semantic, theme-aware tokens (dark = default; light overrides below).
     Components reference ONLY these (or the raw ones on dark islands). ── */
  --surface-0-a: #241708;                     /* page gradient start */
  --surface-0-b: #160f07;
  --surface-0-c: #0d0a07;
  --surface-1:        var(--raw-surface-1);          /* card/panel */
  /* V2 (2026-07-05): lifted from the near-black raw value to a real "raised" step
     above --surface-1 (dropdowns/toasts/footer bar sit clearly above the panel). */
  --surface-1-strong: rgba(30, 20, 10, .90);
  --surface-2:        var(--raw-surface-2);          /* subtle inset chip */
  --surface-hover:    rgba(200, 146, 42, .14);
  --heading:     #e8b84b;                     /* readable heading/emphasis text */
  --text-main:   #e8d5b0;
  --text-dim:    #a89784;
  --text-invert: #241708;                     /* text on accent-filled surfaces */
  --accent-strong: #e8b84b;                   /* theme accent, strong variant */
  --accent-amber:  #d4620a;
  --border-soft:   rgba(200, 146, 42, .22);
  --border-strong: rgba(200, 146, 42, .45);
  /* V2: opaque edge for cards nested on the lighter --pf-board panel — 3.2:1 vs
     the panel, 3.8:1 vs .db-section (WCAG 1.4.11). Deliberately NOT a --border-soft
     bump: that would relight the game-frame/stage borders (--board-border /
     --border-soft outside .pf-board), which must stay dark. */
  --card-edge:     #7d6a52;
  --shadow-color:  rgba(0, 0, 0, .5);
  --scrim:         rgba(8, 5, 2, .85);
  /* V2: sticky app chrome (header/footer) one visible step above the page.
     --scrim stays the darker veil for overlays/backdrops — do not conflate. */
  --chrome:        rgba(33, 22, 9, .92);
  --danger:        #e88;
  --danger-strong: #c85a6a;
  --success:       #88d088;
  /* Near-opaque card/panel gradient + form-input surface (the translucent
     --surface-1 is too see-through for text-heavy panels over the saloon bg). */
  /* V2: panel elevation — lifted so cards/panels read as a step above the page. */
  --card-grad-a: rgba(34, 24, 13, .97);
  --card-grad-b: rgba(22, 15, 8, .98);
  --input-bg:    rgba(8, 5, 2, .85);
  --modal-grad-a: #2e1f0e;
  --modal-grad-b: #0d0a07;
  /* SS-0312: theme-aware game-surface tokens (dark = the former hardcoded
     island values). Light values live in the [data-theme="light"] block. */
  /* V2: game-frame FILL lifted to match the panel elevation. --board-border stays
     .28 (unchanged) — the game-frame/stage EDGE must not get lighter. */
  --board-grad-a: rgba(34, 24, 13, .97);
  --board-grad-b: rgba(22, 15, 8, .98);
  --board-border: rgba(200, 146, 42, .28);
  --board-shadow: 0 18px 55px rgba(0, 0, 0, .55), inset 0 1px 0 rgba(200, 146, 42, .09);
  --felt-base-a: #1d3b2a;
  --felt-base-b: #122418;
  --felt-base-c: #0b160e;
  --felt-rim:    #3a2410;
  --felt-shadow: inset 0 0 60px rgba(0, 0, 0, .6), 0 14px 34px rgba(0, 0, 0, .45);
  --stage-back-a: #16100a;
  --stage-back-b: #0e0905;
  --stage-floor-a: #3a2412;
  --stage-floor-b: #311d0d;
  --spot-accent-mix: 55%;   /* Akzent-Anteil im Rampenlicht-Verlauf */
  --art-glow: 46%;   /* Poster-Kacheln: Akzent-Glow (Betreiber: Dark darf kraeftiger) */
  --art-tint: 20%;
  /* SS-0312 stage 2: small-scale game-surface tokens (wells/chips inset on
     boards, neutral hairlines). Dark = the former hardcoded values. */
  --well:        rgba(8, 5, 2, .45);
  --well-strong: rgba(8, 5, 2, .62);
  --edge:        rgba(255, 255, 255, .07);
  --edge-strong: rgba(255, 255, 255, .14);
  --border-faint: rgba(200, 146, 42, .10);

  /* ── Legacy palette names: kept as aliases of the semantic tokens so the
     existing rules follow the theme. Fixed gradients keep using --gold/
     --gold-light (raw constants, see below) on purpose. ── */
  --ink:        #0d0a07;
  --dark-wood:  #1a1208;
  --mid-wood:   #2e1f0e;
  --warm-wood:  #4a2f14;
  --gold:       #c8922a;
  --gold-light: #e8b84b;
  --amber:      #d4620a;
  /* --smoke: warm sandy beige for secondary text (labels, hints, counters).
     Lightened from #8a7a6a to #a89784 so the contrast on the dark
     saloon background is comfortably AA-compliant (~6:1 instead of 4.5:1).
     Atmosphere stays warm/muted. */
  --smoke:      var(--text-dim);
  --parchment:  var(--text-main);
  --old-paper:  #c9b48a;
  --blood-red:  #8b1a1a;
  --red-light:  #c0352a;
  --green-felt: #1a3d2b;
  --green-ok:   #2d7a4a;
  --shadow:     #0a0806;
  /* Generic border tone (muted gold). WAS UNDEFINED EVERYWHERE - every
     `border: 1px solid var(--border)` (admin shell, toolbar dividers, filter
     fields, pager, podium/report box) was an invalid declaration and rendered
     NO border at all - that is why the outer frame of the variant-B shell was missing. */
  --border:     var(--border-soft);
  --btn-radius: 6px;            /* Button standard: uniform corner radius (soft) for all real action buttons */

  /* Per-mode accent: defaults to gold, overridden in .mode-* classes. */
  --accent:       var(--gold);
  --accent-light: var(--gold-light);

  /* Body font: Inter for UI readability + tabular numbers, loaded
     via Google Fonts in App.razor. System stack as fallback. Headings use
     Rye (see h1/h2/h3 + .card-title/.lobby-code/etc. with explicit
     font-family: 'Rye'). Special Elite was removed entirely. */
  --font-body: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
               'Helvetica Neue', Arial, sans-serif;
}

/* ── Light theme ("Wanted Poster bei Tageslicht"): same color family, inverted
   lightness. Values match the approved mockup (sitewide-layout-final.html).
   Toggled via html[data-theme="light"], persisted in localStorage (ssTheme).
   (Der frühere Zusatz-Selektor für .modal-overlay-v2 stammte aus der
   §8-Insel-Zeit und ist mit dem Insel-Abbau (SS-0312 Etappe 2) überflüssig;
   er bleibt harmlos stehen, falls ein Overlay je wieder eigene Token-Pins
   bekommt.) ── */
[data-theme="light"],
[data-theme="light"] .modal-overlay-v2 {
  --surface-0-a: #fbf3e0;
  --surface-0-b: #f2e3c4;
  --surface-0-c: #e9d7ae;
  --surface-1:        rgba(255, 252, 245, .86);
  --surface-1-strong: rgba(255, 255, 250, .96);
  --surface-2:        rgba(156, 106, 26, .08);
  --surface-hover:    rgba(156, 106, 26, .13);
  --heading:     #7a4a12;
  --text-main:   #3a2a16;
  /* SS-0312 E2: von #6b5c48 abgedunkelt — auf den dunkelsten Sand-Stops der
     Spielflächen (≈#ccb181) fiel Dim-Text sonst auf 3,4–3,8:1. */
  --text-dim:    #4f4335;
  --text-invert: #fff8ec;
  --accent-strong: #7a4a12;
  /* SS-0312 E2: von #b5540a abgedunkelt — fiel auf Sand-Karten unter 3:1. */
  --accent-amber:  #7d3b07;
  --border-soft:   rgba(120, 80, 20, .28);
  --border-strong: rgba(120, 80, 20, .5);
  /* V2 light counterparts: light panel/card already contrast well, so card-edge
     reuses the stronger brown border; chrome mirrors the light scrim. */
  --card-edge:     rgba(120, 80, 20, .5);
  --shadow-color:  rgba(80, 60, 30, .18);
  --scrim:         rgba(255, 250, 240, .9);
  --chrome:        rgba(255, 250, 240, .9);
  --danger:        #a3324a;
  --danger-strong: #7a2338;
  --success:       #17663a;   /* dark enough for 4.5:1 even on the darker modal-gradient end (#f2e3c4) */
  --card-grad-a: rgba(255, 252, 245, .94);
  --card-grad-b: rgba(249, 240, 222, .97);
  --input-bg:    rgba(255, 255, 250, .9);
  --modal-grad-a: #fffdf7;
  --modal-grad-b: #f2e3c4;
  /* SS-0312: light variants of the game-surface tokens — "Wanted Poster bei
     Tageslicht": cream boards, daylight felt, bright stage backdrop. */
  --board-grad-a: rgba(247, 236, 212, .92);
  --board-grad-b: rgba(230, 209, 168, .96);
  --board-border: rgba(120, 80, 20, .35);
  --board-shadow: 0 18px 45px rgba(80, 60, 30, .22), inset 0 1px 0 rgba(255, 255, 255, .6);
  --felt-base-a: #446e55;
  --felt-base-b: #3a6049;
  --felt-base-c: #30523e;
  --felt-mix-a: 7%;
  --felt-mix-b: 12%;
  --felt-mix-c: 15%;
  --felt-rim:    #8a6a3c;
  --felt-shadow: inset 0 0 60px rgba(40, 70, 52, .35), 0 14px 34px rgba(80, 60, 30, .28);
  --stage-back-a: #e9d4a9;
  --stage-back-b: #d8bc88;
  --stage-floor-a: #b8934f;
  --stage-floor-b: #aa8441;
  --spot-accent-mix: 26%;   /* Light: Pastell statt Vollton, sonst faellt der Text unter 4.5:1 */
  --art-glow: 58%;   /* Poster-Kacheln: Akzent im Light kraeftiger, sonst blass */
  --art-tint: 30%;
  --well:        rgba(156, 106, 26, .10);
  --well-strong: rgba(156, 106, 26, .16);
  --edge:        rgba(120, 80, 20, .16);
  --edge-strong: rgba(120, 80, 20, .30);
  --border-faint: rgba(120, 80, 20, .16);
  /* Legacy names that were used directly as colors (not via the aliases above). */
  /* SS-0312 E2: von #6a5642 abgedunkelt (s. --text-dim). */
  --old-paper: #4a3b28;
  --accent:    #9c6a1a;   /* gold-mode accent readable on light; .mode-* still override */
}

/* ── §8 "Always dark islands" — ABGEBAUT (SS-0312 Etappe 2). Der frühere
   Dark-Re-Pin-Block für .screen-game/.screen-break/.screen-voting/
   .screen-result/.card-board ist ersatzlos entfernt: alle Spielflächen laufen
   jetzt auf den theme-fähigen Tokens (Dark-Werte = die alten Insel-Werte).
   Bewusst FEST DUNKEL bleiben nur eigenständige Artwork-/Kino-Flächen
   (Intro-Fenster .gintro-*, Würfel-/Aktions-Kinos, Roll-/Shuffle-Prompts,
   Kick-Toasts, Karten-Rücken, Seeschlacht-Wasser, Chat-Telegrammpapier,
   Kopf-Hero .lobby-hero) — deren Text-Inks hängen an der Raw-Palette
   (--raw-*), nie an Theme-Tokens. ── */

/* Per-game accent colors: applied via mode-* classes on the game screen
   root, the lobby wrapper, and mode pills in profile/statistics. */
.mode-schattenspiel { --accent: #5a2f4a; --accent-light: #9a5a8a; }
.mode-hangman       { --accent: #7a3a1a; --accent-light: #b8693a; }
.mode-tabu          { --accent: #a8553a; --accent-light: #d68a72; }
.mode-musikquiz     { --accent: #a3324a; --accent-light: #d65c78; }
/* Wissensquiz: teal/blue-green - intentionally the only COOL accent, clearly distinct
   from the four warm tones. */
.mode-wissensquiz   { --accent: #1f6f6a; --accent-light: #3fa89f; }
/* Memory: jade/card-table green */
.mode-memory        { --accent: #1f8a6d; --accent-light: #37b894; }
/* Durak: tsarist purple */
.mode-durak         { --accent: #4a2f6e; --accent-light: #7d5bc0; }
/* Skat: oak-leaf green (card table mode) */
.mode-skat          { --accent: #3f6b32; --accent-light: #7faa55; }
/* Doppelkopf: cognac/amber (card table mode) */
.mode-doppelkopf    { --accent: #9a5a1e; --accent-light: #d18a3e; }
/* Poker: garnet red (card table mode) */
.mode-poker         { --accent: #8e2c3b; --accent-light: #c85a6a; }
/* Seeschlacht: navy/steel blue */
.mode-seeschlacht   { --accent: #2b4f74; --accent-light: #4d7eab; }
/* Schnellschuss: cactus teal (Stammtisch shedding game) */
.mode-schnellschuss { --accent: #1f9aae; --accent-light: #4fc4d6; }
/* Rausschmeisser: colt steel / gunmetal (dice race game) */
.mode-rausschmeisser { --accent: #4a5d6b; --accent-light: #7d97a8; }
/* Mahjong: bone-white taupe (stone/porcelain, layered pair puzzle) */
.mode-mahjong       { --accent: #8a7a63; --accent-light: #b8a888; }
/* Boomtown: prairie/denim blue (frontier build-and-trade board game) */
.mode-boomtown      { --accent: #2f6aa6; --accent-light: #5fa0da; }
/* Ultimate TicTacToe: rosewood/mauve (meta tic-tac-toe board game). --x-color/--o-color
   are the readable X/O glyph tints (per theme, ≥7:1) — --accent-light must never be text. */
.mode-uttt          { --accent: #82355c; --accent-light: #c76194; --x-color: #d98cb2; --o-color: #9db2c7; }
[data-theme="light"] .mode-uttt { --x-color: #7a2a4e; --o-color: #3f5468; }

/* SS-0312 stage 2: accent-tinted TEXT ink. Dark keeps the vivid --accent-light
   look (pixel-identical), light switches to a readable accent/text mix —
   --accent-light must never be used as a text color directly. --gold-ink is
   the same idea for the fixed gold accent (--gold as text). The per-mode rule
   re-declares the ink ON the mode root so it picks up the mode accent (custom
   properties resolve where they are declared, not where they are used). */
:root { --accent-ink: var(--accent-light); --gold-ink: #c8922a; }
[data-theme="light"] { --gold-ink: #7a4a12; }
.mode-schattenspiel, .mode-hangman, .mode-tabu, .mode-musikquiz, .mode-wissensquiz,
.mode-memory, .mode-durak, .mode-skat, .mode-doppelkopf, .mode-poker,
.mode-seeschlacht, .mode-schnellschuss, .mode-rausschmeisser, .mode-mahjong,
.mode-boomtown, .mode-uttt {
  --accent-ink: var(--accent-light);
}
[data-theme="light"],
[data-theme="light"] :is(.mode-schattenspiel, .mode-hangman, .mode-tabu,
  .mode-musikquiz, .mode-wissensquiz, .mode-memory, .mode-durak, .mode-skat,
  .mode-doppelkopf, .mode-poker, .mode-seeschlacht, .mode-schnellschuss,
  .mode-rausschmeisser, .mode-mahjong, .mode-boomtown, .mode-uttt) {
  --accent-ink: color-mix(in srgb, var(--accent) 30%, var(--text-main));
}
.uttt-legend .lg-x { color: var(--x-color); font-weight: 700; }
.uttt-legend .lg-o { color: var(--o-color); font-weight: 700; }
.uttt-local.illegal-dim { opacity: .4; filter: saturate(.6); }
.uttt-local.won-x { background: color-mix(in srgb, var(--x-color) 16%, var(--surface-2)); border-color: color-mix(in srgb, var(--x-color) 55%, transparent); }
.uttt-local.won-o { background: color-mix(in srgb, var(--o-color) 16%, var(--surface-2)); border-color: color-mix(in srgb, var(--o-color) 55%, transparent); }
.uttt-local.won-x::after, .uttt-local.won-o::after, .uttt-local.drawn::after {
  content: ''; position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  font-family: 'Rye', cursive; pointer-events: none; font-size: clamp(26px, 7vw, 52px);
}
.uttt-local.won-x::after { content: '✕'; color: var(--x-color); opacity: .92; }
.uttt-local.won-o::after { content: '○'; color: var(--o-color); opacity: .92; }
.uttt-cell.is-x { color: var(--x-color); }
.uttt-cell.is-o { color: var(--o-color); }
@keyframes utti-pop { from { opacity: 0; transform: scale(.4) rotate(-8deg); } to { opacity: 1; transform: none; } }
/* 5 cards must fit a 375px viewport: tighten gap + shrink the row's cards. */

/* Base .btn is display:block + width:100%. In card action bars the
   buttons should be inline + content-width + compact (otherwise full-width "slabs"). */
.card-actions { display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; align-items: center; }
.card-actions .btn,
.pk-actions .btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  width: auto; flex: 0 0 auto; min-width: 104px; padding: 9px 18px;
  font-size: 13px; letter-spacing: .06em; border-radius: var(--btn-radius, 6px);
}

/* Card tables more compact - sections denser, smaller center, more compact "End game"
   (scoped to .card-board so Durak/Seeschlacht remain untouched). */
/* The entire game sits in ONE framed panel (like the header "card"): accent-colored
   border + dark gradient, so nothing floats loosely on the background. */
.card-board {
  gap: 8px; position: relative;
  background: linear-gradient(135deg, var(--board-grad-a), var(--board-grad-b));
  border: 1px solid var(--board-border);
  border-radius: 0 0 4px 4px; padding: 16px 18px;
  box-shadow: var(--board-shadow);
}
/* Docked directly below the header card (like .lobby-actions): header open at bottom,
   board square at top, shared 1px divider, no gap. */
.lobby-redesign .lobby-header + .card-board { border-radius: 0 0 4px 4px; }
.card-board .durak-seats { gap: 8px; }
.card-board .durak-table { padding: 12px 16px; }
.card-board .durak-hand-head { margin-bottom: 4px; }
.card-board .durak-hand { padding-top: 6px; }
.card-board .host-section { border-top: none; padding-top: 0; margin-top: 4px; }
.card-board .abort-btn { width: auto; max-width: 220px; margin: 0 auto; padding: 6px 16px; font-size: 12px; }
/* Shared anchored footer (lobby = game): strip at the bottom edge of the board panel,
   status info on the left (cab-status), context action on the right (start button or game actions).
   Nothing floats freely; the inner .card-actions/.pk-actions row keeps its compact dimensions. */
.card-board .card-actions-bar {
  margin: 10px -18px -16px; display: flex; align-items: center; justify-content: space-between;
  gap: 8px 14px; flex-wrap: wrap; padding: 12px 18px;
  /* Saloon gold like the panel border (.card-board), not the mode accent - the footer
     visually belongs to the panel border. */
  border-top: 1px solid var(--board-border);
  background: var(--surface-2); border-radius: 0 0 4px 4px;
}
.card-board .card-actions-bar:empty { display: none; }
.card-board .card-actions-bar .cab-status {
  display: flex; align-items: center; gap: 8px; flex: 1 1 220px; min-width: 0;
  font-size: 12.5px; color: var(--old-paper); line-height: 1.3;
}
.card-board .card-actions-bar .cab-status b { color: var(--parchment); font-weight: 600; }
.card-board .card-actions-bar .card-actions { margin: 0; flex: 0 0 auto; }
/* Poker actions in the footer: NO inner border (the board panel already frames) and full
   footer width - the buttons spread across the entire strip instead of a box. */
.card-board .card-actions-bar .pk-actions {
  margin: 0; flex: 1 1 100%; width: 100%;
  padding: 0; border: none; background: none; border-radius: 0;
  justify-content: space-between;
}

/* ════ Unified shell - mock-only rules made real. Applies to ALL games in the
   shared GameShell (Lobby + Game). ════ */
/* Width cap: board flush with the 880px header (.lobby-header) - width:100%,
   otherwise the panel shrinks to content width in the centered screen-game flex (grid collapses). */
.card-board { width: 100%; max-width: 1000px; margin-left: auto; margin-right: auto; }
/* Nested (unframed) card panel fills the shell without its own cap. */
.card-board .card-board { max-width: none; }
/* No double border: remove frame from inner .card / profile inside the accent panel. */
.card-board .card { background: none; border-color: transparent; box-shadow: none; }
.card-board .card::before, .card-board .card::after { display: none; }
.card-board .stat-box.wanted-poster { background: none; border-color: transparent; box-shadow: none; }
/* Fit inner game containers into the shell. */
.card-board .screen-voting { background: none; min-height: 0; padding: 0; }
.card-board .hangman-layout, .card-board .see-wrap, .card-board .mq-card,
.card-board .hangman-word-card, .card-board .memory-board-card { margin: 0; }
/* Seeschlacht: "Your Fleet" + "Target Waters" side by side (otherwise they wrap in the narrower panel). */
.card-board .see-main { flex-wrap: nowrap; justify-content: center; gap: 14px; padding: 12px; align-self: stretch; }
.card-board .see-main > div { min-width: 0; }
.card-board .see-targets { justify-content: center; }
/* Break/podium/result screens: height/centering + deframing (own borders/ornaments removed). */
.card-board .screen-result { min-height: 0; padding: 4px 0; }
.card-board .break-stage, .card-board .podium-wrapper { min-height: 0; margin: 0 auto; }
.card-board .break-stage, .card-board .podium-wrapper, .card-board .card-break { background: none; border: none; box-shadow: none; }
.card-board .break-stage::before, .card-board .break-stage::after { display: none; }
/* Podium stats: slim accent scrollbar + sticky heading for many rounds. */
.card-board .podium-stats {
  max-height: 460px; overflow-y: auto; padding-right: 8px;
  /* padding-top 0 - no strip above the sticky header (otherwise scrolling
     text shows through); the header itself provides the top spacing via padding-top. */
  padding-top: 0;
  /* No own well/border inside the board panel — matches the final-score column
     (card-break is unframed here too); the off-tone box read badly on light. */
  background: none; border: none;
  scrollbar-width: thin; scrollbar-color: color-mix(in srgb, var(--accent) 60%, transparent) transparent;
}
.card-board .podium-stats::-webkit-scrollbar { width: 7px; }
.card-board .podium-stats::-webkit-scrollbar-track { background: transparent; }
.card-board .podium-stats::-webkit-scrollbar-thumb { background: color-mix(in srgb, var(--accent) 52%, transparent); border-radius: 999px; }
.card-board .podium-stats::-webkit-scrollbar-thumb:hover { background: color-mix(in srgb, var(--accent) 80%, transparent); }
/* Sticky header sits flush at the top (container padding-top:0) and provides its own
   top spacing; opaque, fully covering background + high z-index - scrolling text is
   cleanly covered instead of showing through. */
.card-board .podium-stats .section-label { position: sticky; top: 0; z-index: 5; margin: 0 0 8px; padding: 16px 0 10px; background: #130d06; }
/* In-game: game components render their own screen-game/screen-break wrapper INSIDE
   the shared GameShell card-board - neutralize (no second saloon background/panel). */
.card-board .screen-game, .card-board .screen-break { background: none; min-height: 0; padding: 0; }
/* Card games bring their own "durak-board card-board" - unfame the nested panel
   so only the outer GameShell draws the accent border (no double border). */
.card-board .card-board { border: none; background: none; box-shadow: none; padding: 0; margin: 0; }
/* In-game abort now runs centrally via the header X - hide the component-specific
   "End game" buttons (host-section/abort-btn) inside the shell. */
.card-board .host-section, .card-board .abort-btn { display: none; }
/* Poker bet bar: no inner border inside the accent panel (no double border). */
.card-board .pk-actions { background: none; border: none; padding: 0; }

/* Deck skin selector (face card letters) at the card table */
.deck-skin-select { display: inline-flex; gap: 0; border: 1px solid var(--border); border-radius: 999px; overflow: hidden; }
.deck-skin-select .dss { background: var(--well); border: none; border-right: 1px solid var(--border); color: var(--smoke);
  font-family: var(--font-body); font-size: 12px; padding: 4px 9px; cursor: pointer; line-height: 1; }
.deck-skin-select .dss:last-child { border-right: none; }
.deck-skin-select .dss.on { background: color-mix(in srgb, var(--accent) 30%, transparent); color: var(--accent-ink); font-weight: 600; }
.deck-skin-select .dss:hover:not(.on) { color: var(--old-paper); }

/* ════════════════════════════════════════════════════════════
   Modal v2 - unified base component
   Used via the <Modal> component in Components/Shared/Modal.razor.
   The old modal wrapper classes (.modal-overlay, .modal-backdrop,
   .modal-content*, .modal-header/body/footer/close, .tdm-modal/-head/-close/-body,
   .history-modal*, .player-profile-modal, .mode-info-modal, .rules-modal,
   .matchmaking-modal, .help-modal/-body, .mini-dialog, .create-lobby-modal)
   were removed in May 2026 (~308 lines). Body/content classes like
   .tdm-hero, .player-profile-info, .join-dialog-* etc. remain and
   are used directly in the <Modal> BodyContent slot.
═══════════════════════════════════════════════════════════════ */
.modal-overlay-v2 {
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,.72);
  /* backdrop-filter removed: caused GPU repaint on every animation frame
     (perf measurement: presentation delay dominates, blur is unnecessarily expensive) */
  z-index: 1000;
  /* align-items:flex-start + overflow-y:auto + margin:auto on child instead of
     align-items:center. Fixes the iOS Safari portrait problem (fixed + backdrop-
     filter + flex-centering caused the modal to jump to the bottom right) and scrolls
     cleanly for very tall modals without clipping the top. On desktop unchanged,
     centered (margin:auto). */
  display: flex;
  align-items: flex-start;
  justify-content: center;
  overflow-y: auto;
  padding: 20px;
  animation: modalV2FadeIn .05s ease-out;
}
@keyframes modalV2FadeIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}

.modal-v2 {
  /* Theme-aware modal surface: outside game pages it follows light/dark;
     inside the always-dark islands the token re-pin keeps it dark. */
  background: linear-gradient(to bottom, var(--modal-grad-a) 0%, var(--modal-grad-b) 100%);
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  box-shadow: 0 12px 40px var(--shadow-color);
  display: flex;
  flex-direction: column;
  /* overflow:visible (was hidden): the game-switch dropdown in the modal
     header must be able to extend BELOW short modals (few settings).
     Corner clipping is handled by radii on the first/last child instead. */
  overflow: visible;
  width: 100%;
  max-height: calc(100vh - 40px);
  margin: auto;   /* centers vertically when there is space, otherwise the overlay scrolls */
}
.modal-v2 > :first-child { border-top-left-radius: 6px; border-top-right-radius: 6px; }
.modal-v2 > :last-child { border-bottom-left-radius: 6px; border-bottom-right-radius: 6px; }
.modal-v2-sm { max-width: 440px; }
.modal-v2-md { max-width: 580px; }
.modal-v2-lg { max-width: 760px; }
.modal-v2-xl { max-width: 920px; }   /* Lobby settings: room for the filter pill row + chips */

.modal-v2-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 14px 18px;
  border-bottom: 1px solid var(--border-soft);
  background: var(--surface-2);
  flex-shrink: 0;
  /* Wrap on mobile: when the header content (e.g. title + HeaderContent + close)
     does not fit on one line, elements may wrap to the next line
     instead of overflowing or overlapping. No effect on desktop since
     the content fits comfortably. */
  flex-wrap: wrap;
}
.modal-v2-title {
  font-family: 'Rye', cursive;
  font-size: 17px;
  color: var(--heading);
  letter-spacing: .5px;
  flex: 1;
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
}
.modal-v2-title-icon {
  font-size: 22px;
  flex-shrink: 0;
  line-height: 1;
  /* Emoji/glyph vertical alignment: emoji glyphs sit visually high in their
     line box (more space below than above), while the Rye title caps
     sit low in the line box (cap height near baseline). flex align-items:center
     aligns the line-box centers, not the visual glyph centers - so without
     correction the icon appears about 2px above the title. translateY corrects
     this. line-height:1 additionally tightens the icon box so the
     nudge remains consistent. */
  transform: translateY(2px);
}
.modal-v2-title-text-wrap {
  display: flex;
  flex-direction: column;
  min-width: 0;
}
.modal-v2-title-text {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.modal-v2-subtitle {
  font-size: 12px;
  color: var(--smoke);
  font-style: italic;
  letter-spacing: 0;
  margin-top: 2px;
}

.modal-v2-close {
  background: transparent;
  border: 1px solid var(--border-soft);
  color: var(--text-dim);
  width: 28px;
  height: 28px;
  border-radius: 3px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  font-size: 14px;
  font-family: inherit;
  flex-shrink: 0;
  transition: all .15s;
  padding: 0;
}
.modal-v2-close:hover {
  color: var(--heading);
  border-color: var(--gold);
  background: var(--surface-hover);
}

.modal-v2-body {
  padding: 18px 20px;
  overflow-y: auto;
  flex: 1;
  min-height: 0;
}

.modal-v2-footer {
  display: flex;
  gap: 10px;
  padding: 12px 18px;
  border-top: 1px solid var(--border-soft);
  background: var(--surface-2);
  justify-content: flex-end;
  flex-wrap: wrap;
  flex-shrink: 0;
}
.modal-v2-footer-vertical {
  flex-direction: column;
  align-items: stretch;
}
.modal-v2-footer-vertical .btn {
  width: 100%;
}

/* ── Confirm-Switch - info card for the existing lobby ────────── */
.switch-lobby-card {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 4px;
  margin: 4px 0 14px;
}
.switch-lobby-code {
  font-family: 'Rye', cursive;
  font-size: 18px;
  letter-spacing: .22em;
  color: var(--heading);
  background: var(--surface-1-strong);
  border: 1px solid var(--gold);
  padding: 5px 12px;
  border-radius: 3px;
  white-space: nowrap;
}
.switch-lobby-meta { min-width: 0; }
.switch-lobby-game { color: var(--parchment); font-weight: 600; }
.switch-lobby-sub  { color: var(--smoke); font-size: 12px; margin-top: 2px; }
.switch-role-chip {
  display: inline-block;
  font-size: 12px;
  letter-spacing: .04em;
  padding: 1px 7px;
  border-radius: 10px;
  margin-left: 2px;
  border: 1px solid rgba(200,146,42,.4);
  color: var(--gold-light);
}
.switch-host-note {
  display: flex;
  gap: 8px;
  align-items: flex-start;
  font-size: 12.5px;
  color: var(--old-paper);
  background: rgba(139,26,26,.12);
  border-left: 2px solid var(--amber);
  padding: 8px 11px;
  border-radius: 0 3px 3px 0;
}
.switch-host-note span:first-child { flex-shrink: 0; }
.secret-word-card > *,
.hangman-word-card > *,
.tabu-word-display > *,
.tabu-reveal-word-card > *,
.mq-card > * { position: relative; z-index: 1; }

.stage-corner {
  position: absolute;
  font-size: 14px;
  color: var(--accent-ink);
  font-family: 'Times New Roman', serif;
  line-height: 1;
  opacity: .8;
  pointer-events: none;
  z-index: 2;
}
.stage-corner-tl { top: 6px; left: 8px; }
.stage-corner-tr { top: 6px; right: 8px; }
.stage-corner-bl { bottom: 6px; left: 8px; }
.stage-corner-br { bottom: 6px; right: 8px; }

/* ─── Western avatar (procedural, deterministic from name hash) ──────
   Used by the Avatar.razor component. Three hat variants, three
   mustache variants, two eye styles - 18 combinations.
   Four sizes Sm/Md/Lg/Xl. */

.avatar {
  position: relative;
  display: inline-block;
  flex-shrink: 0;
  --av-size: 28px;
  --hat-color: #1a0f06;
  width: var(--av-size);
  height: var(--av-size);
  /* Clip to circle - procedural portrait is a clean circle like the
     photo; the hat corners of the square box no longer stick out of the ring. */
  border-radius: 50%;
  overflow: hidden;
}
.avatar-sm { --av-size: 20px; }
.avatar-md { --av-size: 28px; }
.avatar-lg { --av-size: 44px; }
.avatar-xl { --av-size: 60px; }
.avatar-xxl { --av-size: 104px; }

/* Uploaded portrait - sits above the procedural one (same size),
   round & opaque. onerror removes the <img> on 404 - procedural remains. */
.avatar-photo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  object-fit: cover;
  border: 1px solid rgba(0,0,0,.5);
  background: #2a1a0c;
  /* Hidden until onload confirms the file exists; on 404
     onerror keeps it hidden - procedural portrait remains visible. */
  visibility: hidden;
}

/* Team logo (rounded square; placeholder shield + optional image on top). */
.team-logo {
  position: relative;
  display: inline-flex; align-items: center; justify-content: center;
  flex-shrink: 0;
  border-radius: 10px;
  overflow: hidden;
  background: linear-gradient(135deg, #5a3a1f, #241608);
  border: 1px solid rgba(200,146,42,.4);
}
.team-logo-sm { width: 40px; height: 40px; font-size: 20px; border-radius: 8px; }
.team-logo-md { width: 64px; height: 64px; font-size: 30px; }
.team-logo-lg { width: 88px; height: 88px; font-size: 44px; }
/* Sits on the fixed dark .team-logo gradient — must stay raw/light in both themes. */
.team-logo-ph  { color: var(--raw-smoke); line-height: 1; }
.team-logo-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; visibility: hidden; }

/* Teams overview (/Teams) */
.teams-toolbar { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; margin-bottom: 14px; }
.teams-search  { flex: 1; min-width: 180px; max-width: 320px; }
.teams-create-btn { margin-left: auto; }
/* Base .btn is display:block + width:100% + no background. In the
   team UI the buttons should be inline + content-width + more compact. */
.teams-toolbar .btn,
.team-row .btn,
.team-hero-actions .btn,
.team-admin-actions .btn,
.team-back {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  width: auto; flex: 0 0 auto; padding: 9px 16px; font-size: 13px; letter-spacing: .06em;
}
/* Buttons WITHOUT a color modifier (search, view, change logo, promote, back)
   would otherwise inherit the backgroundless base .btn - white <button> default or purple
   <a> link. Style them explicitly as ghost here; gold/red buttons are excluded. */
.teams-toolbar .btn:not([class*="btn-gold"]):not([class*="btn-ghost-red"]):not([class*="btn-red"]),
.team-row .btn:not([class*="btn-gold"]):not([class*="btn-ghost-red"]):not([class*="btn-red"]),
.team-hero-actions .btn:not([class*="btn-gold"]):not([class*="btn-ghost-red"]):not([class*="btn-red"]),
.team-admin-actions .btn:not([class*="btn-gold"]):not([class*="btn-ghost-red"]):not([class*="btn-red"]),
.team-member-actions .btn:not([class*="btn-gold"]):not([class*="btn-ghost-red"]):not([class*="btn-red"]),
.team-back {
  background: transparent;
  border: 1px solid rgba(200,146,42,.32);
  color: var(--old-paper);
  text-decoration: none;
}
.teams-toolbar .btn:not([class*="btn-gold"]):not([class*="btn-ghost-red"]):not([class*="btn-red"]):hover,
.team-row .btn:not([class*="btn-gold"]):not([class*="btn-ghost-red"]):not([class*="btn-red"]):hover,
.team-hero-actions .btn:not([class*="btn-gold"]):not([class*="btn-ghost-red"]):not([class*="btn-red"]):hover,
.team-admin-actions .btn:not([class*="btn-gold"]):not([class*="btn-ghost-red"]):not([class*="btn-red"]):hover,
.team-member-actions .btn:not([class*="btn-gold"]):not([class*="btn-ghost-red"]):not([class*="btn-red"]):hover,
.team-back:hover {
  border-color: var(--gold); color: var(--gold-light); background: rgba(200,146,42,.05);
}
.teams-list { display: flex; flex-direction: column; }
.team-row { display: flex; align-items: center; gap: 12px; padding: 10px 4px; border-bottom: 1px solid rgba(200,146,42,.1); }
.team-row:last-child { border-bottom: none; }

/* Whole-row click affordance: hover background, focus ring and a chevron that
   nudges right on hover. Shared by team rows, "my team" and friend rows. */
.row-clickable { cursor: pointer; border-radius: 6px; padding-left: 10px; padding-right: 8px; transition: background .12s ease; }
.row-clickable:hover, .row-clickable:focus-visible { background: rgba(200,146,42,.08); outline: none; }
.row-clickable:focus-visible { box-shadow: 0 0 0 1px rgba(200,146,42,.5) inset; }
.row-chevron { margin-left: auto; flex: 0 0 auto; color: var(--smoke); font-size: 18px; line-height: 1; opacity: .45; transition: opacity .12s ease, transform .12s ease, color .12s ease; }
.row-clickable:focus-visible .row-chevron {
  opacity: .95;
  transform: translateX(2px);
  color: var(--gold-light);
}
@media (hover: hover) {
  .row-clickable:hover .row-chevron {
    opacity: .95;
    transform: translateX(2px);
    color: var(--gold-light);
  }
}
/* When the row already has an action cluster (which carries margin-left:auto),
   the chevron only needs a small gap, not its own auto-push. */
.row-clickable .friend-row-acts ~ .row-chevron { margin-left: 6px; }
.team-row-main { flex: 1; min-width: 0; }
.team-row-name { color: var(--parchment); font-size: 14px; }
.team-row-desc { color: var(--smoke); font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Team page (/Team/{id}) */
.team-hero { display: flex; gap: 18px; align-items: flex-start; flex-wrap: wrap; }
.team-hero-main { flex: 1; min-width: 200px; }
.team-hero-name { font-size: 22px; margin: 0; text-align: left; }
.team-hero-desc { margin: 4px 0; }
.team-hero-meta { font-size: 12px; }
.team-hero-actions { display: flex; align-items: center; }
.team-hero-note { font-size: 12px; }
.team-sub { color: var(--heading); font-size: 12px; letter-spacing: .04em; text-transform: uppercase; margin: 16px 0 6px; }
.team-sub-first { margin-top: 0; }
.team-stats-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; }
@media (max-width: 540px) { .team-stats-grid { grid-template-columns: repeat(2, 1fr); } }
.team-stat { background: var(--surface-2); border: 1px solid var(--border-soft); border-radius: 5px; padding: 12px 10px; text-align: center; }
.team-stat-val { display: block; font-family: 'Rye', cursive; color: var(--heading); font-size: 20px; }
.team-stat-mode { font-size: 15px; }
.team-stat-lbl { display: block; color: var(--smoke); font-size: 12px; margin-top: 3px; }
.team-members { display: flex; flex-direction: column; }
.team-member-row { display: flex; align-items: center; gap: 11px; padding: 8px 4px; border-bottom: 1px solid rgba(200,146,42,.08); }
.team-member-row:last-child { border-bottom: none; }
/* Avatar + name as a profile link (the row keeps its own action buttons on the
   right, so the link deliberately covers only the identity part). */
.team-member-link { display: flex; align-items: center; gap: 11px; flex: 1; min-width: 0; color: inherit; text-decoration: none; border-radius: 6px; }
.team-member-link:hover .team-member-name { color: var(--heading); text-decoration: underline; text-underline-offset: 2px; }
.team-member-main { flex: 1; min-width: 0; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.team-member-name { color: var(--parchment); font-size: 13.5px; }
.team-req-meta { font-size: 12px; }
.team-member-actions { display: flex; gap: 7px; flex-shrink: 0; }
.team-role-badge { font-size: 12px; letter-spacing: .03em; padding: 1px 8px; border-radius: 10px; border: 1px solid rgba(200,146,42,.22); color: var(--smoke); }
.team-role-admin { background: rgba(200,146,42,.16); border-color: rgba(200,146,42,.6); color: var(--heading); }
.team-admin-box { border-color: rgba(200,146,42,.5); margin-top: 16px; background: rgba(200,146,42,.05); }
.team-admin-title { font-size: 14px; }
.team-admin-actions { display: flex; gap: 10px; flex-wrap: wrap; }

/* Team description inline editor (team admins). */
.team-desc-current { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; }
.team-desc-current .btn { width: auto; flex: 0 0 auto; }
.team-desc-edit { display: flex; flex-direction: column; gap: 8px; }
.team-desc-textarea { width: 100%; resize: vertical; min-height: 60px; }
.team-desc-edit-actions { display: flex; align-items: center; gap: 10px; justify-content: flex-end; }
.team-desc-count { margin-right: auto; font-size: 12px; }

.team-back { margin-top: 10px; }
.team-mine { display: flex; align-items: center; gap: 12px; margin-bottom: 8px; }
.team-mine-main { flex: 1; min-width: 0; }
.team-mine-name { color: var(--parchment); font-size: 14px; }

/* Avatar section in the profile (preview + upload/remove) */
.avatar-edit         { display: flex; gap: 18px; align-items: center; flex-wrap: wrap; }
.avatar-ring         { border: 2px solid rgba(200,146,42,.35); border-radius: 50%; padding: 3px; display: inline-flex; flex-shrink: 0; }
.avatar-edit-body    { flex: 1; min-width: 220px; }
.avatar-edit-actions { display: flex; flex-direction: row; flex-wrap: wrap; gap: 8px; margin: 8px 0 6px; }
/* Compact inline buttons (overrides .btn base: full-width/Rye/large). */
.avatar-edit-actions .btn {
  width: auto; padding: 8px 16px; font-size: 12px; letter-spacing: .06em;
  text-align: center; box-sizing: border-box; cursor: pointer;
}
.avatar-file-input   { display: none; }
.avatar-locked-note  {
  display: flex; gap: 8px; align-items: flex-start;
  color: var(--smoke); font-size: 12.5px;
  background: rgba(200,146,42,.07); border: 1px solid rgba(200,146,42,.18);
  border-radius: 4px; padding: 10px 12px; max-width: 460px;
}

/* Crop editor (modal). The stage shows the image (inserted via JS as an
   absolutely positioned <img> + panned/zoomed); ::before darkens everything
   outside the circle, ::after draws the dashed circle border.
   Both pointer-events:none so dragging works. */
.crop-stage {
  position: relative;
  width: 300px; height: 300px;
  margin: 0 auto;
  background: #241608;
  border-radius: 4px;
  overflow: hidden;
  cursor: grab;
  touch-action: none;
  user-select: none;
}
.crop-stage:active { cursor: grabbing; }
.crop-stage::before {
  content: ''; position: absolute; inset: 0;
  box-shadow: 0 0 0 999px rgba(8,5,2,.62);
  border-radius: 50%;
  pointer-events: none; z-index: 2;
}
.crop-stage::after {
  content: ''; position: absolute; inset: 0;
  border: 1.5px dashed rgba(232,184,75,.7);
  border-radius: 50%;
  pointer-events: none; z-index: 3;
}
.zoom-row { display: flex; align-items: center; gap: 10px; margin: 14px 2px 2px; color: var(--smoke); font-size: 13px; }
.zoom-row input[type=range] { flex: 1; accent-color: var(--gold); }
.crop-hint { display: block; text-align: center; margin-top: 6px; }

/* Avatar at the top of the player profile modal (centered). */
.player-profile-avatar { display: flex; justify-content: center; margin-bottom: 14px; }

/* Face: warm skin tone, slight gradient */
.avatar-face {
  position: absolute;
  left: calc(var(--av-size) * .14);
  top: calc(var(--av-size) * .28);
  width: calc(var(--av-size) * .72);
  height: calc(var(--av-size) * .72);
  border-radius: 50%;
  background: linear-gradient(180deg, #c9a880 0%, #a08560 100%);
  border: 1px solid rgba(0,0,0,.5);
}

/* Hat: rectangular with brim (::before) */
.avatar-hat {
  position: absolute;
  left: calc(var(--av-size) * .04);
  top: 0;
  width: calc(var(--av-size) * .92);
  height: calc(var(--av-size) * .42);
  background: var(--hat-color);
  border: 1px solid rgba(0,0,0,.6);
  border-radius: 2px 2px 50% 50% / 2px 2px 30% 30%;
}
.avatar-hat::before {
  content: '';
  position: absolute;
  left: calc(var(--av-size) * .14);
  bottom: -1px;
  width: calc(var(--av-size) * .64);
  height: calc(var(--av-size) * .11);
  background: inherit;
  border-radius: 2px;
}

/* Hat variants: color */
.avatar-hat-cowboy   { --hat-color: #1f140a; }
.avatar-hat-sheriff  { --hat-color: linear-gradient(180deg, #c9a070, #8a6840); }
.avatar-hat-stranger { --hat-color: #3a2614; }

/* Eyes */
.avatar-eyes {
  position: absolute;
  left: calc(var(--av-size) * .32);
  top: calc(var(--av-size) * .54);
  width: calc(var(--av-size) * .36);
  height: calc(var(--av-size) * .07);
  display: flex;
  justify-content: space-between;
}
.avatar-eyes::before, .avatar-eyes::after {
  content: '';
  background: var(--ink);
  border-radius: 50%;
  width: calc(var(--av-size) * .07);
  height: calc(var(--av-size) * .07);
}
.avatar-eyes-slits::before, .avatar-eyes-slits::after {
  width: calc(var(--av-size) * .11);
  height: calc(var(--av-size) * .04);
  border-radius: 1px;
}

/* Mustache */
.avatar-mustache {
  position: absolute;
  background: var(--ink);
  border-radius: 50%;
}
.avatar-mustache-thick .avatar-mustache {
  left: calc(var(--av-size) * .28);
  top: calc(var(--av-size) * .74);
  width: calc(var(--av-size) * .44);
  height: calc(var(--av-size) * .11);
}
.avatar-mustache-thin .avatar-mustache {
  left: calc(var(--av-size) * .32);
  top: calc(var(--av-size) * .74);
  width: calc(var(--av-size) * .36);
  height: calc(var(--av-size) * .07);
  opacity: .85;
}

/* ─── Wanted poster: sidebar in western profile style ──────────────
   Applied via .stat-box.wanted-poster - score sidebar during Hangman/Tabu/
   Music quiz. Atmospheric swap of the plain box for a
   profile layout (parchment header, double divider, avatar per row). */
.wanted-poster {
  background:
    radial-gradient(ellipse at center top, rgba(201,180,138,.06) 0%, transparent 70%),
    rgba(74,47,20,.32);
  border: 1px solid rgba(201,180,138,.22);
  box-shadow: inset 0 0 0 1px rgba(0,0,0,.4);
  padding: 12px 12px 10px;
}
.wanted-poster .wanted-header {
  text-align: center;
  font-family: 'Rye', cursive;
  font-size: 13px;
  color: var(--old-paper);
  letter-spacing: .22em;
  padding-bottom: 4px;
  border-bottom: 2px double rgba(201,180,138,.3);
  margin-bottom: 4px;
}
.wanted-poster .wanted-sub {
  text-align: center;
  font-size: 12px;
  color: var(--smoke);
  letter-spacing: 1.5px;
  text-transform: uppercase;
  margin-bottom: 10px;
}
.wanted-poster .wanted-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 2px;
  border-bottom: 1px dotted rgba(201,180,138,.18);
}
.wanted-poster .wanted-row:last-child { border-bottom: none; }
.wanted-poster .wanted-row.answered {
  background: rgba(45,122,74,.06);
}
.wanted-poster .wanted-row.active {
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  border-bottom-color: var(--accent-light);
}
.wanted-poster .sidebar-player-name,
.wanted-poster .sidebar-player-name-me {
  flex: 1;
  font-size: 13px;
}
.wanted-poster .sidebar-player-status {
  font-family: 'Rye', cursive;
  color: var(--accent-ink);
  font-size: 14px;
}
@keyframes activePulse {
  0%, 100% { box-shadow: 0 0 0 rgba(0,0,0,0); border-color: rgba(200,146,42,.28); }
  50%      { box-shadow: 0 0 16px color-mix(in srgb, var(--accent-light) 35%, transparent);
             border-color: var(--accent-light); }
}

/* Wanted-row "answered" pulses once on status change */
.wanted-poster .wanted-row.answered {
  animation: answeredFlash 1.2s ease-out;
}
@keyframes answeredFlash {
  0%   { background: color-mix(in srgb, var(--accent) 25%, transparent); }
  100% { background: rgba(45,122,74,.06); }
}

/* Incoming clue: subtle fade-in + slide */
.turn-row.done .t-clue {
  animation: clueFadeIn .55s ease-out;
}
@keyframes clueFadeIn {
  0%   { opacity: 0; transform: translateX(-6px); }
  60%  { opacity: 1; transform: translateX(0); }
  100% { opacity: 1; transform: translateX(0); }
}

/* Screen transitions: smooth fade when switching between Playing/Break/Voting */
.screen-game,
.screen-break,
.screen-voting,
.screen-result {
  animation: screenFadeIn .35s ease-out;
}
@keyframes screenFadeIn {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Hero element (secret word/placeholder) glowing entrance */
.stage-corner {
  animation: cornerTwinkle 3.5s ease-in-out infinite;
}
.stage-corner-tr { animation-delay: .4s; }
.stage-corner-bl { animation-delay: .8s; }
.stage-corner-br { animation-delay: 1.2s; }
@keyframes cornerTwinkle {
  0%, 100% { opacity: .8; text-shadow: 0 0 0 transparent; }
  50%      { opacity: 1;
             text-shadow: 0 0 8px color-mix(in srgb, var(--accent-light) 70%, transparent); }
}
@keyframes votePopIn {
  0%   { transform: scale(1); }
  50%  { transform: scale(1.04); }
  100% { transform: scale(1); }
}

/* Reduced motion: respects the user preference for less animation */
@media (prefers-reduced-motion: reduce) {
  .turn-row.active,
  .turn-row.done .t-clue,
  .wanted-poster .wanted-row.answered,
  .screen-game, .screen-break, .screen-voting, .screen-result,
  .stage-corner, .vote-card.selected,
  .wq-card-enter, .wq-resolving, .mq-resolving, .wq-commentary, .wq-break-explanation,
  .mq-option.wq-reveal-correct, .wq-cat-curtain {
    animation: none;
  }
}
*,
*::before,
*::after { box-sizing: border-box; margin: 0; padding: 0; }
html,
body { height: 100%; }

/* Background is on html so body can remain transparent.
   This is necessary because .saloon-bg with z-index: -1 would disappear
   behind the body background if the body had its own background. */
html {
  /* Theme-aware page canvas: subtle vertical depth like the approved mockup.
     Sits on html (not body) so the fixed .saloon-bg (z-index:-1) stays visible. */
  background: radial-gradient(120% 90% at 50% -10%,
    var(--surface-0-a) 0%, var(--surface-0-b) 45%, var(--surface-0-c) 100%);
  background-color: var(--surface-0-c);
  /* The gradient tile is exactly one viewport high (html { height:100% }) — with
     the default repeat it restarts on longer pages as a hard bright band. The
     tile's bottom edge already reaches --surface-0-c, so no-repeat hands over
     seamlessly to the background-color below. */
  background-repeat: no-repeat;
}

body {
  color: var(--parchment);
  /* Inter as body font. 14px is optimal for Inter - previously 15px
     due to Special Elite, which appears visually larger; Inter does not need
     the compensation. Variable definition see :root above. */
  font-family: var(--font-body);
  font-size: 14px;
  line-height: 1.5;
  overflow-x: hidden;
}

/* Form controls inherit body font instead of browser default (otherwise
   platform-specific Arial/Helvetica/system-sans). Makes individual
   font-family declarations on .btn/.inp/etc. unnecessary. */
input, button, select, textarea {
  font-family: inherit;
}

/* <small> keeps its relative sizing but never drops below the app-wide
   12px text minimum (browser default 0.8333em on the 14px body = ~11.7px). */
small { font-size: max(12px, 0.8333em); }

/* Grain overlay */
body::before {
  content: '';
  position: fixed; inset: 0;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.07'/%3E%3C/svg%3E");
  pointer-events: none; z-index: 998; opacity: .35; mix-blend-mode: overlay;
}

/* ── Saloon background silhouette ──────────────────────────────────────────
   Shadowy saloon scene (bar counter, swing doors, hanging lamps, shelves with
   bottles). Fixed-positioned, behind all app content. Very low
   opacity so the text stays easily readable - the scene feels more like a
   memory or a shadow than a concrete image. */
.saloon-bg {
  position: fixed;
  inset: 0;
  background-image: url("/img/saloon-bg.svg");
  background-size: cover;
  background-position: center bottom;
  background-repeat: no-repeat;
  pointer-events: none;
  /* Negative z-index places the element behind the normal document flow.
     body has no background-color that could cover it (only the
     wood gradient from the html background), so the saloon remains visible. */
  z-index: -1;
  opacity: 0.22;
  /* Gentle fade toward the top so the background is not equally
     present everywhere but atmospherically "clings" toward the bottom. */
  mask-image: linear-gradient(to bottom, transparent 0%, black 35%, black 100%);
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, black 35%, black 100%);
}
/* Light theme: keep the silhouette as a faint sepia print instead of a glow. */
[data-theme="light"] .saloon-bg { opacity: 0.10; mix-blend-mode: multiply; }
[data-theme="light"] .bg-saloon {
  background: radial-gradient(ellipse 90% 55% at 50% 100%, rgba(156, 106, 26, .12) 0%, transparent 65%);
}
/* §8 Teil 2 (dunkler Seiten-Canvas hinter Spiel-Screens) — ABGEBAUT
   (SS-0312 Etappe 2): Spiel-Seiten laufen im Light Theme jetzt auf demselben
   hellen Canvas wie alle anderen Seiten. */

/* ── Screens ── */
.screen-lobby,
.screen-game,
.screen-break,
.screen-voting,
.screen-result {
  flex: 1 0 auto; /* fill the available space in app-main */
  padding: 40px 20px 48px;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  position: relative;
}

.btn-copy {
    font-size: 13px;
    color: var(--gold);
    background: transparent;
    border: 1px solid rgba(200,146,42,.4);
    padding: 6px 14px;
    border-radius: 1px;
    cursor: pointer;
    transition: all .2s;
}

.btn-copy:hover {
    border-color: var(--gold);
    background: rgba(200,146,42,.08);
}

.btn-copy.copied {
    color: var(--green-ok);
    border-color: rgba(45,122,74,.5);
}

.bg-saloon {
  /* Only a gentle glow at the bottom - NO linear-gradient, so the global
     saloon silhouette from .saloon-bg shows through. Used on screens like
     Home, Admin, Game-Break, Lobby-Break - wherever the atmosphere
     should remain visible. When a screen wants to recolor the mood
     (Impostor mode etc.) it uses bg-red/bg-amber/bg-green - those
     still set a full background. */
  background:
    radial-gradient(ellipse 90% 55% at 50% 100%, rgba(74,47,20,.35) 0%, transparent 65%);
}
.bg-red {
  background:
    radial-gradient(ellipse 80% 45% at 50% 55%, rgba(100,14,14,.18) 0%, transparent 70%),
    linear-gradient(to bottom, #060302, #0e0705);
}
.bg-green {
  background:
    radial-gradient(ellipse 80% 45% at 50% 100%, rgba(26,61,43,.28) 0%, transparent 60%),
    linear-gradient(to bottom, #0a0806, #111a0f);
}
.bg-amber {
  background:
    radial-gradient(ellipse 80% 45% at 50% 55%, rgba(100,60,5,.2) 0%, transparent 70%),
    linear-gradient(to bottom, #060402, #0e0905);
}

/* ── Typography ── */
.rye { font-family: 'Rye', cursive; }
.pf { font-family: 'Playfair Display', serif; }
.gold { color: var(--gold-ink); }

.eyebrow {
  font-size: 14px; letter-spacing: .3em; text-transform: uppercase;
  color: var(--smoke); text-align: center; margin-bottom: 14px;
}
.section-label {
  font-size: 14px; letter-spacing: .18em; text-transform: uppercase;
  color: var(--smoke); margin-bottom: 10px;
}
.inline-note {
  font-size: 14px; color: var(--smoke); text-align: center;
  margin-top: 8px; letter-spacing: .08em;
}

/* ── Cards ── */
.card {
  background: linear-gradient(135deg, var(--card-grad-a), var(--card-grad-b));
  border: 1px solid var(--border-soft); border-radius: 2px;
  padding: 24px 28px; position: relative;
  box-shadow: 0 18px 55px var(--shadow-color), inset 0 1px 0 rgba(200,146,42,.09);
}
.card::before,
.card::after {
  content: '✦'; position: absolute; top: 13px;
  color: rgba(200,146,42,.25); font-size: 12px;
}
.card::before { left: 18px; }
.card::after { right: 18px; }

.card-red { border-color: rgba(139,26,26,.35); box-shadow: 0 18px 55px rgba(0,0,0,.65), 0 0 40px rgba(100,14,14,.08); }
.card-red::before,
.card-red::after { color: rgba(139,26,26,.35); }

.card-title {
  font-family: 'Rye', cursive; font-size: 17px; color: var(--heading);
  text-align: center; margin-bottom: 20px; letter-spacing: .09em;
}

/* ── Forms ── */
.lbl {
  font-size: 14px; letter-spacing: .16em; text-transform: uppercase;
  color: var(--smoke); display: block; margin-bottom: 7px;
}
.inp {
  width: 100%; background: var(--input-bg);
  border: 1px solid var(--border-soft); border-radius: 1px;
  color: var(--text-main);
  font-size: 15px; padding: 11px 13px; outline: none; transition: border-color .2s;
}
.inp:focus { border-color: var(--gold); box-shadow: 0 0 14px rgba(200,146,42,.14); }
.inp::placeholder { color: color-mix(in srgb, var(--text-dim) 55%, transparent); }
.inp-lg { font-family: 'Playfair Display', serif; font-size: 22px; font-style: italic; padding: 13px 15px; }
.inp-red { border-color: rgba(139,26,26,.4) !important; }
.fgrp { margin-bottom: 16px; }
select.inp {
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='11' height='7'%3E%3Cpath d='M1 1l4.5 4.5L10 1' stroke='%23c8922a' stroke-width='1.5' fill='none'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 11px center; padding-right: 30px;
}
textarea.inp { resize: vertical; min-height: 100px; font-size: 14px; line-height: 1.6; }

.char-count {
  position: absolute; bottom: 10px; right: 12px;
  font-size: 12px; color: var(--smoke); pointer-events: none;
}
.char-count.warn { color: var(--accent-amber); }
.char-count.over { color: var(--blood-red); }

/* ── Slider ── */

.slider {
  -webkit-appearance: none; appearance: none; width: 100%; height: 4px;
  border-radius: 2px;
  background: linear-gradient(to right,
    var(--gold) 0%,
    var(--gold) var(--val, 50%),
    rgba(200,146,42,.15) var(--val, 50%),
    rgba(200,146,42,.15) 100%);
  outline: none; cursor: pointer;
}
.slider::-webkit-slider-thumb {
  -webkit-appearance: none; width: 18px; height: 18px; border-radius: 50%;
  background: var(--gold-light); border: 2px solid var(--amber);
  box-shadow: 0 0 10px rgba(200,146,42,.4); cursor: pointer;
}
.slider::-moz-range-thumb {
  width: 18px; height: 18px; border-radius: 50%;
  background: var(--gold-light); border: 2px solid var(--amber);
  box-shadow: 0 0 10px rgba(200,146,42,.4); cursor: pointer;
}

/* ── Buttons ── */
.btn {
  display: block; width: 100%; padding: 12px; border-radius: 1px;
  font-family: 'Rye', cursive; font-size: 15px; letter-spacing: .12em;
  text-transform: uppercase; cursor: pointer; transition: all .2s;
  border: none; position: relative; overflow: hidden;
  text-decoration: none;
}
a.btn { text-align: center; }
.btn::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent 30%, rgba(255,255,255,.09) 50%, transparent 70%);
  transform: translateX(-100%); transition: transform .45s;
  pointer-events: none;  /* decorative shimmer must not intercept clicks */
}
@media (hover: hover) {
  .btn:hover::after {
    transform: translateX(100%);
  }
}
.btn:disabled { opacity: .35; cursor: not-allowed; transform: none !important; }

.btn-gold { background: linear-gradient(135deg, var(--amber), var(--gold)); color: var(--shadow); box-shadow: 0 4px 22px rgba(212,98,10,.38); }
@media (hover: hover) {
  .btn-gold:not(:disabled):hover {
    transform: translateY(-1px);
    box-shadow: 0 7px 30px rgba(212,98,10,.55);
  }
}

/* Amber variant for "cautious action" (activate maintenance, destructive confirms). */
/* Gradient end darkened (75% amber): plain --amber pushed white text to 3.8:1. */
.btn-amber { background: linear-gradient(135deg, var(--blood-red), color-mix(in srgb, var(--amber) 75%, #000)); color: #fff; font-weight: bold; box-shadow: 0 4px 22px rgba(139,26,26,.32); }
@media (hover: hover) {
  .btn-amber:not(:disabled):hover {
    transform: translateY(-1px);
    filter: brightness(1.08);
  }
}
.btn-amber:disabled { opacity: .55; cursor: not-allowed; }
/* Merged single definition (was duplicated; cascade computed state preserved:
   later definition won background/color, box-shadow comes from the earlier one). */
.btn-red { background: linear-gradient(135deg, #8b1a1a, #5a0e0e); color: #fff; box-shadow: 0 4px 22px rgba(139,26,26,.38); border: 1px solid rgba(220,100,100,.5); padding: 10px 18px; border-radius: 3px; cursor: pointer; font-family: 'Rye', cursive; letter-spacing: .05em; transition: all .15s; }
@media (hover: hover) {
  .btn-red:not(:disabled):hover {
    transform: translateY(-1px);
  }
}
.btn-green { background: linear-gradient(135deg, var(--green-felt), var(--green-ok)); color: var(--parchment); }
@media (hover: hover) {
  .btn-green:not(:disabled):hover {
    transform: translateY(-1px);
  }
}
.btn-ghost { background: transparent; border: 1px solid rgba(200,146,42,.32); color: var(--old-paper); font-size: 15px; letter-spacing: .08em; }
.btn-ghost:hover { border-color: var(--gold); color: var(--heading); background: var(--surface-hover); }
/* Merged single definition (was duplicated; cascade computed state preserved:
   later definition won background/color/box metrics, font-size comes from the earlier one). */
.btn-ghost-red { background: rgba(139,26,26,.08); border: 1px solid rgba(139,26,26,.4); color: var(--danger); font-size: 15px; padding: 10px 18px; border-radius: 3px; cursor: pointer; transition: all .15s; }
.btn-ghost-red:hover { background: rgba(139,26,26,.18); border-color: rgba(220,100,100,.6); color: var(--red-light); }
.abort-btn {
  display: flex; align-items: center; justify-content: center; gap: 6px;
  width: 100%; padding: 9px; background: transparent;
  border: 1px solid rgba(139,26,26,.3); border-radius: 1px;
  color: rgba(192,53,42,.55);
  font-size: 15px; letter-spacing: .06em; cursor: pointer; transition: all .25s;
}
.abort-btn:hover { border-color: var(--blood-red); color: var(--red-light); background: rgba(139,26,26,.07); }

/* ── Dividers ── */
.div-line { display: flex; align-items: center; gap: 10px; margin: 16px 0; }
.div-line::before,
.div-line::after { content: ''; flex: 1; height: 1px; background: rgba(200,146,42,.18); }
.div-line span { font-size: 12px; letter-spacing: .22em; color: var(--smoke); }
.h-line { height: 1px; background: linear-gradient(to right, transparent, rgba(200,146,42,.35), transparent); margin: 10px 0 18px; }

/* ── Badges ── */
.badge { display: inline-block; padding: 2px 10px; border: 1px solid var(--border-soft); font-size: 12px; letter-spacing: .18em; text-transform: uppercase; color: var(--heading); }

/* ── Lobby code ── */
.lobby-code { font-family: 'Rye', cursive; font-size: 28px; letter-spacing: .35em; color: var(--gold-light); display: inline-block; background: rgba(8,5,2,.9); border: 1px solid var(--gold); padding: 8px 24px; box-shadow: 0 0 26px rgba(200,146,42,.18); }
.code-hint { font-size: 13px; letter-spacing: .2em; color: var(--smoke); text-transform: uppercase; display: block; margin-top: 5px; }

/* ── Streamer mode toggle (eye icon next to lobby code) ─────────────────────────
   Small, subtle, sits directly to the right of the code. When active (code is
   masked), the button gets a gold-filled background + the
   eye-strike effect indicates "hidden". */
.streamer-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  margin-left: 6px;
  padding: 0;
  background: transparent;
  border: 1px solid rgba(200,146,42,.35);
  border-radius: 50%;
  color: var(--gold);
  font-size: 14px;
  cursor: pointer;
  vertical-align: middle;
  transition: background .15s, border-color .15s;
  position: relative;
}
.streamer-toggle:hover {
  background: rgba(200,146,42,.12);
  border-color: var(--gold);
}
.streamer-toggle.is-on {
  background: rgba(200,146,42,.18);
  border-color: var(--gold);
}
/* Diagonal strike through the eye when active (code hidden).
   Pseudo-element so the emoji itself does not need to be changed. */
.streamer-toggle.is-on::after {
  content: "";
  position: absolute;
  inset: 4px;
  border-top: 2px solid var(--gold);
  transform: rotate(-45deg);
  transform-origin: center;
  pointer-events: none;
}

.btn-eye.visible {
    border-color: rgba(200,146,42,.5);
}

/* ── Player slots ── */

.player-slot.filled { border-color: color-mix(in srgb, var(--border-strong) 71%, transparent); }
.player-slot.empty { opacity: .35; }
.player-slot.disconnected { opacity: .45; border-color: rgba(139,26,26,.25); background: rgba(30,5,5,.4); }

/* (Removed) Here was a second, unused `.avatar` rule
   (32px letter avatar from the dead "Player slots"). It collided with
   the procedural avatar (above) and forced its box to 32px while
   child elements scaled via --av-size - overflow (huge head at Xxl size).
   No `class="avatar"` letter markup in use anymore - removed instead of renamed. */

.p-name { font-size: 17px; color: var(--parchment); }

/* ── Player progress bar ── */
.player-progress { width: 100%; margin: 10px 0 14px; }
.pp-bar { width: 100%; height: 5px; background: var(--surface-2); border-radius: 2px; overflow: hidden; }
.pp-fill { height: 100%; border-radius: 2px; transition: width .4s; }
.pp-fill.ok { background: linear-gradient(to right, var(--green-felt), var(--green-ok)); }
.pp-fill.warn { background: linear-gradient(to right, var(--blood-red), var(--amber)); }
.pp-labels { display: flex; justify-content: space-between; margin-top: 5px; font-size: 14px; color: var(--smoke); }
.t-num { width: 22px; height: 22px; border-radius: 50%; border: 1px solid color-mix(in srgb, var(--border-strong) 62%, transparent); display: flex; align-items: center; justify-content: center; font-size: 12px; color: var(--smoke); flex-shrink: 0; }
.turn-row.active .t-num { border-color: var(--accent); color: var(--accent-ink); }
.turn-row.done .t-num { border-color: color-mix(in srgb, var(--accent-light) 50%, transparent); color: var(--accent-ink); }
.t-name { font-size: 16px; color: var(--old-paper); flex: 1; }
.t-clue { font-size: 15px; color: var(--smoke); font-style: italic; }
/* Clue text as the central Schattenspiel evidence: parchment cream (high
   contrast on dark bg), size +1px above default, semi-bold. No
   italics - italics signal "transient" like "typing...", which does not fit
   for entered clues. */
.turn-row.done .t-clue {
  color: var(--parchment);
  font-style: normal;
  font-weight: 600;
  font-size: 16px;
}
.t-clue.clue-chip-row { justify-content: flex-end; font-style: normal; }
.vpip { width: 9px; height: 9px; border-radius: 50%; background: color-mix(in srgb, var(--border-strong) 40%, transparent); border: 1px solid color-mix(in srgb, var(--border-strong) 62%, transparent); transition: all .3s; }
.vpip.done { background: var(--accent-ink); box-shadow: 0 0 7px var(--accent); }

/* ── Result ── */
.r-title { font-family: 'Rye', cursive; font-size: clamp(24px, 5vw, 40px); text-align: center; margin-bottom: 6px; }
.r-gold { color: var(--gold-ink); text-shadow: 0 0 38px rgba(200,146,42,.45); }
.r-red { color: var(--blood-red); text-shadow: 0 0 38px rgba(139,26,26,.45); }
.r-amber { color: var(--accent-amber); text-shadow: 0 0 38px rgba(212,98,10,.45); }
.reveal-box { background: var(--surface-1-strong); border: 1px solid color-mix(in srgb, var(--border-strong) 62%, transparent); padding: 16px 24px; width: 100%; text-align: center; border-radius: 2px; }
.reveal-box.red { border-color: rgba(139,26,26,.35); }
.rl { font-size: 12px; letter-spacing: .28em; text-transform: uppercase; color: var(--smoke); margin-bottom: 7px; }
.rv { font-family: 'Rye', cursive; font-size: 24px; color: var(--heading); }
.rv.red { color: var(--blood-red); }
.rsub { font-size: 15px; color: var(--smoke); margin-top: 4px; }

.sb-rank.first { color: var(--heading); }

/* ── Toasts / Alerts ── */
.toast { padding: 10px 14px; border-radius: 1px; font-size: 15px; border-left: 3px solid; display: flex; align-items: center; gap: 8px; margin-bottom: 8px; animation: toastIn .32s ease both; }
@keyframes toastIn { from { opacity: 0; transform: translateX(40px); } to { opacity: 1; transform: none; } }
.toast-info { background: color-mix(in srgb, var(--success) 12%, var(--surface-1-strong)); border-color: var(--success); color: var(--success); }

.toast-abort { background: color-mix(in srgb, var(--danger-strong) 14%, var(--surface-1-strong)); border-color: var(--danger-strong); color: var(--danger); }
[data-theme="light"] .toast-abort { color: var(--danger-strong); }   /* wie .alert-error: --danger faellt auf dem Rosa-Wash unter 4.5 */

/* Achievement unlock toast (finished screen) */
.toast-achievement { background: color-mix(in srgb, var(--gold) 14%, var(--surface-1-strong)); border-color: var(--gold); color: var(--heading); }

.notifications-overlay { position: fixed; top: 16px; right: 16px; z-index: 999; display: flex; flex-direction: column; gap: 8px; max-width: 320px; }
.alert-error { background: color-mix(in srgb, var(--danger-strong) 16%, var(--surface-1)); border: 1px solid color-mix(in srgb, var(--danger-strong) 45%, transparent); border-left: 3px solid var(--danger-strong); color: var(--danger); padding: 9px 12px; border-radius: 1px; font-size: 15px; margin-bottom: 10px; }
/* Light: --danger on the pink-tinted alert bg lands at ~2.5:1 — take the strong tone for text. */
[data-theme="light"] .alert-error { color: var(--danger-strong); }
/* .alert-success duplicate entry removed - was completely overridden by the later
   definition (profile section) including border-left via border shorthand. */

/* OAuth-only note in the delete modal (no password - type-to-confirm instead of re-auth). */
.oauth-delete-note { display: flex; gap: 8px; align-items: flex-start; background: rgba(70,110,160,.1); border: 1px solid rgba(120,150,200,.3); border-radius: 4px; padding: 10px 12px; margin-bottom: 14px; font-size: 12.5px; color: #bcc8e0; line-height: 1.45; }

/* ── Banners ── */
.waiting-banner { font-size: 16px; letter-spacing: .07em; color: var(--smoke); text-align: center; padding: 12px; border: 1px dashed var(--border-soft); border-radius: 1px; margin-bottom: 14px; animation: waitBlink 2s ease-in-out infinite; }
@keyframes waitBlink { 0%,100% { opacity: .5; } 50% { opacity: 1; } }

/* ── Dots ── */
.dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.dot-idle { background: var(--smoke); }
.dot-active { background: var(--gold-ink); box-shadow: 0 0 8px rgba(200,146,42,.6); animation: dotPulse 1.4s ease-in-out infinite; }
.dot-done { background: var(--green-ok); }

.dot-reconnect { background: var(--amber); animation: dotPulse 1s ease-in-out infinite; }
@keyframes dotPulse { 0%,80%,100% { transform: scale(1); opacity: .5; } 40% { transform: scale(1.4); opacity: 1; } }

/* ── Reconnect indicator (top header area) ───────────────────
   Custom #components-reconnect-modal instead of the blocking default modal.
   Online = invisible (user choice: only shown on problems). Blazor switches the
   -show/-failed/-rejected classes; the appearance comes from here. */
#components-reconnect-modal.conn-indicator {
  /* Centered at top IN the sticky header bar (~50px high). top:10px
     centers the 30px pill vertically in the bar; z-index 1200 > header (900),
     so it sits above the (center-clear) header middle. The header actions
     (streamer/volume/profile) are on the right and remain untouched. */
  position: fixed; top: 10px; left: 50%; transform: translateX(-50%); z-index: 1200;
  display: none;                       /* default + components-reconnect-hide: nichts */
  align-items: center; gap: 8px;
  height: 30px; padding: 0 8px 0 11px;
  border-radius: 16px; font-size: 12px; letter-spacing: .02em;
  background: var(--surface-1-strong);
  border: 1px solid color-mix(in srgb, var(--border-strong) 67%, transparent);
  box-shadow: 0 4px 16px rgba(0,0,0,.45);
}
#components-reconnect-modal .conn-dot { width: 12px; height: 12px; border-radius: 50%; flex-shrink: 0; }
#components-reconnect-modal .conn-label { white-space: nowrap; }
#components-reconnect-modal .conn-label-reconnect,
#components-reconnect-modal .conn-label-lost { display: none; }
#components-reconnect-modal .conn-reload {
  display: none; margin-left: 2px; font-size: 12px; padding: 3px 9px;
  border-radius: 12px; border: 1px solid rgba(200,146,42,.4);
  background: rgba(200,146,42,.16); color: var(--gold-light);
  cursor: pointer; white-space: nowrap; font-family: inherit;
}
#components-reconnect-modal .conn-reload:hover { background: rgba(200,146,42,.28); }

/* Reconnecting (blip) - dot becomes a spinning amber ring, non-blocking */
#components-reconnect-modal.components-reconnect-show { display: inline-flex; }
#components-reconnect-modal.components-reconnect-show .conn-dot {
  background: transparent;
  border: 2px solid rgba(212,98,10,.35); border-top-color: var(--amber);
  animation: spin .7s linear infinite;
}
#components-reconnect-modal.components-reconnect-show .conn-label-reconnect { display: inline; color: var(--amber); }
/* Shared 360-degree rotation (was connspin = mqSpin, exact duplicate). */
@keyframes spin { to { transform: rotate(360deg); } }

/* Loading band for the create-lobby filter data — shown only on a cold cache; the
   matchmaking-dialog prefetch usually warms the bundle before the dialog opens. */
.settings-loading {
  display: flex; align-items: center; gap: 10px; padding: 11px 13px; margin: 8px 0 4px;
  background: rgba(200,146,42,.08); border: 1px solid rgba(200,146,42,.28);
  border-radius: 6px; color: var(--text-dim); font-size: 13px;
}
.settings-loading::before {
  content: ""; flex: none; width: 15px; height: 15px; border-radius: 50%;
  border: 2px solid var(--border-soft); border-top-color: var(--accent);
  animation: spin .7s linear infinite;
}

/* Connection lost / reload required (failed = server gone, rejected = circuit gone) */
#components-reconnect-modal.components-reconnect-failed,
#components-reconnect-modal.components-reconnect-rejected { display: inline-flex; }
#components-reconnect-modal.components-reconnect-failed .conn-dot,
#components-reconnect-modal.components-reconnect-rejected .conn-dot {
  background: var(--red-light); box-shadow: 0 0 7px rgba(192,53,42,.6);
}
#components-reconnect-modal.components-reconnect-failed .conn-label-lost,
#components-reconnect-modal.components-reconnect-rejected .conn-label-lost { display: inline; color: #e8a59b; }
#components-reconnect-modal.components-reconnect-failed .conn-reload,
#components-reconnect-modal.components-reconnect-rejected .conn-reload { display: inline-block; }
.f-hat-crown { position: absolute; top: -14px; left: 50%; transform: translateX(-50%); width: 36px; height: 28px; background: #050202; border-radius: 3px 3px 0 0; }
.f-hat-brim { position: absolute; top: 12px; left: 50%; transform: translateX(-50%); width: 62px; height: 9px; background: #050202; border-radius: 2px; }
.f-head { position: absolute; top: 19px; left: 50%; transform: translateX(-50%); width: 38px; height: 38px; border-radius: 50%; background: #060302; }
.f-head::before,
.f-head::after { content: ''; position: absolute; width: 6px; height: 6px; border-radius: 50%; background: var(--blood-red); top: 36%; box-shadow: 0 0 10px var(--blood-red), 0 0 22px rgba(139,26,26,.7); animation: eyeGlow 2.4s ease-in-out infinite; }
.f-head::before { left: 22%; }
.f-head::after { right: 22%; }
@keyframes eyeGlow { 0%,100% { opacity: 1; } 50% { opacity: .3; } }
.f-body { position: absolute; bottom: 28px; left: 50%; transform: translateX(-50%); width: 52px; height: 86px; background: #060302; border-radius: 26px 26px 8px 8px; }
.f-arm-l { position: absolute; width: 13px; height: 55px; background: #060302; border-radius: 7px; bottom: 36px; left: 13px; transform: rotate(14deg); }
.f-arm-r { position: absolute; width: 13px; height: 55px; background: #060302; border-radius: 7px; bottom: 36px; right: 13px; transform: rotate(-14deg); }
.f-glow { position: absolute; bottom: -10px; left: 50%; transform: translateX(-50%); width: 68px; height: 16px; border-radius: 50%; background: radial-gradient(ellipse, rgba(139,26,26,.35) 0%, transparent 70%); }
@keyframes figPulse { 0%,100% { filter: drop-shadow(0 0 8px rgba(139,26,26,.3)); } 50% { filter: drop-shadow(0 0 22px rgba(139,26,26,.6)); } }

/* ── Crewmate figure: sheriff in cowboy outfit, counterpart to the impostor ──
   Same layout format as .impostor-figure (110x170), but lighter colored,
   with a sheriff star on the chest and gold glow instead of blood-red glow.
   Animation `fig-crew-pulse` analogous to `fig-pulse`. */
.crewmate-figure { position: relative; width: 110px; height: 170px; margin: 0 auto; }

/* Hat: warm brown cowboy hat */
.c-hat-crown {
  position: absolute; top: -14px; left: 50%; transform: translateX(-50%);
  width: 38px; height: 26px;
  background: linear-gradient(180deg, #6a4828 0%, #4a3018 100%);
  border: 1px solid #2a1d0e;
  border-radius: 6px 6px 3px 3px;
}
.c-hat-brim {
  position: absolute; top: 11px; left: 50%; transform: translateX(-50%);
  width: 66px; height: 10px;
  background: linear-gradient(180deg, #5a3f1a 0%, #3a2614 100%);
  border: 1px solid #2a1d0e;
  border-radius: 3px;
}
/* Hat band (small bright line below the crown) */
.c-hat-crown::after {
  content: '';
  position: absolute; bottom: -1px; left: 4px; right: 4px;
  height: 3px;
  background: var(--gold);
  opacity: .7;
}

/* Head: warm skin tone (analogous to the avatar) */
.c-head {
  position: absolute; top: 18px; left: 50%; transform: translateX(-50%);
  width: 38px; height: 38px;
  border-radius: 50%;
  background: linear-gradient(180deg, #c9a880 0%, #a08560 100%);
  border: 1px solid #6a4828;
}
.c-head::before,
.c-head::after {
  content: '';
  position: absolute;
  width: 4px; height: 4px;
  border-radius: 50%;
  background: var(--ink);
  top: 42%;
}
.c-head::before { left: 26%; }
.c-head::after  { right: 26%; }

/* Classic western mustache */
.c-mustache {
  position: absolute; top: 46px; left: 50%; transform: translateX(-50%);
  width: 22px; height: 4px;
  background: var(--ink);
  border-radius: 50%;
  z-index: 1;
}

/* Body: vest, slightly lighter than the impostor */
.c-body {
  position: absolute; bottom: 28px; left: 50%; transform: translateX(-50%);
  width: 54px; height: 88px;
  background: linear-gradient(180deg, #5a3f1a 0%, #3a2614 100%);
  border: 1px solid #2a1d0e;
  border-radius: 22px 22px 6px 6px;
}

/* Sheriff star on the chest - the central accent */
.c-star {
  position: absolute; bottom: 64px; left: 50%; transform: translateX(-50%);
  font-size: 22px;
  color: var(--gold-light);
  text-shadow:
    0 0 8px var(--gold-light),
    0 0 16px var(--gold);
  line-height: 1;
  z-index: 2;
  user-select: none;
}

/* Arms */
.c-arm-l, .c-arm-r {
  position: absolute;
  width: 13px; height: 55px;
  background: linear-gradient(180deg, #5a3f1a 0%, #3a2614 100%);
  border: 1px solid #2a1d0e;
  border-radius: 7px;
  bottom: 36px;
}
.c-arm-l { left: 11px;  transform: rotate(8deg); }
.c-arm-r { right: 11px; transform: rotate(-8deg); }

/* Ground glow - gold instead of blood red */
.c-glow {
  position: absolute; bottom: -10px; left: 50%; transform: translateX(-50%);
  width: 72px; height: 16px;
  border-radius: 50%;
  background: radial-gradient(ellipse, rgba(232,184,75,.4) 0%, transparent 70%);
}
@keyframes figCrewPulse {
  0%, 100% { filter: drop-shadow(0 0 6px rgba(200,146,42,.25)); }
  50%      { filter: drop-shadow(0 0 18px rgba(232,184,75,.5)); }
}   /* Plakette deckt die Kartenkante — im Light heller Grund */

/* ── Layouts ── */
.lobby-header {
  text-align: center;
  margin-bottom: 14px;
  width: 100%;
  max-width: 1000px;
}
.lobby-header-card {
  padding: 14px 22px;
  background: rgba(8,5,2,.55);
  border: 1px solid rgba(200,146,42,.18);
  border-radius: 4px;
}
.lobby-header-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  margin-top: 10px;
  flex-wrap: wrap;
}
/* In the header row .code-hint has more space left/right and
   loses block display so it sits inline next to the code and button. */
.lobby-header-row .code-hint {
  display: inline;
  margin-top: 0;
  max-width: 260px;
  text-align: left;
}
/* Lobby layout: vertically stacked.
   Top (full width): player chips bar
   Below: lobby-main-row with chat large on the left + narrow sidebar on the right */
.lobby-layout { display: flex; flex-direction: column; gap: 16px;
                    width: 100%; max-width: 1000px; }

/* Main area below the player chips: chat large on the left, narrow sidebar on the right.
   DOM order is 'chat-col to sidebar-col', so each gets its column
   automatically via grid - no explicit grid-column needed. */
.lobby-main-row {
  display: grid;
  grid-template-columns: 1fr 270px;
  gap: 16px;
  align-items: start;
}
.lobby-chat-col {
  display: flex;
  flex-direction: column;
  gap: 12px;
  min-width: 0; /* allows the column to shrink, otherwise chat content pushes the grid */
}
.lobby-sidebar-col {
  display: flex;
  flex-direction: column;
  gap: 13px;
}

/* Kept for any places that still reference .lobby-sidebar
   (e.g. the old responsive rule). No longer actively used. */
.lobby-sidebar { display: flex; flex-direction: column; gap: 13px; }
.lobby-players-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; }

.game-layout { display: grid; grid-template-columns: 1fr 240px; gap: 20px; width: 100%; max-width: 820px; align-items: start; }
.game-sidebar { display: flex; flex-direction: column; gap: 12px; }

/* ── Loading & misc ── */
.loading-screen { flex: 1 0 auto; display: flex; align-items: center; justify-content: center; }
.not-found { text-align: center; padding: 60px 20px; }
.not-found h2 { font-size: 28px; color: var(--gold); margin-bottom: 16px; }
.not-found a { color: var(--old-paper); text-decoration: underline; }

/* ── Responsive ── */
@media (max-width: 700px) {
  .lobby-main-row,
.game-layout { grid-template-columns: 1fr; }
  .lobby-sidebar,
.game-sidebar { display: contents; }
}

/* ── Lobby Page ─────────────────────────────────────────────────────────── */
.lobby-loading-text { font-size: 22px; }
.lobby-title { font-family: 'Rye', cursive; font-size: 22px; color: var(--accent); }

.card-players { padding: 20px 22px; }
.card-sidebar { padding: 16px 18px; }

.lobby-section-title { font-family: 'Rye', cursive; font-size: 15px; color: color-mix(in srgb, var(--accent) 30%, var(--text-main)); }
.lobby-player-count { font-size: 15px; color: var(--smoke); }
.card-title-sm { font-family: 'Rye', cursive; font-size: 15px; color: var(--accent-light);
                        letter-spacing: .09em; margin-bottom: 10px; }

.text-danger { color: var(--danger); }
.text-success { color: var(--success); }   /* theme-aware + island re-pin; --green-ok was ~3.6:1 on the dark lobby island */

.settings-info { font-size: 15px; color: var(--smoke); line-height: 2.2; }
.settings-row { display: flex; justify-content: space-between; gap: 12px; align-items: baseline; }
.settings-value { color: var(--accent-ink); text-align: right;
                        min-width: 0; overflow-wrap: anywhere; }
.settings-fixed-note { font-size: 14px; color: rgba(168, 151, 132,.5);
                        margin-top: 8px; font-style: italic; }
.btn-edit { margin-top: 10px; padding: 7px; font-size: 14px; width: 100%; }

/* ── Player chips (lobby) ───────────────────────────────────────────────── */
/* Player overview at the top as a compact chip row instead of a large slot list.
   Avatar + name + badges (host star, admin crown, mod sword, guest diamond,
   own "you" marker). Click opens the profile modal. */
.player-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.player-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: rgba(8,5,2,.5);
  border: 1px solid rgba(200,146,42,.18);
  color: var(--parchment);
  padding: 5px 12px 5px 5px;
  border-radius: 22px;
  font-size: 13px;
  cursor: pointer;
  transition: border-color .15s, background .15s, transform .12s;
}
.player-chip:hover {
  border-color: var(--gold);
  background: rgba(8,5,2,.7);
}
.player-chip:active {
  transform: scale(.98);
}
.player-chip.is-host {
  border-color: rgba(200,146,42,.55);
  background: rgba(200,146,42,.08);
}
.player-chip.is-me {
  outline: 1px solid var(--gold-light);
  outline-offset: -1px;
}
.player-chip.is-guest .player-chip-name {
  color: var(--smoke);
  font-style: italic;
}
.player-chip-avatar {
  display: inline-flex;
  flex-shrink: 0;
}
/* The avatar component now provides the round portrait/photo (instead of
   a name initial); the container is just a flex slot now. */
.player-chip-avatar .avatar { --av-size: 26px; }
.player-chip-name {
  font-size: 13px;
  max-width: 140px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.player-chip-badge {
  font-size: 14px;
  line-height: 1;
  margin-left: -2px;
}
/* Verified profile - blue checkmark (Twitter style), next to the name. */
.verified-check {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: #1d9bf0;
  color: #fff;
  font-weight: bold;
  line-height: 1;
  flex-shrink: 0;
  vertical-align: middle;
  box-shadow: 0 0 0 1px rgba(0,0,0,.25);
}
.verified-check.vc-sm { width: 15px; height: 15px; font-size: 9px; }
.verified-check.vc-md { width: 17px; height: 17px; font-size: 10px; }
.verified-check.vc-lg { width: 21px; height: 21px; font-size: 12px; }
.player-chip-you {
  background: rgba(45,122,74,.2);
  color: var(--green-ok);
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: .1em;
  padding: 1px 6px;
  border-radius: 10px;
  margin-left: 2px;
}
.player-chip-empty {
  display: inline-flex;
  align-items: center;
  padding: 5px 14px;
  border: 1px dashed rgba(168, 151, 132,.3);
  color: var(--smoke);
  font-size: 12px;
  border-radius: 22px;
  font-style: italic;
}

/* Away player - chip grayed out, strikethrough background,
   but remains clickable (profile modal can still be opened). */
.player-chip.is-away {
  opacity: 0.5;
  filter: grayscale(0.6);
}
.player-chip.is-away .player-chip-name {
  text-decoration: line-through;
  text-decoration-color: rgba(168, 151, 132,.4);
  text-decoration-thickness: 1px;
}

/* ── Home Page ───────────────────────────────────────────────────────────── */
.card-home { width: 100%; max-width: 440px; }
.inp-code { letter-spacing: .2em; text-transform: uppercase; }
/* SS-0312: the secret-word glow is a dark-canvas effect — light gets crisp ink
   without the halo (see the light-overrides section at the end of the file). */
.card-turn-list { padding: 18px 20px; margin-bottom: 12px; }
.text-amber { color: var(--accent-amber); }
.text-smoke { color: var(--smoke); }
.text-gold { color: var(--gold-ink); }
.text-gold-light { color: var(--heading); }
.text-blood-red { color: var(--blood-red); }

.typing-anim { animation: waitBlink 1s ease-in-out infinite; }
.card-clue-input { padding: 22px 24px; border-color: var(--border-strong); }
.round-label { font-size: 15px; color: var(--smoke); margin-bottom: 2px; }
.round-number { font-family: 'Rye', cursive; font-size: 30px; color: var(--heading); }
.round-total { font-size: 16px; color: var(--smoke); }

/* ── Game Page – Break ───────────────────────────────────────────────────── */
.screen-break-center { text-align: center; }
.showdown-title { font-family: 'Rye', cursive; font-size: 30px; color: var(--blood-red);
                        text-shadow: 0 0 28px rgba(139,26,26,.5); margin-bottom: 8px; }
.card-break { max-width: 400px; width: 100%; margin: 0 auto; }
.section-label-mb { margin-bottom: 8px; }
.vpip-row { display: flex; gap: 7px; align-items: center; margin-bottom: 8px; }
.card-clues-sidebar { padding: 14px 18px; max-width: 220px; }
.card-guess { padding: 22px 26px; }
.btn-vote { max-width: 260px; margin-top: 14px; }
.abort-btn-centered { max-width: 260px; margin: 0 auto; }
.result-header { text-align: center; margin-bottom: 8px; }
.h-line-result { width: 100%; max-width: 480px; margin: 12px auto; }
.reveal-stack { display: flex; flex-direction: column; gap: 10px; align-items: center;
                          width: 100%; max-width: 460px; margin-bottom: 14px; }

/* Mobile: both grids collapse to a column */


.result-actions { display: flex; gap: 10px; max-width: 460px; width: 100%; }
.btn-flex1 { flex: 1; }
.btn-flex2 { flex: 2; }

/* Impostor game view (screen-game bg-red) more compact - previously did not fit without
   scrolling on one screen: figure scaled down (layout height compensated via negative margin),
   title/subtitle/mission box tighter. */
.screen-game.bg-red .impostor-figure { transform: scale(.6); transform-origin: top center; margin: 0 auto -62px; }
.screen-game.bg-red .impostor-title { font-size: 21px; margin-bottom: 2px; }
.screen-game.bg-red .impostor-subtitle { font-size: 13px; margin-bottom: 10px; }
.screen-game.bg-red .impostor-mission { padding: 11px 16px; margin-bottom: 10px; max-width: 560px; }
.screen-game.bg-red .impostor-mission-title { font-size: 13px; margin-bottom: 5px; }
.screen-game.bg-red .impostor-mission-text { font-size: 13px; line-height: 1.45; }
.screen-game.bg-red .impostor-category { padding: 8px 16px; margin-bottom: 10px; }

/* ── End screen game history ─────────────────────────────────────────────── */
.history-card {
  width: 100%;
  max-width: 480px;
  padding: 16px 20px;
  margin-bottom: 14px;
}
.history-title {
  font-family: 'Rye', cursive;
  font-size: 14px;
  color: var(--gold-ink);
  letter-spacing: .08em;
  margin-bottom: 12px;
  text-align: center;
}
.history-clue-row,
.history-vote-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 7px 0;
  border-bottom: 1px solid var(--border-faint);
  font-size: 14px;
}
.history-clue-row:last-child,
.history-vote-row:last-child {
  border-bottom: none;
}
.history-name { color: var(--old-paper); flex: 0 0 130px; }
.history-name-impostor { color: var(--blood-red); flex: 0 0 130px; font-weight: bold; }
.history-clues { color: var(--gold-ink); flex: 1; text-align: right; }
.history-arrow { color: var(--smoke); }
.history-vote-hit { color: var(--green-ok); flex: 1; text-align: right; }
.history-vote-miss { color: var(--smoke);   flex: 1; text-align: right; }

/* ── Too Few Players Screen ──────────────────────────────────────────────── */
.toofew-card { max-width: 420px; width: 100%; text-align: center; padding: 28px 32px; }
.toofew-text { font-size: 14px; color: var(--smoke); }

/* ── Home Page ───────────────────────────────────────────────────────────── */
/* The former hero/mode-cards/segmented styles are gone — Home now uses the
   sitewide poster grid (.pg-poster-grid) + spotlight banner (.pg-spotlight)
   inside the PageFrame shell. Only the pieces still referenced remain. */
.home-alert {
  max-width: 540px;
  width: 100%;
  margin: 0 auto 24px;
}
/* "Off" badge for disabled modes (admins only) — used on the poster tiles. */
.home-mode-off-badge {
  position: absolute;
  top: 8px;
  right: 8px;
  z-index: 1;
  font-size: 12px;
  letter-spacing: .04em;
  color: var(--danger);
  background: rgba(163,50,74,.18);
  border: 1px solid rgba(163,50,74,.5);
  border-radius: 3px;
  padding: 1px 6px;
}
.mode-switch-off {
  margin-left: auto;
  font-size: 12px;
  color: #e88;
  border: 1px solid rgba(163,50,74,.5);
  border-radius: 3px;
  padding: 0 5px;
}

/* ── JoinLobbyDialog (Modal Specifics) ───────────────────────────────────── */
.join-dialog {
  max-width: 540px;
}
.join-dialog-loading {
  text-align: center;
  padding: 30px;
  color: var(--smoke);
  font-style: italic;
}
.join-dialog-info {
  margin-bottom: 18px;
}
.join-dialog-mode {
  display: flex;
  gap: 14px;
  align-items: flex-start;
  padding: 14px;
  background: rgba(200,146,42,.06);
  border: 1px solid rgba(200,146,42,.22);
  border-radius: 4px;
  margin-bottom: 12px;
}
.join-dialog-mode-icon {
  font-size: 32px;
  line-height: 1;
  flex-shrink: 0;
}
.join-dialog-mode-name {
  font-family: 'Rye', cursive;
  font-size: 17px;
  color: var(--gold);
  margin: 0 0 6px 0;
}
.join-dialog-mode-desc {
  color: var(--parchment);
  font-size: 13px;
  margin: 0;
  line-height: 1.5;
}
.join-dialog-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 18px;
  font-size: 14px;
  color: var(--smoke);
  margin-bottom: 12px;
}
.join-dialog-meta strong {
  color: var(--gold-light);
}
/* "You are joining the lobby as X." – a little breathing room below,
   so the join button does not stick directly to the text. */
.join-dialog-as-user {
  color: var(--smoke);
  font-size: 14px;
  margin: 0 0 14px 0;
}
.join-dialog-as-user strong {
  color: var(--gold-light);
}
.join-dialog-section {
  padding: 14px 0;
}
.join-dialog-section-title {
  font-size: 14px;
  color: var(--gold-light);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  margin: 0 0 10px 0;
}
.join-dialog-auth-actions {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.join-dialog-account-required {
  margin-bottom: 14px;
}

/* compact OAuth button list in the join dialog (variant B from
   `docs/mockups/join-lobby-dialog-refactor.html`). Buttons stack vertically
   with a small gap; below them two subtle footer text links for email login
   or register, instead of the previously dominant wide buttons. */
.join-dialog-oauth {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.join-dialog-footer-links {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 12px 18px;
  margin-top: 10px;
  font-size: 12px;
}
.join-dialog-footer-links a {
  color: var(--gold);
  text-decoration: none;
}
.join-dialog-footer-links a:hover {
  color: var(--gold-light);
}

/* ── Join page (/Join/{code}) — auto-join interstitial + waiting room ─────── */
.join-switch-note { font-size: 12.5px; color: var(--smoke); margin: 6px 0 2px; }

.ji-auto, .ji-wait {
  display: flex; flex-direction: column; align-items: center;
  text-align: center; gap: 9px; padding: 22px 14px; margin-top: 4px;
  background: rgba(8,5,2,.4);
  border: 1px solid var(--border);
  border-radius: 6px;
}
.ji-h {
  font-family: 'Rye', cursive; font-size: 18px; color: var(--accent-light);
  display: flex; align-items: center; gap: 10px;
}
.ji-s { font-size: 13px; color: var(--parchment); max-width: 460px; line-height: 1.55; }
.ji-f { font-size: 12.5px; color: var(--smoke); margin-top: 2px; }

.ji-spin {
  width: 34px; height: 34px;
  border: 3px solid var(--border); border-top-color: var(--accent-light);
  border-radius: 50%; animation: jiSpin .9s linear infinite;
}
@keyframes jiSpin { to { transform: rotate(360deg); } }

.ji-pulse {
  width: 11px; height: 11px; border-radius: 50%; flex: none;
  background: var(--accent-light); animation: jiPulse 1.6s infinite;
}
.ji-pulse-sm { width: 9px; height: 9px; }
@keyframes jiPulse {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent-light) 65%, transparent); }
  70%  { box-shadow: 0 0 0 9px transparent; }
  100% { box-shadow: 0 0 0 0 transparent; }
}

/* ── App Shell: Header + Main + Footer Layout ───────────────────────────── */
.app-shell {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}
.app-main {
  flex: 1 0 auto;
  display: flex;
  flex-direction: column;
  /* NO padding-bottom here! Otherwise a strip without screen background appears.
     Footer spacing is handled inside each .screen-* itself (see above). */
}

/* In-app maximize: the BOX fills the area between top-nav and bottom-nav
   (no zoom — real space). Height is passed down via flex: screen → frame →
   lobby-layout → player-/stage-card → stage; same for the game via card-board. */
/* Mobile strategy: maximize is a DESKTOP feature. The button is hidden at ≤760px
   AND the maximized CSS only kicks in from 761px up — so mobile always keeps
   the responsive normal layout, even when the state (localStorage) is set. */
@media (min-width: 761px) {
  /* Outer screens (carrying .lobby-redesign) fill app-main. IMPORTANT: only these, NOT
     the nested Playing-.screen-game (HangmanPlaying/SeeschlachtPlacement render
     their own .screen-game WITHOUT .lobby-redesign) — otherwise their content loses
     centering (→ left-aligned). */
  /* Frame scroll lock (game/lobby pages): app height = exactly viewport, app-main shrinkable.
     This prevents the page/frame from growing in maximized mode → no page scroll.
     Tall game content scrolls INSIDE the nested screen instead (see below).
     Scoped via :has() deliberately to game/lobby pages only — otherwise the remembered
     maximize state (localStorage) would also height-lock admin/account pages (sticky header
     would scroll away). Other pages keep the normal scrollable app-shell (min-height:100vh). */
  body.ss-maximized:has(.screen-game.lobby-redesign, .screen-lobby) .app-shell { height: 100vh; min-height: 0; }
  body.ss-maximized:has(.screen-game.lobby-redesign, .screen-lobby) .app-main { flex: 1 1 auto; min-height: 0; }

  body.ss-maximized .screen-lobby,
  body.ss-maximized .screen-game.lobby-redesign {
    flex: 1 1 auto; min-height: 0; align-items: stretch; justify-content: flex-start;
    padding: 6px 8px;
  }
  /* Lobby shows the FIXED app footer (imprint bar) → reserve space at the bottom,
     otherwise the action bar (START GAME) disappears behind it. In the game the
     footer is hidden, so no reserve needed there.
     Reserve = footer height (~49px on desktop) + the same 6px gap the top edge has
     (padding: 6px 8px above) → the frame sits symmetrically between header and footer.
     Was 50px, which left only ~1px below the frame after the footer grew. */
  body.ss-maximized .screen-lobby { padding-bottom: 55px; }
  body.ss-maximized .lobby-frame {
    max-width: none; width: 100%; flex: 1 1 auto; min-height: 0;
    display: flex; flex-direction: column;
  }
  body.ss-maximized .lobby-header { max-width: none; width: 100%; }
  /* Lobby: pass height through to the stage/arena. */
  body.ss-maximized .lobby-layout {
    max-width: none; width: 100%; flex: 1 1 auto; min-height: 0;
    display: flex; flex-direction: column;
  }
  body.ss-maximized .lobby-arena { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
  /* Stage AND table fill the arena height equally (seats are %-positioned → scale with it). */
  body.ss-maximized .lobby-stage-theatre,
  body.ss-maximized .lobby-table .felt { flex: 1 1 auto; height: auto; min-height: 0; }
  /* Game: the card-board fills width + height. */
  body.ss-maximized .screen-game.lobby-redesign > .card-board {
    max-width: none; width: 100%; flex: 1 1 auto; min-height: 0;
    display: flex; flex-direction: column;
  }
  /* The nested game screen (Playing/Break/Voting/Result) fills the card-board
     and CENTERS its content itself (its own align/justify:center is kept). */
  /* Inner scroll as a general catch-all: if a game screen does not fill the height,
     it stays centered; if its content is too tall (long final scores/recaps/lists), IT
     scrolls INTERNALLY — the card-board frame + the docked footer stay fixed. `safe center`
     keeps the overflow reachable at the top (otherwise centered flex content clips at the top). */
  body.ss-maximized .card-board > .screen-game,
  body.ss-maximized .card-board > .screen-break,
  body.ss-maximized .card-board > .screen-voting,
  body.ss-maximized .card-board > .screen-result {
    flex: 1 1 auto; min-height: 0; overflow-y: auto; justify-content: safe center;
  }

  /* ── Content uses the maximized area (no zoom) ──────────────────────────────
     Inner width caps are raised; flexible content (memory grid with
     1fr, quiz answers) grows along with them. Fixed sizes (cards, naval battle board)
     are selectively enlarged. */
  /* Word/Quiz/Memory + Shadow Game: layout cap (820px) raised → main column (1fr) grows. */
  body.ss-maximized .card-board .hangman-layout,
  body.ss-maximized .card-board .game-layout { max-width: 1280px; }

  /* Memory: height is passed down via flex to the board, so the fit area has a
     REAL bounded height (no more guessed vh constants). shadowSaloon.fitMemory
     measures .memory-fit and sets --mem-cell = min(width-fit, height-fit). SAME grid
     as normal (fixed 6 columns) — just scaled larger, square, centered, no scrolling. */
  body.ss-maximized .card-board > .screen-game.mode-memory { display: flex; flex-direction: column; }
  body.ss-maximized .mode-memory > .hangman-layout {
    flex: 1 1 auto; min-height: 0; max-width: none;
    /* minmax(0, 1fr) (not the default 1fr, whose implicit min-width:auto lets the board push
       the column wider than the viewport → horizontal scrollbar + a resize-direction feedback
       loop, because fitMemory then measures the inflated width). Now the column always reports
       the TRUE available width, so fitMemory sizes the board to fit — no overflow, no hysteresis. */
    grid-template-columns: minmax(0, 1fr) 220px;
    grid-template-rows: minmax(0, 1fr); align-items: stretch;
  }
  body.ss-maximized .mode-memory .hangman-main { min-height: 0; min-width: 0; }
  body.ss-maximized .mode-memory .memory-board-card { flex: 1 1 auto; min-height: 0; }
  /* Felt HUGS the board (width/height = content) and centers itself in the card's free
     space via margin:auto — instead of spanning the full width and leaving the small board
     stranded in a sea of green. shadowSaloon.fitMemory no longer measures this (shrinking)
     box; it measures the stable card and sizes --mem-cell to fit, so there's no circular
     width dependency. max-*: 100% + the fit-to-height cell keep it inside the card. */
  body.ss-maximized .mode-memory .memory-felt {
    margin: auto; width: fit-content; max-width: 100%; max-height: 100%;
    min-height: 0; display: flex; flex-direction: column;
  }
  body.ss-maximized .mode-memory .memory-fit {
    display: block; min-height: 0;
  }
  body.ss-maximized .mode-memory .memory-board {
    gap: 14px;
    grid-template-columns: repeat(var(--mem-cols, 6), var(--mem-cell, 92px));
    grid-auto-rows: var(--mem-cell, 92px);
    justify-content: center; align-content: center;
  }
  body.ss-maximized .mode-memory .mem-card { width: var(--mem-cell, 92px); height: var(--mem-cell, 92px); aspect-ratio: auto; }
  /* Music quiz/knowledge quiz: let the question card grow + scale question/answers.
     Layout stays the same (no wrapping of the 2x2 answers) — just larger/more readable via clamp,
     answer buttons also get taller (vh) and use the maximized height. */
  body.ss-maximized .card-board .mq-card { max-width: none; }
  /* Card games: override cap (inline 880/1080) + larger cards. */
  body.ss-maximized .card-board .durak-board { max-width: 1280px !important; }

  /* Ultimate TicTacToe: the square board fills the maximized height; the head (legend +
     status) sits above it in the SAME width. Both are sized to the smaller of the area's
     width / (height − head) via container-query units → no page scroll (overflow hidden). */
  body.ss-maximized .card-board > .screen-game.mode-uttt { overflow: hidden; }
  body.ss-maximized .mode-uttt > .uttt-board-area { flex: 1 1 auto; min-height: 0; container-type: size; }
  body.ss-maximized .mode-uttt .uttt-frame { width: min(100cqw, calc(100cqh - 44px)); max-width: none; }
  body.ss-maximized .mode-uttt .uttt-head { min-height: 0; height: 26px; flex-wrap: nowrap; }
  body.ss-maximized .mode-uttt .uttt-status { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  /* Height chain so the felt oval fills the maximized area (board → felt-wrap → felt grow). */
  body.ss-maximized .card-board > .screen-game.mode-schnellschuss { display: flex; flex-direction: column; }
  body.ss-maximized .mode-schnellschuss > .durak-board { flex: 1 1 auto; min-height: 0; }
  /* Offiziersskat (2-player Skat): height chain so the layout board has a REAL bounded
     height — shadowSaloon.fitOsk measures it and bumps ONLY --osk-w/--osk-h (the 2×4
     stack grid never changes). The classic 3-player Skat table is untouched (:has). */
  body.ss-maximized .card-board > .screen-game.mode-skat:has(.osk-board) { display: flex; flex-direction: column; overflow-y: hidden; }
  body.ss-maximized .screen-game.mode-skat > .osk-board { flex: 1 1 auto; min-height: 0; }
  /* Naval battle: raise see-wrap cap. The exact cell size is set by ss.fitSeeBoard via measurement
     (inline --see-cell-max) — so the board NEVER overflows on any resolution. */
  body.ss-maximized .card-board .see-wrap { max-width: 1280px; }
  /* Height chain: limit the board host to the available height (min-height:0 + flex:1),
     otherwise the container grows with the board content and the measurement would be useless. */
  body.ss-maximized .card-board > .screen-game.mode-seeschlacht { display: flex; flex-direction: column; }
  body.ss-maximized .screen-game.mode-seeschlacht > .see-wrap { flex: 1 1 auto; min-height: 0; }
}

/* ── Low-height compact mode: quiz games on flat landscape viewports ──────
   Landscape tablets (e.g. Galaxy Tab A9+: 1280×800 CSS px, minus ~60px browser
   chrome → ~740px usable) fall into the maximized desktop layout above, but the
   quiz cards' DOM-flow stack (Musikquiz ~660px, Wissensquiz ~617px measured)
   exceeds the available ~573px card-board height and triggers the inner
   overflow-y scroll. Below 850px viewport height the fixed paddings and the
   Musikquiz cover block shrink so both quizzes fit without scrolling; taller
   desktops are pixel-identical. Scoped to the two quiz modes — Hangman/Tabu/
   Memory share .hangman-layout but their stacks fit as-is. */
@media (min-width: 761px) and (max-height: 850px) {
  body.ss-maximized .mode-musikquiz .hangman-layout,
  body.ss-maximized .mode-wissensquiz .hangman-layout { padding-top: 8px; padding-bottom: 8px; }
  body.ss-maximized .card-board .card.mq-card { padding: 14px 26px; gap: 10px; }
  body.ss-maximized .mode-musikquiz .mq-option,
  body.ss-maximized .mode-wissensquiz .mq-option { padding: 10px 16px; min-height: 48px; }
}

/* ── App Header (fixed at top) ──────────────────────────────────────────── */
.app-header {
  position: sticky;
  top: 0;
  z-index: 900;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 18px;
  background: var(--chrome);
  backdrop-filter: blur(6px);
  border-bottom: 1px solid var(--border-soft);
}
/* Left group: brand + (when present) the lobby pill / code-join form. Grouping
   them frees the header's horizontal center for the centered announcement banner. */
.app-header-left {
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
}

/* Global announcement banner, centered IN the header row (admin-configurable;
   renders nothing when empty). Absolutely centered so it stays page-centered
   regardless of the differing left/right widths; single-line with ellipsis so it
   never grows the header height. pointer-events:none so it never blocks the
   header controls even if it visually approaches them on narrow widths. */
.announce-strip {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: max-content;
  max-width: min(52vw, 600px);
  pointer-events: none;
}
/* Wide: full inline banner (single line, ellipsized if it gets tight). */
.announce-strip .ann-inline {
  margin-bottom: 0;
  width: 100%;
  align-items: center;
  padding: 5px 14px;
  font-size: 13px;
}
.announce-strip .ann-inline .announce-body {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  text-align: center;
}
.announce-strip .ann-collapsed { display: none; }
/* Hidden measuring copy: JS reads its width to decide whether the full text fits. */
.announce-strip .ann-measure {
  position: absolute;
  left: -9999px;
  top: 0;
  visibility: hidden;
  white-space: nowrap;
  font-size: 13px;
}

/* Collapsed (measured: full text doesn't fit the header center) → show only the
   level icon; a click opens the full text as a popover. Driven by JS measurement
   (shadowSaloon.fitAnnounce), not a fixed breakpoint, so it adapts to text length
   AND window width. */
/* Collapsed: leave the absolute centering and join the header's normal flow as a
   real flex item (between the left group and the actions). That way the icon can
   never overlap the code box — flexbox lays it out instead of stacking it on top. */
.announce-strip.is-collapsed {
  position: static;
  transform: none;
  max-width: none;
  width: auto;
  flex: 0 0 auto;
  pointer-events: auto;
}
.announce-strip.is-collapsed .ann-inline { display: none; }
.announce-strip.is-collapsed .ann-collapsed { display: block; position: relative; pointer-events: auto; }
.announce-strip .ann-toggle {
  margin: 0;
  padding: 0;
  width: 32px;
  height: 32px;
  border: 1px solid currentColor;   /* full ring in the level color (overrides the inline left accent) */
  border-radius: 50%;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.announce-strip .ann-toggle .announce-icon { font-size: 15px; }
.announce-strip .ann-pop {
  display: none;
  position: absolute;
  top: calc(100% + 8px);
  left: 50%;
  transform: translateX(-50%);
  width: max-content;
  max-width: 86vw;
  /* Opaque base + high z-index so the popover sits clearly ON TOP of the page (game-frame
     header/code box below) instead of showing it through the translucent level tint. The inner
     .announce keeps its per-level tint, now layered over this opaque box. */
  background: var(--surface-1-strong);
  border-radius: 6px;
  box-shadow: 0 12px 30px var(--shadow-color);
  z-index: 1300;
}
.announce-strip .ann-collapsed.is-open .ann-pop { display: block; }
.announce-strip .ann-pop .announce {
  margin-bottom: 0;
  padding: 8px 14px;
  font-size: 12.5px;
  align-items: flex-start;
  box-shadow: none;
}
.announce-strip .ann-pop .announce-body { text-align: left; line-height: 1.4; }
.app-header-brand {
  display: flex;
  align-items: center;
  gap: 10px;
  text-decoration: none;
  color: var(--heading);
  font-family: 'Rye', cursive;
  font-size: 16px;
  letter-spacing: 0.06em;
  transition: opacity 0.15s;
}
@media (hover: hover) {
  .app-header-brand:hover {
    opacity: 0.85;
  }
}
.app-header-logo {
  width: 28px;
  height: 28px;
  filter: drop-shadow(0 0 6px rgba(200, 146, 42, 0.4));
}
/* Theme-Logo-Umschaltung: dunkle Kachel im Dark, Pergament-Stempel im Light. */
.logo-for-light { display: none; }
[data-theme="light"] .logo-for-light { display: inline-block; }
[data-theme="light"] .logo-for-dark { display: none; }
[data-theme="light"] .app-header-logo { filter: none; }
.app-header-title {
  display: inline-block;
}
.app-header-actions {
  display: flex;
  align-items: center;
  gap: 10px;
}

/* Streamer mode indicator in the header (only visible when active).
   Matched to the 38px height + pill shape of the other header controls
   (language dropdown, mute, avatar), so the chip does not stand out as smaller.
   Red tint remains as a "privacy active" signal. */
.streamer-chip {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 38px;
  padding: 0 14px;
  background: rgba(139, 26, 26, .22);
  border: 1px solid var(--border-strong);
  color: var(--heading);
  border-radius: 19px;
  font-size: 13px;
  cursor: pointer;
  white-space: nowrap;
  transition: background .15s, border-color .15s;
}
.streamer-chip:hover {
  background: rgba(139, 26, 26, .34);
  border-color: var(--gold);
}
[data-theme="light"] .streamer-chip { background: rgba(139, 26, 26, .10); }
[data-theme="light"] .streamer-chip:hover { background: rgba(139, 26, 26, .18); }
@media (max-width: 540px) {
  /* On narrow screens show only the camera icon, hide text to save space.
     Height stays at 34px like the other header buttons in the mobile layout. */
  .streamer-chip { font-size: 0; height: 34px; padding: 0 11px; }
  .streamer-chip::before { content: '🎥'; font-size: 14px; }
}

/* ── Header Auth Buttons (Guests) ────────────────────────
   Replace the previous hamburger menu for unauthenticated visitors. "Sign in"
   and "Register" are directly visible instead of hidden in a dropdown. */
.header-auth-actions {
  display: flex;
  align-items: center;
  gap: 8px;
}
.auth-btn {
  display: inline-flex;
  align-items: center;
  height: 38px;
  padding: 0 16px;
  border-radius: 6px;
  font-size: 13px;
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
  transition: border-color .15s, background .15s;
}
.auth-btn-ghost {
  background: transparent;
  border: 1px solid rgba(200, 146, 42, 0.4);
  color: var(--parchment);
}
.auth-btn-ghost:hover { border-color: var(--gold); }
.auth-btn-solid {
  background: linear-gradient(180deg, #3a2710, #26190a);
  border: 1px solid var(--gold);
  color: var(--gold-light);
}
.auth-btn-solid:hover { background: linear-gradient(180deg, #4a3214, #2e1f0c); }

/* ── Nav Lobby Pill ──────────────────────────────────────────────────────
   Shown in the header next to the logo when the user is in a lobby
   but not currently on the lobby/game page. Click navigates back. */
.nav-lobby-pill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-left: 14px;
  margin-right: auto;     /* pushes the header-actions block further to the right */
  padding: 5px 12px 5px 8px;
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  border-radius: 18px;
  color: var(--heading);
  font-size: 13px;
  text-decoration: none;
  transition: background .15s, border-color .15s;
  /* gentle pulsing so the user notices the pill */
  animation: navLobbyPulse 2.4s ease-in-out infinite;
}
.nav-lobby-pill:hover {
  background: rgba(200,146,42,.18);
  border-color: var(--gold);
  animation-play-state: paused;
}
.nav-lobby-pill-icon {
  font-size: 16px;
  line-height: 1;
}
.nav-lobby-pill-text {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
}
.nav-lobby-pill-count {
  color: var(--smoke);
  font-size: 12px;
}
@keyframes navLobbyPulse {
  0%, 100% { box-shadow: 0 0 0 rgba(200,146,42,0); }
  50%      { box-shadow: 0 0 14px rgba(200,146,42,.18); }
}

/* Inside the lobby: no pulsing (user is already there),
   slightly more subtle and with a default cursor instead of pointer. */
.nav-lobby-pill.is-current {
  animation: none;
  cursor: default;
  background: rgba(200,146,42,.04);
  border-color: rgba(200,146,42,.25);
}
.nav-lobby-pill.is-current:hover {
  background: rgba(200,146,42,.04);
  border-color: rgba(200,146,42,.25);
}

/* ── Kick Toast (shown by MainLayout when the user was removed from
   the lobby while not on the lobby page) ─────────────────────────────────────── */
.kick-toast-wrap {
  /* Centered directly below the header, but does not push anything.
     Container is just a placeholder for the toast element, which stays sticky. */
  position: sticky;
  top: 60px;
  z-index: 850;
  display: flex;
  justify-content: center;
  pointer-events: none;
}
.kick-toast {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 14px 10px 16px;
  margin: 14px 16px 0 16px;
  background: rgba(30,10,5,.92);
  border: 1px solid rgba(192,53,42,.7);
  border-left: 3px solid var(--blood-red);
  border-radius: 3px;
  box-shadow: 0 6px 24px rgba(0,0,0,.5);
  color: var(--old-paper);
  font-size: 14px;
  max-width: 480px;
  pointer-events: auto;
  animation: kickToastSlideIn .25s ease-out;
}
.kick-toast-icon {
  font-size: 18px;
  color: var(--red-light);
  flex-shrink: 0;
}
.kick-toast-text {
  flex: 1;
}
.kick-toast-close {
  background: transparent;
  border: none;
  color: var(--smoke);
  font-size: 14px;
  cursor: pointer;
  padding: 2px 6px;
  margin: -2px -4px -2px 0;
  border-radius: 2px;
  transition: color .15s, background .15s;
}
.kick-toast-close:hover {
  color: var(--old-paper);
  background: rgba(255,255,255,.08);
}
@keyframes kickToastSlideIn {
  from { transform: translateY(-12px); opacity: 0; }
  to   { transform: translateY(0);     opacity: 1; }
}
/* Mobile: more compact, without mode name */
@media (max-width: 600px) {
  .nav-lobby-pill-text { gap: 4px; }
  .nav-lobby-pill { font-size: 12px; padding: 4px 10px 4px 6px; }
}

/* ── Volume (vertical slider pop-up BELOW the button, hover/focus) ──────── */
.volume-control {
  display: flex;
  align-items: center;
  position: relative;
}
.mute-btn {
  width: 38px;
  height: 38px;
  border-radius: 50%;
  background: var(--surface-1);
  border: 1px solid var(--border-strong);
  color: var(--heading);
  font-size: 16px;
  cursor: pointer;
  transition: all .2s;
  display: flex;
  align-items: center;
  justify-content: center;
}
@media (hover: hover) {
  .mute-btn:hover {
    border-color: var(--gold);
    background: var(--surface-hover);
    transform: scale(1.05);
  }
}
.mute-btn.muted {
  color: color-mix(in srgb, var(--text-dim) 60%, transparent);
  border-color: color-mix(in srgb, var(--text-dim) 30%, transparent);
}
.mute-btn.muted:hover {
  color: var(--text-dim);
  border-color: var(--border-strong);
}

/* Anchored pop-up panel below the button; the ::before strip bridges the
   hover gap between button and panel so it doesn't close mid-way. */
.volume-pop {
  position: absolute;
  top: calc(100% + 8px);
  left: 50%;
  transform: translateX(-50%);
  width: 34px;
  height: 118px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--surface-1-strong);
  border: 1px solid var(--border-soft);
  border-radius: 17px;
  box-shadow: 0 10px 26px var(--shadow-color);
  z-index: 1000;
  /* opacity instead of display:none — a display:none slider could never
     receive keyboard focus, so :focus-within would be unreachable via Tab. */
  opacity: 0;
  pointer-events: none;
  transition: opacity .2s ease;
}
.volume-pop::before {
  content: '';
  position: absolute;
  top: -10px;
  left: 0;
  right: 0;
  height: 10px;
}
.volume-control:focus-within .volume-pop {
  opacity: 1;
  pointer-events: auto;
}
@media (hover: hover) {
  .volume-control:hover .volume-pop {
    opacity: 1;
    pointer-events: auto;
  }
}
/* Horizontal range rotated 270° → max points UP (push up = louder). The
   layout box stays horizontal; hit-testing follows the transformed geometry.
   The input box is 24px thick (WCAG 2.5.8 minimum target size) — the visible
   4px track is drawn by the track pseudo-elements, not the element itself. */
.volume-slider {
  -webkit-appearance: none;
  appearance: none;
  flex: none;
  width: 94px;
  height: 24px;
  background: transparent;
  outline: none;
  cursor: pointer;
  transform: rotate(270deg);
}
.volume-slider::-webkit-slider-runnable-track {
  height: 4px;
  background: var(--surface-2);
  border: 1px solid var(--border-soft);
  border-radius: 2px;
}
.volume-slider::-moz-range-track {
  height: 4px;
  background: var(--surface-2);
  border: 1px solid var(--border-soft);
  border-radius: 2px;
}
.volume-slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 14px;
  height: 14px;
  margin-top: -5px;   /* center the 14px thumb on the 4px(+2px border) track */
  border-radius: 50%;
  background: var(--gold);
  border: 1px solid rgba(8, 5, 2, 0.8);
  cursor: pointer;
}
.volume-slider::-moz-range-thumb {
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--gold);
  border: 1px solid rgba(8, 5, 2, 0.8);
  cursor: pointer;
}

/* Header help button (game rules) — sits in the header-actions, no longer fixed */
.header-help-btn {
  width: 38px;
  height: 38px;
  border-radius: 50%;
  background: var(--surface-1);
  border: 1px solid var(--border-strong);
  color: var(--heading);
  font-family: 'Rye', cursive;
  font-size: 16px;
  cursor: pointer;
  transition: all .2s;
  display: flex;
  align-items: center;
  justify-content: center;
}
@media (hover: hover) {
  .header-help-btn:hover {
    border-color: var(--gold);
    background: var(--surface-hover);
    transform: scale(1.05);
  }
}

@media (max-width: 540px) {
  .app-header { padding: 8px 12px; }
  .app-header-title { display: none; } /* logo only on mobile */
  .mute-btn,
.header-help-btn { width: 34px; height: 34px; font-size: 14px; }
  .volume-control:hover .volume-slider { width: 60px; max-width: 60px; }
  /* Narrow header: show only "Sign in", "Register" is accessible from
     the login page. Saves width next to logo + volume. */
  .auth-btn-solid { display: none; }
  .auth-btn { height: 34px; padding: 0 12px; }
}

/* ── Game Start: Sidebar Button + Fullscreen Countdown Overlay ─────────── */

/* Slimmer start button below the settings (instead of wide below the chat) */
.btn-start-sidebar {
  width: 100%;
  margin-top: 14px;
  padding: 10px 18px;
  font-size: 14px;
  letter-spacing: .08em;
}
.waiting-banner-sidebar {
  margin-top: 14px;
  text-align: center;
  font-size: 13px;
}

/* Overlay for start countdown — lives in .lobby-frame, covers only the lobby card */
.lobby-frame {
  position: relative;
  width: 100%;
  max-width: 1000px;
  border-radius: 4px;
  overflow: hidden;
}
.start-overlay {
  position: absolute;
  inset: 0;
  background: var(--scrim);
  backdrop-filter: blur(6px);
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  animation: startOverlayFadeIn .25s ease-out;
}
@keyframes startOverlayFadeIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}
.start-overlay-content {
  text-align: center;
  max-width: 480px;
  width: 100%;
}
.start-overlay-label {
  font-size: 15px;
  color: var(--smoke);
  letter-spacing: .25em;
  text-transform: uppercase;
  margin-bottom: 14px;
}
.start-overlay-num {
  font-family: 'Rye', cursive;
  font-size: clamp(96px, 18vw, 168px);
  color: var(--accent-strong);
  line-height: 1;
  text-shadow:
    0 0 32px var(--accent-light),
    0 0 64px var(--accent),
    0 4px 0 var(--shadow);
  margin-bottom: 18px;
  animation: startOverlayPulse 1s ease-in-out infinite;
}
@keyframes startOverlayPulse {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.06); }
}
.start-overlay-bar {
  width: 100%;
  height: 6px;
  background: var(--surface-2);
  border: 1px solid var(--border-soft);
  border-radius: 3px;
  overflow: hidden;
  margin-bottom: 20px;
}
.start-overlay-bar-fill {
  height: 100%;
  background: linear-gradient(to right, var(--accent), var(--accent-light));
  box-shadow: 0 0 14px var(--accent-light);
}
.start-overlay-cancel {
  margin-top: 4px;
}

/* ── Chat ────────────────────────────────────────────────────────────────── */
.chat-card {
  padding: 14px 16px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.chat-title {
  font-family: 'Rye', cursive;
  font-size: 14px;
  color: var(--gold);
  letter-spacing: .08em;
}
.chat-messages {
  /* Was 180px before – with the new lobby layout (player list compact at top)
     we have more height available, so we use the space for the chat. */
  height: 380px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 3px;
  scrollbar-width: thin;
  scrollbar-color: rgba(200,146,42,.2) transparent;
}
.chat-messages::-webkit-scrollbar { width: 4px; }
.chat-messages::-webkit-scrollbar-thumb { background: rgba(200,146,42,.2); border-radius: 2px; }

/* Status line */
.chat-status {
  display: flex;
  gap: 6px;
  align-items: baseline;
  padding: 1px 0;
}
.chat-status-text {
  font-size: 13px;
  color: var(--tg-sub, #6b5838);   /* fixed paper ink — the drawer is light in BOTH themes */
  font-style: italic;
}

/* Chat message */
.chat-msg {
  display: flex;
  gap: 6px;
  align-items: baseline;
  padding: 2px 0;
  flex-wrap: wrap;
}
.chat-msg-own .chat-sender { color: var(--tg-ink, #3a2c16); }
.chat-time {
  font-size: 12px;
  color: var(--tg-sub, #6b5838);   /* fixed paper ink — the drawer is light in BOTH themes */
  flex-shrink: 0;
  font-variant-numeric: tabular-nums;
}
.chat-sender {
  font-size: 13px;
  color: var(--tg-wood, #6b4a23);
  font-weight: bold;
  flex-shrink: 0;
}
.chat-sender::after { content: ':'; }
.chat-text {
  font-size: 14px;
  color: var(--old-paper);
  word-break: break-word;
  flex: 1;
}

/* Input line */
.chat-input-row {
  display: flex;
  gap: 6px;
  /* stretch instead of center: button adapts to the input height (input has
     padding-based height ~36 px, button had fixed 32 px → 4 px offset). */
  align-items: stretch;
}
.chat-inp {
  flex: 1;
  min-width: 0;
  font-size: 14px;
}

.chat-send-btn {
  flex-shrink: 0;
  width: 32px;
  background: rgba(8,5,2,.6);
  border: 1px solid rgba(200,146,42,.35);
  border-radius: 1px;
  font-size: 20px;
  color: var(--gold);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all .2s;
  line-height: 1;
  padding: 0;
}
.chat-send-btn:hover:not(:disabled) { background: rgba(200,146,42,.12); border-color: var(--gold); }
.chat-send-btn:disabled { opacity: .35; cursor: default; }

/* Emoji picker removed */

/* ── Game History Modal — Body Classes (all wrappers migrated to <Modal> component) ──── */

.history-loading,
.history-empty {
  padding: 32px;
  text-align: center;
  color: var(--smoke);
  font-size: 14px;
}
.history-list {
  padding: 16px 20px;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

/* ── Game Card ── */
.history-game-card {
  background: rgba(200,146,42,.04);
  border: 1px solid rgba(200,146,42,.12);
  border-radius: 2px;
  padding: 14px 16px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.history-game-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.history-game-meta {
  display: flex;
  gap: 10px;
  align-items: center;
}
.history-game-date {
  font-size: 13px;
  color: var(--smoke);
}
.history-game-duration {
  font-size: 12px;
  color: rgba(168, 151, 132,.55);
  background: rgba(200,146,42,.07);
  padding: 1px 7px;
  border-radius: 10px;
}
.history-winner-badge {
  font-size: 13px;
  padding: 3px 10px;
  border-radius: 2px;
  letter-spacing: .05em;
}
.history-winner-crewmates { background: rgba(34,139,34,.2);   color: #5c5; }
.history-winner-impostor { background: rgba(139,26,26,.25);  color: #e66; }
.history-winner-draw { background: rgba(168, 151, 132,.2); color: var(--smoke); }

.history-label {
  font-size: 12px;
  color: var(--smoke);
  letter-spacing: .1em;
  text-transform: uppercase;
  flex-shrink: 0;
  min-width: 68px;
}
.history-word-row,
.history-impostor-row {
  display: flex;
  align-items: center;
  gap: 10px;
}
.history-word {
  font-family: 'Rye', cursive;
  font-size: 16px;
  color: var(--gold-light);
  letter-spacing: .08em;
}
.history-impostor { font-size: 14px; color: var(--blood-red); }
.history-guess {
  font-size: 12px;
  margin-left: 4px;
}
.history-guess.correct { color: var(--green-ok); }
.history-guess.wrong { color: rgba(200,60,60,.7); }

.history-clues-section { display: flex; flex-direction: column; gap: 6px; }
.history-clues-grid { display: flex; flex-direction: column; gap: 4px; padding-left: 4px; }
.history-player-row {
  display: flex;
  gap: 8px;
  align-items: baseline;
  font-size: 13px;
  padding: 3px 0;
  border-bottom: 1px solid rgba(200,146,42,.05);
}
.history-player-row:last-child { border-bottom: none; }
.history-player-row.is-impostor .history-pname { color: var(--blood-red); }
.history-pname { flex: 0 0 110px; color: var(--old-paper); }
.history-pclues { flex: 1; color: var(--gold); }
.history-pvotes { flex: 0 0 80px; text-align: right; color: rgba(168, 151, 132,.6); font-size: 12px; }

/* ── Settings: Toggle Row ─────────────────────────────────────────────── */
.settings-toggle-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 6px 0;
}
/* .lbl brings display:block + margin-bottom — reset in the flex row
   so the label sits vertically centered, and match the
   compact 13px size of the other config rows. Applies to the
   direct label and the inline-label-with-help variant. */
.settings-toggle-row > .lbl,
.settings-toggle-row > .lbl-with-help-inline {
  display: flex;
  align-items: center;
  margin-bottom: 0;
}
.settings-toggle-row > .lbl,
.settings-toggle-row .lbl-with-help-inline .lbl {
  font-size: 13px;
  margin-bottom: 0;
}
/* Inline hint under a setting label (e.g. "not available in rapid fire"): own line,
   normal sentence case (not the uppercase/letter-spacing of the .lbl it sits in). */
.settings-lbl-hint {
  display: block;
  margin-top: 3px;
  font-size: 12px;
  font-weight: 400;
  text-transform: none;
  letter-spacing: 0;
  line-height: 1.35;
  color: var(--smoke);
}

/* ── Settings Toggle Button ──────────────────────────────────────────────── */
/* Bool slider (red/green) with ✓/✕ in the knob. Base = OFF (red),
   .on = ON (green). Used centrally: admin settings + lobby config.
   Markup: <button class="settings-toggle-btn [on]"><span class="toggle-knob">✓/✕</span></button> */
.settings-toggle-btn {
  width: 46px;
  height: 24px;
  border-radius: 12px;
  position: relative;
  padding: 0;
  border: none;
  cursor: pointer;
  background: rgba(139, 26, 26,.6);   /* off = red */
  transition: background .18s;
  flex-shrink: 0;
}
.settings-toggle-btn.on { background: var(--green-ok); }   /* on = green */
.settings-toggle-btn .toggle-knob {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: #e8d5b0;
  color: #1a1208;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  font-weight: bold;
  transition: left .18s;
  box-shadow: 0 1px 3px rgba(0,0,0,.5);
}
.settings-toggle-btn.on .toggle-knob { left: 24px; }
@media (hover: hover) {
  .settings-toggle-btn:hover {
    filter: brightness(1.12);
  }
}

/* ── Settings Section Label ──────────────────────────────────────────────
   Subtle separator heading between lobby and game settings in the
   new-lobby dialog. Two horizontal lines (pseudo-elements) flank
   the label text. .first = no top margin (first section directly at the
   start of the modal body). Applies to all game modes. */
.settings-section-label {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 14px 0 4px;
  color: var(--smoke);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .8px;
  text-transform: uppercase;
}
.settings-section-label::before,
.settings-section-label::after {
  content: '';
  flex: 1;
  height: 1px;
  background: rgba(200,146,42,.15);
}
.settings-section-label.first { margin-top: 0; }

/* ── Game Variant Block ───────────────────────────────────────────────────
   Visually highlighted block for the rapid-fire mode in the music-quiz
   lobby dialog — replaces the previous settings-toggle-row.
   Shows mode name, short description text and the toggle button.
   .active = rapid-fire enabled (golden border + light background). */
.spielvariante-block {
  border: 1px solid rgba(200,146,42,.2);
  border-radius: 5px;
  background: var(--surface-2);
  margin: 2px 0 6px;
  transition: border-color .18s, background .18s;
}
.spielvariante-block.active {
  border-color: rgba(200,146,42,.45);
  background: rgba(200,146,42,.07);
}
.spielvariante-header {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
}
.spielvariante-info { flex: 1; min-width: 0; }
.spielvariante-name {
  font-size: 13px;
  font-weight: 600;
  color: var(--parchment);
  display: flex;
  align-items: center;
  gap: 6px;
  transition: color .18s;
}
.spielvariante-block.active .spielvariante-name { color: var(--gold-light); }
.spielvariante-desc {
  font-size: 12px;
  color: var(--smoke);
  margin-top: 3px;
  line-height: 1.5;
}

/* ── Advanced Settings Collapsible ─────────────────────────────────────────
   Collapses fine-tuning options (answer delay, stop-on-first).
   Uses native <details> — no JS state needed.
   Deliberately mirrors the filter-collapsible look (bordered box, rotating
   ▸ triangle) so it stands as an equal block next to the filters and
   has a clear click target — instead of floating centered text. */
.settings-advanced-collapsible {
  border: 1px solid rgba(255,255,255,.06);
  border-radius: 4px;
  background: var(--surface-2);
  margin-top: 6px;
}
.settings-advanced-collapsible > .settings-advanced-summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 14px;
  user-select: none;
  border-radius: 4px;
  transition: background .15s ease;
}
.settings-advanced-collapsible > .settings-advanced-summary::-webkit-details-marker {
  display: none;
}
.settings-advanced-collapsible > .settings-advanced-summary:hover {
  background: rgba(255,255,255,.03);
}
.settings-advanced-collapsible > .settings-advanced-summary::before {
  content: '▸';
  font-size: 18px;
  font-weight: 700;
  color: var(--gold, #c8922a);
  transition: transform .2s ease;
  display: inline-block;
  margin-right: 8px;
}
.settings-advanced-collapsible[open] > .settings-advanced-summary::before {
  transform: rotate(90deg);
}
/* ── Lobby Sidebar: Quick-Access Buttons at Top ──────────────────────────── */
.lobby-sidebar-top-btns {
  display: flex;
  gap: 8px;
  margin-bottom: 12px;
}
.btn-sm-action {
  flex: 1;
  font-size: 12px !important;
  padding: 6px 10px !important;
  white-space: nowrap;
}

/* ── Stat Box (Game Sidebar) ─────────────────────────────────────────────── */
.stat-box { background: var(--surface-1-strong); border: 1px solid var(--border-soft); padding: 14px 16px; border-radius: 1px; }
.stat-box h4 { font-family: 'Rye', cursive; font-size: 16px; color: var(--accent); margin-bottom: 10px; letter-spacing: .08em; }
[data-theme="light"] .stat-box h4 { color: var(--accent-ink); }   /* Gold-Akzent faellt auf Pergament unter 4.5:1 */
.stat-box-center { text-align: center; }

/* Gold background for Explainer role reveal */
.bg-gold {
  background: radial-gradient(ellipse at 50% 30%, rgba(200,146,42,.12) 0%, transparent 70%),
              var(--dark);
}

/* ── History: Session Header as Collapsible Button ───────────────────── */
.history-session-header {
  /* button reset because we use <button> instead of <div> */
  background: color-mix(in srgb, var(--well) 33%, transparent);
  border: 1px solid var(--border-faint);
  color: var(--gold-ink);
  font-family: 'Rye', cursive;
  font-size: 13px;
  letter-spacing: .08em;
  padding: 10px 14px;
  margin-top: 10px;
  width: 100%;
  text-align: left;
  display: flex;
  align-items: center;
  gap: 10px;
  cursor: pointer;
  border-radius: 2px;
  transition: background .15s ease, border-color .15s ease;
}
.history-session-header:hover {
  background: var(--surface-2);
  border-color: color-mix(in srgb, var(--border-strong) 67%, transparent);
}
.history-session-header:first-of-type {
  margin-top: 0;
}
.history-session-header.expanded {
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
  border-bottom-color: transparent;
}
.history-session-toggle {
  color: var(--smoke, #a89784);
  font-size: 12px;
  width: 12px;
  flex-shrink: 0;
}
.history-session-title {
  flex-shrink: 0;
}
.history-session-summary {
  font-size: 12px;
  color: var(--smoke, #a89784);
  letter-spacing: .03em;
  margin-left: auto;
  text-transform: none;
  text-align: right;
}
.history-session-my-result strong {
  color: var(--accent-amber);
}
/* Modes without round statistics (e.g. Memory): only the final standings, single-column and
   centered instead of left-aligned in the 280px column. */
.podium-layout.no-stats {
  grid-template-columns: 280px;
  justify-content: center;
}
@keyframes tabu-flash-in { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }

/* ── Game Rules Modal — Body Classes (wrapper migrated to <Modal> component) ─────── */
.rules-content {
  text-align: left;
  font-size: 14px;
  line-height: 1.6;
  color: var(--old-paper);
}
.rules-content p { margin: 0 0 10px 0; }
.rules-content ul { margin: 4px 0 10px 24px; padding: 0; }
.rules-content li { margin: 4px 0; }
.rules-content strong { color: var(--heading); }

/* ── Auth Pages (Setup, Login, Register, Profile) ─────────────────────── */
.auth-screen,
.setup-screen {
  flex: 1 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
}
.card-auth,
.card-setup {
  background: var(--surface-1-strong);
  border: 1px solid var(--border-strong);
  border-radius: 12px;
  padding: 32px;
  max-width: 420px;
  width: 100%;
  box-shadow: 0 4px 32px rgba(0,0,0,.6);
}
.card-setup { max-width: 480px; }

.auth-emoji,
.setup-emoji {
  text-align: center;
  font-size: 48px;
  margin-bottom: 12px;
}
.auth-title,
.setup-title {
  text-align: center;
  font-family: 'Rye', cursive;
  color: var(--heading);
  font-size: 26px;
  margin: 0 0 6px 0;
}
.setup-subtitle {
  text-align: center;
  color: var(--smoke);
  font-size: 14px;
  margin-bottom: 24px;
}

.auth-form,
.setup-form { display: flex; flex-direction: column; gap: 16px; }
.form-group { display: flex; flex-direction: column; gap: 6px; }
/* var(--heading), NOT --gold-light: identical gold in dark mode, but readable
   dark brown in the light theme (gold-light on light modal bg is ~1.5:1). */
.form-group label {
  font-size: 13px;
  color: var(--heading);
}
.form-group small { color: var(--smoke); font-size: 12px; }

/* Honeypot field on public forms (Register): visually and semantically hidden from
   real users (sighted + screen reader), left in the DOM for bots that fill every
   <input> they parse. tabindex="-1" + aria-hidden keep it out of keyboard/AT
   navigation entirely, so it never surfaces to a real visitor. */
.hp-field { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* Spacing between consecutive form-groups inside a modal body.
   `.auth-form` already handles this via its `gap: 16px`, but the modal lacks
   such a wrapper — the form-groups would otherwise stick together (label "Current
   Password" would look like the label of the input above it). Adjacent-sibling selector
   so no top spacing appears on the first form-group. */
.modal-v2-body .form-group + .form-group { margin-top: 14px; }
.form-row { flex-direction: row; align-items: center; justify-content: space-between; gap: 10px; }
.check-row { display: flex; align-items: center; gap: 8px; cursor: pointer; font-size: 13px; color: var(--smoke); }
.check-row input[type="checkbox"] { cursor: pointer; }

.text-warning { color: #d97706; }

.btn-block { width: 100%; }

.auth-link {
  color: var(--heading);   /* not --gold: 2.7:1 on the light auth card */
  text-decoration: none;
  font-size: 13px;
}
.auth-link:hover { color: var(--heading); text-decoration: underline; }
/* Inactive variant (e.g. "Forgot password?" when SMTP is not configured) –
   stays visible but visually greyed out and not clickable. */
.auth-link-disabled {
  color: var(--smoke, #a89784);
  opacity: 0.55;
  cursor: not-allowed;
  text-decoration: line-through;
}
.auth-link-disabled:hover {
  color: var(--smoke, #a89784);
  text-decoration: line-through;
}

.auth-divider {
  text-align: center;
  margin: 24px 0 18px 0;
  position: relative;
  color: var(--smoke);
  font-size: 12px;
}
.auth-divider::before,
.auth-divider::after {
  content: "";
  position: absolute;
  top: 50%;
  width: 40%;
  height: 1px;
  background: rgba(200,146,42,.2);
}
.auth-divider::before { left: 0; }
.auth-divider::after { right: 0; }
.auth-divider span { background: var(--card-grad-b); padding: 0 12px; position: relative; }

.oauth-buttons { display: flex; flex-direction: column; gap: 8px; }
.btn-oauth {
  display: flex; align-items: center; justify-content: center; gap: 10px;
  padding: 10px;
  background: var(--surface-2);
  border: 1px solid var(--border-soft);
  color: var(--old-paper);
  border-radius: 6px;
  text-decoration: none;
  font-size: 14px;
  transition: all .2s;
}
.btn-oauth:hover { border-color: var(--gold); background: var(--surface-hover); }
.oauth-icon { font-weight: bold; width: 20px; text-align: center; }

/* Brand icons from ProviderIcon.razor — same dimensions as the .oauth-icon container,
   so login + profile linked-accounts lists sit on the same visual line. */
.provider-icon {
  width: 18px;
  height: 18px;
  display: inline-block;
  vertical-align: middle;
  flex-shrink: 0;
}

/* Toggle button for password/email form on login + register.
   OAuth is the default path, the classic form path expands on click.
   Kept subtle, only highlights on hover. */
.pw-toggle {
  background: transparent;
  border: 1px solid rgba(200,146,42,.25);
  color: var(--smoke);
  width: 100%;
  padding: 10px 14px;
  cursor: pointer;
  font-size: 14px;
  border-radius: 3px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  transition: all .15s;
}
.pw-toggle:hover { color: var(--heading); border-color: var(--gold); }
.pw-toggle .chevron { font-size: 12px; transition: transform .2s; }
.pw-toggle.expanded .chevron { transform: rotate(180deg); }

/* Collapsed form below the toggle. Toggled via JS
   (login: localStorage memory, register: always initially collapsed). */
.pw-form-collapsible { display: none; margin-top: 14px; padding-top: 14px;
  border-top: 1px dashed rgba(200,146,42,.15); }
.pw-form-collapsible.expanded { display: block; }

.auth-footer {
  margin-top: 20px;
  text-align: center;
  font-size: 13px;
  color: var(--smoke);
}

/* ── Profile Info ─────────────────────────────────────────────────────── */
.profile-info { display: flex; flex-direction: column; gap: 8px; margin-bottom: 16px; }
.profile-info-row { display: flex; align-items: center; gap: 10px; font-size: 14px; }
/* Label fixed on the left, value takes the middle space (`flex:1`), edit button sticks to the right.
   Before the edit-pencil extension, Profile-Info-Rows used `space-between`
   with only two children — now there can be up to three. With `flex:1` on the value
   the layout stays consistent regardless of whether a pencil is attached or not. */
/* min-width:0 lets the flex item shrink below its content width,
   overflow-wrap wraps long values (e.g. long email addresses) instead of
   overflowing the box. */
.profile-info-row > strong,
.profile-info-row > code { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.profile-label { color: var(--smoke); min-width: 90px; }
.profile-section-title { color: var(--heading); font-size: 15px; margin: 0 0 10px 0; }
/* masked values in streamer mode. */
.streamer-masked { color: var(--smoke); letter-spacing: 2px; font-style: italic; }
/* Streamer toggle as a clean single line: right-aligned like a value/edit pencil, no
   wrapping hint anymore (explanation is in the tooltip). */
.profile-streamer-row .settings-toggle-btn { margin-left: auto; }
/* Language dropdown right-aligned like the privacy toggle (same row appearance). */
.profile-divider { border: none; border-top: 1px solid rgba(200,146,42,.15); margin: 22px 0; }

/* Edit pencil behind editable values in the account card (display name, email).
   Subtle, in the saloon gold style, hover brightens. */
.edit-btn {
  background: transparent;
  border: 1px solid var(--border-strong);
  color: var(--heading);
  width: 26px; height: 26px;
  display: inline-flex; align-items: center; justify-content: center;
  cursor: pointer;
  border-radius: 1px;
  font-size: 13px;
  font-family: inherit;
  padding: 0;
  flex-shrink: 0;
  transition: all .15s;
}
.edit-btn:hover {
  border-color: var(--gold);
  color: var(--heading);
  background: rgba(200,146,42,.08);
}

/* Action row below the info rows (e.g. "change password" button).
   Dashed separator visually separates it from the info rows above. */
.profile-action-row {
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px dashed rgba(200,146,42,.1);
  display: flex;
  gap: 8px;
}
/* Buttons in an action row should only be as wide as their content —
   `.btn` has `width:100%` as default, which leads to wall-wide buttons here. */
.profile-action-row .btn-sm-action {
  flex: 0 0 auto;
  width: auto;
}

/* Modal body form label: smaller grey labels above the inputs. */
.form-label {
  display: block;
  font-size: 13px;
  color: var(--smoke);
  margin-bottom: 4px;
}

/* Role badges in the account card: compact symbol display (crown/scale/pencil)
   instead of comma-separated role names, with a title tooltip for the plain-text role.
   Keeps the account card slim when more account data is added later. */
.profile-roles {
  display: inline-flex;
  gap: 6px;
  flex: 1;
}
.profile-role-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  background: var(--surface-2);
  border: 1px solid var(--border-soft);
  color: var(--heading);
  font-size: 14px;
  border-radius: 3px;
  cursor: help;
}

/* ── Profile Page Layout (responsive 2-column) ──────────────────────────── */
/* Own screen container instead of .auth-screen, because the profile should not
   sit in a narrow auth card but may use the full width. */
.profile-screen {
  flex: 1 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 24px 16px 60px;
}
.profile-page {
  width: 100%;
  max-width: 1100px;
  display: flex;
  flex-direction: column;
  gap: 18px;
}
.profile-page-header {
  text-align: center;
  margin-bottom: 6px;
}

/* Two-column layout: left (380px, account management) and right (1fr, statistics
   + history). Each column is its own flex container, so the left sections stay
   stacked tightly — regardless of how tall the right column gets.
   With the old grid layout (grid-auto-flow: dense + explicitly assigned
   grid-column) very tall right sections dragged the whole grid row along and made
   the left cards look visually "torn apart". */
.profile-grid {
  display: grid;
  grid-template-columns: 380px 1fr;
  gap: 18px;
  align-items: start;
}
.profile-column-left,
.profile-column-right {
  display: flex;
  flex-direction: column;
  gap: 18px;
  min-width: 0;  /* so long content (e.g. long email address) does not break the column */
}
.profile-section {
  background: var(--surface-1);
  border: 1px solid var(--border-soft);
  border-radius: 4px;
  padding: 18px 20px 22px;
}
/* Buttons and button links inside a profile section get spacing
   from the preceding content (typically explanatory text). Standard p-margin
   alone is not enough; the "too close" impression comes mainly from
   .btn-block buttons that take up full width and therefore look visually
   very heavy. */
.profile-section > .btn,
.profile-section > a.btn {
  margin-top: 10px;
}
.profile-section > p + .btn,
.profile-section > p + a.btn {
  margin-top: 14px;
}
/* Legacy modifier: profile-section-left / profile-section-right were previously
   used for CSS grid column assignment. With the flex-column layout they are
   no longer semantically needed, but stay on the Razor sections so
   the logical purpose is visible in the markup. No additional styling here. */
.profile-section-danger {
  border-color: rgba(139,26,26,.35);
}
.profile-section .profile-section-title {
  font-family: 'Rye', cursive;
  color: var(--heading);
  font-size: 16px;
  letter-spacing: .04em;
  margin: 0 0 14px 0;
}
.profile-section .profile-danger-title { color: var(--danger); }

/* Collapse to a single column on tablet / smartphone, sections follow
   DOM order: all left sections first (account, display name,
   linked accounts, data, danger zone), then the right ones (statistics, recent games).
   Both flex columns remain active, the grid just switches its column mode
   — stack layout works automatically. */
@media (max-width: 860px) {
  .profile-grid {
    grid-template-columns: 1fr;
  }
}

/* ── Profile Dropdown in MainLayout ───────────────────────────────────── */
/* Closing on outside click now runs via ssClickOutside
   (document listener) instead of a fixed backdrop — which would be trapped
   inside the header box because of backdrop-filter. */
.profile-menu { position: relative; }
.profile-btn {
  position: relative;
  z-index: 1001;      /* must stay above the backdrop */
  width: 38px; height: 38px;
  border-radius: 50%;
  background: var(--surface-1);
  border: 1px solid var(--border-strong);
  color: var(--heading);
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  transition: all .2s;
}
/* Avatar fills the profile button (round photo/portrait instead of a letter). */
.profile-btn .avatar { --av-size: 32px; }
@media (hover: hover) {
  .profile-btn:hover {
    border-color: var(--gold);
    background: var(--surface-hover);
    transform: scale(1.05);
  }
}
.profile-initial {
  font-size: 16px;
  /* line-height: 1 suppresses the default line spacing of the font, which would
     otherwise shift the character upward. Special Elite (typewriter font) has
     additional whitespace at the top of the glyph – a slight translateY
     compensates this visually inside the circle. */
  line-height: 1;
  display: inline-block;
  transform: translateY(1px);
}
.profile-dropdown {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  background: var(--surface-1-strong);
  border: 1px solid var(--border-strong);
  border-radius: 8px;
  min-width: 180px;
  z-index: 1000;
  box-shadow: 0 4px 16px rgba(0,0,0,.6);
  backdrop-filter: blur(4px);
}
.profile-dropdown-header { padding: 10px 14px; border-bottom: 1px solid var(--border-soft); font-size: 13px; color: var(--heading); }
.profile-dropdown-item {
  display: block; padding: 8px 14px;
  color: var(--old-paper);
  text-decoration: none;
  font-size: 13px;
  background: none;
  border: none;
  width: 100%;
  text-align: left;
  cursor: pointer;
  font-family: inherit;
}
.profile-dropdown-item:hover { background: rgba(200,146,42,.1); color: var(--gold); }
.profile-dropdown-divider { height: 1px; background: rgba(200,146,42,.15); margin: 4px 0; }
/* Prevents double borders when the divider comes directly after the header or
   in-game banner (e.g. in the guest menu without profile/admin items before it) -
   both predecessors already have a border-bottom. */
.profile-dropdown-header + .profile-dropdown-divider,
.profile-dropdown-ingame + .profile-dropdown-divider {
  display: none;
}
/* Icons in dropdown items have different glyph widths (👤 vs ⚙).
   A fixed column keeps the text left-aligned. */
.dropdown-icon {
  display: inline-block;
  width: 20px;
  text-align: center;
  margin-right: 6px;
  font-size: 13px;
}

/* Warning banner in the profile menu when the player is in an active game */
.profile-dropdown-ingame {
  padding: 9px 14px;
  background: rgba(212, 98, 10, 0.14);
  border-bottom: 1px solid rgba(212, 146, 42, 0.3);
  border-left: 3px solid var(--gold);
  font-size: 12px;
  color: var(--bone, #ddd);
  line-height: 1.4;
}
.profile-dropdown-logout { color: #b85a4a; }

.alert-success {
  background: rgba(30,100,30,.2);
  border: 1px solid #4ade80;
  color: #4ade80;
  padding: 8px 12px;
  border-radius: 6px;
  font-size: 13px;
  margin-bottom: 8px;
}

.toofew-text { color: var(--smoke); font-size: 14px; text-align: center; }

/* ── Label + ?-Help-Button layout ──────────────────────────────────────────
   Form label with a small ? button beside it. Clicking ? opens a modal
   with brief descriptions (e.g. the game mode overview). Keeps the form
   lean while still allowing contextual lookup. */
.lbl-with-help {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 6px;
}
.lbl-with-help .lbl {
  margin: 0;
}
.help-icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;    /* WCAG 2.5.8 minimum target size */
  min-width: 24px;   /* flex containers must not shrink it below the target size */
  height: 24px;
  padding: 0;
  background: transparent;
  border: 1px solid rgba(200,146,42,.4);
  border-radius: 50%;
  color: var(--heading);
  font-size: 12px;
  font-weight: bold;
  cursor: pointer;
  transition: background .15s, border-color .15s, color .15s;
}
.help-icon-btn:hover {
  background: var(--surface-hover);
  border-color: var(--gold);
  color: var(--heading);
}

/* ── Mode-info modal — body classes (wrapper migrated to <Modal> component) ──── */
.mode-info-intro {
  font-size: 13px;
  margin: 0 0 18px 0;
}
/* Game rules page (/Rules): the former accordion was replaced by the
   sitewide split view (.rules-split, see the Saloon-Rahmen section). */

/* Single-game instructions (GameModeInfoModal): hero header above the GameRulesContent. */
.single-mode-hero { display: flex; align-items: center; gap: 14px; padding: 2px 0 14px;
  border-bottom: 1px solid var(--border); margin-bottom: 14px; }
.single-mode-hero .smh-ic { font-size: 38px; line-height: 1; flex: 0 0 auto; }
.single-mode-hero .smh-name { font-family: 'Rye', serif; color: var(--heading); font-size: 21px; }
.single-mode-hero .smh-meta { font-size: 12px; color: var(--smoke); margin-top: 3px; }
.mode-info-list {
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.mode-info-card {
  display: flex;
  gap: 14px;
  padding: 14px;
  background: var(--surface-1);
  border: 1px solid var(--border-soft);
  border-radius: 4px;
}
.mode-info-card.is-highlighted {
  border-color: var(--gold);
  background: rgba(200,146,42,.06);
}
.mode-info-icon {
  font-size: 32px;
  line-height: 1;
  flex-shrink: 0;
}
.mode-info-text {
  flex: 1;
}
.mode-info-name {
  font-family: 'Rye', cursive;
  font-size: 16px;
  color: var(--gold);
  margin: 0 0 6px 0;
  display: flex;
  align-items: center;
  gap: 10px;
}
.mode-info-current {
  font-size: 12px;
  color: var(--heading);
  background: rgba(200,146,42,.18);
  padding: 2px 8px;
  border-radius: 10px;
  font-weight: normal;
  letter-spacing: 0.02em;
}
.mode-info-desc {
  font-size: 13px;
  color: var(--parchment);
  margin: 0 0 6px 0;
  line-height: 1.5;
}
.mode-info-meta {
  font-size: 12px;
  color: var(--smoke);
}

/* ── Quiz mode pills (only visible when music quiz is selected) ──────────────── */
.quiz-mode-pills {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}
.quiz-pill {
  padding: 8px 16px;
  /* Semantic tokens: --mid-wood is a raw dark constant and stayed pitch dark in
     the light theme (found on Admin → Einrichtung); the island re-pin keeps the
     pill dark inside game surfaces. */
  background: var(--surface-2);
  border: 1px solid var(--border-soft);
  color: var(--text-main);
  border-radius: 20px;
  font-size: 13px;
  cursor: pointer;
  transition: all .15s;
  white-space: nowrap;
}
.quiz-pill:not(:disabled):hover {
  border-color: var(--accent);
  color: var(--heading);
}
.quiz-pill.selected {
  background: rgba(200,146,42,.15);
  border-color: var(--accent-strong);
  color: var(--heading);
}
/* Invalid option (e.g. answer delay >= time per track) - not selectable. */
.quiz-pill:disabled {
  opacity: .3;
  cursor: not-allowed;
  filter: grayscale(.6);
}

/* ── Profile: statistics display ────────────────────────────────────────── */
.stats-summary {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 8px;
  margin-bottom: 18px;
}
.stats-summary-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  background: var(--surface-2);
  border: 1px solid var(--border-soft);
  border-radius: 5px;
  padding: 10px 8px;
  text-align: center;
}
.stats-summary-value {
  font-family: 'Rye', cursive;
  color: var(--heading);
  font-size: 18px;
  margin-bottom: 2px;
}
.stats-summary-label {
  color: var(--smoke);
  font-size: 12px;
  letter-spacing: 0.05em;
}

/* Mode cards in a 2-column grid, single column on narrow screens. */
.stats-mode-grid-2col {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 10px;
}
@media (max-width: 560px) {
  .stats-mode-grid-2col { grid-template-columns: 1fr; }
}
.stats-mode-card {
  background: var(--surface-1);
  border: 1px solid var(--border-soft);
  border-radius: 6px;
  padding: 12px 14px;
  margin-bottom: 0;
}
.stats-mode-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 8px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--border-soft);
}
.stats-mode-name {
  /* --heading instead of the raw mode accent as TEXT (mockup a11y decision +
     convention_accent_light_never_as_text — unreadable on light surfaces). */
  font-family: 'Rye', cursive;
  color: var(--heading);
  font-size: 15px;
}
.stats-mode-played {
  font-size: 12px;
  color: var(--smoke);
}
.stats-mode-grid {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.stats-row {
  display: flex;
  justify-content: space-between;
  font-size: 13px;
}
.stats-row-label {
  color: var(--smoke);
}
.stats-row-value {
  color: var(--old-paper);
  font-variant-numeric: tabular-nums;
}
.stats-pct {
  color: var(--smoke);
  font-size: 12px;
  margin-left: 4px;
}

@media (max-width: 540px) {
  .stats-summary { grid-template-columns: repeat(2, 1fr); }
}

/* ── Achievement gallery (profile tab "Achievements") ────────────────── */
/* 2-column badge grid mirroring .stats-mode-grid-2col; fixed icon column. */
.ach-subheading {
  font-family: 'Rye', cursive;
  color: var(--heading);
  font-size: 15px;
  margin: 16px 0 8px;
}
.ach-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 10px;
}
@media (max-width: 560px) {
  .ach-grid { grid-template-columns: 1fr; }
}
.ach-card {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  background: var(--surface-1);
  border: 1px solid var(--border-soft);
  border-radius: 6px;
  padding: 12px 14px;
}
.ach-card.unlocked {
  border-color: var(--border-strong);
  background: var(--surface-2);
}
.ach-icon {
  font-size: 26px;
  line-height: 1.2;
  width: 34px;
  text-align: center;
  flex: 0 0 auto;
}
.ach-card.locked .ach-icon { filter: grayscale(1); opacity: 0.55; }
.ach-body { flex: 1 1 auto; min-width: 0; }
.ach-title {
  font-family: 'Rye', cursive;
  font-size: 14px;
  color: var(--heading);
}
.ach-card.locked .ach-title { color: var(--old-paper); }
.ach-desc {
  font-size: 12px;
  color: var(--smoke);
  margin-top: 2px;
  line-height: 1.35;
}
.ach-date {
  font-size: 12px;
  color: var(--smoke);
  margin-top: 6px;
}
.ach-progress {
  margin-top: 8px;
  display: flex;
  align-items: center;
  gap: 8px;
}
.ach-bar {
  flex: 1 1 auto;
  height: 5px;
  background: var(--surface-2);
  border-radius: 3px;
  overflow: hidden;
}
.ach-bar-fill {
  height: 100%;
  background: var(--gold);
  border-radius: 3px;
}
.ach-progress-text {
  font-size: 12px;
  color: var(--smoke);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* ── Footer (privacy policy / imprint links) ───────────────────────────────── */
.app-footer {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 900;
  text-align: center;
  padding: 12px 16px;
  font-size: 12px;
  color: var(--text-dim);
  border-top: 1px solid var(--border-soft);
  background: var(--chrome);
  backdrop-filter: blur(6px);
}
.footer-link {
  color: var(--smoke);
  text-decoration: none;
  transition: color 0.15s;
}
.footer-link:hover {
  color: var(--gold);
}
.footer-sep {
  margin: 0 8px;
  opacity: 0.4;
}

/* ── Language dropdown (header + profile) ─────────────────────────────
   Replaces the former segmented footer switcher. Trigger = pill with the
   current flag + chevron (styled like .header-help-btn/.profile-btn);
   expanded it shows a list (flag + native name), backdrop to close. */
.lang-dd { position: relative; display: inline-flex; }
.lang-dd-trigger {
  position: relative;
  z-index: 1001;      /* above the backdrop */
  display: inline-flex;
  align-items: center;
  gap: 5px;
  height: 38px;
  padding: 0 9px;
  border-radius: 19px;
  background: var(--surface-1);
  border: 1px solid var(--border-strong);
  color: var(--heading);
  cursor: pointer;
  transition: all .2s;
}
.lang-dd-trigger:hover {
  border-color: var(--gold);
  background: var(--surface-hover);
}
.lang-dd-flag {
  display: block;
  height: 15px;
  width: auto;
  border-radius: 2px;
  /* Theme-aware contour ring: flag stripes that match the surface (black stripe
     of the DE flag on the dark menu, white UK areas on light surfaces) would
     otherwise melt into the background and make the flag look smaller/misaligned. */
  box-shadow: 0 0 0 1px var(--border-strong);
}
/* In the expanded list use a FIXED UNIFORM FLAG BOX (24x15 + cover) instead of a
   height-based width - otherwise names start at different x positions and the
   flags render at different heights depending on the flag's aspect ratio
   (DE 5:3 vs. UK 2:1), which reads as "not aligned". Cover crops the wider
   ratios slightly (centered), which keeps every flag recognizable. */
.lang-dd-opt .lang-dd-flag {
  width: 24px;
  height: 15px;
  object-fit: cover;
}
.lang-dd-chev {
  font-size: 12px;
  line-height: 1;
  color: var(--heading);
  transition: transform .2s;
}
.lang-dd.open .lang-dd-chev { transform: rotate(180deg); }

.lang-dd-menu {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  min-width: 170px;
  /* The footer dropup inherits .app-footer's text-align:center — the names
     would center within different leftover widths (the active row also holds
     the ✓) and end up visually staggered. */
  text-align: left;
  background: var(--surface-1-strong);
  border: 1px solid var(--border-strong);
  border-radius: 8px;
  z-index: 1000;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.6);
  backdrop-filter: blur(4px);
  overflow: hidden;
}
.lang-dd-opt {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  color: var(--old-paper);
  text-decoration: none;
  font-size: 13px;
}
.lang-dd-opt:hover { background: var(--surface-hover); color: var(--heading); }
.lang-dd-opt.active {
  background: rgba(200, 146, 42, 0.14);
  color: var(--heading);
}
.lang-dd-name { flex: 1; }
.lang-dd-check { color: var(--heading); font-size: 12px; }

/* Footer variant (MainLayout footer): trigger looks like a plain footer link
   (globe + native name), the menu opens UPWARD since the footer sits at the
   page bottom. Used via <LanguageDropdown Footer="true" />. */
.lang-dd-footer .lang-dd-trigger {
  height: auto;
  min-height: 24px;   /* WCAG 2.5.8 minimum target size */
  padding: 2px 4px;
  gap: 6px;
  border: none;
  border-radius: 4px;
  background: none;
  color: var(--text-dim);
  font-size: 12.5px;
}
.lang-dd-footer .lang-dd-trigger:hover { color: var(--heading); background: none; border: none; }
.lang-dd-footer .lang-dd-current { line-height: 1; }
.lang-dd-footer .lang-dd-menu {
  top: auto;
  bottom: calc(100% + 8px);
  right: auto;
  left: 50%;
  transform: translateX(-50%);
  box-shadow: 0 -6px 24px var(--shadow-color);
}

/* Profile variant: the 🌐 label sits on the left, the dropdown opens below.
   To prevent the menu from overflowing the right card edge it stays
   right-aligned to the trigger (default above). */

/* ── Legal pages (privacy policy, imprint) ───────────────────────────────── */
/* Legal pages now live inside the PageFrame board (narrow width) — the class
   only provides typography, no own container/frame anymore. */
.legal-page {
  color: var(--old-paper);
  line-height: 1.6;
}
.legal-page h2 {
  font-family: 'Rye', cursive;
  color: var(--heading);
  font-size: 18px;
  margin-top: 26px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--border-soft);
}
.legal-page h2:first-child { margin-top: 0; }
.legal-page h3 {
  font-family: 'Rye', cursive;
  color: var(--heading);
  font-size: 14px;
  margin-top: 18px;
}
.legal-page p { font-size: 14px; }
.legal-page ul { padding-left: 22px; font-size: 14px; }
.legal-page li { margin-bottom: 5px; }
.legal-page a {
  color: var(--heading);
  text-decoration: underline;
}
.legal-block {
  background: var(--surface-2);
  border-left: 2px solid var(--gold);
  padding: 12px 16px;
  margin: 12px 0;
}
.legal-footer {
  margin-top: 30px;
  color: var(--smoke);
  font-size: 12px;
  text-align: right;
}
/* Notice of precedence on the EN version of the legal texts. */
.legal-translation-notice {
  background: var(--surface-2);
  border-left: 2px solid var(--smoke);
  padding: 10px 14px;
  margin: 0 0 18px;
  color: var(--smoke);
  font-size: 13px;
}

/* ── Home page announcement banner ───────────────────────────────── */
.announce {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  border-radius: 5px;
  padding: 12px 16px;
  margin-bottom: 16px;
  font-size: 14px;
  line-height: 1.5;
  border-left: 4px solid;
}
.announce-icon { font-size: 18px; line-height: 1.3; flex-shrink: 0; }
.announce-body { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.announce.announce-info  { background: rgba(60,120,180,.12);  border-left-color: #5a9bd4; color: #cfe3f5; }
.announce.announce-warn  { background: rgba(212,160,30,.12);  border-left-color: var(--gold); color: #f0dca0; }
.announce.announce-error { background: rgba(139,26,26,.16);   border-left-color: #c0392a; color: #f0c0b8; }
/* Light theme: the banner texts above are LIGHT tints — unreadable on the
   light scrim. Swap to dark variants of the same level colors. */
[data-theme="light"] .announce.announce-info  { color: #1e4e78; }
[data-theme="light"] .announce.announce-warn  { color: #6a4a08; background: rgba(181, 84, 10, .12); }
[data-theme="light"] .announce.announce-error { color: #7a2338; }

/* ── Error page /Error ───────────────────────────────────────────── */
.error-page-text {
  color: var(--old-paper);
  font-size: 14px;
  line-height: 1.6;
  text-align: center;
  margin: 8px 0;
}
.error-page-hint { color: var(--smoke); font-size: 13px; }
.error-page-actions {
  display: flex;
  justify-content: center;
  margin-top: 18px;
}

/* ── Changelog / What's new ──────────────────────────────────────────────── */
/* Lives inside the PageFrame board (narrow width) — no own container anymore. */
.changelog-sub {
  color: var(--smoke);
  font-size: 13px;
  margin: 0 0 26px;
}
.changelog-empty {
  color: var(--smoke);
  font-style: italic;
  padding: 12px 0;
}
.changelog-timeline {
  margin-top: 4px;
}
.cl-entry {
  position: relative;
  padding: 0 0 22px 22px;
  border-left: 2px solid rgba(200, 146, 42, 0.25);
  margin-left: 6px;
}
.cl-entry:last-child {
  border-left-color: transparent;
  padding-bottom: 0;
}
.cl-entry::before {
  content: '';
  position: absolute;
  left: -7px;
  top: 4px;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--gold);
  box-shadow: 0 0 0 3px #14100c;
}
.cl-entry.latest::before {
  background: var(--amber);
  box-shadow: 0 0 0 3px #14100c, 0 0 10px rgba(212, 98, 10, 0.6);
}
.cl-head {
  display: flex;
  align-items: baseline;
  gap: 12px;
  margin-bottom: 8px;
  flex-wrap: wrap;
}
.cl-version {
  font-family: 'Rye', cursive;
  color: var(--heading);
  font-size: 16px;
}
.cl-badge-new {
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: #f0a060;
  border: 1px solid rgba(212, 98, 10, 0.5);
  background: rgba(212, 98, 10, 0.12);
  border-radius: 10px;
  padding: 1px 8px;
}
.cl-date {
  color: var(--smoke);
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  margin-left: auto;
}
.cl-entry-title {
  color: var(--parchment);
  font-weight: 600;
  font-size: 15px;
  margin-bottom: 8px;
}
.cl-body {
  color: var(--old-paper);
  font-size: 13.5px;
  line-height: 1.6;
}
.cl-body strong { color: var(--heading); font-weight: 600; }
.cl-body ul { margin: 4px 0 12px; padding-left: 20px; }
.cl-body li { margin: 3px 0; }
.cl-body p { margin: 6px 0; }
.cl-body a { color: var(--gold); text-decoration: underline; }
/* Headings tamed - a changelog entry already has its own title,
   a markdown H1 should not blow up the card. */
.cl-body h1, .cl-body h2, .cl-body h3, .cl-body h4 {
  font-family: 'Rye', cursive;
  color: var(--gold-light);
  margin: 10px 0 4px;
  line-height: 1.3;
}
.cl-body h1 { font-size: 16px; }
.cl-body h2 { font-size: 15px; }
.cl-body h3, .cl-body h4 { font-size: 13.5px; }
.cl-body h1:first-child, .cl-body h2:first-child, .cl-body h3:first-child { margin-top: 0; }
.cl-body code {
  font-family: 'Courier New', monospace;
  font-size: 12px;
  color: var(--gold-light);
  background: rgba(200, 146, 42, 0.08);
  padding: 1px 4px;
  border-radius: 2px;
}

/* ── Profile: danger zone ─────────────────────────────────────────────── */
.profile-danger-title {
  color: var(--danger) !important;
}
.btn-flex1 { flex: 1; }

/* ── Player name clickable ───────────────────────────────────────────────── */
.p-name-clickable {
  cursor: pointer;
  transition: color 0.15s;
  text-decoration: underline;
  text-decoration-color: rgba(200, 146, 42, 0.25);
  text-underline-offset: 3px;
}
.p-name-clickable:hover {
  color: var(--gold-ink);
  text-decoration-color: var(--gold-ink);
}

/* ── Player profile modal — body classes (wrapper migrated to <Modal> component) ──── */
.player-profile-info {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.player-profile-row {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  padding: 6px 0;
  font-size: 13px;
  border-bottom: 1px solid rgba(200, 146, 42, 0.08);
}
.player-profile-row:last-child { border-bottom: none; }
.player-profile-label {
  color: var(--smoke);
}
.player-profile-value {
  color: var(--old-paper);
  text-align: right;
}
.player-profile-banned { color: var(--danger); }
.player-profile-banned small { color: var(--text-dim); margin-left: 4px; }
.player-profile-role {
  display: inline-block;
  background: rgba(200, 146, 42, 0.12);
  border: 1px solid rgba(200, 146, 42, 0.3);
  border-radius: 3px;
  padding: 1px 6px;
  margin-left: 4px;
  font-size: 12px;
  color: var(--heading);
}
.player-profile-divider {
  border: none;
  border-top: 1px solid rgba(200, 146, 42, 0.15);
  margin: 16px 0 12px;
}
.player-profile-mod {
  background: rgba(139, 26, 26, 0.08);
  border: 1px solid rgba(139, 26, 26, 0.25);
  border-radius: 4px;
  padding: 12px;
}
.player-profile-mod .lbl {
  display: block;
  margin-bottom: 4px;
  font-size: 12px;
  color: var(--smoke);
}
.player-profile-mod .inp { margin-bottom: 10px; }
.player-profile-mod-actions {
  display: flex;
  gap: 8px;
  margin-top: 8px;
}

/* Base of .btn-ghost-red/.btn-red was merged upward into the leading
   .btn-* definitions preserving computed values - only states not yet
   duplicated there remain here (disabled + hover background). */
.btn-ghost-red:disabled { opacity: 0.5; cursor: not-allowed; }

.btn-red:hover { background: linear-gradient(135deg, #a02020, #6a1010); }
.btn-red:disabled { opacity: 0.5; cursor: not-allowed; }

/* ── Recent-games history in the profile (cards in .lg-games) ──────── */
.history-card-compact {
  background: var(--surface-1);
  border: 1px solid var(--border-soft);
  border-left-width: 4px;
  border-radius: 3px;
  padding: 10px 14px;
  font-size: 13px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.history-card-compact.history-outcome-won { border-left-color: rgba(80, 180, 80, 0.7); }
.history-card-compact.history-outcome-lost { border-left-color: rgba(180, 60, 60, 0.7); }
.history-card-compact.history-outcome-draw { border-left-color: rgba(180, 160, 80, 0.55); }

.history-card-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 10px;
}
.history-card-mode {
  font-family: 'Rye', cursive;
  color: var(--accent-light);
  font-size: 14px;
  letter-spacing: 0.04em;
}
.history-card-outcome {
  font-size: 13px;
  padding: 2px 8px;
  border-radius: 2px;
}
.history-outcome-won  .history-card-outcome { background: rgba(80,180,80,.12);  color: #88d088; }
.history-outcome-lost .history-card-outcome { background: rgba(180,60,60,.12);  color: #e88080; }
.history-outcome-draw .history-card-outcome { background: rgba(180,160,80,.12); color: #d8c878; }

.history-card-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  color: var(--smoke);
  font-size: 12px;
}
.history-card-meta > span { white-space: nowrap; }
.history-role-impostor { color: #e88080; }
.history-role-crewmate { color: #88d088; }
.history-word-inline {
  font-family: 'Rye', cursive;
  color: var(--gold);
  letter-spacing: 0.06em;
}

.history-card-coplayers {
  font-size: 12px;
  color: rgba(220, 200, 170, 0.65);
}
.history-card-label {
  color: var(--smoke);
  margin-right: 4px;
}

/* Light: the history outcome badges (won / lost / „geteilt"), the ✓/✗ result marks and the
   Schattenspiel roles use bright colors tuned for the dark card; on the pale history/modal
   they wash out. Switch to the theme's readable inks; the solo/co-player line likewise moves
   off its hardcoded pale beige. Dark keeps its calibrated tones. */
[data-theme="light"] .history-outcome-won  .history-card-outcome,
[data-theme="light"] .track-history-res.res-ok,
[data-theme="light"] .history-role-crewmate,
[data-theme="light"] .lg-wins { color: var(--success); }
[data-theme="light"] .history-outcome-lost .history-card-outcome,
[data-theme="light"] .track-history-res.res-no,
[data-theme="light"] .history-role-impostor { color: var(--danger); }
[data-theme="light"] .history-outcome-draw .history-card-outcome { color: var(--gold-ink); }
[data-theme="light"] .history-card-coplayers { color: var(--text-dim); }

/* ── Lobby grouping in profile history ──────────────────────────
   "Recent games" grouped per lobby session: collapsed headers, click lazily
   loads the games (history-card-compact, defined above) into .lg-games. */
.lobby-group-list { display: flex; flex-direction: column; gap: 10px; margin-bottom: 10px; }
.lobby-group {
  background: var(--surface-1);
  border: 1px solid var(--border-soft);
  border-radius: 4px;
  overflow: hidden;
}
.lobby-group-header {
  display: flex; align-items: center; gap: 12px;
  padding: 11px 14px; cursor: pointer; transition: background .12s;
}
.lobby-group-header:hover { background: rgba(200, 146, 42, 0.06); }
.lg-chevron {
  color: var(--smoke); font-size: 16px; flex-shrink: 0;
  width: 14px; text-align: center; transition: transform .15s;
}
.lobby-group.open .lg-chevron { transform: rotate(90deg); color: var(--accent-light); }
/* Fixed icon zone (like .lg-chevron) so the title always starts at the same x, no matter
   whether the mode glyph is narrow (♠) or wide (⚓/🧠). */
.lg-icons { font-size: 16px; flex-shrink: 0; width: 22px; text-align: center; }
.lg-main { flex: 1; min-width: 0; }
.lg-title {
  font-family: 'Rye', cursive; color: var(--accent-ink);
  font-size: 14px; letter-spacing: .03em;
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
}
.lg-code { color: var(--smoke); font-size: 12px; letter-spacing: .04em; }
.lg-meta { display: flex; flex-wrap: wrap; gap: 6px; color: var(--smoke); font-size: 12px; margin-top: 3px; }
.lg-meta .sep { opacity: .5; }
.lg-wins { color: #88d088; }
.lg-when { flex-shrink: 0; color: var(--smoke); font-size: 12px; white-space: nowrap; }
.lg-games {
  border-top: 1px dashed rgba(200, 146, 42, 0.15);
  padding: 10px 14px 12px 32px;
  display: flex; flex-direction: column; gap: 7px;
  background: var(--surface-2);
}
.lg-loading { color: var(--smoke); font-size: 12px; font-style: italic; padding: 4px 0; }

/* ── Game detail in the profile (clickable co-players + track history) ── */
/* List cards become clickable (open the detail view). */
.history-card-clickable {
  cursor: pointer;
  position: relative;
  padding-right: 30px;
  transition: border-color .15s, transform .05s;
}
.history-card-clickable:hover { border-color: rgba(200, 146, 42, 0.4); }
.history-card-clickable:active { transform: scale(.998); }
.history-card-chevron {
  position: absolute;
  right: 12px;
  top: 50%;
  transform: translateY(-50%);
  color: var(--smoke);
  font-size: 18px;
  opacity: .5;
}
@media (hover: hover) {
  .history-card-clickable:hover .history-card-chevron {
    opacity: 1;
    color: var(--accent-light);
  }
}

/* Detail view (variant B: pane swap within the same modal) */
.btn-back-history {
  background: none;
  border: none;
  color: var(--accent-light);
  font-family: inherit;
  font-size: 13px;
  cursor: pointer;
  padding: 2px 0;
  margin-bottom: 12px;
}
.btn-back-history:hover { color: var(--parchment); }

.partie-detail { display: flex; flex-direction: column; }
.partie-detail-hero {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 10px;
  margin-bottom: 6px;
}
.partie-detail-hero .history-card-mode { font-size: 17px; }
.partie-detail-meta { margin-bottom: 4px; }
.partie-detail-section {
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px dashed rgba(200, 146, 42, 0.18);
}
.partie-detail-sub {
  font-family: 'Rye', cursive;
  color: var(--gold);
  font-size: 12px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  margin-bottom: 8px;
}
.partie-detail-coplayers { font-size: 13px; line-height: 1.9; }
.coplayer-link {
  color: var(--gold-light);
  cursor: pointer;
  border-bottom: 1px dotted rgba(232, 184, 75, 0.45);
}
.coplayer-link:hover { color: var(--parchment); border-bottom-color: var(--parchment); }
.coplayer-guest { color: rgba(220, 200, 170, 0.55); }
.coplayer-guest-mark { font-size: 12px; opacity: .7; margin-left: 2px; }
.coplayer-sep { color: var(--smoke); }

.track-history-list { display: flex; flex-direction: column; gap: 3px; }
.track-history-row {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 6px 9px;
  border-radius: 3px;
  background: var(--surface-1);
  border: 1px solid var(--border-soft);
  font-size: 12.5px;
}
.track-history-clickable { cursor: pointer; transition: border-color .15s, background .15s; }
.track-history-clickable:hover { border-color: rgba(200, 146, 42, 0.4); background: var(--surface-hover); }
.track-history-ord {
  color: var(--smoke);
  width: 20px;
  text-align: right;
  font-variant-numeric: tabular-nums;
  flex: none;
}
.track-history-main { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.track-history-artist { color: var(--parchment); }
.track-history-title { color: var(--smoke); }
.track-history-genre {
  font-size: 12px;
  color: var(--smoke);
  background: rgba(200, 146, 42, 0.08);
  padding: 1px 8px;
  border-radius: 10px;
  white-space: nowrap;
  flex: none;
}
.track-history-res { width: 18px; text-align: center; font-size: 13px; flex: none; }
.track-history-res.res-ok { color: #88d088; }
.track-history-res.res-no { color: #e88080; }

/* ── Card hands in history (Durak/Skat/Doppelkopf/Poker) ── */
.hand-history-list { display: flex; flex-direction: column; gap: 6px; }
.hand-history-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; padding: 5px 2px; border-bottom: 1px solid rgba(200, 146, 42, 0.08); }
.hand-history-row:last-child { border-bottom: none; }
.hand-history-who { width: 120px; flex: 0 0 auto; font-size: 13px; color: var(--parchment); }
.hand-history-cards { display: flex; gap: 4px; flex-wrap: wrap; align-items: center; }
.hand-extra { display: flex; align-items: center; gap: 4px; margin-left: 6px; padding-left: 10px; border-left: 1px solid rgba(200, 146, 42, 0.18); }
.extra-lbl { font-size: 12px; color: var(--smoke); text-transform: uppercase; letter-spacing: 0.04em; }
.deal-tabs { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 10px; }
.deal-chip { font-size: 12px; color: var(--smoke); background: var(--surface-2); border: 1px solid var(--border); padding: 3px 11px; border-radius: 999px; cursor: pointer; transition: 0.15s; }
.deal-chip:hover { border-color: color-mix(in srgb, var(--accent) 50%, transparent); color: var(--parchment); }
.deal-chip.active { background: color-mix(in srgb, var(--accent) 24%, transparent); color: var(--heading); border-color: color-mix(in srgb, var(--accent) 55%, transparent); }

/* ── Battleship boards in history ── */
.board-history-gallery { display: flex; gap: 16px; flex-wrap: wrap; }
.board-history-item { display: flex; flex-direction: column; gap: 6px; }
.board-history-cap { font-size: 13px; color: var(--parchment); }

/* ── Memory board in history (symbol + revealer color) ── */
.mem-history-grid { display: grid; grid-template-columns: repeat(8, 1fr); gap: 5px; max-width: 360px; }
.mem-history-card { aspect-ratio: 3 / 4; border-radius: 5px; display: grid; place-items: center;
  background: radial-gradient(ellipse at 30% 20%, rgba(120, 80, 35, 0.12) 0 30%, transparent 55%), linear-gradient(155deg, #f6ead0, #dec79c);
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4), inset 0 0 0 2px var(--pc, #999); }
.mem-history-ic { width: 64%; height: 64%; color: #5a3a1a; }
.mem-history-legend { display: flex; gap: 14px; flex-wrap: wrap; margin-top: 10px; font-size: 12px; }
.mem-history-legend span { display: inline-flex; align-items: center; gap: 6px; color: var(--parchment); }
.mem-history-legend i { width: 13px; height: 13px; border-radius: 3px; display: inline-block; }

/* Discord brand accent for the OAuth button */
.btn-discord:hover {
  border-color: #5865f2;
  background: rgba(88, 101, 242, 0.12);
}
.btn-discord .oauth-icon { color: #5865f2; }

/* ── Linked accounts in the profile ──────────────────────────────────────── */
.linked-accounts {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.linked-account-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  padding: 10px 14px;
  background: var(--surface-1);
  border: 1px solid var(--border-soft);
  border-radius: 3px;
}
.linked-account-info {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}
.linked-account-name {
  color: var(--old-paper);
  font-size: 14px;
}
.linked-account-status {
  font-size: 12px;
  color: var(--success);   /* theme-aware — the old hardcoded #88d088 was unreadable in light */
}
.linked-account-status-off {
  color: var(--smoke);
}
/* Link/unlink button in the linked-account row: more compact than the
   default saloon button. Default `.btn` has width:100%, text-transform:uppercase,
   font-size:15px, letter-spacing:.12em - everything adds up to a wide
   button that wraps the info column. Trim everything to content width here. */
.linked-account-row .btn-sm-action {
  flex: 0 0 auto;
  width: auto !important;
  display: inline-block;
  padding: 5px 12px !important;
  font-size: 12px !important;

  letter-spacing: .04em !important;
  text-transform: none !important;
}
.linked-account-username {
  color: var(--smoke);   /* theme-aware secondary — no alpha, the old rgba(...,.6) washed out in both themes */
  font-style: italic;
  margin-left: 4px;
  font-size: 12px;
}

/* Steam brand accent for the OAuth button (Steam blue) */
.btn-steam:hover {
  border-color: #66c0f4;
  background: rgba(102, 192, 244, 0.12);
}
.btn-steam .oauth-icon { color: #66c0f4; }

/* ── Email verification: banner in the profile ─────────────────────────────── */
.verify-banner {
  display: flex;
  flex-direction: column;
  gap: 10px;
  align-items: stretch;
}
.verify-banner-text { line-height: 1.5; }
.verify-banner code {
  background: var(--surface-2);
  padding: 1px 6px;
  border-radius: 2px;
  font-size: 0.9em;
}
.alert-warning {
  background: rgba(180, 140, 30, 0.12);
  border: 1px solid rgba(220, 180, 80, 0.4);
  color: #e8c878;
  padding: 12px 14px;
  border-radius: 4px;
  margin-bottom: 14px;
  font-size: 13px;
}
.email-verified {
  color: var(--success);   /* theme-aware — hardcoded #88d088 was 4.2:1 in light */
  margin-left: 6px;
  font-weight: bold;
}
.email-unverified {
  color: var(--amber);
  margin-left: 6px;
  font-size: 12px;
}
.btn-sm {
  padding: 5px 12px;
  font-size: 12px;
  border-radius: 3px;
}

/* Genre chips (lobby music quiz settings) */
/* ── Filter bar (trigger pills) + shared panel ──
   Replaces the stacked filter-collapsible boxes. Works on desktop + mobile. */
.filterbar { display: flex; gap: 10px; flex-wrap: wrap; margin: 4px 0 2px; }
.filter-trigger {
  display: flex; align-items: center; gap: 8px; min-width: 150px; cursor: pointer;
  background: var(--surface-2); border: 1px solid var(--border); border-radius: 10px;
  padding: 9px 14px; color: var(--parchment); font: inherit; text-align: left;
}
.filter-trigger:hover { border-color: color-mix(in srgb, var(--accent) 45%, transparent); }
.filter-trigger.active { border-color: color-mix(in srgb, var(--accent) 60%, transparent); background: color-mix(in srgb, var(--accent) 12%, transparent); }
.filter-trigger .ft-ic { font-size: 15px; flex: 0 0 auto; }
.filter-trigger .ft-name { font-size: 13px; color: var(--parchment); }
.filter-trigger .ft-val { margin-left: auto; font-size: 12px; color: var(--smoke); }
.filter-trigger.has-sel .ft-val { color: var(--accent-light); font-weight: 600; }
.filter-trigger .ft-chev { color: var(--smoke); font-size: 12px; transition: transform .15s; flex: 0 0 auto; }
.filter-trigger.active .ft-chev { transform: rotate(180deg); }
.filter-panel {
  background: var(--surface-1); border: 1px solid color-mix(in srgb, var(--accent) 35%, transparent);
  border-radius: 12px; padding: 14px; margin: 10px 0 4px;
}
.filter-panel .filter-pop-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 10px; }
.filter-panel .fp-title { font-size: 12px; letter-spacing: .08em; text-transform: uppercase; color: var(--gold); }
.filter-panel .fp-clear { font-size: 12px; color: var(--smoke); cursor: pointer; background: none; border: none; padding: 2px 4px; }
.filter-panel .fp-clear:hover { color: var(--accent-light); }
.filter-panel .fp-done {
  margin-top: 12px; width: 100%; padding: 8px; border-radius: var(--btn-radius); cursor: pointer; font: inherit;
  border: 1px solid var(--border); background: color-mix(in srgb, var(--accent) 18%, transparent); color: var(--parchment);
}
.filter-panel .fp-done:hover { background: color-mix(in srgb, var(--accent) 28%, transparent); }

.genre-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  padding: 6px;
  background: var(--surface-2);
  border-radius: 4px;
  border: 1px solid var(--border-soft);
  max-height: 140px;
  overflow-y: auto;
}
.genre-chip {
  padding: 5px 11px;
  font-size: 12px;
  border-radius: 999px;
  background: transparent;
  border: 1px solid color-mix(in srgb, var(--text-main) 55%, transparent);
  color: var(--text-main);
  cursor: pointer;
  transition: all 0.12s ease;
  font-family: inherit;
}
.genre-chip:hover {
  background: var(--surface-hover);
  border-color: var(--accent);
}
.genre-chip.selected {
  background: linear-gradient(135deg, #d4620a, #f0a020);
  border-color: #f0a020;
  color: #1a0e05;
  font-weight: 600;
}
.genre-chip-count {
  margin-left: 4px;
  padding: 1px 6px;
  font-size: 12px;
  font-weight: 400;
  background: var(--surface-2);
  border-radius: 999px;
  vertical-align: middle;
}
.genre-chip.selected .genre-chip-count {
  background: rgba(0,0,0,0.18);
}

/* Music quiz difficulty chips use their traffic-light color when active
   (A green / B gold / C red) instead of the default orange. */
.genre-chip.tier-chip-A.selected {
  background: linear-gradient(135deg, #3f8f59, #5fb87e);
  border-color: #5fb87e;
  color: #08140c;
}
.genre-chip.tier-chip-B.selected {
  background: linear-gradient(135deg, #d4880a, #f0bd20);
  border-color: #f0bd20;
  color: #1a1205;
}
.genre-chip.tier-chip-C.selected {
  background: linear-gradient(135deg, #b04535, #d4685a);
  border-color: #d4685a;
  color: #1a0a08;
}

/* Framed quiz panel: the question + answers sit in a defined card instead of floating
   on the (visually near-invisible) card-board. Both quiz games share .mq-card, so
   Musikquiz + Wissensquiz stay consistent. Saloon-gold border — never the game accent
   (panel borders rule). Overrides the generic ".card-board .card" frame-strip; the width
   still fills the main column (maximized keeps max-width:none) so the frame hugs the real
   quiz area without shrinking it. */
.card-board .card.mq-card {
  background: linear-gradient(135deg, var(--board-grad-a), var(--board-grad-b));
  border: 1px solid var(--board-border);
  border-radius: 6px;
  box-shadow: var(--board-shadow);
  padding: 22px 26px;
}

/* Same Saloon-gold frame for the remaining floating game surfaces: Hangman AND
   Tabu share .hangman-word-card, Memory uses .memory-board-card. Extends the
   SS-0320 quiz treatment so nothing floats loosely on the near-invisible
   card-board. Border is Saloon gold (--board-border), never the mode accent
   (panel-borders rule); each card keeps its own padding. */
.card-board .card.hangman-word-card,
.card-board .card.memory-board-card {
  background: linear-gradient(135deg, var(--board-grad-a), var(--board-grad-b));
  border: 1px solid var(--board-border);
  border-radius: 6px;
  box-shadow: var(--board-shadow);
}

@keyframes mq-cover-pulse {
  0%, 100% { box-shadow: 0 8px 24px rgba(0,0,0,0.5), inset 0 0 30px rgba(0,0,0,0.4), 0 0 24px color-mix(in srgb, var(--accent) 30%, transparent); }
  50%      { box-shadow: 0 8px 24px rgba(0,0,0,0.5), inset 0 0 30px rgba(0,0,0,0.4), 0 0 40px 8px color-mix(in srgb, var(--accent-light) 45%, transparent); }
}

@keyframes mq-eq {
  0%, 100% { transform: scaleY(0.4); }
  50%      { transform: scaleY(1.0); }
}
/* Hover-only, guarded by the pointer capability: on a touch screen :hover STICKS after a
   tap. The 1px lift then applies while tapping and is dropped the moment the option turns
   disabled — the button visibly settles back over the 150ms transition, which reads as the
   quiz "jumping" right after answering. Devices with a real pointer are unaffected. */


/* Mobile: stack answer options in a single column */

.mq-cat-panel > * { position: relative; z-index: 1; }
@keyframes mq-cat-pulse { 0%, 100% { opacity: .5; } 50% { opacity: 1; } }
.mqi-category > * { position: relative; }

/* Apple Music deep link in the music quiz break + podium */
.apple-music-link {
  display: inline-block;
  margin-top: 10px;
  padding: 5px 12px;
  font-size: 12px;
  color: var(--smoke);
  text-decoration: none;
  border: 1px solid var(--edge-strong);
  border-radius: 999px;
  transition: all 0.15s ease;
}
.apple-music-link:hover {
  color: var(--gold-ink);
  border-color: var(--gold-ink);
  background: rgba(212,98,10,0.08);
}
.apple-music-link-inline {
  margin-left: 6px;
  font-size: 12px;
  text-decoration: none;
  opacity: 0.55;
  transition: opacity 0.12s ease;
}
@media (hover: hover) {
  .apple-music-link-inline:hover {
    opacity: 1;
  }
}

/* Clickable settings values (e.g. "13 categories ›") */
.settings-value-link {
  color: var(--heading);
  background: none;
  border: 0;
  padding: 0;
  margin: 0;
  font: inherit;
  cursor: pointer;
  text-align: right;
  text-decoration: underline dotted rgba(212,98,10,0.4);
  text-underline-offset: 3px;
  transition: color 0.12s ease;
}
.settings-value-link:hover {
  color: var(--gold-ink);
  text-decoration-color: var(--gold-ink);
}

/* Modal for category filter overview (small popup) */
.category-filter-modal {
  max-width: 420px;
  width: 90%;
  margin: 0 auto;
  padding: 0;
}
.category-filter-modal-body {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  padding: 16px 18px 20px;
}

/* ── Dual-range slider ─────────────────────────────────────────
   Year filter "from-to" as a single bar with two thumbs instead of two rows.
   Technique: two congruent <input type=range> stacked on top of each other, both
   pointer-events:none - only the thumbs are clickable (pointer-events:auto).
   The colored fill (.dr-fill) between the thumbs is positioned via inline style
   from the current values. */
.dual-range-row {
  display: flex;
  align-items: center;
  gap: 12px;
}
.dual-range-row .dr-rowlabel {
  width: 60px;
  flex-shrink: 0;
  font-size: 13px;
  color: var(--parchment);
}
.dual-range-wrap { flex: 1; min-width: 0; }
.dual-range {
  position: relative;
  height: 22px;
  display: flex;
  align-items: center;
}
.dual-range .dr-track {
  position: absolute;
  left: 0; right: 0;
  height: 4px;
  border-radius: 2px;
  background: var(--edge-strong);
}
.dual-range .dr-fill {
  position: absolute;
  height: 4px;
  border-radius: 2px;
  background: var(--gold-ink);
}
.dual-range input[type="range"] {
  position: absolute;
  left: 0; right: 0;
  width: 100%;
  margin: 0;
  height: 22px;
  appearance: none;
  -webkit-appearance: none;
  background: none;
  pointer-events: none;   /* track inert - only the thumbs receive input */
}
.dual-range input[type="range"]::-webkit-slider-thumb {
  appearance: none;
  -webkit-appearance: none;
  width: 15px; height: 15px;
  border-radius: 50%;
  background: var(--heading);
  border: 2px solid var(--ink);
  cursor: pointer;
  pointer-events: auto;
}
.dual-range input[type="range"]::-moz-range-thumb {
  width: 15px; height: 15px;
  border-radius: 50%;
  background: var(--heading);
  border: 2px solid var(--ink);
  cursor: pointer;
  pointer-events: auto;
}
.dual-range input[type="range"]::-moz-range-track { background: none; }
/* z-index layering: "to" sits on top of "from" by default. When "from" is in the
   upper half (thumbs close together near the right edge), "from" comes on top,
   otherwise it would remain unreachable under the "to" thumb. */
.dual-range .dr-from { z-index: 3; }
.dual-range .dr-to   { z-index: 4; }
.dual-range .dr-from.dr-from-top { z-index: 5; }
.dual-range-vals {
  display: flex;
  justify-content: space-between;
  font-size: 12px;
  color: var(--smoke);
  font-variant-numeric: tabular-nums;
  margin-top: 1px;
}
.break-stage > * { position: relative; z-index: 1; }
@keyframes gintroTtl { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
/* Shared soft fade-in (opacity only - does not conflict with baseline transforms). */
@keyframes gintroFade { from { opacity: 0; } to { opacity: 1; } }
@keyframes gintroDoorL { from { transform: rotateY(0); } to { transform: rotateY(-115deg); } }
@keyframes gintroDoorR { from { transform: rotateY(0); } to { transform: rotateY(115deg); } }
/* Reduced-motion: doors statically OPEN (otherwise they would stay closed and
   cover the scene); title visible. Per-game scene stops further below. */

@keyframes mqiUp { from { opacity: 0; transform: translateY(60px); } to { opacity: 1; transform: none; } }
@keyframes mqiSpin {
  from { transform: rotateX(56deg) rotateZ(0); }
  to   { transform: rotateX(56deg) rotateZ(360deg); }
}
@keyframes mqiNote {
  0%   { opacity: 0; transform: translate(0, 0) scale(.5); }
  20%  { opacity: 1; }
  100% { opacity: 0; transform: translate(60px, -80px) scale(1.1); }
}
@keyframes ssiWater { from { opacity: 0; } to { opacity: .85; } }
@keyframes ssiShipIn { from { opacity: 0; transform: translateY(16px) rotate(-6deg); } to { opacity: 1; transform: none; } }
@keyframes ssiRock { 0%, 100% { transform: rotate(-6deg) translateY(0); } 50% { transform: rotate(6deg) translateY(-4px); } }
@keyframes ssiCross { from { opacity: 0; transform: scale(1.6) rotate(-40deg); } to { opacity: .9; transform: none; } }
@keyframes ssiSweep { 0%, 100% { transform: translate(0, 0); } 50% { transform: translate(-90px, 30px); } }
@keyframes schiSpot {
  0%   { opacity: 0; transform: rotate(-20deg); }
  35%  { opacity: .6; }
  100% { opacity: .45; transform: rotate(12deg); }
}
@keyframes hmiGrow { from { transform: scale(0); } to { transform: scale(1); } }

/* ── Taboo scene — red "TABU" stamp slams down ─────────────────────────────── */
.tbi-stamp {
  font-family: 'Rye', cursive; font-size: 46px; letter-spacing: 3px;
  color: var(--red-light); border: 4px solid var(--red-light); border-radius: 8px;
  padding: 10px 26px; box-shadow: 0 0 26px rgba(192, 53, 42, .35);
  opacity: 0; transform: rotate(-8deg) scale(2.4);
  animation: tbiStamp .45s cubic-bezier(.2, 1.5, .4, 1) 1.5s forwards;
}
@keyframes tbiStamp {
  from { opacity: 0; transform: rotate(-8deg) scale(2.4); }
  to   { opacity: 1; transform: rotate(-8deg) scale(1); }
}
@media (prefers-reduced-motion: reduce) {
  .tbi-stamp { opacity: 1; transform: rotate(-8deg) scale(1); animation: none; }
}

/* ── Knowledge Quiz scene — rotating question mark ─────────────────────────────── */
.wqi-qmark {
  font-family: 'Rye', cursive; font-size: 104px; line-height: 1;
  color: var(--accent-light); filter: drop-shadow(0 0 10px currentColor);
  opacity: 0;
  animation: wqiSpin .9s cubic-bezier(.2, 1, .3, 1) 1.3s forwards, wqiGlow 1.8s ease-in-out 2.3s infinite;
}
@keyframes wqiSpin { from { opacity: 0; transform: rotateY(540deg) scale(.2); } to { opacity: 1; transform: rotateY(0) scale(1); } }
@keyframes wqiGlow { 0%, 100% { filter: drop-shadow(0 0 8px currentColor); } 50% { filter: drop-shadow(0 0 22px currentColor); } }
@media (prefers-reduced-motion: reduce) {
  .wqi-qmark { opacity: 1; transform: none; animation: none; }
}
@keyframes mmiFlip { from { transform: rotateY(180deg); } to { transform: rotateY(0); } }
@keyframes dkiFan {
  from { opacity: 0; transform: rotate(0) translateY(40px); }
  to   { opacity: 1; transform: rotate(var(--r)) translateY(-6px); }
}

/* Mobile portrait: cover/hero smaller, padding more compact, countdown closer to edge */


/* ── Filter chips: stale state for cross-filter counts ─────────────────── */
/* When a category/language is currently reduced to 0 tracks by the other axis
   (e.g. 'Schlager' + 'English'), the chip remains visible — greyed out and
   disabled so the user understands the combination rather than being confused
   about where the option went. */
.genre-chip.stale {
  opacity: 0.55;
  color: var(--smoke);
  border-color: var(--border-soft);
  pointer-events: auto;  /* click allowed so the selection can be undone */
}
.genre-chip.stale .genre-chip-count {
  color: var(--smoke);
}
/* Stale AND selected: struck-through text — the selected filter currently contributes nothing */
.genre-chip.stale.selected {
  text-decoration: line-through;
  text-decoration-color: rgba(212,98,10,.5);
  text-decoration-thickness: 1px;
}

/* Total count hint below the filter sections */
.filter-total-hint {
  margin: 12px 0 4px;
  padding: 8px 12px;
  font-size: 13px;
  text-align: center;
  letter-spacing: .04em;
  color: var(--smoke, #a89784);
  background: var(--surface-2);
  border-radius: 2px;
  border: 1px solid var(--border-soft);
}
.filter-total-hint strong {
  color: var(--gold, #d4920a);
}
.filter-total-hint-empty {
  color: #d97a5a;
  background: rgba(217,122,90,.08);
  border-color: rgba(217,122,90,.25);
}

/* ── Read-only Yes/No icons in the lobby settings box ─────────────────── */
/* Previously shown as text "Yes"/"No" - wraps when space is tight. Now compact
   icons that fit on any line. */
.settings-value-icon-yes {
  color: #5c5;
  font-weight: bold;
  font-size: 16px;
  line-height: 1;
}
.settings-value-icon-no {
  color: #d97a5a;
  font-weight: bold;
  font-size: 16px;
  line-height: 1;
}

/* Filter total hint: third level for "filter yields > 0 tracks but fewer
   than the WordCount setting requires". Orange as a warning between "all ok"
   (smoke) and "0 tracks" (red). */
.filter-total-hint-warn {
  color: var(--amber, #e8a040);
  background: rgba(232,160,64,.08);
  border-color: rgba(232,160,64,.25);
}

/* Clickable game mode text in the read-only settings box: opens the
   game rules modal with GameRulesContent. Looks like a regular settings-value
   but has button reset + subtle info icon to make it clear it is clickable. */
.settings-value-link-mode {
  color: var(--accent-ink);
  background: none;
  border: 0;
  padding: 0;
  margin: 0;
  font: inherit;
  cursor: pointer;
  text-align: right;
  transition: color 0.12s ease;
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.settings-value-link-mode:hover {
  color: var(--gold-ink);
}
.settings-value-info-icon {
  font-size: 12px;
  color: var(--smoke, #a89784);
  opacity: 0.7;
  transition: opacity 0.12s ease;
}
@media (hover: hover) {
  .settings-value-link-mode:hover .settings-value-info-icon {
    opacity: 1;
    color: var(--gold);
  }
}

/* Game mode pill in the game history session header */
.history-session-mode-pill {
  font-size: 12px;
  letter-spacing: .06em;
  color: var(--accent-light);
  background: color-mix(in srgb, var(--accent) 18%, transparent);
  border: 1px solid var(--accent-light);
  padding: 2px 8px;
  border-radius: 2px;
  text-transform: uppercase;
  flex-shrink: 0;
}

/* Apple Music link inline in the track row (game history, music quiz) */
.history-apple-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  margin-left: 6px;
  font-size: 13px;
  text-decoration: none;
  color: var(--gold, #d4920a);
  background: rgba(200,146,42,.10);
  border: 1px solid rgba(200,146,42,.25);
  border-radius: 2px;
  transition: background .15s ease, color .15s ease, border-color .15s ease;
  vertical-align: middle;
}
.history-apple-link:hover {
  background: rgba(200,146,42,.25);
  border-color: rgba(200,146,42,.55);
  color: var(--gold-light);
  text-decoration: none;
}

/* ── History: session scoreboard (above the track/word list) ────────── */
/* Shown in the history modal when a session is expanded — displays the
   final score as at game end, more compact and in history style. */
.history-scoreboard {
  margin: 8px 0 14px;
  padding: 10px 14px;
  background: rgba(0,0,0,.2);
  border: 1px solid rgba(200,146,42,.18);
  border-radius: 2px;
}
.history-scoreboard-label {
  font-family: 'Rye', cursive;
  font-size: 12px;
  letter-spacing: .08em;
  color: var(--gold, #d4920a);
  margin-bottom: 8px;
}
.history-scoreboard-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 4px 0;
  font-size: 13px;
  border-bottom: 1px dotted rgba(200,146,42,.08);
}
.history-scoreboard-row:last-child {
  border-bottom: none;
}
.history-scoreboard-medal {
  width: 24px;
  text-align: center;
  flex-shrink: 0;
  color: var(--smoke, #a89784);
}
.history-scoreboard-name {
  flex: 1;
  color: var(--old-paper, #d6c6a8);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.history-scoreboard-pts {
  font-weight: bold;
  color: var(--gold, #d4920a);
  flex-shrink: 0;
}
.history-scoreboard-row.is-me {
  background: rgba(200,146,42,.06);
  margin: 0 -6px;
  padding-left: 6px;
  padding-right: 6px;
  border-radius: 2px;
}
.history-scoreboard-row.is-me .history-scoreboard-name {
  color: var(--gold-light, #f0a020);
}

/* ══ Inhalts-Meldungen (Mod-Sprint Schritt 1) ═════════════════════════════
   Styles für ReportContentModal (Shared/ReportContentModal.razor) und den
   🚩-Button in den Spielmodi. Wiederverwendete generische Modal-Klassen
   (modal-backdrop, modal-content, fgrp, lbl, inp). */

/* Flag button in the game — icon only, very small and subtle.
   Deliberately no label so the button does not wrap in tight headers.
   Hover shows a faint red tint to make the purpose clear. */
.report-flag-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 1px solid transparent;
  color: rgba(168, 151, 132, 0.35);
  font-size: 13px;
  padding: 2px 4px;
  border-radius: 3px;
  cursor: pointer;
  transition: all .15s;
  line-height: 1;
  flex-shrink: 0;
}
.report-flag-btn:hover {
  border-color: rgba(192, 53, 42, 0.35);
  color: rgba(192, 53, 42, 0.7);
  background: rgba(139, 26, 26, 0.08);
}
.report-flag-btn.reported {
  color: var(--green-ok);
  border-color: transparent;
  cursor: default;
  background: transparent;
}
.report-flag-btn:disabled {
  cursor: default;
}

/* Target display at the top of the report modal — compact info box showing what is being reported */
.report-target-box {
  background: var(--surface-1);
  border: 1px solid var(--border);
  padding: 8px 12px;
  border-radius: 2px;
  margin-bottom: 14px;
}
.report-target-label {
  font-size: 12px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--smoke);
  margin-bottom: 4px;
}
.report-target-name {
  font-family: 'Rye', cursive;
  font-size: 16px;
  color: var(--heading);
}
.report-target-meta {
  font-size: 12px;
  color: var(--smoke);
  margin-top: 3px;
}

/* Reason selection as a list instead of classic radio buttons.
   Clicking the entire row selects it — larger hit area, better on touch. */
.report-reason-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.report-reason-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 12px;
  background: var(--surface-1);
  border: 1px solid var(--border-soft);
  border-radius: 2px;
  cursor: pointer;
  font-size: 14px;
  color: var(--old-paper);
  transition: all .12s;
}
.report-reason-row:hover {
  border-color: rgba(200, 146, 42, 0.4);
  background: rgba(200, 146, 42, 0.04);
}
.report-reason-row.checked {
  border-color: rgba(200, 146, 42, 0.55);
  background: rgba(200, 146, 42, 0.1);
  color: var(--gold-light);
}
.report-reason-row input[type="radio"] {
  accent-color: var(--gold);
  cursor: pointer;
}

/* ══════════════════════════════════════════════════════════════════════════
   MATCHMAKING — Startseiten-Aktions-Buttons + „Lobby beitreten"-Modal
   ══════════════════════════════════════════════════════════════════════════ */

/* ── Matchmaking modal: code field in header ─────────────────────────────── */
/* (Wrapper .matchmaking-modal migrated to <Modal> component — body classes remain) */
.mm-header-code {
  display: flex;
  align-items: center;
  gap: 6px;
}
.mm-header-code .inp-code {
  width: 108px;
  background: var(--input-bg);
  border: 1px solid var(--border-strong);
  color: var(--heading);
  font-family: 'Rye', cursive;
  letter-spacing: .18em;
  text-align: center;
  font-size: 14px;
  padding: 6px 8px;
  border-radius: 3px;
  text-transform: uppercase;
}
.mm-header-code .inp-code::placeholder {
  color: var(--smoke);
  letter-spacing: .1em;
  font-size: 12px;
}
.mm-header-code .mm-code-go {
  font-family: 'Rye', cursive;
  font-size: 12px;
  cursor: pointer;
  background: linear-gradient(135deg, var(--amber), var(--gold));
  color: var(--shadow);
  border: none;
  padding: 7px 12px;
  border-radius: 3px;
}
.mm-header-code .mm-code-go:disabled { opacity: .4; cursor: not-allowed; }
/* On narrow screens the code field wraps below the title.
   - flex-basis: 100% forces it to full width (instead of squeezing next to the title)
   - order: 99 moves it to the end of the header flex container so the close button
     (x) still stays in the first row to the right of the title
   - Works together with flex-wrap: wrap on .modal-v2-header */
@media (max-width: 520px) {
  .mm-header-code {
    flex-basis: 100%;
    order: 99;
  }
  .mm-header-code .inp-code { flex: 1; width: auto; }
}

.mm-subhead {
  font-size: 12px;
  color: var(--smoke);
  letter-spacing: .08em;
  text-transform: uppercase;
  margin: 0 0 12px;
}

/* ── Lobby entry (flat list) ───────────────────────────────────────── */
.mm-lobby {
  display: flex;
  align-items: center;
  gap: 12px;
  background: var(--surface-2);
  border: 1px solid var(--border-soft);
  border-radius: 4px;
  padding: 10px 12px;
  margin-bottom: 8px;
}
.mm-lobby:last-child { margin-bottom: 0; }
.mm-lobby-icon { font-size: 26px; line-height: 1; flex-shrink: 0; }
.mm-lobby-main { flex: 1; min-width: 0; }
.mm-lobby-host { color: var(--parchment); font-size: 14px; }
.mm-lobby-host .mm-host-name { color: var(--heading); }
.mm-lobby-meta {
  font-size: 12px;
  color: var(--smoke);
  margin-top: 2px;
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}
.mm-mode-tag { color: var(--gold-light); letter-spacing: .04em; }
.mm-players { color: var(--old-paper); }
.mm-join-btn {
  font-family: 'Rye', cursive;
  font-size: 12px;
  letter-spacing: .08em;
  text-transform: uppercase;
  cursor: pointer;
  flex-shrink: 0;
  background: linear-gradient(135deg, var(--amber), var(--gold));
  color: var(--shadow);
  border: none;
  padding: 8px 16px;
  border-radius: 3px;
}
@media (hover: hover) {
  .mm-join-btn:hover {
    transform: translateY(-1px);
  }
}

/* ── Empty state ────────────────────────────────────────────────────────── */
.mm-empty {
  text-align: center;
  color: var(--smoke);
  font-size: 13px;
  padding: 34px 12px;
  line-height: 1.6;
}
.mm-empty .mm-empty-icon {
  font-size: 34px;
  display: block;
  margin-bottom: 8px;
  opacity: .6;
}

/* ── Paging ─────────────────────────────────────────────────────────────── */
.mm-paging {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid rgba(200, 146, 42, .14);
}
.mm-page-btn {
  font-size: 13px;
  cursor: pointer;
  padding: 5px 12px;
  border-radius: 2px;
  border: 1px solid var(--border-strong);
  background: var(--surface-1);
  color: var(--old-paper);
}
.mm-page-btn:hover:not(:disabled) { border-color: var(--gold); color: var(--gold-light); }
.mm-page-btn:disabled { opacity: .3; cursor: not-allowed; }
.mm-page-info { font-size: 12px; color: var(--smoke); }

/* ══════════════════════════════════════════════════════════════════════════
   MODUS-PILL MIT DROPDOWN — im Header von MatchmakingDialog und Create-Modal
   ══════════════════════════════════════════════════════════════════════════ */
.mode-pill-header {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  border-radius: 14px;
  font-size: 13px;
  color: var(--heading);
  position: relative;
  cursor: pointer;
  transition: background .15s, border-color .15s;
  user-select: none;
  margin-left: 8px;
}
.mode-pill-header:hover {
  background: rgba(200, 146, 42, .25);
  border-color: var(--gold);
}
.mode-pill-header.open {
  background: rgba(200, 146, 42, .3);
  border-color: var(--gold);
}
.mode-pill-header .caret {
  color: var(--smoke);
  font-size: 12px;
  margin-left: 2px;
}
.mode-switch-dropdown {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  background: var(--surface-1-strong);
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  padding: 4px;
  box-shadow: 0 8px 24px var(--shadow-color);
  z-index: 100;
  min-width: 180px;
  max-height: 260px;   /* long game list scrolls inside (mockup behavior) */
  overflow-y: auto;
  text-transform: none;
  letter-spacing: 0;
}
.mode-switch-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  color: var(--parchment);
  border-radius: 4px;
  cursor: pointer;
  font-size: 13px;
}
.mode-switch-item:hover {
  background: var(--surface-hover);
  color: var(--heading);
}
.mode-switch-item.cur { background: var(--surface-2); color: var(--heading); font-weight: 600; }
.mode-switch-icon { font-size: 18px; line-height: 1; width: 22px; text-align: center; flex-shrink: 0; }
/* Game locked in the switch dropdown because too many players are connected. */
.mode-switch-item.disabled {
  opacity: .5;
  cursor: not-allowed;
  pointer-events: none;
}
.mode-switch-off.cap {
  color: var(--amber, #e8a060);
  border-color: rgba(232, 160, 96, .5);
}

/* ══════════════════════════════════════════════════════════════════════════
   MATCHMAKING — ACTION-CARDS (Schnellstart + Neue Lobby) und Live-Liste
   ══════════════════════════════════════════════════════════════════════════ */
.mm-action-cards {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  margin-bottom: 18px;
}
.mm-action-card {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 16px;
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  border-radius: 5px;
  cursor: pointer;
  text-align: left;
  color: var(--parchment);
  transition: all .15s;
}
@media (hover: hover) {
  .mm-action-card:not(:disabled):hover {
    border-color: var(--gold);
    background: rgba(200, 146, 42, .08);
    transform: translateY(-1px);
  }
}
.mm-action-card:disabled { opacity: .5; cursor: not-allowed; }
.mm-action-quickstart {
  background: linear-gradient(135deg, rgba(212, 98, 10, .22), rgba(212, 98, 10, .05));
  border-color: rgba(212, 98, 10, .55);
}
.mm-action-quickstart:not(:disabled):hover {
  background: linear-gradient(135deg, rgba(212, 98, 10, .32), rgba(212, 98, 10, .1));
  border-color: var(--amber);
}
.mm-action-create {
  background: linear-gradient(135deg, rgba(200, 146, 42, .18), rgba(200, 146, 42, .05));
  border-color: rgba(200, 146, 42, .5);
}
.mm-action-create:not(:disabled):hover {
  background: linear-gradient(135deg, rgba(200, 146, 42, .28), rgba(200, 146, 42, .1));
  border-color: var(--gold);
}
.mm-action-icon { font-size: 28px; flex-shrink: 0; line-height: 1; }
.mm-action-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.mm-action-title {
  color: var(--heading);
  font-family: 'Rye', cursive;
  font-size: 15px;
}
.mm-action-sub { color: var(--smoke); font-size: 12px; }
@media (max-width: 540px) {
  .mm-action-cards { grid-template-columns: 1fr; }
}

.mm-list-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin-bottom: 10px;
}
.mm-subhead {
  font-family: 'Rye', cursive;
  color: var(--heading);
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: .12em;
  margin: 0;
}
.mm-live-hint {
  font-size: 12px;
  color: var(--smoke);
  font-style: italic;
}

/* ══════════════════════════════════════════════════════════════════════════
   MATCHMAKING — INLINE-HUB (Variante A). Ersetzt im Home-Board das Poster-Grid
   statt als Overlay aufzugehen. Wiederverwendet .mm-action-cards / .mm-lobby /
   .mm-empty / .mode-pill-header / .mm-header-code; neu sind nur Leiste + Hero.
   ══════════════════════════════════════════════════════════════════════════ */
.mm-inline-bar {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 16px;
}
.mm-back {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: 'Rye', cursive;
  font-size: 13px;
  letter-spacing: .04em;
  cursor: pointer;
  min-height: 40px;                 /* WCAG 2.5.8: Zielgröße */
  padding: 8px 16px;
  border-radius: var(--btn-radius);
  border: 1px solid var(--border-strong);
  background: var(--surface-1);
  color: var(--old-paper);
  transition: border-color .15s, color .15s, background .15s;
}
.mm-back:hover { border-color: var(--gold); color: var(--gold-light); background: var(--surface-hover); }
.mm-back-arrow { font-size: 16px; line-height: 1; }
.mm-inline-tools {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-left: auto;
  flex-wrap: wrap;
}
/* Die Modus-Pill bringt margin-left:8px mit — im Tools-Flex regelt der gap. */
.mm-inline-tools .mode-pill-header { margin-left: 0; }

.mm-inline-hero {
  display: flex;
  align-items: center;
  gap: 18px;
  padding: 18px 20px;
  margin-bottom: 20px;
  border-radius: 12px;
  border: 1px solid var(--board-border);
  /* Dezenter Akzent-Tint des gewählten Spiels (mode-* setzt --accent); Text
     bleibt auf dem Board-Verlauf → --text-main behält AA-Kontrast. */
  background:
    radial-gradient(circle at 12% 25%,
      color-mix(in srgb, var(--accent) var(--spot-accent-mix, 40%), transparent), transparent 62%),
    linear-gradient(180deg, var(--board-grad-a), var(--board-grad-b));
}
.mm-inline-hero-ic { font-size: 54px; line-height: 1; flex: none; filter: drop-shadow(0 3px 8px var(--shadow-color)); }
.mm-inline-hero-txt { min-width: 0; }
.mm-inline-hero-txt h2 {
  font-family: 'Rye', cursive;
  font-weight: 400;
  color: var(--heading);
  font-size: clamp(20px, 3.5vw, 26px);
  margin: 0 0 5px;
  line-height: 1.1;
}
.mm-inline-hero-txt p { margin: 0 0 8px; color: var(--text-main); font-size: 14px; max-width: 60ch; line-height: 1.5; }
.mm-inline-hero-meta { color: var(--heading); font-size: 13px; font-weight: 600; }

@media (max-width: 560px) {
  .mm-inline-tools { margin-left: 0; width: 100%; }
  .mm-inline-hero { gap: 12px; padding: 14px 16px; }
  .mm-inline-hero-ic { font-size: 40px; }
}

/* ══════════════════════════════════════════════════════════════════════════
   HEADER — Code-Direktbeitritt im Slot rechts vom Brand
   (sichtbar wenn nicht in Lobby + nicht im Spiel; sonst steht dort die
   .nav-lobby-pill bzw. nichts). Visuell als kompakte Pill gestaltet —
   gleiche Höhe und Stil-Sprache wie .nav-lobby-pill, damit der Slot
   konsistent wirkt egal welcher Inhalt drin steht.
   ══════════════════════════════════════════════════════════════════════════ */
.header-code-form {
  display: inline-flex;
  align-items: stretch;            /* icon/input/button all the same height */
  gap: 0;
  margin-left: 14px;               /* mirrors .nav-lobby-pill */
  margin-right: auto;              /* pushes .app-header-actions to the right edge */
  background: var(--surface-1);
  border: 1px solid var(--border-strong);
  border-radius: 18px;
  overflow: hidden;
  transition: border-color .15s, box-shadow .15s, background .15s;
}
.header-code-form:hover { border-color: var(--gold); }
.header-code-form:focus-within {
  border-color: var(--gold);
  box-shadow: 0 0 0 2px rgba(200, 146, 42, .18);
}
/* Focus ring on the WHOLE pill instead of the inner input (the global
   :focus-visible rule would otherwise draw it inside the rounded shape). */
.header-code-form:has(.header-code-input:focus-visible) {
  outline: 3px solid var(--accent-strong);
  outline-offset: 2px;
}
.header-code-form .header-code-input:focus-visible { outline: none !important; }
.header-code-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0 6px 0 10px;
  font-size: 14px;
  line-height: 1;
  color: var(--text-dim);
  user-select: none;
}
.header-code-input {
  background: transparent;
  border: none;
  color: var(--text-main);
  padding: 6px 10px 6px 4px;
  width: 92px;
  text-align: center;
  text-transform: uppercase;
  letter-spacing: 2px;
  font-size: 13px;
  line-height: 1;
}
.header-code-input::placeholder {
  color: color-mix(in srgb, var(--text-dim) 65%, transparent);
  letter-spacing: 1px;
  text-transform: none;
}
.header-code-input:focus { outline: none; }
.header-code-go {
  background: linear-gradient(135deg, var(--amber), var(--gold));
  color: var(--ink);
  border: none;
  padding: 0 12px;
  cursor: pointer;
  font-size: 14px;
  font-weight: bold;
  line-height: 1;
  transition: filter .15s;
}
@media (hover: hover) {
  .header-code-go:hover:not(:disabled) {
    filter: brightness(1.12);
  }
}
.header-code-go:disabled {
  background: var(--surface-2);
  color: color-mix(in srgb, var(--text-dim) 60%, transparent);
  cursor: not-allowed;
}

/* Mobile: icon padding more compact, input narrower. Brand title is
   already hidden via the .app-header-title media query. */
@media (max-width: 540px) {
  .header-code-form { margin-left: 10px; }
  .header-code-icon { padding: 0 4px 0 8px; font-size: 13px; }
  .header-code-input { width: 78px; padding: 6px 8px 6px 4px; }
  .header-code-go { padding: 0 10px; }
}

/* ══════════════════════════════════════════════════════════════════════════
   KONFIG-MODAL KOMPAKT — einzeilige Slider-Zeilen
   ══════════════════════════════════════════════════════════════════════════ */

/* Replaces the two-line .fgrp for slider settings: label fixed on the left,
   slider fills the center, current value on the right — all in one line. */
.slider-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 7px 0;
}
.slider-row .sr-label {
  flex: 0 0 128px;
  color: var(--smoke);
  font-size: 13px;
  /* same typography as .lbl in the other config rows */
  letter-spacing: .16em;
  text-transform: uppercase;
}
.slider-row .slider { flex: 1; }
.slider-row .sr-value {
  flex: 0 0 auto;
  min-width: 48px;
  text-align: right;
  color: var(--heading);
  font-size: 14px;
  font-weight: bold;
}
/* Hint below the max-players slider when the account cap (unconfirmed
   email) limits the slider below the account maximum. */
.slider-cap-note {
  margin: -2px 0 6px;
  padding-left: 140px;
  color: var(--smoke);
  font-size: 12px;
}
/* Two adjacent 420px blocks combined.
   On very narrow screens the slider row wraps: label on top, slider+value below. */
@media (max-width: 420px) {
  .slider-cap-note { padding-left: 0; }
  .slider-row {
    flex-wrap: wrap;
    gap: 4px 12px;
  }
  .slider-row .sr-label { flex-basis: 100%; }
  .slider-row .sr-value { min-width: 40px; }
}

/* ── Help modal (lobby visibility) — wrapper migrated to <Modal> component ── */
/* Body styles are not needed since <Modal> BodyContent works directly with <p> tags
   and global typography rules. Help modal content is short enough that no
   separate body wrapper is required. */

/* Variant for a toggle row: label + help icon side by side, without the
   margin-bottom of the block variant .lbl-with-help. */
.lbl-with-help-inline {
  display: inline-flex;
  align-items: center;
  gap: 7px;
}
/* line-height:1 ensures the '?' glyph sits centered in its own box;
   align-items:center on the container aligns the box to the text line.
   No padding hack needed once the label is properly normalized. */
.lbl-with-help-inline .help-icon-btn {
  line-height: 1;
  min-width: 24px;   /* WCAG 2.5.8 — without this the inline variant shrinks to ~17px */
}

/* ── Visibility badge in the lobby header ─────────────────────────── */
.visibility-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 14px;
  line-height: 1;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  border: 1px solid var(--border-soft);
  background: var(--surface-2);
  color: var(--text-dim);
  cursor: default;
  flex-shrink: 0;
}
.visibility-badge.is-public {
  color: var(--green-ok);
  border-color: rgba(45, 122, 74, .45);
}

/* ── Visibility icon in the nav lobby pill ───────────────────────────── */
.nav-lobby-pill-vis {
  font-size: 12px;
  opacity: .85;
  flex-shrink: 0;
}

/* ── Settings row with pill group (label on left, pills on right) ──────────
   Similar to .settings-toggle-row, but instead of a single toggle button
   there is a pill group on the right (e.g. answer delay: Off / 2 s / 3 s).
   On narrow screens the pill group wraps below the label. */
.settings-pills-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 7px 0;
}
.settings-pills-row > .lbl {
  flex: 1;
  min-width: 0;
  /* .lbl brings display:block + margin-bottom:7px — both would push the
     label out of vertical center in the flex row. Reset here
     and align to the compact 13px size of the slider rows. */
  display: flex;
  align-items: center;
  margin-bottom: 0;
  font-size: 13px;
}
.settings-pills-row .quiz-mode-pills {
  flex-shrink: 0;
  margin: 0;
  /* Pills remain single-line — wrapping on narrow screens happens
     at row level (.settings-pills-row), not within the pill group. */
  flex-wrap: nowrap;
}
@media (max-width: 460px) {
  .settings-pills-row {
    flex-wrap: wrap;
    align-items: flex-start;
  }
  .settings-pills-row > .lbl { flex-basis: 100%; }
}

/* ── TrackDetailModal (Shared, readonly) — body classes ─────────────────────
   Wrapper/header (.tdm-modal/-head/-close/-body) migrated to <Modal> component.
   The body layout classes below remain — <Modal> BodyContent renders them
   directly. Own tdm-* content classes instead of track-detail-* from admin.css,
   because admin.css is not loaded outside the admin area (Game/Lobby/Profile). */
.tdm-hero {
  display: flex;
  gap: 14px;
  align-items: flex-start;
  margin-bottom: 16px;
  padding-bottom: 16px;
  border-bottom: 1px solid rgba(200, 146, 42, .15);
}
.tdm-cover {
  width: 104px; height: 104px;
  border-radius: 8px;
  object-fit: cover;
  flex-shrink: 0;
  border: 1px solid rgba(200, 146, 42, .25);
  box-shadow: 0 4px 18px rgba(0, 0, 0, .5);
}
.tdm-cover-empty {
  display: flex; align-items: center; justify-content: center;
  font-size: 36px;
  background: radial-gradient(circle at 35% 30%, var(--warm-wood), var(--ink));
}
.tdm-hero-text { flex: 1; min-width: 0; }
.tdm-artist {
  font-size: 18px; color: var(--heading);
  overflow-wrap: anywhere;
}
.tdm-title {
  font-size: 15px; color: var(--parchment);
  margin-top: 2px; overflow-wrap: anywhere;
}
.tdm-album {
  font-size: 12px; color: var(--smoke); font-style: italic;
  margin-top: 6px; overflow-wrap: anywhere;
}
.tdm-grid {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 8px 16px;
  font-size: 13px;
}
.tdm-label {
  color: var(--smoke);
  text-transform: uppercase;
  letter-spacing: .05em;
  font-size: 12px;
  align-self: center;
}
.tdm-value { color: var(--parchment); }
.tdm-pill {
  display: inline-block;
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  border-radius: 4px;
  padding: 2px 8px;
  font-size: 12px;
  color: var(--heading);
}
.tdm-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 18px;
}
.tdm-btn {
  flex: 1;
  min-width: 150px;
  text-align: center;
  text-decoration: none;
}
.tdm-btn-star-on {
  background: rgba(200, 146, 42, .16);
  border-color: var(--gold);
  color: var(--heading);
}
.tdm-btn-flag { border-color: rgba(192, 53, 42, .5); color: #e0998f; }

/* 'Already reported' state — applies to track and player report buttons.
   The button is already disabled (.btn:disabled dims it); this class
   additionally gives it a calm green done accent so it looks
   'confirmed done' rather than 'broken/disabled'.
   !important because .btn:disabled dimming would otherwise swallow the border color. */
.tdm-btn-reported,
.btn-reported {
  border-color: rgba(45, 122, 74, .55) !important;
  color: var(--green-ok) !important;
}

/* Clickable track rows (podium, lobby history, profile) — open the TrackDetailModal. */
.track-clickable { cursor: pointer; }
.track-clickable:hover { color: var(--heading); }

/* ── Profile: favorites section ───────────────────────────────────────────── */
.profile-fav-count { font-size: 12px; color: var(--smoke); font-weight: normal; }
.profile-fav-list { display: flex; flex-direction: column; }
.profile-fav-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 0;
  border-bottom: 1px solid rgba(200, 146, 42, .12);
}
.profile-fav-row:last-child { border-bottom: none; }
.profile-fav-main {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: 1;
  min-width: 0;
}
.profile-fav-cover {
  width: 38px; height: 38px;
  border-radius: 5px;
  object-fit: cover;
  flex-shrink: 0;
}
.profile-fav-cover-empty {
  display: flex; align-items: center; justify-content: center;
  font-size: 16px;
  background: radial-gradient(circle at 35% 30%, var(--warm-wood), var(--ink));
}
.profile-fav-text { flex: 1; min-width: 0; }
.profile-fav-artist {
  font-size: 13px; color: var(--heading);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.profile-fav-title {
  font-size: 12px; color: var(--smoke);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* Action column per favorites row (preview · remove/inline confirm). */
.profile-fav-acts {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
}
/* Both action buttons compact + consistent. Overrides .btn base
   (full-width, Rye, uppercase) AND gives the play button an explicit background —
   otherwise the <button> shows browser default chrome. */
.profile-fav-acts .btn {
  width: auto; min-width: 32px; height: 30px; padding: 0 10px;
  display: inline-flex; align-items: center; justify-content: center;
  font-family: inherit; font-size: 13px; letter-spacing: 0; text-transform: none;
  border-radius: 4px; line-height: 1;
}
.profile-fav-play {
  background: transparent;
  border: 1px solid var(--border-strong);
  color: var(--heading);
}
.profile-fav-play:hover { background: rgba(200, 146, 42, .15); border-color: var(--gold); }

/* Make AdminPager styles available outside admin — the pager is now used on
   saloon pages (profile history/favorites, teams overview) that only load
   saloon.css. The button/container styles otherwise live only in admin.css.
   On admin/mod pages admin.css is loaded AFTER saloon.css and overrides these
   rules so the pager table-shell layout remains unchanged there. */
.admin-pager {
  display: flex; align-items: center; justify-content: center;
  gap: 4px; flex-wrap: wrap; padding: 14px 0 2px;
}
.admin-pager-info { font-size: 12px; color: var(--smoke); margin-left: 6px; }
.lot-page-btn {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 32px; height: 32px; padding: 0 8px;
  background: var(--surface-1); border: 1px solid var(--border-soft);
  color: var(--text-dim); font-size: 13px; border-radius: 3px;
  cursor: pointer; transition: all .2s;
}
.lot-page-btn:hover:not(:disabled) { color: var(--gold); border-color: rgba(200, 146, 42, .5); }
.lot-page-btn:disabled { opacity: .3; cursor: default; }
.lot-page-btn.lot-page-active {
  background: rgba(200, 146, 42, .15); border-color: var(--gold); color: var(--gold-light);
}

.profile-fav-remove {
  width: 30px; height: 30px;
  flex-shrink: 0;
  border-radius: 5px;
  border: 1px solid rgba(192, 53, 42, .4);
  background: var(--surface-2);
  color: var(--parchment);
  cursor: pointer;
  font-size: 13px;
}
.profile-fav-paging {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  margin-top: 12px;
  padding-top: 10px;
  border-top: 1px solid rgba(200, 146, 42, .12);
}
.profile-fav-page-info { font-size: 12px; color: var(--smoke); letter-spacing: .04em; }

/* ── Profile: 'recent games' button (opens the history modal) ───────────── */
.profile-history-btn {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
}
.profile-history-btn-count { font-size: 12px; color: var(--smoke); }

/* ════════════════════════════════════════════════════════════════════
   Friends feature
   ════════════════════════════════════════════════════════════════════ */

/* Counter badge (open incoming requests) — on the section title and in the dropdown. */
.badge-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  font-family: Georgia, serif;
  font-size: 12px;
  font-weight: bold;
  color: #1a0f06;
  background: var(--gold-light);
  border-radius: 9px;
  vertical-align: middle;
}
.profile-section-subtle {
  font-size: 12px;
  color: var(--smoke);
  font-weight: normal;
  margin-left: 4px;
}

/* Nav badge: small dot counter at the top right of the profile avatar button. */
.nav-badge {
  position: absolute;
  top: -4px;
  right: -4px;
  min-width: 17px;
  height: 17px;
  padding: 0 4px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: Georgia, serif;
  font-size: 12px;
  font-weight: bold;
  color: #1a0f06;
  background: var(--gold-light);
  border: 1px solid rgba(13, 10, 7, 0.7);
  border-radius: 9px;
  pointer-events: none;
}
.profile-btn { position: relative; }
.nav-badge-inline { margin-left: auto; }

/* Group heading within the friends section (incoming/outgoing/list). */
.friend-group-label {
  color: var(--heading);
  font-size: 12px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  margin: 16px 0 4px;
}
.friend-group-label:first-of-type { margin-top: 6px; }

.friend-list { display: flex; flex-direction: column; }
/* Row wraps: avatar + name/meta on line 1, action buttons slide right-aligned
   onto a second line when space is tight (narrow profile column),
   instead of squeezing the text. */
.friend-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 11px;
  padding: 10px 2px;
  border-bottom: 1px solid rgba(200, 146, 42, 0.08);
}
.friend-row:last-child { border-bottom: none; }
/* min-width forces the wrap: if the text column cannot shrink below 60%,
   buttons must go to the next line (instead of squeezing the text). */
.friend-row-main { flex: 1 1 auto; min-width: 60%; }
.friend-row-name {
  font-size: 13.5px;
  color: var(--parchment);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.friend-row-meta { color: var(--smoke); font-size: 12px; margin-top: 2px; line-height: 1.35; }
.friend-row-acts {
  display: flex;
  gap: 7px;
  flex: 0 0 auto;
  margin-left: auto;
  align-items: center;
  flex-wrap: wrap;
  justify-content: flex-end;
}
.friend-inline-q { color: var(--smoke); font-size: 12px; }

/* ── Friend/team presence (online dot, game badge, join) ── */
.friend-avatar-wrap { position: relative; flex: 0 0 auto; line-height: 0; }
.presence-dot {
  position: absolute; right: -2px; bottom: -2px;
  width: 12px; height: 12px; border-radius: 50%;
  border: 2px solid #20180f;            /* ring in saloon dark, separates dot from avatar */
}
.presence-dot.online  { background: #5fb96b; box-shadow: 0 0 6px rgba(95, 185, 107, .7); }
.presence-dot.offline { background: #6b5d50; }
.presence-online      { color: var(--success); }
.presence-offline     { color: var(--smoke); }
.presence-sub         { color: var(--smoke); }
.game-badge           { display: inline-flex; align-items: center; gap: 5px; color: var(--gold); }
.team-member-presence { display: block; font-size: 12px; margin-top: 2px; color: var(--smoke); }

/* Compact button for list actions (accept/decline/remove ...). */
.btn-xs {
  display: inline-block;
  width: auto;
  font-size: 12px;
  padding: 4px 10px;
  border-radius: 3px;
  white-space: nowrap;
  cursor: pointer;
}

/* Friendship block in PlayerProfileModal. */
.player-profile-friend { margin-top: 4px; }
.player-profile-friend .alert-error { margin-bottom: 8px; }
.player-profile-friend-state {
  color: var(--success);
  font-size: 13px;
  margin-bottom: 8px;
}
.player-profile-friend-q {
  color: var(--smoke);
  font-size: 12.5px;
  align-self: center;
  margin-right: 2px;
}
.player-profile-team-link {
  color: var(--heading);
  text-decoration: underline dotted;
  text-underline-offset: 2px;
}
.player-profile-team-link:hover { color: var(--gold); }

/* Visually hidden but present for screen readers and search engines
   (e.g. the landing page H1 whose brand title would otherwise only appear in the header). */
.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ════════════════════════════════════════════════════════════════════
   Profile page with tabs
   ════════════════════════════════════════════════════════════════════ */

/* Identity bar: remains visible above all tabs (portrait + name + team/matches).
   flex-wrap + min-width:0 so a long name + actions never blow up narrow screens. */
.profile-id-bar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 16px;
  background: var(--surface-1);
  border: 1px solid var(--border-soft);
  border-radius: 4px;
  padding: 14px 18px;
  margin-bottom: 14px;
}
.profile-id-avatar { flex-shrink: 0; }
.profile-id-main { min-width: 0; }
.profile-id-name { font-family: 'Rye', cursive; color: var(--heading); font-size: 20px; line-height: 1.1; display: flex; align-items: center; gap: 6px; }
.profile-id-meta { color: var(--text-dim); font-size: 12.5px; margin-top: 5px; }
.profile-id-team { color: var(--heading); text-decoration: underline dotted; text-underline-offset: 2px; }
.profile-id-team:hover { color: var(--gold); }

/* The former .profile-tabs/.profile-tab bar was replaced by the shared subnav
   (SubnavTabs / .pg-tab) in the PageFrame header row. */

/* Tab content: flex grid. Default = full width; .col-half = two side by side
   (on narrow screens they collapse back to one column via min-width). */
.profile-tab-body {
  display: flex;
  flex-wrap: wrap;
  gap: 18px;
  align-items: flex-start;
}
/* Tab contents are ALWAYS in the DOM (one .tab-region per tab) and toggled via
   CSS only — tab switching is a pure visibility toggle without
   re-render/remount. Each region is its own flex container for its sections/pairs;
   only the active one is visible. */
.profile-tab-body > .tab-region { flex: 1 1 100%; }
.tab-region {
  display: flex;
  flex-wrap: wrap;
  gap: 18px;
  align-items: flex-start;
}
.tab-region.tab-hidden { display: none; }
.tab-region > section { flex: 1 1 100%; margin: 0; }
/* Explicit 50/50 pair row — keeps data+danger-zone or account+linked side by side
   robustly, even if one card is missing (e.g. 'Linked accounts' without OAuth).
   A single col-half grows to full width via flex-grow. */
.tab-region > .profile-pair {
  flex: 1 1 100%;
  display: flex;
  flex-wrap: wrap;
  gap: 18px;
  align-items: flex-start;
}
.profile-pair > .col-half { flex: 1 1 calc(50% - 9px); min-width: 280px; margin: 0; }
/* Favorites renders (due to DOM order) before the stats — pushed to the end of the tab via order. */
.profile-tab-body > .profile-fav-last { order: 5; }
@keyframes wqCardIn {
  from { opacity: 0; transform: perspective(900px) rotateX(-10deg) scale(.97); }
  to   { opacity: 1; transform: none; }
}
.wq-reveal-area.has-expl { min-height: 120px; }
@keyframes wqResolvingPulse { 0%, 100% { opacity: .55; } 50% { opacity: 1; } }
@keyframes wqCorrectPop { from { transform: scale(.96); } to { transform: scale(1.02); } }
@keyframes wqRevealFade { from { opacity: 0; } to { opacity: 1; } }
@keyframes wqCurtainOut {
  to { opacity: 0; transform: perspective(900px) rotateX(14deg) scale(.97); }
}

.mem-card {
  position: relative; aspect-ratio: 1; border-radius: 10px; display: grid; place-items: center;
  box-shadow: 0 4px 12px rgba(0, 0, 0, .45);
  transition: transform .25s ease, box-shadow .2s ease, opacity .3s ease;
}
/* Square tiles (width from grid, height = width). Icon fills most of the tile (little
   border) so the woodcut motifs read clearly, even at small cell sizes. Stays clear of the
   fixed 13px owner dot in the bottom-right corner. */
.mem-card .ic { width: 80%; height: 80%; }
.mem-card.back {
  background: radial-gradient(120% 120% at 50% 34%, #3a2812 0%, #1b1106 72%);
  border: 1px solid var(--gold); color: var(--gold-light);
}
.mem-card.back::before {
  content: ""; position: absolute; inset: 6px; border-radius: 6px;
  border: 1px solid color-mix(in srgb, var(--gold) 45%, transparent);
}
.mem-card.back::after {
  content: ""; position: absolute; width: 27%; height: 27%; transform: rotate(45deg);
  border: 1px solid color-mix(in srgb, var(--gold) 55%, transparent);
}
.mem-card.back .emblem { position: relative; width: 22%; height: 22%; color: var(--gold-light); }
.mem-card.is-clickable { cursor: pointer; }
@media (hover: hover) {
  .mem-card.is-clickable:hover {
    transform: translateY(-2px);
    box-shadow: 0 7px 18px rgba(0, 0, 0, .5);
  }
}
.mem-card.face {
  background: linear-gradient(160deg, #efdcb4, #d6bd92); border: 1px solid #b89a63; color: #2e1f0e;
  animation: memFlip .28s ease;
}
.mem-card.sel {
  box-shadow: 0 0 0 3px var(--accent-ink), 0 6px 18px rgba(0, 0, 0, .55); transform: translateY(-2px);
}
.mem-card.match {
  opacity: .55; box-shadow: 0 0 0 2px var(--gold-ink), 0 0 16px color-mix(in srgb, var(--gold) 45%, transparent);
  animation: memMatch .5s ease;
}
.mem-card.miss { box-shadow: 0 0 0 3px var(--red-light); animation: memMiss .4s ease; }
.mem-card .owner {
  position: absolute; bottom: 6px; right: 6px; width: 13px; height: 13px; border-radius: 50%;
  border: 1px solid rgba(0, 0, 0, .45);
}

/* Solo end-screen summary (under the final score in the podium): misses + time tiles and a
   personal-best line (gold when beaten). Only rendered for single-player Memory games. */
.mem-solo { margin-top: 12px; }
.mem-solo-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.mem-solo-tile { display: flex; flex-direction: column; align-items: center; gap: 3px;
  padding: 12px 8px; border-radius: 10px;
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent) 40%, transparent); }
.mem-solo-val { font-family: 'Rye', serif; font-size: 26px; line-height: 1; color: var(--accent-ink); }
.mem-solo-lbl { font-size: 11px; color: var(--old-paper); letter-spacing: .03em; }
.mem-solo-record { margin-top: 12px; text-align: center; font-size: 13px; padding: 9px 12px; border-radius: 9px; }
.mem-solo-record.best { color: var(--gold-ink); font-weight: 700;
  background: color-mix(in srgb, var(--gold) 16%, transparent);
  border: 1px solid color-mix(in srgb, var(--gold) 50%, transparent); }
.mem-solo-record.par { color: var(--old-paper);
  background: rgba(255,255,255,.03); border: 1px solid var(--border); }

@keyframes memFlip  { from { transform: rotateY(90deg); } to { transform: rotateY(0); } }
@keyframes memMatch { 0% { box-shadow: 0 0 0 3px var(--gold), 0 0 26px var(--gold); opacity: 1; } 100% { opacity: .55; } }
@keyframes memMiss  { 0%, 100% { transform: translateX(0); } 25% { transform: translateX(-3px); } 75% { transform: translateX(3px); } }
/* Face cards now show the suit symbol centered (like number cards) — no separate court pip anymore. */
/* Narrow screens: cards more compact again, otherwise the hand exceeds the width. */

.durak-pair.open.sel-target { cursor: pointer; }
@keyframes seeTimerPulse { 0%,100% { box-shadow: 0 0 0 0 rgba(192,53,42,.0); } 50% { box-shadow: 0 0 10px 1px rgba(192,53,42,.5); } }
@media (max-width: 760px) {
    /* The desktop measure-fit pins one row (.card-board .see-main nowrap, see the
       card-board block) — below the maximize breakpoint boards + shipyard must
       stack again, otherwise the duel boards overflow narrow viewports. */
    .card-board .see-main { flex-wrap: wrap; }
} /* opponent ship (spectator) */
/* Shared sea: empty tiles (odd player count) darkened/hatched — never shootable. */
.see-cell.empty-tile { background: repeating-linear-gradient(45deg, rgba(0,0,0,.35) 0 5px, rgba(0,0,0,.18) 5px 10px), #0a141f; opacity: .55; cursor: default; }
/* Fine separator at tile borders (right/bottom edge of each tile). */
.see-cell.sep-r { box-shadow: inset -2px 0 0 color-mix(in srgb, var(--accent-light) 55%, transparent); }
.see-cell.sep-b { box-shadow: inset 0 -2px 0 color-mix(in srgb, var(--accent-light) 55%, transparent); }
.see-cell.sep-r.sep-b { box-shadow: inset -2px 0 0 color-mix(in srgb, var(--accent-light) 55%, transparent), inset 0 -2px 0 color-mix(in srgb, var(--accent-light) 55%, transparent); }
/* Hidden ship count (lobby option). */
.see-stand .pships.hidden-cnt { color: var(--smoke); font-size: 14px; }
.see-ship-item .ship-vis { display: flex; gap: 2px; }
.see-ship-item .ship-vis i { width: 12px; height: 12px; border-radius: 2px; background: linear-gradient(135deg, var(--accent-light), var(--accent)); }
.see-target-tab .t-ships { font-size: 12px; color: var(--smoke); font-variant-numeric: tabular-nums; }
.see-target-tab.active .t-ships { color: var(--heading); }

@keyframes seeHit {
  0%   { transform: scale(.35); filter: brightness(2.6); box-shadow: 0 0 0 0 rgba(232, 184, 75, .8); }
  45%  { transform: scale(1.18); filter: brightness(1.6); box-shadow: 0 0 10px 4px rgba(192, 53, 42, .65); }
  100% { transform: scale(1);    filter: brightness(1);   box-shadow: 0 0 0 0 rgba(192, 53, 42, 0); }
}
@keyframes seeSplash {
  0%   { box-shadow: 0 0 0 0 rgba(122, 162, 200, .55); }
  70%  { box-shadow: 0 0 0 7px rgba(122, 162, 200, .12); }
  100% { box-shadow: 0 0 0 9px rgba(122, 162, 200, 0); }
}
@keyframes seeSink {
  0%   { transform: translateY(-3px) scale(1.15) rotate(-6deg); filter: brightness(1.8); }
  35%  { transform: translateY(1px)  scale(1.05) rotate(5deg);  filter: brightness(1.3); }
  70%  { transform: translateY(3px)  scale(.96)  rotate(-3deg); filter: brightness(.95); }
  100% { transform: translateY(0)    scale(1)    rotate(0);     filter: brightness(.78); }
}
@keyframes seeStartFade { from { opacity: 0; } to { opacity: 1; } }
@keyframes seeStartRise { from { opacity: 0; transform: translateY(18px) scale(.96); } to { opacity: 1; transform: none; } }
@keyframes seeStartPulse {
  0%, 100% { box-shadow: 0 0 0 4px rgba(77, 126, 171, .25), 0 0 30px rgba(77, 126, 171, .5); }
  50%      { box-shadow: 0 0 0 6px rgba(77, 126, 171, .35), 0 0 46px rgba(77, 126, 171, .85); }
}
@keyframes seeStartBlink { 0%, 100% { opacity: .3; } 50% { opacity: 1; } }

/* ════════════════════════════
   LOBBY REDESIGN (mode-specific) — 'At the Table' / 'The Stage'
   Accent comes from .mode-* (--accent / --accent-light), applied
   at the .screen-lobby root. Used consistently here.
════════════════════════════ */
.lobby-redesign .lobby-title,
.lobby-redesign .lobby-section-title { color: color-mix(in srgb, var(--accent) 30%, var(--text-main)); }
.lobby-arena { padding: 18px 20px; }

/* ── At the table: elliptical felt surface with seats around it ── */
.lobby-table .felt {
  position: relative;
  height: 420px;   /* same default height as the stage (.lobby-stage-theatre) */
  margin-top: 12px;
  border-radius: 50% / 44%;
  border: 10px solid var(--felt-rim);
  background:
    radial-gradient(ellipse at 50% 42%,
      color-mix(in srgb, var(--accent) var(--felt-mix-a, 14%), var(--felt-base-a)) 0%,
      color-mix(in srgb, var(--accent) var(--felt-mix-b, 26%), var(--felt-base-b)) 60%,
      color-mix(in srgb, var(--accent) var(--felt-mix-c, 32%), var(--felt-base-c)) 100%);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 35%, transparent),
              var(--felt-shadow);
}
.lobby-table .seat {
  position: absolute;
  transform: translate(-50%, -50%);
  width: 104px;
  display: flex; flex-direction: column; align-items: center; gap: 5px;
  text-align: center;
}
.seat-filled {
  background: none; border: none; padding: 0; cursor: pointer;
  color: var(--parchment); font: inherit;
  transition: transform .12s;
}
@media (hover: hover) {
  .seat-filled:hover {
    transform: translate(-50%, -50%) scale(1.06);
  }
}
.seat-name {
  font-size: 14px; color: var(--parchment);
  max-width: 108px; overflow: hidden; white-space: nowrap;
  display: inline-flex; align-items: center; justify-content: center; gap: 3px;
}
.seat-filled.is-host .seat-name { color: var(--text-main); font-weight: 600; }
.seat-filled.is-away { opacity: .55; }
.seat-badge.badge-host { color: color-mix(in srgb, var(--accent) 30%, var(--text-main)); }
.seat-you {
  font-size: 12px; letter-spacing: .12em; text-transform: uppercase; color: var(--text-main);
}
.seat-ghost .seat-avatar-empty {
  width: 44px; height: 44px; border-radius: 50%; margin: 0 auto; font-size: 18px;
  border: 1px dashed color-mix(in srgb, var(--accent) 45%, rgba(200,146,42,.3));
  display: flex; align-items: center; justify-content: center; color: var(--text-main);
  background: var(--surface-2);
}
.seat-ghost .seat-name { color: var(--text-main); opacity: .75; }

/* ── The Stage: audience (comfortable up to 10, dense crowd beyond that) ── */
.aud-cluster {
  display: flex; flex-wrap: wrap; gap: 6px; margin-top: 12px;
  max-height: 160px; overflow-y: auto;
  scrollbar-width: thin; scrollbar-color: rgba(200,146,42,.2) transparent;
}
.aud-dot {
  position: relative; width: 32px; height: 32px; border-radius: 50%; padding: 0;
  display: flex; align-items: center; justify-content: center;
  border: 1.5px solid color-mix(in srgb, var(--accent) 35%, rgba(200,146,42,.25));
  background: rgba(8,5,2,.4); cursor: pointer; overflow: visible;
}
.aud-dot.is-host { border-color: var(--accent-light); box-shadow: 0 0 8px color-mix(in srgb, var(--accent-light) 45%, transparent); }
.aud-dot.is-me { border-color: var(--accent-light); border-width: 2px; }
.aud-dot .dot-star { position: absolute; top: -6px; right: -4px; font-size: 12px; color: var(--accent-light); }
.aud-more {
  width: 32px; height: 32px; border-radius: 50%;
  border: 1.5px dashed var(--accent); background: rgba(8,5,2,.4);
  color: var(--accent-light); font-size: 12px; cursor: pointer;
}
.aud-more:hover { background: color-mix(in srgb, var(--accent) 18%, transparent); }

/* All players modal */
.all-players-grid { display: flex; flex-direction: column; gap: 4px; max-height: 60vh; overflow-y: auto; }
.all-player-row {
  display: flex; align-items: center; gap: 10px;
  background: rgba(8,5,2,.3); border: 1px solid rgba(200,146,42,.14);
  border-radius: 4px; padding: 6px 10px; cursor: pointer; color: var(--parchment); font: inherit;
}
.all-player-row:hover { border-color: var(--accent); }
.all-player-name { font-size: 14px; }

/* ── Chat: collapsible + privacy veil ── */
.chat-title-row { display: flex; align-items: center; justify-content: space-between; }
.chat-collapse-btn, .chat-reopen {
  background: rgba(8,5,2,.4); border: 1px solid rgba(200,146,42,.24);
  color: var(--smoke); cursor: pointer; transition: all .15s; font-family: var(--font-body);
}
.chat-collapse-btn { border-radius: 3px; padding: 3px 9px; font-size: 13px; }
.chat-collapse-btn:hover, .chat-reopen:hover { border-color: var(--accent); color: var(--accent-light); }
.chat-reopen { width: 100%; text-align: center; padding: 12px; border-style: dashed; border-radius: 4px; font-size: 14px; }
.chat-messages-wrap { position: relative; }

/* ── Lobby header as hero/shield: code prominent, spotlight, accent ── */
.lobby-redesign .lobby-hero {
  position: relative; overflow: hidden;
  background: linear-gradient(180deg, color-mix(in srgb, var(--accent) 22%, #160f08) 0%, #120c07 100%);
  border: 1px solid var(--accent);
}
.lobby-redesign .lobby-hero::before {
  content: ""; position: absolute; top: -60%; left: 50%; transform: translateX(-50%);
  width: 55%; height: 180%; pointer-events: none; z-index: 0;
  background: radial-gradient(ellipse at 50% 0%, color-mix(in srgb, var(--accent-light) 22%, transparent) 0%, transparent 60%);
}
.lobby-redesign .lobby-hero .lobby-title,
.lobby-redesign .lobby-hero .lobby-header-row { position: relative; z-index: 1; }
.lobby-redesign .lobby-hero .lobby-code {
  border-color: var(--accent);
  box-shadow: 0 0 26px color-mix(in srgb, var(--accent) 34%, transparent), inset 0 0 16px rgba(0,0,0,.6);
}
.lobby-redesign .lobby-hero .streamer-toggle.is-on { border-color: var(--accent); color: var(--accent-light); }
.lobby-redesign .lobby-hero .btn-copy:hover { border-color: var(--accent); color: var(--accent-light); }
/* Stage hero: prop + 'On stage today' + game name as marquee */
.lobby-redesign .lobby-hero { padding: 12px 22px; }
.lobby-redesign .lobby-hero .buhne-eyebrow { font-size: 12px; letter-spacing: .26em; text-transform: uppercase; color: var(--smoke); position: relative; z-index: 1; }
.lobby-redesign .lobby-hero .buhne-game { display: flex; align-items: center; justify-content: center; gap: 7px; font-family: 'Rye', cursive; font-size: 28px; color: var(--accent-light); position: relative; z-index: 1; margin: 2px 0 10px; }
.lobby-redesign .lobby-hero .buhne-prop { font-size: 24px; line-height: 1; filter: drop-shadow(0 2px 4px #000); }

/* ── Unified code box: code centered, visibility on left + eye on right integrated, copy below ── */
.code-box-wrap { display: flex; flex-direction: column; align-items: center; gap: 7px; position: relative; z-index: 1; }
.code-box {
  position: relative; display: flex; align-items: center; justify-content: center;
  background: var(--surface-1-strong); border: 1px solid var(--accent); border-radius: 3px; padding: 6px 44px;
  box-shadow: 0 0 22px color-mix(in srgb, var(--accent) 30%, transparent), inset 0 0 14px var(--shadow-color);
}
.code-box-text { font-family: 'Rye', cursive; letter-spacing: .2em; color: var(--heading); font-size: 23px; }
.code-box-vis { position: absolute; left: 11px; top: 50%; transform: translateY(-50%); font-size: 13px; line-height: 1; opacity: .85; }
.code-box-eye {
  position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
  background: transparent; border: none; cursor: pointer;
  color: var(--smoke); font-size: 15px; line-height: 1; padding: 4px;
  min-width: 24px; min-height: 24px;   /* WCAG 2.5.8 */
}
.code-box-eye:hover, .code-box-eye.is-on { color: var(--accent-strong); }
.code-box-wrap .btn-copy { color: color-mix(in srgb, var(--accent) 30%, var(--text-main)); border-color: var(--accent); }
.lobby-hero .code-box-text { font-size: 25px; }
.lobby-hero .code-box { padding: 6px 46px; }

/* ── Mobile (≤700px): felt ellipse → compact felt card, seats wrap, boxes tighter ── */
@media (max-width: 700px) {
  .screen-lobby.lobby-redesign { padding: 16px 10px 34px; }
  .lobby-arena { padding: 14px 12px; }
  .lobby-redesign .lobby-stage-theatre { min-height: 300px; }
  .lobby-table .felt {
    height: auto; border-radius: 12px; border-width: 5px;
    display: flex; flex-wrap: wrap; justify-content: center; align-items: flex-start;
    gap: 14px 8px; padding: 16px 10px 18px;
  }
  .lobby-table .radar { display: none; }
  .lobby-table .felt-center { position: static; transform: none; width: 100%; flex-basis: 100%; margin-bottom: 2px; }
  .lobby-table .seat { position: static; transform: none; width: 72px; }
    @media (hover: hover) {
    .lobby-table .seat-filled:hover {
      transform: scale(1.04);
    }
  }
  .code-box { padding: 6px 36px; }
  .code-box-text, .lobby-hero .code-box-text { font-size: 21px; }
  .lobby-hero .code-box { padding: 6px 38px; }
  .lobby-redesign .lobby-hero .buhne-game { font-size: 24px; }
  .lobby-redesign .lobby-hero .buhne-prop { font-size: 21px; }
  .aud-cluster { max-height: 132px; }
}

/* ── Code coaster in the felt center (table) + slim table header ── */
.lobby-table .felt-center {
  position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
  display: flex; flex-direction: column; align-items: center; gap: 9px; text-align: center; z-index: 1;
}
.lobby-table .felt-code {
  font-size: 22px; letter-spacing: .28em; padding: 6px 18px; border-color: var(--accent);
  box-shadow: 0 0 22px color-mix(in srgb, var(--accent) 30%, transparent), inset 0 0 14px rgba(0,0,0,.6);
}
.felt-code-actions { display: flex; align-items: center; gap: 8px; }
.lobby-redesign .lobby-head-slim { padding: 9px 22px; background: var(--surface-2); }
.lobby-redesign .lobby-head-slim .lobby-title { font-size: 18px; }

/* ── Unified lobby header (3 zones) — game pill on left, code centered,
   seats/copy/chat bubble/settings on right. Replaces lobby-head-slim & lobby-hero. ── */
.lobby-redesign .lobby-uh {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  background: linear-gradient(180deg, color-mix(in srgb, var(--accent) 16%, var(--surface-1)), var(--surface-1));
  border: 1px solid var(--accent);
  border-bottom: 3px solid var(--accent);
  border-radius: 4px;
  text-align: left;
}
.lobby-uh .uh-left   { display: flex; align-items: center; gap: 9px; min-width: 0; }
.lobby-uh .uh-center { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); }
.lobby-uh .uh-right  { display: flex; align-items: center; gap: 8px; }
.lobby-uh .uh-pill   { display: inline-flex; align-items: center; gap: 9px; min-width: 0; }
.lobby-uh .uh-ico {
  width: 30px; height: 30px; flex: none; border-radius: 6px;
  display: flex; align-items: center; justify-content: center; font-size: 16px;
  background: color-mix(in srgb, var(--accent) 45%, #1a1208);
  color: #f0e6d2; border: 1px solid var(--accent);
}
.lobby-uh .uh-name {
  /* --heading instead of the raw mode accent as TEXT (documented contrast bug
     the moment a light theme exists — see convention_accent_light_never_as_text). */
  font-family: 'Rye', cursive; font-size: 18px; color: var(--heading);
  line-height: 1.1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 240px;
}
/* Copy icon docks to the right of the centered code box without pushing it off center. */
.lobby-uh .uh-center .uh-copy { position: absolute; left: 100%; top: 50%; transform: translateY(-50%); margin-left: 8px; }
.lobby-uh .uh-icon-btn {
  position: relative; background: transparent; border: 1px solid var(--accent); border-radius: 4px;
  cursor: pointer; color: color-mix(in srgb, var(--accent) 30%, var(--text-main)); width: 32px; height: 32px;
  display: flex; align-items: center; justify-content: center; font-size: 15px; line-height: 1; transition: background .15s;
}
.lobby-uh .uh-icon-btn:hover { background: color-mix(in srgb, var(--accent) 18%, transparent); }
.lobby-uh .uh-help { font-weight: 700; }
.lobby-uh .uh-leave {
  color: var(--danger);
  background: color-mix(in srgb, var(--danger) 12%, transparent);
  border-color: color-mix(in srgb, var(--danger) 55%, transparent);
}
.lobby-uh .uh-leave:hover { background: color-mix(in srgb, var(--danger) 22%, transparent); }
.lobby-uh .uh-copy.copied { border-color: var(--green-ok); color: var(--green-ok); }
.lobby-uh .uh-bubble.unread { border-color: var(--accent-light); animation: uhBubblePulse 1.4s ease-in-out infinite; }
.lobby-uh .uh-unread-dot {
  position: absolute; top: -4px; right: -4px; width: 11px; height: 11px;
  border-radius: 50%; background: var(--blood-red); border: 2px solid #140d07;
}
@keyframes uhBubblePulse {
  0%, 100% { box-shadow: 0 0 7px color-mix(in srgb, var(--accent-light) 45%, transparent); }
  50%      { box-shadow: 0 0 16px color-mix(in srgb, var(--accent-light) 85%, transparent); }
}
.lobby-uh .uh-gear {
  display: inline-flex; align-items: center; gap: 7px; font-family: var(--font-body); font-size: 13px;
  background: color-mix(in srgb, var(--accent) 10%, transparent); border: 1px solid var(--accent);
  border-radius: 4px; color: color-mix(in srgb, var(--accent) 30%, var(--text-main)); cursor: pointer; padding: 7px 11px; white-space: nowrap; transition: background .15s;
}
.lobby-uh .uh-gear:hover { background: color-mix(in srgb, var(--accent) 22%, transparent); }
/* Icon-only fallback below ~480px: the settings label is the only visible
   header-button text — on very narrow screens it collapses to the gear icon
   (accessible name preserved via aria-label on the button). */
@media (max-width: 480px) {
  .uh-gear-label { display: none; }
  .lobby-uh .uh-gear { width: 32px; height: 32px; padding: 7px; justify-content: center; }
}
/* Leave/end as a red icon in the header (to the right of settings). */
.lobby-uh .uh-leave { border-color: color-mix(in srgb, var(--blood-red) 55%, transparent); color: var(--red-light); }
.lobby-uh .uh-leave:hover { background: rgba(139, 26, 26, .14); border-color: var(--blood-red); }

/* Light: the same faint glyph outline as the poster icons, so the color emojis in the
   header's transparent toolbar buttons (history/chat/link, globe/lock/eye, gear) don't
   wash out on the pale header. The mode icon (.uh-ico) sits on its own dark tile and needs
   none; the symbol glyphs that already carry a color (? and ✕) and the gear's text label
   stay crisp. */
[data-theme="light"] .lobby-uh .uh-icon-btn:not(.uh-help):not(.uh-leave),
[data-theme="light"] .lobby-uh .uh-gear span[aria-hidden="true"],
[data-theme="light"] .lobby-uh .code-box-vis,
[data-theme="light"] .lobby-uh .code-box-eye {
  text-shadow: 0 0 1px rgba(58, 42, 22, .5), 0 1px 1px rgba(58, 42, 22, .32);
}

/* Action row below the player area (replaces chat column + sidebar) */
.lobby-actions { display: flex; flex-direction: column; gap: 10px; }
.lobby-actions-row { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
/* Start button (or wait banner) on the right: same height as history/leave
   (btn-sm-action = 6px/12px). Horizontally a bit wider for prominence. */
.lobby-actions-row .lobby-actions-start { margin-left: auto; margin-top: 0; margin-bottom: 0; width: auto; padding: 6px 18px; font-size: 12px; }
/* History/leave: text-width & left-aligned instead of stretched (btn-sm-action is flex:1 from the old sidebar context). */
.lobby-actions-row .btn-sm-action { flex: 0 0 auto; width: auto; }

/* Lobby header, player box and action row as ONE continuous panel —
   flush-stacked (no gap), 4px rounded top+bottom, touching edges square
   (one clean separator each). The button bar docks at the bottom instead of floating. */
.lobby-redesign .lobby-header { margin-bottom: 0; }
.lobby-redesign .lobby-header-card { border-bottom: none; border-radius: 4px 4px 0 0; border-color: rgba(200,146,42,.28); }
.lobby-redesign .lobby-layout { gap: 0; }
.lobby-redesign .lobby-layout > .card:first-child { border-radius: 0; }
.lobby-redesign .lobby-actions {
  border: 1px solid var(--border-soft); border-top: none; border-radius: 0 0 4px 4px;
  background: var(--surface-2); padding: 12px 16px;
}

/* Chat as a sliding-in sidebar (overlay), triggered via the header bubble */
.chat-drawer-back {
  position: fixed; inset: 0; background: rgba(0,0,0,.45);
  opacity: 0; pointer-events: none; transition: opacity .2s; z-index: 900;
}
.chat-drawer-back.open { opacity: 1; pointer-events: auto; }
/* "Telegram board": light parchment instead of a black gradient. Everything scoped under
   .chat-drawer so the global .chat-* rules (e.g. report snapshot in admin) stay untouched. */
.chat-drawer {
  position: fixed; top: 0; right: 0; bottom: 0; width: 340px; max-width: 86vw; z-index: 901;
  --tg-ink: #3a2c16; --tg-sub: #574730; --tg-slip: #fbf3e0; --tg-slip-own: #efe7cf;
  --tg-line: #c2a86f; --tg-wood: #6b4a23;
  background: radial-gradient(140% 120% at 50% -10%, #f3e9d2, #e3d4b4 70%, #d8c6a0);
  border-left: 3px solid var(--tg-wood); box-shadow: -12px 0 30px rgba(0,0,0,.5);
  transform: translateX(100%); transition: transform .24s ease;
  display: flex; flex-direction: column;
}
.chat-drawer.open { transform: translateX(0); }

/* Head: dark wooden bar with a parchment title */
.chat-drawer-head { display: flex; align-items: center; gap: 8px; padding: 12px 15px;
  background: linear-gradient(180deg, #3a2913, #2c1e10); border-bottom: 2px solid var(--tg-wood); }
.chat-drawer-head .chat-title { flex: 1; color: var(--gold-light); }
.chat-drawer-close { background: transparent; border: none; color: #d9c39a; cursor: pointer; font-size: 16px; line-height: 1; padding: 4px; min-width: 24px; min-height: 24px; }
.chat-drawer-close:hover { color: #fff; }

.chat-drawer .chat-messages-wrap { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.chat-drawer .chat-messages { flex: 1; height: auto; min-height: 0; padding: 12px; gap: 6px;
  scrollbar-color: rgba(107,74,35,.4) transparent; }
.chat-drawer .chat-messages::-webkit-scrollbar-thumb { background: rgba(107,74,35,.4); }

/* Status bar centered, muted */
.chat-drawer .chat-status { justify-content: center; }
.chat-drawer .chat-status-text { color: var(--tg-sub); }
.chat-drawer .chat-status .chat-time { color: var(--tg-sub); opacity: .8; }

/* Nachricht als Telegramm-Zettel */
.chat-drawer .chat-msg { background: var(--tg-slip); border: 1px solid #cdb98c; border-radius: 6px;
  padding: 5px 9px; box-shadow: 0 1px 2px rgba(80,55,20,.12); }
.chat-drawer .chat-msg-own { background: var(--tg-slip-own); border-color: var(--tg-line); }
/* SS-0312-E2-Nebenbefund: #9a865f fiel auf dem hellsten Papier-Stop auf 3,2:1. */
.chat-drawer .chat-msg .chat-time { color: var(--tg-sub); }
.chat-drawer .chat-msg .chat-sender { color: #7a4a16; }
.chat-drawer .chat-msg-own .chat-sender { color: #8a5a10; }
.chat-drawer .chat-msg .chat-text { color: var(--tg-ink); }

/* Eingabe + Senden auf Pergament */
.chat-drawer .chat-input-row { padding: 11px 12px; border-top: 1px solid var(--tg-line); background: #e7d7b6; }
.chat-drawer .chat-inp { background: var(--tg-slip); border: 1px solid var(--tg-line); color: var(--tg-ink); }
.chat-drawer .chat-inp::placeholder { color: #9a865f; }
.chat-drawer .chat-inp:focus { border-color: #8a5a10; box-shadow: 0 0 10px rgba(138,90,16,.18); }
.chat-drawer .chat-send-btn { background: var(--tg-wood); border: 1px solid #4f3415; color: #f3e2bf; border-radius: 5px; }
.chat-drawer .chat-send-btn:hover:not(:disabled) { background: #7d5828; border-color: #4f3415; }

/* Empty state instead of black emptiness */
.chat-drawer .chat-empty { margin: auto; text-align: center; padding: 20px;
  display: flex; flex-direction: column; align-items: center; gap: 8px; }
.chat-drawer .chat-empty-glyph { font-size: 34px; line-height: 1; opacity: .85; }
.chat-drawer .chat-empty-title { font-size: 14px; font-style: italic; color: #5a4321; }
.chat-drawer .chat-empty-hint { font-size: 12px; color: var(--tg-sub); }

/* ── "The Stage" as a theatre: min-height + curtain, spotlight, footlights, stage floor;
   players stand as performers on the floor (≤10) or as a dense ensemble (>10). ── */
.lobby-redesign .lobby-stage-theatre {
  position: relative; min-height: 420px; overflow: hidden; border-radius: 8px; margin-top: 4px;
  display: flex; flex-direction: column; justify-content: flex-end;
  background: radial-gradient(120% 95% at 50% 130%, color-mix(in srgb, var(--accent) 18%, var(--stage-back-a)), var(--stage-back-b) 72%);
  border: 1px solid var(--border-soft);
}
.stage-valance { position: absolute; top: 0; left: 0; right: 0; height: 28px; z-index: 4; background: linear-gradient(180deg, #6e2326, #4a1416); box-shadow: 0 3px 8px rgba(0,0,0,.5); }
.stage-valance::after { content: ""; position: absolute; left: 0; right: 0; bottom: -9px; height: 9px; background: repeating-linear-gradient(90deg, #7a2a2d 0 7px, #5a1c1f 7px 14px); clip-path: polygon(0 0,5% 100%,10% 0,15% 100%,20% 0,25% 100%,30% 0,35% 100%,40% 0,45% 100%,50% 0,55% 100%,60% 0,65% 100%,70% 0,75% 100%,80% 0,85% 100%,90% 0,95% 100%,100% 0); }
.stage-drape { position: absolute; top: 0; bottom: 0; width: 46px; z-index: 3; background: repeating-linear-gradient(90deg, #5a1a1c, #6e2326 9px, #491315 18px); box-shadow: inset -12px 0 18px rgba(0,0,0,.5); }
.stage-drape-l { left: 0; }
.stage-drape-r { right: 0; transform: scaleX(-1); }
.stage-spot { position: absolute; top: -6%; left: 50%; transform: translateX(-50%); width: 58%; height: 118%; z-index: 1; pointer-events: none; background: radial-gradient(ellipse at 50% 0%, color-mix(in srgb, var(--accent-light) 24%, transparent) 0%, transparent 62%); }
.stage-hint { position: absolute; top: 76px; left: 0; right: 0; text-align: center; z-index: 3; font-family: 'Rye', cursive; font-size: 13px; letter-spacing: .08em; color: var(--text-main); }
.stage-floor { position: absolute; left: 0; right: 0; bottom: 0; height: 76px; z-index: 1; border-top: 3px solid var(--accent); background: repeating-linear-gradient(90deg, var(--stage-floor-a) 0 28px, var(--stage-floor-b) 28px 56px); box-shadow: inset 0 10px 20px var(--shadow-color); }
.stage-footlights { position: absolute; left: 46px; right: 46px; bottom: 72px; display: flex; justify-content: center; gap: 16px; z-index: 5; pointer-events: none; }
.stage-footlights span { width: 8px; height: 8px; border-radius: 50%; background: var(--accent-light); box-shadow: 0 0 8px var(--accent-light), 0 0 18px color-mix(in srgb, var(--accent-light) 60%, transparent); }
.stage-troupe { position: relative; z-index: 6; display: flex; flex-wrap: wrap; justify-content: center; align-items: flex-end; gap: 10px 18px; padding: 0 58px 24px; }
.stage-perf { background: transparent; border: none; cursor: pointer; display: flex; flex-direction: column; align-items: center; gap: 5px; padding: 0; width: 72px; transition: transform .12s; }
@media (hover: hover) {
  .stage-perf:hover {
    transform: translateY(-3px);
  }
}
.stage-perf-av { position: relative; display: inline-flex; border-radius: 50%; }
.stage-perf.is-host .stage-perf-av { box-shadow: 0 0 12px color-mix(in srgb, var(--accent-light) 55%, transparent); }
.stage-perf.is-me .stage-perf-av { outline: 2px solid var(--gold-light); outline-offset: 2px; }
.stage-perf.is-away { opacity: .5; }
.stage-perf-star { position: absolute; top: -7px; right: -5px; font-size: 13px; color: color-mix(in srgb, var(--accent) 30%, var(--text-main)); text-shadow: 0 1px 2px var(--shadow-color); }
.stage-perf-nm { font-size: 12px; color: var(--parchment); white-space: nowrap; max-width: 108px; overflow: hidden; text-overflow: ellipsis; display: inline-flex; align-items: center; justify-content: center; gap: 3px; }
.stage-perf-you { color: var(--text-main); font-weight: 600; }
.stage-perf-free { align-self: flex-end; margin-bottom: 8px; font-size: 12px; color: var(--text-main); opacity: .8; font-style: italic; border: 1px dashed rgba(200,146,42,.25); border-radius: 20px; padding: 6px 12px; }
.stage-aud { position: relative; z-index: 6; margin: 0; padding: 14px 54px 24px; justify-content: center; }

/* ════════════════════════════════════════════════════════════════════════════
   SS — Projektweiter Button-Standard: einheitlicher Eckenradius (Weich, --btn-radius).
   EINE Stelle für ALLE echten Aktions-Buttons. .btn deckt alle .btn-Kompositionen ab
   (btn-gold/-ghost/-amber/-green/-oauth/-sm/-xs/-edit/-sm-action/-start-sidebar/-vote/
   -block/podium-btn/tdm-btn/mq-play-btn/tabu-skip-btn/profile-history-btn …); die übrigen
   Selektoren sind eigenständige Buttons ohne .btn-Basis.
   BEWUSST AUSGENOMMEN (bleiben wie sie sind): runde Icon-/Avatar-Buttons
   (.mute-btn/.header-help-btn/.profile-btn/.help-icon-btn = 50%), Schalter
   (.settings-toggle-btn), rahmenlose Textlinks (.btn-back-history) und Chips/Tags/Pillen.
   ════════════════════════════════════════════════════════════════════════════ */
.btn,
.btn-red, .btn-ghost-red, .abort-btn, .btn-copy, .chat-send-btn, .chat-collapse-btn,
.report-flag-btn, .auth-btn, .edit-btn, .mm-join-btn, .mm-page-btn, .lot-page-btn,
.lobby-uh .uh-icon-btn, .lobby-uh .uh-gear {
  border-radius: var(--btn-radius);
}

/* Mobile: head stacked, code no longer absolutely centered */
@media (max-width: 700px) {
  .lobby-redesign .lobby-uh { flex-direction: column; gap: 9px; }
  .lobby-uh .uh-center { position: static; transform: none; display: inline-flex; align-items: center; gap: 8px; }
  .lobby-uh .uh-center .uh-copy { position: static; transform: none; margin-left: 0; }
  .lobby-uh .uh-right { flex-wrap: wrap; justify-content: center; }
}

/* ── Schub 2: Signatur-Requisit im Filz-Zentrum je Tisch-Spiel ── */
.lobby-table .tprop {
  display: flex; align-items: flex-end; justify-content: center; gap: 6px;
  min-height: 44px; margin-bottom: 2px; position: relative; z-index: 1;
}
.tprop-ship { width: 58px; height: 30px; filter: drop-shadow(0 2px 4px #000); }
.tprop-cross { width: 28px; height: 28px; }
.tprop-card {
  width: 28px; height: 40px; border-radius: 3px;
  background: linear-gradient(160deg, #f4ecd8, #dcc9a0); border: 1px solid #8a6a3a;
  color: #7a1f1f; font-weight: 700; font-size: 12px;
  display: flex; align-items: center; justify-content: center; box-shadow: 0 3px 7px rgba(0,0,0,.5);
}
.tprop-card.l { transform: rotate(-9deg) translateY(-3px); }
.tprop-card.r { transform: rotate(9deg) translateY(-3px); }
.tprop-back {
  width: 28px; height: 40px; border-radius: 3px; border: 1px solid var(--accent-light);
  background: repeating-linear-gradient(45deg,
    color-mix(in srgb, var(--accent) 70%, #1a1208) 0 5px,
    color-mix(in srgb, var(--accent) 45%, #1a1208) 5px 10px);
}
.tprop-mask { font-size: 32px; filter: drop-shadow(0 2px 4px #000); line-height: 1; }
/* Schnellschuss: mini shedding cards (own brand colors, not the ivory playing cards) */
.tprop-ssk { width: 28px; height: 40px; border-radius: 4px; display: flex; align-items: center; justify-content: center;
  font-family: 'Rye', cursive; font-size: 13px; color: #fff; text-shadow: 0 1px 2px rgba(0,0,0,.6);
  border: 1.5px solid rgba(255,255,255,.55); box-shadow: 0 3px 7px rgba(0,0,0,.5); }
.tprop-ssk.c-red { background: #b5392f; }
.tprop-ssk.c-blue { background: #2f74a6; }
.tprop-ssk.wild { background: radial-gradient(120% 120% at 50% 34%, #2c1e10, #160f08 72%);
  border-color: var(--accent-light); color: var(--accent-light); font-size: 15px; }
.tprop-ssk.l { transform: rotate(-9deg) translateY(-3px); }
.tprop-ssk.r { transform: rotate(9deg) translateY(-3px); }
/* Rausschmeisser: pawn trio (classic player colors) + die */
.tprop-pawn { width: 22px; height: 28px; filter: drop-shadow(0 2px 4px #000); }
.tprop-pawn.l { transform: rotate(-8deg) translateY(1px); }
.tprop-pawn.r { transform: rotate(8deg) translateY(1px); }
.tprop-die { font-size: 24px; line-height: 1; color: #f1e7d0; filter: drop-shadow(0 2px 4px #000);
  align-self: center; margin-left: 2px; }
/* Mahjong: ivory tile trio with the real CC0 faces */
.tprop-tile { width: 26px; height: 34px; border-radius: 4px; display: flex; align-items: center; justify-content: center;
  background: linear-gradient(160deg, #efdcb4, #d6bd92); border: 1px solid #b89a63;
  box-shadow: 0 3px 0 0 #8a7047, 0 3px 7px rgba(0,0,0,.5); }
.tprop-tile img { width: 18px; height: 24px; object-fit: contain; }
.tprop-tile.l { transform: rotate(-9deg) translateY(-2px); }
.tprop-tile.r { transform: rotate(9deg) translateY(-2px); }
/* Boomtown: terrain hex trio (forest / pasture camp / wheat) */
.tprop-hex { width: 30px; height: 34px; display: grid; place-items: center; font-size: 15px; line-height: 1;
  clip-path: polygon(50% 0, 100% 25%, 100% 75%, 50% 100%, 0 75%, 0 25%);
  filter: drop-shadow(0 2px 4px #000); }
.tprop-hex.mid { width: 36px; height: 41px; font-size: 18px; margin-top: -4px; }

/* Battleship war council: sonar rings + slow radar sweep over the felt */
.lobby-table .radar {
  position: absolute; inset: 6%; border-radius: 50% / 44%; overflow: hidden;
  pointer-events: none; opacity: .5; z-index: 0;
  background: repeating-radial-gradient(circle at 50% 50%,
    transparent 0 28px, color-mix(in srgb, var(--accent-light) 16%, transparent) 28px 29px);
}
.lobby-table .radar::after {
  content: ""; position: absolute; inset: -20%; transform-origin: 50% 50%;
  background: conic-gradient(from 0deg, color-mix(in srgb, var(--accent-light) 24%, transparent) 0deg, transparent 55deg);
  animation: lobbyRadarSweep 6s linear infinite;
}
@keyframes lobbyRadarSweep { to { transform: rotate(360deg); } }

/* ════════════════════════════════════════════════════════════
   „Runde beendet"-Signal — Overlay über dem eingefrorenen Brett im
   RoundBreak-State (Memory / Durak / Seeschlacht; rollout-fähig).
   position:fixed über dem Spiel, pointer-events:none (blockiert nichts),
   z-index unter Header/Toast/Modal. Komponente: Components/Shared/
   RoundOverCue.razor · Mockup: docs/mockups/round-over-signal.html
   ════════════════════════════════════════════════════════════ */
.round-over {
  position: fixed; inset: 0; z-index: 50;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 18px; pointer-events: none;
  background: radial-gradient(ellipse at center, rgba(0,0,0,.32) 30%, rgba(0,0,0,.62) 100%);
  animation: roDim .45s ease-out both;
}
@keyframes roDim { from { opacity: 0; } to { opacity: 1; } }

/* Wax/Wanted stamp: slams in with a slight rotation */
.round-over-stamp {
  font-family: 'Rye', cursive; text-transform: uppercase; letter-spacing: .04em;
  color: var(--accent-light); text-align: center;
  padding: 14px 34px; border: 4px double var(--accent-light); border-radius: 10px;
  background: color-mix(in srgb, var(--accent) 18%, rgba(13,10,7,.72));
  transform: rotate(-7deg);
  text-shadow: 0 2px 0 rgba(0,0,0,.5), 0 0 22px color-mix(in srgb, var(--accent-light) 45%, transparent);
  box-shadow: 0 0 0 1px rgba(0,0,0,.4), 0 14px 40px rgba(0,0,0,.55);
  animation: roStamp .5s cubic-bezier(.2,1.4,.35,1) both;
}
.round-over-stamp .ro-title { display: block; font-size: clamp(30px, 6vw, 52px); }
.round-over-stamp .ro-sub {
  display: block; font-family: var(--font-body); font-weight: 700; letter-spacing: .18em;
  font-size: 13px; color: var(--gold-light); margin-top: 6px; opacity: .85;
}
@keyframes roStamp {
  0%   { opacity: 0; transform: rotate(-7deg) scale(2.6); }
  60%  { opacity: 1; transform: rotate(-7deg) scale(.92); }
  80%  { transform: rotate(-7deg) scale(1.04); }
  100% { transform: rotate(-7deg) scale(1); }
}

/* Static "result incoming..." hint (intentionally does NOT count visibly) */
.round-over-badge {
  font-family: var(--font-body); font-weight: 600; font-size: 15px; color: var(--parchment);
  background: rgba(0,0,0,.5); border: 1px solid var(--accent-light); border-radius: 999px;
  padding: 7px 18px; opacity: 0; animation: roBadge .4s ease-out .35s forwards;
}
@keyframes roBadge { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

/* ── Situative Flourishes ── */
.ro-flourish { position: absolute; inset: 0; pointer-events: none; }

/* Memory: aufsteigende Funken (Paare setzen sich) */
.ro-sparks span {
  position: absolute; bottom: 38%; width: 8px; height: 8px; border-radius: 50%;
  background: var(--accent-light); box-shadow: 0 0 12px var(--accent-light);
  opacity: 0; animation: roRise 1.2s ease-out forwards;
}
@keyframes roRise {
  0%   { opacity: 0; transform: translateY(40px) scale(.4); }
  20%  { opacity: 1; }
  100% { opacity: 0; transform: translateY(-120px) scale(1); }
}

/* Durak: taunt banner for the loser */
.ro-durak {
  display: flex; align-items: flex-end; justify-content: center; padding-bottom: 14%;
  font-family: 'Rye', cursive; color: var(--red-light); font-size: 26px; letter-spacing: .3em;
  text-shadow: 0 2px 10px rgba(0,0,0,.6);
  opacity: 0; animation: roBadge .45s ease-out .6s forwards;
}

/* Schnellschuss: "shot empty" banner */
.ro-schnellschuss {
  display: flex; align-items: flex-end; justify-content: center; padding-bottom: 14%;
  font-family: 'Rye', cursive; color: var(--accent-light); font-size: 24px; letter-spacing: .26em;
  text-shadow: 0 2px 10px rgba(0,0,0,.6);
  opacity: 0; animation: roBadge .45s ease-out .6s forwards;
}

/* Battleship: rising smoke over the hit fleet */
.ro-smoke span {
  position: absolute; bottom: 30%; width: 60px; height: 60px; border-radius: 50%;
  background: radial-gradient(circle, rgba(180,170,160,.5), transparent 70%);
  opacity: 0; animation: roSmoke 1.8s ease-out forwards;
}
@keyframes roSmoke {
  0%   { opacity: 0; transform: translateY(0) scale(.3); }
  30%  { opacity: .7; }
  100% { opacity: 0; transform: translateY(-90px) scale(2.2); }
}

@media (prefers-reduced-motion: reduce) {
  .round-over, .round-over-stamp, .round-over-badge,
  .ro-sparks span, .ro-durak, .ro-schnellschuss, .ro-smoke span { animation-duration: .01ms; }
}

/* ── IconSelect: custom dropdown with a fixed icon column + right-aligned counter ──
   GLOBAL (was previously only in admin.css → unstyled in the lobby/game = white box).
   Moved here so the control appears everywhere in the same Saloon look; uses the global
   :root vars (--border/--old-paper/--amber/--smoke). The open list is positioned via
   ssIconSelect (helpers.js, global). */
.icon-select { position: relative; display: inline-block; min-width: 150px; }
.icon-select.block { display: block; width: 100%; }
.icon-select:focus { outline: none; }
.icon-select:focus-visible .icon-select-btn { border-color: var(--amber); }
.icon-select-btn {
  width: 100%;
  display: grid;
  grid-template-columns: 1.7em 1fr auto;
  align-items: center;
  gap: 8px;
  padding: 7px 8px;
  background: var(--input-bg);
  border: 1px solid var(--border);
  border-radius: 2px;
  color: var(--old-paper);
  font-size: 12px;
  cursor: pointer;
  text-align: left;
}
.icon-select.open .icon-select-btn,
.icon-select-btn:hover { border-color: var(--amber); }
.icon-select-btn:disabled { opacity: .5; cursor: not-allowed; }
.icon-select-ico  { display: inline-flex; justify-content: center; width: 1.7em; }
.icon-select-lbl  { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.icon-select-lbl.ph { color: var(--smoke); }
.icon-select-chev { color: var(--smoke); font-size: 12px; }
.icon-select-backdrop { position: fixed; inset: 0; z-index: 40; }
.icon-select-list {
  position: fixed; z-index: 41; left: 0; top: 0;
  width: max-content; max-width: min(360px, 90vw);
  max-height: 320px; overflow-y: auto;
  background: var(--surface-1-strong);
  border: 1px solid var(--border);
  border-radius: 2px;
  box-shadow: 0 14px 36px rgba(0,0,0,.6);
}
.icon-select-opt {
  display: grid;
  grid-template-columns: 1.7em 1fr auto;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  cursor: pointer;
  color: var(--old-paper);
  border-bottom: 1px solid rgba(200,146,42,.08);
  font-size: 12px;
}
.icon-select-opt:last-child { border-bottom: none; }
.icon-select-opt:hover,
.icon-select-opt.hl  { background: rgba(200,146,42,.12); }
.icon-select-opt.sel { background: rgba(200,146,42,.20); }
.icon-select-opt.all { font-weight: 600; }
.icon-select-name  { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.icon-select-count { color: var(--smoke); font-size: 12px; font-variant-numeric: tabular-nums; }

/* ═══════════════════════════════════════════════════════════════════════════
   Schattenspiel · Variante „Undercover"  (verdeckte Rollen + Eliminierungs-Loop)
   Akzent = mode-schattenspiel (Pflaume). Geist-Palette: fahles Blaugrau.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Geist-Figur (Reveal-Intro), analog zur Crewmate-Figur ── */
.ghost-figure { position: relative; width: 110px; height: 170px; margin: 0 auto; opacity: .94; }
.g-hat-crown { position: absolute; top: -14px; left: 50%; transform: translateX(-50%); width: 38px; height: 26px;
  background: linear-gradient(180deg,#54636e,#39454e); border: 1px solid #28323a; border-radius: 6px 6px 3px 3px; }
.g-hat-brim { position: absolute; top: 11px; left: 50%; transform: translateX(-50%); width: 66px; height: 10px;
  background: linear-gradient(180deg,#46555f,#2e3940); border: 1px solid #28323a; border-radius: 3px; }
.g-head { position: absolute; top: 18px; left: 50%; transform: translateX(-50%); width: 38px; height: 38px; border-radius: 50%;
  background: radial-gradient(circle at 50% 38%, #d6e2ec, #8ea3b3); border: 1px solid #5b6b78; }
.g-eyes { position: absolute; top: 32px; left: 50%; transform: translateX(-50%); color: #28333c; letter-spacing: 6px; font-size: 12px; z-index: 2; }
.g-body { position: absolute; bottom: 28px; left: 50%; transform: translateX(-50%); width: 54px; height: 88px;
  background: linear-gradient(180deg, rgba(174,191,204,.85), rgba(111,132,148,.5)); border: 1px solid #46555f; border-radius: 22px 22px 16px 16px; }
.g-glow { position: absolute; bottom: -10px; left: 50%; transform: translateX(-50%); width: 72px; height: 16px; border-radius: 50%;
  background: radial-gradient(ellipse, rgba(174,191,204,.4) 0%, transparent 70%); }
@keyframes figGhostPulse { 0%,100% { filter: drop-shadow(0 0 6px rgba(174,191,204,.3)); } 50% { filter: drop-shadow(0 0 16px rgba(174,191,204,.55)); } }

/* ── Schattenspiel left column framed as ONE panel (SS-0328, Option B) ──────────
   Both the classic Schattenspiel (Game.razor RenderPlaying) and the Undercover
   variant (UndercoverPlaying) put their left column in `.ss-panel`. Instead of
   stacked floating cards it sits in a single Saloon-gold frame; the inner cards
   become sections (hero wash for the secret word, subtle wells for the turn list
   + clue input). Only inside the card-board shell — outside it the classic stacked
   look is unaffected. */
.card-board .ss-panel {
  background: linear-gradient(135deg, var(--board-grad-a), var(--board-grad-b));
  border: 1px solid var(--board-border);
  border-radius: 6px;
  box-shadow: var(--board-shadow);
  padding: 16px 18px;
  display: flex; flex-direction: column; gap: 12px;
}
/* Flex gap owns the spacing — drop the cards' own margins to avoid double gaps. */
.card-board .ss-panel > * { margin: 0; }
/* Secret word = hero section: accent wash + accent-tinted border (civilian). */
.card-board .ss-panel .secret-word-card {
  background:
    radial-gradient(ellipse at 50% 0%, color-mix(in srgb, var(--accent) 24%, transparent) 0%, transparent 62%),
    var(--well);
  border: 1px solid color-mix(in srgb, var(--accent) 34%, var(--board-border));
  border-radius: 8px;
}
/* Impostor keeps red; overrides the accent wash with a red wash + red border. */
.card-board .ss-panel .secret-word-card.card-red {
  background:
    radial-gradient(ellipse at 50% 0%, rgba(139,26,26,.28) 0%, transparent 62%),
    var(--well);
  border-color: rgba(139,26,26,.5);
}
/* Ghost keeps its cool border (the !important rule already survives); add a well. */
.card-board .ss-panel .secret-word-card.uc-ghost-word { background: var(--well); }
/* Turn list + clue input = subtle well sections. */
.card-board .ss-panel .card-turn-list,
.card-board .ss-panel .card-clue-input {
  background: var(--well);
  border: 1px solid var(--board-border);
  border-radius: 8px;
}
/* Impostor clue input keeps its red section border. */
.card-board .ss-panel .card-clue-input.card-red { border-color: rgba(139,26,26,.5); }

/* Spectator god-view is a single card → frame it like the other single game cards. */
.card-board .uc-spectator .card-turn-list {
  background: linear-gradient(135deg, var(--board-grad-a), var(--board-grad-b));
  border: 1px solid var(--board-border);
  border-radius: 6px;
  box-shadow: var(--board-shadow);
}

/* Impostor mission + category cards (classic Schattenspiel, above the game layout)
   are also stripped in the card-board shell → floating. Frame them as red-tinted
   panels (they carry the .card-red role signal) so they no longer hang in the air. */
.card-board .impostor-mission,
.card-board .impostor-category {
  background: linear-gradient(135deg, var(--board-grad-a), var(--board-grad-b));
  border: 1px solid rgba(139, 26, 26, .5);
  border-radius: 8px;
  box-shadow: var(--board-shadow);
  margin-left: auto; margin-right: auto;
}

/* Diskussions-Banner */
.disc-banner { background: color-mix(in srgb, var(--accent) 10%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent) 35%, transparent); border-radius: 8px;
  padding: 12px 16px; text-align: center; color: var(--accent-ink); font-size: 14px; margin-top: 12px; }
.spectator-banner { display: flex; align-items: center; gap: 10px; justify-content: center; max-width: 560px; margin: 0 auto 14px;
  background: color-mix(in srgb, var(--well) 67%, transparent); border: 1px solid var(--border); border-radius: 10px; padding: 10px 14px; color: var(--old-paper); font-size: 13px; }
.spectator-banner .eye { font-size: 16px; }
.uc-vote-head .r-title { font-family: 'Rye', cursive; font-size: 26px; color: var(--accent-ink); }
.role-pill { background: color-mix(in srgb, var(--accent) 25%, transparent); border: 1px solid color-mix(in srgb, var(--accent) 45%, transparent);
  border-radius: 999px; padding: 4px 12px; font-size: 12px; color: var(--accent-ink); font-weight: 600; }
.role-pill.ghost { background: rgba(111,132,148,.22); border-color: rgba(174,191,204,.45); color: #aebfcc; }
.uc-reveal .r-title { font-family: 'Rye', cursive; font-size: 24px; color: var(--accent-ink); }
.tally-reveal { max-width: 480px; margin: 12px auto 0; display: flex; flex-direction: column; gap: 8px; }
.tally-row { display: flex; align-items: center; gap: 10px; padding: 9px 12px; background: color-mix(in srgb, var(--well) 67%, transparent);
  border: 1px solid var(--border); border-radius: 8px; }
.tally-row.top { border-color: color-mix(in srgb, var(--accent) 60%, transparent); background: color-mix(in srgb, var(--accent) 13%, transparent); }
.tally-row .nm { color: var(--parchment); font-weight: 600; min-width: 84px; text-align: left; }
.tally-row .tokens { display: flex; gap: 5px; align-items: center; justify-content: flex-start; min-height: 19px; }
.vtoken { display: inline-grid; place-items: center; font-size: 18px; line-height: 1; transform: scale(0); opacity: 0;
  filter: drop-shadow(0 1px 2px rgba(0,0,0,.55)); animation: ucPop .4s cubic-bezier(.2,1.4,.4,1) both; }
@keyframes ucPop { from { transform: scale(0); opacity: 0; } to { transform: scale(1); opacity: 1; } }
@keyframes ucFadeIn { to { opacity: 1; } }
@keyframes ucKickout {
  0% { left: 150px; top: 96px; transform: rotate(0) scale(.85); opacity: .15; }
  30% { opacity: 1; }
  100% { left: 392px; top: 64px; transform: rotate(230deg) scale(1.05); opacity: 1; } }
@keyframes ucStamp { 0% { transform: rotate(-11deg) scale(.4); opacity: 0; } 60% { transform: rotate(-11deg) scale(1.15); opacity: 1; } 100% { transform: rotate(-11deg) scale(1); opacity: .95; } }

/* Base card size for Schnellschuss — a touch larger than Durak's 60x84 (sparser table, no pips). */
.mode-schnellschuss .durak-board { --card-w: 72px; --card-h: 100px; }
/* Topbar badges sit centered above the felt (no trailing widget to balance the row otherwise). */
.mode-schnellschuss .durak-topbar { justify-content: center; }
/* "Deine Hand · N Karten" header centered over the hand fan (mode-scoped so Durak/Poker/Skat
   keep their left-aligned shared header); .grow spacer neutralized so it doesn't push left. */
.mode-schnellschuss .durak-hand-head { justify-content: center; }
.mode-schnellschuss .durak-hand-head .grow { display: none; }
@keyframes ssk-note-in { from { opacity: 0; transform: translate(-50%, calc(-100% + 8px)); }
    to { opacity: 1; transform: translate(-50%, -100%); } }
.ssk-card.c-red    { background: #b5392f; } .ssk-card.c-red    .ssk-big { color: #b5392f; }
.ssk-card.c-yellow { background: #d9a527; } .ssk-card.c-yellow .ssk-big { color: #9c6e10; }
.ssk-card.c-green  { background: #3f8a52; } .ssk-card.c-green  .ssk-big { color: #3f8a52; }
.ssk-card.c-blue   { background: #2f74a6; } .ssk-card.c-blue   .ssk-big { color: #2f74a6; }
.ssk-cbtn.c-red { background: #b5392f; } .ssk-cbtn.c-yellow { background: #d9a527; }
.ssk-cbtn.c-green { background: #3f8a52; } .ssk-cbtn.c-blue { background: #2f74a6; }
@keyframes ssk-cine-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes ssk-cine-pop { 0% { transform: scale(.5); opacity: 0; } 60% { transform: scale(1.06); } 100% { transform: scale(1); opacity: 1; } }
@keyframes ssk-cine-flip { 0% { transform: rotateY(90deg) scale(1.2); opacity: 0; } 60% { transform: rotateY(-10deg) scale(2.1); } 100% { transform: rotateY(0) scale(2); opacity: 1; } }
@keyframes ssk-cine-shake { 0%,100% { transform: translateX(0); } 20% { transform: translateX(-4px); } 40% { transform: translateX(4px); } 60% { transform: translateX(-3px); } 80% { transform: translateX(3px); } }
@keyframes ssk-draw-pop { 0% { transform: scale(.8); opacity: 0; } 100% { transform: scale(1); opacity: 1; } }
@keyframes ssk-draw-bob { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-3px); } }
@media (min-width: 761px) {
  body.ss-maximized .card-board > .screen-game.mode-rausschmeisser { display: flex; flex-direction: column; }
  body.ss-maximized .mode-rausschmeisser > .rsm-board { flex: 1 1 auto; min-height: 0; }
}
@keyframes rsm-vpulse { 0%, 100% { opacity: .35; } 50% { opacity: 1; } }   /* Prompt-Karte bleibt dunkel (Kino-Muster) → --raw-* statt --accent-light/mode-getönt, gilt für alle Würfelspiele (Rausschmeisser+Boomtown teilen diese Klasse) */
   /* Prompt-Karte bleibt dunkel (Kino-Muster) */
@keyframes rsm-rp-glow { 0%, 100% { box-shadow: 0 18px 50px rgba(0,0,0,.55), 0 0 0 rgba(125,151,168,0); }
    50% { box-shadow: 0 18px 50px rgba(0,0,0,.55), 0 0 30px rgba(125,151,168,.55); } }
@keyframes dcvPulse { 0%, 100% { box-shadow: 0 0 0 0 rgba(192,53,42,.5); } 50% { box-shadow: 0 0 0 8px rgba(192,53,42,0); } }
@keyframes rsm-tumble { 0% { transform: rotate(0deg) translateY(0); } 25% { transform: rotate(95deg) translateY(-12px); }
    50% { transform: rotate(185deg) translateY(0); } 75% { transform: rotate(280deg) translateY(-9px); } 100% { transform: rotate(360deg) translateY(0); } }
@keyframes rsm-sum-pop { from { transform: scale(.4); opacity: 0; } to { transform: scale(1); opacity: 1; } }
@keyframes rsm-toast-in { from { transform: translateY(16px); opacity: 0; } to { transform: translateY(0); opacity: 1; } }
.ro-flourish.ro-rausschmeisser { font-family: 'Rye', cursive; font-size: 30px; color: var(--accent-ink);
    text-shadow: 0 3px 10px rgba(0,0,0,.7); }
/* Topbar info (layout/tiles/status/hint) sits CENTERED above the board (owner preference) —
   neutralize the .grow spacer that would push the tools to the right edge. */
.mode-mahjong .durak-topbar { justify-content: center; }
.mode-mahjong .durak-topbar .grow { display: none; }
/* Maximized: shadowSaloon.fitMahjong measures the host and sets --scale inline (measured
   fit); --scale:1.6 is only the no-JS fallback. overflow:hidden — the fit guarantees the
   board fits, and auto-scrollbars would shrink the measured area and feed back into the
   next fit (bars appear ↔ disappear). max-width:none overrides the inline 1100px cap
   (same pattern as the maximized durak-board) so wide layouts can use the full width. */
@media (min-width: 761px) {
  body.ss-maximized .card-board > .screen-game.mode-mahjong { display: flex; flex-direction: column; }
  body.ss-maximized .mode-mahjong > .mjg-board { flex: 1 1 auto; min-height: 0; max-width: none !important; }
  /* Height chain continued through the new .mjg-layout grid (same pattern as
     mode-memory > .hangman-layout): the maximized fit reads .mjg-stage-wrap's
     clientHeight as its budget, so the wrap MUST be height-locked by the layout.
     Without this the wrap is content-sized and feeds the fit its own output —
     a shrink loop down to the 0.72 floor. */
  body.ss-maximized .mode-mahjong .mjg-layout {
      flex: 1 1 auto; min-height: 0;
      grid-template-rows: minmax(0, 1fr); align-items: stretch;
  }
  body.ss-maximized .mode-mahjong .mjg-sidebar { align-self: start; }
}
@keyframes mjg-hint-pulse { 0%, 100% { box-shadow: 0 0 0 2px var(--gold), var(--mjg-sh, 0 calc(2px * var(--scale)) 0 0 #8a7047, 0 4px 7px rgba(0,0,0,.42)); }
    50% { box-shadow: 0 0 0 4px var(--gold-light), 0 0 18px rgba(232,184,75,.65), var(--mjg-sh, 0 calc(2px * var(--scale)) 0 0 #8a7047, 0 4px 7px rgba(0,0,0,.42)); } }
@keyframes mjg-toast-in { from { transform: translateY(12px); opacity: 0; } to { transform: translateY(0); opacity: 1; } }   /* Prompt-Karte bleibt dunkel (Kino-Muster) → --raw-* statt --accent-light/mode-getönt */
   /* Prompt-Karte bleibt dunkel (Kino-Muster) */
@keyframes mjg-sp-glow { 0%, 100% { box-shadow: 0 18px 50px rgba(0,0,0,.55), 0 0 0 rgba(184,168,136,0); }
    50% { box-shadow: 0 18px 50px rgba(0,0,0,.55), 0 0 30px rgba(184,168,136,.5); } }
.ro-flourish.ro-mahjong { font-family: 'Rye', cursive; font-size: 30px; color: var(--accent-ink);
    text-shadow: 0 3px 10px rgba(0,0,0,.7); }
@keyframes mjg-badge-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .4; } }
/* Center the chrome rows (topbar, dev-card hand) to match the centered hex board —
   they otherwise inherited the shared left-aligned flex defaults and hung to the left. */
.mode-boomtown .durak-topbar { justify-content: center; }
.mode-boomtown .bt-hand { justify-content: center; }
.bt-restile.r-wood   { background: #2c4a2a; }
.bt-restile.r-cattle { background: #5d7a33; }
.bt-restile.r-wheat  { background: #7a5c14; }
.bt-restile.r-gold   { background: #55575f; }
.bt-restile.r-clay   { background: #8a5a30; }

/* Narrow / mobile: sidebar wraps below the board full-width */

@media (min-width: 761px) {
  body.ss-maximized .card-board > .screen-game.mode-boomtown { display: flex; flex-direction: column; }
  body.ss-maximized .mode-boomtown > .bt-board { flex: 1 1 auto; min-height: 0; }
  /* The board row flexes to fill the height; the sidebar matches board height and scrolls
     internally if its cards exceed it, so the fitted board never overflows. */
  body.ss-maximized .mode-boomtown .bt-main { flex: 1 1 auto; min-height: 0; align-items: stretch; }
  body.ss-maximized .mode-boomtown .bt-hud { min-height: 0; overflow-y: auto; }
}
.ro-flourish.ro-boomtown { font-family: 'Rye', cursive; font-size: 30px; color: var(--accent-ink);
    text-shadow: 0 3px 10px rgba(0,0,0,.7); }

/* ════════════════════════════════════════════════════════════
   SITEWIDE "SALOON-RAHMEN" — unified page shell for all
   non-stage pages (Home, Profil, Teams, Admin, Mod, Regeln,
   Neuigkeiten, Legal). Source of truth: the approved mockup
   docs/mockups/sitewide-layout-final.html.
════════════════════════════════════════════════════════════ */

/* ── WCAG 2.2 AA: visible focus (2.4.7) + focus not obscured by the sticky
   header/footer bars (2.4.11). The global !important guards against any
   component-level outline:none silently killing the ring. Components that
   deliberately move the ring onto a surrounding container (search pills)
   must pair `outline:none !important` on the input with a `:has()` ring
   on the container — see .pf-search below for the pattern. ── */
:focus-visible { outline: 3px solid var(--accent-strong) !important; outline-offset: 2px; }
button, a, input, select, textarea, [tabindex] { scroll-margin-top: 96px; scroll-margin-bottom: 84px; }

/* ── Page frame (PageFrame.razor): header card → tabs row → board → footer ── */
.pf-main {
  flex: 1 0 auto;
  width: 100%;
  padding: 26px 22px 70px;   /* bottom clears the fixed .app-footer */
  display: flex; flex-direction: column; align-items: center;
}
.pf-col {
  width: 100%;
  --pf-border: color-mix(in srgb, var(--accent) 42%, transparent);
  animation: pfFade .22s ease;
}
.pf-col.w-narrow   { max-width: 720px; }
.pf-col.w-standard { max-width: 1000px; }
.pf-col.w-wide     { max-width: 1280px; }
@keyframes pfFade { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: translateY(0); } }

.pf-pageuh {
  display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap;
  border-radius: 4px 4px 0 0;
  background: linear-gradient(180deg, color-mix(in srgb, var(--accent) 14%, var(--scrim)), var(--scrim));
  border: 1px solid var(--pf-border); border-bottom: none;
}
.pf-pageuh-top {
  position: relative; display: flex; align-items: center; justify-content: space-between;
  gap: 12px; width: 100%; padding: 9px 16px; flex-wrap: wrap;
}
.pf-title { display: flex; align-items: center; gap: 9px; font-family: 'Rye', cursive; color: var(--heading); font-size: 16px; margin: 0; }
.pf-title h1 { font: inherit; color: inherit; margin: 0; letter-spacing: inherit; }
.pf-ico {
  width: 30px; height: 30px; border-radius: 6px; display: grid; place-items: center; font-size: 16px;
  background: color-mix(in srgb, var(--accent) 28%, transparent);
  border: 1px solid var(--pf-border); color: var(--heading);
}
.pf-acts { display: flex; align-items: center; gap: 6px; }
.pf-tabs {
  display: flex; gap: 2px; width: 100%; min-width: 0; padding: 0 12px;
  border-top: 1px solid var(--pf-border); overflow-x: auto;
}
/* Pages pass the Tabs fragment conditionally (loading states) — hide the row
   entirely while it has no real tab buttons, so no empty border strip shows. */
.pf-tabs:not(:has(*)) { display: none; }
.pf-board {
  /* V2: own gradient tier (was --surface-1) so nested cards that also use
     --surface-1 (status-card, db-section, stats-mode-card, pg-poster, …) read as
     a distinct raised layer instead of doubling the identical panel tone. Cards on
     it get --card-edge borders (rule below) to stay ≥3:1. */
  border: 1px solid var(--pf-border);
  background: linear-gradient(160deg, var(--card-grad-a), var(--card-grad-b));
  padding: 20px 22px;
}
/* V2: AA edge for cards nested directly on the (now lighter) .pf-board panel.
   Scoped under .pf-board so the game-frame/stage borders (.card-board,
   .lobby-stage-theatre — outside PageFrame) are NOT touched and stay dark.
   Higher specificity than the cards' own .xxx { border: … } → no !important. */
.pf-board .status-card, .pf-board .db-section, .pf-board .maintenance-card,
.pf-board .mailoauth-card, .pf-board .backup-card, .pf-board .users-row,
.pf-board .report-block, .pf-board .chat-snapshot, .pf-board .importjobs-card,
.pf-board .stats-mode-card, .pf-board .stat-box, .pf-board .card,
.pf-board .pg-poster, .pf-board [class$="-card"], .pf-board [class$="-section"] {
  border-color: var(--card-edge);
}
.pf-board .erow { background: var(--surface-2); border-left-color: var(--card-edge); }
.pf-board.pad-none { padding: 0; }
/* Card-bottom rule: round the bottom ONLY when no footer bar follows
   (docked pages keep it square so the footer joins seamlessly). */
.pf-board.cap-bottom { border-radius: 0 0 4px 4px; }
.pf-footer-bar {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 11px 16px; border: 1px solid var(--pf-border); border-top: none;
  border-radius: 0 0 4px 4px; background: var(--surface-1-strong);
}
@media (max-width: 640px) { .pf-main { padding-left: 12px; padding-right: 12px; } }

/* ── Shared pill-tab idiom (SubnavTabs.razor) — the ONE navigational pattern
   replacing Admin sidebar tabs, Profil tabs and Mod tabs. ── */
.pg-tab {
  font: inherit; font-size: 12.5px; color: var(--text-dim); background: transparent;
  border: none; border-bottom: 2px solid transparent; padding: 9px 13px; cursor: pointer;
  display: inline-flex; align-items: center; gap: 6px; white-space: nowrap;
}
.pg-tab:hover { color: var(--text-main); }
.pg-tab.on { color: var(--heading); border-bottom-color: var(--accent-light); }
.pg-tab .cnt { font-size: 12px; background: var(--surface-2); border: 1px solid var(--border-soft); border-radius: 999px; padding: 0 6px; }
.pg-tab .tab-sub { font-size: 12px; color: var(--text-dim); font-weight: 400; opacity: .8; }
.pg-tab .tab-caret { opacity: .6; font-size: 12px; }
/* Second (smaller) tab row for Admin's real sub-level (Content/Diagnose/
   Einstellungen) — rendered inside the board, clearly a 2nd hierarchy level. */
.pf-sub-tabs {
  display: flex; gap: 2px; flex-wrap: wrap; margin: -6px 0 16px; padding-left: 6px;
  border-bottom: 1px solid var(--border-soft);
}
.pf-sub-tabs .pg-tab { font-size: 12px; padding: 6px 12px; }
.pf-sub-tabs .pg-tab.on { font-weight: 600; }

/* ── Generic in-board building blocks (from the approved mockup) ── */
.pg-title { font-family: 'Rye', cursive; color: var(--heading); font-size: 22px; margin: 0 0 4px; }
.pg-sub { color: var(--text-dim); font-size: 13px; margin: 0 0 18px; max-width: 640px; }
.pg-section { margin-bottom: 22px; }
.pg-section-head { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.pg-section-head h3 { font-family: 'Rye', cursive; color: var(--heading); font-size: 15px; margin: 0; }
.pf-search {
  flex: 1; min-width: 160px; display: flex; align-items: center; gap: 7px; padding: 8px 12px;
  border-radius: 7px; background: var(--surface-1); border: 1px solid var(--border-soft);
  color: var(--text-dim); font-size: 12.5px;
}
/* Search box above the statistics card grids (profile + admin). */
.stats-search { flex: none; max-width: 320px; margin: 14px 0 12px; }
.pf-search input {
  flex: 1; min-width: 0; border: none; background: transparent; color: var(--text-main);
  font: inherit; padding: 0;
}
.pf-search:has(input:focus-visible) { outline: 3px solid var(--accent-strong); outline-offset: 2px; border-color: var(--accent); }
.pf-search input:focus-visible { outline: none !important; }

/* ── Home: flat poster grid (alphabetical, all games equal) ── */
.pg-poster-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; }
.pg-poster {
  position: relative; border-radius: 9px; overflow: hidden; border: 1px solid var(--border-soft);
  background: var(--surface-1); cursor: pointer; transition: .15s;
  text-align: left; font: inherit; color: inherit; padding: 0; margin: 0;
  /* Flex column instead of block: Blazor leaves whitespace text nodes inside
     the button (around the conditional spotlight/off badges). In block layout
     they form an anonymous line box (~8px pale bar ABOVE the art area, came
     and went with the spotlight rotation); as whitespace-only flex items they
     are guaranteed not to render. */
  display: flex; flex-direction: column;
}
.pg-poster .art { flex: none; }
.pg-poster .bd { flex: 1; }
@media (hover: hover) {
  .pg-poster:hover {
    transform: translateY(-2px);
    border-color: var(--border-strong);
  }
}
.pg-poster.spotlight-active {
  border: 2px solid var(--accent-strong);
  box-shadow: 0 0 0 1px var(--accent-strong), 0 4px 14px color-mix(in srgb, var(--accent-strong) 35%, transparent);
}
.pg-poster-tag {
  position: absolute; top: 8px; right: 8px; z-index: 1; background: var(--accent-strong);
  color: var(--text-invert); font-size: 12px; font-weight: 700; padding: 3px 8px;
  border-radius: 20px; letter-spacing: .02em;
}
.pg-poster .art {
  height: 76px; display: grid; place-items: center; font-size: 34px; color: var(--heading);
  /* Top glow PLUS an even base tint. Deliberately a LINEAR gradient: the
     mockup's oversized radial ellipse (120% 140%) rasterizes
     non-deterministically in Chromium (some tiles paint the falloff
     inverted → reads as a white bar at the top). The linear falloff is
     visually equivalent and paints reliably. */
  background:
    linear-gradient(180deg, color-mix(in srgb, var(--accent) var(--art-glow, 34%), transparent) 0%, transparent 85%),
    color-mix(in srgb, var(--accent) var(--art-tint, 14%), transparent);
}
/* Color emojis carry their own hues and ignore `color`. In light mode the pale
   accent wash behind them is low-contrast against cool glyphs (the anchor, the
   blue theatre mask). A thin dark outline lifts every icon off the wash; it is
   imperceptible on warm/dark emojis that already contrast, so the rule is
   systemic rather than per-mode. Light mode only — the dark theme sits the icons
   on a dark wash where the issue does not occur. text-shadow, not filter, so the
   outline traces the glyph and not the tinted box (both share this element). */
[data-theme="light"] .pg-poster .art { text-shadow: 0 0 1px rgba(58, 42, 22, .6), 0 1px 1px rgba(58, 42, 22, .38); }
.pg-poster .bd { padding: 9px 11px 11px; }
.pg-poster .nm { font-family: 'Rye', cursive; color: var(--heading); font-size: 13.5px; margin: 0 0 3px; }
.pg-poster .ds { color: var(--text-dim); font-size: 12px; line-height: 1.4; margin: 0; min-height: 34px; }
.pg-poster .pl { color: var(--heading); font-size: 12px; margin: 6px 0 0; font-weight: 600; }
.pg-poster-off { opacity: .55; }
/* right:auto — the base badge rule anchors right:8px; with BOTH set the badge
   would stretch across the full tile width (left+right resolved together). */
.pg-poster .home-mode-off-badge { position: absolute; top: 8px; left: 8px; right: auto; z-index: 1; }
@media (max-width: 960px) { .pg-poster-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 640px) { .pg-poster-grid { grid-template-columns: 1fr 1fr; } }

/* ── Home: "Im Rampenlicht" spotlight banner. Seit SS-0312 theme-fähig:
   Flächen über --spot-accent-mix/--surface-0-c (Light mischt gegen Weiß,
   s. Light-Override weiter unten), Texte über --heading/--text-main.
   Mode accent comes from the .mode-* class on the banner. ── */
.pg-spotlight {
  position: relative; overflow: hidden; margin-bottom: 18px; display: flex; align-items: center;
  gap: 22px; flex-wrap: wrap; padding: 22px 26px; border-radius: 10px;
  border: 1px solid var(--accent);
  background: linear-gradient(110deg, color-mix(in srgb, var(--accent) var(--spot-accent-mix), var(--surface-0-c)) 0%, var(--surface-0-c) 62%);
  transition: background .3s ease, border-color .3s ease;
}
.pg-spotlight-glow {
  position: absolute; right: -50px; top: -60px; width: 280px; height: 280px; border-radius: 50%;
  pointer-events: none;
  background: radial-gradient(circle, color-mix(in srgb, var(--accent-light) 45%, transparent), transparent 65%);
}
/* Fixed icon zone: the glyph is centered inside a constant-width box so the
   banner geometry never shifts between wide emojis (brain, masks) and narrow
   symbol glyphs (♦/♣/♠) — the text column always starts at the same x. */
.pg-spotlight-ic { font-size: 76px; line-height: 1; color: var(--text-main); filter: drop-shadow(0 8px 20px rgba(0,0,0,.5)); flex: none; position: relative; z-index: 1; width: 96px; display: grid; place-items: center; }
.pg-spotlight-txt { flex: 1; min-width: 220px; position: relative; z-index: 1; }
.pg-spotlight-tag { font-size: 12px; letter-spacing: .18em; text-transform: uppercase; color: var(--heading); margin-bottom: 6px; font-weight: 600; }
.pg-spotlight-txt h2 { font-family: 'Rye', cursive; font-size: 22px; color: var(--heading); margin: 0 0 6px; }
.pg-spotlight-txt p { color: var(--text-main); font-size: 13px; margin: 0; max-width: 520px; opacity: .9; }
.pg-spotlight-btns { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 12px; }
.pg-spotlight-btns .btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  width: auto; flex: 0 0 auto; padding: 9px 18px; font-size: 13px; border-radius: var(--btn-radius);
}
.pg-spotlight-btns .btn-ghost { border-color: var(--heading); color: var(--text-main); }
.pg-spotlight-meta { margin-top: 10px; font-size: 12px; color: var(--smoke); }
/* Light: Glow, Ring + Fortschrittsleiste nutzen den GRUND-Akzent statt
   --accent-light — sonst wirkt der Banner wie eine andere Spielfarbe als
   die Poster-Kacheln (Betreiber-Fund: "andere Akzentfarbe?"). */
/* Light: gegen WEISS mischen statt gegen den warmen Sand — dunkle Akzente
   (Aubergine, Sienna) vermatschen sonst zu Beige und der Banner wirkt farblos. */
[data-theme="light"] .pg-spotlight {
  background: linear-gradient(110deg, color-mix(in srgb, var(--accent) 36%, #fffdf7) 0%, var(--surface-0-c) 62%);
}
[data-theme="light"] .pg-spotlight-glow { background: radial-gradient(circle, color-mix(in srgb, var(--accent) 30%, rgba(255,253,247,.0)), transparent 65%); }
[data-theme="light"] .pg-spotlight-ring .rprog { stroke: var(--accent); }
[data-theme="light"] .pg-spotlight-bar .fill { background: var(--accent); }
/* Light: Titel/Tag auf dem Akzent-Pastell brauchen den dunkelsten Textton —
   --heading (#7a4a12) schafft dort nur ~4:1. Dark bleibt Gold. */
[data-theme="light"] .pg-spotlight-tag,
[data-theme="light"] .pg-spotlight-txt h2 { color: var(--text-main); }

/* Auto-rotation controls (WCAG 2.2.2 pause/stop/hide): pause button top-right
   with an SVG progress ring + slim progress bar along the bottom edge. Both are
   pure CSS animations over --spotlight-cycle (MUST match the C# rotation
   interval in Home.razor); .is-paused (server truth: hover/focus/button)
   freezes them via animation-play-state, a fresh @key per rotation restarts
   them. Raw tokens only — the banner stays an always-dark island. */
.pg-spotlight { --spotlight-cycle: 30s; }
.pg-spotlight:focus-within {
  border-color: var(--accent-light);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent-light) 30%, transparent);
}
@media (hover: hover) {
  .pg-spotlight:hover {
    border-color: var(--accent-light);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent-light) 30%, transparent);
  }
}
.pg-spotlight-ctrl { position: absolute; top: 10px; right: 10px; display: flex; align-items: center; gap: 8px; z-index: 1; }
.pg-spotlight-paused-lbl { font-size: 12px; color: var(--smoke); }
.pg-spotlight-pause {
  position: relative; width: 36px; height: 36px; border-radius: 50%; border: none; padding: 0;
  display: inline-flex; align-items: center; justify-content: center; cursor: pointer;
  background: color-mix(in srgb, var(--text-main) 12%, transparent);
  color: var(--text-main); font-size: 14px; line-height: 1;
}
.pg-spotlight-pause:hover { background: color-mix(in srgb, var(--text-main) 22%, transparent); }
.pg-spotlight-ring { position: absolute; inset: 0; width: 36px; height: 36px; transform: rotate(-90deg); pointer-events: none; }
.pg-spotlight-ring circle { fill: none; stroke-width: 2.5; }
.pg-spotlight-ring .rtrack { stroke: color-mix(in srgb, var(--text-main) 18%, transparent); }
/* dasharray/-offset = circumference of r=16 (2·π·16 ≈ 100.53) */
.pg-spotlight-ring .rprog {
  stroke: var(--accent-light); stroke-linecap: round;
  stroke-dasharray: 100.53; stroke-dashoffset: 100.53;
  animation: spotlight-ring var(--spotlight-cycle) linear forwards;
}
@keyframes spotlight-ring { to { stroke-dashoffset: 0; } }
.pg-spotlight-bar {
  position: absolute; left: 0; right: 0; bottom: 0; height: 4px; pointer-events: none;
  background: color-mix(in srgb, var(--text-main) 15%, transparent);
}
.pg-spotlight-bar .fill {
  display: block; height: 100%; background: var(--accent-light);
  transform: scaleX(0); transform-origin: left;
  animation: spotlight-bar var(--spotlight-cycle) linear forwards;
}
@keyframes spotlight-bar { to { transform: scaleX(1); } }
.pg-spotlight.is-paused .rprog, .pg-spotlight.is-paused .fill { animation-play-state: paused; }
@media (prefers-reduced-motion: reduce) {
  .pg-spotlight-ring .rprog, .pg-spotlight-bar .fill { animation: none; }
}

@media (max-width: 640px) {
  .pg-spotlight { flex-direction: column; text-align: center; padding: 20px; }
  .pg-spotlight-btns, .pg-spotlight-meta { justify-content: center; }
}

/* Link row "view full profile" in the player quick-view modal. */
.player-profile-fulllink { margin-top: 12px; text-align: center; font-size: 13px; }
.player-profile-fulllink a { color: var(--heading); text-decoration: none; }
.player-profile-fulllink a:hover { text-decoration: underline; }

/* ── Hero row (public profile head) + generic list rows (friends/favorites) ── */
.pg-hero {
  display: flex; align-items: center; gap: 18px; padding: 18px 20px; border-radius: 10px;
  background: var(--surface-1); border: 1px solid var(--border-soft); margin-bottom: 18px; flex-wrap: wrap;
}
.pg-hero-info { flex: 1; min-width: 140px; }
.pg-hero h2 { font-family: 'Rye', cursive; color: var(--heading); font-size: 22px; margin: 0 0 4px; }
.pg-hero p { color: var(--text-dim); font-size: 12.5px; margin: 0; }
.pg-hero-team-link { color: var(--heading); text-decoration: none; }
.pg-hero-team-link:hover { text-decoration: underline; }
.pg-team-row {
  display: flex; align-items: center; gap: 12px; padding: 11px 13px; border-radius: 8px;
  background: var(--surface-1); border: 1px solid var(--border-soft); margin-bottom: 8px;
}
.pg-row-main { flex: 1; min-width: 0; }
.pg-row-title { color: var(--text-main); font-size: 13px; font-weight: 600; }
.pg-row-meta { color: var(--text-dim); font-size: 12px; }

/* ── Rules page: split view (game list left, detail right) ── */
.rules-split { display: grid; grid-template-columns: 220px 1fr; gap: 16px; align-items: start; }
.rules-split-list { display: flex; flex-direction: column; gap: 3px; }
/* .pf-search is flex:1 for toolbar use — inside the vertical list column that
   would make it GROW with the detail pane's height. Pin it to its own height. */
.rules-split-list .pf-search { flex: 0 0 auto; margin-bottom: 10px; }
.rsplit-item {
  display: flex; align-items: center; gap: 9px; width: 100%; padding: 9px 12px; border-radius: 7px;
  border: 1px solid transparent; background: transparent; color: var(--text-main);
  font: inherit; font-size: 12.5px; cursor: pointer; text-align: left;
}
.rsplit-item:hover { background: var(--surface-hover); }
.rsplit-item.on { background: var(--surface-2); border-color: var(--border-strong); color: var(--heading); font-weight: 600; }
.rsplit-item .ic { font-size: 16px; width: 20px; flex: none; display: inline-flex; align-items: center; justify-content: center; }
.rsplit-empty { font-size: 12.5px; color: var(--text-dim); padding: 8px 12px; }
.rules-split-detail { background: var(--surface-1); border: 1px solid var(--border-soft); border-radius: 8px; padding: 18px 20px; min-width: 0; }
.rsd-head { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.rsd-head .ic { font-size: 28px; }
.rsd-head h2 { font-family: 'Rye', cursive; color: var(--heading); font-size: 17px; margin: 0; }
.rsd-meta { font-size: 12px; color: var(--text-dim); margin-bottom: 12px; }
@media (max-width: 640px) { .rules-split { grid-template-columns: 1fr; } }

/* ── Header theme toggle (light/dark) — same pill sizing as the other
   header controls. ── */
.theme-btn {
  width: 38px; height: 38px; border-radius: 50%; display: inline-flex; align-items: center;
  justify-content: center; cursor: pointer; padding: 0; font-size: 15px;
  background: var(--surface-1); border: 1px solid var(--border-strong); color: var(--heading);
  transition: border-color .15s, background .15s;
}
.theme-btn:hover { border-color: var(--gold); background: var(--surface-hover); }

/* ── Light theme: targeted surface fixes for legacy hull pieces that keep
   their hardcoded dark tints otherwise. Kept as an explicit, bounded list. ── */
[data-theme="light"] body::before { opacity: .18; }   /* grain: much softer on paper */
[data-theme="light"] .profile-dropdown,
[data-theme="light"] .lang-dd-list { background: var(--surface-1-strong); border-color: var(--border-soft); color: var(--text-main); }
[data-theme="light"] .auth-btn-solid { background: linear-gradient(180deg, #f4e6c6, #ecd9ac); color: var(--heading); }
[data-theme="light"] .auth-btn-solid:hover { background: linear-gradient(180deg, #f8ecd2, #f0e0b8); }

[data-theme="light"] .oauth-delete-note { color: #3a4a6a; }

[data-theme="light"] .email-verified { color: var(--success); }
[data-theme="light"] .cl-badge-new { color: #8a4108; }
[data-theme="light"] .presence-online { color: var(--success); }
[data-theme="light"] .btn-ghost-red { color: #a32a2a; border-color: rgba(139, 26, 26, .45); }
[data-theme="light"] .btn-ghost-red:hover { color: #8b1a1a; }
[data-theme="light"] .help-icon-btn { color: #7a4a12; }
[data-theme="light"] .card-board .podium-stats .section-label { background: #f3e6c8; }
[data-theme="light"] .player-slot.disconnected { background: rgba(163, 50, 74, .08); }
[data-theme="light"] .r-gold, [data-theme="light"] .r-red,
[data-theme="light"] .r-amber { text-shadow: none; }   /* Titel-Glow vermatscht auf Pergament */
[data-theme="light"] .abort-btn { color: var(--danger-strong); border-color: rgba(139, 26, 26, .45); }
[data-theme="light"] .start-overlay-num { text-shadow: none; }
[data-theme="light"] .uc-role-tag.ghost,
[data-theme="light"] .role-pill.ghost,
[data-theme="light"] .uc-ghost-saved { color: #47596a; }
[data-theme="light"] .ro-flourish { text-shadow: none; }

/* ── WCAG 2.5.8: 24px-Mindestzielgrößen für kompakte Controls (app-weit).
   min-height wirkt nur auf die zu kleinen Instanzen; normal große Inputs
   (30px+) bleiben unverändert. ── */
input[type="text"], input[type="search"], input[type="email"],
input[type="password"], input[type="number"], select { min-height: 24px; }
.icon-select-btn { min-height: 24px; }

/* ── Bühnen-Lobby: Scheinwerfer-Rigg + Requisiten (SS-0312-Deko) ──────────
   Rigg/Lampen aus festen Holz-Tönen (Artwork, beide Themes), Lichtkegel in
   der Mode-Akzentfarbe. Die "Lichtprobe" schwenkt die Kegel EINMAL beim Laden
   ein (< 5 s → kein WCAG-2.2.2-Pausensteuerelement nötig); bei
   prefers-reduced-motion stehen sie sofort. Requisite liegt HINTER der
   Truppe (z-Index) und tritt auf vollen Bühnen zurück (.stage-prop-crowded). */
.stage-rig {
  position: absolute; top: 34px; left: 62px; right: 62px; height: 8px; z-index: 4;
  background: linear-gradient(180deg, #4a3620, #2e2214); border-radius: 3px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, .35);
}
.stage-lamp { position: absolute; top: 38px; width: 22px; height: 27px; z-index: 4; transform: translateX(-50%) rotate(var(--lamp-tilt, 0deg)); }
.stage-lamp::before { content: ""; position: absolute; top: 0; left: 50%; transform: translateX(-50%); width: 5px; height: 8px; background: #2e2214; }
.stage-lamp::after {
  content: ""; position: absolute; top: 7px; left: 50%; transform: translateX(-50%);
  width: 20px; height: 19px; border-radius: 5px 5px 8px 8px;
  background: linear-gradient(180deg, #4a3620, #241708);
  box-shadow: inset 0 -4px 6px color-mix(in srgb, var(--accent) 70%, transparent);
}
.stage-lamp-l { left: 24%; --lamp-tilt: 14deg; }
.stage-lamp-c { left: 50%; }
.stage-lamp-r { left: 76%; --lamp-tilt: -14deg; }
.stage-beam {
  position: absolute; top: 58px; width: 160px; height: 72%; z-index: 1;
  margin-left: -80px; pointer-events: none; transform-origin: 50% 0;
  clip-path: polygon(45% 0, 55% 0, 100% 100%, 0 100%);
  background: linear-gradient(180deg, color-mix(in srgb, var(--accent) 22%, transparent), transparent 78%);
}
.stage-beam-l { left: 24%; transform: rotate(14deg);  animation: stage-beam-l 3.8s ease-in-out 1; }
.stage-beam-c { left: 50%; transform: rotate(0deg);   animation: stage-beam-c 3.8s ease-in-out .25s 1 backwards; }
.stage-beam-r { left: 76%; transform: rotate(-14deg); animation: stage-beam-r 3.8s ease-in-out .5s 1 backwards; }
@keyframes stage-beam-l { 0% { transform: rotate(-14deg); opacity: 0; } 18% { opacity: 1; } 62% { transform: rotate(19deg); } 100% { transform: rotate(14deg); } }
@keyframes stage-beam-c { 0% { transform: rotate(-9deg); opacity: 0; } 18% { opacity: 1; } 62% { transform: rotate(7deg); } 100% { transform: rotate(0deg); } }
@keyframes stage-beam-r { 0% { transform: rotate(14deg); opacity: 0; } 18% { opacity: 1; } 62% { transform: rotate(-19deg); } 100% { transform: rotate(-14deg); } }
@media (prefers-reduced-motion: reduce) {
  .stage-beam-l, .stage-beam-c, .stage-beam-r { animation: none; }
}
.stage-prop { position: absolute; bottom: 72px; left: 21%; transform: translateX(-50%); z-index: 2; text-align: center; transition: opacity .3s; }
.stage-prop-crowded { opacity: .35; }
.sprop-base { width: 120px; height: 10px; margin: 6px auto 0; border-radius: 4px; background: linear-gradient(180deg, #8a6a3c, #6b4a23); box-shadow: 0 4px 8px rgba(0, 0, 0, .25); }
.sprop-gallows { position: relative; width: 110px; height: 96px; margin: 0 auto; }
.sprop-gallows .post { position: absolute; left: 14px; bottom: 0; width: 9px; height: 96px; background: #6b4a23; border-radius: 2px; }
.sprop-gallows .arm  { position: absolute; left: 14px; top: 0; width: 72px; height: 8px; background: #6b4a23; border-radius: 2px; }
.sprop-gallows .rope { position: absolute; left: 76px; top: 8px; width: 3px; height: 22px; background: #8a6a3c; }
.sprop-gallows .tile { position: absolute; left: 60px; top: 30px; width: 34px; height: 34px; background: #f7ecd4; border: 2px solid #8a6a3c; border-radius: 4px; font-family: 'Rye', cursive; font-size: 20px; display: flex; align-items: center; justify-content: center; color: #3a2a16; }
.sprop-mic { position: relative; width: 80px; height: 110px; margin: 0 auto; }
.sprop-mic .head { position: absolute; top: 0; left: 50%; transform: translateX(-50%); width: 30px; height: 30px; border-radius: 50%; background: radial-gradient(circle at 35% 30%, #6b5838, #2e2214); }
.sprop-mic .pole { position: absolute; top: 28px; left: 50%; transform: translateX(-50%); width: 5px; height: 70px; background: #4a3620; }
.sprop-mic .foot { position: absolute; bottom: 0; left: 50%; transform: translateX(-50%); width: 56px; height: 8px; border-radius: 50%; background: #2e2214; }
.sprop-mic .note { position: absolute; font-size: 22px; color: #3a2a16; opacity: .8; }
.lobby-stage-theatre .sprop-mic .note { color: color-mix(in srgb, var(--accent) 40%, #3a2a16); }
.sprop-mic .note-l { left: -26px; top: 8px; }
.sprop-mic .note-r { right: -24px; top: -8px; }
.sprop-podium { position: relative; width: 96px; height: 104px; margin: 0 auto; }
.sprop-podium .top  { position: absolute; top: 0; left: 0; right: 0; height: 14px; background: #6b4a23; border-radius: 4px; }
.sprop-podium .body { position: absolute; top: 12px; left: 8px; right: 8px; bottom: 0; border-radius: 0 0 6px 6px; background: linear-gradient(180deg, #8a6a3c, #6b4a23); display: flex; align-items: center; justify-content: center; font-family: 'Rye', cursive; font-size: 40px; color: #f7ecd4; }
.sprop-tabu { position: relative; width: 92px; height: 96px; margin: 0 auto; background: #f7ecd4; border: 2px solid #8a6a3c; border-radius: 6px; padding-top: 10px; transform: rotate(-3deg); }
.sprop-tabu .word   { display: block; font-family: 'Rye', cursive; font-size: 15px; letter-spacing: .06em; color: #3a2a16; }
.sprop-tabu .strike { display: block; width: 70%; height: 3px; margin: 4px auto 6px; background: #a3324a; transform: rotate(-4deg); }
.sprop-tabu .shh    { font-size: 26px; }
@media (max-width: 640px) {
  .stage-prop { transform: translateX(-50%) scale(.75); transform-origin: bottom center; }
  .stage-rig { left: 50px; right: 50px; }
}

/* Light: Lobby-Panels (Header-Karte, Spieler-Panel, Fusszeile) waren mit dem
   globalen Karten-Verlauf fast reinweiss ("blendet") — im Lobby-Kontext auf
   warmes Pergament abgesenkt. Aussenseiten behalten den Standard-Verlauf. */
[data-theme="light"] .screen-lobby .card,
[data-theme="light"] .screen-game .card {
  --card-grad-a: rgba(246, 235, 210, .95);
  --card-grad-b: rgba(236, 220, 184, .97);
}

/* Light: sattes Filzgrün -> Texte AUF dem Filz hell (wie im Dark), sonst kein AA. */
[data-theme="light"] .lobby-table .seat-name,
[data-theme="light"] .lobby-table .seat-you,
[data-theme="light"] .lobby-table .seat-avatar-empty,
[data-theme="light"] .lobby-table .seat-ghost .seat-name { color: var(--text-invert); }

/* Light: Kopfzeilen-Karte der Lobby als dunkleres Sand-Band — hebt die
   Kopfzeile vom Pergament-Rest ab (Betreiber-Feedback: zu wenig Hierarchie). */
/* §3-Ausweichregel: Schnellschuss-Türkis ist der hellste Akzent und fällt im
   Light unter die Kanten-Schwelle (Ring 2,7:1) — abgedunkeltes Light-Paar.
   Erster und bisher einziger Modus mit explizitem Light-Override. */
[data-theme="light"] .mode-schnellschuss {
  --accent: #157585;
  --accent-light: #3b9fb2;
}
[data-theme="light"] .screen-lobby .lobby-header-card,
[data-theme="light"] .screen-game .lobby-header-card {
  /* Band traegt den Spiel-Akzent als Schleier (wie im Dark der dunkle Grund
     die Akzente traegt) — Basis bleibt das Sand-Band. Seit SS-0312 Etappe 2
     gilt dasselbe Band auch auf den Spiel-Seiten (gleiche Header-Komponente). */
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--accent) 14%, #e3cda0),
    color-mix(in srgb, var(--accent) 20%, #d9bf8c));
  /* Rahmen bleibt Saloon-Gold-Braun — Panel-Raender tragen NIE den Mode-Akzent
     (etablierte Regel, s. .card-actions-bar). Gleiches Token wie die Panels
     darunter, damit Ober- und Unterrahmen exakt denselben Ton haben. */
  border-color: var(--border-soft);
}
[data-theme="light"] :is(.screen-lobby, .screen-game) .lobby-header-card .uh-name,
[data-theme="light"] :is(.screen-lobby, .screen-game) .lobby-header-card .help-icon-btn,
[data-theme="light"] :is(.screen-lobby, .screen-game) .lobby-header-card .uh-help { color: var(--text-main); }
/* Light: Icon-Chip als HELLE Akzent-Marke (Pastell-Grund + tiefer Akzent-Glyph)
   statt des importierten Dunkel-Chips — jedes Spiel behält seinen Akzent. */
/* Light: Verlauf/Chat/Copy-Buttons tragen Emoji-Glyphen (eigenfarbig, beige!)
   — auf dem Sand-Band unsichtbar. Gleiche Plakette wie der Icon-Chip. */
[data-theme="light"] :is(.screen-lobby, .screen-game) .lobby-uh .uh-icon-btn {
  background: color-mix(in srgb, var(--accent) 12%, #fffdf7);
  border-color: color-mix(in srgb, var(--accent) 65%, #3a2a16);
}
[data-theme="light"] :is(.screen-lobby, .screen-game) .lobby-uh .uh-gear {
  background: color-mix(in srgb, var(--accent) 12%, #fffdf7);
  border-color: color-mix(in srgb, var(--accent) 65%, #3a2a16);
}
[data-theme="light"] :is(.screen-lobby, .screen-game) .lobby-uh .uh-ico {
  /* Heller als das Sand-Band (Plakette) + dunkle Akzent-Kontur — dunkle
     Akzente (Aubergine, Sienna) verschwimmen sonst mit dem Band-Ton. */
  background: color-mix(in srgb, var(--accent) 20%, #fffdf7);
  color: color-mix(in srgb, var(--accent) 55%, #3a2a16);
  border-color: color-mix(in srgb, var(--accent) 65%, #3a2a16);
}

/* ═══════════════════════════════════════════════════════════════════════════
   Portrait shell — phone held upright
   ═══════════════════════════════════════════════════════════════════════════
   The maximize block further up (min-width: 761px) locks the app to the
   viewport height so game content can never grow the page. Phones had no
   equivalent at all: game screens ran in plain document flow, every fixed
   height (felt min-height, screen paddings, stacked header) added up and every
   game scrolled. This is the portrait counterpart of that block — the same
   flex height chain (shell -> main -> screen -> card-board -> game screen),
   with two differences:

     - 100dvh instead of 100vh. The mobile browser's collapsing URL bar shrinks
       the visible area; 100vh keeps the LARGER value, so the bottom of the
       layout would sit below the fold exactly while the bar is shown.
     - It is always on. There is no maximize toggle on mobile (the button is
       hidden at <=760px), so the portrait layout is the only layout.

   Landscape phones are deliberately NOT covered — they keep today's responsive
   flow until they get their own pass.

   Placed at the END of the file on purpose: it has to win over both the shared
   shell rules and the per-mode rules above it, which sit at equal specificity.
   ═══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 760px) and (orientation: portrait) {

  /* ── Shell: height chain ────────────────────────────────────────────────
     Scoped via :has() to a page that actually shows a game — every other page
     keeps the normal scrollable app shell (min-height:100vh). The app footer
     is not rendered on the game page (MainLayout), so 100dvh is the full
     budget and nothing has to be reserved at the bottom. */
  body:has(.screen-game.lobby-redesign) .app-shell { height: 100dvh; min-height: 0; }
  body:has(.screen-game.lobby-redesign) .app-main  { flex: 1 1 auto; min-height: 0; }

  .screen-game.lobby-redesign {
    flex: 1 1 auto; min-height: 0;
    /* was 40px 20px 48px — 82px of pure budget. The bottom inset covers the iOS home
       indicator: 100dvh spans the FULL screen including that strip, so without the
       reservation the last row renders underneath it and looks cut off (found on a
       real device — an emulated viewport reports no safe area).
       max(8px, …) and not the bare env(): ANDROID reports 0 for the inset unless the
       page opts into viewport-fit=cover, so the panel frame ended up flush against the
       screen edge and its bottom border was shaved off by the gesture bar. The 8px floor
       gives every device a visible frame; iOS still gets its full inset. */
    padding: 6px 6px max(8px, env(safe-area-inset-bottom, 0px));
    align-items: stretch; justify-content: flex-start;
  }

  /* Game header stays a SINGLE row. The <=700px rule above stacks it into a
     column, which costs ~50px; that rule is meant for the lobby header (which
     carries the code box and has no height lock to feed) and is left alone
     there — this override is scoped to the game screen. */
  .screen-game.lobby-redesign .lobby-uh { flex-direction: row; gap: 8px; padding: 5px 8px; }
  .screen-game.lobby-redesign .lobby-uh .uh-right { flex-wrap: nowrap; justify-content: flex-end; gap: 4px; }
  .screen-game.lobby-redesign .lobby-uh .uh-name { font-size: 15px; }

  /* The one framed panel fills the rest and passes the height on. Its 18px inset
     is a desktop value: it costs 36px of width (which the seat row and the badge
     row need) and 36px of height, and the game components nest a second board
     inside it, so the inset is paid twice. 8px keeps the frame readable. */
  .screen-game.lobby-redesign > .card-board {
    max-width: none; width: 100%; flex: 1 1 auto; min-height: 0;
    display: flex; flex-direction: column; gap: 6px; padding: 8px;
  }
  /* Nested game screen fills the panel and centers itself. If a screen truly
     cannot be squeezed (long result lists), IT scrolls internally — the frame
     and the docked footer stay put. `safe center` keeps the top reachable;
     plain centering clips overflow at the top edge. */
  .card-board > .screen-game,
  .card-board > .screen-break,
  .card-board > .screen-voting,
  .card-board > .screen-result {
    flex: 1 1 auto; min-height: 0; overflow-y: auto; justify-content: safe center;
  }

  /* ── Schnellschuss ──────────────────────────────────────────────────────
     Four zones: HUD (fixed) - felt (flex) - hand (fixed) - status strip.
     Mockup: docs/mockups/ss0382-schnellschuss-hochkant.html */
  /* The component renders its own screen-game + durak-board INSIDE the outer
     card-board, so the height has to be passed through both of them before the
     felt can claim what is left (same two links the maximize block needs). */
  .card-board > .screen-game.mode-schnellschuss { display: flex; flex-direction: column; }
  .mode-schnellschuss > .durak-board { flex: 1 1 auto; min-height: 0; }

  /* Card size follows the viewport HEIGHT, not just the width: on a 568px-tall
     phone the fixed 81px cards plus a wrapped seat row leave the pile zone with
     ~17px, which renders the table unusable. Tall phones (>=675px) still get the
     full 81px, so nothing changes on a normal device. Width keeps the 58:81
     ratio of the artwork. */
  .mode-schnellschuss .durak-board {
    --card-h: clamp(58px, 12dvh, 81px);
    --card-w: calc(var(--card-h) * .716);
    gap: 4px;
  }

  /* HUD: the four badges fit one row at 375px only once the phase badge is out
     of the row — it carries the longest text and forced a three-row wrap.
     flex-basis 100% parks it on its own line below, unstyled, as a plain
     single-line status. */
  .mode-schnellschuss .durak-topbar { gap: 5px; }
  .mode-schnellschuss .durak-topbar .durak-chip { padding: 3px 8px; gap: 4px; }
  /* "Ziehstapel"/"Aktive Farbe" alone are ~134px of the 325px row — without them
     the four badges fit one line; glyph and colour swatch carry the meaning. */
  .mode-schnellschuss .durak-topbar .ssk-chip-lbl { display: none; }
  .mode-schnellschuss .durak-topbar .ssk-chip-ic { display: inline; }
  /* Two lines, not one: the longest status ("Du bist am Zug — leg eine passende
     Karte (Farbe oder Symbol) oder zieh nach") gets cut mid-word on one line even
     on a 428px device. Two lines cost ~18px, which the felt has to spare. */
  .mode-schnellschuss .durak-topbar .durak-chip.phase {
    flex: 1 0 100%; text-align: center;
    background: none; border-color: transparent; color: var(--parchment);
    padding: 0 6px; min-width: 0; line-height: 1.3;
    white-space: normal; overflow: hidden;
    display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
  }

  /* Felt: the min-height is the single biggest reason the screen overflowed —
     it reserved 46vh regardless of what was left. Dropped; the felt now takes
     exactly the space the fixed zones leave over. The oval also becomes a
     rounded rectangle: at ~335px felt width the ellipse wastes the corners
     that the seat row needs. */
  .mode-schnellschuss .ssk-felt {
    min-height: 0; border-radius: 18px; border-width: 6px;
    padding: 8px 8px 6px; display: flex; flex-direction: column;
  }
  /* The wrap must not shrink past what the felt actually needs (seat rows +
     the pile floor). Without this the felt keeps shrinking and its content
     spills OVER the hand instead of handing the overflow up to the nested
     game screen, which is the element that scrolls. Only reachable in the
     extreme case: smallest phone, six players, and a wrapped seat row. */
  .mode-schnellschuss .ssk-felt-wrap { min-height: min-content; }
  .mode-schnellschuss .ssk-felt-rim { inset: 3px; border-radius: 13px; }
  .mode-schnellschuss .ssk-dir-wm { font-size: clamp(90px, 34vw, 150px); }

  /* Seats leave the arc. SeatStyle() writes only left/top as an inline style —
     position:static makes the browser ignore both, so the C# helper (and the
     arc it draws on wider screens) stays untouched. */
  .mode-schnellschuss .ssk-seats {
    display: flex; flex-wrap: wrap; justify-content: center; gap: 4px;
    position: relative; z-index: 2;
  }
  .mode-schnellschuss .ssk-seat {
    position: static; transform: none; width: auto;
    flex-direction: row; align-items: center; gap: 3px;
    padding: 2px 6px 2px 2px; border: 1px solid transparent; border-radius: 999px;
    background: rgba(6, 14, 11, .5);
  }
  /* The whole seat is ONE pill in portrait, so the active/next highlight moves
     from the head to the seat — otherwise the ring wraps only the name and the
     card count sits visibly outside it (seen on the device). */
  .mode-schnellschuss .ssk-seat.active {
    background: color-mix(in srgb, var(--accent) 24%, transparent);
    box-shadow: 0 0 0 1px var(--accent-light), 0 0 16px rgba(79, 196, 214, .5);
  }
  .mode-schnellschuss .ssk-seat.next {
    border-color: #ff6b57; box-shadow: 0 0 0 1px #ff6b57, 0 0 10px rgba(255, 107, 87, .45);
  }
  .mode-schnellschuss .ssk-seat.active .ssk-seat-head,
  .mode-schnellschuss .ssk-seat.next .ssk-seat-head {
    background: none; box-shadow: none; border-color: transparent;
  }
  .mode-schnellschuss .ssk-seat-head { padding: 0; gap: 3px; }
  .mode-schnellschuss .ssk-seat .avatar-md { --av-size: 24px; }
  .mode-schnellschuss .ssk-seat-nm { font-size: 13px; max-width: 54px; }
  /* The mini fan goes: up to 8 card backs per seat is ~60px, and three seats then
     no longer fit one row (measured 324px against 317px available). The bare count
     next to the avatar carries the same information; the single-card 🔫 badge is
     what actually needs to stand out. Worst case (three names at the 54px cap) now
     measures 303px, so the row holds without wrapping. */
  .mode-schnellschuss .ssk-seat-mini .ssk-back { display: none; }
  .mode-schnellschuss .ssk-seat-mini { gap: 3px; }

  /* Piles take the remaining felt height and stay a touch larger than the hand
     cards — they are the read target, not a tap target. */
  .mode-schnellschuss .ssk-center {
    position: static; transform: none;
    flex: 1 1 auto; justify-content: center; gap: clamp(16px, 6vw, 30px);
    /* NOT min-height:0. The piles are the one thing that must stay readable —
       if the seat row wraps far enough to squeeze them, this floor makes the
       felt overflow instead, and the nested game screen's overflow-y takes over.
       A short scroll beats an unreadable table. +22px = the pile caption. */
    min-height: calc(var(--card-h) + 22px);
  }
  /* The piles carry the free height that portrait opens up — with few players
     the felt is mostly empty at the old 95px cap. They stay well clear of the
     hand cards, so the two rows never read as the same size. */
  .mode-schnellschuss .ssk-center .ssk-card,
  .mode-schnellschuss .ssk-center .ssk-back.lg {
    --card-h: clamp(70px, 13dvh, 118px);
    --card-w: calc(var(--card-h) * .716);
  }

  /* Hand: ONE row, always. The overlap is computed from the card count (--n,
     set by the component) against the row's own width via container units:
     margin = (available - n*w) / (n-1). Two guards around it:
       - min(-12px, ...) keeps the normal fan look while the cards still fit,
       - max(-(w - 24px), ...) never lets a card's visible strip fall below
         24px (WCAG 2.5.8 target size) — past that the row scrolls horizontally
         instead of stacking a second line. */
  .mode-schnellschuss .ssk-hand {
    container-type: inline-size;
    /* Same floor logic as the pile zone: the row may never be shorter than a
       card plus its lift, otherwise the hand clips instead of scrolling. */
    flex: 0 0 auto; min-height: calc(var(--card-h) + 18px);
    flex-wrap: nowrap; padding: 14px 6px 4px;
    overflow-x: auto; overflow-y: hidden;
    justify-content: safe center; scroll-snap-type: x proximity;
  }
  .mode-schnellschuss .ssk-hand .ssk-card {
    flex: 0 0 auto; scroll-snap-align: center;
    margin-left: max(
      calc(-1 * (var(--card-w) - 24px)),
      min(-12px, calc((100cqw - var(--n, 7) * var(--card-w)) / (var(--n, 7) - 1)))
    );
  }
  .mode-schnellschuss .ssk-hand .ssk-card:first-child { margin-left: 0; }
  /* The lift of a playable card is a transform (no layout height), but it has
     to stay inside the row's padding-top or it clips against the felt above. */
  .mode-schnellschuss .ssk-hand .ssk-card.playable { transform: translateY(-12px); }

  .mode-schnellschuss .durak-hand-head { margin-bottom: 0; gap: 6px; }
  .mode-schnellschuss .ssk-banner { margin: 4px auto 0; font-size: 12px; padding: 4px 14px; }
  .mode-schnellschuss .ssk-decide { margin: 4px auto 0; padding: 6px 12px; font-size: 12px; }
  .hangman-main, .game-sidebar { min-width: 0; }

  /* ── Memory: Höhenkette, sonst frisst der Fit seine eigene Ausgabe ───────
     fitMemory measures .memory-board-card. Without the lock below that card is CONTENT-sized:
     its height comes from the felt, the felt's from the board, the board's from --mem-cell —
     which is what the fit just wrote. So every pass measures a box that the previous pass
     already shrank, and because Game.razor re-renders on a 1s ticker the board visibly
     collapses a step per second. The maximize block has carried this exact lock since it hit
     the same loop; portrait enabled the fit but not the chain that makes it stable.
     The felt therefore HUGS the board (fit-content + margin:auto) instead of spanning the card
     and driving its height. */
  /* The docked footer pulls itself to the panel edge with a negative margin (-18px) — that
     matches the DESKTOP padding of .card-board. Portrait has 8px, so the bar stuck out by 9px
     per side and produced 18px of horizontal scroll. Portrait's scroll container is the inner
     .screen-game, and ANY overhang beyond it produces a scrollbar — a negative margin reduced
     to 8px still leaves 8px (measured). Hence no overhang at all in portrait: the bar sits
     flush inside the panel content and the panel's 8px padding stays visible as a thin edge.
     Affects every game carrying this footer. */
  .card-board .card-actions-bar { margin-left: 0; margin-right: 0; padding: 10px 12px; }

  /* ── Shadow game: condense the role reveal ──────────────────────────────
     The clue phase itself fits portrait untouched (measured: 0). Only the ROLE REVEAL
     overflows, and it is on a 5 second timer — whatever sticks out below cannot be scrolled
     to in that time. The impostor is hit hardest, because that is where the mission text
     sits. Measured on his screen: 83px of overflow.
     The card values must be addressed via .screen-game.bg-red — that is where the existing
     condensations live, so a rule on .impostor-* alone loses on specificity.
     Shares of the fix: reveal cards 34px, panel/gaps 24px, turn rows 25px. */
  .screen-game.bg-red .impostor-title { font-size: 19px; margin-bottom: 2px; }
  .screen-game.bg-red .impostor-subtitle { font-size: 12px; margin-bottom: 6px; }
  .screen-game.bg-red .impostor-mission { padding: 8px 12px; margin-bottom: 6px; }
  .screen-game.bg-red .impostor-mission-text { font-size: 12.5px; line-height: 1.35; }
  .screen-game.bg-red .impostor-category { padding: 6px 12px; margin-bottom: 6px; }
  .card-board .ss-panel { padding: 8px; }   /* .card-board .ss-panel (0,2,0) setzt 16px/18px — gleiche Spezifität nötig */
  .game-layout { gap: 8px; }
  .card.card-turn-list { padding: 8px; }

  /* ── Poker: structure the action bar instead of letting it wrap ──────────
     Measured, the footer was the single largest item of the game at 218px (`.pk-actions`
     alone 173px) — not the board, whose cards are already down to 34×48. The cause is the
     wrap: three buttons at `min-width: 104px` plus the raise block (`min-width: 220px`) do
     not fit one row at 345px and stack uncontrolled.
     The raise block now gets a deliberate row of its own — it carries the slider and the
     quick bets and genuinely needs the width — and the three buttons share a second row in
     equal parts (`flex: 1 1 0` instead of a fixed minimum). That is two planned rows instead
     of three to four accidental ones. */
  .card-board .card-actions-bar { gap: 4px 10px; padding: 6px 12px; }
  .card-board .card-actions-bar .pk-actions { gap: 4px; }

  /* ── Officers' skat: height chain for the measured fit ───────────────────
     fitOsk measures .osk-board. Without this lock the board is content-driven and the fit
     would measure its own output — the same feedback loop as memory. The screen becomes a
     flex column and the board takes the remaining height. */
  .card-board > .screen-game.mode-skat { display: flex; flex-direction: column; }
  .mode-skat > .osk-board { flex: 1 1 auto; min-height: 0; }

  .card-board > .screen-game.mode-memory { display: flex; flex-direction: column; }
  .mode-memory > .hangman-layout {
    flex: 1 1 auto; min-height: 0;
    grid-template-rows: minmax(0, 1fr); align-items: stretch;
  }
  .mode-memory .hangman-main { min-height: 0; min-width: 0; }
  .mode-memory .memory-board-card { flex: 1 1 auto; min-height: 0; }
  .mode-memory .memory-felt {
    margin: auto; width: fit-content; max-width: 100%; max-height: 100%;
    min-height: 0; display: flex; flex-direction: column;
  }
  .mode-memory .memory-fit { display: block; min-height: 0; }

  /* Score sidebar → one swipeable row. The header/subtitle of the wanted poster are
     dropped: at pill size they are pure decoration, and the row reads without them. */
  .hangman-layout > .game-sidebar { min-width: 0; }
  .game-sidebar .wanted-poster {
    display: flex; flex-direction: row; align-items: center; gap: 5px;
    padding: 4px; overflow-x: auto; overflow-y: hidden;
    scroll-snap-type: x proximity; background: none; border: none; box-shadow: none;
  }
  .game-sidebar .wanted-header,
  .game-sidebar .wanted-sub { display: none; }
  /* The three pill rules are deliberately staggered by specificity, because the stacked list
     uses border-bottom as a row SEPARATOR and that same edge is the pill frame's bottom side:
       (0,3,0) base pill      - replaces the dotted separator with a full transparent frame
       (0,3,1) last pill      - beats .wanted-poster .wanted-row:last-child (0,2,1)
       (0,4,0) own pill       - beats the last-pill rule, so its accent wins on all four sides
     The last-child exception writes the SHORTHAND border-bottom: none, which expands to
     width: medium (=3px) and color: currentcolor. Re-arming only border-bottom-style there is
     therefore not enough - it un-hides that inherited 3px parchment edge and the pill ends up
     with a thick light underline. All three longhands have to be restated. */
  .game-sidebar .wanted-poster .wanted-row {
    flex: 0 0 auto; scroll-snap-align: start;
    display: inline-flex; align-items: center; gap: 5px;
    padding: 3px 9px 3px 3px; border-radius: 999px;
    border: 1px solid transparent;
    background: rgba(6, 10, 8, .5); white-space: nowrap;
  }
  .game-sidebar .wanted-poster .wanted-row:last-child {
    border-bottom: 1px solid transparent;
  }
  /* Own row stays put while scrolling — you always see your own standing. */
  .game-sidebar .wanted-poster .wanted-row:has(.sidebar-player-name-me) {
    position: sticky; left: 0; z-index: 2;
    border-color: var(--accent);
    background: color-mix(in srgb, var(--accent) 20%, #0b0906);
    box-shadow: 6px 0 10px -6px rgba(0, 0, 0, .9);
  }
  .game-sidebar .wanted-row .avatar { --av-size: 22px; }
  .game-sidebar .sidebar-player-name,
  .game-sidebar .sidebar-player-name-me { font-size: 12.5px; max-width: 90px; overflow: hidden; text-overflow: ellipsis; }
  .game-sidebar .sidebar-player-status { font-size: 12.5px; }
  .mem-card { width: var(--mem-cell, auto); height: var(--mem-cell, auto); aspect-ratio: auto; }

  /* ── Mahjong: Brett um 90° gedreht gezeichnet ────────────────────────────
     All five layouts are landscape (1.21:1 to 5.23:1); upright the turtle drops to 18px
     tiles, dragon and spider to 10px. Rotating the DRAWING (never the rules — see the
     comment in MahjongPlaying.razor) puts the long axis on the long screen axis.
     Tile and grid step transpose exactly: 26x34 -> 34x26, step 30/40 -> 40/30, so the
     stage is the transpose of the base one and the gaps swap along with it.
     The motif is NOT rotated - it stays upright and is scaled to the new tile height. */
  .mode-mahjong .mjg-stage {
    width: calc(var(--rot-w) * var(--scale)); height: calc(var(--rot-h) * var(--scale));
  }
  .mode-mahjong .mjg-stone {
    width: calc(34px * var(--scale)); height: calc(26px * var(--scale));
    left: calc(var(--rx) * 40px * var(--scale));
    top:  calc(var(--x)  * 30px * var(--scale));
  }
  .mode-mahjong .mjg-stone img { width: calc(26px * var(--scale)); height: calc(20px * var(--scale)); }
  /* 24px of vertical wrap padding is a fifth of the tile budget on a phone. */
  .mode-mahjong .mjg-stage-wrap { padding: 10px 6px; }
  /* Four chips and two tools wrap to three rows on a phone — 116px of chrome, paid for
     directly in tile size by the two height-bound layouts (dragon, spider). Padding and
     gap shrink; the font sizes stay put (12px floor, DESIGN_GUIDE §6). */
  .mode-mahjong .durak-topbar { gap: 5px; }
  .mode-mahjong .durak-chip { padding: 4px 8px; }
  .mode-mahjong .mjg-tool { padding: 4px 9px; }

  /* Height chain for the fit — same pattern as the maximize block: fitMahjong reads the
     wrap's clientHeight as its budget, so the wrap must be height-locked by its ancestors.
     Content-sized, it would feed the fit its own output (shrink loop to the floor).
     grid-template-rows sizes the BOARD row only; a score sidebar lands in an implicit
     auto row below it and keeps its content height. */
  .card-board > .screen-game.mode-mahjong { display: flex; flex-direction: column; }
  .mode-mahjong > .mjg-board { flex: 1 1 auto; min-height: 0; }
  .mode-mahjong .mjg-layout {
    flex: 1 1 auto; min-height: 0;
    grid-template-rows: minmax(0, 1fr); align-items: stretch;
  }

  /* ── Seeschlacht Flottenduell: ein Brett zur Zeit ───────────────────────
     Both boards together need 899px against a 707px panel — own fleet and target
     waters are never both visible anyway, they are just split by a scroll. Shrinking
     is no way out: fitting both would put cells at ~17px, under the 24px target size,
     on the very board you aim at. So portrait shows ONE board and the switch picks it;
     the hidden one stays in the DOM and keeps its state. */
  .mode-seeschlacht .see-switch { display: flex; gap: 6px; width: 100%; }
  .mode-seeschlacht .see-main.see-focus-own > .see-side-target,
  .mode-seeschlacht .see-main.see-focus-target > .see-side-own { display: none; }
  /* With only one board on screen the cell may grow past the desktop cap of 24px.
     fitSeeBoard clears its inline --see-cell-max below the maximize breakpoint, so this
     is the value that applies; minmax(15px, …) keeps shrinking on smaller phones. */
  .mode-seeschlacht .see-board-wrap { --see-cell-max: 29px; }
  .mode-seeschlacht .see-main { padding: 8px; gap: 8px; }
  .mode-seeschlacht .see-board-h { font-size: 13px; margin: 0 0 4px; }
  .mode-seeschlacht .see-topbar { gap: 5px; }
  .mode-seeschlacht .see-chip { padding: 4px 8px; }

  /* ── Geteilte See: ein 10×10-Fenster auf das große Gitter ────────────────
     The grid keeps rendering in full and the coordinates stay absolute — clicks, salvo
     selection and every rule are untouched. The wrap is clipped to one tile (size set by
     fitSeeBoard from measured geometry) and its children are shifted by the tile origin.
     Shifting is done on the CHILDREN, not on the wrap: the wrap carries the wooden frame,
     which has to stay put. */
  .mode-seeschlacht .see-board-wrap[data-win]:not([data-win="0"]) { overflow: hidden; }
  .mode-seeschlacht .see-board-wrap[data-win]:not([data-win="0"]) > * {
    transform: translate(calc(-1 * var(--see-win-x) * var(--see-step, 0px)),
                         calc(-1 * var(--see-win-y) * var(--see-step, 0px)));
  }
  /* The labels are tile-local (modulo), so their VALUES already fit any window — only their
     position has to be undone on the axis along which they must stay pinned to the edge. */
  .mode-seeschlacht .see-board-wrap[data-win]:not([data-win="0"]) > .see-rowlabel {
    transform: translateY(calc(-1 * var(--see-win-y) * var(--see-step, 0px)));
  }
  .mode-seeschlacht .see-board-wrap[data-win]:not([data-win="0"]) > .see-collabels {
    transform: translateX(calc(-1 * var(--see-win-x) * var(--see-step, 0px)));
  }
  .mode-seeschlacht .see-board-wrap[data-win]:not([data-win="0"]) > .corner { transform: none; }

  .mode-seeschlacht .see-minimap {
    display: grid; gap: 4px; margin: 0 auto 4px;
    grid-template-columns: repeat(var(--see-mm-cols, 2), minmax(0, 26px));
  }
  .mode-seeschlacht .see-actions { gap: 6px; }
  .mode-seeschlacht .see-actions .btn { padding: 8px 12px; }
  .mode-seeschlacht .see-status { font-size: 12px; }

  /* ── Werft: Flottenleiste statt Seitenspalte ─────────────────────────────
     The 230px side column drops below the board in portrait and would stack seven ships
     into ~380px of height, which the placement board needs. As a swipeable row of chips
     the same seven fit in one line — the ship's own bar graphic already identifies it,
     so the name may go and the size is enough. Same move as the score sidebar. */
  .mode-seeschlacht .see-panel h3 { display: none; }
  .mode-seeschlacht .see-werft {
    flex-direction: row; gap: 6px; overflow-x: auto; overflow-y: hidden;
    scroll-snap-type: x proximity; padding-bottom: 2px;
  }
  .mode-seeschlacht .see-ship-item {
    flex: 0 0 auto; scroll-snap-align: start; min-height: 40px; padding: 6px 9px; gap: 6px;
  }
  .mode-seeschlacht .see-ship-item .nm { display: none; }
  .mode-seeschlacht .see-ship-item .sz { margin-left: 0; }
}
