/* ════════════════════════════════════════════════════════════
   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-cream:      #fff8ec;   /* text on fills that stay dark in BOTH themes (red/amber/felt buttons) */
  --raw-border:     rgba(200, 146, 42, .22);
  /* Currently unreferenced (the dark --surface-1-strong is now a
     literal "raised" value, not this alias). Kept as a raw-palette reference;
     --raw-surface-1 was removed once --surface-1 became an opaque literal per theme. */
  --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: #2b1c0c;                     /* page gradient start (lifted one step out of near-black) */
  --surface-0-b: #1e1409;
  --surface-0-c: #171008;
  --surface-1:        #34271a;                       /* card ON the panel: one step lighter than the panel (raised, not sunken) */
  /* 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: #3c2e1e;
  --surface-2:        var(--raw-surface-2);          /* subtle inset chip */
  --surface-hover:    rgba(200, 146, 42, .14);
  --heading:     #dcae52;                     /* readable heading/emphasis text (slightly desaturated: ~7.7:1 on the panel) */
  --text-main:   #dccbaa;                     /* ~10:1 on the panel — deliberately below the former ~14:1 */
  --text-dim:    #ad9b85;                     /* >= 4.6:1 on --surface-1-strong (table heads), ~5.2:1 on the card */
  --text-invert: #241708;                     /* text on accent-filled surfaces */
  --accent-strong: #e8b84b;                   /* theme accent, strong variant */
  --accent-amber:  #d4620a;
  --border-soft:   rgba(200, 146, 42, .18);
  --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:     rgba(200, 146, 42, .20);
  --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(42, 29, 14, .94);
  /* Elevation: depth is carried by shadows, not by opaque edge lines.
     --elev-1 = card/chip/chrome, --elev-2 = panel/modal/dropdown/toast. */
  --elev-1: 0 1px 2px rgba(0, 0, 0, .45), 0 4px 14px rgba(0, 0, 0, .32);
  --elev-2: 0 2px 4px rgba(0, 0, 0, .5), 0 14px 36px rgba(0, 0, 0, .45);
  /* Status inks shared with admin.css (formerly hex literals there). */
  --warn-ink: #f0b070;
  --info-ink: #8fb8e8;
  --row-line: rgba(200, 146, 42, .10);
  /* Strength of the saloon scene (.saloon-bg). Content sits on opaque panels, so the
     scene only shows in the side bands. Its colours are --scene-ink / --scene-glow,
     set per design; without them the rule falls back to the amber of this design. */
  --silhouette-opacity: .85;
  --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: #2c2013;
  --card-grad-b: #251b0f;
  --input-bg:    #1f160c;
  --modal-grad-a: #352614;
  --modal-grad-b: #1e140a;
  /* Theme-aware game-surface tokens (dark = the former hardcoded
     island values). Light values live in the [data-scheme="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: #2c2013;
  --board-grad-b: #251b0f;
  --board-border: rgba(200, 146, 42, .28);
  /* Maximized game board atmosphere (rule in the maximized block below).
     Dark schemes: only a faint centre light — the weakest accent inks on accent chips sit
     just above 4.5:1, so the light stays at their limit (3 %); the stage effect comes
     mostly from darker edges, which only raise contrast for the light text.
     --board-wash = share of the mode accent seeping in from the header / bottom edge. */
  --board-spot: rgba(255, 240, 210, .03);
  --board-edge: rgba(0, 0, 0, .50);
  --board-wash: 14%;
  --board-shadow: var(--elev-2), 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;
  /* Light-theme 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;
  /* Red as TEXT: --red-light reaches only ~2.7-2.9:1 on the dark boards. --red-ink follows the
     scheme (blood red in light); --raw-red-ink is for fixed-dark islands (intros, cinemas,
     toasts, felt) that stay dark in every theme. Fills, rings and bars keep --red-light. */
  --raw-red-ink: #f96b5a;
  --red-ink:     var(--raw-red-ink);
  --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).
   Selected via html[data-scheme="light"] — the SCHEME (dark|light) drives every
   component rule below; html[data-theme="<key>"] only adds a theme's own token
   block on top (seasonal themes). Both are written by theme-boot.js / ssTheme,
   persisted in localStorage (ssTheme = theme key).
   This block is the BASE of every light theme; Light Saloon itself carries its own
   [data-theme="light"] block further down. Tokens are declared on html only — a
   second selector on .modal-overlay-v2 (island era) re-pinned these base values on
   every modal and overrode the theme blocks there, so modals in the other light
   themes showed Light Saloon sand. ── */
[data-scheme="light"] {
  --surface-0-a: #f3e6c9;
  --surface-0-b: #eadab3;
  --surface-0-c: #e2cfa2;
  --surface-1:        #fbf5e6;                 /* card: lightest surface, but cream — never white */
  --surface-1-strong: #fdf9ee;
  --surface-2:        rgba(156, 106, 26, .08);
  --surface-hover:    rgba(156, 106, 26, .13);
  --heading:     #7a4a12;
  --text-main:   #4a3520;                     /* ~10:1 on the panel — deliberately below the former ~13:1 */
  /* Warm mid-brown: ~7:1 on the cream card, ~4.9:1 on the page canvas
     (#e2cfa2). The former #4f4335 was tuned for the old darker sand stops. */
  --text-dim:    #62503c;
  --text-invert: #fff8ec;
  --accent-strong: #7a4a12;
  /* Light-theme stage 2: darkened from #b5540a — fell below 3:1 on sand cards. */
  --accent-amber:  #7d3b07;
  --border-soft:   rgba(120, 80, 20, .20);
  --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, .28);
  --shadow-color:  rgba(80, 60, 30, .18);
  --scrim:         rgba(255, 250, 240, .9);
  --chrome:        rgba(244, 232, 206, .92);
  --elev-1: 0 1px 2px rgba(80, 55, 20, .10), 0 4px 14px rgba(80, 55, 20, .10);
  --elev-2: 0 2px 4px rgba(80, 55, 20, .12), 0 14px 36px rgba(80, 55, 20, .16);
  --warn-ink: #8a4c04;
  --info-ink: #1f4f86;
  --row-line: rgba(120, 80, 20, .12);
  --scene-ink: #4a3420; --scene-glow: #c08a22;
  --silhouette-opacity: .80;
  --danger:        #a3324a;
  --danger-strong: #7a2338;
  --red-ink:       #8b1a1a;
  --success:       #17663a;   /* dark enough for 4.5:1 even on the darker modal-gradient end (#f2e3c4) */
  --card-grad-a: #f7eed9;
  --card-grad-b: #f2e6cb;
  --input-bg:    #fdf9ee;
  --modal-grad-a: #fbf5e6;
  --modal-grad-b: #efe2c6;
  /* Light variants of the game-surface tokens — "wanted poster in daylight":
     cream boards, daylight felt, bright stage backdrop. */
  --board-grad-a: #f7eed9;
  --board-grad-b: #f2e6cb;
  --board-border: rgba(120, 80, 20, .35);
  /* Light schemes: the centre light only brightens (raises contrast); no darkened
     edges — the light panel has no headroom (heading on the panel is already ~6:1). */
  --board-spot: rgba(255, 255, 255, .28);
  --board-edge: transparent;
  --board-wash: 10%;
  --board-shadow: var(--elev-2), 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;
  --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). */
  /* Light-theme stage 2: darkened from #6a5642 (see --text-dim). */
  --old-paper: #4a3b28;
  --accent:    #9c6a1a;   /* gold-mode accent readable on light; .mode-* still override */
}

/* ── Themes on the DARK scheme (html[data-theme="<key>"] on top of data-scheme="dark").
   Only tokens — the component rules come from the scheme. Everything a theme does
   not set falls through to the :root (dark) values. Mockup + rationale:
   docs/mockups/ss0464-saisonale-themes.html. Game accents (.mode-*) are theme-
   independent by design; only the DEFAULT accent (gold) and the surfaces change.
   Aliases resolve where they are declared, so --accent/--accent-ink/--gold-ink are
   re-declared here to pick up the theme's gold (alias trap, see A11). ── */

/* Halloween — pumpkin on violet-black */
[data-theme="halloween"] {
  --surface-0-a: #2a1533; --surface-0-b: #1d0f24; --surface-0-c: #150a1a;
  --chrome:        rgba(40, 22, 48, .94);
  --scrim:         rgba(21, 10, 26, .85);
  --card-grad-a: #2c1a37; --card-grad-b: #24142e;
  --board-grad-a: #2c1a37; --board-grad-b: #24142e;
  --surface-1:        #36223f;
  --surface-1-strong: #3f2a4a;
  --input-bg:    #1f1226;
  --modal-grad-a: #372440; --modal-grad-b: #1f1226;
  --text-main:   #e8dccb;
  --text-dim:    #b39fb0;
  --old-paper:   #cdb6b0;
  --heading:     #f0932b;
  --accent-strong: #f0932b;
  --accent-amber:  #c4501a;
  --gold:       #e07b1a;
  --gold-light: #ffa640;
  --amber:      #c4501a;
  --btn-gold-start: #d6571c;   /* lighter pumpkin: dark ink stays >= 4.5:1 along the whole button */
  --accent:       #f0932b;
  --accent-light: #ffb054;
  --accent-ink:   var(--accent-light);
  --border-soft:   rgba(240, 147, 43, .20);
  --border-strong: rgba(240, 147, 43, .45);
  --card-edge:     rgba(240, 147, 43, .22);
  --board-border:  rgba(240, 147, 43, .30);
  --row-line:      rgba(240, 147, 43, .12);
  --border-faint:  rgba(240, 147, 43, .10);
  --surface-2:     rgba(240, 147, 43, .08);
  --surface-hover: rgba(240, 147, 43, .14);
  --elev-1: 0 1px 2px rgba(0, 0, 0, .5), 0 4px 14px rgba(0, 0, 0, .38);
  --elev-2: 0 2px 4px rgba(0, 0, 0, .55), 0 14px 36px rgba(0, 0, 0, .5);
  --warn-ink: #ffb86b;
  --info-ink: #9fb8f0;
  --deco-image: url("/img/saloon-deco-halloween.svg");
  --deco-opacity: .85;
  --scene-ink: #b184cf; --scene-glow: #f0932b;
  --deco-flake: #eadfc6;
}
/* Christmas — fir green, gold, red */
[data-theme="christmas"] {
  --surface-0-a: #142a1c; --surface-0-b: #0e1e14; --surface-0-c: #0a160f;
  --chrome:        rgba(18, 38, 26, .94);
  --scrim:         rgba(10, 22, 15, .85);
  --card-grad-a: #172c20; --card-grad-b: #12241a;
  --board-grad-a: #172c20; --board-grad-b: #12241a;
  --surface-1:        #1e3628;
  --surface-1-strong: #244030;
  --input-bg:    #10201a;
  --modal-grad-a: #1c3427; --modal-grad-b: #0e1e14;
  --text-main:   #eadfc6;
  --text-dim:    #a9b8a4;
  --old-paper:   #c8c9a8;
  --heading:     #e8b84b;
  --accent-amber:  #b3372f;
  --amber:      #b3372f;
  --btn-gold-start: #d1564f;   /* lighter red: #b3372f gave the dark button ink only 3.3:1 */
  --accent:       #b3372f;
  --accent-light: #e0574a;
  --accent-ink:   var(--accent-light);
  --border-soft:   rgba(232, 184, 75, .20);
  --card-edge:     rgba(232, 184, 75, .22);
  --board-border:  rgba(232, 184, 75, .30);
  /* No centre light: the inks have no headroom on this green board; edges only. */
  --board-spot:    transparent;
  --board-edge:    rgba(0, 0, 0, .60);
  --row-line:      rgba(232, 184, 75, .12);
  --elev-1: 0 1px 2px rgba(0, 0, 0, .5), 0 4px 14px rgba(0, 0, 0, .36);
  --elev-2: 0 2px 4px rgba(0, 0, 0, .55), 0 14px 36px rgba(0, 0, 0, .48);
  --deco-image: url("/img/saloon-deco-christmas.svg");
  --deco-opacity: .85;
  --scene-ink: #86b892; --scene-glow: #e8b84b;
  --deco-flake: #f4f1e6;
}
/* Vivid — cool ink, saturated accents */
[data-theme="vivid"] {
  --surface-0-a: #1a1d2e; --surface-0-b: #13162a; --surface-0-c: #0e1020;
  --chrome:        rgba(28, 31, 48, .94);
  --scrim:         rgba(14, 16, 32, .85);
  --card-grad-a: #1f2338; --card-grad-b: #191c2e;
  --board-grad-a: #1f2338; --board-grad-b: #191c2e;
  --surface-1:        #282d47;
  --surface-1-strong: #303655;
  --input-bg:    #151829;
  --modal-grad-a: #262b44; --modal-grad-b: #13162a;
  --text-main:   #e9e6f2;
  --text-dim:    #aaa6c0;
  --old-paper:   #c9c4d8;
  --text-invert: #1a1d2e;
  --heading:     #ffd166;
  --accent-strong: #ffd166;
  --accent-amber:  #ef476f;
  --gold:       #f4a261;
  --gold-light: #ffd166;
  --amber:      #ef476f;
  --accent:       #ef476f;
  --accent-light: #ff7a9c;
  --accent-ink:   var(--accent-light);
  --success:       #06d6a0;
  --danger:        #ff7a9c;
  --danger-strong: #ef476f;
  --border-soft:   rgba(255, 209, 102, .22);
  --border-strong: rgba(255, 209, 102, .45);
  --card-edge:     rgba(255, 209, 102, .24);
  --board-border:  rgba(255, 209, 102, .30);
  --board-wash:    18%;
  --board-spot:    rgba(235, 235, 255, .02);
  --row-line:      rgba(255, 209, 102, .12);
  --border-faint:  rgba(255, 209, 102, .10);
  --surface-2:     rgba(255, 209, 102, .08);
  --surface-hover: rgba(255, 209, 102, .14);
  --elev-1: 0 1px 2px rgba(0, 0, 0, .5), 0 4px 14px rgba(0, 0, 0, .36);
  --elev-2: 0 2px 4px rgba(0, 0, 0, .55), 0 14px 36px rgba(0, 0, 0, .48);
  --warn-ink: #ffb86b;
  --info-ink: #4cc9f0;
  --scene-ink: #8f97dc; --scene-glow: #ffd166;
}
/* Hoher Kontrast ("contrast", HK-1 "Schwarz & Gold") — text >= 7:1 (AAA), opaque surfaces and
   edges >= 3:1, no shadows, no silhouette. Only the tokens live here; the outlined chips, accent
   stripes and heavier edges hang on html[data-contrast="more"] (block at the end of this file).
   Mockup with the measured pairs: docs/mockups/ss0498-hoher-kontrast.html. */
[data-theme="contrast"] {
  --surface-0-a: #0b0906; --surface-0-b: #0b0906; --surface-0-c: #0b0906;
  --chrome:        #000000;
  --scrim:         rgba(0, 0, 0, .88);
  --shadow-color:  rgba(0, 0, 0, 0);
  --card-grad-a: #14100b; --card-grad-b: #14100b;
  --board-grad-a: #14100b; --board-grad-b: #14100b;
  --surface-1:        #1d1710;
  --surface-1-strong: #231c13;
  --surface-2:     #2c2418;
  --surface-hover: #2e2517;
  --input-bg:    #000000;
  --modal-grad-a: #14100b; --modal-grad-b: #14100b;
  --text-main:   #fff6e6;
  --text-dim:    #e3d6bf;
  --old-paper:   #f0e6d4;
  --text-invert: #000000;
  --heading:     #ffd166;
  --accent-strong: #ffd166;
  --accent-amber:  #ffb86b;
  --focus-ring:    #6fd3ff;   /* ice blue: must stand apart from the gold of headings and buttons */
  --gold:       #ffd166;
  --gold-light: #ffe08a;
  --amber:      #ffd166;
  --accent:       #ffd166;
  --accent-light: #ffe08a;
  --btn-gold-start: #ffd166;
  --btn-gold-end:   #ffd166;
  --btn-gold-ink:   #000000;
  --btn-gold-glow:  0 0 0 rgba(0, 0, 0, 0);
  --ghost-line: #ffd166;
  --ghost-ink:  #ffd166;
  --tab-on:     #ffd166;
  --tab-line:   #ffd166;
  --toggle-on:      #8ef0a8;
  --toggle-on-edge: #8ef0a8;
  --success:       #8ef0a8;
  --danger:        #ff9d8f;
  --danger-strong: #ff9d8f;
  --red-ink:       #ff9d8f;
  --red-fill-a:    #ff9d8f;
  --red-fill-b:    #ff9d8f;
  --ghost-red-ink:   #ff9d8f;
  --ghost-red-line:  #ff9d8f;
  --ghost-red-hover: #ffc2b8;
  --warn-ink: #ffd27a;
  --info-ink: #9dd2ff;
  --border-soft:   #9c8658;
  --border-strong: #cfb27a;
  --card-edge:     #9c8658;
  --board-border:  #cfb27a;
  --row-line:      #5e5038;
  --border-faint:  #5e5038;
  --edge:          #5e5038;
  --edge-strong:   #9c8658;
  --well:          #000000;
  --well-strong:   #000000;
  --elev-1: 0 0 0 rgba(0, 0, 0, 0);
  --elev-2: 0 0 0 rgba(0, 0, 0, 0);
  --board-shadow: 0 0 0 rgba(0, 0, 0, 0);
  --board-spot: transparent;
  --board-edge: transparent;
  --board-wash: 0%;
  --felt-base-a: #123524; --felt-base-b: #0d2a1c; --felt-base-c: #08170f;
  --felt-rim:    #cfb27a;
  --silhouette-opacity: 0;
}

/* ── Themes on the LIGHT scheme (html[data-theme] on top of data-scheme="light").
   The light block above declares the light inks and surfaces; these blocks come
   later in the file and therefore win — so they must ALSO re-declare the light inks
   (--text-*, --old-paper, --heading, --gold-ink, --accent-amber, --scrim, --input-bg,
   --modal-grad-*), otherwise sand-brown inks stay on cool or green paper. ── */

/* Vivid (light) — cool paper, saturated accents */
[data-theme="vividlight"] {
  --surface-0-a: #eef0fa; --surface-0-b: #e2e6f4; --surface-0-c: #d6dcef;
  --chrome:        rgba(240, 243, 252, .92);
  --scrim:         rgba(238, 240, 250, .9);
  --shadow-color:  rgba(40, 50, 90, .18);
  --card-grad-a: #f6f7fd; --card-grad-b: #eef1fa;
  --board-grad-a: #f6f7fd; --board-grad-b: #eef1fa;
  --surface-1:        #f8f9fe;
  --surface-1-strong: #fdfdff;
  --input-bg:    #fdfdff;
  --modal-grad-a: #f8f9fe; --modal-grad-b: #e6eaf6;
  --surface-2:     rgba(60, 70, 120, .08);
  --surface-hover: rgba(60, 70, 120, .13);
  --text-main:   #3a3e55;
  --text-dim:    #4d536b;   /* was #5a6079: 4.1 to 4.4 : 1 on tinted cards and the game grounds */
  --old-paper:   #4a4f6a;
  --heading:     #9c1f60;
  --accent-strong: #9c1f60;
  --accent-amber:  #b3226b;
  --gold:       #d97a1e;
  --gold-light: #f4b942;
  --amber:      #e63e6d;
  --accent:       #d4386f;
  --accent-light: #ff7aa2;
  --success:       #0a654a;
  --danger:        #a31250;
  --danger-strong: #8e1244;
  --border-soft:   rgba(60, 70, 120, .22);
  --border-strong: rgba(60, 70, 120, .5);
  --card-edge:     rgba(60, 70, 120, .26);
  --board-border:  rgba(60, 70, 120, .35);
  --row-line:      rgba(60, 70, 120, .12);
  --border-faint:  rgba(60, 70, 120, .12);
  --elev-1: 0 1px 2px rgba(40, 50, 90, .10), 0 4px 14px rgba(40, 50, 90, .10);
  --elev-2: 0 2px 4px rgba(40, 50, 90, .12), 0 14px 36px rgba(40, 50, 90, .16);
  --warn-ink: #9a4b00;
  --info-ink: #1f5fa8;
  --scene-ink: #3c4678; --scene-glow: #e08a1e;
}
/* Easter — spring green paper, lilac, egg-yolk gold */
[data-theme="easter"] {
  --surface-0-a: #f3f7e8; --surface-0-b: #e9f1d9; --surface-0-c: #dce9c8;
  --chrome:        rgba(244, 248, 232, .92);
  --scrim:         rgba(243, 247, 232, .9);
  --shadow-color:  rgba(60, 80, 30, .18);
  --card-grad-a: #f8fbef; --card-grad-b: #f1f6e3;
  --board-grad-a: #f8fbef; --board-grad-b: #f1f6e3;
  --surface-1:        #fcfdf5;
  --surface-1-strong: #fefff8;
  --input-bg:    #fefff8;
  --modal-grad-a: #fcfdf5; --modal-grad-b: #ecf3dc;
  --surface-2:     rgba(90, 110, 60, .08);
  --surface-hover: rgba(90, 110, 60, .13);
  --text-main:   #3a3d2a;
  --text-dim:    #535842;   /* was #61664f: 4.1 to 4.4 : 1 on tinted cards and the game grounds */
  --old-paper:   #4e5140;
  --heading:     #6f478f;
  --accent-strong: #6f478f;
  --accent-amber:  #8f5a00;
  --gold:       #c9a227;
  --gold-light: #ecd35c;
  --amber:      #e08a3c;
  --accent:       #6f478f;
  --accent-light: #b48ad6;
  --success:       #2a7a4b;
  --border-soft:   rgba(90, 110, 60, .22);
  --border-strong: rgba(90, 110, 60, .5);
  --card-edge:     rgba(90, 110, 60, .26);
  --board-border:  rgba(90, 110, 60, .35);
  --row-line:      rgba(90, 110, 60, .12);
  --border-faint:  rgba(90, 110, 60, .12);
  --elev-1: 0 1px 2px rgba(60, 80, 30, .10), 0 4px 14px rgba(60, 80, 30, .10);
  --elev-2: 0 2px 4px rgba(60, 80, 30, .12), 0 14px 36px rgba(60, 80, 30, .16);
  --warn-ink: #8f5a00;
  --info-ink: #2b6cb0;
  --deco-image: url("/img/saloon-deco-easter.svg");
  --deco-opacity: .85;
  --scene-ink: #4f6236; --scene-glow: #c9a227;
  --deco-flake: #f4a6c0;
}

/* Light Saloon — "Mittagssonne": sun-bleached linen instead of sand, the header, footer,
   page head and game head as a walnut sign (chrome inks, see the Chrome inks block),
   brass lines, a terracotta primary button, brick instead of raspberry. Mockup with the
   measured pairs: docs/mockups/light-saloon-redesign.html (variant A). */
[data-theme="light"] {
  --surface-0-a: #f2ede4; --surface-0-b: #e8e0d2; --surface-0-c: #ddd2c1;
  --scrim:         rgba(250, 247, 240, .9);
  --shadow-color:  rgba(58, 40, 24, .16);
  --card-grad-a: #f9f6f0; --card-grad-b: #f2ede3;
  --board-grad-a: #f9f6f0; --board-grad-b: #f2ede3;
  --surface-1:        #fdfbf7;
  --surface-1-strong: #fffefb;
  --input-bg:    #fffefb;
  --modal-grad-a: #fbf9f4; --modal-grad-b: #efe9dd;
  --surface-2:     rgba(74, 52, 32, .05);
  --surface-hover: rgba(184, 134, 43, .10);
  --text-main:   #45382c;   /* ~9.7:1 on the panel (DESIGN_GUIDE §2: 8-10:1 by intent, not 14:1) */
  --text-dim:    #62564a;
  --old-paper:   #54473a;
  --heading:     #633a17;
  --accent-strong: #7b5214;
  --accent-amber:  #8a4312;
  --gold:       #b8862b;
  --gold-light: #dcae52;
  --accent:       #b8862b;
  --accent-light: #dcae52;
  --btn-gold-start: #cf7a35;
  --btn-gold-end:   #d9a44a;
  --btn-gold-ink:   #1e140b;
  --btn-gold-glow:  0 3px 12px rgba(191, 106, 40, .26);
  --ghost-line:     rgba(99, 58, 23, .34);
  --ghost-ink:      #4a321c;
  --success:       #2c6a3f;
  --danger:        #a3392a;
  --danger-strong: #82291c;
  --red-ink:       #93301f;
  --red-fill-a:    #a3392a;
  --red-fill-b:    #7f2a1e;
  --ghost-red-ink:   #8e2f20;
  --ghost-red-line:  rgba(142, 47, 32, .40);
  --ghost-red-hover: #6f2418;
  --toggle-on:      #2c6a3f;
  --toggle-on-edge: #24573a;
  --warn-ink: #8a5108;
  --info-ink: #2a5b86;
  --border-soft:   rgba(74, 52, 32, .16);
  --border-strong: rgba(74, 52, 32, .42);
  --card-edge:     rgba(74, 52, 32, .18);
  --board-border:  rgba(74, 52, 32, .35);   /* same strength as before: the game frame must not get lighter */
  --row-line:      rgba(74, 52, 32, .10);
  --border-faint:  rgba(74, 52, 32, .12);
  --edge:          rgba(74, 52, 32, .14);
  --edge-strong:   rgba(74, 52, 32, .28);
  --well:          rgba(74, 52, 32, .07);
  --well-strong:   rgba(74, 52, 32, .12);
  --elev-1: 0 1px 2px rgba(58, 40, 24, .10), 0 4px 14px rgba(58, 40, 24, .07);
  --elev-2: 0 2px 4px rgba(58, 40, 24, .12), 0 18px 40px rgba(58, 40, 24, .14);
  --felt-base-a: #406c54; --felt-base-b: #365d48; --felt-base-c: #2d4f3d;
  --felt-rim:    #5b4330;
  --stage-back-a: #eadfcb; --stage-back-b: #dac9ac;
  --stage-floor-a: #a88457; --stage-floor-b: #9a774b;
  --accent-ink-mix: 50%;   /* --chip-tint (20 %) and --gold-ink follow further down (same-specificity rules) */
  /* Lobby panels + the game head (walnut sign with the accent along its lower edge). */
  --lobby-card-a: #f9f6f0; --lobby-card-b: #f1ebdf;
  --band-a: #47341f; --band-b: #3b2b1b;
  --band-mix-a: 14%; --band-mix-b: 10%;
  --band-rule: 3px;
  --plaque: #3b2b1b; --plaque-edge: #f1dcb2;
  --plaque-ico-mix: 38%; --plaque-ink-mix: 20%;
  --panel-veil: #f4efe6;
  /* Walnut chrome: header, footer, page head, game head. */
  --chrome:             #3a2a1d;
  --chrome-heading:     #f0cd84;
  --chrome-text:        #eadcc4;
  --chrome-dim:         #c9b79b;
  --chrome-old-paper:   #d8c7a8;
  --chrome-focus:       #f0cd84;
  --chrome-control:     rgba(255, 240, 215, .08);
  --chrome-raised:      #4a3726;
  --chrome-hover:       rgba(240, 205, 132, .12);
  --chrome-line:        rgba(230, 187, 108, .30);
  --chrome-line-strong: rgba(230, 187, 108, .55);
  --chrome-red:         #f59a86;
  --chrome-red-line:    rgba(245, 154, 134, .50);
  --chrome-red-hover:   #ffc2b4;
  --chrome-ann-info:    #cfe3f5;
  --chrome-ann-warn:    #f0dca0;
  --chrome-ann-warn-bg: rgba(212, 160, 30, .14);
  --chrome-ann-error:   #f0c0b8;
  --logo-light-display: none;
  --logo-dark-display:  inline-block;
  --logo-filter:        drop-shadow(0 0 6px rgba(200, 146, 42, .4));
}

/* Desert Sky ("desert") — daylight taken literally: sky blue at the top of the page,
   adobe sand at the bottom, terracotta leads (headings, primary button with light ink),
   turquoise is the counter colour (tabs, links, switches, focus, info, secondary button),
   poster heads in the full enamel accent. Mockup: docs/mockups/light-saloon-redesign.html (C). */
[data-theme="desert"] {
  --surface-0-a: #d6e5ea; --surface-0-b: #ebe6dc; --surface-0-c: #e4d4bd;
  --chrome:        rgba(251, 250, 246, .92);
  --scrim:         rgba(251, 249, 244, .9);
  --shadow-color:  rgba(70, 50, 35, .16);
  --card-grad-a: #fcfaf6; --card-grad-b: #f6f1e9;
  --board-grad-a: #fcfaf6; --board-grad-b: #f6f1e9;
  --surface-1:        #fffdf9;
  --surface-1-strong: #fffefc;
  --input-bg:    #fffefc;
  --modal-grad-a: #fdfbf8; --modal-grad-b: #f3ece2;
  --surface-2:     rgba(23, 112, 107, .05);
  --surface-hover: rgba(23, 112, 107, .08);
  --text-main:   #463a31;   /* ~9.7:1 on the panel (DESIGN_GUIDE §2: 8-10:1 by intent, not 14:1) */
  --text-dim:    #5f554c;
  --old-paper:   #53483e;
  --heading:     #8f3b1b;
  --accent-strong: #17706b;
  --accent-amber:  #8c3a14;
  --gold:       #c98a2e;
  --gold-light: #e3b05a;
  --accent:       #a8401e;
  --accent-light: #c9602f;
  --btn-gold-start: #a8401e;
  --btn-gold-end:   #b24e27;
  --btn-gold-ink:   #fff8ec;
  --btn-gold-glow:  0 4px 14px rgba(168, 64, 30, .26);
  --ghost-line:     rgba(23, 112, 107, .45);
  --ghost-ink:      #0f5a56;   /* was #17706b: 2.8 to 3.6 : 1 at the worst stop of the game grounds */
  --tab-on:         #12605c;   /* one step darker than the turquoise: the page head carries a terracotta tint */
  --tab-line:       #17706b;
  --toggle-on:      #17706b;
  --toggle-on-edge: #125a56;
  --success:       #2a6b45;
  --danger:        #a3302a;
  --danger-strong: #7f241f;
  --red-ink:       #a3302a;
  --red-fill-a:    #a3302a;
  --red-fill-b:    #7f241f;
  --ghost-red-ink:   #9a2d26;
  --ghost-red-line:  rgba(163, 48, 42, .42);
  --ghost-red-hover: #7a221c;
  --warn-ink: #8c5000;
  --info-ink: #17706b;
  --border-soft:   rgba(60, 50, 40, .13);
  --border-strong: rgba(60, 50, 40, .38);
  --card-edge:     rgba(60, 50, 40, .14);
  --board-border:  rgba(80, 60, 40, .35);
  --row-line:      rgba(60, 50, 40, .08);
  --border-faint:  rgba(60, 50, 40, .10);
  --edge:          rgba(60, 50, 40, .12);
  --edge-strong:   rgba(60, 50, 40, .26);
  --well:          rgba(23, 112, 107, .06);
  --well-strong:   rgba(23, 112, 107, .10);
  --elev-1: 0 1px 2px rgba(70, 50, 35, .08), 0 6px 16px rgba(70, 50, 35, .07);
  --elev-2: 0 2px 6px rgba(70, 50, 35, .10), 0 20px 44px rgba(70, 50, 35, .14);
  --felt-base-a: #2f6c5c; --felt-base-b: #285d4f; --felt-base-c: #214e42;
  --felt-rim:    #8c5a3a;
  --stage-back-a: #dfe9ea; --stage-back-b: #cfdadb;
  --stage-floor-a: #b07a52; --stage-floor-b: #a06c46;
  --scene-ink: #5a3a22; --scene-glow: #d0892a;
  --accent-ink-mix: 48%;   /* --chip-tint (18 %) and --gold-ink follow further down (same-specificity rules) */
  --lobby-card-a: #fcfaf6; --lobby-card-b: #f4eee4;
  --band-a: #f7f3ec; --band-b: #efe8dc;
  --band-mix-a: 10%; --band-mix-b: 16%;
}

/* ── §8 "Always dark islands" — DISMANTLED in light-theme stage 2. The former
   dark re-pin block for .screen-game/.screen-break/.screen-voting/
   .screen-result/.card-board was removed outright: every game surface now runs
   on the theme-aware tokens (dark values = the old island values).
   Deliberately kept FIXED DARK are only standalone artwork/cinema surfaces
   (intro windows .gintro-*, dice/action cinemas, roll/shuffle prompts,
   kick toasts, card backs, Seeschlacht water, chat telegram paper,
   header hero .lobby-hero) — their text inks hang off the raw palette
   (--raw-*), never off 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-scheme="light"] .mode-uttt { --x-color: #7a2a4e; --o-color: #3f5468; }
/* Quizmaster: brass (host-moderated quiz show; reserved in DESIGN_GUIDE §3, measured against
   every neighbour — copper and bronze were too close to Tabu and Doppelkopf). */
.mode-quizmaster    { --accent: #76702a; --accent-light: #b3aa50; }
/* Klapperschlange: chartreuse, venom green (snake; reserved in DESIGN_GUIDE §3 for the solo
   arcade games, measured against every neighbour). */
.mode-klapperschlange { --accent: #6f8f22; --accent-light: #a8c455; }
/* Spukstollen: mint, a will-o'-the-wisp in the mine (maze chase; reserved in DESIGN_GUIDE §3 for
   the solo arcade games, measured against every neighbour). */
.mode-spukstollen   { --accent: #3aa88a; --accent-light: #6fd0b4; }
/* Frachtgut: lavender (falling freight; reserved in DESIGN_GUIDE §3 for the solo arcade games,
   chosen for its distance to every neighbour — it tells nothing about the game on purpose). */
.mode-frachtgut     { --accent: #6a5fa8; --accent-light: #a79ae0; }
/* Mühle: dove blue (board duel; reserved in DESIGN_GUIDE §3 for the board games, nearest
   neighbour Boomtown 12.8). Its --accent-light passes as dark ink on every board (min 4.67). */
.mode-muehle        { --accent: #566b8c; --accent-light: #93a9cc; }
/* Schach: ebony and ivory, the colours of the pieces (board duel; reserved in DESIGN_GUIDE §3,
   nearest neighbour Mahjong 18.8). Its --accent-light passes as dark ink on every board. */
.mode-schach        { --accent: #5c5446; --accent-light: #c4b89c; }
/* Backgammon: rose quartz (board duel; reserved in DESIGN_GUIDE §3, nearest neighbour Tabu 13.3). */
.mode-backgammon    { --accent: #a0546a; --accent-light: #d68aa0; }
/* Sudoku: indigo, cool and clear (number puzzle; reserved in DESIGN_GUIDE §3, measured against
   every neighbour). */
.mode-sudoku        { --accent: #40409a; --accent-light: #8184dc; }
/* Bonanza: bone ivory, the colour of the dice (nearest neighbour Mahjong 13.0). Its --accent-light
   passes as ink on every dark board (10.96 on the panel) and needs no darker-scheme ink. */
.mode-bonanza       { --accent: #8c8060; --accent-light: #d8ccae; }

/* Light-theme 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-scheme="light"] { --gold-ink: #7a4a12; }
/* Christmas default accent: its red reaches only ~4:1 as text on the green board, so the
   ink is lighter than --accent-light. Must follow the :root line above (same specificity). */
[data-theme="christmas"] { --accent-ink: #f4695a; }
/* Light Saloon's and Desert Sky's gold inks. Must follow the two lines above for the same reason. */
[data-theme="light"] { --gold-ink: #7b5214; }
[data-theme="desert"] { --gold-ink: #7d5212; }
[data-theme="contrast"] { --gold-ink: #ffd166; --accent-ink: #ffd166; }
/* The same trap silently dropped these four theme inks until 2026-09-28 (they sat inside the
   theme blocks, above the :root/scheme lines). Halloween and Vivid (light) were lifted one
   step in the same hue once they applied: the old values reached only 4.28 and 4.24 on the card. */
[data-theme="halloween"]  { --gold-ink: #e4882e; }
[data-theme="vivid"]      { --gold-ink: #f4a261; }
[data-theme="vividlight"] { --gold-ink: #a5520d; }
[data-theme="easter"]     { --gold-ink: #7a6210; }
.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, .mode-quizmaster, .mode-klapperschlange, .mode-spukstollen,
.mode-frachtgut, .mode-muehle, .mode-schach, .mode-backgammon, .mode-sudoku, .mode-bonanza {
  --accent-ink: var(--accent-light);
}
/* Dark-scheme ink for the darker accents: their --accent-light stays below 4.5:1 as text
   on the dark boards (worst: Christmas). Same OKLCH hue, lighter; the accent pair itself
   is unchanged (DESIGN_GUIDE §3). The light rule below is more specific and still wins. */
.mode-schattenspiel  { --accent-ink: #c480b2; }
.mode-hangman        { --accent-ink: #d88657; }
.mode-musikquiz      { --accent-ink: #f27590; }
.mode-poker          { --accent-ink: #e77684; }
.mode-seeschlacht    { --accent-ink: #6fa1d0; }
.mode-durak          { --accent-ink: #a988f1; }
.mode-rausschmeisser { --accent-ink: #8ba5b6; }
.mode-uttt           { --accent-ink: #e178ab; }
.mode-backgammon     { --accent-ink: #db8fa5; }
.mode-sudoku         { --accent-ink: #8e92eb; }
/* Hoher Kontrast: every mode gets the lighter sibling of its --accent-light (mixed with white until
   >= 7:1 on the card #1d1710, AAA) — computed in docs/mockups/ss0498-hoher-kontrast.html. The accent
   pair itself stays unchanged. Two attribute+class selectors beat the one-class rules above. */
[data-theme="contrast"] .mode-backgammon      { --accent-ink: #d88fa4; }
[data-theme="contrast"] .mode-bonanza         { --accent-ink: #d8ccae; }
[data-theme="contrast"] .mode-boomtown        { --accent-ink: #6faade; }
[data-theme="contrast"] .mode-doppelkopf      { --accent-ink: #d79855; }
[data-theme="contrast"] .mode-durak           { --accent-ink: #b19dd9; }
[data-theme="contrast"] .mode-frachtgut       { --accent-ink: #b0a4e3; }
[data-theme="contrast"] .mode-hangman         { --accent-ink: #cf9979; }
[data-theme="contrast"] .mode-klapperschlange { --accent-ink: #a8c455; }
[data-theme="contrast"] .mode-mahjong         { --accent-ink: #b8a888; }
[data-theme="contrast"] .mode-memory          { --accent-ink: #37b894; }
[data-theme="contrast"] .mode-muehle          { --accent-ink: #93a9cc; }
[data-theme="contrast"] .mode-schach          { --accent-ink: #c4b89c; }
[data-theme="contrast"] .mode-musikquiz       { --accent-ink: #e28da1; }
[data-theme="contrast"] .mode-quizmaster      { --accent-ink: #b3aa50; }
[data-theme="contrast"] .mode-rausschmeisser  { --accent-ink: #92a8b6; }
[data-theme="contrast"] .mode-schattenspiel   { --accent-ink: #c099b6; }
[data-theme="contrast"] .mode-schnellschuss   { --accent-ink: #4fc4d6; }
[data-theme="contrast"] .mode-seeschlacht     { --accent-ink: #8aaac8; }
[data-theme="contrast"] .mode-skat            { --accent-ink: #89b163; }
[data-theme="contrast"] .mode-spukstollen     { --accent-ink: #6fd0b4; }
[data-theme="contrast"] .mode-sudoku          { --accent-ink: #9a9de3; }
[data-theme="contrast"] .mode-tabu            { --accent-ink: #d9937d; }
[data-theme="contrast"] .mode-poker           { --accent-ink: #db929d; }
[data-theme="contrast"] .mode-uttt            { --accent-ink: #d890b4; }
[data-theme="contrast"] .mode-wissensquiz     { --accent-ink: #5ab4ac; }
/* Accent share of the tinted chip ground behind accent-ink text (selected chips, role and
   difficulty badges). Above ~14 % the tint lifts the dark ground so far that the lighter
   inks drop below 4.5:1; the light scheme has headroom and keeps a stronger tint.
   A percentage, not a colour alias, so each rule still mixes its own mode accent. */
:root { --chip-tint: 14%; }
[data-scheme="light"] { --chip-tint: 26%; }
/* Light Saloon mixes a stronger accent into its inks (--accent-ink-mix 50 %), so its chips
   stay lighter to keep the inks at >= 4.5:1. Follows the scheme line (same specificity). */
[data-theme="light"] { --chip-tint: 20%; }
[data-theme="desert"] { --chip-tint: 18%; }
/* Hoher Kontrast: chips carry no tint at all — they are outlined ([data-contrast="more"] block). */
[data-theme="contrast"] { --chip-tint: 0%; }
[data-scheme="light"],
[data-scheme="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, .mode-quizmaster,
  .mode-klapperschlange, .mode-spukstollen, .mode-frachtgut, .mode-muehle, .mode-schach, .mode-backgammon,
  .mode-sudoku, .mode-bonanza) {
  --accent-ink: color-mix(in srgb, var(--accent) var(--accent-ink-mix, 30%), var(--text-main));
}
/* Mint is the lightest accent: at Light Saloon's 50 % and Desert Sky's 48 % its ink reached only
   4.25 and 4.45 : 1 on the cards, and less on the mint-tinted top band of the board. 32 % keeps
   it at >= 4.84 there (worst case over every gradient stop). */
[data-theme="light"] .mode-spukstollen, [data-theme="desert"] .mode-spukstollen { --accent-ink-mix: 32%; }

/* ── Chrome inks. Header, footer, page head (.pf-pageuh) and game head (.lobby-header-card)
   may sit on a darker band than the page (Light Saloon: walnut). Inside them the semantic
   tokens point to --chrome-* values; a theme that sets none of those keeps the page values
   (pixel-identical). --page-* snapshots the page tokens on html (they resolve there, after
   every theme block), so the popovers inside the chrome can hand the page values back.
   --ann-*: announcement banner inks in the header (light-scheme rule falls back to its own). ── */
:root {
  --page-heading: var(--heading);
  --page-text-main: var(--text-main);
  --page-text-dim: var(--text-dim);
  --page-old-paper: var(--old-paper);
  --page-gold-ink: var(--gold-ink);
  --page-accent-strong: var(--accent-strong);
  --page-input-bg: var(--input-bg);
  --page-surface-1: var(--surface-1);
  --page-surface-1-strong: var(--surface-1-strong);
  --page-surface-2: var(--surface-2);
  --page-surface-hover: var(--surface-hover);
  --page-border-soft: var(--border-soft);
  --page-border-strong: var(--border-strong);
  --page-red-ink: var(--red-ink);
  --page-ghost-line: var(--ghost-line);
  --page-ghost-ink: var(--ghost-ink);
  --page-ghost-red-ink: var(--ghost-red-ink);
  --page-ghost-red-line: var(--ghost-red-line);
  --page-ghost-red-hover: var(--ghost-red-hover);
}
:is(.app-header, .app-footer, .pf-pageuh, .lobby-header-card) {
  --heading: var(--chrome-heading, var(--page-heading));
  --text-main: var(--chrome-text, var(--page-text-main));
  --parchment: var(--chrome-text, var(--page-text-main));
  --text-dim: var(--chrome-dim, var(--page-text-dim));
  --smoke: var(--chrome-dim, var(--page-text-dim));
  --old-paper: var(--chrome-old-paper, var(--page-old-paper));
  --gold-ink: var(--chrome-heading, var(--page-gold-ink));
  --accent-strong: var(--chrome-focus, var(--page-accent-strong));
  --input-bg: var(--chrome-control, var(--page-input-bg));
  --surface-1: var(--chrome-raised, var(--page-surface-1));
  --surface-1-strong: var(--chrome-raised, var(--page-surface-1-strong));
  --surface-2: var(--chrome-control, var(--page-surface-2));
  --surface-hover: var(--chrome-hover, var(--page-surface-hover));
  --border-soft: var(--chrome-line, var(--page-border-soft));
  --border-strong: var(--chrome-line-strong, var(--page-border-strong));
  --red-ink: var(--chrome-red, var(--page-red-ink));
  --ghost-line: var(--chrome-line-strong, var(--page-ghost-line));   /* unset in a theme: invalid → the button's own fallback */
  --ghost-ink: var(--chrome-old-paper, var(--page-ghost-ink));
  --ghost-red-ink: var(--chrome-red, var(--page-ghost-red-ink));
  --ghost-red-line: var(--chrome-red-line, var(--page-ghost-red-line));
  --ghost-red-hover: var(--chrome-red-hover, var(--page-ghost-red-hover));
  --ann-info-ink: var(--chrome-ann-info);
  --ann-warn-ink: var(--chrome-ann-warn);
  --ann-warn-bg: var(--chrome-ann-warn-bg);
  --ann-error-ink: var(--chrome-ann-error);
}
:is(.app-header, .app-footer, .pf-pageuh, .lobby-header-card)
  :is(.profile-dropdown, .volume-pop, .lang-dd-menu, .ann-pop, .modal-overlay-v2) {
  --heading: var(--page-heading);
  --text-main: var(--page-text-main);
  --parchment: var(--page-text-main);
  --text-dim: var(--page-text-dim);
  --smoke: var(--page-text-dim);
  --old-paper: var(--page-old-paper);
  --gold-ink: var(--page-gold-ink);
  --accent-strong: var(--page-accent-strong);
  --input-bg: var(--page-input-bg);
  --surface-1: var(--page-surface-1);
  --surface-1-strong: var(--page-surface-1-strong);
  --surface-2: var(--page-surface-2);
  --surface-hover: var(--page-surface-hover);
  --border-soft: var(--page-border-soft);
  --border-strong: var(--page-border-strong);
  --red-ink: var(--page-red-ink);
  --ghost-line: var(--page-ghost-line);
  --ghost-ink: var(--page-ghost-ink);
  --ghost-red-ink: var(--page-ghost-red-ink);
  --ghost-red-line: var(--page-ghost-red-line);
  --ghost-red-hover: var(--page-ghost-red-hover);
  --ann-info-ink: initial;
  --ann-warn-ink: initial;
  --ann-warn-bg: initial;
  --ann-error-ink: initial;
}
.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: 0.5rem; flex-wrap: wrap; justify-content: center; align-items: center; }
.card-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: 0.5rem; 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: 1rem 1.125rem;
  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; }
/* 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 row keeps its compact dimensions. */
.card-board .card-actions-bar {
  margin: 0.625rem -1.125rem -1rem; display: flex; align-items: center; justify-content: space-between;
  gap: 0.5rem 0.875rem; flex-wrap: wrap; padding: 0.75rem 1.125rem;
  /* 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: 0.5rem; flex: 1 1 220px; min-width: 0;
  font-size: 0.78125rem; color: var(--old-paper); line-height: 1.3;
}
.card-board .card-actions-bar .cab-status b { color: var(--parchment); font-weight: 600; }
/* May shrink, so its own flex-wrap takes effect on a narrow screen: with flex 0 0 auto the row
   kept both buttons side by side and pushed the page 40 px wide on a 375 px phone. */
.card-board .card-actions-bar .card-actions { margin: 0; flex: 0 1 auto; min-width: 0; }

/* ════ 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 { min-height: 0; margin: 0 auto; }
.card-board .break-stage, .card-board .card-break { background: none; border: none; box-shadow: none; }
.card-board .break-stage::before, .card-board .break-stage::after { display: none; }
/* 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; }

/* ════════════════════════════════════════════════════════════
   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: 1.25rem;
  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: var(--elev-2);
  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: 0.75rem;
  padding: 0.875rem 1.125rem;
  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: 1.0625rem;
  color: var(--heading);
  letter-spacing: .5px;
  flex: 1;
  display: flex;
  align-items: center;
  gap: 0.625rem;
  min-width: 0;
}
.modal-v2-title-icon {
  font-size: 1.375rem;
  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);
}
/* Element variant (IconContent, e.g. an avatar): a rendered box already sits
   centred in the line box, so it gets neither the emoji nudge nor the glyph
   font-size. */
.modal-v2-title-icon-el {
  flex-shrink: 0;
  display: flex;
  align-items: center;
}
.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;
}
/* Small technical addition after the title (e.g. record id). Body font on
   purpose: the Rye display face makes digits hard to read at this size. */
.modal-v2-title-suffix {
  flex-shrink: 0;
  font-family: var(--font-body);
  font-size: 0.75rem;
  font-weight: 400;
  color: var(--smoke);
  letter-spacing: 0;
}
.modal-v2-subtitle {
  font-size: 0.75rem;
  color: var(--smoke);
  font-style: italic;
  letter-spacing: 0;
  margin-top: 0.125rem;
}

.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: 0.875rem;
  font-family: inherit;
  flex-shrink: 0;
  transition: all .15s;
  padding: 0;
}
@media (hover: hover) {
  .modal-v2-close:hover {
    color: var(--heading);
    border-color: var(--gold);
    background: var(--surface-hover);
  }
}

.modal-v2-body {
  padding: 1.125rem 1.25rem;
  overflow-y: auto;
  flex: 1;
  min-height: 0;
}

.modal-v2-footer {
  display: flex;
  gap: 0.625rem;
  padding: 0.75rem 1.125rem;
  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: 0.75rem;
  padding: 0.75rem 0.875rem;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 4px;
  margin: 0.25rem 0 0.875rem;
}
.switch-lobby-code {
  font-family: 'Rye', cursive;
  font-size: 1.125rem;
  letter-spacing: .22em;
  color: var(--heading);
  background: var(--surface-1-strong);
  border: 1px solid var(--gold);
  padding: 0.3125rem 0.75rem;
  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: 0.75rem; margin-top: 0.125rem; }
.switch-role-chip {
  display: inline-block;
  font-size: 0.75rem;
  letter-spacing: .04em;
  padding: 0.0625rem 0.4375rem;
  border-radius: 10px;
  margin-left: 0.125rem;
  border: 1px solid rgba(200,146,42,.4);
  color: var(--heading);
}
.switch-host-note {
  display: flex;
  gap: 0.5rem;
  align-items: flex-start;
  font-size: 0.78125rem;
  color: var(--old-paper);
  background: rgba(139,26,26,.12);
  border-left: 2px solid var(--amber);
  padding: 0.5rem 0.6875rem;
  border-radius: 0 3px 3px 0;
}
.switch-host-note span:first-child { flex-shrink: 0; }
.hangman-word-card > *,
.tabu-word-display > *,
.tabu-reveal-word-card > *,
.mq-card > * { position: relative; z-index: 1; }

.stage-corner {
  position: absolute;
  font-size: 0.875rem;
  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: 1.25rem; border-radius: 8px; }
.team-logo-md { width: 64px; height: 64px; font-size: 1.875rem; }
.team-logo-lg { width: 88px; height: 88px; font-size: 2.75rem; }
/* 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: 0.625rem; flex-wrap: wrap; align-items: center; margin-bottom: 0.875rem; }
.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: 0.375rem;
  width: auto; flex: 0 0 auto; padding: 0.5625rem 1rem; font-size: 0.8125rem; 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;
}
@media (hover: hover) {
  .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(--heading); background: rgba(200,146,42,.05);
  }
}
.teams-list { display: flex; flex-direction: column; }
.team-row { display: flex; align-items: center; gap: 0.75rem; padding: 0.625rem 0.25rem; 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: 0.625rem; padding-right: 0.5rem; transition: background .12s ease; }
.row-clickable:focus-visible { background: rgba(200,146,42,.08); outline: none; }
@media (hover: hover) {
  .row-clickable:hover { 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: 1.125rem; 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(--heading);
}
@media (hover: hover) {
  .row-clickable:hover .row-chevron {
    opacity: .95;
    transform: translateX(2px);
    color: var(--heading);
  }
}
/* 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: 0.375rem; }
.team-row-main { flex: 1; min-width: 0; }
.team-row-name { color: var(--parchment); font-size: 0.875rem; }
.team-row-desc { color: var(--smoke); font-size: 0.75rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Team page (/Team/{id}) */
.team-hero { display: flex; gap: 1.125rem; align-items: flex-start; flex-wrap: wrap; }
.team-hero-main { flex: 1; min-width: 200px; }
.team-hero-name { font-size: 1.375rem; margin: 0; text-align: left; }
.team-hero-desc { margin: 0.25rem 0; }
.team-hero-meta { font-size: 0.75rem; }
.team-hero-actions { display: flex; align-items: center; }
.team-hero-note { font-size: 0.75rem; }
.team-sub { color: var(--heading); font-size: 0.75rem; letter-spacing: .04em; text-transform: uppercase; margin: 1rem 0 0.375rem; }
.team-sub-first { margin-top: 0; }
.team-stats-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0.625rem; }
@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: 0.75rem 0.625rem; text-align: center; }
.team-stat-val { display: block; font-family: 'Rye', cursive; color: var(--heading); font-size: 1.25rem; }
.team-stat-mode { font-size: 0.9375rem; }
.team-stat-lbl { display: block; color: var(--smoke); font-size: 0.75rem; margin-top: 0.1875rem; }
.team-members { display: flex; flex-direction: column; }
.team-member-row { display: flex; align-items: center; gap: 0.6875rem; padding: 0.5rem 0.25rem; 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: 0.6875rem; flex: 1; min-width: 0; color: inherit; text-decoration: none; border-radius: 6px; }
@media (hover: hover) {
  .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: 0.5rem; flex-wrap: wrap; }
.team-member-name { color: var(--parchment); font-size: 0.84375rem; }
.team-req-meta { font-size: 0.75rem; }
.team-member-actions { display: flex; gap: 0.4375rem; flex-shrink: 0; }
.team-role-badge { font-size: 0.75rem; letter-spacing: .03em; padding: 0.0625rem 0.5rem; 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: 1rem; background: rgba(200,146,42,.05); }
.team-admin-title { font-size: 0.875rem; }
.team-admin-actions { display: flex; gap: 0.625rem; flex-wrap: wrap; }

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

.team-back { margin-top: 0.625rem; }
.team-mine { display: flex; align-items: center; gap: 0.75rem; margin-bottom: 0.5rem; }
.team-mine-main { flex: 1; min-width: 0; }
.team-mine-name { color: var(--parchment); font-size: 0.875rem; }

/* Avatar section in the profile (preview + upload/remove) */
.avatar-edit         { display: flex; gap: 1.125rem; align-items: center; flex-wrap: wrap; }
.avatar-ring         { border: 2px solid rgba(200,146,42,.35); border-radius: 50%; padding: 0.1875rem; 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: 0.5rem; margin: 0.5rem 0 0.375rem; }
/* Compact inline buttons (overrides .btn base: full-width/Rye/large). */
.avatar-edit-actions .btn {
  width: auto; padding: 0.5rem 1rem; font-size: 0.75rem; letter-spacing: .06em;
  text-align: center; box-sizing: border-box; cursor: pointer;
}
.avatar-file-input   { display: none; }
.avatar-locked-note  {
  display: flex; gap: 0.5rem; align-items: flex-start;
  color: var(--smoke); font-size: 0.78125rem;
  background: rgba(200,146,42,.07); border: 1px solid rgba(200,146,42,.18);
  border-radius: 4px; padding: 0.625rem 0.75rem; 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: 0.625rem; margin: 0.875rem 0.125rem 0.125rem; color: var(--smoke); font-size: 0.8125rem; }
.zoom-row input[type=range] { flex: 1; accent-color: var(--gold); }
.crop-hint { display: block; text-align: center; margin-top: 0.375rem; }

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

/* 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(--old-paper);   /* --smoke: 3.7 to 4.5 : 1 on the poster in the light themes */
  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;
}
/* The row of whoever is to move is tinted with the mode colour: the mode ink on it measured
   3.9 to 4.3 : 1 (6.8 in the high-contrast theme). Name and points take the heading ink there. */
.wanted-poster .wanted-row.active :is(.sidebar-player-name-me, .sidebar-player-status) { color: var(--heading); }
[data-scheme="light"] .wanted-poster .wanted-row.active :is(.sidebar-player-name-me, .sidebar-player-status) { color: var(--text-main); }
@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); }
}
@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: 0.875rem;
  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(0.75rem, 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: .28; mix-blend-mode: overlay;
}

/* ── Saloon scene behind the page ──────────────────────────────────────────
   The bar seen from the room: back bars with bottles, batwing doors, two hanging
   lamps, the counter with its foot rail. Fixed, behind all app content, and drawn
   as inline SVG (SaloonBackdrop.razor) so every design paints it in its own colours:
     --scene-ink   shapes and lines        --scene-glow  light and brass
     page colour   cut-outs                --silhouette-opacity  overall strength
   Depth comes from the group opacities inside the drawing, not from colours. */
.saloon-bg {
  position: fixed;
  inset: 0;
  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: var(--silhouette-opacity, .85);
  /* 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%);
}
.saloon-bg > svg { display: block; width: 100%; height: 100%; }
.saloon-bg .scene-ink   { fill: var(--scene-ink, #c8922a); }
.saloon-bg .scene-line  { fill: none; stroke: var(--scene-ink, #c8922a); }
.saloon-bg .scene-glow  { fill: var(--scene-glow, #f3c66c); }
.saloon-bg .scene-stop  { stop-color: var(--scene-glow, #f3c66c); }
.saloon-bg .scene-page  { fill: var(--surface-0-c); }
/* On paper the page ground is white and the panels lose their fill: the scene and the
   decoration would print behind the text of every sheet. */
@media print { .saloon-bg, .saloon-deco, .deco-layer { display: none; } }

/* ── Seasonal decoration (themes with HasDeco) ──────────────────────────────
   .saloon-deco: second fixed layer with the theme's overlay SVG (pumpkins/webs or
   tree/wreath/lights), same fit + mask as .saloon-bg, with its own opacity. The overlay
   sits on anchor points of the scene (shelves, counter, door arch).
   .deco-layer: the MOVING elements (snowflakes / spider + bats), fixed, below the
   content (z-index -1 like the scene, later in the DOM = painted above it),
   pointer-events none. Panels are opaque, so the layer only shows on the page ground.
   Shown per html[data-theme]; html[data-deco="off"] (header control) and
   prefers-reduced-motion stop the motion. Only transform/opacity animate. */
.saloon-deco {
  position: fixed; inset: 0; z-index: -1; pointer-events: none;
  background: var(--deco-image, none) center bottom / cover no-repeat;
  opacity: var(--deco-opacity, 0);
  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%);
}
.deco-layer { position: fixed; inset: 0; z-index: -1; pointer-events: none; overflow: hidden; }
.deco-layer > div { display: none; }
[data-theme="halloween"] .deco-layer .deco-hw,
[data-theme="christmas"] .deco-layer .deco-xmas,
[data-theme="easter"] .deco-layer .deco-easter { display: block; }
html[data-deco="off"] .deco-layer { display: none; }
.deco-flake {
  position: absolute; top: -12px; width: var(--s, 6px); height: var(--s, 6px); border-radius: 50%;
  background: var(--deco-flake, #eadfc6); opacity: var(--o, .8);
  box-shadow: 0 0 6px rgba(255, 255, 255, .35);
  animation: decoFall var(--d, 12s) linear infinite; animation-delay: var(--dl, 0s);
}
@keyframes decoFall {
  0%   { transform: translate3d(0, -20px, 0); }
  25%  { transform: translate3d(14px, 25vh, 0); }
  50%  { transform: translate3d(-10px, 50vh, 0); }
  75%  { transform: translate3d(12px, 75vh, 0); }
  100% { transform: translate3d(-6px, 105vh, 0); }
}
.deco-spider {
  position: absolute; left: 7%; top: 0; width: 2px; height: 230px; transform-origin: top center;
  background: linear-gradient(to bottom, transparent 0, rgba(234, 220, 203, .35) 60px, rgba(234, 220, 203, .35) 100%);
  animation: decoDangle 7s ease-in-out infinite alternate;
}
.deco-spider::after {
  content: ''; position: absolute; left: 50%; bottom: -10px; width: 18px; height: 14px; margin-left: -9px; border-radius: 50%;
  background: #2a1731;
  box-shadow: 0 0 0 1px rgba(240, 147, 43, .35), -9px -2px 0 -4px #2a1731, 9px -2px 0 -4px #2a1731,
              -11px 4px 0 -5px #2a1731, 11px 4px 0 -5px #2a1731, -10px 9px 0 -5px #2a1731, 10px 9px 0 -5px #2a1731;
}
@keyframes decoDangle { from { transform: scaleY(.55) rotate(-2deg); } to { transform: scaleY(1) rotate(2deg); } }
.deco-bat {
  position: absolute; top: var(--t, 30%); left: -60px; width: 44px; height: 20px; opacity: .55;
  animation: decoFly var(--d, 34s) linear infinite; animation-delay: var(--dl, 0s);
}
.deco-bat-sm { width: 30px; height: 14px; }
.deco-bat svg { width: 100%; height: 100%; fill: #1a0f22; filter: drop-shadow(0 0 1px rgba(240, 147, 43, .4)); animation: decoFlap .5s ease-in-out infinite alternate; transform-origin: center; }
@keyframes decoFly { from { transform: translate3d(0, 0, 0); } 50% { transform: translate3d(50vw, -30px, 0); } to { transform: translate3d(110vw, 10px, 0); } }
@keyframes decoFlap { from { transform: scaleY(.6); } to { transform: scaleY(1); } }
/* Easter: petals tumble down slowly, two butterflies flutter across. */
.deco-petal {
  position: absolute; top: -14px; width: var(--s, 10px); height: calc(var(--s, 10px) * .62);
  border-radius: 60% 60% 60% 60% / 80% 80% 40% 40%; background: var(--c, #f4a6c0); opacity: var(--o, .75);
  animation: decoDrift var(--d, 16s) linear infinite; animation-delay: var(--dl, 0s);
}
@keyframes decoDrift {
  0%   { transform: translate3d(0, -20px, 0) rotate(0deg); }
  25%  { transform: translate3d(22px, 25vh, 0) rotate(120deg); }
  50%  { transform: translate3d(-14px, 50vh, 0) rotate(240deg); }
  75%  { transform: translate3d(18px, 75vh, 0) rotate(360deg); }
  100% { transform: translate3d(-8px, 105vh, 0) rotate(480deg); }
}
.deco-butterfly {
  position: absolute; top: var(--t, 30%); left: -60px; width: 34px; height: 24px; opacity: .8;
  animation: decoFlutter var(--d, 40s) linear infinite; animation-delay: var(--dl, 0s);
}
.deco-butterfly-sm { width: 26px; height: 18px; }
.deco-butterfly svg { width: 100%; height: 100%; animation: decoWings .35s ease-in-out infinite alternate; transform-origin: center; }
@keyframes decoFlutter { 0% { transform: translate3d(0, 0, 0); } 25% { transform: translate3d(28vw, -40px, 0); } 50% { transform: translate3d(55vw, 10px, 0); } 75% { transform: translate3d(82vw, -30px, 0); } 100% { transform: translate3d(110vw, 0, 0); } }
@keyframes decoWings { from { transform: scaleX(.35); } to { transform: scaleX(1); } }
@media (prefers-reduced-motion: reduce) {
  .deco-flake, .deco-spider, .deco-bat, .deco-bat svg, .deco-petal, .deco-butterfly, .deco-butterfly svg { animation: none; }
  .deco-flake, .deco-petal { top: calc(20% + var(--o, .5) * 60%); }   /* resting dots instead of falling ones */
}
/* Brand badge + spotlight star: seasonal glyphs per theme (decorative, aria-hidden). */
.app-header-season { display: none; font-size: 1rem; line-height: 1; margin-left: 0.25rem; }
[data-theme="halloween"] .app-header-season, [data-theme="christmas"] .app-header-season, [data-theme="easter"] .app-header-season { display: inline; }
[data-theme="halloween"] .app-header-season::before { content: '🎃'; }
[data-theme="christmas"] .app-header-season::before { content: '🎄'; }
[data-theme="easter"] .app-header-season::before { content: '🐰'; }
.pg-spotlight-star::before { content: '★'; }
[data-theme="halloween"] .pg-spotlight-star::before { content: '🕸'; }
[data-theme="christmas"] .pg-spotlight-star::before { content: '❄'; }
[data-theme="easter"] .pg-spotlight-star::before { content: '🥚'; }
/* Header control for the decoration layer: same chrome as .theme-btn; glyph per theme. */
.deco-btn-glyph::before { content: '✨'; }
[data-theme="halloween"] .deco-btn-glyph::before { content: '🕷'; }
[data-theme="christmas"] .deco-btn-glyph::before { content: '❄'; }
[data-theme="easter"] .deco-btn-glyph::before { content: '🐰'; }
.deco-btn[aria-pressed="false"] .deco-btn-glyph { opacity: .45; filter: grayscale(1); }
[data-scheme="light"] .bg-saloon {
  background: radial-gradient(ellipse 90% 55% at 50% 100%, rgba(156, 106, 26, .12) 0%, transparent 65%);
}
/* §8 part 2 (dark page canvas behind game screens) — DISMANTLED in
   light-theme stage 2: in the light theme game pages now run on the same
   bright canvas as every other page. */

/* ── 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;
}

.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-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: 0.875rem; letter-spacing: .3em; text-transform: uppercase;
  color: var(--smoke); text-align: center; margin-bottom: 0.875rem;
}
.section-label {
  font-size: 0.875rem; letter-spacing: .18em; text-transform: uppercase;
  color: var(--smoke); margin-bottom: 0.625rem;
}

/* ── Cards ── */
.card {
  background: linear-gradient(135deg, var(--card-grad-a), var(--card-grad-b));
  border: 1px solid var(--border-soft); border-radius: 2px;
  padding: 1.5rem 1.75rem; position: relative;
  box-shadow: 0 18px 55px var(--shadow-color), inset 0 1px 0 rgba(200,146,42,.09);
}
/* Ornament only: it sits on top of the card's content and, in the narrow game header, right
   over the ✕ button — without pointer-events: none it swallowed the tap on the button's middle. */
.card::before,
.card::after {
  content: '✦'; position: absolute; top: 13px;
  color: rgba(200,146,42,.25); font-size: 0.75rem;
  pointer-events: none;
}
.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: 1.0625rem; color: var(--heading);
  text-align: center; margin-bottom: 1.25rem; letter-spacing: .09em;
}

/* ── Forms ── */
.lbl {
  font-size: 0.875rem; letter-spacing: .16em; text-transform: uppercase;
  color: var(--smoke); display: block; margin-bottom: 0.4375rem;
}
.inp {
  width: 100%; background: var(--input-bg);
  border: 1px solid var(--border-soft); border-radius: 1px;
  color: var(--text-main);
  font-size: 0.9375rem; padding: 0.6875rem 0.8125rem; 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); }
.fgrp { margin-bottom: 1rem; }
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: 1.875rem;
}
textarea.inp { resize: vertical; min-height: 100px; font-size: 0.875rem; line-height: 1.6; }

/* ── 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: 0.75rem; border-radius: 1px;
  font-family: 'Rye', cursive; font-size: 0.9375rem; 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; }

/* The start colour has its own hook: a theme whose --amber is too dark for the dark ink
   (Christmas, Halloween) lightens the button alone, not every other use of --amber.
   End, ink and glow have optional hooks too (a theme with a dark primary button and light ink). */
.btn-gold { background: linear-gradient(135deg, var(--btn-gold-start, var(--amber)), var(--btn-gold-end, var(--gold))); color: var(--btn-gold-ink, var(--shadow)); box-shadow: var(--btn-gold-glow, 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: var(--raw-cream); 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, var(--red-fill-a, #8b1a1a), var(--red-fill-b, #5a0e0e)); color: var(--raw-cream); box-shadow: 0 4px 22px rgba(139,26,26,.38); border: 1px solid rgba(220,100,100,.5); padding: 0.625rem 1.125rem; 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);
  }
}
/* --raw-cream, not --parchment: the felt gradient stays dark, while --parchment follows
   --text-main and turned dark brown in the light theme (~1.2:1 on the felt end). */
.btn-green { background: linear-gradient(135deg, var(--green-felt), var(--green-ok)); color: var(--raw-cream); }
@media (hover: hover) {
  .btn-green:not(:disabled):hover {
    transform: translateY(-1px);
  }
}
.btn-ghost { background: transparent; border: 1px solid var(--ghost-line, rgba(200,146,42,.32)); color: var(--ghost-ink, var(--old-paper)); font-size: 0.9375rem; letter-spacing: .08em; }
@media (hover: hover) {
  .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: 0.9375rem; padding: 0.625rem 1.125rem; border-radius: 3px; cursor: pointer; transition: all .15s; }
@media (hover: hover) {
  .btn-ghost-red:hover { background: rgba(139,26,26,.18); border-color: rgba(220,100,100,.6); color: var(--red-ink); }
}

/* ── Dividers ── */
.div-line { display: flex; align-items: center; gap: 0.625rem; margin: 1rem 0; }
.div-line::before,
.div-line::after { content: ''; flex: 1; height: 1px; background: rgba(200,146,42,.18); }
.div-line span { font-size: 0.75rem; letter-spacing: .22em; color: var(--smoke); }

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

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

/* ── 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: 0.375rem;
  padding: 0;
  background: transparent;
  border: 1px solid rgba(200,146,42,.35);
  border-radius: 50%;
  color: var(--gold);
  font-size: 0.875rem;
  cursor: pointer;
  vertical-align: middle;
  transition: background .15s, border-color .15s;
  position: relative;
}
@media (hover: hover) {
  .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: 1.0625rem; color: var(--parchment); }

/* ── Player progress bar ── */
.player-progress { width: 100%; margin: 0.625rem 0 0.875rem; }
.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: 0.3125rem; font-size: 0.875rem; color: var(--smoke); }
.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: 1rem 1.5rem; width: 100%; text-align: center; border-radius: 2px; }
.reveal-box.red { border-color: rgba(139,26,26,.35); }
.rl { font-size: 0.75rem; letter-spacing: .28em; text-transform: uppercase; color: var(--smoke); margin-bottom: 0.4375rem; }
.rv { font-family: 'Rye', cursive; font-size: 1.5rem; color: var(--heading); }
.rv.red { color: var(--blood-red); }
.rsub { font-size: 0.9375rem; color: var(--smoke); margin-top: 0.25rem; }

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

/* ── Toasts / Alerts ── */
.toast { box-shadow: var(--elev-2); padding: 0.625rem 0.875rem; border-radius: 1px; font-size: 0.9375rem; border-left: 3px solid; display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.5rem; 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-scheme="light"] .toast-abort { color: var(--danger-strong); }   /* like .alert-error: --danger drops below 4.5 on the pink wash */

/* 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); }
.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: 0.5625rem 0.75rem; border-radius: 1px; font-size: 0.9375rem; margin-bottom: 0.625rem; }
/* Light: --danger on the pink-tinted alert bg lands at ~2.5:1 — take the strong tone for text. */
[data-scheme="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: 0.5rem; align-items: flex-start; background: rgba(70,110,160,.1); border: 1px solid rgba(120,150,200,.3); border-radius: 4px; padding: 0.625rem 0.75rem; margin-bottom: 0.875rem; font-size: 0.78125rem; color: var(--text-main); line-height: 1.45; }

/* ── Lock page (/banned) and the reduced header of a locked account ──
   The status box takes the surface and border of .alert-error; the card is as wide as the
   setup card. */
.card-auth.card-banned { max-width: 480px; }
.card-banned .profile-section { margin-bottom: 0.75rem; }
.ban-box {
  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); border-radius: 1px;
  padding: 0.625rem 0.75rem; margin-bottom: 0.875rem;
  color: var(--danger); font-size: 0.9375rem; line-height: 1.45;
}
[data-scheme="light"] .ban-box { color: var(--danger-strong); }
.ban-box .ban-line { font-weight: 600; }
.ban-box .ban-reason { margin-top: 0.25rem; font-size: 0.875rem; overflow-wrap: anywhere; }
.ban-box .ban-reason i { font-weight: 400; }
.ban-intro { font-size: 0.875rem; line-height: 1.55; margin-bottom: 1rem; }
.auth-footer b { color: var(--text-main); font-weight: 600; }
.hdr-logout {
  height: 38px; padding: 0 0.875rem; border-radius: 19px; cursor: pointer; white-space: nowrap;
  display: inline-flex; align-items: center; gap: 0.375rem;
  /* same tokens as .theme-btn beside it — the header maps them onto its own surface */
  background: var(--surface-1); border: 1px solid var(--border-strong);
  color: var(--heading); font: 500 0.8125rem 'Inter', system-ui, sans-serif;
}
.hdr-logout:focus-visible { outline: 2px solid var(--heading); outline-offset: 2px; }
.volume-control.is-hidden { display: none; }
@media (max-width: 360px) { .hdr-logout-text { display: none; } }

/* ── Banners ── */
.waiting-banner { font-size: 1rem; letter-spacing: .07em; color: var(--text-main); text-align: center; padding: 0.75rem; border: 1px dashed var(--border-soft); border-radius: 1px; margin-bottom: 0.875rem; 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: 0.5rem;
  height: 30px; padding: 0 0.5rem 0 0.6875rem;
  border-radius: 16px; font-size: 0.75rem; 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: 0.125rem; font-size: 0.75rem; padding: 0.1875rem 0.5625rem;
  border-radius: 12px; border: 1px solid rgba(200,146,42,.4);
  background: rgba(200,146,42,.16); color: var(--heading);
  cursor: pointer; white-space: nowrap; font-family: inherit;
}
@media (hover: hover) {
  #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: 0.625rem; padding: 0.6875rem 0.8125rem; margin: 0.5rem 0 0.25rem;
  background: rgba(200,146,42,.08); border: 1px solid rgba(200,146,42,.28);
  border-radius: 6px; color: var(--text-dim); font-size: 0.8125rem;
}
.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; }
@keyframes eyeGlow { 0%,100% { opacity: 1; } 50% { opacity: .3; } }
@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)); } }
@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)); }
}   /* The plaque covers the card edge - light ground in the light theme */

/* ── Layouts ── */
.lobby-header {
  text-align: center;
  margin-bottom: 0.875rem;
  width: 100%;
  max-width: 1000px;
}
.lobby-header-card {
  padding: 0.875rem 1.375rem;
  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: 1rem;
  margin-top: 0.625rem;
  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: 1rem;
                    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: 1rem;
  align-items: start;
}
.lobby-chat-col {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  min-width: 0; /* allows the column to shrink, otherwise chat content pushes the grid */
}
.lobby-sidebar-col {
  display: flex;
  flex-direction: column;
  gap: 0.8125rem;
}

/* 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: 0.8125rem; }
.lobby-players-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.625rem; }

.game-sidebar { display: flex; flex-direction: column; gap: 0.75rem; }

/* ── Loading & misc ── */
.loading-screen { flex: 1 0 auto; display: flex; align-items: center; justify-content: center; }
.not-found { text-align: center; padding: 3.75rem 1.25rem; }
.not-found h2 { font-size: 1.75rem; color: var(--heading); margin-bottom: 1rem; }
.not-found a { color: var(--old-paper); text-decoration: underline; }

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

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

.card-players { padding: 1.25rem 1.375rem; }
.card-sidebar { padding: 1rem 1.125rem; }

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

.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: 0.9375rem; color: var(--smoke); line-height: 2.2; }
.settings-row { display: flex; justify-content: space-between; gap: 0.75rem; align-items: baseline; }
.settings-value { color: var(--accent-ink); text-align: right;
                        min-width: 0; overflow-wrap: anywhere; }
.settings-fixed-note { font-size: 0.875rem; color: rgba(168, 151, 132,.5);
                        margin-top: 0.5rem; font-style: italic; }
.btn-edit { margin-top: 0.625rem; padding: 0.4375rem; font-size: 0.875rem; 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: 0.5rem;
}
.player-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  background: rgba(8,5,2,.5);
  border: 1px solid rgba(200,146,42,.18);
  color: var(--parchment);
  padding: 0.3125rem 0.75rem 0.3125rem 0.3125rem;
  border-radius: 22px;
  font-size: 0.8125rem;
  cursor: pointer;
  transition: border-color .15s, background .15s, transform .12s;
}
@media (hover: hover) {
  .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: 0.8125rem;
  max-width: 140px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.player-chip-badge {
  font-size: 0.875rem;
  line-height: 1;
  margin-left: -0.125rem;
}
/* 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: 0.5625rem; }
.verified-check.vc-md { width: 17px; height: 17px; font-size: 0.625rem; }
.verified-check.vc-lg { width: 21px; height: 21px; font-size: 0.75rem; }
.player-chip-you {
  background: rgba(45,122,74,.2);
  color: var(--green-ok);
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: .1em;
  padding: 0.0625rem 0.375rem;
  border-radius: 10px;
  margin-left: 0.125rem;
}
.player-chip-empty {
  display: inline-flex;
  align-items: center;
  padding: 0.3125rem 0.875rem;
  border: 1px dashed rgba(168, 151, 132,.3);
  color: var(--smoke);
  font-size: 0.75rem;
  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; }
/* 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: 1.125rem 1.25rem; margin-bottom: 0.75rem; }
.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(--red-ink); }
.round-total { font-size: 1rem; color: var(--old-paper); }
.card-break { max-width: 400px; width: 100%; margin: 0 auto; }
.section-label-mb { margin-bottom: 0.5rem; }
.card-clues-sidebar { padding: 0.875rem 1.125rem; max-width: 220px; }
.card-guess { padding: 1.375rem 1.625rem; }
.btn-vote { max-width: 260px; margin-top: 0.875rem; }
.reveal-stack { display: flex; flex-direction: column; gap: 0.625rem; align-items: center;
                          width: 100%; max-width: 460px; margin-bottom: 0.875rem; }
.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-mission-title { font-size: 13px; margin-bottom: 5px; }
.screen-game.bg-red .impostor-category { padding: 8px 16px; margin-bottom: 10px; }

/* ── End screen game history ─────────────────────────────────────────────── */
.history-card {
  width: 100%;
  max-width: 480px;
  padding: 1rem 1.25rem;
  margin-bottom: 0.875rem;
}
.history-title {
  font-family: 'Rye', cursive;
  font-size: 0.875rem;
  color: var(--gold-ink);
  letter-spacing: .08em;
  margin-bottom: 0.75rem;
  text-align: center;
}
.history-clue-row,
.history-vote-row {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  padding: 0.4375rem 0;
  border-bottom: 1px solid var(--border-faint);
  font-size: 0.875rem;
}
.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; }

/* ── 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 1.5rem;
}
/* Visibility badge for non-public game modes (ModeVisibilityBadge): "inaktiv" (admins +
   testers) in gold, "deaktiviert" (admins only) in grey. The tint sits on an opaque surface
   so the text keeps its contrast on top of the colourful poster art. Placement per container
   below (poster tile, spotlight tag, game-switch dropdown). */
.mode-vis-badge {
  display: inline-block;
  font-size: 0.75rem;
  font-weight: 400;
  letter-spacing: .04em;
  text-transform: none;
  line-height: 1.4;
  white-space: nowrap;
  border: 1px solid;
  border-radius: 3px;
  padding: 0.0625rem 0.375rem;
}
/* Both badges carry the body ink: the gold and the grey ink fell below 4.5:1 on their tinted
   ground in several dark themes. Gold and grey stay readable through ground and edge. */
.mode-vis-badge.inactive {
  color: var(--text-main);
  background: linear-gradient(rgba(200,146,42,.16), rgba(200,146,42,.16)), var(--surface-1-strong);
  border-color: rgba(200,146,42,.55);
}
.mode-vis-badge.off {
  color: var(--text-main);
  background: linear-gradient(rgba(168,151,132,.14), rgba(168,151,132,.14)), var(--surface-1-strong);
  border-color: rgba(168,151,132,.45);
}
/* Inside a variant pill (Seeschlacht → Raumschlacht) the badge follows the label, not glued to it. */
.quiz-pill .mode-vis-badge { margin-left: 6px; }
.rsplit-item .mode-vis-badge { margin-left: auto; }
.pg-spotlight-tag .mode-vis-badge { margin-left: 0.5rem; vertical-align: 1px; }
/* "nur Admins" on the own-word-list switch while it is not released yet (same grey badge). */
.spielvariante-name .mode-vis-badge { margin-left: 0.5rem; vertical-align: 1px; }
/* Profile card of a mode feature (question sets): beside the Rye heading, in body type. */
.profile-section-title .mode-vis-badge { margin-left: 0.5rem; vertical-align: 2px; font-family: var(--font-body); }
.mode-switch-off {
  margin-left: auto;
  font-size: 0.75rem;
  color: #e88;
  border: 1px solid rgba(163,50,74,.5);
  border-radius: 3px;
  padding: 0 0.3125rem;
}

/* ── JoinLobbyDialog (Modal Specifics) ───────────────────────────────────── */
.join-dialog {
  max-width: 540px;
}
.join-dialog-loading {
  text-align: center;
  padding: 1.875rem;
  color: var(--smoke);
  font-style: italic;
}
.join-dialog-info {
  margin-bottom: 1.125rem;
}
.join-dialog-mode {
  display: flex;
  gap: 0.875rem;
  align-items: flex-start;
  padding: 0.875rem;
  background: rgba(200,146,42,.06);
  border: 1px solid rgba(200,146,42,.22);
  border-radius: 4px;
  margin-bottom: 0.75rem;
}
.join-dialog-mode-icon {
  font-size: 2rem;
  line-height: 1;
  flex-shrink: 0;
}
.join-dialog-mode-name {
  font-family: 'Rye', cursive;
  font-size: 1.0625rem;
  color: var(--gold);
  margin: 0 0 0.375rem 0;
}
.join-dialog-mode-desc {
  color: var(--parchment);
  font-size: 0.8125rem;
  margin: 0;
  line-height: 1.5;
}
.join-dialog-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.375rem 1.125rem;
  font-size: 0.875rem;
  color: var(--smoke);
  margin-bottom: 0.75rem;
}
.join-dialog-meta strong {
  color: var(--heading);
}
/* "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: 0.875rem;
  margin: 0 0 0.875rem 0;
}
.join-dialog-as-user strong {
  color: var(--heading);
}
.join-dialog-section {
  padding: 0.875rem 0;
}
.join-dialog-section-title {
  font-size: 0.875rem;
  color: var(--heading);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  margin: 0 0 0.625rem 0;
}
.join-dialog-auth-actions {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}
.join-dialog-account-required {
  margin-bottom: 0.875rem;
}

/* 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: 0.5rem;
}
.join-dialog-footer-links {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.75rem 1.125rem;
  margin-top: 0.625rem;
  font-size: 0.75rem;
}
.join-dialog-footer-links a {
  color: var(--gold);
  text-decoration: none;
}
@media (hover: hover) {
  .join-dialog-footer-links a:hover {
    color: var(--heading);
  }
}

/* ── Join page (/Join/{code}) — auto-join interstitial + waiting room ─────── */
.join-switch-note { font-size: 0.78125rem; color: var(--smoke); margin: 0.375rem 0 0.125rem; }

.ji-auto, .ji-wait {
  display: flex; flex-direction: column; align-items: center;
  text-align: center; gap: 0.5625rem; padding: 1.375rem 0.875rem; margin-top: 0.25rem;
  background: rgba(8,5,2,.4);
  border: 1px solid var(--border);
  border-radius: 6px;
}
.ji-h {
  font-family: 'Rye', cursive; font-size: 1.125rem; color: var(--accent-light);
  display: flex; align-items: center; gap: 0.625rem;
}
.ji-s { font-size: 0.8125rem; color: var(--parchment); max-width: 460px; line-height: 1.55; }
.ji-f { font-size: 0.78125rem; color: var(--smoke); margin-top: 0.125rem; }

.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; }
  /* Duel table: the table takes the arena height, the chairs keep theirs. */
  body.ss-maximized .duel-scene { flex: 1 1 auto; min-height: 0; }
  body.ss-maximized .duel-table { flex: 1 1 auto; height: auto; min-height: var(--th); }
  /* Arcade cabinet: board, cabinet and notice board take the panel height; the screen gets
     the rest inside the cabinet and scrolls should a full lobby not fit. */
  body.ss-maximized .lobby-arcade { padding: 18px 24px; }
  body.ss-maximized .arc-lobby { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
  body.ss-maximized .arc-lobby-grid { flex: 1 1 auto; min-height: 0; grid-template-rows: minmax(0, 1fr); }
  body.ss-maximized .cab { min-height: 0; }
  body.ss-maximized .cab-body { flex: 1 1 auto; min-height: 0; }
  body.ss-maximized .cab-bezel { flex: 1 1 auto; min-height: 0; display: flex; }
  body.ss-maximized .cab-screen { flex: 1 1 auto; min-height: 0; overflow: auto; padding: 16px 20px; }
  @container (min-width: 860px) {
    body.ss-maximized .cab-title { font-size: 34px; }
    body.ss-maximized .cab-slots { gap: 7px; margin-top: 14px; }
    body.ss-maximized .cab-slot { min-height: 40px; padding: 6px 12px; font-size: 15px; }
  }
  /* 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;
  }
  /* Atmosphere for the full-screen board, which otherwise is one large, nearly flat
     gradient around a centred game. Painted as extra BACKGROUND LAYERS of the board
     itself (top to bottom: centre light, darker edges, accent wash from the header and
     the bottom edge, wood grain, base gradient) — no pseudo-elements and no new stacking
     context, so fixed overlays inside the board keep their z-index against the app
     header. Game surfaces with their own backdrop (felt, water, board artwork) sit on
     top and stay untouched.
     Grain: horizontal fractal noise, white, alpha pre-scaled, blended soft-light. The
     filter region is set to exactly the tile and the tile is STRETCHED to the board width
     (not repeated) — with the default filter region the tile edges do not stitch and a
     hard vertical seam appears every tile width.
     Watermark: the mode emblem, burnt in twice in the empty corners (large bottom left,
     smaller top right), below the grain so the wood texture runs through it. The page sets
     the four data URIs inline (BoardEmblemStyle, from the mode metadata); the scheme picks
     its pair here, so a theme switch needs no re-render. Ink and strength are baked into
     the SVG: black under light text, white under dark text — the line can only ever add
     contrast. Offsets include the 20-unit air of the 280-unit view box. */
  body.ss-maximized .screen-game.lobby-redesign > .card-board {
    --board-mark-bl: var(--board-mark-dark-bl, none);
    --board-mark-tr: var(--board-mark-dark-tr, none);
    background:
      radial-gradient(38% 46% at 50% 48%, var(--board-spot), transparent 100%),
      radial-gradient(120% 120% at 50% 48%, transparent 50%, var(--board-edge) 100%),
      linear-gradient(180deg, color-mix(in srgb, var(--accent) var(--board-wash), transparent) 0%, transparent 32%),
      linear-gradient(0deg, color-mix(in srgb, var(--accent) calc(var(--board-wash) * .6), transparent) 0%, transparent 22%),
      url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='1600' height='240' viewBox='0 0 1600 240' preserveAspectRatio='none'%3E%3Cfilter id='g' x='0' y='0' width='100%25' height='100%25' filterUnits='userSpaceOnUse'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.005 0.125' numOctaves='3' seed='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 1  0 0 0 0 1  0 0 0 0 1  0 0 0 0.234 -0.063'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23g)'/%3E%3C/svg%3E") 0 0 / 100% 240px repeat-y,
      var(--board-mark-tr) right -66px top -69px / min(35%, 373px) auto no-repeat,
      var(--board-mark-bl) left -74px bottom -84px / min(47%, 490px) auto no-repeat,
      linear-gradient(135deg, var(--board-grad-a), var(--board-grad-b));
    background-blend-mode: normal, normal, normal, normal, soft-light, normal, normal, normal;
  }
  [data-scheme="light"] body.ss-maximized .screen-game.lobby-redesign > .card-board {
    --board-mark-bl: var(--board-mark-light-bl, none);
    --board-mark-tr: var(--board-mark-light-tr, none);
  }
  /* The framed game panels inside the board (quiz card, Hangman/Tabu word card, Memory
     board card) keep frame and shadow but let the board atmosphere show through at 45 %
     — otherwise they cover most of the board with the same flat gradient again.
     Worst case measured over the accent wash: secondary text 5.3:1, headings 6.0:1. */
  body.ss-maximized .screen-game.lobby-redesign > .card-board :is(.card.mq-card, .card.hangman-word-card, .card.memory-board-card) {
    background: linear-gradient(135deg,
      color-mix(in srgb, var(--board-grad-a) 55%, transparent),
      color-mix(in srgb, var(--board-grad-b) 55%, transparent));
  }
  /* 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 { 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-layout.memory-solo { grid-template-columns: minmax(0, 1fr); }
  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; }
  /* Card tables (.ct-table): table, seats and hand on the left, a 260px column on the right
     with the value card, the turn status and the actions — the footer bar is gone, so the
     table fits 900px of height again without scrolling. Height chain: the screen becomes a
     flex column, the table grid takes the rest, the felt the rest of the left column. */
  body.ss-maximized .card-board > .screen-game:has(> .ct-table) { display: flex; flex-direction: column; }
  body.ss-maximized .screen-game > .ct-table {
    flex: 1 1 auto; min-height: 0; display: grid; grid-template-columns: minmax(0, 1fr) 260px;
    grid-template-rows: minmax(0, 1fr); column-gap: 16px; align-items: stretch;
  }
  body.ss-maximized .ct-table { --card-w: 108px; --card-h: 152px; }   /* = maximized .durak-card (game-pieces.css) */
  body.ss-maximized .ct-table > .ct-main { display: flex; flex-direction: column; gap: 12px; min-width: 0; min-height: 0; }
  body.ss-maximized .ct-table > .ct-main > .durak-table { flex: 1 1 auto; min-height: 0; }
  body.ss-maximized .ct-table > .ct-side { display: flex; flex-direction: column; gap: 10px; min-height: 0; overflow-y: auto; }
  body.ss-maximized .ct-side .ct-vals {
    display: grid; grid-template-columns: auto 1fr; gap: 4px 12px; justify-content: stretch;
    padding: 14px 16px; border-radius: 12px; font-size: 14px;
  }
  body.ss-maximized .ct-side .ct-vals-title {
    display: block; grid-column: 1 / -1; margin-bottom: 4px;
    font-size: 12px; letter-spacing: .18em; text-transform: uppercase; color: var(--smoke);
  }
  body.ss-maximized .ct-side .ct-val { display: contents; }
  body.ss-maximized .ct-side .ct-val b { text-align: right; }
  body.ss-maximized .ct-side .ct-turn { justify-content: flex-start; padding: 12px 14px; border-radius: 10px; font-size: 14px; }
  body.ss-maximized .ct-side .ct-actions { flex-direction: column; flex-wrap: nowrap; align-items: stretch; }
  body.ss-maximized .ct-side .ct-actions .btn { width: 100%; min-height: 42px; }
  /* Poker: the raise sheet is always open in the side column — no toggle, no close. */
  body.ss-maximized .ct-side .pk-sheet { display: flex; order: 6; box-shadow: var(--elev-1); }
  body.ss-maximized .ct-side .pk-sheet-row { flex-direction: column; }
  /* Offiziersskat: the table panel keeps its content height — fitOsk models it (a growing
     felt would feed the fit its own output); the spare height centres the layout instead. */
  body.ss-maximized .osk-board > .ct-main { justify-content: center; }
  body.ss-maximized .osk-board > .ct-main > .osk-table { flex: 0 0 auto; }
  /* Real-time games (.arc-board): the field takes the height left beside the side cards and its
     size follows the canvas's aspect ratio (container units on .arc-field) — no fixed caps. */
  body.ss-maximized .card-board > .screen-game:has(> .arc-board) { display: flex; flex-direction: column; }
  body.ss-maximized .screen-game > .arc-board { flex: 1 1 auto; min-height: 0; }
  body.ss-maximized .arc-board > .arc-layout { flex: 1 1 auto; min-height: 0; grid-template-rows: minmax(0, 1fr); align-items: stretch; }
  body.ss-maximized .arc-layout > .arc-main { min-height: 0; }
  body.ss-maximized .arc-layout > .arc-side { min-height: 0; overflow-y: auto; }
  /* Beside the field (not on the one-column phone layout): the side cards start at the field's
     top edge and the columns hug it. The board is the size container; the field's height is
     the height left or the width left beside the side columns times the canvas's aspect ratio,
     whichever is smaller. The field column is exactly as wide as the field, the group is
     centred, and the side columns take half of the spare height as top padding.
     Mirrored values: --arc-sides is the side columns plus gaps of .arc-layout / .fg-layout in
     game.css (250 + 18, 170 + 250 + 2 × 18), --arc-ratio the canvas's height / width from the
     field width rules just below. Change both places together. */
  @media (min-width: 821px) {
    body.ss-maximized .screen-game > .arc-board { container-type: size; }
    body.ss-maximized .arc-board > .arc-layout { --arc-sides: 268px; --arc-ratio: 1;
      --arc-fh: min(100cqh, (100cqw - var(--arc-sides)) * var(--arc-ratio));
      grid-template-columns: calc(var(--arc-fh) / var(--arc-ratio)) 250px; justify-content: center; }
    body.ss-maximized .arc-board > .arc-layout:has(.sp-mine) { --arc-ratio: calc(21 / 19); }
    body.ss-maximized .arc-board > .arc-layout.fg-layout { --arc-sides: 456px; --arc-ratio: calc(18 / 11);
      grid-template-columns: 170px calc(var(--arc-fh) / var(--arc-ratio)) 250px; }
    body.ss-maximized .arc-layout > .arc-side { padding-top: calc((100cqh - var(--arc-fh)) / 2); }
  }
  body.ss-maximized .arc-main > .arc-field { flex: 1 1 auto; min-height: 0; container-type: size; display: grid; place-items: center; }
  body.ss-maximized .arc-field > .ks-yard { width: min(100cqw, 100cqh); }
  body.ss-maximized .arc-field > .sp-mine { width: min(100cqw, calc(100cqh * 19 / 21)); }
  body.ss-maximized .arc-field > .fg-shaft { width: min(100cqw, calc(100cqh * 11 / 18)); }
  body.ss-maximized .ct-side .pk-sheet-x,
  body.ss-maximized .ct-side .pk-raise-open { display: none; }

  /* 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-play { flex: 1 1 auto; min-height: 0; max-width: none; grid-template-rows: auto minmax(0, 1fr) auto; }
  body.ss-maximized .mode-uttt .uttt-board-area { height: 100%; min-height: 0; container-type: size; }
  body.ss-maximized .mode-uttt .uttt-frame { width: min(100cqw, 100cqh); max-width: none; }
  /* 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: 0.625rem 1.125rem;
  background: var(--chrome);
  backdrop-filter: blur(6px);
  border-bottom: 1px solid var(--border-soft);
  box-shadow: var(--elev-1);
}
/* 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: 0.75rem;
  min-width: 0;
  /* On the narrowest phones the group shrinks below its content (brand + lobby pill); clip it
     at its own edge instead of letting the pill paint under the announcement icon. The clip
     margin keeps focus rings visible. */
  overflow: clip;
  overflow-clip-margin: 4px;
}

/* 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: 0.3125rem 0.875rem;
  font-size: 0.8125rem;
}
.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: 0.8125rem;
}

/* 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: 0.9375rem; }
.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: 0.5rem 0.875rem;
  font-size: 0.78125rem;
  align-items: flex-start;
  box-shadow: none;
}
.announce-strip .ann-pop .announce-body { text-align: left; line-height: 1.4; }
/* Phones: centered under the 32px icon, the up-to-86vw popover ran off the left edge
   whenever the icon sat left of center (game page: the left group is just the brand).
   Unpositioning the icon wrapper makes the header the containing block, so the
   popover centers on the screen instead. */
@media (max-width: 760px) {
  .announce-strip.is-collapsed .ann-collapsed { position: static; }
  .announce-strip.is-collapsed { margin: 0 6px; }   /* breathing room between the pill and the actions */
}
.app-header-brand {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  text-decoration: none;
  color: var(--heading);
  font-family: 'Rye', cursive;
  font-size: 1rem;
  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));
}
/* Logo variant: dark tile in the dark scheme, parchment stamp in the light one. A light theme
   with a dark header (Light Saloon) keeps the dark tile via the --logo-* hooks. */
.logo-for-light { display: none; }
[data-scheme="light"] .logo-for-light { display: var(--logo-light-display, inline-block); }
[data-scheme="light"] .logo-for-dark { display: var(--logo-dark-display, none); }
[data-scheme="light"] .app-header-logo { filter: var(--logo-filter, none); }
.app-header-title {
  display: inline-block;
}
.app-header-actions {
  display: flex;
  align-items: center;
  gap: 0.625rem;
}

/* 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: 0.4375rem;
  height: 38px;
  padding: 0 0.875rem;
  background: rgba(139, 26, 26, .22);
  border: 1px solid var(--border-strong);
  color: var(--heading);
  border-radius: 19px;
  font-size: 0.8125rem;
  cursor: pointer;
  white-space: nowrap;
  transition: background .15s, border-color .15s;
}
@media (hover: hover) {
  .streamer-chip:hover {
    background: rgba(139, 26, 26, .34);
    border-color: var(--gold);
  }
}
[data-scheme="light"] .streamer-chip { background: rgba(139, 26, 26, .10); }
@media (hover: hover) {
  [data-scheme="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 0.6875rem; }
  .streamer-chip::before { content: '🎥'; font-size: 0.875rem; }
}

/* ── 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: 0.5rem;
}
.auth-btn {
  display: inline-flex;
  align-items: center;
  height: 38px;
  padding: 0 1rem;
  border-radius: 6px;
  font-size: 0.8125rem;
  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);
}
@media (hover: hover) {
  .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);
}
@media (hover: hover) {
  .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: 0.5rem;
  margin-left: 0.875rem;
  margin-right: auto;     /* pushes the header-actions block further to the right */
  padding: 0.3125rem 0.75rem 0.3125rem 0.5rem;
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  border-radius: 18px;
  color: var(--heading);
  font-size: 0.8125rem;
  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;
}
@media (hover: hover) {
  .nav-lobby-pill:hover {
    background: rgba(200,146,42,.18);
    border-color: var(--gold);
    animation-play-state: paused;
  }
}
.nav-lobby-pill-icon {
  font-size: 1rem;
  line-height: 1;
}
.nav-lobby-pill-text {
  display: inline-flex;
  align-items: baseline;
  gap: 0.375rem;
  min-width: 0;
}
/* The mode name gives way first on a narrow header (the brand, the announcement icon and the
   actions do not shrink) — without it the pill kept its full width and slid under the
   announcement icon on a 390px phone. The count stays. */
.nav-lobby-pill { min-width: 0; overflow: hidden; }   /* clip rather than paint under the announcement icon */
.nav-lobby-pill-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nav-lobby-pill-count { flex: 0 0 auto; }
.nav-lobby-pill-count {
  color: var(--smoke);
  font-size: 0.75rem;
}
@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);
}
@media (hover: hover) {
  .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: 0.75rem;
  padding: 0.625rem 0.875rem 0.625rem 1rem;
  margin: 0.875rem 1rem 0 1rem;
  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: 0.875rem;
  max-width: 480px;
  pointer-events: auto;
  animation: kickToastSlideIn .25s ease-out;
}
.kick-toast-icon {
  font-size: 1.125rem;
  color: var(--raw-red-ink);
  flex-shrink: 0;
}
.kick-toast-text {
  flex: 1;
}
.kick-toast-close {
  background: transparent;
  border: none;
  color: var(--smoke);
  font-size: 0.875rem;
  cursor: pointer;
  padding: 0.125rem 0.375rem;
  margin: -0.125rem -0.25rem -0.125rem 0;
  border-radius: 2px;
  transition: color .15s, background .15s;
}
@media (hover: hover) {
  .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: 0.25rem; }
  .nav-lobby-pill { font-size: 0.75rem; padding: 0.25rem 0.625rem 0.25rem 0.375rem; margin-left: 0.375rem; }
  /* On the lobby page itself the pill only says "you are here" — mode and code stand right
     below in the lobby head — and a phone header has no room for it next to the actions. */
  .nav-lobby-pill.is-current { display: none; }
}

/* ── 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: 1rem;
  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);
}
@media (hover: hover) {
  .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: -0.3125rem;   /* 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: 1rem;
  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: 0.5rem 0.75rem; }
  .app-header-title { display: none; } /* logo only on mobile */
  .mute-btn,
.header-help-btn { width: 34px; height: 34px; font-size: 0.875rem; }
  @media (hover: hover) {
    .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 0.75rem; }
}

/* ── 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: 0.875rem;
  padding: 0.625rem 1.125rem;
  font-size: 0.875rem;
  letter-spacing: .08em;
}
.waiting-banner-sidebar {
  margin-top: 0.875rem;
  text-align: center;
  font-size: 0.8125rem;
}

/* 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: 1.5rem;
  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: 0.9375rem;
  color: var(--smoke);
  letter-spacing: .25em;
  text-transform: uppercase;
  margin-bottom: 0.875rem;
}
.start-overlay-num {
  font-family: 'Rye', cursive;
  font-size: clamp(6rem, 18vw, 10.5rem);
  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: 1.125rem;
  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: 1.25rem;
}
.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: 0.25rem;
}

/* ── Chat ────────────────────────────────────────────────────────────────── */
.chat-card {
  padding: 0.875rem 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.625rem;
}
.chat-title {
  font-family: 'Rye', cursive;
  font-size: 0.875rem;
  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: 0.1875rem;
  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: 0.375rem;
  align-items: baseline;
  padding: 0.0625rem 0;
}
.chat-status-text {
  font-size: 0.8125rem;
  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: 0.375rem;
  align-items: baseline;
  padding: 0.125rem 0;
  flex-wrap: wrap;
}
.chat-msg-own .chat-sender { color: var(--tg-ink, #3a2c16); }
.chat-time {
  font-size: 0.75rem;
  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: 0.8125rem;
  color: var(--tg-wood, #6b4a23);
  font-weight: bold;
  flex-shrink: 0;
}
.chat-sender::after { content: ':'; }
.chat-text {
  font-size: 0.875rem;
  color: var(--old-paper);
  word-break: break-word;
  flex: 1;
}

/* Input line */
.chat-input-row {
  display: flex;
  gap: 0.375rem;
  /* 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: 0.875rem;
}

.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: 1.25rem;
  color: var(--gold);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all .2s;
  line-height: 1;
  padding: 0;
}
@media (hover: hover) {
  .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: 2rem;
  text-align: center;
  color: var(--smoke);
  font-size: 0.875rem;
}
.history-list {
  padding: 1rem 1.25rem;
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

/* ── Game Card ── */
.history-game-card {
  background: rgba(200,146,42,.04);
  border: 1px solid rgba(200,146,42,.12);
  border-radius: 2px;
  padding: 0.875rem 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.625rem;
}
.history-game-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.history-game-meta {
  display: flex;
  gap: 0.625rem;
  align-items: center;
}
.history-game-date {
  font-size: 0.8125rem;
  color: var(--smoke);
}
.history-game-duration {
  font-size: 0.75rem;
  color: rgba(168, 151, 132,.55);
  background: rgba(200,146,42,.07);
  padding: 0.0625rem 0.4375rem;
  border-radius: 10px;
}
.history-winner-badge {
  font-size: 0.8125rem;
  padding: 0.1875rem 0.625rem;
  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: 0.75rem;
  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: 0.625rem;
}
.history-word {
  font-family: 'Rye', cursive;
  font-size: 1rem;
  color: var(--heading);
  letter-spacing: .08em;
}
.history-impostor { font-size: 0.875rem; color: var(--blood-red); }
.history-guess {
  font-size: 0.75rem;
  margin-left: 0.25rem;
}
.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: 0.375rem; }
.history-clues-grid { display: flex; flex-direction: column; gap: 0.25rem; padding-left: 0.25rem; }
.history-player-row {
  display: flex;
  gap: 0.5rem;
  align-items: baseline;
  font-size: 0.8125rem;
  padding: 0.1875rem 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: 0.75rem; }

/* ── Settings: Toggle Row ─────────────────────────────────────────────── */
.settings-toggle-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.375rem 0;
}
/* Sub-switch whose main switch is off. */
.settings-toggle-row.is-disabled { opacity: .5; }
.settings-toggle-row.is-disabled .settings-toggle-btn { cursor: default; }
/* .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: 0.8125rem;
  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: 0.1875rem;
  font-size: 0.75rem;
  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(--toggle-on, var(--green-ok)); }
/* Profile: account theme preference row (select + hint). */
.profile-theme-row { flex-wrap: wrap; row-gap: 0.25rem; }
.profile-theme-select { width: auto; min-width: 200px; max-width: 100%; }
.profile-theme-hint { flex-basis: 100%; font-size: 0.75rem; color: var(--text-dim); }   /* 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: 0.75rem;
  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: 0.5rem;
  margin: 0.875rem 0 0.25rem;
  color: var(--smoke);
  font-size: 0.75rem;
  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: 0.125rem 0 0.375rem;
  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: 0.625rem;
  padding: 0.625rem 0.75rem;
}
.spielvariante-info { flex: 1; min-width: 0; }
.spielvariante-name {
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--parchment);
  display: flex;
  align-items: center;
  gap: 0.375rem;
  transition: color .18s;
}
/* --heading, not --gold-light: identical in the dark theme, readable dark gold in the light one
   (--gold-light as text fell to near-invisible on the light surfaces). */
.spielvariante-block.active .spielvariante-name { color: var(--heading); }
.spielvariante-desc {
  font-size: 0.75rem;
  color: var(--smoke);
  margin-top: 0.1875rem;
  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: 0.375rem;
}
.settings-advanced-collapsible > .settings-advanced-summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.625rem 0.875rem;
  user-select: none;
  border-radius: 4px;
  transition: background .15s ease;
}
.settings-advanced-collapsible > .settings-advanced-summary::-webkit-details-marker {
  display: none;
}
@media (hover: hover) {
  .settings-advanced-collapsible > .settings-advanced-summary:hover {
    background: rgba(255,255,255,.03);
  }
}
.settings-advanced-collapsible > .settings-advanced-summary::before {
  content: '▸';
  font-size: 1.125rem;
  font-weight: 700;
  color: var(--gold, #c8922a);
  transition: transform .2s ease;
  display: inline-block;
  margin-right: 0.5rem;
}
.settings-advanced-collapsible[open] > .settings-advanced-summary::before {
  transform: rotate(90deg);
}
/* ── Card table rules (Skat, Doppelkopf) ───────────────────────────────────
   The rules dialog: preset cards, the line that says what deviates from the rulebook, and the
   collapsed single rules. Tokens only, so every design carries it. */
.rule-presets {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9.5rem, 1fr));
  gap: 0.5rem;
  margin: 0.25rem 0 0;
}
.rule-preset {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
  min-height: 3.5rem;
  padding: 0.5625rem 0.75rem;
  border: 1px solid var(--border-soft);
  border-radius: 8px;
  background: var(--surface-2);
  color: var(--text-main);
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.rule-preset-name { font-size: 0.875rem; font-weight: 600; }
.rule-preset-sub { font-size: 0.78125rem; color: var(--old-paper); }
.rule-preset.selected { border-color: var(--heading); box-shadow: inset 0 0 0 1px var(--heading); }
.rule-preset.selected .rule-preset-name { color: var(--heading); }
.rule-preset:focus-visible { outline: 2px solid var(--heading); outline-offset: 2px; }
.rule-summary { margin: 0.625rem 0 0.25rem; font-size: 0.8125rem; line-height: 1.45; color: var(--text-main); }
.rule-summary b { color: var(--heading); }
.rule-summary.plain { color: var(--old-paper); }
.rule-adjust > .settings-advanced-summary { min-height: 2.75rem; font-size: 0.875rem; font-weight: 600; color: var(--heading); }
.rule-adjust-count { margin-left: auto; font-size: 0.78125rem; font-weight: 400; color: var(--old-paper); }
.rule-adjust-body { padding: 0 0.875rem 0.5rem; }
/* Three long option names do not fit one line of a phone: the group may wrap, the page never scrolls sideways. */
.settings-pills-row.rule-choice { flex-wrap: wrap; }
.settings-pills-row.rule-choice .quiz-mode-pills { flex-wrap: wrap; flex-shrink: 1; justify-content: flex-end; }
/* The reason a chosen option cannot be saved, under its row. */
.settings-note.rule-error { color: var(--red-ink); font-weight: 600; }
/* Read-only settings view: the line above the rules that deviate from the rulebook. */
.settings-rule-divider {
  margin: 0.375rem 0 0.125rem;
  padding-top: 0.375rem;
  border-top: 1px solid var(--border-soft);
  font-size: 0.75rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  line-height: 1.8;
  color: var(--old-paper);
}

/* ── Lobby Sidebar: Quick-Access Buttons at Top ──────────────────────────── */
.lobby-sidebar-top-btns {
  display: flex;
  gap: 0.5rem;
  margin-bottom: 0.75rem;
}
.btn-sm-action {
  flex: 1;
  font-size: 0.75rem !important;
  padding: 0.375rem 0.625rem !important;
  white-space: nowrap;
}

/* ── Stat Box (Game Sidebar) ─────────────────────────────────────────────── */
.stat-box { background: var(--surface-1-strong); border: 1px solid var(--border-soft); padding: 0.875rem 1rem; border-radius: 1px; }
.stat-box h4 { font-family: 'Rye', cursive; font-size: 1rem; color: var(--accent); margin-bottom: 0.625rem; letter-spacing: .08em; }
[data-scheme="light"] .stat-box h4 { color: var(--accent-ink); }   /* the gold accent drops below 4.5:1 on parchment */
.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: 0.8125rem;
  letter-spacing: .08em;
  padding: 0.625rem 0.875rem;
  margin-top: 0.625rem;
  width: 100%;
  text-align: left;
  display: flex;
  align-items: center;
  gap: 0.625rem;
  cursor: pointer;
  border-radius: 2px;
  transition: background .15s ease, border-color .15s ease;
}
@media (hover: hover) {
  .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: 0.75rem;
  width: 12px;
  flex-shrink: 0;
}
.history-session-title {
  flex-shrink: 0;
}
.history-session-summary {
  font-size: 0.75rem;
  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. */
@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: 0.875rem;
  line-height: 1.6;
  color: var(--old-paper);
}
.rules-content p { margin: 0 0 0.625rem 0; }
.rules-content ul { margin: 0.25rem 0 0.625rem 1.5rem; padding: 0; }
.rules-content li { margin: 0.25rem 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: 1.25rem;
}
.card-auth,
.card-setup {
  background: var(--surface-1-strong);
  border: 1px solid var(--border-strong);
  border-radius: 12px;
  padding: 2rem;
  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: 3rem;
  margin-bottom: 0.75rem;
}
.auth-title,
.setup-title {
  text-align: center;
  font-family: 'Rye', cursive;
  color: var(--heading);
  font-size: 1.625rem;
  margin: 0 0 0.375rem 0;
}
.setup-subtitle {
  text-align: center;
  color: var(--smoke);
  font-size: 0.875rem;
  margin-bottom: 1.5rem;
}

.auth-form,
.setup-form { display: flex; flex-direction: column; gap: 1rem; }
.form-group { display: flex; flex-direction: column; gap: 0.375rem; }
/* 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: 0.8125rem;
  color: var(--heading);
}
.form-group small { color: var(--smoke); font-size: 0.75rem; }

/* 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: 0.875rem; }
.form-row { flex-direction: row; align-items: center; justify-content: space-between; gap: 0.625rem; }
.check-row { display: flex; align-items: center; gap: 0.5rem; cursor: pointer; font-size: 0.8125rem; 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: 0.8125rem;
}
@media (hover: hover) {
  .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;
}
@media (hover: hover) {
  .auth-link-disabled:hover {
    color: var(--smoke, #a89784);
    text-decoration: line-through;
  }
}

.auth-divider {
  text-align: center;
  margin: 1.5rem 0 1.125rem 0;
  position: relative;
  color: var(--smoke);
  font-size: 0.75rem;
}
.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 0.75rem; position: relative; }

.oauth-buttons { display: flex; flex-direction: column; gap: 0.5rem; }
.btn-oauth {
  display: flex; align-items: center; justify-content: center; gap: 0.625rem;
  padding: 0.625rem;
  background: var(--surface-2);
  border: 1px solid var(--border-soft);
  color: var(--old-paper);
  border-radius: 6px;
  text-decoration: none;
  font-size: 0.875rem;
  transition: all .2s;
}
@media (hover: hover) {
  .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: 0.625rem 0.875rem;
  cursor: pointer;
  font-size: 0.875rem;
  border-radius: 3px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  transition: all .15s;
}
@media (hover: hover) {
  .pw-toggle:hover { color: var(--heading); border-color: var(--gold); }
}
.pw-toggle .chevron { font-size: 0.75rem; 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: 0.875rem; padding-top: 0.875rem;
  border-top: 1px dashed rgba(200,146,42,.15); }
.pw-form-collapsible.expanded { display: block; }

.auth-footer {
  margin-top: 1.25rem;
  text-align: center;
  font-size: 0.8125rem;
  color: var(--smoke);
}

/* ── Profile Info ─────────────────────────────────────────────────────── */
.profile-info { display: flex; flex-direction: column; gap: 0.5rem; margin-bottom: 1rem; }
.profile-info-row { display: flex; align-items: center; gap: 0.625rem; font-size: 0.875rem; }
/* 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: 0.9375rem; margin: 0 0 0.625rem 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: 1.375rem 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: 0.8125rem;
  font-family: inherit;
  padding: 0;
  flex-shrink: 0;
  transition: all .15s;
}
@media (hover: hover) {
  .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: 0.75rem;
  padding-top: 0.75rem;
  border-top: 1px dashed rgba(200,146,42,.1);
  display: flex;
  gap: 0.5rem;
}
/* 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: 0.8125rem;
  color: var(--smoke);
  margin-bottom: 0.25rem;
}

/* 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: 0.375rem;
  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: 0.875rem;
  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: 1.5rem 1rem 3.75rem;
}
.profile-page {
  width: 100%;
  max-width: 1100px;
  display: flex;
  flex-direction: column;
  gap: 1.125rem;
}
.profile-page-header {
  text-align: center;
  margin-bottom: 0.375rem;
}

/* 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: 1.125rem;
  align-items: start;
}
.profile-column-left,
.profile-column-right {
  display: flex;
  flex-direction: column;
  gap: 1.125rem;
  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: 1.125rem 1.25rem 1.375rem;
}
/* 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: 0.625rem;
}
.profile-section > p + .btn,
.profile-section > p + a.btn {
  margin-top: 0.875rem;
}
/* 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: 1rem;
  letter-spacing: .04em;
  margin: 0 0 0.875rem 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: 1rem;
  /* 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: 0.625rem 0.875rem; border-bottom: 1px solid var(--border-soft); font-size: 0.8125rem; color: var(--heading); }
.profile-dropdown-item {
  display: block; padding: 0.5rem 0.875rem;
  color: var(--old-paper);
  text-decoration: none;
  font-size: 0.8125rem;
  background: none;
  border: none;
  width: 100%;
  text-align: left;
  cursor: pointer;
  font-family: inherit;
}
@media (hover: hover) {
  .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: 0.25rem 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: 0.375rem;
  font-size: 0.8125rem;
}

/* Warning banner in the profile menu when the player is in an active game */
.profile-dropdown-ingame {
  padding: 0.5625rem 0.875rem;
  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: 0.75rem;
  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: 0.5rem 0.75rem;
  border-radius: 6px;
  font-size: 0.8125rem;
  margin-bottom: 0.5rem;
}
/* Light: the fixed #4ade80 lands at ~1.7:1 on light cards — take the theme-aware success ink on a
   lighter veil (the dark green tint alone held it at 4.93:1). */
[data-scheme="light"] .alert-success {
  background: color-mix(in srgb, var(--success) 10%, transparent);
  color: var(--success);
  border-color: color-mix(in srgb, var(--success) 45%, transparent);
}

/* ── 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: 0.5rem;
  margin-bottom: 0.375rem;
}
.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: 0.75rem;
  font-weight: bold;
  cursor: pointer;
  transition: background .15s, border-color .15s, color .15s;
}
@media (hover: hover) {
  .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: 0.8125rem;
  margin: 0 0 1.125rem 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: 0.875rem; padding: 0.125rem 0 0.875rem;
  border-bottom: 1px solid var(--border); margin-bottom: 0.875rem; }
.single-mode-hero .smh-ic { font-size: 2.375rem; line-height: 1; flex: 0 0 auto; }
.single-mode-hero .smh-name { font-family: 'Rye', serif; color: var(--heading); font-size: 1.3125rem; }
.single-mode-hero .smh-meta { font-size: 0.75rem; color: var(--smoke); margin-top: 0.1875rem; }
.mode-info-list {
  display: flex;
  flex-direction: column;
  gap: 0.875rem;
}
.mode-info-card {
  display: flex;
  gap: 0.875rem;
  padding: 0.875rem;
  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: 2rem;
  line-height: 1;
  flex-shrink: 0;
}
.mode-info-text {
  flex: 1;
}
.mode-info-name {
  font-family: 'Rye', cursive;
  font-size: 1rem;
  color: var(--gold);
  margin: 0 0 0.375rem 0;
  display: flex;
  align-items: center;
  gap: 0.625rem;
}
.mode-info-current {
  font-size: 0.75rem;
  color: var(--heading);
  background: rgba(200,146,42,.18);
  padding: 0.125rem 0.5rem;
  border-radius: 10px;
  font-weight: normal;
  letter-spacing: 0.02em;
}
.mode-info-desc {
  font-size: 0.8125rem;
  color: var(--parchment);
  margin: 0 0 0.375rem 0;
  line-height: 1.5;
}
.mode-info-meta {
  font-size: 0.75rem;
  color: var(--smoke);
}

/* ── Quiz mode pills (only visible when music quiz is selected) ──────────────── */
.quiz-mode-pills {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
}
.quiz-pill {
  padding: 0.5rem 1rem;
  /* 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: 0.8125rem;
  cursor: pointer;
  transition: all .15s;
  white-space: nowrap;
}
@media (hover: hover) {
  .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: 0.5rem;
  margin-bottom: 1.125rem;
}
.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: 0.625rem 0.5rem;
  text-align: center;
}
.stats-summary-value {
  font-family: 'Rye', cursive;
  color: var(--heading);
  font-size: 1.125rem;
  margin-bottom: 0.125rem;
}
.stats-summary-label {
  color: var(--smoke);
  font-size: 0.75rem;
  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: 0.625rem;
}
@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: 0.75rem 0.875rem;
  margin-bottom: 0;
}
.stats-mode-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 0.5rem;
  padding-bottom: 0.375rem;
  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: 0.9375rem;
}
.stats-mode-played {
  font-size: 0.75rem;
  color: var(--smoke);
}
.stats-mode-grid {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}
.stats-row {
  display: flex;
  justify-content: space-between;
  font-size: 0.8125rem;
}
.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: 0.75rem;
  margin-left: 0.25rem;
}

@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: 0.9375rem;
  margin: 1rem 0 0.5rem;
}
.ach-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 0.625rem;
}
@media (max-width: 560px) {
  .ach-grid { grid-template-columns: 1fr; }
}
.ach-card {
  display: flex;
  gap: 0.75rem;
  align-items: flex-start;
  background: var(--surface-1);
  border: 1px solid var(--border-soft);
  border-radius: 6px;
  padding: 0.75rem 0.875rem;
}
.ach-card.unlocked {
  border-color: var(--border-strong);
  background: var(--surface-2);
}
.ach-icon {
  font-size: 1.625rem;
  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: 0.875rem;
  color: var(--heading);
}
.ach-card.locked .ach-title { color: var(--old-paper); }
.ach-desc {
  font-size: 0.75rem;
  color: var(--smoke);
  margin-top: 0.125rem;
  line-height: 1.35;
}
.ach-date {
  font-size: 0.75rem;
  color: var(--smoke);
  margin-top: 0.375rem;
}
.ach-progress {
  margin-top: 0.5rem;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
.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: 0.75rem;
  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: 0.75rem 1rem;
  font-size: 0.75rem;
  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;
}
@media (hover: hover) {
  .footer-link:hover {
    color: var(--gold);
  }
}
.footer-sep {
  margin: 0 0.5rem;
  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: 0.3125rem;
  height: 38px;
  padding: 0 0.5625rem;
  border-radius: 19px;
  background: var(--surface-1);
  border: 1px solid var(--border-strong);
  color: var(--heading);
  cursor: pointer;
  transition: all .2s;
}
@media (hover: hover) {
  .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: 0.75rem;
  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: var(--elev-2);
  backdrop-filter: blur(4px);
  overflow: hidden;
}
.lang-dd-opt {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  padding: 0.5rem 0.75rem;
  color: var(--old-paper);
  text-decoration: none;
  font-size: 0.8125rem;
}
@media (hover: hover) {
  .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: 0.75rem; }
/* Theme picker (header, ≥3 active themes): same dropdown chrome as the language
   switcher; the trigger shows a three-tone swatch of the current theme. */
.theme-dd-trigger { min-width: 30px; min-height: 30px; padding: 0 0.375rem 0 0.25rem; gap: 0.25rem; }
.theme-swatch { display: inline-block; width: 18px; height: 18px; border-radius: 50%; border: 1px solid var(--border-strong); flex: none; }
/* Button reset for the options. :where() keeps it at one class of specificity, so the shared
   .lang-dd-opt:hover and .lang-dd-opt.active (two) still win — as .theme-dd .lang-dd-opt it
   tied with them, came later and wiped out the hover and the active highlight. */
:where(.theme-dd) .lang-dd-opt { background: none; border: 0; width: 100%; font: inherit; color: inherit; cursor: pointer; text-align: left; }
/* The menu hangs off a ~40 px trigger, so shrink-to-fit gave it only its 170 px minimum and
   "Shadow Saloon" plus the ✓ wrapped. As wide as the longest row instead, names on one line. */
.theme-dd .lang-dd-menu { width: max-content; }
/* Sun/moon between swatch and name (the scheme, instead of "(light)"/"(dark)" in the name);
   a fixed box keeps the names aligned whatever the glyph's own width, and the name's auto
   margin keeps the ✓ of the active row at the right edge. */
.theme-dd .theme-scheme { flex: none; width: 1rem; text-align: center; font-size: 0.75rem; line-height: 1; }
.theme-dd .lang-dd-name { white-space: nowrap; flex: 0 1 auto; margin-right: auto; }
.theme-dd-group { margin-top: 0.25rem; padding: 0.375rem 0.75rem 0.125rem; border-top: 1px solid var(--border-soft); font-size: 0.75rem; letter-spacing: .12em; text-transform: uppercase; color: var(--text-dim); }

/* 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: 0.125rem 0.25rem;
  gap: 0.375rem;
  border: none;
  border-radius: 4px;
  background: none;
  color: var(--text-dim);
  font-size: 0.78125rem;
}
@media (hover: hover) {
  .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: 1.125rem;
  margin-top: 1.625rem;
  padding-bottom: 0.375rem;
  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: 0.875rem;
  margin-top: 1.125rem;
}
.legal-page p { font-size: 0.875rem; }
.legal-page ul { padding-left: 1.375rem; font-size: 0.875rem; }
.legal-page li { margin-bottom: 0.3125rem; }
.legal-page a {
  color: var(--heading);
  text-decoration: underline;
}
.legal-block {
  background: var(--surface-2);
  border-left: 2px solid var(--gold);
  padding: 0.75rem 1rem;
  margin: 0.75rem 0;
}
.legal-footer {
  margin-top: 1.875rem;
  color: var(--smoke);
  font-size: 0.75rem;
  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: 0.625rem 0.875rem;
  margin: 0 0 1.125rem;
  color: var(--smoke);
  font-size: 0.8125rem;
}

/* ── Home page announcement banner ───────────────────────────────── */
.announce {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
  border-radius: 5px;
  padding: 0.75rem 1rem;
  margin-bottom: 1rem;
  font-size: 0.875rem;
  line-height: 1.5;
  border-left: 4px solid;
}
.announce-icon { font-size: 1.125rem; 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-scheme="light"] .announce.announce-info  { color: var(--ann-info-ink, #1e4e78); }
[data-scheme="light"] .announce.announce-warn  { color: var(--ann-warn-ink, #6a4a08); background: var(--ann-warn-bg, rgba(181, 84, 10, .12)); }
[data-scheme="light"] .announce.announce-error { color: var(--ann-error-ink, #7a2338); }

/* ── Error page /Error ───────────────────────────────────────────── */
.error-page-text {
  color: var(--old-paper);
  font-size: 0.875rem;
  line-height: 1.6;
  text-align: center;
  margin: 0.5rem 0;
}
.error-page-hint { color: var(--smoke); font-size: 0.8125rem; }
.error-page-actions {
  display: flex;
  justify-content: center;
  margin-top: 1.125rem;
}

/* ── Changelog / What's new ──────────────────────────────────────────────── */
/* Lives inside the PageFrame board (narrow width) — no own container anymore. */
.changelog-sub {
  color: var(--smoke);
  font-size: 0.8125rem;
  margin: 0 0 1.625rem;
}
.changelog-empty {
  color: var(--smoke);
  font-style: italic;
  padding: 0.75rem 0;
}
.changelog-timeline {
  margin-top: 0.25rem;
}
.cl-entry {
  position: relative;
  padding: 0 0 1.375rem 1.375rem;
  border-left: 2px solid rgba(200, 146, 42, 0.25);
  margin-left: 0.375rem;
}
.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: 0.75rem;
  margin-bottom: 0.5rem;
  flex-wrap: wrap;
}
.cl-version {
  font-family: 'Rye', cursive;
  color: var(--heading);
  font-size: 1rem;
}
.cl-badge-new {
  font-size: 0.75rem;
  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: 0.0625rem 0.5rem;
}
.cl-date {
  color: var(--smoke);
  font-size: 0.75rem;
  font-variant-numeric: tabular-nums;
  margin-left: auto;
}
.cl-entry-title {
  color: var(--parchment);
  font-weight: 600;
  font-size: 0.9375rem;
  margin-bottom: 0.5rem;
}
.cl-body {
  color: var(--old-paper);
  font-size: 0.84375rem;
  line-height: 1.6;
}
.cl-body strong { color: var(--heading); font-weight: 600; }
.cl-body ul { margin: 0.25rem 0 0.75rem; padding-left: 1.25rem; }
.cl-body li { margin: 0.1875rem 0; }
.cl-body p { margin: 0.375rem 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(--heading);
  margin: 0.625rem 0 0.25rem;
  line-height: 1.3;
}
.cl-body h1 { font-size: 1rem; }
.cl-body h2 { font-size: 0.9375rem; }
.cl-body h3, .cl-body h4 { font-size: 0.84375rem; }
.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: 0.75rem;
  color: var(--heading);
  background: rgba(200, 146, 42, 0.08);
  padding: 0.0625rem 0.25rem;
  border-radius: 2px;
}

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

/* ── Player name clickable ───────────────────────────────────────────────── */
/* A <button> now, not a <span> (WCAG 2.1.1/4.1.2 — a span can't be reached or
   activated by keyboard). The reset below reproduces the old inline-text look
   exactly; color/text-align/line-height go to "inherit" because a plain
   <button> would otherwise use the UA button color/centering instead of the
   surrounding text's. */
.p-name-clickable {
  background: none;
  border: 0;
  margin: 0;
  padding: 0;
  font: inherit;
  color: inherit;
  text-align: inherit;
  line-height: inherit;
  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:focus-visible {
  outline: 2px solid var(--gold-light);
  outline-offset: 2px;
  border-radius: 2px;
}
@media (hover: hover) {
  .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: 0.375rem;
}
.player-profile-row {
  display: flex;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.375rem 0;
  font-size: 0.8125rem;
  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: 0.25rem; }
.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: 0.0625rem 0.375rem;
  margin-left: 0.25rem;
  font-size: 0.75rem;
  color: var(--heading);
}
.player-profile-divider {
  border: none;
  border-top: 1px solid rgba(200, 146, 42, 0.15);
  margin: 1rem 0 0.75rem;
}
.player-profile-mod {
  background: rgba(139, 26, 26, 0.08);
  border: 1px solid rgba(139, 26, 26, 0.25);
  border-radius: 4px;
  padding: 0.75rem;
}
.player-profile-mod .lbl {
  display: block;
  margin-bottom: 0.25rem;
  font-size: 0.75rem;
  color: var(--smoke);
}
.player-profile-mod .inp { margin-bottom: 0.625rem; }
.player-profile-mod-actions {
  display: flex;
  gap: 0.5rem;
  margin-top: 0.5rem;
}

/* 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; }

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

/* ── Recent-games history in the profile (flat list of cards, .hist-list) ──────── */
.history-card-compact {
  background: var(--surface-1);
  border: 1px solid var(--border-soft);
  border-left-width: 4px;
  border-radius: 3px;
  padding: 0.625rem 0.875rem;
  font-size: 0.8125rem;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}
.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: 0.625rem;
}
.history-card-mode {
  font-family: 'Rye', cursive;
  color: var(--accent-light);
  font-size: 0.875rem;
  letter-spacing: 0.04em;
}
.history-card-outcome {
  font-size: 0.8125rem;
  padding: 0.125rem 0.5rem;
  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: 0.375rem;
  color: var(--smoke);
  font-size: 0.75rem;
}
.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: 0.75rem;
  color: var(--text-dim);
}
.history-card-label {
  color: var(--smoke);
  margin-right: 0.25rem;
}

/* 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. Dark keeps its calibrated tones. */
[data-scheme="light"] .history-outcome-won  .history-card-outcome,
[data-scheme="light"] .track-history-res.res-ok,
[data-scheme="light"] .history-role-crewmate { color: var(--success); }
[data-scheme="light"] .history-outcome-lost .history-card-outcome,
[data-scheme="light"] .track-history-res.res-no,
[data-scheme="light"] .history-role-impostor { color: var(--danger); }
[data-scheme="light"] .history-outcome-draw .history-card-outcome { color: var(--gold-ink); }

/* ── The list itself: one separator line per day, then that day's cards ──
   The day stands once, in the separator; the card's meta line carries the time only. The
   lobby code behind the mode name keeps the games of one sitting recognisable. */
.hist-list { display: flex; flex-direction: column; gap: 0.4375rem; margin-bottom: 0.625rem; }
.hist-day {
  display: flex; align-items: center; gap: 0.625rem; margin: 0.4375rem 0 0.0625rem;
  font-size: 0.75rem; letter-spacing: .08em; text-transform: uppercase; color: var(--smoke);
}
.hist-day:first-child { margin-top: 0; }
.hist-day::after { content: ""; flex: 1; height: 1px; background: var(--border-soft); }
.hist-day b { color: var(--text-main); font-weight: 600; letter-spacing: .06em; }
.hc-code {
  font-family: 'Inter', system-ui, sans-serif; font-size: 0.75rem; font-weight: 400;
  color: var(--smoke); letter-spacing: .04em; margin-left: 0.5rem; white-space: nowrap;
}
/* Narrow phone: mode name plus code and a long result ("shared 1st place") do not fit one
   line — the result badge moves below instead of running out of the card. */
.hist-list .history-card-head { flex-wrap: wrap; row-gap: 0.25rem; }
.hist-list .history-card-mode { min-width: 0; }
.hist-list .history-card-outcome { white-space: nowrap; }

/* ── 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: 1.875rem;
  transition: border-color .15s, transform .05s;
}
@media (hover: hover) {
  .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: 1.125rem;
  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: 0.8125rem;
  cursor: pointer;
  padding: 0.125rem 0;
  margin-bottom: 0.75rem;
}
@media (hover: hover) {
  .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: 0.625rem;
  margin-bottom: 0.375rem;
}
.partie-detail-hero .history-card-mode { font-size: 1.0625rem; }
.partie-detail-meta { margin-bottom: 0.25rem; }
.partie-detail-section {
  margin-top: 0.875rem;
  padding-top: 0.75rem;
  border-top: 1px dashed rgba(200, 146, 42, 0.18);
}
.partie-detail-sub {
  font-family: 'Rye', cursive;
  color: var(--gold);
  font-size: 0.75rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  margin-bottom: 0.5rem;
}
.partie-detail-coplayers { font-size: 0.8125rem; line-height: 1.9; }
.coplayer-link {
  color: var(--heading);
  cursor: pointer;
  border-bottom: 1px dotted color-mix(in srgb, var(--heading) 45%, transparent);
}
@media (hover: hover) {
  .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: 0.75rem; opacity: .7; margin-left: 0.125rem; }
.coplayer-sep { color: var(--smoke); }

.track-history-list { display: flex; flex-direction: column; gap: 0.1875rem; }
.track-history-row {
  display: flex;
  align-items: center;
  gap: 0.5625rem;
  padding: 0.375rem 0.5625rem;
  border-radius: 3px;
  background: var(--surface-1);
  border: 1px solid var(--border-soft);
  font-size: 0.78125rem;
}
.track-history-clickable { cursor: pointer; transition: border-color .15s, background .15s; }
@media (hover: hover) {
  .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: 0.75rem;
  color: var(--smoke);
  background: rgba(200, 146, 42, 0.08);
  padding: 0.0625rem 0.5rem;
  border-radius: 10px;
  white-space: nowrap;
  flex: none;
}
.track-history-res { width: 18px; text-align: center; font-size: 0.8125rem; 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: 0.375rem; }
.hand-history-row { display: flex; align-items: center; gap: 0.625rem; flex-wrap: wrap; padding: 0.3125rem 0.125rem; 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: 0.8125rem; color: var(--parchment); }
.hand-history-cards { display: flex; gap: 0.25rem; flex-wrap: wrap; align-items: center; }
.hand-extra { display: flex; align-items: center; gap: 0.25rem; margin-left: 0.375rem; padding-left: 0.625rem; border-left: 1px solid rgba(200, 146, 42, 0.18); }
.extra-lbl { font-size: 0.75rem; color: var(--smoke); text-transform: uppercase; letter-spacing: 0.04em; }
.deal-tabs { display: flex; gap: 0.375rem; flex-wrap: wrap; margin-bottom: 0.625rem; }
.deal-chip { font-size: 0.75rem; color: var(--smoke); background: var(--surface-2); border: 1px solid var(--border); padding: 0.1875rem 0.6875rem; border-radius: 999px; cursor: pointer; transition: 0.15s; }
@media (hover: hover) {
  .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: 1rem; flex-wrap: wrap; }
.board-history-item { display: flex; flex-direction: column; gap: 0.375rem; }
.board-history-cap { font-size: 0.8125rem; color: var(--parchment); }

/* ── Memory board in history (symbol + revealer color) ── */
.mem-history-grid { display: grid; grid-template-columns: repeat(8, 1fr); gap: 0.3125rem; 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: 0.875rem; flex-wrap: wrap; margin-top: 0.625rem; font-size: 0.75rem; }
.mem-history-legend span { display: inline-flex; align-items: center; gap: 0.375rem; color: var(--parchment); }
.mem-history-legend i { width: 13px; height: 13px; border-radius: 3px; display: inline-block; }

/* Discord brand accent for the OAuth button */
@media (hover: hover) {
  .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: 0.5rem;
}
.linked-account-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 0.75rem;
  padding: 0.625rem 0.875rem;
  background: var(--surface-1);
  border: 1px solid var(--border-soft);
  border-radius: 3px;
}
.linked-account-info {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  flex-wrap: wrap;
}
.linked-account-name {
  color: var(--old-paper);
  font-size: 0.875rem;
}
.linked-account-status {
  font-size: 0.75rem;
  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: 0.3125rem 0.75rem !important;
  font-size: 0.75rem !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: 0.25rem;
  font-size: 0.75rem;
}

/* Steam brand accent for the OAuth button (Steam blue) */
@media (hover: hover) {
  .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: 0.625rem;
  align-items: stretch;
}
.verify-banner-text { line-height: 1.5; }
.verify-banner code {
  background: var(--surface-2);
  padding: 0.0625rem 0.375rem;
  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: 0.75rem 0.875rem;
  border-radius: 4px;
  margin-bottom: 0.875rem;
  font-size: 0.8125rem;
}
/* Light: the fixed #e8c878 lands at ~1.4:1 on light cards — take the amber ink. */
[data-scheme="light"] .alert-warning {
  color: var(--accent-amber);
  border-color: color-mix(in srgb, var(--accent-amber) 35%, transparent);
}
.email-verified {
  color: var(--success);   /* theme-aware — hardcoded #88d088 was 4.2:1 in light */
  margin-left: 0.375rem;
  font-weight: bold;
}
.email-unverified {
  color: var(--amber);
  margin-left: 0.375rem;
  font-size: 0.75rem;
}
.btn-sm {
  padding: 0.3125rem 0.75rem;
  font-size: 0.75rem;
  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: 0.625rem; flex-wrap: wrap; margin: 0.25rem 0 0.125rem; }
.filter-trigger {
  display: flex; align-items: center; gap: 0.5rem; min-width: 150px; cursor: pointer;
  background: var(--surface-2); border: 1px solid var(--border); border-radius: 10px;
  padding: 0.5625rem 0.875rem; color: var(--parchment); font: inherit; text-align: left;
}
@media (hover: hover) {
  .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: 0.9375rem; flex: 0 0 auto; }
.filter-trigger .ft-name { font-size: 0.8125rem; color: var(--parchment); }
.filter-trigger .ft-val { margin-left: auto; font-size: 0.75rem; 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: 0.75rem; 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: 0.875rem; margin: 0.625rem 0 0.25rem;
}
.filter-panel .filter-pop-head { display: flex; align-items: center; justify-content: space-between; gap: 0.625rem; margin-bottom: 0.625rem; }
.filter-panel .fp-title { font-size: 0.75rem; letter-spacing: .08em; text-transform: uppercase; color: var(--gold); }
.filter-panel .fp-clear { font-size: 0.75rem; color: var(--smoke); cursor: pointer; background: none; border: none; padding: 0.125rem 0.25rem; }
@media (hover: hover) {
  .filter-panel .fp-clear:hover { color: var(--accent-light); }
}
.filter-panel .fp-done {
  margin-top: 0.75rem; width: 100%; padding: 0.5rem; 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);
}
@media (hover: hover) {
  .filter-panel .fp-done:hover { background: color-mix(in srgb, var(--accent) 28%, transparent); }
}

.genre-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.375rem;
  padding: 0.375rem;
  background: var(--surface-2);
  border-radius: 4px;
  border: 1px solid var(--border-soft);
  max-height: 140px;
  overflow-y: auto;
}
.genre-chip {
  padding: 0.3125rem 0.6875rem;
  font-size: 0.75rem;
  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;
}
@media (hover: hover) {
  .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: 0.25rem;
  padding: 0.0625rem 0.375rem;
  font-size: 0.75rem;
  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
   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: 0.625rem;
  padding: 0.3125rem 0.75rem;
  font-size: 0.75rem;
  color: var(--smoke);
  text-decoration: none;
  border: 1px solid var(--edge-strong);
  border-radius: 999px;
  transition: all 0.15s ease;
}
@media (hover: hover) {
  .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: 0.375rem;
  font-size: 0.75rem;
  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;
}
@media (hover: hover) {
  .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: 0.375rem;
  padding: 1rem 1.125rem 1.25rem;
}

/* ── 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: 0.75rem;
}
.dual-range-row .dr-rowlabel {
  width: 60px;
  flex-shrink: 0;
  font-size: 0.8125rem;
  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: 0.75rem;
  color: var(--smoke);
  font-variant-numeric: tabular-nums;
  margin-top: 0.0625rem;
}
.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); } }
@keyframes tbiStamp {
  from { opacity: 0; transform: rotate(-8deg) scale(2.4); }
  to   { opacity: 1; transform: rotate(-8deg) scale(1); }
}
@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); } }
@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: 0.75rem 0 0.25rem;
  padding: 0.5rem 0.75rem;
  font-size: 0.8125rem;
  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: 1rem;
  line-height: 1;
}
.settings-value-icon-no {
  color: #d97a5a;
  font-weight: bold;
  font-size: 1rem;
  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: 0.25rem;
}
@media (hover: hover) {
  .settings-value-link-mode:hover {
    color: var(--gold-ink);
  }
}
.settings-value-info-icon {
  font-size: 0.75rem;
  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: 0.75rem;
  letter-spacing: .06em;
  color: var(--accent-light);
  background: color-mix(in srgb, var(--accent) 18%, transparent);
  border: 1px solid var(--accent-light);
  padding: 0.125rem 0.5rem;
  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: 0.375rem;
  font-size: 0.8125rem;
  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;
}
@media (hover: hover) {
  .history-apple-link:hover {
    background: rgba(200,146,42,.25);
    border-color: rgba(200,146,42,.55);
    color: var(--heading);
    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: 0.5rem 0 0.875rem;
  padding: 0.625rem 0.875rem;
  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: 0.75rem;
  letter-spacing: .08em;
  color: var(--gold, #d4920a);
  margin-bottom: 0.5rem;
}
.history-scoreboard-row {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  padding: 0.25rem 0;
  font-size: 0.8125rem;
  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 -0.375rem;
  padding-left: 0.375rem;
  padding-right: 0.375rem;
  border-radius: 2px;
}
.history-scoreboard-row.is-me .history-scoreboard-name {
  color: var(--gold-light, #f0a020);
}

/* == Content reports (mod sprint step 1) ==================================
   Styles for ReportContentModal (Shared/ReportContentModal.razor) and the
   report button in the game modes. Reuses the generic modal classes
   (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: 0.8125rem;
  padding: 0.125rem 0.25rem;
  border-radius: 3px;
  cursor: pointer;
  transition: all .15s;
  line-height: 1;
  flex-shrink: 0;
}
@media (hover: hover) {
  .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: 0.5rem 0.75rem;
  border-radius: 2px;
  margin-bottom: 0.875rem;
}
.report-target-label {
  font-size: 0.75rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--smoke);
  margin-bottom: 0.25rem;
}
.report-target-name {
  font-family: 'Rye', cursive;
  font-size: 1rem;
  color: var(--heading);
}
.report-target-meta {
  font-size: 0.75rem;
  color: var(--smoke);
  margin-top: 0.1875rem;
}

/* 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: 0.375rem;
}
.report-reason-row {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  padding: 0.5625rem 0.75rem;
  background: var(--surface-1);
  border: 1px solid var(--border-soft);
  border-radius: 2px;
  cursor: pointer;
  font-size: 0.875rem;
  color: var(--old-paper);
  transition: all .12s;
}
@media (hover: hover) {
  .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(--heading);
}
.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: 0.375rem;
}
.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: 0.875rem;
  padding: 0.375rem 0.5rem;
  border-radius: 3px;
  text-transform: uppercase;
}
.mm-header-code .inp-code::placeholder {
  color: var(--smoke);
  letter-spacing: .1em;
  font-size: 0.75rem;
}
.mm-header-code .mm-code-go {
  font-family: 'Rye', cursive;
  font-size: 0.75rem;
  cursor: pointer;
  background: linear-gradient(135deg, var(--amber), var(--gold));
  color: var(--shadow);
  border: none;
  padding: 0.4375rem 0.75rem;
  border-radius: 3px;
}
.mm-header-code .mm-code-go:disabled { opacity: .4; cursor: not-allowed; }
/* The field keeps its 108 px on every width: it sits in the tools row of the game page next
   to the game pill. The old modal rule (full row below the title under 520 px) went with the
   modal - on the phone it had stretched the field to a line of its own, beside the header's
   own code pill. */

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

/* ── Lobby entry (flat list) ───────────────────────────────────────── */
.mm-lobby {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  background: var(--surface-2);
  border: 1px solid var(--border-soft);
  border-radius: 4px;
  padding: 0.625rem 0.75rem;
  margin-bottom: 0.5rem;
}
.mm-lobby:last-child { margin-bottom: 0; }
.mm-lobby-icon { font-size: 1.625rem; line-height: 1; flex-shrink: 0; }
.mm-lobby-main { flex: 1; min-width: 0; }
.mm-lobby-host { color: var(--parchment); font-size: 0.875rem; }
.mm-lobby-host .mm-host-name { color: var(--heading); }
.mm-lobby-meta {
  font-size: 0.75rem;
  color: var(--smoke);
  margin-top: 0.125rem;
  display: flex;
  gap: 0.625rem;
  flex-wrap: wrap;
}
.mm-mode-tag { color: var(--heading); letter-spacing: .04em; }
.mm-players { color: var(--old-paper); }
.mm-join-btn {
  font-family: 'Rye', cursive;
  font-size: 0.75rem;
  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: 0.5rem 1rem;
  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: 0.8125rem;
  padding: 2.125rem 0.75rem;
  line-height: 1.6;
}
.mm-empty .mm-empty-icon {
  font-size: 2.125rem;
  display: block;
  margin-bottom: 0.5rem;
  opacity: .6;
}

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

/* ══════════════════════════════════════════════════════════════════════════
   MODE PILL WITH PICKER - ModeSwitchMenu (create/solo and settings dialog,
   matchmaking bar): a button pill anchoring the game picker
   ══════════════════════════════════════════════════════════════════════════ */
.mode-switch { position: relative; display: inline-block; }
.mode-pill-header {
  font: inherit;
  line-height: normal;
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  padding: 0.25rem 0.625rem;
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  border-radius: 14px;
  font-size: 0.8125rem;
  color: var(--heading);
  position: relative;
  cursor: pointer;
  transition: background .15s, border-color .15s;
  user-select: none;
  margin-left: 0.5rem;
}
@media (hover: hover) {
  .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: 0.75rem;
  margin-left: 0.125rem;
}
/* ── Game picker: popover under the pill (wide) or sheet from below (≤ 760 px) ──
   One markup for both. Search field with hit counter on top, below it the list grouped by
   game family with sticky group heads. The focus stays in the field; the marked row (.hl)
   follows aria-activedescendant. */
.mode-picker-scrim { display: none; }
.mode-picker {
  position: absolute; top: calc(100% + 6px); left: 0; z-index: 100;
  width: 360px; max-width: calc(100vw - 24px); max-height: 440px;
  display: flex; flex-direction: column;
  background: var(--surface-1-strong); border: 1px solid var(--border-strong); border-radius: 8px;
  box-shadow: var(--elev-2);
  font-family: var(--font-body); font-size: 0.8125rem; font-weight: 400; color: var(--text-main);
  text-transform: none; letter-spacing: 0; text-align: left;
}
.mode-picker:focus { outline: none; }
/* In the matchmaking bar the pill sits at the right edge: open towards the left. */
.mm-inline-tools .mode-picker { left: auto; right: 0; }
.mp-head { display: none; }
.mp-search { padding: 0.625rem 0.625rem 0.375rem; flex: none; }
.mp-search .pf-search { height: 38px; padding: 0 0.75rem; background: var(--input-bg); border-color: var(--border-strong); }
.mp-search .pf-search input { font-size: 0.8125rem; }
.mp-count { font-size: 0.75rem; color: var(--text-dim); white-space: nowrap; }
.mp-chips { display: none; }
.mp-list { overflow-y: auto; padding: 0 0.375rem 0.375rem; scrollbar-width: thin; flex: 1; min-height: 0; position: relative; }
.mp-group { padding-bottom: 0.25rem; }
.mp-gh {
  position: sticky; top: 0; z-index: 1; background: var(--surface-1-strong);
  display: flex; align-items: center; gap: 0.4375rem; padding: 0.5rem 0.5rem 0.25rem;
  font-size: 0.75rem; letter-spacing: .14em; text-transform: uppercase; color: var(--text-dim); font-weight: 500;
}
.mp-gh .g { letter-spacing: 0; }
.mp-gh .n { margin-left: auto; letter-spacing: 0; font-weight: 400; }
.mp-item {
  display: flex; align-items: center; gap: 0.625rem; width: 100%; min-height: 40px;
  padding: 0.375rem 0.625rem; border: 0; border-radius: 5px; background: none;
  font: inherit; text-align: left; color: var(--text-main); cursor: pointer;
}
.mp-item .ic { width: 22px; text-align: center; font-size: 1.0625rem; line-height: 1; flex: none; }
.mp-item .nm { flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.mp-item .pl { font-size: 0.75rem; color: var(--text-dim); white-space: nowrap; }
.mp-item.cur { background: var(--surface-2); color: var(--heading); font-weight: 600; }
/* Mark and hover keep the body ink: --heading on the hover surface drops to 4.3:1 in one
   theme. The mark carries a ring in --heading on top. */
.mp-item.hl { background: var(--surface-hover); color: var(--text-main); box-shadow: inset 0 0 0 2px var(--heading); }
@media (hover: hover) {
  .mp-item:hover { background: var(--surface-hover); color: var(--text-main); }
}
.mp-item.off .nm, .mp-item.off .ic { opacity: .55; }
/* Game locked because too many players are connected. */
.mp-item.disabled { opacity: .5; pointer-events: none; }
.mp-item .mode-vis-badge { margin-left: auto; }
.mp-empty { padding: 1.625rem 0.875rem; text-align: center; color: var(--text-dim); }
.mp-empty .big { display: block; font-size: 1.75rem; margin-bottom: 0.25rem; }

/* Family chips: jump targets in the sheet of the game picker and on the grouped home page.
   The active chip is a solid --heading with --text-invert — the one pair that holds in every
   theme (a gold tint or solid gold falls below 4.5:1 in the light ones). */
.fam-chip {
  display: inline-flex; align-items: center; gap: 0.375rem; height: 30px; padding: 0 0.625rem;
  border-radius: 999px; border: 1px solid var(--border-strong); background: var(--surface-2);
  color: var(--text-main); font: inherit; font-size: 0.78125rem; white-space: nowrap; flex: none;
  cursor: pointer; scroll-snap-align: start;
}
.fam-chip .cnt { font-size: 0.75rem; color: var(--text-dim); }
.fam-chip.on, .fam-chip[aria-current="true"] { background: var(--heading); border-color: var(--heading); color: var(--text-invert); font-weight: 600; }
.fam-chip.on .cnt, .fam-chip[aria-current="true"] .cnt { color: var(--text-invert); }
.fam-chip:disabled { opacity: .45; cursor: default; }

@media (max-width: 760px) {
  /* Sheet from below, above the dialog (1000) and below the toasts (1200). */
  .mode-picker-scrim { display: block; position: fixed; inset: 0; z-index: 1099; background: var(--scrim); }
  .mode-picker, .mm-inline-tools .mode-picker {
    position: fixed; left: 0; right: 0; top: auto; bottom: 0; z-index: 1100;
    width: auto; max-width: none; height: 82dvh; max-height: 82dvh;
    border-radius: 12px 12px 0 0; border-bottom: 0;
    padding-bottom: env(safe-area-inset-bottom);
  }
  .mp-head {
    display: flex; align-items: center; justify-content: space-between; padding: 0.75rem 0.875rem 0.125rem;
    font-family: 'Rye', cursive; color: var(--heading); font-size: 0.9375rem;
  }
  .mp-close {
    width: 32px; height: 32px; border-radius: 4px; border: 1px solid var(--border-soft);
    background: transparent; color: var(--text-dim); font-size: 0.8125rem; cursor: pointer;
  }
  .mp-chips { display: flex; gap: 0.375rem; overflow-x: auto; scrollbar-width: none; padding: 0.125rem 0.625rem 0.5rem; flex: none; }
  .mp-chips::-webkit-scrollbar { display: none; }
  .mp-chips .fam-chip { height: 28px; font-size: 0.75rem; }
  .mp-list { padding-bottom: 0.75rem; }
}
@keyframes mp-sheet-in { from { transform: translateY(100%); } }
@media (max-width: 760px) and (prefers-reduced-motion: no-preference) {
  .mode-picker { animation: mp-sheet-in .22s ease-out; }
}
.mode-switch-off.cap {
  color: var(--amber, #e8a060);
  border-color: rgba(232, 160, 96, .5);
}

/* ══════════════════════════════════════════════════════════════════════════
   MATCHMAKING - ACTION CARDS (quick start + new lobby) and the live list
   ══════════════════════════════════════════════════════════════════════════ */
.mm-action-cards {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.625rem;
  margin-bottom: 1.125rem;
}
.mm-action-card {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.875rem 1rem;
  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);
}
@media (hover: hover) {
  .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);
}
@media (hover: hover) {
  .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: 1.75rem; flex-shrink: 0; line-height: 1; }
.mm-action-text { display: flex; flex-direction: column; gap: 0.125rem; min-width: 0; }
.mm-action-title {
  color: var(--heading);
  font-family: 'Rye', cursive;
  font-size: 0.9375rem;
}
.mm-action-sub { color: var(--smoke); font-size: 0.75rem; }
@media (max-width: 540px) {
  .mm-action-cards { grid-template-columns: 1fr; }
}
/* A game that can be played alone gets a quiet line under the two cards, right-aligned like a
   footnote: "Lieber allein? Solo spielen". Not a third card - under "Mehrspieler" the cards are
   the choice, the solo way only has to be findable (someone searched for "... alone"). */
.mm-solo-line {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 0.5rem;
  flex-wrap: wrap;
  font-size: 0.8125rem;
  color: var(--text-main);
  margin: -0.5rem 0.125rem 1.125rem 0;
}
.mm-solo-line > svg { flex: none; }
.mm-solo-link {
  font: inherit;
  font-weight: 600;
  color: var(--heading);
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  text-decoration: underline;
  text-decoration-color: var(--gold);
  text-underline-offset: 0.2em;
}
.mm-solo-link:hover { text-decoration-thickness: 2px; }
.mm-solo-link:disabled { opacity: .5; cursor: not-allowed; }

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

/* ══════════════════════════════════════════════════════════════════════════
   MATCHMAKING - INLINE HUB (variant A). Replaces the poster grid on the home board
   instead of opening as an overlay. Reuses .mm-action-cards / .mm-lobby /
   .mm-empty / .mode-pill-header / .mm-header-code; only the bar and hero are new.
   ══════════════════════════════════════════════════════════════════════════ */
.mm-inline-bar {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-wrap: wrap;
  margin-bottom: 1rem;
}
.mm-back {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-family: 'Rye', cursive;
  font-size: 0.8125rem;
  letter-spacing: .04em;
  cursor: pointer;
  min-height: 40px;                 /* WCAG 2.5.8: target size */
  padding: 0.5rem 1rem;
  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;
}
@media (hover: hover) {
  .mm-back:hover { border-color: var(--gold); color: var(--heading); background: var(--surface-hover); }
}
.mm-back-arrow { font-size: 1rem; line-height: 1; }
.mm-inline-tools {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  margin-left: auto;
  flex-wrap: wrap;
}
/* The mode pill brings its own margin-left:8px - inside the tools flex the gap handles it. */
.mm-inline-tools .mode-pill-header { margin-left: 0; }

@media (max-width: 560px) {
  .mm-inline-tools { margin-left: 0; width: 100%; }
}

/* ══════════════════════════════════════════════════════════════════════════
   HEADER - direct code join in the slot right of the brand
   (visible when not in a lobby and not in a game; otherwise .nav-lobby-pill
   sits there, or nothing). Styled as a compact pill - same height and visual
   language as .nav-lobby-pill, so that the slot looks consistent no matter
   which content it holds.
   ══════════════════════════════════════════════════════════════════════════ */
.header-code-form {
  display: inline-flex;
  align-items: stretch;            /* icon/input/button all the same height */
  gap: 0;
  margin-left: 0.875rem;               /* 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;
}
@media (hover: hover) {
  .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 0.375rem 0 0.625rem;
  font-size: 0.875rem;
  line-height: 1;
  color: var(--text-dim);
  user-select: none;
}
.header-code-input {
  background: transparent;
  border: none;
  color: var(--text-main);
  padding: 0.375rem 0.625rem 0.375rem 0.25rem;
  width: 92px;
  text-align: center;
  text-transform: uppercase;
  letter-spacing: 2px;
  font-size: 0.8125rem;
  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 0.75rem;
  cursor: pointer;
  font-size: 0.875rem;
  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: 0.625rem; }
  .header-code-icon { padding: 0 0.25rem 0 0.5rem; font-size: 0.8125rem; }
  .header-code-input { width: 78px; padding: 0.375rem 0.5rem 0.375rem 0.25rem; }
  .header-code-go { padding: 0 0.625rem; }
}

/* ══════════════════════════════════════════════════════════════════════════
   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: 0.75rem;
  padding: 0.4375rem 0;
}
.slider-row .sr-label {
  flex: 0 0 128px;
  color: var(--smoke);
  font-size: 0.8125rem;
  /* 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: 0.875rem;
  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: -0.125rem 0 0.375rem;
  padding-left: 8.75rem;
  color: var(--smoke);
  font-size: 0.75rem;
}
.slider-cap-note a, .slider-cap-note a:visited { color: var(--heading); text-decoration: underline; }   /* inline links in form notes: theme ink, never the browser's visited purple */
/* 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: 0.25rem 0.75rem;
  }
  .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: 0.4375rem;
}
/* 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: 0.875rem;
  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: 0.75rem;
  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: 0.75rem;
  padding: 0.4375rem 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: 0.8125rem;
}
.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: 0.875rem;
  align-items: flex-start;
  margin-bottom: 1rem;
  padding-bottom: 1rem;
  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: 2.25rem;
  background: radial-gradient(circle at 35% 30%, var(--warm-wood), var(--ink));
}
.tdm-hero-text { flex: 1; min-width: 0; }
.tdm-artist {
  font-size: 1.125rem; color: var(--heading);
  overflow-wrap: anywhere;
}
.tdm-title {
  font-size: 0.9375rem; color: var(--parchment);
  margin-top: 0.125rem; overflow-wrap: anywhere;
}
.tdm-album {
  font-size: 0.75rem; color: var(--smoke); font-style: italic;
  margin-top: 0.375rem; overflow-wrap: anywhere;
}
.tdm-grid {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.5rem 1rem;
  font-size: 0.8125rem;
}
.tdm-label {
  color: var(--smoke);
  text-transform: uppercase;
  letter-spacing: .05em;
  font-size: 0.75rem;
  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: 0.125rem 0.5rem;
  font-size: 0.75rem;
  color: var(--heading);
}
.tdm-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 1.125rem;
}
.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; }
@media (hover: hover) {
  .track-clickable:hover { color: var(--heading); }
}

/* ── Profile: favorites section ───────────────────────────────────────────── */
.profile-fav-count { font-size: 0.75rem; color: var(--smoke); font-weight: normal; }
.profile-fav-list { display: flex; flex-direction: column; }
.profile-fav-row {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  padding: 0.5rem 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: 0.625rem;
  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: 1rem;
  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: 0.8125rem; color: var(--heading);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.profile-fav-title {
  font-size: 0.75rem; 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: 0.375rem;
  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 0.625rem;
  display: inline-flex; align-items: center; justify-content: center;
  font-family: inherit; font-size: 0.8125rem; 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);
}
@media (hover: hover) {
  .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: 0.25rem; flex-wrap: wrap; padding: 0.875rem 0 0.125rem;
}
.admin-pager-info { font-size: 0.75rem; color: var(--smoke); margin-left: 0.375rem; }
.lot-page-btn {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 32px; height: 32px; padding: 0 0.5rem;
  background: var(--surface-1); border: 1px solid var(--border-soft);
  color: var(--text-dim); font-size: 0.8125rem; border-radius: 3px;
  cursor: pointer; transition: all .2s;
}
@media (hover: hover) {
  .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(--heading);
}

.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: 0.8125rem;
}
.profile-fav-paging {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.875rem;
  margin-top: 0.75rem;
  padding-top: 0.625rem;
  border-top: 1px solid rgba(200, 146, 42, .12);
}
.profile-fav-page-info { font-size: 0.75rem; 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: 0.75rem; 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 0.3125rem;
  font-family: Georgia, serif;
  font-size: 0.75rem;
  font-weight: bold;
  color: #1a0f06;
  background: var(--gold-light);
  border-radius: 9px;
  vertical-align: middle;
}
.profile-section-subtle {
  font-size: 0.75rem;
  color: var(--smoke);
  font-weight: normal;
  margin-left: 0.25rem;
}

/* 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 0.25rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: Georgia, serif;
  font-size: 0.75rem;
  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: 0.75rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  margin: 1rem 0 0.25rem;
}
.friend-group-label:first-of-type { margin-top: 0.375rem; }

.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: 0.5rem 0.6875rem;
  padding: 0.625rem 0.125rem;
  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: 0.84375rem;
  color: var(--parchment);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.friend-row-meta { color: var(--smoke); font-size: 0.75rem; margin-top: 0.125rem; line-height: 1.35; }
.friend-row-acts {
  display: flex;
  gap: 0.4375rem;
  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: 0.75rem; }

/* ── 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: 0.3125rem; color: var(--gold); }
.team-member-presence { display: block; font-size: 0.75rem; margin-top: 0.125rem; color: var(--smoke); }

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

/* Friendship block in PlayerProfileModal. */
.player-profile-friend { margin-top: 0.25rem; }
.player-profile-friend .alert-error { margin-bottom: 0.5rem; }
.player-profile-friend-state {
  color: var(--success);
  font-size: 0.8125rem;
  margin-bottom: 0.5rem;
}
.player-profile-friend-q {
  color: var(--smoke);
  font-size: 0.78125rem;
  align-self: center;
  margin-right: 0.125rem;
}
.player-profile-team-link {
  color: var(--heading);
  text-decoration: underline dotted;
  text-underline-offset: 2px;
}
@media (hover: hover) {
  .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: -0.0625rem;
  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: 1rem;
  background: var(--surface-1);
  border: 1px solid var(--border-soft);
  border-radius: 4px;
  padding: 0.875rem 1.125rem;
  margin-bottom: 0.875rem;
}
.profile-id-avatar { flex-shrink: 0; }
.profile-id-main { min-width: 0; }
.profile-id-name { font-family: 'Rye', cursive; color: var(--heading); font-size: 1.25rem; line-height: 1.1; display: flex; align-items: center; gap: 0.375rem; }
.profile-id-meta { color: var(--text-dim); font-size: 0.78125rem; margin-top: 0.3125rem; }
.profile-id-team { color: var(--heading); text-decoration: underline dotted; text-underline-offset: 2px; }
@media (hover: hover) {
  .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: 1.125rem;
  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: 1.125rem;
  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: 1.125rem;
  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(--raw-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(--raw-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);
}

@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); }

@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: 1.125rem 1.25rem; }

/* ── 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: 0.75rem;
  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: 0.3125rem;
  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: 0.875rem; color: var(--parchment);
  max-width: min(108px, 100%); overflow: hidden; white-space: nowrap;
  display: inline-flex; align-items: center; justify-content: center; gap: 0.1875rem;
}
/* Long names end in an ellipsis inside the seat (the full name is the seat's title) instead of
   running into the neighbours — on a phone the seats are only 72px wide. */
.seat-name-t { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.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: 0.75rem; 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: 1.125rem;
  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); }   /* full ink: at .75 the label fell to 3.8:1 on light felts */

/* ── The Stage: audience (comfortable up to 10, dense crowd beyond that) ── */
.aud-cluster {
  display: flex; flex-wrap: wrap; gap: 0.375rem; margin-top: 0.75rem;
  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: 0.75rem; 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: 0.75rem; cursor: pointer;
}
@media (hover: hover) {
  .aud-more:hover { background: color-mix(in srgb, var(--accent) 18%, transparent); }
}

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

/* ── Chat: collapsible + privacy veil ── */
.chat-title-row { display: flex; align-items: center; justify-content: space-between; }
.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);
}
@media (hover: hover) {
  .chat-reopen:hover { border-color: var(--accent); color: var(--accent-light); }
}
.chat-reopen { width: 100%; text-align: center; padding: 0.75rem; border-style: dashed; border-radius: 4px; font-size: 0.875rem; }
.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); }
/* Stage hero: prop + 'On stage today' + game name as marquee */
.lobby-redesign .lobby-hero { padding: 0.75rem 1.375rem; }
.lobby-redesign .lobby-hero .buhne-eyebrow { font-size: 0.75rem; 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: 0.4375rem; font-family: 'Rye', cursive; font-size: 1.75rem; color: var(--accent-light); position: relative; z-index: 1; margin: 0.125rem 0 0.625rem; }
.lobby-redesign .lobby-hero .buhne-prop { font-size: 1.5rem; 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: 0.4375rem; 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: 0.375rem 2.75rem;
  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: 1.4375rem; }
.code-box-vis { position: absolute; left: 11px; top: 50%; transform: translateY(-50%); font-size: 0.8125rem; 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: 0.9375rem; line-height: 1; padding: 0.25rem;
  min-width: 24px; min-height: 24px;   /* WCAG 2.5.8 */
}
@media (hover: hover) {
  .code-box-eye:hover, .code-box-eye.is-on { color: var(--accent-strong); }
}
.lobby-hero .code-box-text { font-size: 1.5625rem; }
.lobby-hero .code-box { padding: 0.375rem 2.875rem; }

/* ── Mobile (≤700px): felt ellipse → compact felt card, seats wrap, boxes tighter ── */
@media (max-width: 700px) {
  /* Bottom clears the fixed footer, which wraps into two rows on the phone (67 px). */
  .screen-lobby.lobby-redesign { padding: 1rem 0.625rem 4.5rem; }
  .lobby-arena { padding: 0.625rem 0.75rem; }
  .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; align-content: center;
    gap: 0.875rem 0.5rem; padding: 0.75rem 0.5rem 0.875rem;
  }
  .lobby-table .radar { display: none; }
  /* The lobby takes the free height down to the footer (the rules of the maximised view):
     the felt grows, the seats stand centred, the start bar docks at the bottom instead of
     leaving a stretch of bare saloon under the panel. */
  .screen-lobby.lobby-redesign { display: flex; flex-direction: column; }
  .screen-lobby .lobby-frame { flex: 1 1 auto; display: flex; flex-direction: column; min-height: 0; }
  .screen-lobby .lobby-layout { flex: 1 1 auto; display: flex; flex-direction: column; min-height: 0; }
  .screen-lobby .lobby-arena { flex: 1 1 auto; display: flex; flex-direction: column; min-height: 0; }
  .screen-lobby .lobby-table .felt { flex: 1 1 auto; }
  /* The table prop row above the seats is empty on the phone: it goes, the seats move up. */
  .lobby-table .felt > .felt-center { display: none; }
  .player-progress { margin: 0.5rem 0 0.625rem; }
  /* The main action is the whole bar, not a small button on the right: full width, 44 px,
     the same for the wait banner of the fellow players; a start reason gets its own row. */
  .lobby-actions-row .lobby-actions-start { margin-left: 0; flex: 1 1 100%; width: 100%; min-height: 44px; padding: 0.625rem 1rem; font-size: 0.875rem; text-align: center; }
  .lobby-actions-row .lobby-start-reason { margin-left: 0; flex-basis: 100%; }
  .lobby-actions-row .waiting-banner-sidebar.lobby-actions-start { margin: 0; }
  /* .felt > : one step stronger than the base .lobby-table .felt-center rule further down
     (position: absolute, centred) — at equal strength that rule won on order and put the
     table prop on top of the seat row. */
  .lobby-table .felt > .felt-center { position: static; transform: none; width: 100%; flex-basis: 100%; margin-bottom: 0.125rem; }
  .lobby-table .seat { position: static; transform: none; width: 72px; }
    @media (hover: hover) {
    .lobby-table .seat-filled:hover {
      transform: scale(1.04);
    }
  }
  .code-box { padding: 0.375rem 2.25rem; }
  .code-box-text, .lobby-hero .code-box-text { font-size: 1.3125rem; }
  .lobby-hero .code-box { padding: 0.375rem 2.375rem; }
  .lobby-redesign .lobby-hero .buhne-game { font-size: 1.5rem; }
  .lobby-redesign .lobby-hero .buhne-prop { font-size: 1.3125rem; }
  .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: 0.5625rem; text-align: center; z-index: 1;
}
.lobby-table .felt-code {
  font-size: 1.375rem; letter-spacing: .28em; padding: 0.375rem 1.125rem; 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: 0.5rem; }
.lobby-redesign .lobby-head-slim { padding: 0.5625rem 1.375rem; background: var(--surface-2); }
.lobby-redesign .lobby-head-slim .lobby-title { font-size: 1.125rem; }

/* ── 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: 0.75rem;
  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: 0.5625rem; 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: 0.5rem; }
.lobby-uh .uh-pill   { display: inline-flex; align-items: center; gap: 0.5625rem; 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: 1rem;
  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: 1.125rem; 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: 0.5rem; }
.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: 0.9375rem; line-height: 1; transition: background .15s;
}
@media (hover: hover) {
  .lobby-uh .uh-icon-btn:hover { background: color-mix(in srgb, var(--accent) 18%, transparent); }
}
.lobby-uh .uh-help { font-weight: 700; }
[data-theme="vividlight"] .lobby-uh .uh-name { color: #2a2d42; }   /* heading and body ink: 4.3 : 1 at the header's worst stop */
/* In a phone-wide header the row squeezed the buttons to 22 px: they keep the width a target needs. */
.lobby-uh .uh-icon-btn { flex-shrink: 0; min-width: 24px; }
.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);
}
@media (hover: hover) {
  .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;
}
/* ☰ app menu (game page): only shown on portrait phones, where the app header is
   hidden — see the portrait block at the end of this file. The dot and the
   screen-reader note appear while an announcement is set. */
.lobby-uh .uh-menu { display: none; font-size: 1.0625rem; }
.lobby-uh .uh-menu-dot {
  display: none; position: absolute; top: -4px; right: -4px; width: 11px; height: 11px;
  border-radius: 50%; background: var(--gold); border: 2px solid #140d07;
}
.lobby-uh .uh-menu-note {
  display: none; position: absolute; width: 1px; height: 1px; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap;
}
/* ☰ app menu of a PageFrame page that opts in (Admin): the same idea as the game
   page — on a portrait phone the app header is dropped and the ☰ brings it back as
   an overlay (portrait block at the end of this file). Hidden everywhere else. */
.pf-menu {
  display: none; position: relative; align-items: center; justify-content: center;
  width: 2.25rem; height: 2.25rem; padding: 0; flex-shrink: 0;
  border: 1px solid var(--pf-border); border-radius: 6px;
  background: color-mix(in srgb, var(--accent) 18%, transparent);
  color: var(--heading); font-size: 1.0625rem; cursor: pointer;
}
.pf-menu:focus-visible { outline: 3px solid var(--text-main); outline-offset: 2px; }
.pf-menu-dot {
  display: none; position: absolute; top: -4px; right: -4px; width: 11px; height: 11px;
  border-radius: 50%; background: var(--gold); border: 2px solid #140d07;
}
.pf-menu-note {
  display: none; position: absolute; width: 1px; height: 1px; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap;
}
.app-hdr-scrim { display: none; }
@keyframes appHdrDrop {
  from { transform: translateY(-100%); }
  to   { transform: none; }
}
@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: 0.4375rem; font-family: var(--font-body); font-size: 0.8125rem;
  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: 0.4375rem 0.6875rem; white-space: nowrap; transition: background .15s;
}
@media (hover: hover) {
  .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: 0.4375rem; 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-ink); }
@media (hover: hover) {
  .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-scheme="light"] .lobby-uh .uh-icon-btn:not(.uh-help):not(.uh-leave),
[data-scheme="light"] .lobby-uh .uh-gear span[aria-hidden="true"],
[data-scheme="light"] .lobby-uh .code-box-vis,
[data-scheme="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) */
/* Team choice in the lobby: the team numbers above the portrait at the seat. The felt is dark
   in every theme, so the control takes the seat's own ink (--parchment). */
.lobby-table .seat-with-team { gap: 0.25rem; }
.seat-inner { display: flex; flex-direction: column; align-items: center; gap: 0.3125rem; width: 100%; text-align: center; }
@media (hover: hover) { .seat-inner.seat-filled:hover { transform: scale(1.06); } }
.seat-team { display: inline-flex; flex: none; border: 1px solid var(--border-strong); border-radius: 0.375rem; overflow: hidden; background: rgba(0,0,0,.5); }
.seat-team-btn { min-width: 2.125rem; height: 1.75rem; padding: 0 0.375rem; border: 0; background: transparent; color: var(--parchment); font: 700 0.875rem/1 var(--font-body); font-variant-numeric: tabular-nums; cursor: pointer; }
.seat-team-btn + .seat-team-btn { border-left: 1px solid var(--border-strong); }
.seat-team-btn.on { background: linear-gradient(135deg, var(--btn-gold-start, var(--amber)), var(--btn-gold-end, var(--gold))); color: var(--btn-gold-ink, var(--shadow)); }
.seat-team-btn:focus-visible { outline: 2px solid currentColor; outline-offset: -3px; }
.seat-team-ro { padding: 0.25rem 0.5rem; color: var(--parchment); font: 700 0.8125rem/1.2 var(--font-body); white-space: nowrap; }
.team-sizes { display: flex; flex-wrap: wrap; gap: 0.375rem; justify-content: center; align-items: center; margin-top: 1.875rem; }
.team-chip { font-family: var(--font-body); font-size: 0.75rem; font-variant-numeric: tabular-nums; padding: 0.125rem 0.5rem; border: 1px solid var(--border-soft); border-radius: 999px; color: var(--text-main); }
.team-sizes-warn { font-size: 0.875rem; font-weight: 600; color: var(--red-ink, var(--danger)); }
.lobby-start-reason { margin-left: auto; font-size: 0.8125rem; color: var(--red-ink, var(--danger)); }
.lobby-start-reason + .lobby-actions-start { margin-left: 0; }

.lobby-actions { display: flex; flex-direction: column; gap: 0.625rem; }
.lobby-actions-row { display: flex; align-items: center; gap: 0.5625rem; 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: 0.375rem 1.125rem; font-size: 0.75rem; }
/* 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: 0.75rem 1rem;
}

/* ── Duel table: the lobby of the two-player games (DuelTable.razor) ──
   A wooden table seen from above with a Windsor chair on each side instead of the felt. The table
   is an OBJECT like the arcade cabinet: one walnut in every dark theme, one daylight oak in every
   light one; only its rim follows the theme (--felt-rim, gold in high contrast). Name plates stand
   beside the chairs on the card, so they keep the card's text inks. Sizes: --cw chair, --tw/--th
   table, --cp centre piece. */
.lobby-duel {
  --wood-a: #6d4829; --wood-b: #56381c; --wood-seam: rgba(18, 9, 2, .55);
  --wood-grain-l: rgba(255, 220, 170, .05); --wood-grain-d: rgba(0, 0, 0, .08); --wood-side: #2c1b0b;
  --wood-rim: color-mix(in srgb, var(--felt-rim) 70%, #56381c);
  --chair-a: #58391f; --chair-b: #402815; --chair-edge: #22150a;
  --lamp-glow: rgba(255, 196, 110, .20); --table-shadow: 0 24px 34px rgba(0, 0, 0, .5); --item-shadow: rgba(0, 0, 0, .45);
}
[data-scheme="light"] .lobby-duel {
  --wood-a: #bf9160; --wood-b: #a4784a; --wood-seam: rgba(80, 48, 20, .42);
  --wood-grain-l: rgba(255, 240, 215, .10); --wood-grain-d: rgba(90, 55, 20, .08); --wood-side: #6f4b2b;
  --wood-rim: color-mix(in srgb, var(--felt-rim) 70%, #a4784a);
  --chair-a: #93673d; --chair-b: #76512e; --chair-edge: #4d3219;
  --lamp-glow: rgba(255, 214, 140, .24); --table-shadow: 0 18px 26px rgba(80, 55, 30, .30); --item-shadow: rgba(60, 35, 10, .35);
}
[data-theme="contrast"] .lobby-duel { --wood-rim: var(--felt-rim); --wood-seam: rgba(0, 0, 0, .75); --chair-edge: var(--felt-rim); }
.duel-scene {
  --cw: 88px; --tw: 600px; --th: 240px; --cp: 150px;
  display: flex; flex-direction: column; align-items: center; gap: 0.375rem; padding: 0.5rem 0 0.625rem;
}
.duel-row { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; column-gap: 0.875rem; width: 100%; }
.duel-chair { position: relative; width: var(--cw); display: flex; flex-direction: column; align-items: center;
  filter: drop-shadow(0 6px 7px var(--item-shadow)); }
.duel-row.bottom .duel-chair { flex-direction: column-reverse; }
/* Windsor chair from above: a curved bow with spindles behind the seat. */
.duel-back { position: relative; z-index: 1; width: 100%; height: calc(var(--cw) * .3); margin-bottom: calc(var(--cw) * -.08);
  border: calc(var(--cw) * .07) solid var(--chair-a); border-bottom: 0; border-radius: 50% 50% 0 0 / 100% 100% 0 0;
  box-shadow: 0 -1px 0 1px var(--chair-edge);
  background: repeating-linear-gradient(90deg, transparent 0 calc(var(--cw) * .09), var(--chair-b) calc(var(--cw) * .09) calc(var(--cw) * .12)); }
.duel-row.bottom .duel-back { margin: calc(var(--cw) * -.08) 0 0; border: calc(var(--cw) * .07) solid var(--chair-a); border-top: 0;
  border-radius: 0 0 50% 50% / 0 0 100% 100%; box-shadow: 0 1px 0 1px var(--chair-edge); }
.duel-seat { width: 88%; height: calc(var(--cw) * .74); border-radius: 14px 14px 18px 18px; border: 2px solid var(--chair-edge);
  background: radial-gradient(70% 60% at 50% 45%, color-mix(in srgb, var(--chair-a) 88%, #fff), var(--chair-b)); }
.duel-row.bottom .duel-seat { border-radius: 18px 18px 14px 14px; }
.duel-av, .duel-ghost { position: absolute; left: 50%; z-index: 2; transform: translate(-50%, -50%); border-radius: 50%; }
.duel-row.top .duel-av, .duel-row.top .duel-ghost { top: calc(var(--cw) * .59); }
.duel-row.bottom .duel-av, .duel-row.bottom .duel-ghost { top: calc(var(--cw) * .37); }
.duel-av { display: flex; padding: 0; border: 2px solid var(--raw-parchment); background: none; cursor: pointer; line-height: 0;
  box-shadow: 0 2px 6px rgba(0, 0, 0, .45); transition: transform .12s; }
.duel-av.is-host { border-color: var(--raw-gold-light); box-shadow: 0 0 0 2px color-mix(in srgb, var(--raw-gold) 55%, transparent), 0 2px 6px rgba(0, 0, 0, .45); }
.duel-av.is-away { opacity: .55; }
@media (hover: hover) {
  .duel-av:hover { transform: translate(-50%, -50%) scale(1.06); }
}
.duel-ghost { width: 44px; height: 44px; display: flex; align-items: center; justify-content: center;
  border: 1.5px dashed #e0cfa8; color: #e0cfa8; font-size: 1.125rem; background: rgba(0, 0, 0, .18); }
.duel-plate { display: flex; flex-direction: column; align-items: flex-start; gap: 0.1875rem; min-width: 0; }
.duel-name { display: inline-flex; align-items: center; gap: 0.25rem; max-width: 100%; font-size: 0.875rem; font-weight: 600; color: var(--text-main); }
.duel-name-t { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.duel-name.is-free { color: var(--text-dim); font-weight: 500; font-style: italic; }
.duel-star { color: var(--gold-ink); }
.duel-you { font-size: 0.75rem; letter-spacing: .12em; text-transform: uppercase; color: var(--text-dim); }
.duel-table { position: relative; width: var(--tw); max-width: 100%; height: var(--th); margin-bottom: 0.5rem;
  border-radius: 12px; border: 5px solid var(--wood-rim);
  background:
    radial-gradient(55% 75% at 10% 14%, var(--lamp-glow), transparent 70%),
    repeating-linear-gradient(180deg, transparent 0 45px, var(--wood-seam) 45px 47px),
    repeating-linear-gradient(177deg, var(--wood-grain-l) 0 2px, transparent 2px 9px, var(--wood-grain-d) 9px 10px, transparent 10px 17px),
    linear-gradient(180deg, var(--wood-a), var(--wood-b));
  box-shadow: 0 8px 0 var(--wood-side), var(--table-shadow); }
.duel-it { position: absolute; line-height: 0; filter: drop-shadow(0 4px 4px var(--item-shadow)); }
.duel-it svg { display: block; width: 100%; height: auto; }
.duel-cp { left: 50%; top: 50%; width: var(--cp); transform: translate(-50%, -50%) rotate(-3deg); }
.duel-cp.wide { width: calc(var(--cp) * 1.45); }
.duel-sheet { width: calc(var(--cp) * .72); left: 44%; }
.duel-sheet.me { bottom: 5%; transform: translateX(-50%) rotate(-4deg); }
.duel-sheet.opp { top: 5%; transform: translateX(-50%) rotate(176deg); }
.duel-pencil { width: calc(var(--cp) * .42); }
.duel-pencil.me { left: calc(44% + var(--cp) * .4); bottom: 14%; transform: rotate(-58deg); }
.duel-pencil.opp { right: calc(56% + var(--cp) * .4); top: 14%; transform: rotate(122deg); }
.duel-bell { right: 13%; top: 50%; width: calc(var(--cp) * .22); transform: translateY(-50%); }
.duel-lamp { left: 3.5%; top: 8%; width: calc(var(--cp) * .28); filter: drop-shadow(0 0 12px rgba(255, 200, 120, .55)); }
.duel-glass { width: calc(var(--cp) * .17); }
.duel-glass.me { right: 15%; bottom: 9%; }
.duel-glass.opp { left: 17%; top: 8%; }
.duel-chalk { left: calc(50% + var(--cp) * .56); top: 62%; width: calc(var(--cp) * .2); transform: rotate(18deg); }
.duel-x { stroke: var(--x-color); }
.duel-o { stroke: var(--o-color); }
.duel-mj { left: 50%; width: calc(var(--cp) * 1.25); }
.duel-mj.me { bottom: 6%; transform: translateX(-50%); }
.duel-mj.opp { top: 6%; transform: translateX(-50%) rotate(180deg); }
.duel-mj text { font-family: 'Noto Sans SC', 'Microsoft YaHei', 'PingFang SC', sans-serif; }
/* Mühle: each player's nine stones heaped beside the board, opposite the glasses. */
.duel-pile { width: calc(var(--cp) * .3); }
.duel-pile.me { left: 15%; bottom: 10%; }
.duel-pile.opp { right: 15%; top: 10%; }
/* Phone: smaller chairs and centre piece, the table takes the card width. Two seats need no progress
   line — the empty chair and "1 / 2" already say who is missing. */
@media (max-width: 700px) {
  .duel-scene { --cw: 74px; --tw: 100%; --th: 214px; --cp: 116px; }
  .lobby-duel .player-progress { display: none; }
}

/* ── Arcade cabinet: the race lobby of the real-time games ──
   A wooden saloon arcade machine instead of the felt table (ArcadeCabinet.razor). The cabinet,
   the highscore board and the notice board are OBJECTS — wood, brass and a dark screen in both
   themes; only the marquee glass and the screen ink take the game accent. Narrow: the cabinet
   alone, its screen switches between players and highscores. Wide (container ≥ 860 px): board
   left, cabinet centre, notice board right; in maximize they take the full panel height. */
.lobby-arcade { padding: 1rem 1rem 1.125rem;
  background-image: radial-gradient(90% 70% at 50% 100%, rgba(212, 98, 10, .10), transparent 70%); }
.arc-lobby { container-type: inline-size; }
.arc-lobby-grid { display: grid; grid-template-columns: minmax(0, 430px); justify-content: center; gap: 28px; }
.arc-lobby .cab-plaque { display: none; }
.cab { position: relative; display: flex; flex-direction: column; min-width: 0;
  --cab-ink: color-mix(in srgb, var(--accent-light) 82%, #fff); --cab-dim: #b9a88f; --cab-brass: #b98a3c;
  filter: drop-shadow(0 16px 26px rgba(0, 0, 0, .45)); }
/* Marquee: backlit parchment glass in the game colour, brass frame — warm, not neon. */
.cab-marquee { position: relative; padding: 14px 14px 10px; text-align: center; border-radius: 14px 14px 0 0;
  background: radial-gradient(120% 140% at 50% 0%, color-mix(in srgb, var(--accent-light) 50%, #f3e2b8) 0%,
              color-mix(in srgb, var(--accent-light) 30%, #e9d3a0) 62%, color-mix(in srgb, var(--accent) 45%, #6a4a22) 100%);
  border: 3px solid var(--cab-brass); border-bottom-width: 4px;
  box-shadow: inset 0 0 18px rgba(255, 236, 190, .35), 0 0 22px color-mix(in srgb, var(--accent-light) 25%, transparent); }
.cab-title { font: 400 26px/1.05 'Rye', serif; color: #2a1606; text-shadow: 0 1px 0 rgba(255, 240, 210, .6); letter-spacing: .03em; }
.cab-kind { margin-top: 3px; font-size: 12px; font-weight: 700; letter-spacing: .22em; text-transform: uppercase; color: #3a2410; }
.cab-bulbs { position: absolute; left: 10px; right: 10px; top: 4px; display: flex; justify-content: space-between; }
.cab-bulbs i { width: 5px; height: 5px; border-radius: 50%; background: #ffe7a8; box-shadow: 0 0 6px #ffd27a; opacity: .8; }
/* Wooden body with side shading */
.cab-body { position: relative; display: flex; flex-direction: column; gap: 10px; padding: 12px 14px 14px;
  background: linear-gradient(90deg, rgba(0, 0, 0, .35), transparent 8%, transparent 92%, rgba(0, 0, 0, .35)),
              repeating-linear-gradient(180deg, #5a3a1c 0 3px, #4d3117 3px 7px, #553619 7px 11px);
  border-left: 3px solid var(--cab-brass); border-right: 3px solid var(--cab-brass); }
.cab-bezel { padding: 8px; border-radius: 12px; background: linear-gradient(180deg, #1b140c, #0e0a06); border: 2px solid #2a1d10;
  box-shadow: inset 0 0 0 2px rgba(185, 138, 60, .35); }
.cab-screen { position: relative; border-radius: 10px; padding: 10px 12px 12px; color: #e8dcc0;
  background: radial-gradient(120% 100% at 50% 40%, color-mix(in srgb, var(--accent) 16%, #0d0a07), #070504);
  box-shadow: inset 0 0 30px rgba(0, 0, 0, .9), inset 0 0 60px color-mix(in srgb, var(--accent) 18%, transparent); }
.cab-screen::after { content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  background: repeating-linear-gradient(180deg, rgba(255, 255, 255, .035) 0 1px, transparent 1px 3px); }
/* Both tab panes share one grid cell, the hidden one only invisible — so the screen keeps
   the taller pane's height and START does not jump when switching tabs. */
.cab-screen { display: grid; grid-template-columns: minmax(0, 1fr); align-content: start; }
.cab-pane { grid-row: 2; grid-column: 1; }
.cab-pane[hidden] { display: block; visibility: hidden; }
.cab-tabs { grid-row: 1; display: flex; justify-content: center; gap: 6px; margin-bottom: 8px; }
.cab-tabs button { min-height: 28px; padding: 2px 12px; border-radius: 999px; border: 1px solid rgba(255, 255, 255, .16); background: none;
  font: inherit; font-size: 12px; letter-spacing: .12em; text-transform: uppercase; color: var(--cab-dim); cursor: pointer; }
.cab-tabs button.on { color: var(--cab-ink); border-color: var(--cab-ink); }
.cab-scr-head { display: flex; flex-direction: column; align-items: center; }
.cab-scr-h { text-align: center; font-size: 13px; font-weight: 700; letter-spacing: .3em; text-transform: uppercase; color: var(--cab-ink); }
.cab-scr-sub { margin-top: 1px; text-align: center; font-size: 12px; letter-spacing: .12em; text-transform: uppercase; color: var(--cab-dim); }
.cab-slots { list-style: none; margin: 8px 0 0; padding: 0; display: grid; gap: 4px; }
.cab-slot { width: 100%; min-height: 32px; display: flex; align-items: center; gap: 8px; padding: 4px 8px; border: 0; border-radius: 6px;
  background: rgba(255, 255, 255, .04); font: inherit; font-size: 13px; color: #e8dcc0; text-align: left; cursor: pointer; }
.cab-slots.many .cab-slot { min-height: 28px; padding-block: 2px; }
.cab-slot.free { color: var(--cab-dim); font-style: italic; cursor: default; }
button.cab-slot.share { cursor: pointer; }
.cab-slot.me { box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--cab-ink) 70%, transparent); }
.cab-slot.away { opacity: .6; }
.cab-pn { flex: none; width: 24px; font-size: 12px; font-weight: 700; font-style: normal; letter-spacing: .1em; color: var(--cab-ink); }
.cab-nm { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cab-star { color: #e8b84b; }
.cab-you, .cab-st { flex: none; font-size: 12px; font-style: normal; color: var(--cab-dim); }
.cab-slot.me .cab-you { color: var(--cab-ink); }
.cab-slot.share .cab-st { color: var(--cab-ink); text-decoration: underline; text-underline-offset: 2px; }
.cab-coin { flex: none; font-size: 14px; }
.cab-slot:focus-visible, .cab-tabs button:focus-visible { outline: 2px solid var(--cab-ink); outline-offset: 1px; }
@media (hover: hover) {
  button.cab-slot:hover { background: rgba(255, 255, 255, .09); }
  .cab-tabs button:hover { color: var(--cab-ink); }
}
.cab-need { margin-top: 8px; text-align: center; font-size: 12.5px; color: #f0b070; }
.cab-guest, .cab-empty { margin-top: 8px; text-align: center; font-size: 12.5px; color: var(--cab-dim); }
.cab-hs { width: 100%; margin-top: 8px; border-collapse: collapse; table-layout: fixed; font-size: 13px; font-variant-numeric: tabular-nums; }
.cab-hs td { padding: 2px 4px; color: #e8dcc0; }
.cab-hs td.p { width: 32px; color: var(--cab-dim); }
.cab-hs td.n { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cab-hs td.r { width: 72px; text-align: right; font-weight: 700; color: var(--cab-ink); }
.cab-hs tr.me td { background: color-mix(in srgb, var(--accent) 30%, transparent); color: #fff3d6; }
.cab-hs tr.me td:first-child { border-radius: 4px 0 0 4px; }
.cab-hs tr.me td:last-child { border-radius: 0 4px 4px 0; }
.cab-hs tr.gap td { padding: 0; line-height: 1; text-align: center; color: var(--cab-dim); }
/* Control deck: joystick and buttons are decoration, START is the real button. */
.cab-deck { display: flex; align-items: center; gap: 12px; padding: 10px 12px; border-radius: 10px;
  background: linear-gradient(180deg, #2d2014, #1a120a); border: 2px solid #2a1d10; box-shadow: inset 0 1px 0 rgba(255, 220, 160, .12); }
.cab-stick { position: relative; flex: none; width: 46px; height: 46px; border-radius: 50%;
  background: radial-gradient(circle, #120d08 55%, #2d2014 56%); border: 2px solid #0b0805; }
.cab-stick::before { content: ""; position: absolute; left: 50%; top: 50%; width: 8px; height: 26px; transform: translate(-50%, -85%);
  background: linear-gradient(90deg, #8a8278, #d6cfc4, #7a7268); border-radius: 4px; }
.cab-stick::after { content: ""; position: absolute; left: 50%; top: 50%; width: 22px; height: 22px; transform: translate(-50%, -150%);
  border-radius: 50%; background: radial-gradient(circle at 35% 30%, #ff8e7a, #a3261a); }
.cab-btns { flex: none; display: flex; gap: 7px; }
.cab-btns i { width: 22px; height: 22px; border-radius: 50%; box-shadow: 0 2px 0 #0b0805;
  background: radial-gradient(circle at 35% 30%, color-mix(in srgb, var(--accent-light) 80%, #fff), var(--accent)); }
.cab-start { flex: 1; min-width: 0; min-height: 52px; border: 0; border-radius: 26px; cursor: pointer;
  font: 400 17px 'Rye', serif; letter-spacing: .2em; text-transform: uppercase; color: #1b0f06;
  background: radial-gradient(circle at 50% 30%, #ffd48a, #d4620a); box-shadow: 0 4px 0 #6a2e08, 0 0 20px rgba(212, 98, 10, .35); }
.cab-start:disabled { cursor: not-allowed; color: #3a2a1a; background: radial-gradient(circle at 50% 30%, #a8927a, #6d5a45); box-shadow: 0 4px 0 #2f2418; }
.cab-start:focus-visible { outline: 3px solid #ffe7a8; outline-offset: 3px; }
.cab-start:not(:disabled):active { transform: translateY(2px); box-shadow: 0 2px 0 #6a2e08; }
@media (hover: hover) { .cab-start:not(:disabled):hover { filter: brightness(1.08); } }
.cab-wait { flex: 1; min-width: 0; min-height: 48px; display: flex; align-items: center; justify-content: center; padding: 4px 10px;
  border-radius: 8px; border: 1px solid rgba(200, 146, 42, .3); background: rgba(0, 0, 0, .25); color: #d8c7a8; font-size: 13px; text-align: center; }
.cab-error { margin: 0; }
.cab-foot { height: 14px; border-radius: 0 0 10px 10px; background: linear-gradient(180deg, #3a2612, #1f140a); border: 3px solid var(--cab-brass); border-top: none; }
/* Boards hung beside the cabinet (wide only) */
.cab-plaque { flex-direction: column; gap: 6px; min-width: 0; min-height: 0; overflow: auto; padding: 14px 16px; border-radius: 10px;
  background: repeating-linear-gradient(180deg, #3a2612 0 6px, #33210f 6px 12px); border: 3px solid #b98a3c; box-shadow: var(--elev-2);
  color: #f0e2c4; --cab-ink: #e8b84b; --cab-dim: #c9b48a; }
.cab-plaque h3 { margin: 0 0 4px; text-align: center; font: 400 18px 'Rye', serif; color: #e8b84b; }
.cab-sub { font-size: 12px; letter-spacing: .16em; text-transform: uppercase; color: #c9b48a; text-align: center; }
.cab-plaque .cab-hs { margin-top: 2px; font-size: 14px; }
.cab-plaque .cab-hs td { color: #f0e2c4; }
.cab-plaque .cab-hs td.r { color: #e8b84b; }
.cab-plaque .cab-hs tr.me td { color: #fff3d6; }
.cab-hr { height: 1px; margin: 8px 0; background: rgba(230, 194, 122, .3); }
.cab-plaque dl { display: grid; grid-template-columns: auto 1fr; gap: 6px 12px; margin: 0; font-size: 14px; }
.cab-plaque dt { color: #c9b48a; }
.cab-plaque dd { margin: 0; text-align: right; font-weight: 600; }
.cab-plaque p { margin: 0; font-size: 14px; line-height: 1.5; }
.cab-plaque p.cab-note { font-size: 13px; color: #c9b48a; text-align: center; }
.cab-grow { flex: 1; }
/* Phone: header, lobby head and the fixed footer leave ~450 px — marquee, screen head, slots and
   deck tighten so START sits above the footer without scrolling (6 seats at 390 × 749). The
   marquee drops its "arcade · race" line, the screen says "race" already. */
@media (max-width: 760px) {
  .lobby-arcade { padding: 10px 10px 12px; }
  .cab-marquee { padding: 10px 12px 7px; }
  .cab-title { font-size: 22px; }
  .cab-kind { display: none; }
  .cab-body { gap: 8px; padding: 8px 10px 10px; }
  .cab-bezel { padding: 6px; }
  .cab-screen { padding: 8px 10px 10px; }
  .cab-scr-head { flex-direction: row; flex-wrap: wrap; justify-content: center; align-items: baseline; gap: 2px 10px; }
  .cab-slots { gap: 3px; margin-top: 6px; }
  .cab-slot, .cab-slots.many .cab-slot { min-height: 28px; padding-block: 2px; }
  /* 7–8 seats: two columns (P1–P4 left), the coin gives way to the name. */
  .cab-slots.many { grid-template-columns: 1fr 1fr; grid-template-rows: repeat(4, auto); grid-auto-flow: column; }
  .cab-slots.many .cab-slot { gap: 6px; padding-inline: 6px; }
  .cab-slots.many .cab-coin { display: none; }
  .cab-slots.many .cab-pn { width: 20px; }
  .cab-need, .cab-guest, .cab-empty { margin-top: 6px; }
  .cab-deck { padding: 7px 10px; }
  .cab-stick { width: 40px; height: 40px; }
  .cab-start { min-height: 46px; }
  .cab-wait { min-height: 44px; }
  .cab-foot { height: 10px; }
}
@container (min-width: 860px) {
  .arc-lobby-grid { grid-template-columns: minmax(0, 520px) minmax(220px, 300px); align-items: stretch; }
  .arc-lobby-grid.has-board { grid-template-columns: minmax(220px, 300px) minmax(0, 520px) minmax(220px, 300px); }
  .arc-lobby .cab-plaque { display: flex; }
  /* Wide: the boards hang beside the cabinet, so its screen always shows the players. */
  .cab-tabs, .cab-pane-scores, .cab-pane-scores[hidden] { display: none; }
  .cab-pane-players[hidden] { visibility: visible; }
}

/* 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, visibility 0s .24s;
  display: flex; flex-direction: column;
  /* Closed means out of the tab order too: off-screen controls must not take the focus. */
  visibility: hidden;
}
.chat-drawer.open { transform: translateX(0); visibility: visible; transition: transform .24s ease, visibility 0s; }

/* Head: dark wooden bar with a parchment title */
.chat-drawer-head { display: flex; align-items: center; gap: 0.5rem; padding: 0.75rem 0.9375rem;
  background: linear-gradient(180deg, #3a2913, #2c1e10); border-bottom: 2px solid var(--tg-wood); }
.chat-drawer-head .chat-title { flex: 1; color: var(--raw-gold-light); }
.chat-drawer-close { background: transparent; border: none; color: #d9c39a; cursor: pointer; font-size: 1rem; line-height: 1; padding: 0.25rem; min-width: 24px; min-height: 24px; }
@media (hover: hover) {
  .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: 0.75rem; gap: 0.375rem;
  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); }   /* at 80 % opacity the time measured 3.6 : 1 */

/* Nachricht als Telegramm-Zettel */
.chat-drawer .chat-msg { background: var(--tg-slip); border: 1px solid #cdb98c; border-radius: 6px;
  padding: 0.3125rem 0.5625rem; 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); }
/* Light-theme stage 2 side finding: #9a865f fell to 3.2:1 on the brightest paper stop. */
.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); }

/* Input + send on parchment */
.chat-drawer .chat-input-row { padding: 0.6875rem 0.75rem; 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; }
@media (hover: hover) {
  .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: 1.25rem;
  display: flex; flex-direction: column; align-items: center; gap: 0.5rem; }
.chat-drawer .chat-empty-glyph { font-size: 2.125rem; line-height: 1; opacity: .85; }
.chat-drawer .chat-empty-title { font-size: 0.875rem; font-style: italic; color: #5a4321; }
.chat-drawer .chat-empty-hint { font-size: 0.75rem; 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: 0.25rem;
  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: 0.8125rem; 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: 1rem; 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: 0.625rem 1.125rem; padding: 0 3.625rem 1.5rem; }
.stage-perf { background: transparent; border: none; cursor: pointer; display: flex; flex-direction: column; align-items: center; gap: 0.3125rem; 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: 0.8125rem; color: color-mix(in srgb, var(--accent) 30%, var(--text-main)); text-shadow: 0 1px 2px var(--shadow-color); }
.stage-perf-nm { font-size: 0.75rem; color: var(--parchment); white-space: nowrap; max-width: 108px; overflow: hidden; text-overflow: ellipsis; display: inline-flex; align-items: center; justify-content: center; gap: 0.1875rem; }
.stage-perf-you { color: var(--text-main); font-weight: 600; }
.stage-perf-free { align-self: flex-end; margin-bottom: 0.5rem; font-size: 0.75rem; color: var(--text-main); opacity: .8; font-style: italic; border: 1px dashed rgba(200,146,42,.25); border-radius: 20px; padding: 0.375rem 0.75rem; }
.stage-aud { position: relative; z-index: 6; margin: 0; padding: 0.875rem 3.375rem 1.5rem; justify-content: center; }

/* ════════════════════════════════════════════════════════════════════════════
   SS - project-wide button standard: uniform corner radius (soft, --btn-radius).
   ONE place for ALL real action buttons. .btn covers every .btn composition
   (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 ...); the remaining
   selectors are standalone buttons without the .btn base.
   DELIBERATELY EXCLUDED (these stay as they are): round icon/avatar buttons
   (.mute-btn/.header-help-btn/.profile-btn/.help-icon-btn = 50%), switches
   (.settings-toggle-btn), borderless text links (.btn-back-history) and chips/tags/pills.
   ════════════════════════════════════════════════════════════════════════════ */
.btn,
.btn-red, .btn-ghost-red, .chat-send-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);
}

/* Narrow windows: the centred code would run into the buttons on the right (it is centred on
   the header, not between its neighbours) - there it takes its place in the row instead. */
@media (max-width: 920px) {
  .lobby-uh .uh-center { position: static; transform: none; display: inline-flex; align-items: center; gap: 0.5rem; }
  .lobby-uh .uh-center .uh-copy { position: static; transform: none; margin-left: 0; }
}

/* Mobile: the lobby head in two rows - game pill left and the icon buttons right in the first,
   the code box with its copy button centred in the second (was three stacked rows, ~50 px
   more). The game screen has its own single-row rule below (<= 760 px portrait). */
@media (max-width: 700px) {
  .lobby-redesign .lobby-uh { flex-direction: row; flex-wrap: wrap; gap: 0.5rem 0.75rem; padding: 0.5rem 0.75rem; }
  .lobby-uh .uh-left { order: 1; min-width: 0; }
  .lobby-uh .uh-right { order: 2; margin-left: auto; flex-wrap: nowrap; justify-content: flex-end; gap: 0.25rem; }
  .lobby-uh .uh-center { order: 3; flex-basis: 100%; position: static; transform: none; display: inline-flex; align-items: center; justify-content: center; gap: 0.5rem; }
  .lobby-uh .uh-center .uh-copy { position: static; transform: none; margin-left: 0; }
}

/* ── Stage 2: signature prop in the felt centre per table game ── */
.lobby-table .tprop {
  display: flex; align-items: flex-end; justify-content: center; gap: 0.375rem;
  min-height: 44px; margin-bottom: 0.125rem; 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: 0.75rem;
  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: 2rem; 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: 0.8125rem; 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: 0.9375rem; }
.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: 1.5rem; line-height: 1; color: #f1e7d0; filter: drop-shadow(0 2px 4px #000);
  align-self: center; margin-left: 0.125rem; }
/* 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: 0.9375rem; 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: 1.125rem; margin-top: -0.25rem; }

/* 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); } }

/* ════════════════════════════════════════════════════════════
   Round-over cue - overlay above the frozen board in the
   RoundBreak state (Memory / Durak / Seeschlacht; ready to roll out further).
   position:fixed above the game, pointer-events:none (blocks nothing),
   z-index below header/toast/modal. Component: 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: 1.125rem; 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: 0.875rem 2.125rem; 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(1.875rem, 6vw, 3.25rem); }
.round-over-stamp .ro-sub {
  display: block; font-family: var(--font-body); font-weight: 700; letter-spacing: .18em;
  font-size: 0.8125rem; color: var(--raw-gold-light); margin-top: 0.375rem; 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: 0.9375rem; color: var(--parchment);
  background: rgba(0,0,0,.5); border: 1px solid var(--accent-light); border-radius: 999px;
  padding: 0.4375rem 1.125rem; 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: rising sparks (pairs settle) */
.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-ink); font-size: 1.625rem; 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: 1.5rem; 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: 0.5rem;
  padding: 0.4375rem 0.5rem;
  background: var(--input-bg);
  border: 1px solid var(--border);
  border-radius: 2px;
  color: var(--old-paper);
  font-size: 0.75rem;
  cursor: pointer;
  text-align: left;
}
@media (hover: hover) {
  .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: 0.75rem; }
.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: 0.5rem;
  padding: 0.5rem 0.625rem;
  cursor: pointer;
  color: var(--old-paper);
  border-bottom: 1px solid rgba(200,146,42,.08);
  font-size: 0.75rem;
}
.icon-select-opt:last-child { border-bottom: none; }
@media (hover: hover) {
  .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: 0.75rem; font-variant-numeric: tabular-nums; }
@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 (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; }
/* Turn list = subtle well section. */
.card-board .ss-panel .card-turn-list {
  background: var(--well);
  border: 1px solid var(--board-border);
  border-radius: 8px;
}
/* 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-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;
}
/* ── Schattenspiel / Undercover clue phase (Game.razor RenderPlaying, UndercoverPlaying) ──
   Mockup docs/mockups/schattenspiel-hud.html. Wide: the framed panel (list + input) left,
   role card and round card right, both centred. Narrow: a value line (role tag · round), the
   own word or category as one line, the list takes the rest and scrolls in itself, the input
   docks at the bottom. Role colours: impostor red, crew/citizen gold, the ghost blue-grey. */
.sh-layout { display: grid; grid-template-columns: minmax(0, 1fr) 300px; gap: 18px; width: 100%; max-width: 980px;
  margin: 0 auto; align-items: center; }
.sh-main { min-width: 0; }
.sh-vals, .sh-word { display: none; }
.sh-grow { flex: 1 1 auto; }
.sh-main .turn-row .t-name { background: none; border: 0; padding: 0; font: inherit; color: inherit; text-align: left; cursor: pointer; min-height: 24px; }   /* the name is a button: 21 px was below the target size */
.sh-main .turn-row .t-name.gold { color: var(--heading); }
.sh-out { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; margin-top: 8px; font-size: 12.5px; color: var(--smoke); }
.sh-out-nm { background: none; border: 0; padding: 0; font: inherit; color: var(--smoke); text-decoration: line-through; cursor: pointer; }
/* Input docked: field + send in one row, rules and clock below, the time bar last. */
.sh-dock { display: flex; flex-direction: column; gap: 6px; padding: 10px 12px; border-radius: 8px;
  background: var(--well); border: 1px solid var(--board-border); }
.sh-dock.red { border-color: rgba(139, 26, 26, .5); }
.sh-in { display: flex; gap: 8px; align-items: stretch; }
.sh-in .clue-input-wrap { flex: 1 1 auto; min-width: 0; margin: 0; }
.sh-in .btn { width: auto; flex: 0 0 auto; margin: 0; padding: 0 18px; }
.sh-send-short { display: none; }
.sh-meta { display: flex; align-items: center; gap: 8px; font-size: 12px; color: var(--smoke); }
.sh-meta .clue-timer-num { font-size: 13px; font-weight: 600; white-space: nowrap; }
/* Role card + round card (wide) */
.sh-side { display: flex; flex-direction: column; gap: 12px; min-width: 0; }
.sh-rc { container-type: inline-size; border-radius: 12px; padding: 14px 16px; box-shadow: var(--elev-1);
  background: var(--well); border: 1px solid var(--board-border); text-align: center; }
.sh-rc h4 { margin: 0 0 6px; font-family: 'Rye', serif; font-weight: 400; font-size: 16px; }
.sh-rc p { margin: 0; font-size: 13px; line-height: 1.45; color: var(--old-paper); }
.sh-rc .l { font-size: 12px; letter-spacing: .14em; text-transform: uppercase; color: var(--smoke); }
/* Long words: the size follows the letter count (--len) so the word stays on one line. */
.sh-rc .w { font-family: 'Rye', serif; color: var(--heading); white-space: nowrap; margin: 4px 0;
  letter-spacing: .06em; font-size: clamp(16px, calc(100cqw / (var(--len, 8) * .8)), 30px); }
.sh-rc.imp { text-align: left; background: color-mix(in srgb, #8b1a1a 20%, var(--well)); border-color: rgba(249, 107, 90, .45); }
.sh-rc.imp h4 { color: var(--red-ink); }
.sh-rc.imp .cat { margin-top: 10px; padding-top: 10px; border-top: 1px solid rgba(249, 107, 90, .3); font-size: 12px;
  letter-spacing: .14em; text-transform: uppercase; color: var(--smoke); }
.sh-rc.imp .cat b { display: block; font-family: 'Rye', serif; font-weight: 400; font-size: 22px; letter-spacing: .04em;
  text-transform: none; color: var(--heading); }
.sh-rc.crew, .sh-rc.civ { border-color: var(--gold-ink); }
.sh-rc.civ h4 { color: var(--heading); }
.sh-rc.ghost { border-color: rgba(174, 191, 204, .5); }
.sh-rc.ghost h4, .sh-rc.ghost .w { color: #aebfcc; }
.sh-rc.round { text-align: left; }
.sh-rc.round .v { font-family: 'Rye', serif; font-size: 28px; color: var(--heading); }
.sh-rc.round .timer-bar { margin-top: 6px; }
.sh-disc-tag { font-size: 12.5px; color: var(--accent-ink); }
/* The ghost's pale blue-grey is a dark-scheme ink; the light scheme gets a deep slate. */
[data-scheme="light"] :is(.sh-role.ghost, .sh-word.ghost .w, .sh-rc.ghost h4, .sh-rc.ghost .w) { color: #45596a; }
/* The impostor's plate is a red mid-tone in the light themes: the muted and the heading ink fall short on it. */
[data-scheme="light"] :is(.sh-word.imp, .sh-rc.imp) :is(.l, .w, .h, p, .cat) { color: var(--text-main); }
[data-scheme="light"] :is(.sh-role.imp, .sh-rc.imp h4) { color: #6e1212; }
[data-scheme="light"] .sh-rc .l { color: var(--text-main); }
[data-scheme="light"] :is(.sh-word.imp, .sh-rc.imp) { background: color-mix(in srgb, #8b1a1a 9%, var(--well)); }
@media (max-width: 760px) {
  .sh-layout { grid-template-columns: minmax(0, 1fr); gap: 8px; }
  .sh-side { display: none; }
  .sh-vals { display: flex; align-items: center; gap: 8px; }
  .sh-role { display: inline-flex; align-items: center; gap: 5px; padding: 3px 10px; border-radius: 999px; font-size: 12.5px; font-weight: 600; white-space: nowrap; }
  .sh-role.imp { color: var(--red-ink); background: color-mix(in srgb, #8b1a1a 22%, transparent); border: 1px solid color-mix(in srgb, var(--red-ink) 55%, transparent); }
  .sh-role.crew, .sh-role.civ { color: var(--heading); background: color-mix(in srgb, var(--gold) 14%, transparent); border: 1px solid color-mix(in srgb, var(--gold-ink) 60%, transparent); }
  .sh-role.ghost { color: #aebfcc; background: rgba(174, 191, 204, .1); border: 1px solid rgba(174, 191, 204, .5); }
  .sh-round { font-size: 13px; color: var(--old-paper); white-space: nowrap; }
  .sh-word { container-type: inline-size; position: relative; display: flex; align-items: center; gap: 10px; padding: 7px 12px; border-radius: 10px;
    background: var(--well); border: 1px solid var(--gold-ink); }
  .sh-word.imp { background: color-mix(in srgb, #8b1a1a 18%, var(--well)); border-color: rgba(249, 107, 90, .45); }
  .sh-word.ghost { border-color: rgba(174, 191, 204, .45); }
  .sh-word .l { flex: none; font-size: 12px; letter-spacing: .12em; text-transform: uppercase; color: var(--smoke); }
  .sh-word .w { min-width: 0; font-family: 'Rye', serif; color: var(--heading); letter-spacing: .05em; white-space: nowrap;
    font-size: clamp(14px, calc((100cqw - 120px) / (var(--len, 8) * .78)), 22px); }
  .sh-word.ghost .w { color: #aebfcc; }
  .sh-word .h { font-size: 12px; color: var(--smoke); text-align: right; }
  .sh-mission > summary { width: 26px; height: 26px; border-radius: 50%; display: grid; place-items: center; list-style: none; cursor: pointer;
    font-size: 13px; color: var(--old-paper); border: 1px solid var(--border); }
  .sh-mission > summary::-webkit-details-marker { display: none; }
  .sh-mission[open] > summary { color: var(--heading); border-color: var(--heading); }
  .sh-mission-pop { position: absolute; left: 0; right: 0; top: calc(100% + 4px); z-index: 5; padding: 10px 12px; border-radius: 10px;
    font-size: 13px; line-height: 1.45; color: var(--parchment); background: var(--surface-1);
    border: 1px solid rgba(249, 107, 90, .45); box-shadow: var(--elev-2); }
  .sh-dock { padding: 8px; }
  .sh-send-long { display: none; }
  .sh-send-short { display: inline; }
  .sh-meta > span:first-child { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
}
.role-pill { background: color-mix(in srgb, var(--accent) var(--chip-tint), transparent); border: 1px solid color-mix(in srgb, var(--accent) 45%, transparent);
  border-radius: 999px; padding: 0.25rem 0.75rem; font-size: 0.75rem; 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; }
.vtoken { display: inline-grid; place-items: center; font-size: 1.125rem; 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; }
/* The green card is a shade darker than the green of the oval sign (#3f8a52): white corner signs
   measured 4.2 : 1 on that, 4.8 on this. */
/* White corner signs measured 2.2 : 1 on the yellow; a dark ink holds 6 : 1 (the other three colours carry white). */
.ssk-card.c-yellow :is(.ssk-corner, .ssk-sign) { color: #3b2a05; text-shadow: none; }
.ssk-card.c-green  { background: #3a8050; } .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; }
/* White on the yellow reads 2.2 : 1 — the yellow button carries the dark ink of the yellow card. */
.ssk-cbtn.c-yellow { background: #d9a527; color: #2a1c00; text-shadow: none; }
.ssk-cbtn.c-green { background: #3a8050; } .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; }
  /* Board takes the full height beside the side column; the column docks at the top. */
  body.ss-maximized .mode-rausschmeisser .rsm-main { flex: 1 1 auto; min-height: 0; grid-template-rows: minmax(0, 1fr); align-items: stretch; }
  body.ss-maximized .mode-rausschmeisser .rsm-side { align-self: start; }
}
@keyframes rsm-vpulse { 0%, 100% { opacity: .35; } 50% { opacity: 1; } }   /* The prompt card stays dark (cinema pattern): --raw-* instead of --accent-light/mode tinting; applies to all dice games (Rausschmeisser+Boomtown share this class) */
   /* The prompt card stays dark (cinema pattern) */
@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: 1.875rem; color: var(--accent-ink);
    text-shadow: 0 3px 10px rgba(0,0,0,.7); }
/* 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: auto minmax(0, 1fr); align-items: stretch;
  }
  body.ss-maximized .mode-mahjong .mjg-sidebar { align-self: start; }

  /* Side arrangement: when the board is height-bound, fitMahjong moves the value row into
     the right column (above the race ranking, which is there anyway) and the board gets the
     full height. The choice is measured from .mjg-layout, whose size does not depend on it. */
  /* The right column starts flush with the wood well's top edge (a spacer row below takes
     the rest) and moves in by the free room fitMahjong reports (--mjg-free beside the board,
     --mjg-free-y above it), so it sits next to the board instead of at the far edge. */
  body.ss-maximized .mode-mahjong .mjg-layout[data-arr="side"] {
      grid-template-columns: minmax(0, 1fr) 250px; grid-template-rows: auto auto minmax(0, 1fr);
      grid-template-areas: "stage hud" "stage rail" "stage ."; row-gap: 10px;
  }
  body.ss-maximized .mode-mahjong .mjg-layout.solo[data-arr="side"] { grid-template-areas: "stage hud" "stage ." "stage ."; }
  /* The column overlaps the (positioned) stage wrap by --mjg-free, so it must stack above it —
     otherwise the wrap swallows clicks on the left part of the tool buttons. */
  body.ss-maximized .mode-mahjong .mjg-layout[data-arr="side"] > :is(.mjg-hud, .mjg-sidebar) {
      margin-left: calc(-1 * var(--mjg-free, 0px)); margin-right: var(--mjg-free, 0px);
      position: relative; z-index: 1;
  }
  body.ss-maximized .mjg-layout[data-arr="side"] .mjg-hud {
      align-self: start; margin-top: var(--mjg-free-y, 0px); flex-direction: column; align-items: stretch; gap: 10px;
      padding: 0; background: none; border: none; box-shadow: none;
  }
  body.ss-maximized .mjg-layout[data-arr="side"] .mjg-hud-stats {
      flex-direction: column; align-items: stretch; gap: 0; white-space: normal;
      padding: 14px 16px; background: var(--surface-1); border: 1px solid var(--card-edge);
      border-radius: 12px; box-shadow: var(--elev-1);
  }
  body.ss-maximized .mjg-layout[data-arr="side"] .mjg-hud-cap {
      display: block; font-size: 12px; letter-spacing: .18em; text-transform: uppercase; color: var(--smoke);
  }
  body.ss-maximized .mjg-layout[data-arr="side"] .mjg-hud-lay {
      font-family: 'Rye', cursive; font-size: 17px; color: var(--heading); margin: 2px 0 10px;
  }
  body.ss-maximized .mjg-layout[data-arr="side"] .mjg-hud-num { font-size: 34px; line-height: 1; }
  body.ss-maximized .mjg-layout[data-arr="side"] .mjg-hud-num small { font-size: 13px; margin-left: 6px; }
  body.ss-maximized .mjg-layout[data-arr="side"] .mjg-hud-bar {
      display: block; height: 6px; border-radius: 3px; background: var(--well); margin: 12px 0 5px; overflow: hidden;
  }
  body.ss-maximized .mjg-layout[data-arr="side"] .mjg-hud-bar i {
      display: block; height: 100%; background: linear-gradient(90deg, var(--accent), var(--accent-light));
  }
  body.ss-maximized .mjg-layout[data-arr="side"] .mjg-hud-sub { display: block; font-size: 12.5px; color: var(--smoke); }
  body.ss-maximized .mjg-layout[data-arr="side"] .mjg-hud-timer { margin-top: 10px; font-size: 15px; }
  body.ss-maximized .mjg-layout[data-arr="side"] .mjg-hud .mjg-tool {
      height: 40px; padding: 0 14px; gap: 8px; font-size: 14px;
  }
  body.ss-maximized .mjg-layout[data-arr="side"] .mjg-tool-cnt { margin-left: auto; }
}
@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; } }   /* The prompt card stays dark (cinema pattern): --raw-* instead of --accent-light/mode tinting */
   /* The prompt card stays dark (cinema pattern) */
@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: 1.875rem; 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; } }
@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: 1.875rem; 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(--focus-ring, var(--accent-strong)) !important; outline-offset: 2px; }   /* --focus-ring: optional own ring colour (Hoher Kontrast) */
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: 1.625rem 1.375rem 4.375rem;   /* 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;
  /* Head band = chrome tier (theme-aware, one step above the page), tinted with the
     page accent. Formerly mixed into --scrim (the overlay veil), which no theme
     overrides — the band stayed brown-black in every seasonal theme. */
  background: linear-gradient(180deg, color-mix(in srgb, var(--accent) 14%, var(--chrome)), var(--chrome));
  border: 1px solid var(--pf-border); border-bottom: none;
}
.pf-pageuh-top {
  position: relative; display: flex; align-items: center; justify-content: space-between;
  gap: 0.75rem; width: 100%; padding: 0.5625rem 1rem; flex-wrap: wrap;
}
.pf-title { display: flex; align-items: center; gap: 0.5625rem; font-family: 'Rye', cursive; color: var(--heading); font-size: 1rem; 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: 1rem;
  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: 0.375rem; }
.pf-tabs {
  display: flex; gap: 0.125rem; width: 100%; min-width: 0; padding: 0 0.75rem;
  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: 1.25rem 1.375rem;
  box-shadow: var(--elev-2);
}
/* 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"]:not(.lot-partie-section) {   /* a spacing wrapper, not a card: a shadow drew a box without padding */
  border-color: var(--card-edge);
  box-shadow: var(--elev-1);
}
.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: 0.75rem;
  padding: 0.6875rem 1rem; 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: 0.75rem; padding-right: 0.75rem; } }

/* ── 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: 0.78125rem; color: var(--text-dim); background: transparent;
  border: none; border-bottom: 2px solid transparent; padding: 0.5625rem 0.8125rem; cursor: pointer;
  display: inline-flex; align-items: center; gap: 0.375rem; white-space: nowrap;
}
@media (hover: hover) {
  .pg-tab:hover { color: var(--text-main); }
}
.pg-tab.on { color: var(--tab-on, var(--heading)); border-bottom-color: var(--tab-line, var(--accent-light)); }
/* A tab with an address of its own is a link (the home page's two tabs): same look as the button. */
a.pg-tab, a.pg-tab:hover { text-decoration: none; }
.pg-tab .cnt { font-size: 0.75rem; background: var(--surface-2); border: 1px solid var(--border-soft); border-radius: 999px; padding: 0 0.375rem; }
.pg-tab .tab-sub { font-size: 0.75rem; color: var(--text-dim); font-weight: 400; opacity: .8; }
.pg-tab .tab-caret { opacity: .6; font-size: 0.75rem; }
/* 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: 0.125rem; flex-wrap: wrap; margin: -0.375rem 0 1rem; padding-left: 0.375rem;
  border-bottom: 1px solid var(--border-soft);
}
.pf-sub-tabs .pg-tab { font-size: 0.75rem; padding: 0.375rem 0.75rem; }
.pf-sub-tabs .pg-tab.on { font-weight: 600; }

/* Home page only: the two tabs are the page's main switch, not a quiet sub-navigation.
   Two joined segments, the active one filled with the gold button pair (it holds its
   contrast in the frame header of every theme, which the accent tokens do not). */
.pf-tabs.home { gap: 0; padding: 0.625rem 0.75rem; }
.pf-tabs.home .pg-tab {
  font-size: 0.9375rem; padding: 0.5rem 1.125rem; gap: 0.5rem; margin-left: -1px;
  border: 1px solid var(--gold); border-radius: 0; background: transparent; color: var(--heading);
}
.pf-tabs.home .pg-tab:first-child { border-radius: 8px 0 0 8px; margin-left: 0; }
.pf-tabs.home .pg-tab:last-child { border-radius: 0 8px 8px 0; }
.pf-tabs.home .pg-tab.on {
  background: linear-gradient(135deg, var(--btn-gold-start, var(--amber)), var(--btn-gold-end, var(--gold)));
  border-color: transparent; color: var(--btn-gold-ink, var(--shadow)); font-weight: 600;
}
.pf-tabs.home .pg-tab svg { flex: none; }
.pf-tabs.home .pg-tab > span[aria-hidden] { display: inline-flex; }
.pf-tabs.home .tab-sub { color: var(--text-main); opacity: 1; font-size: 0.75rem; }
.pf-tabs.home .pg-tab.on .tab-sub { color: inherit; opacity: 1; }
/* Phone: the two tabs share the width, the addition drops below the word; the segments stay joined. */
@media (max-width: 540px) {
  .pf-tabs.home .pg-tab {
    flex: 1 1 0; min-width: 0; display: grid; grid-template-columns: auto auto; grid-template-rows: auto auto;
    justify-content: center; align-items: center; column-gap: 0.5rem; row-gap: 0;
    padding-inline: 0.5rem; white-space: normal; text-align: left; line-height: 1.25;
  }
  .pf-tabs.home .pg-tab > span[aria-hidden] { grid-row: 1 / 3; }
  .pf-tabs.home .tab-sub { grid-column: 2; }
  /* Three segments (multiplayer, solo, tournaments) do not fit beside each other with icon
     and addition: the icon moves above the word and the addition is left out. */
  .pf-tabs.home.three .pg-tab {
    grid-template-columns: auto; justify-items: center; text-align: center; row-gap: 0.125rem; padding-inline: 0.25rem;
  }
  .pf-tabs.home.three .pg-tab > span[aria-hidden] { grid-row: 1; }
  .pf-tabs.home.three .tab-sub { display: none; }
}

/* ── Generic in-board building blocks (from the approved mockup) ── */
.pg-title { font-family: 'Rye', cursive; color: var(--heading); font-size: 1.375rem; margin: 0 0 0.25rem; }
.pg-sub { color: var(--text-dim); font-size: 0.8125rem; margin: 0 0 1.125rem; max-width: 640px; }
.pg-section { margin-bottom: 1.375rem; }
.pg-section-head { display: flex; align-items: center; gap: 0.625rem; margin-bottom: 0.625rem; }
.pg-section-head h3 { font-family: 'Rye', cursive; color: var(--heading); font-size: 0.9375rem; margin: 0; }
.pf-search {
  flex: 1; min-width: 160px; display: flex; align-items: center; gap: 0.4375rem; padding: 0.5rem 0.75rem;
  border-radius: 7px; background: var(--surface-1); border: 1px solid var(--border-soft);
  color: var(--text-dim); font-size: 0.78125rem;
}
/* Search box above the statistics card grids (profile + admin). */
.stats-search { flex: none; max-width: 320px; margin: 0.875rem 0 0.75rem; }
.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: head of the game list — title with count, search, view switch ── */
.home-head { display: flex; align-items: center; gap: 0.625rem; margin: 0 0 0.625rem; flex-wrap: wrap; }
.home-head h3 { font-family: 'Rye', cursive; color: var(--heading); font-size: 0.9375rem; margin: 0; }
.home-count { font-family: var(--font-body); font-size: 0.78125rem; color: var(--text-dim); }
.home-head .sp { flex: 1; }
.home-search { flex: 0 0 240px; min-width: 0; height: 36px; padding: 0 0.75rem; background: var(--input-bg); border-color: var(--border-strong); }
.home-search input { font-size: 0.8125rem; }
.home-search input::-webkit-search-cancel-button { display: none; }
.home-search-x {
  flex: none; width: 24px; height: 24px; border: 0; border-radius: 50%; padding: 0;
  background: transparent; color: var(--text-dim); font-size: 0.75rem; cursor: pointer;
}
/* View switch (classic A–Z / grouped by family): two icon buttons with aria-pressed. The
   pressed one is a solid --heading with --text-invert, like the active family chip. */
.view-seg { display: inline-flex; flex: none; border: 1px solid var(--border-strong); border-radius: 7px; overflow: hidden; }
.view-seg button {
  width: 36px; height: 34px; border: 0; padding: 0; display: grid; place-items: center;
  background: var(--surface-2); color: var(--text-dim); cursor: pointer;
}
.view-seg button + button { border-left: 1px solid var(--border-strong); }
.view-seg button[aria-pressed="true"] { background: var(--heading); color: var(--text-invert); }
.view-seg button:focus-visible { outline-offset: -3px; }
/* On the pressed button the ring would have the colour of the fill. */
.view-seg button[aria-pressed="true"]:focus-visible { outline-color: var(--text-invert) !important; }
/* Family chips of the grouped view: jump targets, sticking below the app header. */
.home-fams {
  position: sticky; top: var(--home-sticky-top, 52px); z-index: 5;
  margin: 0 -1.375rem 0.375rem; padding: 0.5rem 1.375rem;
  background: var(--card-grad-b); border-bottom: 1px solid var(--border-soft);
  display: flex; flex-wrap: wrap; gap: 0.375rem;
}
.home-res-info { font-size: 0.78125rem; color: var(--text-dim); margin: 0.125rem 0 0.625rem; }
/* Always in the page (a live region that appears already filled is not announced); empty without a search. */
.home-res-info:empty { margin: 0; }
.home-empty { padding: 1.75rem 1rem; text-align: center; color: var(--text-dim); font-size: 0.8125rem; }
.home-empty .big { display: block; font-size: 1.875rem; margin-bottom: 0.375rem; }
.home-fam { scroll-margin-top: 112px; margin-bottom: 1.375rem; }
.home-fam-head { display: flex; align-items: center; gap: 0.5625rem; margin: 0.25rem 0 0.625rem; flex-wrap: wrap; }
.home-fam-head .fg {
  width: 26px; height: 26px; border-radius: 6px; display: grid; place-items: center; font-size: 0.875rem;
  background: color-mix(in srgb, var(--gold) 22%, transparent); border: 1px solid var(--border-strong); color: var(--heading);
}
.home-fam-head h3 { font-family: 'Rye', cursive; color: var(--heading); font-size: 0.9375rem; margin: 0; font-weight: 400; }
.home-fam-head .cnt {
  font-size: 0.75rem; color: var(--text-dim); background: var(--surface-2); border: 1px solid var(--border-soft);
  border-radius: 999px; padding: 0 0.4375rem; line-height: 18px;
}
.home-fam-head .sub { font-size: 0.78125rem; color: var(--text-dim); margin-left: 0.25rem; }

/* ── Home: poster tiles, "woodcut poster". The head is a fixed dark island like the join
   banners: ground from the game colour, the game's emblem cut off as the motif, icon and name
   on it — raw inks, the same in every theme. Below it description and player count. ── */
.pg-poster-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0.75rem; }
.pg-poster {
  position: relative; border-radius: 9px; overflow: hidden;
  border: 1px solid color-mix(in srgb, var(--accent-light) 42%, var(--card-edge));
  background: var(--surface-1); cursor: pointer; box-shadow: var(--elev-1);
  text-align: left; font: inherit; color: inherit; padding: 0; margin: 0; text-decoration: none;
  /* Flex column instead of block: Blazor leaves whitespace text nodes inside the button; in
     block layout they form an anonymous line box (a pale bar above the art area). */
  display: flex; flex-direction: column;
}
/* place-items: normal — a grid container would centre the absolutely positioned name and
   shrink it to its text width. */
.pg-poster .art {
  position: relative; flex: none; height: 104px; overflow: hidden; display: block; place-items: normal;
  background: linear-gradient(140deg,
    color-mix(in srgb, var(--accent-light) 30%, var(--accent)) 0%,
    color-mix(in srgb, var(--accent) 88%, #120c06) 52%,
    color-mix(in srgb, var(--accent) 55%, #120c06) 100%);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .14), inset 0 -1px 0 color-mix(in srgb, var(--accent-light) 60%, transparent);
}
/* The emblem as a mask: shape from the mode metadata (--emblem, mode-emblems.css), colour from
   here. The second mask layer fades it out downwards, so no bright lines lie behind the name. */
.pg-poster .emb {
  position: absolute; right: -22px; top: -18px; width: 146px; height: 146px; opacity: .62;
  background: color-mix(in srgb, var(--accent-light) 80%, #fff8ec);
  /* The fallback masks everything away: without the emblem sheet the head stays plain instead
     of showing a bright square. */
  -webkit-mask: var(--emblem, linear-gradient(transparent, transparent)) center / contain no-repeat, linear-gradient(180deg, #000 0, #000 40%, transparent 66%);
          mask: var(--emblem, linear-gradient(transparent, transparent)) center / contain no-repeat, linear-gradient(180deg, #000 0, #000 40%, transparent 66%);
  -webkit-mask-composite: source-in; mask-composite: intersect;
}
.pg-poster .art::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 80%; pointer-events: none; z-index: 1;
  background: linear-gradient(180deg, rgba(10, 8, 6, 0) 0%, rgba(10, 8, 6, .58) 42%, rgba(10, 8, 6, .88) 100%);
}
.pg-poster .ic {
  position: absolute; left: 11px; top: 10px; z-index: 2; font-size: 1.875rem; line-height: 1;
  color: #fff8ec; filter: drop-shadow(0 2px 3px rgba(0, 0, 0, .5));
}
.pg-poster .nm {
  position: absolute; left: 11px; right: 11px; bottom: 8px; z-index: 2; margin: 0;
  font-family: 'Rye', cursive; font-weight: 400; color: #fff8ec; font-size: 0.90625rem; line-height: 1.25;
  text-shadow: 0 1px 2px rgba(0, 0, 0, .6);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.pg-poster .bd { flex: 1; padding: 0.5625rem 0.6875rem 0.6875rem; }
.pg-poster .ds { color: var(--text-dim); font-size: 0.75rem; line-height: 1.4; margin: 0; min-height: 34px; }
.pg-poster .pl { color: var(--heading); font-size: 0.75rem; margin: 0.375rem 0 0; font-weight: 600; }
.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);
}
/* Flags at the top right of the head (the icon sits left): visibility badge and spotlight
   tag. Both in full do not fit a phone tile, so beside a visibility badge (admins/testers
   only) the tag keeps just its star — the gold frame already marks the tile, the label stays
   for screen readers. */
.pg-poster-flags {
  position: absolute; top: 8px; right: 8px; z-index: 3; max-width: calc(100% - 56px);
  display: flex; align-items: flex-start; justify-content: flex-end; gap: 4px;
}
.pg-poster-flags:has(.mode-vis-badge) .pg-poster-tag-txt {
  position: absolute; width: 1px; height: 1px; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap;
}
.pg-poster-tag {
  display: inline-flex; gap: 0.3em; background: var(--accent-strong);
  color: var(--text-invert); font-size: 0.75rem; font-weight: 700; padding: 0.1875rem 0.5rem;
  border-radius: 20px; letter-spacing: .02em;
}
.pg-poster-off { opacity: .55; }
@media (hover: hover) {
  .pg-poster { transition: transform .15s ease, box-shadow .15s ease; }
  .pg-poster:hover { transform: translateY(-3px); box-shadow: var(--elev-1), 0 8px 22px color-mix(in srgb, var(--accent-light) 32%, transparent); }
  .pg-poster .emb { transition: opacity .2s ease, transform .2s ease; }
  .pg-poster:hover .emb { opacity: .9; transform: rotate(-3deg) scale(1.05); }
}
@media (prefers-reduced-motion: reduce) {
  .pg-poster, .pg-poster .emb { transition: none; }
  .pg-poster:hover { transform: none; }
  .pg-poster:hover .emb { transform: none; }
}
@media (max-width: 960px) { .pg-poster-grid { grid-template-columns: repeat(2, 1fr); } }

/* ── Home: "Im Rampenlicht" spotlight banner — the tile at large. A fixed dark island:
   accent ground, the emblem cut off on the right, a brand chip, raw inks (the same in every
   theme). Mode accent comes from the .mode-* class on the banner.
   The ground reads the game colour through two registered colour properties: only so can it
   glide to the next game's colour (a gradient of unregistered variables always snaps). ── */
@property --spot-a { syntax: '<color>'; inherits: true; initial-value: #1f8a6d; }
@property --spot-b { syntax: '<color>'; inherits: true; initial-value: #37b894; }
.pg-spotlight {
  --spot-a: var(--accent); --spot-b: var(--accent-light);
  position: relative; overflow: hidden; margin-bottom: 1.125rem; display: flex; align-items: center;
  gap: 1.375rem; padding: 1.375rem 1.625rem; border-radius: 10px; color: #f0e6d2;
  /* Fixed height for three lines of description: the list below no longer jumps when the
     banner rotates to a game with a longer text. */
  min-height: 250px;
  border: 1px solid color-mix(in srgb, var(--spot-b) 55%, transparent);
  box-shadow: var(--elev-1), inset 0 1px 0 rgba(255, 255, 255, .14);
  background: linear-gradient(100deg,
    color-mix(in srgb, var(--spot-a) 60%, #120c06) 0%,
    color-mix(in srgb, var(--spot-a) 92%, #120c06) 58%,
    color-mix(in srgb, var(--spot-b) 36%, var(--spot-a)) 100%);
  transition: --spot-a .35s ease, --spot-b .35s ease;
}
/* The veil in px, not in %: it covers the text block (which ends 672px from the left at the
   latest) at every banner width and only runs out above the emblem. */
.pg-spotlight::after {
  content: ''; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: linear-gradient(90deg, rgba(10, 8, 6, .62) 0, rgba(10, 8, 6, .52) 640px, rgba(10, 8, 6, 0) 860px);
}
.pg-spotlight-emb {
  position: absolute; right: -30px; top: 50%; width: 300px; height: 300px; margin-top: -150px; opacity: .72;
  pointer-events: none; background: color-mix(in srgb, var(--accent-light) 78%, #fff8ec);
  -webkit-mask: var(--emblem, linear-gradient(transparent, transparent)) center / contain no-repeat;
          mask: var(--emblem, linear-gradient(transparent, transparent)) center / contain no-repeat;
}
/* Brand chip like .lobby-uh .uh-ico: firm ground, bright glyph, accent frame. A fixed box, so
   the text column starts at the same x for wide emojis and narrow suit glyphs. */
.pg-spotlight-chip {
  position: relative; z-index: 2; flex: none; width: 64px; height: 64px; border-radius: 14px;
  display: grid; place-items: center; font-size: 2.125rem; line-height: 1; color: #f0e6d2;
  background: color-mix(in srgb, var(--accent) 45%, #1a1208); border: 1px solid var(--accent-light);
  box-shadow: 0 6px 16px rgba(0, 0, 0, .45), inset 0 1px 0 rgba(255, 255, 255, .18);
}
.pg-spotlight-txt { flex: 1; min-width: 220px; max-width: 560px; position: relative; z-index: 2; }
.pg-spotlight-tag { font-size: 0.75rem; letter-spacing: .18em; text-transform: uppercase; color: #f6ead2; margin-bottom: 0.375rem; font-weight: 600; }
.pg-spotlight-star { color: #e8b84b; }
.pg-spotlight-fam { letter-spacing: .04em; font-weight: 500; text-transform: none; }
.pg-spotlight-txt h2 { font-family: 'Rye', cursive; font-weight: 400; font-size: 1.625rem; color: #fff8ec; margin: 0 0 0.375rem; text-shadow: 0 1px 2px rgba(0, 0, 0, .5); }
.pg-spotlight-txt p { color: #f0e6d2; font-size: 0.8125rem; margin: 0; max-width: 520px; }
.pg-spotlight-btns { display: flex; gap: 0.625rem; flex-wrap: wrap; margin-top: 0.75rem; }
.pg-spotlight-btns .btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 0.375rem;
  width: auto; flex: 0 0 auto; padding: 0.5625rem 1.125rem; font-size: 0.8125rem; border-radius: var(--btn-radius);
}
.pg-spotlight-btns .btn-ghost { background: rgba(10, 8, 6, .25); border-color: rgba(255, 248, 236, .55); color: #fff8ec; }
.pg-spotlight-btns .lbl-short { display: none; }
.pg-spotlight-meta { margin-top: 0.625rem; font-size: 0.75rem; color: #d9ccb4; display: flex; gap: 0.875rem; align-items: center; flex-wrap: wrap; }
.pg-spotlight-lob { display: inline-flex; align-items: center; gap: 0.4375rem; }
.pg-spotlight-lob::before { content: ''; width: 7px; height: 7px; border-radius: 50%; background: #5fd39a; box-shadow: 0 0 0 3px rgba(95, 211, 154, .22); }
/* Soft change when the banner rotates: emblem, chip and text block (and the tag on the tile)
   are re-created per game and fade in — colour and opacity only, nothing moves. */
@keyframes spotlight-in { from { opacity: 0; } }
.pg-spotlight-chip, .pg-spotlight-txt, .pg-poster-tag { animation: spotlight-in .35s ease; }
.pg-spotlight-emb { animation: spotlight-emb-in .35s ease; }
@keyframes spotlight-emb-in { from { opacity: 0; } }
@media (prefers-reduced-motion: reduce) {
  .pg-spotlight { transition: none; }
  .pg-spotlight-chip, .pg-spotlight-txt, .pg-spotlight-emb, .pg-poster-tag { animation: none; }
}

/* 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 inks only — the banner is 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), var(--elev-1);
}
@media (hover: hover) {
  .pg-spotlight:not(.pg-spotlight-hub):hover {
    border-color: var(--accent-light);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent-light) 30%, transparent), var(--elev-1);
  }
}
.pg-spotlight-ctrl { position: absolute; top: 10px; right: 10px; display: flex; align-items: center; gap: 0.5rem; z-index: 3; }
/* On its own dark plate: up here the veil has run out and the ground can be bright. */
.pg-spotlight-paused-lbl { font-size: 0.75rem; color: #fff8ec; background: rgba(10, 8, 6, .6); padding: 0.125rem 0.5rem; border-radius: 999px; }
.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: rgba(10, 8, 6, .45); color: #fff8ec; font-size: 0.875rem; line-height: 1;
}
@media (hover: hover) {
  .pg-spotlight-pause:hover { background: rgba(10, 8, 6, .65); }
}
.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: rgba(255, 248, 236, .35); }
/* 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; z-index: 3;
  background: rgba(255, 248, 236, .16);
}
.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; }
}

/* The same poster at rest, as the head of a game's lobby hub (/Play/<game>): it takes the
   height of its text, is no control (no highlight on hover — on the home page that marks the
   halted rotation) and does not fade in: the circuit re-creates the prerendered markup, a
   fade would blink. The meta line keeps its height while the player range is still loading. */
.pg-spotlight-hub { min-height: 0; margin-bottom: 1.25rem; }
.pg-spotlight-hub .pg-spotlight-chip, .pg-spotlight-hub .pg-spotlight-txt, .pg-spotlight-hub .pg-spotlight-emb { animation: none; }
.pg-spotlight-hub .pg-spotlight-meta { min-height: 1.125rem; }

/* ── Home, narrow (≤ 760 px): the spotlight is a band, the tiles are compact ── */
@media (max-width: 760px) {
  /* The view switch stays in the title row (it costs no height); the title gives way and
     wraps, the search takes a row of its own below. */
  .home-head h3 { flex: 1 1 0; min-width: 0; }
  .home-head .sp { display: none; }
  .home-head .home-search { order: 3; flex: 1 0 100%; }
  .home-fams {
    margin: 0 -0.75rem 0.25rem; padding: 0.375rem 0.75rem; flex-wrap: nowrap; overflow-x: auto;
    scrollbar-width: none; scroll-snap-type: x proximity;
  }
  .home-fams::-webkit-scrollbar { display: none; }
  .home-fam { scroll-margin-top: 104px; margin-bottom: 1rem; }
  .home-fam-head .sub { display: none; }

  /* The band rests (one random game per visit), so it has neither pause button nor progress
     bar; the tag carries no family, and there is no lobby line — the band is too narrow. */
  .pg-spotlight-head { display: none; }
  .pg-spotlight { gap: 0.75rem; padding: 0.625rem 0.75rem 0.75rem; margin-bottom: 0.75rem; min-height: 0; }
  .pg-spotlight::after { background: linear-gradient(90deg, rgba(10, 8, 6, .6) 0%, rgba(10, 8, 6, .5) 70%, rgba(10, 8, 6, .2) 100%); }
  .pg-spotlight-emb { right: 64px; width: 104px; height: 104px; margin-top: -52px; opacity: .6; }
  .pg-spotlight-chip { width: 44px; height: 44px; border-radius: 9px; font-size: 1.625rem; }
  .pg-spotlight-txt {
    min-width: 0; max-width: none; display: grid; grid-template-columns: minmax(0, 1fr) auto;
    column-gap: 0.75rem; align-items: center;
  }
  /* Tag and name wrap instead of being cut off with an ellipsis (reflow without loss). */
  .pg-spotlight-tag { grid-column: 1; margin: 0; letter-spacing: .08em; }
  .pg-spotlight-txt h2 { grid-column: 1; font-size: 0.9375rem; margin: 0.0625rem 0 0; line-height: 1.2; overflow-wrap: anywhere; }
  .pg-spotlight-btns { grid-column: 2; grid-row: 1 / span 2; margin: 0; }
  .pg-spotlight-btns .btn { height: 32px; padding: 0 0.75rem; font-size: 0.75rem; }
  .pg-spotlight-btns .lbl-long { display: none; }
  .pg-spotlight-btns .lbl-short { display: inline; }
  .pg-spotlight-txt p, .pg-spotlight-meta, .pg-spotlight-fam, .pg-spotlight-ctrl, .pg-spotlight-bar,
  .pg-spotlight-btns .btn-ghost { display: none; }

  /* Compact tiles: the head carries emblem, icon and name; below it only the player count.
     The description is one tap away on the hub's poster. */
  .pg-poster-grid { gap: 0.625rem; }
  .pg-poster .art { height: 80px; }
  .pg-poster .emb { width: 112px; height: 112px; right: -18px; top: -16px; }
  .pg-poster .ic { font-size: 1.5rem; left: 9px; top: 8px; }
  .pg-poster .nm { font-size: 0.8125rem; left: 9px; right: 9px; bottom: 7px; }
  .pg-poster .bd { padding: 0.375rem 0.5625rem 0.5rem; }
  .pg-poster .ds { display: none; }
  .pg-poster .pl { margin: 0; }
  .pg-poster.no-pl .bd { display: none; }   /* solo tab: no player count — the tile is just its head */
  .pg-poster-tag { padding: 0.125rem 0.4375rem; }
}
/* Smallest phones: the button gets a row of its own and the text the full width; the veil lies
   evenly, because the text now reaches the right edge. */
@media (max-width: 340px) {
  .pg-spotlight-txt { grid-template-columns: minmax(0, 1fr); row-gap: 0.375rem; }
  .pg-spotlight-btns { grid-column: 1; grid-row: auto; }
  .pg-spotlight-btns .btn { flex: 1 0 100%; }
  .pg-spotlight::after { background: rgba(10, 8, 6, .56); }
}
/* The hub's poster is no band on a narrow screen: the description is the text of the page and
   stays, with family tag, button and meta line. The text reaches the right edge and runs over
   the emblem, so the veil lies evenly and the emblem steps back. */
@media (max-width: 760px) {
  .pg-spotlight-hub { align-items: flex-start; padding: 0.875rem 0.875rem 1rem; margin-bottom: 1rem; }
  .pg-spotlight-hub::after { background: rgba(10, 8, 6, .58); }
  .pg-spotlight-hub .pg-spotlight-emb { right: -28px; width: 168px; height: 168px; margin-top: -84px; opacity: .5; }
  .pg-spotlight-hub .pg-spotlight-txt { display: block; }
  .pg-spotlight-hub .pg-spotlight-tag { margin-bottom: 0.25rem; }
  .pg-spotlight-hub .pg-spotlight-txt h2 { font-size: 1.25rem; margin: 0 0 0.3125rem; }
  .pg-spotlight-hub .pg-spotlight-txt p { display: block; }
  .pg-spotlight-hub .pg-spotlight-btns { margin-top: 0.625rem; }
  .pg-spotlight-hub .pg-spotlight-btns .btn-ghost { display: inline-flex; }
  .pg-spotlight-hub .pg-spotlight-meta { display: flex; }
}

/* Link row "view full profile" in the player quick-view modal. */
.player-profile-fulllink { margin-top: 0.75rem; text-align: center; font-size: 0.8125rem; }
.player-profile-fulllink a { color: var(--heading); text-decoration: none; }
@media (hover: hover) {
  .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: 1.125rem; padding: 1.125rem 1.25rem; border-radius: 10px;
  background: var(--surface-1); border: 1px solid var(--border-soft); margin-bottom: 1.125rem; flex-wrap: wrap;
}
.pg-hero-info { flex: 1; min-width: 140px; }
.pg-hero h2 { font-family: 'Rye', cursive; color: var(--heading); font-size: 1.375rem; margin: 0 0 0.25rem; }
.pg-hero p { color: var(--text-dim); font-size: 0.78125rem; margin: 0; }
.pg-hero-team-link { color: var(--heading); text-decoration: none; }
@media (hover: hover) {
  .pg-hero-team-link:hover { text-decoration: underline; }
}
.pg-team-row {
  display: flex; align-items: center; gap: 0.75rem; padding: 0.6875rem 0.8125rem; border-radius: 8px;
  background: var(--surface-1); border: 1px solid var(--border-soft); margin-bottom: 0.5rem;
}
.pg-row-main { flex: 1; min-width: 0; }
.pg-row-title { color: var(--text-main); font-size: 0.8125rem; font-weight: 600; }
.pg-row-meta { color: var(--text-dim); font-size: 0.75rem; }

/* ── Rules page: split view (game list left, detail right) ── */
.rules-split { display: grid; grid-template-columns: 220px 1fr; gap: 1rem; align-items: start; }
.rules-split-list { display: flex; flex-direction: column; gap: 0.1875rem; }
/* .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: 0.625rem; }
.rsplit-item {
  display: flex; align-items: center; gap: 0.5625rem; width: 100%; padding: 0.5625rem 0.75rem; border-radius: 7px;
  border: 1px solid transparent; background: transparent; color: var(--text-main);
  font: inherit; font-size: 0.78125rem; cursor: pointer; text-align: left; text-decoration: none;
}
@media (hover: hover) {
  .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: 1rem; width: 20px; flex: none; display: inline-flex; align-items: center; justify-content: center; }
.rsplit-empty { font-size: 0.78125rem; color: var(--text-dim); padding: 0.5rem 0.75rem; }
.rules-split-detail { background: var(--surface-1); border: 1px solid var(--border-soft); border-radius: 8px; padding: 1.125rem 1.25rem; min-width: 0; }
.rsd-head { display: flex; align-items: center; gap: 0.625rem; margin-bottom: 0.625rem; }
.rsd-head .ic { font-size: 1.75rem; }
.rsd-head h2 { font-family: 'Rye', cursive; color: var(--heading); font-size: 1.0625rem; margin: 0; }
.rsd-meta { font-size: 0.75rem; color: var(--text-dim); margin-bottom: 0.75rem; }
.rsd-play { display: inline-block; width: auto; margin-top: 0.5rem; padding: 0.5625rem 1.125rem; font-size: 0.8125rem; }
/* The overview (/Rules without a game): every game with its one line. */
.rules-overview { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.75rem; }
.rules-overview li { display: flex; flex-direction: column; gap: 0.125rem; }
.rules-overview a { display: inline-flex; align-items: center; gap: 0.5rem; color: var(--heading); font-weight: 600; font-size: 0.875rem; text-decoration: none; }
.rules-overview a .ic { width: 20px; flex: none; display: inline-flex; justify-content: center; }
.rules-overview .ds { color: var(--text-dim); font-size: 0.78125rem; line-height: 1.45; padding-left: 1.75rem; }
@media (hover: hover) {
  .rules-overview a:hover { text-decoration: underline; }
}
@media (max-width: 640px) {
  .rules-split { grid-template-columns: 1fr; }
  /* One column: on a game's own address its rules come first, the list of the other games
     after. The overview would only repeat the list above it. */
  .rules-split.has-sel .rules-split-detail { order: -1; }
  .rules-split:not(.has-sel) .rules-split-detail { display: none; }
}

/* ── A game's own page: the text below its lobby hub — how it is played, its rules page, the
   other games of its family. ── */
.play-about {
  margin-top: 1.25rem; padding: 1.125rem 1.25rem; min-width: 0;
  background: var(--surface-1); border: 1px solid var(--border-soft); border-radius: 8px;
}
.play-about h2 { font-family: 'Rye', cursive; color: var(--heading); font-size: 1.0625rem; margin: 0 0 0.5rem; }
.play-about h3 { color: var(--heading); font-size: 0.8125rem; font-weight: 600; margin: 1rem 0 0.5rem; }
.play-about-lead { color: var(--text-dim); font-size: 0.8125rem; line-height: 1.5; margin: 0 0 0.875rem; }
.play-about-players { display: block; margin-top: 0.25rem; color: var(--heading); font-weight: 600; }
.play-about-links { font-size: 0.8125rem; margin: 0.25rem 0 0; }
.play-about-links a { color: var(--heading); text-decoration: underline; }
.play-about-links a + a { margin-left: 1rem; }
/* Solo tab: the line of links to the games' own pages below the tiles (the tiles are buttons there). */
.home-solo-pages {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.25rem 1rem;
  margin-top: 1rem; font-size: 0.8125rem; color: var(--text-dim);
}
.home-solo-pages a { color: var(--heading); text-decoration: underline; }

/* == Tournaments: the hall tab's list, the dialog that sets one up, a tournament's hall ==
   Cards and the hall's head band carry the game's colour as a dark island (fixed light text on
   it, like the poster tiles); everything else sits on the page's own surfaces and tokens. */
.tour-head { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem 0.75rem; margin-bottom: 0.375rem; }
.tour-h { font-family: 'Rye', cursive; font-size: 1.0625rem; color: var(--heading); margin: 0; margin-right: auto; }
.tour-cnt { font-family: var(--font-body); font-size: 0.8125rem; color: var(--text-dim); }
.tour-intro { margin: 0 0 0.875rem; font-size: 0.8125rem; color: var(--text-dim); max-width: 52rem; }
.tour-empty { color: var(--text-dim); margin: 1rem 0; }
.tour-seg { display: inline-flex; flex-wrap: wrap; border: 1px solid var(--border-strong); border-radius: 6px; overflow: hidden; }
.tour-seg button {
  font: inherit; font-size: 0.8125rem; padding: 0.3125rem 0.6875rem; border: 0; cursor: pointer;
  background: transparent; color: var(--text-main); display: inline-flex; align-items: center; gap: 0.3125rem;
}
.tour-seg button + button { border-left: 1px solid var(--border-soft); }
.tour-seg button[aria-pressed="true"] {
  background: linear-gradient(135deg, var(--btn-gold-start, var(--amber)), var(--btn-gold-end, var(--gold)));
  color: var(--btn-gold-ink, var(--shadow)); font-weight: 600;
}
.tour-seg button:focus-visible { outline-offset: -3px; }
.tour-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(17.5rem, 1fr)); gap: 0.875rem; }
.tour-card {
  display: flex; flex-direction: column; border-radius: 9px; overflow: hidden; background: var(--surface-1);
  border: 1px solid color-mix(in srgb, var(--accent-light) 42%, var(--card-edge)); box-shadow: var(--elev-1);
}
.tour-art {
  position: relative; height: 4.5rem; flex: none;
  background: linear-gradient(140deg,
    color-mix(in srgb, var(--accent-light) 30%, var(--accent)) 0%,
    color-mix(in srgb, var(--accent) 88%, #120c06) 52%,
    color-mix(in srgb, var(--accent) 55%, #120c06) 100%);
}
.tour-ic {
  display: grid; place-items: center; width: 2.25rem; height: 2.25rem; border-radius: 8px; font-size: 1.25rem;
  background: rgba(18, 12, 6, .55); color: #fff8ec; flex: none;
}
.tour-art .tour-ic { position: absolute; left: 0.75rem; bottom: 0.625rem; }
.tour-st {
  position: absolute; right: 0.625rem; top: 0.625rem; font-size: 0.75rem; letter-spacing: .1em; text-transform: uppercase;
  padding: 0.125rem 0.5rem; border-radius: 4px; background: #120c06; color: #fff8ec; font-weight: 600;
}
.tour-st.live::before { content: "● "; color: #9fe0a0; }
.tour-bd { display: flex; flex-direction: column; gap: 0.3125rem; padding: 0.6875rem 0.75rem 0.75rem; flex: 1; }
.tour-nm { font-family: 'Rye', cursive; font-size: 1rem; margin: 0; }
.tour-nm a { color: var(--heading); text-decoration: none; }
@media (hover: hover) { .tour-nm a:hover { text-decoration: underline; } }
.tour-ds { font-size: 0.8125rem; color: var(--text-main); }
.tour-meta { display: flex; flex-wrap: wrap; gap: 0.25rem 0.75rem; font-size: 0.75rem; color: var(--text-dim); }
.tour-act { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; margin-top: auto; padding-top: 0.375rem; }
.tour-act a.btn { text-decoration: none; }
.tour-hint { font-size: 0.75rem; color: var(--text-dim); }
.tour-reg { font-size: 0.75rem; color: var(--heading); font-weight: 600; }

/* The dialog. */
.tour-form { display: flex; flex-direction: column; gap: 0.625rem; }
.tour-sec { font-family: 'Rye', cursive; font-size: 0.9375rem; color: var(--heading); margin: 0.5rem 0 0; }
.tour-row { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem 0.75rem; }
.tour-k { font-size: 0.8125rem; color: var(--text-main); min-width: 7.5rem; }
.tour-num { width: 5.5rem; }
.tour-mini { margin: -0.25rem 0 0; font-size: 0.75rem; color: var(--text-dim); }
.tour-note { margin: 0.375rem 0 0; padding: 0.5rem 0.75rem; border-radius: 6px; font-size: 0.8125rem; background: var(--surface-2); color: var(--text-main); }

/* The hall. */
.tour-hall { border: 1px solid var(--border-strong); border-radius: 8px; overflow: hidden; background: var(--surface-1); }
.tour-hh {
  display: flex; align-items: center; gap: 0.75rem; padding: 0.875rem 1rem; color: #fff8ec;
  background: linear-gradient(140deg, color-mix(in srgb, var(--accent) 70%, #120c06), color-mix(in srgb, var(--accent) 34%, #120c06));
}
.tour-hh-main { display: flex; flex-direction: column; gap: 0.375rem; min-width: 0; }
.tour-hh-pills { display: flex; flex-wrap: wrap; gap: 0.375rem; }
.tour-pill { font-size: 0.75rem; padding: 0.125rem 0.5rem; border-radius: 999px; background: rgba(18, 12, 6, .55); color: #fff8ec; }
.tour-pill.state { font-weight: 600; }
.tour-pill.state.live::before { content: "● "; color: #9fe0a0; }
.tour-org { font-size: 0.75rem; color: #f1e6d2; overflow-wrap: anywhere; }
.tour-hb { display: flex; flex-direction: column; gap: 0.875rem; padding: 0.875rem 1rem 1rem; }
.tour-ctl, .tour-own {
  display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem 0.625rem; padding: 0.625rem 0.75rem; border-radius: 8px;
  border: 1px solid var(--border-soft); background: var(--surface-2);
}
.tour-own { border-color: var(--border-strong); }
.tour-own-txt { color: var(--text-main); margin-right: auto; }
.tour-own a.btn { text-decoration: none; }
.tour-confirm { margin: 0; color: var(--text-main); }
.tour-lab { font-size: 0.75rem; letter-spacing: .12em; text-transform: uppercase; color: var(--text-dim); font-weight: 600; margin-bottom: 0.375rem; }
.tour-ctl .tour-lab { margin: 0; }
.tour-cd { font-size: 0.8125rem; color: var(--text-main); }
.tour-sp { flex: 1; }
.tour-two { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 1rem; align-items: start; }
.tour-info p { margin: 0 0 0.5rem; font-size: 0.8125rem; color: var(--text-main); }
.tour-chips { display: flex; flex-wrap: wrap; gap: 0.375rem; margin-bottom: 0.75rem; }
.tour-chip {
  display: inline-flex; align-items: center; gap: 0.25rem; font-size: 0.8125rem; padding: 0.1875rem 0.5625rem; border-radius: 999px;
  border: 1px solid var(--border-soft); background: var(--surface-2); color: var(--text-main);
}
.tour-chip.me { border-color: var(--border-strong); font-weight: 600; }
.tour-x {
  font: inherit; font-size: 0.75rem; line-height: 1; min-width: 1.5rem; min-height: 1.5rem; border-radius: 50%; cursor: pointer;
  border: 1px solid var(--border-soft); background: transparent; color: var(--text-dim); margin-left: 0.25rem;
}
@media (hover: hover) { .tour-x:hover { color: var(--danger); border-color: var(--danger); } }
.tour-scroll { overflow-x: auto; }
.tour-st-table { width: 100%; border-collapse: collapse; font-size: 0.8125rem; }
.tour-st-table th { text-align: left; font-weight: 600; color: var(--text-dim); padding: 0.3125rem 0.5rem; border-bottom: 1px solid var(--border-strong); white-space: nowrap; }
.tour-st-table td { padding: 0.3125rem 0.5rem; border-bottom: 1px solid var(--border-soft); color: var(--text-main); }
.tour-st-table .r { text-align: right; font-variant-numeric: tabular-nums; }
.tour-st-table .dim { color: var(--text-dim); }
.tour-st-table .pts { font-weight: 700; color: var(--heading); }
.tour-st-table tr.me td { background: var(--surface-2); font-weight: 600; }
.tour-st-table tr.out td { color: var(--text-dim); }
.tour-tbs { display: grid; grid-template-columns: repeat(auto-fill, minmax(13.75rem, 1fr)); gap: 0.625rem; }
.tour-tb { border: 1px solid var(--border-soft); border-radius: 8px; padding: 0.5rem 0.625rem 0.625rem; background: var(--surface-2); }
.tour-tb.mine { border-color: var(--border-strong); box-shadow: 0 0 0 1px var(--border-strong); }
.tour-th { display: flex; align-items: baseline; gap: 0.5rem; margin-bottom: 0.25rem; }
.tour-tt { font-weight: 700; color: var(--heading); font-size: 0.8125rem; }
.tour-ts { margin-left: auto; font-size: 0.75rem; color: var(--text-dim); text-align: right; }
.tour-ts.live { color: var(--text-main); }
.tour-pl { display: flex; gap: 0.5rem; font-size: 0.8125rem; color: var(--text-main); padding: 0.125rem 0; }
.tour-pl.out { color: var(--text-dim); }
.tour-pl-s { margin-left: auto; font-variant-numeric: tabular-nums; color: var(--text-dim); white-space: nowrap; }
.tour-go { display: flex; flex-wrap: wrap; gap: 0.375rem; margin-top: 0.375rem; }
.tour-go a.btn { text-decoration: none; }
.tour-pod { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0.625rem; }
.tour-pod-p {
  display: flex; flex-direction: column; align-items: center; gap: 0.125rem; padding: 0.75rem 0.5rem; border-radius: 8px; text-align: center;
  border: 1px solid var(--border-soft); background: var(--surface-2);
}
.tour-pod-p.first { border-color: var(--border-strong); }
.tour-pod-m { font-size: 1.5rem; }
.tour-pod-n { font-weight: 700; color: var(--heading); overflow-wrap: anywhere; }
.tour-pod-v { font-size: 0.75rem; color: var(--text-dim); }
.tour-foot { display: flex; padding: 0.625rem 1rem; border-top: 1px solid var(--border-soft); }
.tour-foot a.btn { text-decoration: none; }
@media (max-width: 760px) {
  .tour-two, .tour-pod { grid-template-columns: minmax(0, 1fr); }
  .tour-hb { padding: 0.75rem; }
  .tour-k { min-width: 100%; }
}
.play-about-more { list-style: none; display: flex; flex-wrap: wrap; gap: 0.5rem; margin: 0; padding: 0; }
.play-about-more a {
  display: inline-flex; align-items: center; gap: 0.375rem; min-height: 32px; padding: 0 0.75rem;
  border-radius: 999px; border: 1px solid var(--border-strong); background: var(--surface-2);
  color: var(--text-main); font-size: 0.78125rem; text-decoration: none;
}
@media (hover: hover) {
  .play-about-more a:hover { background: var(--surface-hover); }
}

/* ── 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: 0.9375rem;
  background: var(--surface-1); border: 1px solid var(--border-strong); color: var(--heading);
  transition: border-color .15s, background .15s;
}
@media (hover: hover) {
  .theme-btn:hover { border-color: var(--gold); background: var(--surface-hover); }
}
/* The game rules in the app header: shown only behind the game page's menu on a narrow
   portrait phone, where the game header drops its "?" (game.css). */
.theme-btn.app-hdr-rules { display: none; }

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


[data-scheme="light"] .email-verified { color: var(--success); }
[data-scheme="light"] .cl-badge-new { color: #8a4108; }
[data-scheme="light"] .presence-online { color: var(--success); }
[data-scheme="light"] .btn-ghost-red { color: var(--ghost-red-ink, #8b1a1a); border-color: var(--ghost-red-line, rgba(139, 26, 26, .45)); }   /* #a32a2a measured 4.1:1 on the card gradient; this holds 4.5:1 on every stop */
@media (hover: hover) {
  [data-scheme="light"] .btn-ghost-red:hover { color: var(--ghost-red-hover, #6e1212); }
}
[data-scheme="light"] .help-icon-btn { color: #7a4a12; }
[data-scheme="light"] .player-slot.disconnected { background: rgba(163, 50, 74, .08); }
[data-scheme="light"] .r-gold, [data-scheme="light"] .r-red,
[data-scheme="light"] .r-amber { text-shadow: none; }   /* the title glow muddies on parchment */
[data-scheme="light"] .start-overlay-num { text-shadow: none; }
[data-scheme="light"] .uc-role-tag.ghost,
[data-scheme="light"] .role-pill.ghost,
[data-scheme="light"] .uc-ghost-saved { color: #47596a; }
[data-scheme="light"] .ro-flourish { text-shadow: none; }

/* -- WCAG 2.5.8: 24px minimum target sizes for compact controls (app-wide).
   min-height only affects the instances that are too small; normally sized inputs
   (30px+) stay unchanged. -- */
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; }

/* ── Stage lobby: spotlight rig + props (decorative) ──────────────────────
   Rig/lamps in fixed wood tones (artwork, both themes), light cones in the
   mode accent colour. The "light check" sweeps the cones ONCE on load
   (< 5 s → no WCAG 2.2.2 pause control needed); with prefers-reduced-motion
   they stand still immediately. The prop sits BEHIND the troupe (z-index)
   and steps back on crowded stages (.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: -5rem; 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: 0.375rem 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: 1.25rem; 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: 1.375rem; 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: 2.5rem; color: #f7ecd4; }
.sprop-tabu { position: relative; width: 92px; height: 96px; margin: 0 auto; background: #f7ecd4; border: 2px solid #8a6a3c; border-radius: 6px; padding-top: 0.625rem; transform: rotate(-3deg); }
.sprop-tabu .word   { display: block; font-family: 'Rye', cursive; font-size: 0.9375rem; letter-spacing: .06em; color: #3a2a16; }
.sprop-tabu .strike { display: block; width: 70%; height: 3px; margin: 0.25rem auto 0.375rem; background: #a3324a; transform: rotate(-4deg); }
.sprop-tabu .shh    { font-size: 1.625rem; }
@media (max-width: 640px) {
  .stage-prop { transform: translateX(-50%) scale(.75); transform-origin: bottom center; }
  .stage-rig { left: 50px; right: 50px; }
}

/* Light: the lobby panels (header card, player panel, footer) were almost pure
   white with the global card gradient ("blendet") - lowered to warm parchment in
   the lobby context. Pages outside it keep the standard gradient. */
[data-scheme="light"] .screen-lobby .card,
[data-scheme="light"] .screen-game .card {
  --card-grad-a: var(--lobby-card-a, rgba(246, 235, 210, .95));
  --card-grad-b: var(--lobby-card-b, rgba(236, 220, 184, .97));
}

/* Light: rich felt green -> text ON the felt is light (as in dark), otherwise no AA. */
[data-scheme="light"] .lobby-table .seat-name,
[data-scheme="light"] .lobby-table .seat-team-btn:not(.on),
[data-scheme="light"] .lobby-table .seat-team-ro,
[data-scheme="light"] .lobby-table .seat-you,
[data-scheme="light"] .lobby-table .seat-badge.badge-host,
[data-scheme="light"] .lobby-table .seat-avatar-empty,
[data-scheme="light"] .lobby-table .seat-ghost .seat-name { color: var(--text-invert); }

/* Light: the lobby header card as a darker sand band - lifts the header off
   the rest of the parchment (operator feedback: too little hierarchy). */
/* Section 3 fallback rule: Schnellschuss turquoise is the brightest accent and
   drops below the edge threshold in light (ring 2.7:1) - darkened light pair.
   First and so far only mode with an explicit light override. */
[data-scheme="light"] .mode-schnellschuss {
  --accent: #157585;
  --accent-light: #3b9fb2;
}
[data-scheme="light"] .screen-lobby .lobby-header-card,
[data-scheme="light"] .screen-game .lobby-header-card {
  /* The band carries the game accent as a veil (the way the dark ground carries
     the accents in dark mode) — the sand band stays the base. Since light-theme
     stage 2 the same band also applies on game pages (same header component). */
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--accent) var(--band-mix-a, 14%), var(--band-a, #e3cda0)),
    color-mix(in srgb, var(--accent) var(--band-mix-b, 20%), var(--band-b, #d9bf8c)));
/* The border stays saloon gold-brown - panel edges NEVER carry the mode accent
     (established rule, see .card-actions-bar). Same token as the panels below,
     so that the top and bottom borders share exactly the same tone. */
  border-color: var(--border-soft);
}
[data-scheme="light"] :is(.screen-lobby, .screen-game) .lobby-header-card .uh-name,
[data-scheme="light"] :is(.screen-lobby, .screen-game) .lobby-header-card .help-icon-btn,
[data-scheme="light"] :is(.screen-lobby, .screen-game) .lobby-header-card .uh-help { color: var(--text-main); }
/* Vivid light: the body ink reaches 4.3 : 1 at the header's darkest stop. */
[data-theme="vividlight"] :is(.screen-lobby, .screen-game) .lobby-header-card .uh-name { color: #2a2d42; }
/* Light: the icon chip as a LIGHT accent mark (pastel ground + deep accent glyph)
   instead of the imported dark chip - every game keeps its own accent. */
/* Light: the history/chat/copy buttons carry emoji glyphs (own colour, beige!)
   - invisible on the sand band. Same plaque as the icon chip. */
/* --plaque = plaque ground, --plaque-edge = outline/glyph partner; a theme with a dark band
   (Light Saloon) swaps the two ends and raises the accent share of the icon chip. */
[data-scheme="light"] :is(.screen-lobby, .screen-game) .lobby-uh .uh-icon-btn {
  background: color-mix(in srgb, var(--accent) 12%, var(--plaque, #fffdf7));
  border-color: color-mix(in srgb, var(--accent) 65%, var(--plaque-edge, #3a2a16));
}
[data-scheme="light"] :is(.screen-lobby, .screen-game) .lobby-uh .uh-gear {
  background: color-mix(in srgb, var(--accent) 12%, var(--plaque, #fffdf7));
  border-color: color-mix(in srgb, var(--accent) 65%, var(--plaque-edge, #3a2a16));
}
[data-scheme="light"] :is(.screen-lobby, .screen-game) .lobby-uh .uh-ico {
/* Lighter than the sand band (plaque) + a dark accent outline - dark
     accents (aubergine, sienna) otherwise blur into the band tone. */
  background: color-mix(in srgb, var(--accent) var(--plaque-ico-mix, 20%), var(--plaque, #fffdf7));
  color: color-mix(in srgb, var(--accent) var(--plaque-ink-mix, 55%), var(--plaque-edge, #3a2a16));
  border-color: color-mix(in srgb, var(--accent) 65%, var(--plaque-edge, #3a2a16));
}
/* Optional accent edge under the game head (--band-rule width; Light Saloon's walnut sign).
   A deliberate exception to "panel edges never carry the mode accent" (HANDOVER A11): the
   head is a sign, not a panel frame. Placed after the band rule, which resets border-color. */
[data-scheme="light"] :is(.screen-lobby, .screen-game).lobby-redesign .lobby-header-card {
  border-bottom: var(--band-rule, 0px) solid var(--accent);
}

/* ═══════════════════════════════════════════════════════════════════════════
   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.
   ═══════════════════════════════════════════════════════════════════════════ */
/* ═══════════════════════════════════════════════════════════════════════
   Feedback — submission form, own case list, thread.
   Admin-only parts live in admin.css; everything here is shared by both,
   because admin.css loads IN ADDITION to saloon.css.
   ═══════════════════════════════════════════════════════════════════ */

/* Compact buttons in feedback button rows. Base .btn is block + width:100%
   (see the "full width trap" in the design guide), so a row needs a container
   or, as here, an explicit modifier — same shape as .card-actions .btn. */
.fb-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 0.375rem;
  width: auto; flex: 0 0 auto; min-width: 104px;
  padding: 0.5rem 1rem; font-size: 0.8125rem; letter-spacing: .06em;
}

/* ── Badges: status / kind / area ──────────────────────────────────── */
/* Never colour alone: each badge carries an icon and a word, so it survives
   colour blindness and forced-colours mode. */
.fb-st, .fb-kind, .fb-area {
  display: inline-flex; align-items: center; gap: 0.375rem;
  font-size: 0.75rem; line-height: 1.5; white-space: nowrap;
}
.fb-st {
  border-radius: 999px; padding: 0.1875rem 0.6875rem;
  border: 1px solid; letter-spacing: .04em; font-weight: 500;
}
.fb-st-new  { color: var(--heading);  border-color: var(--border-strong);   background: rgba(200,146,42,.12); }
.fb-st-prog { color: #eb9a52;         border-color: rgba(212,98,10,.55);    background: rgba(212,98,10,.14); }
.fb-st-acc  { color: #6fc796;         border-color: rgba(45,122,74,.6);     background: rgba(45,122,74,.16); }
.fb-st-done { color: #d7f0e0;         border-color: #3f9a68;                background: rgba(45,122,74,.55); }
.fb-st-rej  { color: var(--danger);   border-color: rgba(192,53,42,.55);    background: rgba(139,26,26,.18); }
.fb-kind, .fb-area {
  border: 1px solid var(--border-soft); border-radius: 4px; padding: 0.125rem 0.5rem;
  color: var(--text-dim);
}
.fb-area { color: var(--accent-ink); border-color: var(--border-strong); background: rgba(200,146,42,.08); }

[data-scheme="light"] .fb-st-prog { color: #8a3c06; background: rgba(212,98,10,.12); }
[data-scheme="light"] .fb-st-acc  { color: #175434; background: rgba(45,122,74,.12); }
[data-scheme="light"] .fb-st-done { color: #f2fbf5; background: #2d7a4a; border-color: #1d6340; }
[data-scheme="light"] .fb-st-rej  { color: #912121; background: rgba(139,26,26,.10); }

/* ── Form ──────────────────────────────────────────────────────────── */
.fb-frm-row  { margin-bottom: 1rem; }
.fb-frm-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0.875rem; }
.fb-frm-label {
  display: block; font-size: 0.75rem; letter-spacing: .14em; text-transform: uppercase;
  color: var(--text-dim); margin-bottom: 0.375rem;
}
.fb-req      { color: var(--heading); }
.fb-optional { color: var(--text-dim); letter-spacing: 0; text-transform: none; }
.fb-counter  { float: right; font-size: 0.75rem; color: var(--text-dim);
               font-variant-numeric: tabular-nums; letter-spacing: 0; }
.fb-frm-hint { font-size: 0.75rem; color: var(--text-dim); margin-top: 0.3125rem; }
.fb-frm-text { min-height: 7rem; resize: vertical; line-height: 1.55; }

.fb-chipset { display: flex; gap: 0.5rem; flex-wrap: wrap; }
.fb-chip {
  border: 1px solid var(--border-soft); border-radius: 999px; background: var(--surface-1);
  color: var(--text-dim); padding: 0.375rem 0.8125rem; font-size: 0.8125rem;
  font-family: inherit; cursor: pointer; min-height: 30px;
  display: inline-flex; align-items: center; gap: 0.4375rem;
}
.fb-chip.on {
  border-color: var(--border-strong); color: var(--accent-ink);
  background: linear-gradient(180deg, rgba(200,146,42,.18), rgba(200,146,42,.06));
}

/* Upload zone is a <label> wrapping the file input: clicking anywhere on it
   opens the picker, and the input stays in the DOM for keyboard users
   (visually hidden, NOT display:none, which would drop it from the tab order). */
.fb-upload {
  display: block; border: 1px dashed var(--border-strong); border-radius: 8px;
  background: var(--surface-1); padding: 1rem; text-align: center; cursor: pointer;
}
.fb-upload-ico  { font-size: 1.375rem; display: block; margin-bottom: 0.375rem; }
.fb-upload-main { color: var(--text-main); font-size: 0.8125rem; }
.fb-upload-sub  { color: var(--text-dim); font-size: 0.75rem; margin-top: 0.25rem; display: block; }
.fb-upload-input {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.fb-upload:focus-within { border-color: var(--gold); box-shadow: 0 0 0 2px rgba(200,146,42,.35); }

/* ── Screenshot strip ──────────────────────────────────────────────── */
.fb-shots { display: flex; gap: 0.625rem; flex-wrap: wrap; margin-top: 0.75rem; }
.fb-shot {
  position: relative; width: 8.625rem; border: 1px solid var(--card-edge);
  border-radius: 6px; background: var(--surface-1); overflow: hidden;
}
.fb-shot-btn {
  display: block; width: 100%; height: 5.125rem; padding: 0; border: 0;
  background: rgba(8,5,2,.5); cursor: pointer; overflow: hidden;
}
.fb-shot-btn img { width: 100%; height: 100%; object-fit: cover; display: block; }
.fb-shot-pending {
  height: 5.125rem; display: flex; align-items: center; justify-content: center;
  background: rgba(8,5,2,.5); color: var(--text-dim); font-size: 1.375rem;
}
.fb-shot-meta {
  display: block; padding: 0.3125rem 0.4375rem; font-size: 0.75rem;
  color: var(--text-dim); word-break: break-all;
}
.fb-shot-rm {
  position: absolute; top: 0.3125rem; right: 0.3125rem; width: 24px; height: 24px;
  border-radius: 5px; border: 1px solid rgba(192,53,42,.6); background: rgba(20,8,5,.85);
  color: var(--danger); display: flex; align-items: center; justify-content: center;
  cursor: pointer; font-size: 0.8125rem;
}

/* ── Case list (profile + admin) ───────────────────────────────────── */
.fb-list { display: flex; flex-direction: column; gap: 0.625rem; }
.fb-row {
  border: 1px solid var(--card-edge); border-radius: 8px; background: var(--surface-1);
  padding: 0.75rem 0.875rem; display: grid; grid-template-columns: minmax(0,1fr) auto;
  gap: 0.625rem 1rem; align-items: start; cursor: pointer;
}
.fb-row.unread { border-left: 3px solid var(--gold); padding-left: 0.75rem; }
.fb-row-title {
  margin: 0 0 0.375rem; font-size: 0.9375rem; color: var(--text-main); font-weight: 600;
  display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap;
}
.fb-row-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--gold); flex: 0 0 auto; }
.fb-row-tags { display: flex; gap: 0.4375rem; flex-wrap: wrap; align-items: center; }
.fb-row-foot {
  margin-top: 0.5rem; font-size: 0.75rem; color: var(--text-dim);
  display: flex; gap: 0.875rem; flex-wrap: wrap; font-variant-numeric: tabular-nums;
}
.fb-row-new   { color: var(--gold-ink); }
.fb-row-right { display: flex; flex-direction: column; align-items: flex-end; gap: 0.5rem; }
.fb-row-id    { font-family: ui-monospace, Consolas, monospace; font-size: 0.75rem; color: var(--text-dim); }
.fb-my-actions {
  display: flex; align-items: center; justify-content: space-between; gap: 0.75rem;
  flex-wrap: wrap; margin-top: 1rem; padding-top: 0.875rem;
  border-top: 1px solid var(--border-soft);
}

/* ── Detail head ───────────────────────────────────────────────────── */
.fb-detail-title { margin: 0 0 0.25rem; font-size: 1rem; color: var(--text-main); font-weight: 600; }
.fb-detail-tags  { display: flex; gap: 0.4375rem; flex-wrap: wrap; align-items: center; margin-bottom: 0.875rem; }
.fb-detail-when  { font-size: 0.75rem; color: var(--text-dim); }

/* ── Thread ────────────────────────────────────────────────────────── */
.fb-thread { display: flex; flex-direction: column; gap: 0.75rem; }
.fb-msg {
  border: 1px solid var(--card-edge); border-radius: 8px; background: var(--surface-1);
  padding: 0.75rem 0.875rem;
}
.fb-msg.admin {
  border-color: var(--border-strong);
  background: linear-gradient(180deg, rgba(200,146,42,.10), var(--surface-1));
}
/* Internal notes are visually unmistakable — an admin must never mistake one
   for a message the reporter can read. */
.fb-msg.internal {
  border-style: dashed; border-color: rgba(120,110,95,.6);
  background: repeating-linear-gradient(135deg,
      var(--surface-1), var(--surface-1) 10px,
      rgba(120,110,95,.10) 10px, rgba(120,110,95,.10) 20px);
}
.fb-msg.system {
  background: transparent; border: none; border-left: 2px solid var(--border-soft);
  border-radius: 0; padding: 0.25rem 0 0.25rem 0.75rem;
  color: var(--text-dim); font-size: 0.8125rem;
}
.fb-msg-head {
  display: flex; align-items: center; gap: 0.5625rem; margin-bottom: 0.5rem;
  flex-wrap: wrap; font-size: 0.78125rem; color: var(--text-dim);
}
.fb-msg-who  { color: var(--text-main); font-weight: 600; font-size: 0.8125rem; }
.fb-msg-role {
  font-size: 0.75rem; letter-spacing: .1em; text-transform: uppercase;
  border: 1px solid var(--border-strong); color: var(--gold-ink);
  border-radius: 3px; padding: 0.0625rem 0.375rem;
}
.fb-msg-role.user { border-color: var(--border-soft); color: var(--text-dim); }
.fb-msg-sp   { flex: 1 1 auto; }
.fb-msg-body { color: var(--text-main); font-size: 0.875rem; white-space: pre-wrap; }
.fb-sys-note { margin-top: 0.25rem; color: var(--text-main); font-size: 0.8125rem; }

/* ── Reply composer ────────────────────────────────────────────────── */
.fb-reply {
  border: 1px solid var(--card-edge); border-radius: 8px; background: var(--surface-1);
  padding: 0.75rem 0.875rem; margin-top: 0.875rem;
}
.fb-reply-head { display: flex; align-items: center; gap: 0.625rem; margin-bottom: 0.5625rem; flex-wrap: wrap; }
.fb-reply-lbl  { font-size: 0.75rem; letter-spacing: .14em; text-transform: uppercase; color: var(--text-dim); }
.fb-reply-hint { font-size: 0.75rem; color: var(--text-dim); }
.fb-reply-text { min-height: 5.25rem; resize: vertical; }
.fb-reply-actions {
  display: flex; gap: 0.5rem; justify-content: flex-end; align-items: center;
  margin-top: 0.625rem; flex-wrap: wrap;
}
.fb-reply-count { font-size: 0.75rem; color: var(--text-dim); font-variant-numeric: tabular-nums; }
.fb-toggle-internal {
  display: inline-flex; align-items: center; gap: 0.4375rem; font-size: 0.78125rem;
  color: var(--text-dim); background: transparent;
  border: 1px solid var(--border-soft); border-radius: 999px;
  padding: 0.25rem 0.6875rem; cursor: pointer; min-height: 28px; font-family: inherit;
}
.fb-toggle-internal.on { color: var(--gold-ink); border-color: var(--border-strong); background: rgba(200,146,42,.1); }

/* ── Closed hint / notices ─────────────────────────────────────────── */
.fb-closed, .fb-notice {
  border: 1px solid var(--border-soft); border-radius: 8px; background: var(--surface-1);
  padding: 0.75rem 0.875rem; margin-top: 0.875rem; color: var(--text-dim);
  font-size: 0.8125rem; display: flex; align-items: center; gap: 0.625rem;
}
.fb-closed-lock, .fb-notice-ico { font-size: 1.0625rem; flex: 0 0 auto; }

/* ── Lightbox ──────────────────────────────────────────────────────── */
.fb-lightbox {
  display: flex; align-items: center; justify-content: center;
  background: rgba(6,4,2,.6); border-radius: 6px; overflow: hidden;
}
.fb-lightbox img { max-width: 100%; max-height: 70vh; display: block; }
.fb-lightbox-meta {
  margin-top: 0.5rem; font-size: 0.75rem; color: var(--text-dim);
  font-variant-numeric: tabular-nums; text-align: center;
}
.fb-lightbox-count { font-size: 0.8125rem; color: var(--text-dim); font-variant-numeric: tabular-nums; }

@media (hover: hover) {
  .fb-chip:hover            { border-color: var(--border-strong); color: var(--accent-ink); }
  .fb-row:hover             { border-color: var(--border-strong); }
  .fb-upload:hover          { border-color: var(--gold); }
  .fb-toggle-internal:hover { border-color: var(--border-strong); color: var(--gold-ink); }
  .fb-shot-rm:hover         { background: rgba(139,26,26,.5); }
}

@media (max-width: 760px) {
  .fb-frm-grid  { grid-template-columns: 1fr; }
  .fb-row       { grid-template-columns: 1fr; }
  .fb-row-right { flex-direction: row; align-items: center; justify-content: space-between; }
}

/* ═══════════════════════════════════════════════════════════════════════
   Karma — recognition for accepted feedback. NOT a currency:
   the name "Goldnuggets" is reserved for a possible in-game currency, so
   nothing here should read like a wallet.
   ═══════════════════════════════════════════════════════════════════ */

.karma-balance {
  display: flex; align-items: center; gap: 0.875rem;
  border: 1px solid var(--card-edge); border-radius: 8px; background: var(--surface-1);
  padding: 0.875rem 1rem; margin-bottom: 1rem;
}
.karma-big {
  font-family: 'Rye', cursive; font-size: 1.875rem; color: var(--heading);
  line-height: 1; font-variant-numeric: tabular-nums;
  display: flex; align-items: center; gap: 0.5625rem; flex: 0 0 auto;
}
.karma-text   { font-size: 0.8125rem; color: var(--text-dim); }
.karma-text b { color: var(--text-main); display: block; font-size: 0.875rem; margin-bottom: 0.125rem; }

.karma-hist-title {
  margin: 1.125rem 0 0; font-size: 0.75rem; letter-spacing: .14em;
  text-transform: uppercase; color: var(--text-dim); font-weight: 600;
}
.karma-ledger { list-style: none; margin: 0.75rem 0 0; padding: 0; }
.karma-ledger li {
  display: grid; grid-template-columns: auto minmax(0,1fr) auto; gap: 0.625rem;
  align-items: baseline; padding: 0.4375rem 0;
  border-bottom: 1px solid var(--border-soft); font-size: 0.8125rem;
}
.karma-ledger li:last-child { border-bottom: none; }
.karma-amt  { color: var(--gold-ink); font-weight: 600; font-variant-numeric: tabular-nums; }
.karma-src  { color: var(--text-main); overflow-wrap: anywhere; }
.karma-src a { color: var(--text-main); text-decoration: none; }
.karma-when { color: var(--text-dim); font-size: 0.75rem; font-variant-numeric: tabular-nums; }

@media (hover: hover) {
  .karma-src a:hover { color: var(--gold-ink); text-decoration: underline; }
}

@media (max-width: 760px) {
  .karma-ledger li { grid-template-columns: auto minmax(0,1fr); }
  .karma-when      { grid-column: 2; }
}

@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.
       Sides: 0 since the edge-to-edge pass (operator wish, with the PageFrame pages and
       the lobby) — the game header and the board run to the screen edge and drop their
       side borders below; the board keeps its 8px inset for the nested game frame. */
    padding: 0 0 max(8px, env(safe-area-inset-bottom, 0px));
    align-items: stretch; justify-content: flex-start;
  }
  .screen-game.lobby-redesign > .lobby-header-card,
  .screen-game.lobby-redesign > .card-board {
    border-left: none; border-right: none; border-radius: 0;
  }

  /* The lobby (waiting room) likewise: no gutter, and the frame starts right below
     the app header instead of floating vertically centred in the leftover height
     (the ≤700px rule gives 1rem 0.625rem 4.5rem; the bottom clears the fixed footer,
     two rows on the phone). */
  .screen-lobby.lobby-redesign { padding: 0 0 4.5rem; justify-content: flex-start; }
  .screen-lobby.lobby-redesign .lobby-frame { border-radius: 0; }
  .screen-lobby.lobby-redesign .lobby-frame .lobby-header-card,
  .screen-lobby.lobby-redesign .lobby-frame .lobby-layout > .card {
    border-left: none; border-right: none; border-radius: 0;
  }

  /* Game header stays a SINGLE row. The <=700px rule above wraps the lobby header into
     two rows (the code box takes the second); the game header has no code box and no
     height lock to feed, so this override keeps it to one row with tighter gaps. */
  .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; }

  /* App header behind the ☰: the game page drops it (~55px for every game) and the ☰
     in the game header brings the REAL header back as an overlay — volume, theme
     menu, profile menu and the decoration switch (WCAG 2.2.2) work as everywhere.
     Keyed to the ☰ itself, so game states without a game header (role reveal,
     countdown) keep their normal header. Stacking: scrim 940 < header 950 < modals
     (>= 1000), so the leave confirm opened from a header link sits on top. */
  body:has(.lobby-uh .uh-menu, .pf-menu) .app-header { display: none; }
  .screen-game.lobby-redesign .lobby-uh .uh-menu { display: flex; }
  .pf-menu { display: inline-flex; }
  body:has(.lobby-uh .uh-menu, .pf-menu) .app-shell.hdr-open .app-header {
    display: flex; position: fixed; top: 0; left: 0; right: 0; z-index: 950;
    box-shadow: var(--elev-2);
  }
  @media (prefers-reduced-motion: no-preference) {
    body:has(.lobby-uh .uh-menu, .pf-menu) .app-shell.hdr-open .app-header { animation: appHdrDrop .18s ease-out; }
  }
  body:has(.lobby-uh .uh-menu, .pf-menu) .app-hdr-scrim {
    display: block; position: fixed; inset: 0; z-index: 940; background: rgba(8, 5, 2, .62);
  }
  body:has(.app-header .announce-strip) .lobby-uh .uh-menu-dot  { display: block; }
  body:has(.app-header .announce-strip) .lobby-uh .uh-menu-note { display: block; }
  body:has(.app-header .announce-strip) .pf-menu-dot  { display: block; }
  body:has(.app-header .announce-strip) .pf-menu-note { display: block; }

  /* Every PageFrame page (Home, Profil, Regeln, Rechtliches, Neuigkeiten, Feedback,
     Bestenliste, Teams; Admin and Mod drop the header behind the ☰ as well) goes edge
     to edge like the game page: no page gutter, no gap below the app header, no side
     borders, a slim board inset. The frame's gutters, borders and the 1.375rem board
     padding cost 70px of a 360px screen; the content box grows from 290px to 344px.
     The fixed app footer keeps its reservation. */
  .pf-main { padding: 0 0 4.375rem; }
  .pf-main .pf-pageuh, .pf-main .pf-board, .pf-main .pf-footer-bar {
    border-left: none; border-right: none; border-radius: 0;
  }
  .pf-main .pf-pageuh-top { padding: 0.5rem 0.625rem; }
  .pf-main .pf-board { padding: 0.5rem; }
  .pf-main .pf-board.pad-none { padding: 0; }

  /* 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 gets cut mid-word on a single line even
     on a 428px device ("Du bist am Zug — leg eine passende Karte (Farbe oder Symbol) oder zieh nach").
     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: height chain, otherwise the fit eats its own output ---------
     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: 0.625rem 0.75rem; }

  /* ── Shadow game: the impostor's category card a notch tighter ──────────
     It sits in the role reveal, which runs on a timer — whatever sticks out below cannot be
     scrolled to in time. Addressed via .screen-game.bg-red like the desktop condensation, a
     rule on .impostor-* alone would lose on specificity. */
  .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) sets 16px/18px — needs equal specificity */
  /* Clue phase: panel fills the height, the list scrolls in itself, the dock stays at the bottom. */
  .card-board > .screen-game.sh-screen { display: flex; flex-direction: column; justify-content: flex-start; }
  .sh-screen > .sh-layout { flex: 1 1 auto; min-height: 0; grid-template-rows: minmax(0, 1fr); align-items: stretch; }
  .card-board .sh-main { min-height: 0; gap: 8px; }
  .card-board .sh-main > .card-turn-list { flex: 1 1 auto; min-height: 0; overflow-y: auto; }
  .card-board .sh-main > :is(.sh-dock, .sh-wait) { margin-top: auto; }
  .card.card-turn-list { padding: 0.5rem; }

  /* Footer bar (arcade, quizmaster, …) tighter on a phone. */
  .card-board .card-actions-bar { gap: 0.25rem 0.625rem; padding: 0.375rem 0.75rem; }

  /* ── 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 tables (.ct-table): value row · seat pills · felt · turn line · fan · actions ──
     Height chain as for Offiziersskat: the table takes the panel height, the felt the rest,
     so the turn line, the hand and the action row sit at the bottom. Seats WRAP into a
     second line instead of scrolling sideways (a swiped-away opponent is a hidden one), names
     shorten. The action row stays inside the panel — no negative-margin overhang, which
     would make the scrolling .screen-game scroll sideways (see the footer bar note above). */
  .card-board > .screen-game:has(> .ct-table) { display: flex; flex-direction: column; }
  .screen-game > .ct-table { flex: 1 1 auto; min-height: 0; gap: 8px; }
  .ct-table .durak-table { flex: 1 1 auto; padding: 10px; gap: 12px; }
  .ct-table .durak-seats { flex-wrap: wrap; justify-content: center; overflow: visible; padding-bottom: 0; }
  .ct-table .durak-seat .ct-nm { max-width: 9ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  /* Two or more opponents: each pill stacks the name over role + count, so two to three pills
     share one line at 360px instead of one pill per line (measured: 2 x ~250px -> 2 x ~150px). */
  .ct-table .durak-seats:has(> .durak-seat + .durak-seat) .durak-seat {
    display: grid; grid-template-columns: auto auto auto; grid-template-rows: auto auto;
    column-gap: 5px; row-gap: 1px; align-items: center; padding: 3px 10px 3px 3px; border-radius: 16px;
  }
  .ct-table .durak-seats:has(> .durak-seat + .durak-seat) .durak-seat .who { display: contents; }
  .ct-table .durak-seats:has(> .durak-seat + .durak-seat) .durak-seat .avatar { grid-row: 1 / 3; grid-column: 1; }
  .ct-table .durak-seats:has(> .durak-seat + .durak-seat) .durak-seat .ct-nm { grid-row: 1; grid-column: 2 / 4; }
  .ct-table .durak-seats:has(> .durak-seat + .durak-seat) .durak-seat .durak-role { grid-row: 2; grid-column: 2; padding: 0 6px; }
  .ct-table .durak-seats:has(> .durak-seat + .durak-seat) .durak-seat .cnt { grid-row: 2; grid-column: 3; }
  /* Card-count games: the count moves onto the avatar as a badge, the pill keeps name + role —
     that is what lets two opponents with long roles ("Gegenspieler", "Alleinspieler") share
     one line. Poker keeps its .cnt line: that is the stack, not a card count. */
  .ct-table .durak-seats:has(> .durak-seat + .durak-seat) .durak-seat:has(.ct-cardcnt) .ct-cardcnt { display: none; }
  .ct-table .durak-seats:has(> .durak-seat + .durak-seat) .durak-seat:has(.ct-cardcnt) .ct-seat-n {
    display: grid; place-items: center; grid-row: 1 / 3; grid-column: 1; align-self: end; justify-self: end;
    min-width: 16px; height: 16px; padding: 0 3px; margin: 0 -4px -2px 0; border-radius: 8px; z-index: 1;
    font-size: 12px; font-weight: 700; line-height: 1; font-variant-numeric: tabular-nums;
    color: var(--raw-parchment); background: var(--raw-ink, #1a1208); border: 1px solid var(--border-strong);
  }
  .ct-table .ct-hand { padding-top: 14px; }
  .ct-table .ct-actions { gap: 6px; flex-wrap: nowrap; }
  .ct-table .ct-actions .btn { flex: 1 1 0; min-width: 0; padding: 9px 8px; }
  /* Durak: the step tag of the shared throw-in gets a third line of the stacked pill, and the
     trump swap — its label names two cards — a row of its own instead of a third of one. */
  .ct-table .durak-seats:has(> .durak-seat + .durak-seat) .durak-seat .durak-tag { grid-row: 3; grid-column: 2 / 4; justify-self: start; }
  .ct-table .durak-seats:has(> .durak-seat + .durak-seat) .durak-seat:has(.durak-tag) .avatar { grid-row: 1 / 4; }
  .ct-table .ct-actions:has(.durak-swap) { flex-wrap: wrap; }
  .ct-table .ct-actions .durak-swap { flex: 1 1 100%; }
  /* Offiziersskat: content-height table panel (fitOsk models it, see the maximize block). */
  .osk-board.ct-table .osk-table { flex: 0 0 auto; }

  /* ── Real-time games (.arc-board): value row · field · buttons ──────────────
     Same chain as the maximize block: the field takes the rest, its size follows the canvas's
     aspect ratio; the buttons sit at the bottom in thumb reach and get a little bigger. */
  .card-board > .screen-game:has(> .arc-board) { display: flex; flex-direction: column; }
  .screen-game > .arc-board { flex: 1 1 auto; min-height: 0; gap: 8px; }
  .arc-board > .arc-layout { flex: 1 1 auto; min-height: 0; grid-template-rows: minmax(0, 1fr) auto; align-items: stretch; }
  .arc-layout > .arc-main { min-height: 0; }
  .arc-main > .arc-field { flex: 1 1 auto; min-height: 0; container-type: size; display: grid; place-items: start center; }   /* field right under the value row, spare room above the buttons */
  .arc-field > .ks-yard { width: min(100cqw, 100cqh); }
  .arc-field > .sp-mine { width: min(100cqw, calc(100cqh * 19 / 21)); }
  .arc-field > .fg-shaft { width: min(100cqw, calc(100cqh * 11 / 18)); }
  /* .arc-pad-card prefix: game.css loads after this file, its base .arc-dpad / .fg-pad rules win a tie. */
  .arc-pad-card .arc-dpad { grid-template-columns: repeat(3, 60px); grid-template-rows: repeat(3, 48px); }
  .arc-pad-card .fg-pad button { min-height: 48px; }

  .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);
  }
  /* The chips were made for the dark table: in the light themes their dark ground carried the
     dark ink (names at under 2 : 1). There they are light cards like everything else. */
  [data-scheme="light"] .game-sidebar .wanted-poster .wanted-row { background: var(--surface-1-strong); }
  [data-scheme="light"] .game-sidebar .wanted-poster .wanted-row:has(.sidebar-player-name-me) {
    background: color-mix(in srgb, var(--accent) 14%, var(--surface-1-strong));
    box-shadow: 6px 0 10px -6px rgba(0, 0, 0, .25);
  }
  [data-contrast="more"] .game-sidebar .wanted-poster .wanted-row :is(.sidebar-player-name-me, .sidebar-player-status) { color: var(--text-main); }   /* mode ink on the own chip: 6.8 : 1 */
  .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: board drawn turned by 90° ────────────────────────────
     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. */
  /* Two scales: --scale follows the width, --scale-y the height (fitMahjong). A height-rich
     board lets the lying tile (34:26) stretch up to the real upright shape (26:34) instead of
     leaving empty bands above and below; never narrower than upright. The motif keeps its
     proportions (object-fit: contain); stack edges, dot and radius follow the width. */
  .mode-mahjong .mjg-stage {
    width: calc(var(--rot-w) * var(--scale)); height: calc(var(--rot-h) * var(--scale-y, var(--scale)));
  }
  .mode-mahjong .mjg-stone {
    width: calc(34px * var(--scale)); height: calc(26px * var(--scale-y, var(--scale)));
    left: calc(var(--rx) * 40px * var(--scale));
    top:  calc(var(--x)  * 30px * var(--scale-y, var(--scale)));
  }
  .mode-mahjong .mjg-stone img { width: calc(26px * var(--scale)); height: calc(20px * var(--scale-y, 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; }
  /* Value row stays one line on a 320px phone: the hint keeps glyph + count (its name
     stays in aria-label), the board name ellipsizes. */
  .mode-mahjong .mjg-hint .mjg-tool-lbl { display: none; }
  /* The game header right above already carries the mode glyph — the name needs the room. */
  .mode-mahjong .mjg-hud-ico { display: none; }
  .mode-mahjong .mjg-hud { padding-left: 8px; }
  .mode-mahjong .mjg-hud-stats { gap: 6px; }

  /* 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).
     Rows: value row (auto), in the race the ranking pills above the board (auto), BOARD (the
     only flexible row). */
  .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; row-gap: 6px;
    grid-template-rows: auto minmax(0, 1fr); align-items: stretch;
  }
  .mode-mahjong .mjg-layout:not(.solo) { grid-template-rows: auto auto minmax(0, 1fr); }
  .mode-mahjong .mjg-layout > .mjg-sidebar { align-self: start; }

/* -- Seeschlacht fleet duel: one board at a time ------------------------
     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; }

/* -- Shared Sea: a 10x10 window onto the large grid ---------------------
     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; }

/* -- Shipyard: fleet bar instead of a side column -----------------------
     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; }
}

/* ── Leaderboard /Toplist ───────────────────────────────────────── */
/* The dropdown items are display:block, so an auto margin would force a line break. */
a.profile-dropdown-item[href="/Toplist"] { white-space: nowrap; }
.nav-admin-only {
    margin-left: 0.4rem; font-size: 0.75rem; white-space: nowrap;
    color: var(--text-dim); border: 1px solid var(--border-strong); border-radius: 999px; padding: 0 0.45rem;
}
.toplist-preview {
    display: flex; gap: 0.625rem; align-items: center; flex-wrap: wrap; padding: 0.625rem 1rem;
    background: repeating-linear-gradient(135deg, rgba(212,98,10,.16) 0 12px, rgba(212,98,10,.08) 12px 24px);
    border-bottom: 1px solid rgba(212,98,10,.55); color: var(--text-main); font-size: 0.8125rem;
}
.toplist-preview .btn { margin-left: auto; flex: 0 0 auto; width: auto; min-width: 0; }
.toplist-modes {
    display: flex; gap: 0.375rem; flex-wrap: wrap; padding: 0.75rem 1rem;
    border-bottom: 1px solid var(--border-soft);
}
.toplist-chip {
    display: inline-flex; align-items: center; gap: 0.375rem; min-height: 2rem; padding: 0.3rem 0.75rem;
    border-radius: 999px; border: 1px solid var(--border-soft); background: transparent;
    color: var(--text-dim); font: inherit; font-size: 0.8125rem; cursor: pointer; white-space: nowrap;
}
/* Solid --heading with --text-invert, like the family chips: the one pair that holds in every
   theme (the gold fill with dark ink measured 3.4–3.7:1 in three light themes). */
.toplist-chip.on { border-color: var(--heading); background: var(--heading); color: var(--text-invert); font-weight: 600; }
.toplist-chip:focus-visible, .toplist-name:focus-visible { outline: 2px solid var(--heading); outline-offset: 2px; }
@media (hover: hover) { .toplist-chip:not(.on):hover { border-color: var(--border-strong); color: var(--text-main); } }
.toplist-scope {
    display: flex; gap: 0.875rem; flex-wrap: wrap; padding: 0.5rem 1rem; font-size: 0.8125rem;
    color: var(--text-dim); border-bottom: 1px solid var(--border-soft);
}
.toplist-scope b { color: var(--text-main); font-weight: 500; }
.toplist-empty { padding: 1rem; margin: 0; }
.toplist-table-wrap { overflow-x: auto; }
.toplist-table { width: 100%; border-collapse: collapse; font-size: 0.875rem; }
.toplist-table th, .toplist-table td { padding: 0.5rem 1rem; border-bottom: 1px solid var(--border-soft); text-align: left; }
.toplist-table th { color: var(--heading); font-size: 0.75rem; letter-spacing: .08em; text-transform: uppercase; font-weight: 600; }
.toplist-table .r { text-align: right; font-variant-numeric: tabular-nums; }
.toplist-place { width: 4rem; color: var(--text-dim); font-variant-numeric: tabular-nums; }
.toplist-name {
    background: none; border: 0; padding: 0; font: inherit; color: var(--heading); cursor: pointer;
    text-decoration: underline; text-decoration-color: color-mix(in srgb, var(--heading) 35%, transparent); text-underline-offset: 3px;
}
.toplist-you {
    margin-left: 0.375rem; font-size: 0.75rem; padding: 0 0.45rem; border-radius: 999px;
    border: 1px solid var(--green-ok); color: var(--text-main);
}
.toplist-table tr.me td, .toplist-item.me { background: rgba(79,174,116,.12); }
.toplist-gap td { text-align: center; color: var(--text-dim); font-size: 0.75rem; padding: 0.2rem; }
.toplist-foot { margin: 0; padding: 0.625rem 1rem; font-size: 0.8125rem; color: var(--text-dim); }
.toplist-list { display: none; list-style: none; margin: 0; padding: 0; }
.toplist-item {
    display: grid; grid-template-columns: 2.25rem 1fr auto; gap: 0.625rem; align-items: center;
    padding: 0.625rem 1rem; border-bottom: 1px solid var(--border-soft); font-size: 0.875rem;
}
.toplist-item .toplist-place { width: auto; text-align: center; }
.toplist-value { text-align: right; font-variant-numeric: tabular-nums; }
.toplist-value small { display: block; color: var(--text-dim); font-size: 0.75rem; }
@media (max-width: 640px) {
    .toplist-table-wrap { display: none; }
    .toplist-list { display: block; }
    .toplist-modes { flex-wrap: nowrap; overflow-x: auto; }
}

/* ── Own word list (lobby settings, Schattenspiel / Hangman / Tabu) ─────── */
.cwl { margin: 0.25rem 0 0.5rem; }
.cwl-name-row { margin: 0.5rem 0 0.625rem; }
.cwl-name-input {
  width: 100%; font-family: 'Playfair Display', serif; font-style: italic; font-size: 0.9375rem;
  background: var(--input-bg); border: 1px solid var(--border-soft); border-radius: 6px;
  color: var(--text-main); padding: 0.4375rem 0.625rem;
}
.cwl-sub-label { font-size: 0.75rem; letter-spacing: .08em; text-transform: uppercase; color: var(--text-dim); margin: 0.25rem 0 0.375rem; }
.cwl-cat-chips { display: flex; flex-wrap: wrap; gap: 0.4375rem; }
.cwl-cat-chip {
  display: inline-flex; align-items: center; border-radius: 999px;
  background: var(--surface-2); border: 1px solid var(--border-soft); font-size: 0.8125rem; color: var(--text-main);
}
.cwl-cat-chip.editing { border-color: var(--accent-ink, var(--gold)); background: color-mix(in srgb, var(--accent) 16%, var(--surface-2)); }
.cwl-chip-main {
  display: inline-flex; align-items: center; gap: 0.4375rem; background: none; border: none; color: inherit;
  font: inherit; padding: 0.375rem 0.25rem 0.375rem 0.75rem; min-height: 28px; cursor: pointer; border-radius: 999px 0 0 999px;
}
.cwl-cnt { color: var(--text-dim); font-variant-numeric: tabular-nums; }
.cwl-mini-btn {
  width: 24px; height: 24px; margin-right: 0.25rem; border-radius: 50%; border: none; background: transparent;
  color: var(--text-dim); font-size: 0.75rem; display: inline-flex; align-items: center; justify-content: center; cursor: pointer;
}
.cwl-add-cat {
  display: inline-flex; align-items: center; gap: 0.3125rem; padding: 0.375rem 0.8125rem; min-height: 28px;
  border-radius: 999px; border: 1px dashed var(--border-strong); background: transparent;
  color: var(--accent-ink, var(--gold-ink)); font-size: 0.8125rem; cursor: pointer;
}
.cwl-editor { margin-top: 0.75rem; border: 1px solid var(--border-soft); border-radius: 8px; background: var(--surface-2); padding: 0.75rem; }
.cwl-editor-head { display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.5rem; }
.cwl-editor-head input {
  flex: 1; min-width: 0; background: var(--input-bg); border: 1px solid var(--border-soft); border-radius: 6px;
  color: var(--heading); font-weight: 600; font-size: 0.875rem; padding: 0.375rem 0.5625rem;
}
.cwl-editor-label { display: block; font-size: 0.75rem; color: var(--text-dim); margin-bottom: 0.25rem; }
.cwl-editor textarea {
  width: 100%; min-height: 108px; resize: vertical; background: var(--input-bg); border: 1px solid var(--border-soft);
  border-radius: 6px; color: var(--text-main); font-family: inherit; font-size: 0.875rem; line-height: 1.7; padding: 0.5625rem 0.6875rem;
}
.cwl-editor-foot { display: flex; align-items: center; justify-content: space-between; gap: 0.625rem; flex-wrap: wrap; margin-top: 0.5rem; }
.cwl-msg { font-size: 0.8125rem; padding: 0.5rem 0.6875rem; border-radius: 6px; margin: 0.5rem 0; }
.cwl-msg.ok  { color: var(--success); background: color-mix(in srgb, var(--success) 12%, var(--surface-1)); border: 1px solid color-mix(in srgb, var(--success) 40%, transparent); }
.cwl-msg.err { color: var(--danger);  background: color-mix(in srgb, var(--danger) 10%, var(--surface-1));  border: 1px solid color-mix(in srgb, var(--danger) 40%, transparent); }
.cwl-io-row { display: flex; gap: 0.5rem; flex-wrap: wrap; margin-top: 0.375rem; }
.cwl-file { position: relative; overflow: hidden; }
.cwl-file input[type="file"] { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer; }
.cwl-file:focus-within,
.cwl-chip-main:focus-visible,
.cwl-mini-btn:focus-visible,
.cwl-add-cat:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }
.cwl-io-note { font-size: 0.75rem; color: var(--text-dim); margin-top: 0.5rem; line-height: 1.6; }
@media (hover: hover) {
  .cwl-chip-main:hover { color: var(--heading); }
  .cwl-mini-btn:hover  { color: var(--danger); background: var(--surface-1); }
  .cwl-add-cat:hover   { background: color-mix(in srgb, var(--accent) 12%, transparent); }
}

/* ── Quizmaster question sets (/QuizSets) ─────────────────────────────────── */
.qs-intro { margin: 0 0 0.75rem; }
.qs-chips { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 0.75rem; }
.qs-chip {
  display: inline-flex; align-items: center; gap: 0.375rem; max-width: 100%;
  padding: 0.375rem 0.75rem; border-radius: 999px; cursor: pointer; font-size: 0.8125rem;
  background: var(--surface-2); border: 1px solid var(--border-soft); color: var(--text-main);
}
.qs-chip[aria-selected="true"] { border-color: var(--accent); color: var(--accent-ink); background: color-mix(in srgb, var(--accent) 14%, var(--surface-2)); }
.qs-chip-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 14rem; }
.qs-chip-count { font-size: 0.75rem; color: var(--text-dim); }
.qs-set-head { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; margin-bottom: 0.75rem; }
.qs-name { flex: 1 1 14rem; min-width: 0; }
.qs-spacer { flex: 1; }
.qs-editor { display: grid; grid-template-columns: minmax(15rem, 2fr) 3fr; gap: 0.75rem; align-items: start; }
.qs-card { border: 1px solid var(--border-soft); border-radius: 8px; background: var(--surface-2); padding: 0.75rem; min-width: 0; }
.qs-card-title { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; margin-bottom: 0.5rem; }
.qs-card-title h3 { margin: 0; font-size: 0.9375rem; color: var(--heading); }
.qs-count { font-size: 0.75rem; color: var(--text-dim); }
.qs-qlist { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.25rem; max-height: 60vh; overflow-y: auto; }
.qs-qlist button {
  display: grid; grid-template-columns: 1.75rem 1fr auto; align-items: center; gap: 0.5rem; width: 100%; text-align: left;
  padding: 0.375rem 0.5rem; border-radius: 6px; cursor: pointer; font: inherit; font-size: 0.8125rem;
  background: transparent; border: 1px solid transparent; color: var(--text-main);
}
.qs-qlist button[aria-current="true"] { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, transparent); }
.qs-n { color: var(--text-dim); font-variant-numeric: tabular-nums; }
.qs-t { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.qs-ic { color: var(--text-dim); font-size: 0.75rem; white-space: nowrap; }
.qs-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 0.5rem; }
.qs-hint { font-size: 0.75rem; color: var(--text-dim); line-height: 1.6; margin: 0.375rem 0 0; }
.qs-warn { font-size: 0.75rem; line-height: 1.6; margin-top: 0.5rem; padding: 0.5rem 0.6875rem; border-radius: 6px;
  color: var(--text-main); background: color-mix(in srgb, var(--gold) 10%, var(--surface-1)); border: 1px solid color-mix(in srgb, var(--gold) 40%, transparent); }
.qs-wall { display: grid; grid-template-columns: 4.5rem repeat(var(--qs-cols, 1), minmax(3.5rem, 1fr)); gap: 0.25rem; align-items: stretch; overflow-x: auto; }
.qs-wall-cat { display: flex; gap: 0.125rem; align-items: center; min-width: 0; }
.qs-wall-cat .inp { min-width: 0; font-size: 0.75rem; padding: 0.25rem 0.375rem; }
.qs-rowval { font-size: 0.75rem; padding: 0.25rem 0.375rem; }
.qs-cell {
  min-height: 2.5rem; border-radius: 6px; cursor: pointer; font: inherit; font-size: 0.8125rem; font-weight: 600;
  background: var(--surface-1); border: 1px dashed var(--border-soft); color: var(--text-dim);
}
.qs-cell.filled { border-style: solid; color: var(--accent-ink); border-color: color-mix(in srgb, var(--accent) 50%, transparent); }
.qs-cell.gap { color: var(--danger); }
.qs-cell[aria-current="true"] { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 16%, var(--surface-1)); }
.qs-mini {
  width: 1.5rem; height: 1.5rem; flex: 0 0 auto; border-radius: 4px; cursor: pointer; font-size: 0.75rem;
  background: transparent; border: 1px solid var(--border-soft); color: var(--text-dim);
}
.qs-mini:disabled { opacity: .4; cursor: default; }
.qs-form { display: flex; flex-direction: column; gap: 0.75rem; }
.qs-row { display: grid; grid-template-columns: 1fr 1fr; gap: 0.75rem; }
.qs-field { display: flex; flex-direction: column; gap: 0.25rem; min-width: 0; }
.qs-field label, .qs-lbl { font-size: 0.75rem; color: var(--text-dim); }
.qs-field textarea.inp { resize: vertical; min-height: 3rem; line-height: 1.5; }
.qs-seg { display: inline-flex; border: 1px solid var(--border-soft); border-radius: 6px; overflow: hidden; align-self: flex-start; max-width: 100%; }
.qs-seg button {
  padding: 0.375rem 0.75rem; cursor: pointer; font: inherit; font-size: 0.8125rem;
  background: transparent; border: 0; color: var(--text-main); border-right: 1px solid var(--border-soft);
}
.qs-seg button:last-child { border-right: 0; }
.qs-seg button[aria-pressed="true"] { background: color-mix(in srgb, var(--accent) var(--chip-tint), transparent); color: var(--accent-ink); font-weight: 600; }
.qs-media { display: flex; gap: 0.75rem; align-items: flex-start; margin-top: 0.5rem; flex-wrap: wrap; }
.qs-media-col { display: flex; flex-direction: column; gap: 0.5rem; margin-top: 0.5rem; }
.qs-media-side { display: flex; flex-direction: column; gap: 0.25rem; min-width: 0; flex: 1; }
.qs-thumb { width: 8rem; height: 6rem; object-fit: cover; border-radius: 6px; border: 1px solid var(--border-soft); background: var(--surface-1); }
.qs-tracks { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.375rem; }
.qs-track { display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: 0.5rem; padding: 0.375rem 0.5rem;
  border-radius: 6px; border: 1px solid var(--border-soft); background: var(--surface-1); font-size: 0.8125rem; }
.qs-track.sel { border-color: var(--accent); }
.qs-track audio { width: 9rem; height: 2rem; }
.qs-cover { font-size: 1.25rem; }
.qs-vchips { display: flex; flex-wrap: wrap; gap: 0.375rem; align-items: center; }
.qs-vchip { display: inline-flex; align-items: center; gap: 0.25rem; padding: 0.25rem 0.5rem; border-radius: 999px;
  font-size: 0.8125rem; background: var(--surface-1); border: 1px solid var(--border-soft); }
.qs-vinput { flex: 1 1 10rem; }
.qs-opt-row { display: grid; grid-template-columns: auto 1.5rem 1fr auto; align-items: center; gap: 0.375rem; margin-bottom: 0.375rem; }
.qs-opt { font-weight: 700; color: var(--accent-ink); }
.qs-toggle { display: flex; align-items: flex-start; gap: 0.5rem; cursor: pointer; }
.qs-toggle input { margin-top: 0.2rem; }
.qs-status { display: flex; flex-wrap: wrap; gap: 0.375rem; align-items: center; margin-top: 0.75rem; font-size: 0.75rem; color: var(--text-dim); }
.qs-ok { color: var(--success); }
.qs-gap { color: var(--danger); }
@media (max-width: 900px) {
  .qs-editor { grid-template-columns: 1fr; }
  .qs-row { grid-template-columns: 1fr; }
  .qs-qlist { max-height: 40vh; }
}
@media (hover: hover) {
  .qs-chip:hover, .qs-qlist button:hover, .qs-cell:hover { border-color: var(--accent); }
  .qs-mini:hover:not(:disabled) { color: var(--danger); }
}
/* Three header actions do not fit a phone in one row; they wrap here, nowhere else. */
.mode-quizmaster .pf-acts { flex-wrap: wrap; justify-content: flex-end; }
.qm-stage-row { display: flex; align-items: center; gap: 0.375rem; flex-wrap: wrap; margin: 0.5rem 0 0; }
.qm-stage-url { flex: 1 1 14rem; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 0.75rem;
  padding: 0.375rem 0.5rem; border-radius: 6px; background: var(--input-bg); border: 1px solid var(--border-soft); color: var(--text-main); }

/* ═══════════════════════════════════════════════════════════════════════════
   Hoher Kontrast — html[data-contrast="more"] (set by theme-boot.js / ssTheme for every
   catalog theme with HighContrast). Tokens live in the theme block; these rules turn
   tinted surfaces into outlines, the game accent into a stripe in the light mode ink,
   and every edge into an opaque one. Attribute + class selectors outrank the component
   rules, so the block can sit anywhere. Mockup: docs/mockups/ss0498-hoher-kontrast.html.
   ═══════════════════════════════════════════════════════════════════════════ */
/* No atmosphere layers: silhouette, grain and seasonal decoration stay off. */
[data-contrast="more"] :is(.saloon-bg, .saloon-deco, .deco-layer) { display: none; }
[data-contrast="more"] body::before { display: none; }
/* Chrome: black bars with a gold edge; links underlined. */
[data-contrast="more"] .app-header { border-bottom: 2px solid var(--gold); backdrop-filter: none; }
[data-contrast="more"] .app-footer { border-top: 2px solid var(--gold); backdrop-filter: none; }
[data-contrast="more"] .footer-sep { opacity: 1; }
[data-contrast="more"] :is(.footer-link, .legal-page a, .cl-body a, .not-found a, .karma-src a, .player-profile-fulllink a) {
  text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 2px;
}
/* Page frame and panels: plain black head, opaque 2 px edges. */
[data-contrast="more"] .pf-pageuh { background: #000; border: 2px solid var(--board-border); border-bottom: none; }
[data-contrast="more"] .pf-tabs { border-top-color: var(--border-soft); }
[data-contrast="more"] .pg-tab.on { border-bottom-width: 3px; }
/* The home page's segments are told apart by fill and border, not by an underline. */
[data-contrast="more"] .pf-tabs.home .pg-tab.on { border-bottom-width: 1px; }
/* Tournament cards and the hall's head band without the colour wash: the surface, a bar in the game's ink. */
[data-contrast="more"] .tour-art { background: var(--surface-1); border-top: 6px solid var(--accent-ink); border-bottom: 1px solid var(--card-edge); }
[data-contrast="more"] .tour-hh { background: var(--surface-1); color: var(--text-main); border-top: 6px solid var(--accent-ink); border-bottom: 1px solid var(--card-edge); }
[data-contrast="more"] .tour-hh .tour-org { color: var(--text-main); }
[data-contrast="more"] :is(.pf-board, .card-board) { border: 2px solid var(--board-border); }
[data-contrast="more"] .pf-footer-bar { border: 2px solid var(--board-border); border-top: none; }
[data-contrast="more"] .modal-v2 { border: 2px solid var(--border-strong); box-shadow: none; }
[data-contrast="more"] :is(.profile-dropdown, .lang-dd-menu, .volume-pop) { border: 2px solid var(--border-strong); box-shadow: none; }
/* Buttons: flat fills with black ink, 2 px outlines. */
[data-contrast="more"] .btn-ghost { border-width: 2px; }
[data-contrast="more"] :is(.btn-ghost-red, .btn-action-red) { border: 2px solid var(--ghost-red-line); color: var(--ghost-red-ink); background: transparent; }
[data-contrast="more"] .btn-red { background: var(--danger); color: #000; border: 2px solid var(--danger); box-shadow: none; }
[data-contrast="more"] .btn-green { background: var(--success); color: #000; }
[data-contrast="more"] .btn-amber { background: var(--warn-ink); color: #000; box-shadow: none; }
[data-contrast="more"] .btn::after { display: none; }
[data-contrast="more"] .btn:disabled { opacity: .6; }
/* Toggles: an outline around the track, the "off" state no longer relies on the red tint alone. */
[data-contrast="more"] .settings-toggle-btn { box-shadow: inset 0 0 0 2px var(--border-strong); background: #000; }
[data-contrast="more"] .settings-toggle-btn.on { background: var(--toggle-on); box-shadow: none; }
[data-contrast="more"] .toggle { background: #000; border: 2px solid var(--border-strong); }
[data-contrast="more"] .toggle.on { background: var(--toggle-on); border-color: var(--toggle-on); }
/* Home: flat — no emblem, gradient or veil. Poster tiles show the game as a stripe in its mode
   ink with the name in the body ink; the spotlight is a framed card with an accent bar. */
[data-contrast="more"] .pg-poster { border: 1px solid var(--card-edge); box-shadow: none; }
[data-contrast="more"] .pg-poster .art {
  height: auto; min-height: 76px; background: var(--surface-1); box-shadow: none;
  border-top: 6px solid var(--accent-ink); border-bottom: 1px solid var(--card-edge); padding: 0.625rem 0.6875rem 0.5rem;
}
[data-contrast="more"] .pg-poster .art::after, [data-contrast="more"] .pg-poster .emb { display: none; }
[data-contrast="more"] .pg-poster .ic { position: static; display: block; filter: none; color: var(--accent-ink); margin-bottom: 0.375rem; }
/* Two lines reserved, so the rule under the head sits at one height across a row. */
[data-contrast="more"] .pg-poster .nm { position: static; color: var(--text-main); text-shadow: none; min-height: 2.5em; }
[data-contrast="more"] .pg-poster.spotlight-active { border: 3px solid var(--gold); box-shadow: none; }
[data-contrast="more"] .pg-spotlight { background: var(--surface-1); border: 2px solid var(--accent-ink); border-left-width: 10px; box-shadow: none; color: var(--text-main); transition: none; }
[data-contrast="more"] .pg-spotlight::after, [data-contrast="more"] .pg-spotlight-emb { display: none; }
[data-contrast="more"] :is(.pg-spotlight-tag, .pg-spotlight-star, .pg-spotlight-txt h2) { color: var(--accent-ink); text-shadow: none; }
[data-contrast="more"] .pg-spotlight-txt p { color: var(--text-main); }
[data-contrast="more"] .pg-spotlight-meta { color: var(--text-dim); }
[data-contrast="more"] .pg-spotlight-chip { background: #000; color: var(--accent-ink); border: 2px solid var(--accent-ink); box-shadow: none; }
[data-contrast="more"] .pg-spotlight-btns .btn-ghost { background: transparent; border: 2px solid var(--gold); color: var(--gold); }
[data-contrast="more"] .pg-spotlight-pause { background: #000; color: var(--text-main); box-shadow: inset 0 0 0 2px var(--text-main); }
[data-contrast="more"] .pg-spotlight-paused-lbl { background: #000; color: var(--text-main); }
[data-contrast="more"] .pg-spotlight-bar { background: var(--card-edge); }
[data-contrast="more"] .pg-spotlight-bar .fill { background: var(--accent-ink); }
@media (max-width: 760px) {
  [data-contrast="more"] .pg-poster .art { min-height: 0; padding: 0.5rem 0.5625rem 0.375rem; }
  [data-contrast="more"] .pg-spotlight { border-left-width: 6px; }
}
/* Game head: black band, accent stripe in the mode ink, outlined plaques. */
[data-contrast="more"] .lobby-redesign .lobby-uh { background: #000; border: 2px solid var(--board-border); border-bottom: 3px solid var(--accent-ink); }
[data-contrast="more"] .lobby-uh .uh-ico { background: #000; color: var(--accent-ink); border: 2px solid var(--accent-ink); }
[data-contrast="more"] .lobby-uh :is(.uh-icon-btn, .uh-gear) { background: #000; color: var(--text-main); border: 1px solid var(--border-strong); }
[data-contrast="more"] .lobby-uh .uh-leave { color: var(--red-ink); border-color: var(--red-ink); }
[data-contrast="more"] .code-box { background: #000; border: 2px solid var(--gold); box-shadow: none; }
/* Seat cards and the turn line of the card tables: their tinted grounds lift the surface so far
   that the mode inks (made for 7 : 1 on the plain surface) measured 5.5 to 6.9 there. */
[data-contrast="more"] .durak-seat { background: var(--surface-1); }
[data-contrast="more"] .ct-turn, [data-contrast="more"] .ct-turn.is-me { background: transparent; }
/* Chips on an accent tint (the --chip-tint users): no fill, an outline in the mode ink. */
[data-contrast="more"] :is(.skat-rung.now, .durak-role.def, .mjg-spec-chip.active,
  .deck-skin-select .dss.on, .role-pill, .qs-seg [aria-pressed="true"], .wq-difficulty) {
  box-shadow: inset 0 0 0 1px var(--accent-ink);
}
/* Difficulty plaque: its own colour (not the mode) needs an AAA ink as well. */
[data-contrast="more"] .wq-difficulty { --accent-ink: color-mix(in srgb, var(--accent-light) 55%, #ffffff); }
/* Quiz options: selected = thick ring, correct = solid success frame, wrong = dashed (not colour alone). */
[data-contrast="more"] .mq-option { background: var(--surface-1); border: 2px solid var(--border-strong); }
[data-contrast="more"] .mq-option:disabled { opacity: 1; }
[data-contrast="more"] .mq-option.selected { background: var(--surface-1); border: 3px solid var(--gold); box-shadow: none; }
[data-contrast="more"] .mq-option-letter { background: #000; border: 2px solid var(--gold); color: var(--gold); }
[data-contrast="more"] .mq-option.selected .mq-option-letter { background: var(--gold); color: #000; }
[data-contrast="more"] .mq-option.wq-reveal-correct { background: var(--surface-1); border: 3px solid var(--success); box-shadow: none; transform: none; }
[data-contrast="more"] .mq-option.wq-reveal-wrong { opacity: 1; filter: none; border: 2px dashed var(--danger); }
[data-contrast="more"] .mq-option.wq-reveal-wrong .mq-option-text { text-decoration: line-through; text-decoration-thickness: 2px; }
/* Status surfaces: card ground, 2 px frame in the status ink. */
[data-contrast="more"] :is(.toast-info, .toast-abort, .toast-achievement) { background: var(--surface-1-strong); border: 2px solid currentColor; border-left-width: 6px; }
[data-contrast="more"] :is(.alert-error, .alert-success, .alert-warning, .alert-info) { background: var(--surface-1); border: 2px solid currentColor; border-left-width: 6px; }
[data-contrast="more"] .announce { background: #000; border: 2px solid currentColor; border-left-width: 6px; }
/* Maximized board: a flat ground instead of the lit, grained, watermarked stage. */
[data-contrast="more"] body.ss-maximized .screen-game.lobby-redesign > .card-board { background: var(--board-grad-a); }
[data-contrast="more"] body.ss-maximized .screen-game.lobby-redesign > .card-board :is(.card.mq-card, .card.hangman-word-card, .card.memory-board-card) { background: var(--surface-1); }

/* Memory cards are buttons: the look stays the card's own. The owner mark carries the initial. */
button.mem-card { padding: 0; font: inherit; color: inherit; cursor: default; }
button.mem-card.is-clickable { cursor: pointer; }
button.mem-card:focus-visible { outline: 3px solid var(--heading); outline-offset: 2px; z-index: 2; }
.mem-card .owner { display: grid; place-items: center; font-size: 9px; font-weight: 700; line-height: 1; color: #1b1106; }
/* The same mark beside the name in the score list: the legend of the owner dots. */
.sidebar-swatch { flex: 0 0 auto; width: 16px; height: 16px; border-radius: 50%; display: grid; place-items: center;
  font-size: 10px; font-weight: 700; line-height: 1; color: #1b1106; }
/* A note under a row of pills, in line with the pills (the label column is 140px wide). */
.slider-cap-note.pills-note { padding-left: 140px; }
@media (max-width: 560px) { .slider-cap-note.pills-note { padding-left: 0; } }

/* Memory: a card that turns, matches or misses does so without motion for whoever asked for less of it. */
@media (prefers-reduced-motion: reduce) {
  .mem-card, .mem-card.flipped, .mem-card.matched, .mem-card.miss { animation: none !important; }
}
