/* Custom styles based on MAUI application design */
/* Color palette reference: https://color.romanuke.com/tsvetovaya-palitra-3852/ */

/* ════════════════════════════════════════════════════════════════════════════
   Colour token system — THREE tiers (see color-consolidation-effort).
     1. TONES  (--tone-*)  — the ONLY place a hex literal lives. Named by colour
        (raw material). One tone = one value; dup values collapsed here.
     2. ROLES  (--action-* / --text-* / --surface-* / --status-* / --tint-*)  —
        named by USE, never by colour. Reference a tone. This is the vocabulary
        new code should consume. A theme swap re-points tones (or a role), never
        renames a role.
     3. LEGACY --tt-* shims — every historical --tt-* var now points at a role,
        so the ~400 existing call-sites keep working untouched while they migrate
        to roles over time. Do NOT add new --tt-* vars; consume roles directly.
   Night: the block after :root gives every tone its night value and re-points the few roles whose night differs
   from their tone (design_handoff_dark_theme). Names never change; a new tone needs both values.
   ════════════════════════════════════════════════════════════════════════════ */
:root {
    /* ─────────── Tier 1 — TONES (hex lives here only) ─────────── */
    /* Brand clay (DECISION 4: all clay collapsed to #b27c62; legacy #b6846b dropped) */
    --tone-brand-clay: #b27c62;
    --tone-brand-clay-dark: #9c6a52;
    --tone-brand-clay-tint: #F7F3EF;
    --tone-brand-gold: #b0935a;
    --tone-dark-clay-ink: #59392D;      /* opaque dark clay-brown filter text */
    --tone-dark-clay-ink-soft: #A06F5B; /* filter reset label */
    --tone-hand-pill-taupe: #7A6A52;
    --tone-hand-pill-taupe-bg: #F1ECE1;
    --tone-hand-pill-taupe-border: #E2D8C4;
    --tone-ring-gold: #c2a878;    /* DESIGNER: gold avatar ring (was clay) */

    /* Protocol loser-arrow stage palette (design_handoff_bracket_protocol §3.2 PB2_ARW): each consolation
       stage — a receiver column — gets one of 5 cycled colours. Clay reuses the brand token; the other four
       are stage-only. */
    --tone-arrow-pine: #2f7468;
    --tone-arrow-blue: #54648f;
    --tone-arrow-plum: #8a5a78;
    --tone-arrow-ochre: #a3752c;

    /* Reds */
    --tone-accent-red: #D23B2E;   /* accent / loss / section-red (absorbed sharp #f73149) */
    --tone-danger-red: #c0392b;   /* solid destructive (logout/delete) — DECISION 2 kept */
    --tone-reject-rose: #CD5C5C;
    --tone-maroon: #8C2F24;       /* error text only (DECISION E: geo split out) */
    --tone-geo-distance: #8C2F24; /* distance meta — own tone so errors recolour independently */
    --tone-geo-distance-pin: #7E2A20;

    /* Greens (DESIGNER Q1: gain-green folded into win-green → rating-up == win). Two greens. */
    --tone-ok-green: #3f9f6a;     /* confirm/success (legacy #52E02C dropped) */
    --tone-ok-green-dark: #348A5B; /* pressed "confirm": darker by day, lighter at night (a black mix can't lighten) */
    --tone-border-ok: #CFE3D6;    /* green note: border */
    --tone-ok-ink: #3D6B51;       /* green note: text */
    --tone-win-green: #1F9D57;    /* win / live / rating-up (absorbed gain #58A943) */
    --tone-live-grad-top: #1f8a52;
    --tone-live-grad-bot: #2da866;
    --tone-loss-rose: #BA4A57;    /* rating-down in tiles */

    /* Amber / gold / blues */
    --tone-amber: #C98A1E;        /* draw / pending (absorbed #b58324) */
    --tone-warn-amber: #b9772b;
    --tone-warn-ink: #7d5a22;      /* amber "denied" panel title/ink */
    --tone-warn-ink-soft: #6d5c3f; /* amber "denied" panel body text */
    --tone-gold-badge: #9A6F2E;
    --tone-medal-gold: #c9a227;   /* 1st-place / top-3 medal + protocol place number */
    --tone-medal-bronze: #b07a4a; /* 3rd-place medal tone (player-tournaments place chip) */
    --tone-info-blue: #3f93d6;
    --tone-info-ink: #365B7C;     /* info-note text: info-blue is too light for text (3.0) */
    --tone-telegram-blue: #2aabee;
    --tone-tg-wallpaper: #dfe7ee; /* Telegram chat background behind a message preview */
    --tone-tg-sender: #2b7bb9;    /* sender name + links inside a Telegram message preview */
    --tone-tg-meta: #a0a8b0;      /* time stamp inside a Telegram message preview */
    --tone-slate-blue: #5b6b7a;   /* lock / no-DM pill text */
    --tone-chart-line: #3f9ae0;   /* rating-history area chart line + fill */
    --tone-chart-record: #1e6fb0; /* "Record: N TTAR" value on the history chart */

    /* Expenses & support (/donate, the menu banner): the dark clay banner and the expense/support meters. */
    --tone-dark-clay-ink-hover: #684536;
    --tone-clay-light: #ecc3ad;   /* clay accent on the dark banner */
    --tone-green-on-dark: #7fd3a2; /* "covered" on the dark banner */
    --tone-expense-bar: #d6cfc4;
    --tone-meter-track: #ece7df;
    --tone-radio-ring: #c9c2b8;   /* unchecked radio of the payment methods */

    /* Admin registration-statistics charts (REGSTATS §3). The funnel is one clay ramp
       (registered → engaged → played → qualified) light→dark; each area has a slightly darker line tone. */
    --tone-stat-registered: #e8d7ce;      /* mix(brand-clay, 0.3 toward white) — registered area */
    --tone-stat-registered-line: #d0b3a4; /* registered line over the area */
    --tone-stat-engaged: #d0ad9c;         /* mix(brand-clay, 0.62 toward white) — engaged area */
    --tone-stat-engaged-line: #bb8b73;    /* engaged line over the area */
    --tone-stat-qualified-line: #3f271e;  /* qualified line (darker than dark-clay-ink) */
    --tone-stat-unknown-bar: #bdb7ae;     /* hatched "не определена" share */
    /* Warm neutrals specific to the stats charts (the prototype's own greys — kept distinct from the
       cooler --tone-ink-* / --tone-gray-* so the clay chrome stays warm). */
    --tone-stat-ink-2: #6f6a63;       /* card labels */
    --tone-stat-ink-muted: #8a857e;   /* secondary meta */
    --tone-stat-ink-faint: #9a948c;   /* table sub-text / uppercase headers */
    --tone-stat-axis: #a09a92;        /* chart axis text */
    --tone-stat-card-border: #e6e2db; /* stat card / message-card border */
    --tone-stat-warm-bg: #faf9f6;     /* "не определена" row / warm panels */
    --tone-stat-readout-bg: #fff7ef;  /* heatmap hover readout strip */
    --tone-stat-axis-zero: #d8d4cd;   /* zero grid line */
    --tone-stat-icon-faint: #cfccc6;  /* empty/no-access card icon */
    --tone-stat-cell-ink: #7a746c;    /* dark text over a light heatmap cell */
    --tone-stat-hatch-a: #e3dfd8;     /* unknown-growth hatch light band */
    --tone-stat-hatch-b: #efece6;     /* share-bar hatch light band */
    /* Heatmap clay/grey ramp stops (light → mid → dark), consumed as rgb() by AdminStatsDisplay. */
    --tone-stat-heat-clay-0: 248, 242, 238;
    --tone-stat-heat-clay-1: 178, 124, 98;
    --tone-stat-heat-clay-2: 89, 57, 45;
    --tone-stat-heat-gray-0: 244, 242, 239;
    --tone-stat-heat-gray-1: 196, 191, 184;
    --tone-stat-heat-gray-2: 118, 113, 106;

    /* Text inks */
    --tone-ink-primary: #222222;   /* absorbed #262626 / #2B2B2B / #000010 */
    --tone-ink-secondary: #5e5b57; /* absorbed #5a5a5a / #6B6B6B / #7A7A7A / #3A3A3A */
    --tone-ink-tertiary: #9A9A9A;  /* absorbed #938d85 / #8a8a8a / #A8A8A8 */
    --tone-ink-heading: #3b3a38;
    --tone-white: #FFFFFF;

    /* Brand chrome grey — DESIGNER: kept distinct from gray-200 (appbar/tabbar restored to #CACAC8) */
    --tone-chrome-grey: #CACAC8;

    /* Neutral scale */
    --tone-gray-50: #F5F5F5;
    --tone-gray-100: #E1E1E1;
    --tone-gray-200: #C8C8C8;
    --tone-gray-300: #ACACAC;
    --tone-gray-400: #919191;
    --tone-gray-500: #6E6E6E;   /* absorbed TertiaryDark #686869 (~2pt) */
    --tone-gray-600: #404040;
    --tone-gray-700: #7D7D7D;   /* off-scale legacy SecondaryDark (open question) */
    --tone-gray-900: #212121;
    --tone-gray-950: #141414;
    --tone-faint-separator: #CFCDC7;       /* darker separator/chevron — NOT the light hairline */
    --tone-faint-separator-light: #BCBCBC; /* delta-unit separator */

    /* Surfaces / borders / tints */
    --tone-page-bg: #F5F3F0;      /* DESIGNER Q3: single page bg; #FFF7EF (page-bg-warm) folded away */
    --tone-card-warm: #fbfaf8;
    --tone-border-card: #E4E1DA;  /* absorbed GameCard_Border #E0E0E0 */
    --tone-border-warm: #d8d5d0;  /* absorbed row-hover #d7d2c8 / #d0ccc4 */
    --tone-hairline: #eceae7;     /* light divider (absorbed #E4E2DD) */
    --tone-tint-warm-neutral: #f1eee7; /* absorbed #efedea / #EFECE6 / #ece9e4 */
    --tone-tint-highlight-me: #F7E1D5; /* DESIGNER Q4: single "me" highlight; tournament cream #fbf6ee folded away */
    --tone-border-me-row: #eccbb8;
    --tone-tint-ok: #e6f3ec;      /* absorbed win-badge #DBE9DE */
    --tone-tint-amber: #fdf3e7;
    --tone-tint-info: #eaf3fb;
    --tone-tint-error: #fdf1f0;
    --tone-tint-lock: #eef2f6;
    --tone-border-info: #cfe4f5;
    --tone-border-warn: #f2dcc0;
    --tone-border-error: #f1cac4;

    /* Tournament guest (profile-less participant): warm-neutral silhouette + pill. */
    --tone-guest-avatar-bg: #EDEAE5;
    --tone-guest-border: #C6BFB4;   /* dashed avatar/pill border */
    --tone-guest-icon: #9B948A;     /* silhouette stroke */
    --tone-guest-pill-bg: #F1EFEA;
    --tone-guest-pill-ink: #7C756A;
    /* Guest info-note card (own warm-amber set — kept distinct from the generic alert-warn tint). */
    --tone-guest-note-bg: #FDF8EC;
    --tone-guest-note-border: #ECDCB4;
    --tone-guest-note-ink: #6D5C33;
    --tone-guest-note-title: #8A6D24;
    --tone-guest-note-icon: #B58324;
    --tone-guest-note-marker: #C09A4A;

    /* External (RTTF-imported) player: slate-blue "RTTF" pill + globe avatar badge. */
    --tone-external-ink: #4E6076;
    --tone-external-bg: #EDF1F6;
    --tone-external-border: #C9D6E4;
    --tone-external-badge-bg: #5B6B7A;

    /* Tournament status-badge tints (DECISION 3: three kept distinct) */
    --tone-status-reg-bg: #EEE7E2;
    --tone-status-neutral-bg: #e6e4df;
    --tone-status-draft-bg: #e9e7e0;
    --tone-status-finished-fg: #8a8a8a; /* distinct from draft/cancelled #9a9a9a */

    /* Misc accents */
    --tone-status-inactive-grey: #B3ACA4; /* absorbed lock glyph #B0A79E */
    --tone-nodm-brick: #BF5A4F;
    --tone-header-grad-top: #ebeae7;
    --tone-header-grad-bot: #d9d8d5;
    --tone-tour-disabled-bg: #faf8f4;
    --tone-tour-disabled-text: #cfcabf;
    --tone-tour-row-hot: #FDF8EC; /* warm cream, live-game row (prototype #fdf8ef; shares the guest-note hex) */
    /* Protocol ("схема") blank-sheet BLOCK borders — the cross-table cells and bracket match boxes. A
       deliberately "paper"-toned line, stronger than the light card border, so the empty protocol reads
       as a printable sheet (prototype #c9c3b8). The bracket CONNECTORS (stubs + rail between blocks) use
       the lighter --border-card instead, so the links sit visually behind the blocks. */
    --tone-protocol-grid: #c9c3b8;
    --tone-badge-gold-tint: #F6EED9;
    --tone-badge-gold-border: #E7D6AD;
    --tone-qualifying-cream: #F6EED9;
    /* Map-service marks on the venue create form (prototype oklch dots, baked to hex). */
    --tone-map-google: #4c82c6;
    --tone-map-yandex: #bc634d;
    --tone-map-2gis: #4d9351;
    --tone-map-osm: #00959c;
    --tone-map-apple: #75716b;
    /* Hover/pressed veil, an r, g, b triplet: rgba(var(--tone-state-overlay), .06) — black by day, white at night. */
    --tone-state-overlay: 0, 0, 0;

    /* ─────────── Tier 2 — ROLES (named by use; reference tones) ─────────── */
    /* Actions */
    --action-primary: var(--tone-brand-clay);
    --action-primary-pressed: var(--tone-brand-clay-dark);
    --action-confirm: var(--tone-ok-green);
    --action-confirm-pressed: var(--tone-ok-green-dark);
    --action-destructive: var(--tone-accent-red);        /* outlined destructive (tournaments) */
    --action-destructive-strong: var(--tone-danger-red); /* solid logout/delete (open question) */
    --action-reject: var(--tone-reject-rose);
    --action-secondary: var(--tone-white);
    --action-neutral-warm: var(--tone-tint-warm-neutral);
    --action-telegram: var(--tone-telegram-blue);
    --surface-tg-chat: var(--tone-tg-wallpaper);
    --text-tg-sender: var(--tone-tg-sender);
    --text-tg-meta: var(--tone-tg-meta);
    --action-disabled-bg: var(--tone-gray-200);
    --action-disabled-text: var(--tone-gray-950);

    /* Controls */
    --control-track: var(--tone-tint-warm-neutral);
    --control-thumb: var(--tone-white); /* the selected segment's chip on --control-track; lighter than the track at night */
    --control-selected-tint: var(--tone-brand-clay-tint);
    --focus-ring: var(--tone-brand-clay);

    /* Text */
    --text-primary: var(--tone-ink-primary);
    --text-secondary: var(--tone-ink-secondary);
    --text-muted: var(--tone-ink-tertiary);
    --text-heading-warm: var(--tone-ink-heading);
    --text-disabled: var(--tone-gray-300);
    --text-on-accent: var(--tone-white); /* on deep fills only (action-primary/-confirm/-destructive-strong, badge-count…) */
    /* On a fill that is a text/status role (status-win, status-pending, text-accent, action-primary-pressed…): those
       turn light at night, so white on them fails — this one is the card colour there. */
    --text-on-status: var(--tone-white);
    --text-ok: var(--tone-ok-ink);
    --text-info: var(--tone-info-ink);
    --text-link: var(--tone-brand-clay-dark);
    --text-filter-name: var(--tone-dark-clay-ink);
    --text-filter-reset: var(--tone-dark-clay-ink-soft);
    --text-error: var(--tone-maroon);
    --text-accent: var(--tone-accent-red);
    --text-name-suffix: var(--tone-brand-gold);
    --text-place-medal: var(--tone-medal-gold);
    --text-distance: var(--tone-geo-distance);
    --text-score-dimmed: var(--tone-gray-200);
    --text-neutral-strong: var(--tone-gray-600);
    --neutral-mid: var(--tone-gray-500);

    /* Surfaces */
    --surface-page: var(--tone-page-bg);
    --surface-card: var(--tone-white);
    --surface-card-warm: var(--tone-card-warm);
    --surface-sheet: var(--tone-gray-100);
    --surface-raised: var(--tone-white); /* popover, menu, tooltip: above the card at night */
    --surface-inverse: var(--tone-gray-900); /* toast / snackbar */
    --surface-selected-row: var(--tone-gray-100);
    --surface-me-row: var(--tone-tint-highlight-me);
    --surface-row-hot: var(--tone-tour-row-hot); /* warm cream for a row with a live game (prototype #fdf8ef) */
    --surface-disabled-warm: var(--tone-tour-disabled-bg);
    --surface-distance-pin: var(--tone-geo-distance-pin);
    --surface-header-gradient-top: var(--tone-header-grad-top);
    --surface-header-gradient-bot: var(--tone-header-grad-bot);
    --text-disabled-warm: var(--tone-tour-disabled-text);

    /* Borders / lines */
    --border-card: var(--tone-border-card);
    --border-card-warm: var(--tone-border-warm);
    --border-hairline: var(--tone-hairline);
    --border-separator: var(--tone-faint-separator);
    --border-separator-light: var(--tone-faint-separator-light);
    --border-me-row: var(--tone-border-me-row);
    --border-avatar: var(--tone-ring-gold); /* DESIGNER: gold avatar ring (was clay) */
    --border-protocol-grid: var(--tone-protocol-grid);
    --line-input: var(--tone-gray-400);
    --line-divider: var(--tone-gray-200);

    /* Expenses & support */
    --surface-banner-dark: var(--tone-dark-clay-ink);
    --surface-banner-dark-hover: var(--tone-dark-clay-ink-hover);
    --text-on-dark-accent: var(--tone-clay-light);
    --status-covered-on-dark: var(--tone-green-on-dark);
    --chart-expense: var(--tone-expense-bar);
    --chart-support: var(--tone-brand-clay);
    --meter-track: var(--tone-meter-track);
    --line-radio: var(--tone-radio-ring);
    --action-wallet: var(--tone-gray-900); /* stand-in until the wallet's official button (Google Pay brand rules) */

    /* Statistics & support cards: the stats charts' warm greys (kept apart from the cooler --text-muted family) */
    --text-label-warm: var(--tone-stat-ink-2);
    --text-meta-warm: var(--tone-stat-ink-muted);
    --text-axis: var(--tone-stat-axis);
    --text-axis-inactive: var(--tone-stat-icon-faint);
    --text-warn: var(--tone-warn-ink);
    --text-warn-soft: var(--tone-warn-ink-soft);
    --line-axis-zero: var(--tone-stat-axis-zero);
    --surface-panel-warm: var(--tone-stat-warm-bg);

    /* Chrome */
    --chrome-appbar: var(--tone-chrome-grey); /* DESIGNER: restored to #CACAC8, distinct from gray-200 */
    --chrome-dark-surface: var(--tone-gray-700);

    /* Statuses */
    --status-win: var(--tone-win-green);
    --status-win-tint: var(--tone-tint-ok);
    --status-live-gradient-top: var(--tone-live-grad-top);
    --status-live-gradient-bot: var(--tone-live-grad-bot);
    --status-rating-up: var(--tone-win-green); /* DESIGNER Q1: rating-up == win */
    --status-loss: var(--tone-accent-red);
    --status-loss-tint: var(--tone-tint-error);
    --status-rating-down: var(--tone-loss-rose);
    --status-pending: var(--tone-amber);
    --status-registration-bg: var(--tone-status-reg-bg);
    --status-registration-fg: var(--tone-brand-clay-dark);
    --status-neutral-bg: var(--tone-status-neutral-bg);
    --status-draft-bg: var(--tone-status-draft-bg);
    --status-finished-fg: var(--tone-status-finished-fg);
    --status-lock: var(--tone-slate-blue);
    --status-inactive: var(--tone-status-inactive-grey);
    --status-nodm: var(--tone-nodm-brick);

    /* Badges / alerts (composite roles keep their fg tone here; bg/border via tint/border tones) */
    --badge-qualifying-fg: var(--tone-gold-badge);
    --badge-qualifying-bg: var(--tone-badge-gold-tint);
    --badge-qualifying-border: var(--tone-badge-gold-border);
    --badge-hand-fg: var(--tone-hand-pill-taupe);
    --badge-hand-bg: var(--tone-hand-pill-taupe-bg);
    --badge-hand-border: var(--tone-hand-pill-taupe-border);
    /* Closed (invite-only) tournament: the pill and the note share the taupe hand-pill set. */
    --badge-closed-bg: var(--tone-hand-pill-taupe-bg);
    --badge-closed-border: var(--tone-hand-pill-taupe-border);
    --badge-closed-fg: var(--tone-hand-pill-taupe);
    /* Menu badges: a count = waits for your answer, a dot = something new */
    --badge-count-bg: var(--tone-accent-red);
    --badge-count-fg: var(--tone-white);
    --badge-new-dot: var(--tone-brand-clay);
    --badge-map-google: var(--tone-map-google);
    --badge-map-yandex: var(--tone-map-yandex);
    --badge-map-2gis: var(--tone-map-2gis);
    --badge-map-osm: var(--tone-map-osm);
    --badge-map-apple: var(--tone-map-apple);
    --alert-info-fg: var(--tone-info-blue);
    --alert-info-bg: var(--tone-tint-info);
    --alert-info-border: var(--tone-border-info);
    --alert-warn-fg: var(--tone-warn-amber);
    --alert-warn-bg: var(--tone-tint-amber);
    --alert-warn-border: var(--tone-border-warn);
    --alert-error-fg: var(--tone-maroon);
    --alert-error-bg: var(--tone-tint-error);
    --alert-error-border: var(--tone-border-error);
    --alert-ok-bg: var(--tone-tint-ok);
    --alert-ok-border: var(--tone-border-ok);
    --status-lock-bg: var(--tone-tint-lock);
    /* Waitlist ("запас"): the warm-amber set shared with the guest note, plus the nearest
       existing golds/taupe for the queue number, the header meta and the "unconfirmed" hint. */
    --alert-waitlist-bg: var(--tone-guest-note-bg);
    --alert-waitlist-border: var(--tone-guest-note-border);
    --alert-waitlist-fg: var(--tone-guest-note-ink);
    --alert-waitlist-title: var(--tone-guest-note-title);
    --alert-waitlist-icon: var(--tone-guest-note-icon);
    --alert-waitlist-meta: var(--tone-brand-gold);
    --alert-waitlist-number: var(--tone-ring-gold);
    --alert-waitlist-hint: var(--tone-hand-pill-taupe);
    /* Amber notice (a running tournament's "the whole format can change"): the same warm-amber tones */
    --alert-notice-bg: var(--tone-guest-note-bg);
    --alert-notice-border: var(--tone-guest-note-border);
    --alert-notice-fg: var(--tone-guest-note-ink);
    --alert-notice-icon: var(--tone-guest-note-icon);

    /* Alpha washes (web: color-mix from base tone; MAUI: #AARRGGBB literal) */
    --tint-clay-soft: color-mix(in srgb, var(--tone-brand-clay) 10%, transparent);
    --tint-clay-strip: color-mix(in srgb, var(--tone-brand-clay) 13%, transparent);
    --tint-clay-border: color-mix(in srgb, var(--tone-brand-clay) 38%, transparent);
    --tint-clay-reset-border: color-mix(in srgb, var(--tone-brand-clay) 50%, transparent);
    --tint-accent-soft: color-mix(in srgb, var(--tone-accent-red) 9%, transparent);
    --tint-loss-soft: color-mix(in srgb, var(--tone-accent-red) 11%, transparent);
    --tint-win-soft: color-mix(in srgb, var(--tone-win-green) 12%, transparent);
    --tint-pending-soft: color-mix(in srgb, var(--tone-amber) 13%, transparent);
    --tint-tg-soft: color-mix(in srgb, var(--tone-telegram-blue) 11%, transparent);
    --tint-live-shadow: color-mix(in srgb, var(--tone-live-grad-bot) 28%, transparent);
    --tint-danger-hover: color-mix(in srgb, var(--tone-accent-red) 8%, transparent);
    /* Scrims under sheets and dialogs stay black, a bit denser at night: rgba(0, 0, 0, calc(.4 + var(--scrim-extra))). */
    --scrim-extra: 0;

    /* Layout / typography (not colours) */
    --tt-border-radius: 8px;
    --tt-appbar-height: 64px;
    --tt-bottomnav-height: 64px;
    /* Mobile bottom sheets rest here, above the nav. Custom overlays use it for `bottom` and in their max-height. */
    --sheet-bottom: var(--tt-bottomnav-height);
    /* Fixed page action bars (.rail-buttons, .ladder-bar …) stay under every overlay: MudBlazor drawer 1100,
       popover 1200, custom sheets 1200–1300, dialogs 1400. A bar above them hides the sheet's bottom buttons. */
    --z-page-bar: 1050;
    /* Max width of the left-aligned page content column (see .tt-main-content-left-aligned .mud-container).
       The player window uses it to center itself over the content, not the whole viewport. */
    --tt-content-max: 860px;
    --tt-font-family: 'Roboto', system-ui, sans-serif;
    --tt-font-size-body: 0.9375rem; /* 15px */
    --tt-font-size-secondary: 0.8125rem; /* 13px */

    /* ─────────── Tier 3 — LEGACY --tt-* SHIMS (point at roles; do not extend) ───────────
       Every historical colour var below now resolves through a role so existing
       call-sites are appearance-preserving. Migrate sites to roles, then delete a shim. */
    --tt-primary: var(--chrome-appbar);
    --tt-primary-text: var(--text-primary);
    --tt-primary-dark: var(--action-primary);
    --tt-primary-dark-text: var(--text-accent);
    --tt-secondary: var(--action-primary);
    --tt-secondary-text: var(--text-on-accent);
    --tt-tertiary: var(--status-loss);
    --tt-tertiary-soft: var(--text-accent);
    --tt-alert-error-bg: var(--alert-error-bg);
    --tt-alert-error-border: var(--alert-error-border);
    --tt-alert-error-text: var(--alert-error-fg);
    --tt-accept: var(--action-confirm);
    --tt-reject: var(--action-reject);
    --tt-increased-rating: var(--status-rating-up);
    --tt-decreased-rating: var(--status-rating-down);
    --tt-white: var(--tone-white);
    --tt-black: var(--text-primary);
    --tt-gray-50: var(--tone-gray-50);
    --tt-gray-100: var(--tone-gray-100);
    --tt-gray-200: var(--tone-gray-200);
    --tt-gray-300: var(--tone-gray-300);
    --tt-gray-400: var(--tone-gray-400);
    --tt-gray-500: var(--tone-gray-500);
    --tt-gray-600: var(--tone-gray-600);
    --tt-gray-900: var(--tone-gray-900);
    --tt-gray-950: var(--tone-gray-950);
    --tt-current-player-top-bg: var(--surface-me-row);
    --tt-bottom-sheet-bg-light: var(--surface-sheet);
    --tt-bottom-sheet-separator-light: var(--border-hairline);
    --tt-page-bg: var(--surface-page);
    --tt-game-result-win: var(--status-win);
    --tt-game-result-loss: var(--status-loss);
    --tt-game-result-draw: var(--status-pending);
    --tt-game-result-neutral: var(--text-muted);
    --tt-game-card-border: var(--border-card);
    --tt-game-card-separator: var(--border-hairline);
    --tt-game-card-pressed: var(--control-selected-tint);
    --tt-game-text-name: var(--text-primary);
    --tt-game-text-name-strong: var(--text-primary);
    --tt-game-text-sub: var(--text-secondary);
    --tt-game-text-separator: var(--border-separator);
    --tt-game-text-accent-amber: var(--text-name-suffix);
    --tt-game-text-muted: var(--text-muted);
    --tt-game-text-secondary: var(--text-secondary);
    --tt-game-text-delta-unit: var(--border-separator-light);
    --tt-game-qualifying-text: var(--badge-qualifying-fg);
    --tt-game-qualifying-bg: var(--badge-qualifying-bg);
    --tt-game-qualifying-border: var(--badge-qualifying-border);
    --tt-game-hand-pill-text: var(--badge-hand-fg);
    --tt-game-hand-pill-bg: var(--badge-hand-bg);
    --tt-game-hand-pill-border: var(--badge-hand-border);
    --tt-settings-accent: var(--action-primary);
    --tt-settings-accent-dark: var(--action-primary-pressed);
    --tt-settings-accent-tint: var(--control-selected-tint);
    --tt-settings-bg: var(--surface-page);
    --tt-settings-card: var(--surface-card-warm);
    --tt-settings-card-border: var(--border-card-warm);
    --tt-settings-line: var(--border-hairline);
    --tt-settings-ink: var(--text-heading-warm);
    --tt-settings-ink-2: var(--text-secondary);
    --tt-settings-ink-3: var(--text-muted);
    --tt-ok-green: var(--action-confirm);
    --tt-settings-danger: var(--action-destructive-strong);
    --tt-settings-info: var(--alert-info-fg);
    --tt-settings-info-bg: var(--alert-info-bg);
    --tt-settings-info-border: var(--alert-info-border);
    --tt-settings-warn: var(--alert-warn-fg);
    --tt-settings-warn-bg: var(--alert-warn-bg);
    --tt-settings-warn-border: var(--alert-warn-border);
    --tt-settings-tg-blue: var(--action-telegram);
    --tt-settings-tg-blue-soft: var(--tint-tg-soft);
    --tt-settings-pill-neutral-bg: var(--control-track);
    --tt-settings-pill-neutral-text: var(--text-secondary);
    --tt-settings-pill-ok-bg: var(--status-win-tint);
    --tt-settings-pill-lock-bg: var(--status-lock-bg);
    --tt-settings-pill-lock-text: var(--status-lock);
    --tt-settings-header-grad-top: var(--surface-header-gradient-top);
    --tt-settings-header-grad-bot: var(--surface-header-gradient-bot);
    --tt-tour-badge-clay-bg: var(--status-registration-bg);
    --tt-tour-badge-clay-fg: var(--status-registration-fg);

    /* Protocol loser-arrow stage colours (5-colour cycle) + their 10%/38% chip tints (§2.1). */
    --tt-arrow-0: var(--tone-brand-clay-dark);
    --tt-arrow-1: var(--tone-arrow-pine);
    --tt-arrow-2: var(--tone-arrow-blue);
    --tt-arrow-3: var(--tone-arrow-plum);
    --tt-arrow-4: var(--tone-arrow-ochre);
    --tt-arrow-0-bg: color-mix(in srgb, var(--tt-arrow-0) 10%, transparent);
    --tt-arrow-1-bg: color-mix(in srgb, var(--tt-arrow-1) 10%, transparent);
    --tt-arrow-2-bg: color-mix(in srgb, var(--tt-arrow-2) 10%, transparent);
    --tt-arrow-3-bg: color-mix(in srgb, var(--tt-arrow-3) 10%, transparent);
    --tt-arrow-4-bg: color-mix(in srgb, var(--tt-arrow-4) 10%, transparent);
    --tt-arrow-0-bd: color-mix(in srgb, var(--tt-arrow-0) 38%, transparent);
    --tt-arrow-1-bd: color-mix(in srgb, var(--tt-arrow-1) 38%, transparent);
    --tt-arrow-2-bd: color-mix(in srgb, var(--tt-arrow-2) 38%, transparent);
    --tt-arrow-3-bd: color-mix(in srgb, var(--tt-arrow-3) 38%, transparent);
    --tt-arrow-4-bd: color-mix(in srgb, var(--tt-arrow-4) 38%, transparent);
    --tt-tour-badge-win-bg: var(--status-win-tint);
    --tt-tour-badge-win-fg: var(--status-win);
    --tt-tour-badge-amber-fg: var(--status-pending);
    --tt-tour-badge-amber-bg: var(--tint-pending-soft);
    --tt-tour-badge-loss-fg: var(--status-loss);
    --tt-tour-badge-loss-bg: var(--tint-loss-soft);
    --tt-tour-badge-mute-fg: var(--text-muted);
    --tt-tour-badge-mute-bg: var(--status-neutral-bg);
    --tt-tour-badge-neutral-bg: var(--status-neutral-bg);
    --tt-tour-badge-draft-bg: var(--status-draft-bg);
    --tt-tour-live-grad-top: var(--status-live-gradient-top);
    --tt-tour-live-grad-bot: var(--status-live-gradient-bot);
    --tt-tour-live-shadow: var(--tint-live-shadow);
    --tt-tour-suffix-gold: var(--text-name-suffix);
    --tt-tour-place-medal: var(--text-place-medal);
    /* Player-tournaments surfaces (summary + page): place chips, external "slate", disc backgrounds. */
    --tt-ptours-gold: var(--tone-medal-gold);
    --tt-ptours-gold-bg: color-mix(in srgb, var(--tone-medal-gold) 13%, transparent);
    --tt-ptours-slate: var(--tone-slate-blue);
    --tt-ptours-slate-bg: var(--tone-tint-lock);
    --tt-ptours-bronze: var(--tone-medal-bronze);
    --tt-ptours-disc-own: var(--tone-tint-warm-neutral);
    --tt-ptours-clay: var(--action-primary);
    --tt-ptours-clay-dark: var(--action-primary-pressed);
    --tt-ptours-clay-soft: var(--tint-clay-soft);
    --tt-tour-score-lose: var(--text-score-dimmed);
    --tt-tour-card-border: var(--border-card);
    --tt-tour-protocol-grid: var(--border-protocol-grid);
    /* Outer frame of the protocol cross-table — deliberately darker than the inter-row grid so the table edge
       reads stronger than its internal lines (design request). Neutral muted tone for now. */
    --tt-tour-protocol-frame: var(--text-muted);
    --tt-tour-chip-bg: var(--control-track);
    --tt-tour-row-current: var(--surface-me-row); /* DESIGNER Q4: unified "me" highlight */
    --tt-tour-row-hot: var(--surface-row-hot);
    --tt-tour-ink-2: var(--text-secondary);
    --tt-tour-ink-soft: var(--text-secondary);
    --tt-tour-handle: var(--text-muted);
    --tt-tour-disabled-bg: var(--surface-disabled-warm);
    --tt-tour-disabled-text: var(--text-disabled-warm);
    --tt-guest-avatar-bg: var(--tone-guest-avatar-bg);
    --tt-guest-border: var(--tone-guest-border);
    --tt-guest-icon: var(--tone-guest-icon);
    --tt-guest-pill-bg: var(--tone-guest-pill-bg);
    --tt-guest-pill-ink: var(--tone-guest-pill-ink);
    --tt-guest-note-bg: var(--tone-guest-note-bg);
    --tt-guest-note-border: var(--tone-guest-note-border);
    --tt-guest-note-ink: var(--tone-guest-note-ink);
    --tt-guest-note-title: var(--tone-guest-note-title);
    --tt-guest-note-icon: var(--tone-guest-note-icon);
    --tt-guest-note-marker: var(--tone-guest-note-marker);
    --tt-external-ink: var(--tone-external-ink);
    --tt-external-bg: var(--tone-external-bg);
    --tt-external-border: var(--tone-external-border);
    --tt-external-badge-bg: var(--tone-external-badge-bg);
    --tt-rate-accent: var(--text-accent);
    --tt-rate-accent-soft: var(--tint-accent-soft);
    --tt-rate-ink: var(--text-primary);
    --tt-rate-muted: var(--text-muted);
    --tt-rate-sub: var(--text-muted);
    --tt-rate-line: var(--border-hairline);
    --tt-rate-card-bg: var(--surface-card);
    --tt-rate-card-bd: var(--border-card);
    --tt-rate-sunk: var(--control-track);
    --tt-rate-delta-up: var(--status-win);
    --tt-rate-delta-down: var(--status-loss);
    --tt-rate-delta-flat: var(--text-muted);
    --tt-rate-dist: var(--text-distance);
    --tt-rate-dist-pin: var(--surface-distance-pin);
    --tt-rate-inactive: var(--status-inactive);
    --tt-rate-nodm: var(--status-nodm);
    --tt-rate-lock: var(--status-inactive);
    --tt-rate-tg: var(--action-telegram);
    --tt-rate-you-bg: var(--surface-me-row);
    --tt-rate-you-bd: var(--border-me-row);
}

/* ─────────── Night palette ───────────
   Same tones and roles, night values. js/theme.js sets data-theme on <html> before the first paint (the saved
   choice, or prefers-color-scheme for "system"). Screen only: a printout always takes the day palette. */
@media screen {
    :root[data-theme="dark"] {
        color-scheme: dark;

        --tone-brand-clay: #9C6A52;
        --tone-brand-clay-dark: #BF8C72;
        --tone-brand-clay-tint: #302822;
        --tone-brand-gold: #CDAE74;
        --tone-dark-clay-ink: #E6C6B3;
        --tone-dark-clay-ink-soft: #C99A84;
        --tone-hand-pill-taupe: #C4B396;
        --tone-hand-pill-taupe-bg: #2B2721;
        --tone-hand-pill-taupe-border: #4A4235;
        --tone-ring-gold: #B89E6E;

        --tone-arrow-pine: #5DB3A4;
        --tone-arrow-blue: #8F9DD4;
        --tone-arrow-plum: #C78FB3;
        --tone-arrow-ochre: #D5A55B;

        /* Reds */
        --tone-accent-red: #EE6A5C;
        --tone-danger-red: #C94236;
        --tone-reject-rose: #E07B74;
        --tone-maroon: #F09284;
        --tone-geo-distance: #E58E80;
        --tone-geo-distance-pin: #C2574A;

        --tone-ok-green: #2E8456;
        --tone-ok-green-dark: #3E9C69;
        --tone-border-ok: #2C4A39;
        --tone-ok-ink: #9FD3B3;
        --tone-win-green: #43B877;
        --tone-live-grad-top: #1D7A49;
        --tone-live-grad-bot: #26935A;
        --tone-loss-rose: #E57C88;

        /* Amber / gold / blues */
        --tone-amber: #DCA23E;
        --tone-warn-amber: #E0A45A;
        --tone-warn-ink: #EBCB91;
        --tone-warn-ink-soft: #CDBB98;
        --tone-gold-badge: #DDB872;
        --tone-medal-gold: #D8B23A;
        --tone-medal-bronze: #C99263;
        --tone-info-blue: #6DB1EB;
        --tone-info-ink: #A9CBEB;
        --tone-telegram-blue: #2AABEE;
        --tone-tg-wallpaper: #17212B;
        --tone-tg-sender: #6AB3F3;
        --tone-tg-meta: #6D7A86;
        --tone-slate-blue: #A2B2C2;
        --tone-chart-line: #5DAEEE;
        --tone-chart-record: #8CC4F2;

        --tone-dark-clay-ink-hover: #47302A;
        --tone-clay-light: #ECC3AD;
        --tone-green-on-dark: #7FD3A2;
        --tone-expense-bar: #4D4842;
        --tone-meter-track: #2E2A26;
        --tone-radio-ring: #736D66;

        --tone-stat-registered: #4A372D;
        --tone-stat-registered-line: #8A6B5B;
        --tone-stat-engaged: #6E4F40;
        --tone-stat-engaged-line: #B78A72;
        --tone-stat-qualified-line: #EBCDBB;
        --tone-stat-unknown-bar: #5B5650;
        --tone-stat-ink-2: #A9A39B;
        --tone-stat-ink-muted: #99938B;
        --tone-stat-ink-faint: #8D877F;
        --tone-stat-axis: #858079;
        --tone-stat-card-border: #34312D;
        --tone-stat-warm-bg: #1E1C1A;
        --tone-stat-readout-bg: #2A241E;
        --tone-stat-axis-zero: #45413C;
        --tone-stat-icon-faint: #4F4B46;
        --tone-stat-cell-ink: #D9D2C9;
        --tone-stat-hatch-a: #2F2C28;
        --tone-stat-hatch-b: #282522;
        --tone-stat-heat-clay-0: 38, 33, 30;
        --tone-stat-heat-clay-1: 156, 106, 82;
        --tone-stat-heat-clay-2: 236, 196, 172;
        --tone-stat-heat-gray-0: 36, 34, 31;
        --tone-stat-heat-gray-1: 92, 88, 83;
        --tone-stat-heat-gray-2: 176, 170, 162;

        /* Text inks */
        --tone-ink-primary: #ECE8E3;
        --tone-ink-secondary: #B4AFA8;
        --tone-ink-tertiary: #9A958E;
        --tone-ink-heading: #DEDAD4;
        --tone-white: #22201D;

        --tone-chrome-grey: #252320;

        /* Neutral scale */
        --tone-gray-50: #1E1C1A;
        --tone-gray-100: #312E2B;
        --tone-gray-200: #3D3A36;
        --tone-gray-300: #67635E;
        --tone-gray-400: #726E68;
        --tone-gray-500: #9B968F;
        --tone-gray-600: #CFCAC3;
        --tone-gray-700: #87827C;
        --tone-gray-900: #0E0D0C;
        --tone-gray-950: #8E8983;
        --tone-faint-separator: #4D4944;
        --tone-faint-separator-light: #5C5853;

        /* Surfaces / borders / tints */
        --tone-page-bg: #161513;
        --tone-card-warm: #1C1A18;
        --tone-border-card: #36332F;
        --tone-border-warm: #3E3B37;
        --tone-hairline: #2E2B28;
        --tone-tint-warm-neutral: #2D2A26;
        --tone-tint-highlight-me: #3A2B23;
        --tone-border-me-row: #6B4A3A;
        --tone-tint-ok: #172A20;
        --tone-tint-amber: #2D2317;
        --tone-tint-info: #16232F;
        --tone-tint-error: #301C1A;
        --tone-tint-lock: #1C232B;
        --tone-border-info: #24405A;
        --tone-border-warn: #574329;
        --tone-border-error: #5E2E28;

        --tone-guest-avatar-bg: #2E2B27;
        --tone-guest-border: #5F5850;
        --tone-guest-icon: #8E877D;
        --tone-guest-pill-bg: #2B2825;
        --tone-guest-pill-ink: #B0A89C;
        --tone-guest-note-bg: #2A2419;
        --tone-guest-note-border: #4E4129;
        --tone-guest-note-ink: #DCCBA2;
        --tone-guest-note-title: #E6C878;
        --tone-guest-note-icon: #D8A443;
        --tone-guest-note-marker: #C7A55E;

        --tone-external-ink: #A8B8CB;
        --tone-external-bg: #1B222A;
        --tone-external-border: #344150;
        --tone-external-badge-bg: #5A6B7E;

        /* Tournament status-badge tints (DECISION 3: three kept distinct) */
        --tone-status-reg-bg: #33291F;
        --tone-status-neutral-bg: #312F2C;
        --tone-status-draft-bg: #2C2B27;
        --tone-status-finished-fg: #8C8781;

        /* Misc accents */
        --tone-status-inactive-grey: #6E6963;
        --tone-nodm-brick: #DD7D72;
        --tone-header-grad-top: #2F2D2A;
        --tone-header-grad-bot: #282623;
        --tone-tour-disabled-bg: #1B1A17;
        --tone-tour-disabled-text: #57534D;
        --tone-tour-row-hot: #2A2419;
        --tone-protocol-grid: #4B4641;
        --tone-badge-gold-tint: #2F2818;
        --tone-badge-gold-border: #5A4A2B;
        --tone-qualifying-cream: #2F2818;
        --tone-map-google: #6E9FDB;
        --tone-map-yandex: #D9806A;
        --tone-map-2gis: #6DB571;
        --tone-map-osm: #2BB3B9;
        --tone-map-apple: #9A958F;
        --tone-state-overlay: 255, 255, 255;

        /* Roles whose night differs from their tone's night. */
        --text-on-accent: #FFFFFF;          /* white stays white on clay / red / green fills */
        --badge-count-fg: #FFFFFF;
        --badge-count-bg: #D23B2E;          /* the day red: white digits AA 4.8 (the night accent-red is a text tone) */
        --surface-banner-dark: #3B271F;     /* the support banner: dark clay, lighter than the night page */
        --text-score-dimmed: var(--tone-gray-300); /* a dim text, not a line colour */
        --surface-raised: var(--tone-gray-100);
        --surface-inverse: var(--tone-gray-200);
        --control-thumb: var(--tone-gray-200);

        /* Tints: the same formula with a higher share — the same share reads weaker on dark. */
        --tint-clay-soft: color-mix(in srgb, var(--tone-brand-clay) 14%, transparent);
        --tint-clay-strip: color-mix(in srgb, var(--tone-brand-clay) 18%, transparent);
        --tint-clay-border: color-mix(in srgb, var(--tone-brand-clay) 50%, transparent);
        --tint-clay-reset-border: color-mix(in srgb, var(--tone-brand-clay) 60%, transparent);
        --tint-accent-soft: color-mix(in srgb, var(--tone-accent-red) 14%, transparent);
        --tint-loss-soft: color-mix(in srgb, var(--tone-accent-red) 16%, transparent);
        --tint-win-soft: color-mix(in srgb, var(--tone-win-green) 16%, transparent);
        --tint-pending-soft: color-mix(in srgb, var(--tone-amber) 16%, transparent);
        --tint-tg-soft: color-mix(in srgb, var(--tone-telegram-blue) 16%, transparent);
        --tint-live-shadow: color-mix(in srgb, var(--tone-live-grad-bot) 40%, transparent);
        --tint-danger-hover: color-mix(in srgb, var(--tone-accent-red) 12%, transparent);
        --scrim-extra: 0.15;
    }
}

/* Base styles */
html {
    overflow-x: hidden;
    height: 100%;
    color-scheme: light;
}

body {
    /* Fixed-height, non-scrolling shell root. The app-wide scroll container is .mud-main-content
       (MainLayout.razor), NOT the window/body — the shell is a 100svh flex column
       (appbar / scrolling middle / bottom nav) so the bottom nav is an in-flow band that never
       lags the visual viewport (see BottomNavigation.razor / MainLayout.razor for the why).
       overflow:hidden here keeps body itself from scrolling; overflow-x:clip is retained so any
       accidental horizontal overflow is clipped rather than spawning an x-scrollbar. Because the
       real scroller is .mud-main-content (an element), position:sticky inside pages engages
       against it — the old "window is the scroll container, so sticky never engages" caveat no
       longer applies; page stickies are anchored at scroller top:0 / bottom:0. */
    height: 100svh;
    overflow: hidden;
    overflow-x: clip;
    margin: 0;
    padding: 0;
    font-family: var(--tt-font-family);
}

/* Japanese fonts have no italic: a synthesized slant of kanji looks broken, so CJK stays upright (Roboto keeps its own). */
html:lang(ja) {
    font-synthesis-style: none;
}

/* Every layout's one root. The WASM takeover removes each prerendered top-level node under <body>, and one detached
   meanwhile (a page translator) kills the page, so nothing may sit loose. No box of its own: layout is unchanged. */
.layout-shell {
    display: contents;
}

/* PlayerAvatar initials without a photo: the day pastel pair and the raw name-hash colour arrive as custom properties.
   At night the hash colour sits 34% over the card and the initials are it lightened toward white (no bright blobs). */
.mud-avatar.tt-avatar-hash {
    background: var(--_av-bg);
    color: var(--_av-fg);
}

@media screen {
    :root[data-theme="dark"] .mud-avatar.tt-avatar-hash {
        background: color-mix(in srgb, var(--_av) 34%, var(--surface-card));
        color: color-mix(in srgb, var(--_av) 50%, white);
    }
}

/* An <img> with a night variant: render both (lazy, so the hidden one isn't fetched); only the inactive one is hidden,
   so the component's own display stays. A printout takes the day one. */
:root:not([data-theme="dark"]) .theme-img--dark {
    display: none;
}

@media screen {
    :root[data-theme="dark"] .theme-img--light {
        display: none;
    }
}

@media print {
    .theme-img--dark {
        display: none;
    }
}

/* Night elevation is lightness: flat cards keep only their border, floating layers add the card border and a black
   shadow dense enough to read on the dark page. */
@media screen {
    :root[data-theme="dark"] .mud-popover.mud-paper {
        background-color: var(--surface-raised);
    }

    :root[data-theme="dark"] .mud-popover.mud-paper,
    :root[data-theme="dark"] .mud-dialog,
    :root[data-theme="dark"] .mud-snackbar,
    :root[data-theme="dark"] [data-sheet-panel] {
        box-shadow: 0 0 0 1px var(--border-card), 0 10px 30px rgba(0, 0, 0, 0.45);
    }

    /* MudBlazor paints its scrollbar a fixed light grey. */
    :root[data-theme="dark"] ::-webkit-scrollbar-thumb {
        background: var(--tone-gray-300);
    }

    :root[data-theme="dark"] ::-webkit-scrollbar-thumb:hover {
        background: var(--tone-gray-500);
    }

    :root[data-theme="dark"],
    :root[data-theme="dark"] body * {
        scrollbar-color: var(--tone-gray-300) transparent;
    }
}

/* MudBlazor overrides */
.mud-main-content {
    background-color: var(--tt-page-bg);
}

.mud-paper,
.mud-card,
.mud-button-root:not(.mud-switch-base),
.mud-input,
.mud-text-field {
    border-radius: var(--tt-border-radius);
}

/* MudSwitch renders its draggable knob as a .mud-switch-base, which also carries
   .mud-button-root (it is an internal MudIconButton). The global button sizing
   below was forcing min-height:44px and a square border-radius onto that knob,
   inflating it past the 38px track and pushing it down ("sagging" switch). Scope
   the override to real buttons by excluding the switch base. */
.mud-button-root:not(.mud-switch-base) {
    font-weight: 500;
    text-transform: none;
    padding: 10px 14px;
    min-height: 44px;
}

    /* Disabled button: Gray200 fill, no opacity fade. .mud-hidden (opacity:0) is excluded — MudDatePicker
       uses it for off-month cells, and the !important opacity here made the disabled ones visible. */
    .mud-button-root:not(.mud-switch-base):not(.mud-hidden):disabled,
    .mud-button-root:not(.mud-switch-base):not(.mud-hidden).mud-disabled {
        background-color: var(--tt-gray-200) !important;
        color: var(--tt-gray-950) !important;
        box-shadow: none !important;
        opacity: 1 !important;
        border-color: transparent !important;
        cursor: default;
    }

/* ============================================================================
   Tournament hand-CSS button family (prototype tour-chrome.jsx `Btn`) — the SINGLE
   home for the .btn look. Markup is `class="btn <color> [<size>]"`. Colour lives here
   once (this is what used to drift between scoped copies); size modifiers (.block/.sm)
   and any component-local size overrides (compact match-row, create/start block) stay
   in the scoped .razor.css of the component that needs them. Border tone for the white
   outline/neutral variants is --tt-settings-card-border (design token border-warm).
   ============================================================================ */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    border: 1.5px solid transparent;
    border-radius: 8px;
    padding: 12px 16px;
    font-size: 15px;
    font-weight: 600;
    line-height: 1;
    cursor: pointer;
    color: var(--text-on-accent);
}

    .btn:disabled {
        opacity: 0.5;
        cursor: not-allowed;
    }

/* Full-width (block) modifier — width only; per prototype `full` does NOT change the
   md size. Pages that historically ran a smaller block button keep that size via a
   scoped override. Bottom spacing is NOT set here: some rails stack their block buttons
   and add margin-bottom in their own scope (TournamentDetailPage), while others space
   them with a flex `gap` (Create/Start .rail-buttons) — a global margin would double up. */
.btn.block {
    display: flex;
    width: 100%;
}

/* Compact (sm) modifier. */
.btn.sm {
    padding: 6px 12px;
    font-size: 12.5px;
}

/* Colour variants — the one place each fill/border/text lives. */
.btn.clay {
    background: var(--tt-settings-accent);
}

.btn.green {
    background: var(--tt-ok-green);
}

.btn.red {
    background: var(--tt-game-result-loss);
    color: var(--text-on-status);
}

/* Confirm actions are the only green-filled buttons (design §4: green = confirm only).
   Transparent border (not none) so its height matches an outlined sibling in a pair. */
.btn.confirm-green {
    background: var(--tt-ok-green);
    color: var(--text-on-accent);
    border-color: transparent;
}

/* Accent outline (web .btn.outline): white fill, warm border, clay text. */
.btn.outline {
    background: var(--surface-card);
    border: 1.5px solid var(--tt-settings-card-border);
    color: var(--tt-settings-accent);
}

/* Neutral (web .btn.neutral): same warm border as .btn.outline; differs only by the
   muted INK2 label (not the clay text the outline variant uses). */
.btn.neutral {
    background: var(--surface-card);
    border: 1.5px solid var(--tt-settings-card-border);
    color: var(--tt-tour-ink-2);
}

/* Danger outline (web .btn.outline-red): white fill, red border + text. */
.btn.outline-red {
    background: var(--surface-card);
    border: 1.5px solid var(--tt-game-result-loss);
    color: var(--tt-game-result-loss);
}

/* Cancel-tournament outline: white fill, soft alert border, red text. */
.btn.cancel-tour {
    background: var(--surface-card);
    border: 1.5px solid var(--tt-alert-error-border);
    color: var(--tt-game-result-loss);
}

/* Leading icon / in-button spinner (prototype Btn icon=): inherits the button text color. */
.btn-icon {
    width: 18px;
    height: 18px;
    font-size: 18px;
    flex-shrink: 0;
}

.btn-spin {
    width: 18px !important;
    height: 18px !important;
    flex-shrink: 0;
    color: currentColor;
}

    .btn-spin .mud-progress-circular-circle {
        color: currentColor;
    }

/* Rating colors */
.tt-rating-increased {
    color: var(--tt-increased-rating);
    font-weight: 500;
}

.tt-rating-decreased {
    color: var(--tt-decreased-rating);
    font-weight: 500;
}

/* Action buttons */
.tt-accept-button {
    background-color: var(--tt-accept) !important;
    color: var(--text-on-accent) !important;
}

.tt-reject-button {
    background-color: var(--tt-reject) !important;
    color: var(--text-on-status) !important;
}

/* Mobile adjustments */
@media (max-width: 959px) {
    /* No bottom reserve needed anymore: the bottom nav is an in-flow flex band BELOW the
       .mud-main-content scroller (not a fixed bar overlapping it), so page content already ends
       above the nav. A padding-bottom here would just add a dead scrollable strip. */

    /* Stick tab bar to the top of the .mud-main-content scroller (which carries the AppBar
       padding-top), so top:0 sits directly under the fixed AppBar. */
    .mud-tabs-tabbar {
        position: sticky;
        top: 0;
        z-index: 100;
    }
}

/* Shared sticky tab-bar chrome for the app's custom (non-MudBlazor) horizontal tab strips
   (Tournaments feed .tour-tabs, History .hist-tabs, tournament detail .sub-tabs). Only the parts
   that are IDENTICAL across all three live here: the sticky frame and the mobile full-bleed. Each
   page keeps its own scoped class for what genuinely differs (gap, margins, tab typography, whether
   the pill/legend slot exists). Compose them: class="tt-sticky-tabs <page-class>".
   Sticks inside the .mud-main-content scroller — its padding-top already reserves the fixed AppBar
   height, so top:0 sits right under the bar with no per-breakpoint 56/64px offset. The opaque
   page-bg keeps scrolling content from showing through the pinned bar; the active underline must be
   an in-box border-bottom (not a negative margin / absolute ::after) so the mobile overflow-x below
   spawns no phantom scrollbar. */
.tt-sticky-tabs {
    display: flex;
    border-bottom: 1px solid var(--tt-game-card-separator);
    position: sticky;
    top: 0;
    z-index: 10;
    background: var(--tt-page-bg);
}

/* Mobile: full-bleed the bar */
@media (max-width: 720px) {
    .tt-sticky-tabs {
        margin-left: -16px;
        margin-right: -16px;
        padding-left: 16px;
        padding-right: 16px;
        padding-top: 8px;
        overflow-x: auto;
        scrollbar-width: none; /* Firefox / standard */
    }

        .tt-sticky-tabs::-webkit-scrollbar {
            display: none;
        }
}

/* Horizontal gestures (ttGesture in interop.js). data-tt-pan-y marks a gesture's area — a tab bar's parent, the
   drawer and its scrim: the browser pans only mostly-vertical moves there and leaves the rest to the gesture, which
   claims exactly those. touch-action stops at the nearest scroller, so a horizontally scrollable box inside (a tab
   bar too) keeps its own panning. A swipeable bar's panel (its later siblings) follows the finger, then enters from
   the swipe's side. */
@media (max-width: 959px) {
    [data-tt-pan-y] {
        touch-action: pan-y pinch-zoom;
    }

    [data-tt-enter="next"] ~ * {
        animation: tt-tab-enter-next 0.22s ease-out;
    }

    [data-tt-enter="prev"] ~ * {
        animation: tt-tab-enter-prev 0.22s ease-out;
    }
}

@keyframes tt-tab-enter-next {
    from {
        transform: translateX(40px);
        opacity: 0;
    }
}

@keyframes tt-tab-enter-prev {
    from {
        transform: translateX(-40px);
        opacity: 0;
    }
}

@media (prefers-reduced-motion: reduce) {
    [data-tt-enter] ~ * {
        animation: none;
    }
}

/* Dark mode intentionally disabled — light-only app */

/* Bottom sheet action button: icon on top, label below (matches MAUI layout) */
.bs-action-btn {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    width: 70px;
    padding: 10px 0;
    background: transparent;
    border: none;
    cursor: pointer;
    color: inherit;
    gap: 6px;
}

    .bs-action-btn span {
        font-size: 12px;
        line-height: 1.2;
        text-align: center;
        white-space: nowrap;
    }

/* List tile shared styles */
.tt-tile {
    cursor: pointer;
}

.tt-tile--selected {
    background-color: var(--tt-gray-100) !important;
}

.tt-tile--current-player {
    background-color: var(--tt-current-player-top-bg) !important;
}

.tt-tile-secondary-text {
    color: var(--tt-gray-400);
}

/* ═══════════════════════════════════════════════════════════════════════════
   Ratings section — cards · roomy · red accent · bracketed delta (design §5/§8/§14)
   ═══════════════════════════════════════════════════════════════════════════ */

/* .rate-page / .rate-title moved to the scoped Pages/Top/TopPage.razor.css so Top shares the plain
   left-aligned column shell (24×32 desktop, 16 mobile @720px, title shown on mobile) of HistoryPage /
   TournamentsPage. The old full-bleed host + hidden-mobile-title lived here and drifted this page.
   The tab chrome is the shared <PillTabBar> (its own scoped CSS); the old .rate-tabs MudTabs
   stylesheet that used to live here died when TopPage switched to PillTabBar. */

/* Filters column spacing */
.rate-filters {
    display: flex;
    flex-direction: column;
    gap: 14px;
    margin-bottom: 18px;
}

/* Search field — thin card border, magnifier on the LEFT (prototype SearchField) */
.rate-search {
    display: flex;
    align-items: center;
    gap: 9px;
    background: var(--surface-card);
    border: 1px solid var(--tt-rate-card-bd);
    border-radius: 10px;
    padding: 10px 14px;
}

.rate-search-icon {
    display: inline-flex;
    flex-shrink: 0;
}

.rate-search-input {
    flex: 1;
    border: none;
    outline: none;
    background: none;
    font-family: var(--tt-font-family);
    font-size: 15px;
    color: var(--tt-rate-ink);
    min-width: 0;
}

    .rate-search-input::placeholder {
        color: var(--text-muted);
    }

.rate-search-clear {
    border: none;
    background: none;
    cursor: pointer;
    color: var(--text-disabled);
    display: flex;
    padding: 2px;
}

.rate-found {
    font-size: 14px;
    color: var(--text-muted);
}

/* Mobile: tighter vertical rhythm (matches the prototype's compact mobile shell).
   Placed AFTER the base rules so equal-specificity mobile overrides win. The side gutter now comes
   from .rate-page (scoped TopPage.razor.css) like History/Tournaments — no per-panel inset here. */
@media (max-width: 720px) {
    .rate-filters {
        gap: 12px;
        margin-bottom: 12px;
    }

    .rate-search {
        padding: 9px 12px;
    }
}

/* Sort segment + distance on ONE row */
.rate-controls-row {
    display: flex;
    align-items: center;
    gap: 20px;
    flex-wrap: wrap;
}

/* Sort segment (By rating / Near me) — sunken track, white active pill, red label */
.rate-seg {
    display: inline-flex;
    background: var(--tt-rate-sunk);
    border-radius: 9px;
    padding: 3px;
    gap: 2px;
    flex-shrink: 0;
}

.rate-seg-btn {
    border: none;
    border-radius: 7px;
    text-transform: none;
    font-family: var(--tt-font-family);
    font-size: 13.5px;
    font-weight: 600;
    padding: 6px 14px;
    color: var(--text-secondary);
    background: transparent;
    cursor: pointer;
    white-space: nowrap;
    transition: color .12s, background .12s;
}

/* "By rating" is a link (crawlers follow it to the leaders page), drawn as its siblings. */
a.rate-seg-btn {
    display: inline-flex;
    align-items: center;
    text-decoration: none;
}

.rate-seg-btn--on {
    background: var(--control-thumb);
    color: var(--tt-rate-accent);
    font-weight: 700;
    box-shadow: 0 1px 2px rgba(0,0,0,0.08);
}

/* Distance control — inline with the segment */
.rate-dist-control {
    display: flex;
    align-items: center;
    gap: 14px;
    flex: 1;
    min-width: 260px;
    max-width: 420px;
}

.rate-dist-label {
    font-size: 14px;
    color: var(--neutral-mid);
    flex-shrink: 0;
}
/* Fixed width (not just min-width): the label text changes as you drag the slider ("1000 km" ↔
   "all players"); a constant box keeps the slider's flex space stable so it doesn't resize mid-drag. */
.rate-dist-value {
    font-size: 14px;
    font-weight: 700;
    color: var(--tt-rate-accent);
    flex-shrink: 0;
    width: 92px;
    text-align: right;
    white-space: nowrap;
}
/* Distance slider — red accent, fixed height so dragging the thumb doesn't reflow the row.
   MudSlider grows its box while pressed (thumb scale + value popover); pin the height and clip. */
.rate-slider {
    margin: 0 !important;
    padding: 0 !important;
    height: 24px !important;
    min-height: 24px !important;
    display: flex !important;
    align-items: center !important;
}

    .rate-slider .mud-slider-track-filled,
    .rate-slider .mud-slider-thumb {
        color: var(--tt-rate-accent) !important;
    }
        /* Keep the thumb from enlarging the track box on press (no layout shift). */
        .rate-slider .mud-slider-thumb::before,
        .rate-slider .mud-slider-thumb::after {
            display: none !important;
        }

    .rate-slider input[type="range"] {
        margin: 0 !important;
    }

/* Interval chips (Day…All) */
.rate-chips .mud-chip {
    border-radius: 999px;
    font-weight: 500;
    font-size: 13.5px;
    border: 1px solid var(--tt-rate-card-bd);
    background: var(--surface-card);
    color: var(--text-secondary);
}

    .rate-chips .mud-chip.mud-chip-selected {
        border-color: var(--tt-rate-accent);
        background: var(--tt-rate-accent-soft);
        color: var(--tt-rate-accent);
        font-weight: 700;
    }

/* Active-mode filter bar: period chips row · chat pill · summary (CHANGE_active_players §2.1) */
.rate-activebar {
    display: flex;
    flex-direction: column;
    gap: 9px;
}

.rate-activebar-chatrow {
    display: flex;
    align-items: center;
    gap: 9px;
    flex-wrap: wrap;
}

/* Chat filter pill — white/bordered with no filter, filled accent when a chat is picked. */
.rate-chat-pill {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 6px 11px;
    border-radius: 18px;
    border: 1px solid var(--tt-rate-card-bd);
    background: var(--surface-card);
    color: var(--text-primary);
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
    max-width: 100%;
}

    /* Telegram glyph in the "all chats" pill is blue, matching the chat-list icon. */
    .rate-chat-pill .rate-chat-pill-tg {
        color: var(--tt-rate-tg);
    }

    .rate-chat-pill--on {
        border-color: var(--tt-rate-accent);
        background: var(--tt-rate-accent);
        color: var(--text-on-status);
    }

        /* On the filled (chat-picked) pill keep the glyph white for contrast. */
        .rate-chat-pill--on .rate-chat-pill-tg {
            color: var(--text-on-status);
        }

    .rate-chat-pill .rate-chat-pill-name {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

.rate-chat-pill-reset {
    background: none;
    border: none;
    padding: 0;
    cursor: pointer;
    font-family: var(--tt-font-family);
    font-size: 12.5px;
    font-weight: 600;
    color: var(--tt-rate-accent);
}

.rate-active-summary {
    font-size: 13px;
    color: var(--neutral-mid);
}

    .rate-active-summary b {
        color: var(--text-primary);
        font-weight: 700;
    }

/* Chat-pick dialog rows (Active in chat) */
.rate-chatpick-row {
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
    padding: 11px 4px;
    background: none;
    border: none;
    border-top: 1px solid var(--tt-rate-line);
    cursor: pointer;
    font-family: var(--tt-font-family);
    text-align: left;
}

.rate-chatpick-icon {
    width: 34px;
    height: 34px;
    border-radius: 9px;
    background: var(--tint-tg-soft);
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    color: var(--tt-rate-tg);
}

.rate-chatpick-name {
    display: block;
    font-size: 14.5px;
    color: var(--text-primary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.rate-chatpick-meta {
    display: block;
    font-size: 12px;
    color: var(--text-secondary);
    margin-top: 1px;
}

/* Self-rank link ("You are in N place.") — bars icon + red underlined link */
.rate-selfrank {
    font-size: 14px;
    color: var(--neutral-mid);
    display: flex;
    align-items: center;
    gap: 6px;
}

.rate-selfrank-icon {
    display: inline-flex;
    flex-shrink: 0;
}

.rate-selfrank-link {
    color: var(--tt-rate-accent);
    font-weight: 700;
    border-bottom: 1px solid var(--tt-rate-accent);
    cursor: pointer;
}

/* ── Unified rows as cards ─────────────────────────────────────────────── */
.rate-row {
    display: flex;
    align-items: center;
    gap: 14px;
    background: var(--tt-rate-card-bg);
    border: 1px solid var(--tt-rate-card-bd);
    border-radius: 12px;
    padding: 13px 16px;
    margin-bottom: 8px;
    cursor: pointer;
    transition: border-color .12s, background .12s;
}

    .rate-row:hover {
        border-color: var(--border-card-warm);
    }

.rate-row--selected {
    border-color: var(--tt-rate-accent);
}

/* The current player's own row(s): the app-wide "me" highlight. */
.rate-row--me {
    background: var(--surface-me-row);
}

    .rate-row--me:not(.rate-row--selected) {
        border-color: var(--border-me-row);
    }

/* Rank number */
.rate-row-pos {
    min-width: 30px;
    text-align: right;
    color: var(--tt-rate-muted);
    font-size: 15px;
    font-weight: 500;
    font-variant-numeric: tabular-nums;
    flex-shrink: 0;
}

/* Middle block */
.rate-row-main {
    min-width: 0;
    flex: 1;
}

.rate-row-nameline {
    display: flex;
    align-items: center;
    gap: 6px;
    line-height: 1.25;
}

.rate-row-name {
    font-size: 15.5px;
    font-weight: 600;
    color: var(--tt-rate-ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.rate-row-handle {
    font-size: 13.5px;
    font-style: italic;
    color: var(--tt-rate-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    min-width: 0;
}

.rate-row-sub {
    font-size: 12.5px;
    color: var(--text-muted);
    margin-top: 2px;
    font-variant-numeric: tabular-nums;
}

    .rate-row-sub b {
        font-weight: 700;
        color: var(--neutral-mid);
    }
/* Geo two-hand sub-lines: "right R · games: G" / "(left) R · games: G" (prototype PlayerRow). */
.rate-row-sub-lines {
    display: flex;
    flex-direction: column;
    gap: 1px;
}

.rate-hand-prefix {
    color: var(--text-muted);
}

/* Non-playing hand markers (ranking rows): accent "*" beside the name, caption underneath. */
.rate-row-weak-star {
    color: var(--tt-rate-accent);
    font-weight: 700;
    font-size: 15px;
    line-height: 1;
    flex-shrink: 0;
}

/* Meta line under a ranked name: tokens joined by "·" (rate-rows.jsx MetaLine). Desktop shows only the
   weak-axis caption; mobile adds games and the delta (.rate-mob). */
.rate-row-meta {
    display: flex;
    align-items: center;
    gap: 5px;
    min-width: 0;
    margin-top: 2px;
    overflow: hidden;
    white-space: nowrap;
    font-size: 12px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

    .rate-row-meta .rate-delta {
        font-size: 12.5px;
    }

.rate-meta-tok + .rate-meta-tok::before {
    content: "·";
    margin-right: 5px;
    font-weight: 400;
    color: var(--border-separator);
}

/* The sub-lines own their top gap, so a meta line hidden on desktop leaves no stub; the extra class
   out-specifies PlayerAvatarView's scoped .pav-subline (that bundle loads after app.css). */
.rate-row .rate-row-main .pav-subline {
    margin-top: 0;
}

.rate-row-weak-prefix {
    color: var(--tone-dark-clay-ink-soft);
}

/* A provisional (qualifying) rating: italic name, muted rating, "qualifying N/10" in place of games. */
.rate-row-name--qual {
    font-style: italic;
}

/* A provisional (qualifying) rating and its "qualifying N/10" progress: one look in the lists, the header and the tiles.
   Put on the innermost span of the value, so a component's own colour on the wrapper can't override it. */
.rating-provisional {
    color: var(--text-muted);
    font-style: italic;
}

.qual-progress {
    color: var(--tone-dark-clay-ink-soft);
    font-style: italic;
}

.rate-qual-line {
    font-style: italic;
}

    .rate-row-sub .rate-qual-line b {
        font-weight: 500;
        color: var(--text-muted);
    }

.rate-row-mainline {
    color: var(--tt-rate-muted);
}

/* Chat games wording swaps by width: long "Registered games:" on desktop (WebChats),
   compact "Games:" on mobile (ChatRow). Both spans are rendered; CSS shows one per breakpoint. */
.rate-chat-games--short {
    display: none;
}

@media (max-width: 959px) {
    .rate-chat-games--full {
        display: none;
    }

    .rate-chat-games--short {
        display: inline;
    }
}

/* Right block — ranking layout (rating big) */
.rate-row-right {
    text-align: right;
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 2px;
}

.rate-row-rating {
    font-size: 15.5px;
    font-weight: 700;
    color: var(--tt-rate-ink);
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.2px;
    display: inline-flex;
    align-items: baseline;
    gap: 4px;
}

    .rate-row-rating .unit {
        font-size: 11.5px;
        font-weight: 600;
        color: var(--tt-rate-sub);
        letter-spacing: 0;
    }

    .rate-row-rating .rate-delta {
        margin-left: 2px;
    }

.rate-row-games {
    font-size: 12.5px;
    color: var(--tt-rate-sub);
    font-variant-numeric: tabular-nums;
}

/* Delta (bracket style) */
.rate-delta {
    font-weight: 700;
    font-size: 13.5px;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.rate-delta--up {
    color: var(--tt-rate-delta-up);
}

.rate-delta--down {
    color: var(--tt-rate-delta-down);
}

.rate-delta--flat {
    color: var(--tt-rate-delta-flat);
}

/* Right block — geo layout (distance big, warm maroon) */
.rate-row-dist {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    flex-shrink: 0;
    color: var(--tt-rate-dist);
    font-size: 15px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.rate-dist-pin {
    display: inline-flex;
    width: 15px;
    height: 15px;
    border-radius: 8px;
    background: var(--tt-rate-dist-pin);
    align-items: center;
    justify-content: center;
    color: var(--text-on-accent);
}
/* Geo player-row distance: warm brown, no pin (prototype PlayerRow). Chats keep the maroon Dist + pin. */
.rate-row-dist--geo {
    color: var(--tt-settings-accent-dark);
}

/* "you" badge */
.rate-you-badge {
    font-size: 11px;
    font-weight: 700;
    color: var(--tt-rate-accent);
    background: var(--tt-rate-accent-soft);
    padding: 1px 7px;
    border-radius: 4px;
    flex-shrink: 0;
}

/* Status markers */
.rate-inactive-icon {
    color: var(--tt-rate-inactive);
    display: inline-flex;
    flex-shrink: 0;
}

.rate-nodm-icon {
    color: var(--tt-rate-nodm);
    display: inline-flex;
    flex-shrink: 0;
}

.rate-lock-icon {
    color: var(--tt-rate-lock);
    display: inline-flex;
    flex-shrink: 0;
}

/* Chevron (card affordance) */
.rate-chevron {
    color: var(--border-separator);
    flex-shrink: 0;
    display: flex;
    margin-left: 2px;
}

/* ── Chat row ──────────────────────────────────────────────────────────── */
.rate-chat-icon {
    width: 44px;
    height: 44px;
    border-radius: 11px;
    background: var(--tint-tg-soft);
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    color: var(--tt-rate-tg);
}

/* Each row carries both placements of what moves between breakpoints (RatingRow); one is shown. */
@media (min-width: 721px) {
    .rate-row .rate-mob {
        display: none;
    }
}

/* Mobile: one flat white strip, full width past the .rate-page gutter, rows split by hairlines — the
   card frame and chevron cost the name ~46px. Placed after the base row rules so equal specificity wins. */
@media (max-width: 720px) {
    .rate-list {
        margin: 0 -16px;
        background: var(--surface-card);
        border-top: 1px solid var(--border-hairline);
    }

    .rate-row {
        gap: 10px;
        padding: 11px 14px;
        margin-bottom: 0;
        border: none;
        border-bottom: 1px solid var(--border-hairline);
        border-radius: 0;
    }

        .rate-row:hover,
        .rate-row--me:not(.rate-row--selected) {
            border-color: var(--border-hairline);
        }

    .rate-row--selected {
        background: var(--control-track);
    }

    .rate-row .rate-desk,
    .rate-chevron {
        display: none;
    }

    .rate-row-pos {
        min-width: 20px;
        font-size: 13.5px;
    }

    .rate-row .rate-row-main.pav-root {
        gap: 10px;
    }

        .rate-row .rate-row-main .pav-name-row {
            gap: 5px;
        }

    .rate-row-rating {
        flex-direction: column;
        align-items: flex-end;
        gap: 0;
        font-size: 16.5px;
        line-height: 1.05;
        letter-spacing: -0.3px;
    }

        .rate-row-rating .unit {
            margin-top: 2px;
            font-size: 9px;
            font-weight: 700;
            letter-spacing: 0.5px;
            color: var(--text-muted);
        }

    .rate-row-sub {
        min-width: 0;
        font-size: 12px;
    }

        .rate-row-sub .rate-row-handle {
            font-size: 12px;
        }

    .rate-chat-icon {
        width: 40px;
        height: 40px;
    }
}

/* Empty state */
.rate-empty {
    text-align: center;
    color: var(--tt-rate-sub);
    font-size: 15px;
    padding: 60px 30px;
}

/* Chat top header */
.rate-chattop-title {
    font-size: 24px;
    font-weight: 700;
    color: var(--tt-rate-ink);
    letter-spacing: -0.3px;
    line-height: 1.2;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.rate-chattop-sub {
    font-size: 13px;
    color: var(--text-muted);
    margin-top: 2px;
}

.rate-back-link {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: var(--tt-rate-accent);
    font-size: 14px;
    font-weight: 600;
    cursor: pointer;
    background: none;
    border: none;
    padding: 0;
}

.score-input .mud-input-root {
    text-align: center;
    font-size: 2rem !important;
    font-weight: bold;
}

/* ===== Unified page content width & left alignment =====
   Every non-login page renders inside <MudMainContent class="tt-main-content-left-aligned">.
   Pages wrap their body in <MudContainer MaxWidth="Large"> (1280px, margin:auto centered) or,
   for the profile, in .tt-settings-page (already 860px). We normalize both so all content shares
   one max-width (860px — the profile's width) and is pinned to the LEFT edge (against the drawer),
   instead of MudBlazor's default centering that leaves large side gutters on wide screens.
   The drawer still offsets the whole main-content area by its width (margin-left on .mud-main-content),
   so "left edge" here means flush against the side menu. */
.mud-main-content.tt-main-content-left-aligned .mud-container {
    max-width: var(--tt-content-max, 860px);
    margin-left: 0;
    margin-right: auto;
}

/* ===== Settings/profile redesign — page + buttons ===== */
.tt-settings-page {
    background: var(--tt-settings-bg);
    max-width: 860px;
    /* Left-aligned (was margin:0 auto) to match the unified layout. */
    margin: 0 auto 0 0;
    padding: 26px 28px 60px;
}

/* Caps label above a section (settings cards, guest-landing teasers, …).
   Shared design element — mirrors MAUI's SectionTitle style. No bottom gap:
   each use-site supplies its own spacing (card wrapper margin / MudGrid spacing). */
.tt-section-title {
    font-size: 11.5px;
    font-weight: 700;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: var(--tt-settings-ink-3);
    padding: 0 4px 0;
}

/* Shared explanatory / helper text — the single style for "here's what will happen" notes across the
   app, so their size doesn't drift page to page. Matches the New Game intro body (0.875rem / 1.5 /
   ink-2). Use it (add the class) instead of hand-rolling a per-page note size. */
.tt-hint-text {
    font-size: 0.875rem;
    line-height: 1.5;
    color: var(--tt-settings-ink-2);
}

@media (max-width: 599px) {
    .tt-settings-page {
        padding: 16px 16px 40px;
    }
}

.profile-save-bar {
    margin-top: 22px;
}

.profile-actions {
    margin-top: 22px;
    display: flex;
    flex-direction: column;
    gap: 11px;
}

.profile-save-bar + .profile-actions {
    margin-top: 11px;
}

/* Mobile: Save stays on screen. Sticky, not fixed: the main scroller already ends above the bottom nav and the
   Hybrid keyboard, and at the end of the page the button settles back above Logout. */
@media (max-width: 959px) {
    .profile-save-bar {
        position: sticky;
        bottom: 0;
        z-index: var(--z-page-bar);
        margin-top: 12px;
        padding: 10px 0;
        background: var(--tt-settings-bg);
    }

    .profile-save-bar + .profile-actions {
        margin-top: 1px;
    }
}

/* Protocol dialog on mobile — EDGE-TO-EDGE full-screen sheet (handoff bracket-protocol screenshot 03). Uses the
   720px breakpoint so it matches the create-form action bar, which goes position:fixed at ≤720px (its scoped
   CreateTournamentPage.razor.css) — the dialog must cover the bar wherever the bar is fixed, else the form's
   Create/Draft buttons still show. Desktop (>720px) keeps the centered MaxWidth.Medium dialog. MudDialog markup
   is global, so these rules live in app.css, not a scoped file. */
@media (max-width: 720px) {
    /* Covers the create-form action rail so only the protocol's OWN footer (arrows toggle + close + print) is
       visible, not the form's Create/Draft rail. */
    .mud-dialog.protocol-mud-dialog {
        /* fixed + inset:0 ignores the container's centering/padding so the sheet truly reaches every edge. */
        position: fixed;
        inset: 0;
        width: 100vw;
        max-width: 100vw;
        height: 100dvh;
        max-height: 100dvh;
        margin: 0;
        border-radius: 0;
        display: flex;
        flex-direction: column;
    }

        /* Content grows and scrolls; the action bar stays pinned at the bottom of the sheet. Descendant (not
           child) combinators throughout: MudBlazor nests .mud-dialog-content / .mud-dialog-actions below the
           surface, so `>` would not match. */
        .mud-dialog.protocol-mud-dialog .mud-dialog-content {
            flex: 1 1 auto;
            max-height: none;
            overflow-y: auto;
        }

        .mud-dialog.protocol-mud-dialog .mud-dialog-actions {
            flex: 0 0 auto;
            flex-wrap: wrap;
        }

            /* Mobile (SPEC §3.1): the loser-transitions toggle sits on its OWN full-width row ABOVE the
               [close | print] row. flex-basis:100% forces the wrap; the MudBlazor spacer (class .flex-grow-1,
               NOT .mud-spacer) is collapsed so close + print pair up on the next line. */
            .mud-dialog.protocol-mud-dialog .mud-dialog-actions .proto-arrows-btn {
                flex: 0 0 100%;
                justify-content: center;
            }

            .mud-dialog.protocol-mud-dialog .mud-dialog-actions .flex-grow-1 {
                display: none;
            }

            /* Close + Print share the row below the toggle with DIFFERENT sizes (prototype tour-protocol.jsx:
               Закрыть is `flex:initial` = content-width, «Открыть для печати» is `flex:1` = fills the rest). Equal
               `flex:1 1 0` made print wrap to two lines; sizing it this way keeps both on ONE line, print wide.
               Close is a Variant.Outlined button (.mud-button-outlined) to match the secondary-button style used
               on pages like NewGame — hence the outlined selector here, not .mud-button-text. */
            .mud-dialog.protocol-mud-dialog .mud-dialog-actions .mud-button-outlined {
                flex: 0 0 auto;
            }

            .mud-dialog.protocol-mud-dialog .mud-dialog-actions .mud-button-filled {
                flex: 1 1 auto;
                white-space: nowrap;
            }
}

.tt-settings-primary.mud-button-root {
    height: 50px;
    border-radius: 13px;
    background-color: var(--tt-settings-accent) !important;
    color: var(--text-on-accent) !important;
    font-weight: 700;
    box-shadow: 0 2px 0 rgba(0, 0, 0, 0.10);
    text-transform: none;
}

    .tt-settings-primary.mud-button-root:hover {
        background-color: var(--tt-settings-accent-dark) !important;
        color: var(--text-on-status) !important;
    }

    .tt-settings-primary.mud-button-root:disabled,
    .tt-settings-primary.mud-button-root.mud-disabled {
        background-color: var(--tt-gray-200) !important;
        color: var(--tt-settings-ink-3) !important;
    }

.tt-settings-ghost.mud-button-root {
    height: 48px;
    border-radius: 13px;
    background-color: var(--surface-card);
    border: 1px solid var(--tt-settings-card-border);
    color: var(--tt-settings-ink);
    font-weight: 600;
    text-transform: none;
}

.tt-settings-ghost-danger.mud-button-root {
    height: 48px;
    border-radius: 13px;
    background-color: var(--surface-card);
    border: 1px solid var(--tt-settings-card-border);
    color: var(--tt-settings-danger);
    font-weight: 600;
    text-transform: none;
}

/* ===== RTTF integration (profile settings) ===== */
.rttf-code-chip {
    display: inline-flex;
    align-items: center;
    gap: 9px;
    margin-top: 9px;
    padding: 5px 11px;
    border: 1px dashed var(--tt-settings-card-border);
    border-radius: 10px;
    background-color: var(--surface-card);
    cursor: pointer;
    font-family: inherit;
}

.rttf-code-value {
    font-weight: 700;
    letter-spacing: 0.08em;
    font-variant-numeric: tabular-nums;
    color: var(--tt-settings-ink);
}

.rttf-code-hint {
    font-size: 11.5px;
    font-weight: 600;
    color: var(--tt-settings-ink-3);
}

.rttf-relink-note {
    font-size: 12px;
    line-height: 1.4;
    color: var(--tt-settings-ink-3);
}

/* Profile → Telegram: what happens in Telegram after "Link", and the wait for the bot's confirmation. */
.tg-link-note {
    margin-top: 10px;
    font-size: 12px;
    line-height: 1.4;
    color: var(--tt-settings-ink-3);
}

.tg-link-wait {
    display: flex;
    align-items: center;
    gap: 8px;
}

/* Main-hand segmented choice (Right / Left) — settings-screen.jsx HandChoice. */
.hand-seg {
    display: inline-flex;
    gap: 3px;
    padding: 3px;
    border: 1px solid var(--tt-settings-card-border);
    border-radius: 12px;
    background-color: var(--tt-settings-bg);
    flex-shrink: 0;
}

.hand-seg-btn {
    padding: 9px 14px;
    border: none;
    border-radius: 9px;
    background-color: transparent;
    color: var(--tt-settings-ink-2);
    cursor: pointer;
    font-family: inherit;
    font-size: 14.5px;
    font-weight: 500;
    transition: all .14s;
}

.hand-seg-btn--on {
    background-color: var(--control-thumb);
    color: var(--tt-settings-accent);
    font-weight: 700;
    box-shadow: 0 1px 2px rgba(0, 0, 0, .12);
}

.hand-seg-btn:disabled {
    cursor: default;
    opacity: .7;
}

/* "set once" note shown in place of the choice after the hand is locked in. */
.hand-locked {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: 12.5px;
    color: var(--tt-settings-ink-3);
}

/* Star footnote under the ranked list explaining the "*" off-axis marker (rate-rows.jsx WeakFootnote). */
.top-weak-footnote {
    display: flex;
    align-items: baseline;
    gap: 6px;
    font-size: 12.5px;
    color: var(--tt-rate-muted);
    padding: 14px 4px 4px;
}

.top-weak-footnote-star {
    color: var(--tone-dark-clay-ink-soft);
    font-weight: 700;
}

/* Lefty "left hand" badge next to a name in the top list (rate-rows.jsx LeftHandTag). */
.top-lefty-badge {
    font-size: 10px;
    font-weight: 600;
    color: var(--tt-game-hand-pill-text);
    background: var(--tt-game-hand-pill-bg);
    border: 1px solid var(--tt-game-hand-pill-border);
    border-radius: 4px;
    padding: 1px 5px;
    white-space: nowrap;
    flex-shrink: 0;
    line-height: 1.5;
}

.rttf-flow-lookup {
    display: flex;
    align-items: center;
    margin-top: 10px;
}

.rttf-flow-found {
    margin-top: 12px;
    padding: 10px 12px;
    border: 1px solid var(--tt-settings-card-border);
    border-radius: 11px;
    background-color: var(--tt-settings-bg);
}

.rttf-flow-hint {
    font-size: 12px;
    line-height: 1.4;
    color: var(--tt-settings-ink-3);
    margin-top: 8px;
}

/* ===== New Game redesign =====
   Warm terracotta concept ported from the MAUI screen. Uses the settings
   accent (--tt-settings-accent #b27c62) as the page's primary tone. The
   --ng-* locals keep the palette in one place. */
.ng-card,
.ng-keepawake,
.ng-intro {
    --ng-terra: var(--tt-settings-accent);
    --ng-terra-dark: var(--tt-settings-accent-dark);
    --ng-ink: var(--tt-settings-ink);
    --ng-ink-2: var(--tt-settings-ink-2);
    --ng-ink-3: var(--tt-settings-ink-3);
    --ng-card-border: var(--tt-settings-card-border);
    --ng-gray-btn: var(--tone-tint-warm-neutral);
}

/* Intro block */
.ng-intro {
    text-align: center;
}

.ng-intro__title {
    margin: 0;
    font-size: 1.75rem;
    font-weight: 300;
    color: var(--tt-settings-ink-2);
    letter-spacing: 0.01em;
}

.ng-intro__lead {
    margin: 6px 0 0;
    font-size: 0.9375rem;
    color: var(--ng-ink-2);
}

.ng-intro__body {
    margin: 12px 0 0;
    font-size: 0.875rem;
    line-height: 1.5;
    color: var(--ng-ink-2);
    text-align: left;
}

/* Keep-screen-on row */
.ng-keepawake__hint {
    margin-left: 52px;
    display: block;
}

/* ----- Hand toggle (segmented pill) ----- */
.ng-hand-toggle {
    display: inline-flex;
    gap: 0;
    border-radius: 8px;
    padding: 3px;
    background: var(--tt-settings-pill-neutral-bg, var(--control-track));
    border: 1px solid var(--tt-settings-card-border);
}

.ng-hand-seg {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 5px 11px;
    border: none;
    border-radius: 6px;
    background: transparent;
    color: var(--tt-settings-ink-3);
    font-size: 0.8125rem;
    font-weight: 500;
    white-space: nowrap;
    cursor: pointer;
    transition: all 0.14s ease;
}

.ng-hand-seg--on {
    background: var(--tt-settings-accent);
    color: var(--text-on-accent);
    font-weight: 600;
}

.ng-hand-toggle--ink .ng-hand-seg--on {
    background: var(--tt-settings-ink-2);
    color: var(--text-on-status);
}

/* ----- Registration card ----- */
.ng-card {
    position: relative;
    border-radius: 18px;
    border: 1px solid var(--ng-card-border);
    background: var(--tt-settings-card);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
    padding: 16px;
}

.ng-card__close {
    position: absolute;
    top: 10px;
    right: 10px;
    width: 30px;
    height: 30px;
    border-radius: 9px;
    border: none;
    background: transparent;
    color: var(--tt-tertiary);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    z-index: 1;
}

    .ng-card__close:hover {
        background: var(--tint-danger-hover);
    }

.ng-you-row {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    margin-bottom: 4px;
}

.ng-you-label {
    font-size: 1rem;
    font-weight: 600;
    color: var(--ng-ink);
}

.ng-versus {
    text-align: center;
    font-size: 0.8125rem;
    color: var(--ng-ink-3);
    font-style: italic;
    margin: 2px 0 12px;
}

/* Empty-state opponent CTA */
.ng-opp-cta {
    width: 100%;
    height: 56px;
    border-radius: 14px;
    border: none;
    background: var(--ng-terra);
    color: var(--text-on-accent);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1rem;
    font-weight: 600;
    cursor: pointer;
    box-shadow: 0 2px 0 rgba(0, 0, 0, 0.10);
    transition: background 0.14s ease;
}

    .ng-opp-cta:hover {
        background: var(--ng-terra-dark);
        color: var(--text-on-status);
    }

/* Selected opponent card */
.ng-opp {
    border-radius: 14px;
    border: 1px solid var(--ng-card-border);
    background: var(--surface-card);
    padding: 12px;
}

.ng-opp__top {
    display: flex;
    align-items: center;
    gap: 12px;
}

.ng-opp__info {
    flex: 1;
    min-width: 0;
}

.ng-opp__name {
    font-size: 1rem;
    font-weight: 700;
    color: var(--ng-ink);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.ng-opp__meta {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 2px;
}

.ng-opp__rating {
    font-size: 0.9375rem;
    font-weight: 700;
    color: var(--ng-terra);
    font-variant-numeric: tabular-nums;
}

.ng-opp__unit {
    font-size: 0.65rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    color: var(--ng-ink-3);
}

.ng-opp__dot {
    color: var(--ng-ink-3);
}

.ng-opp__games {
    font-size: 0.8125rem;
    color: var(--ng-ink-3);
}

.ng-opp__hand {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin-top: 11px;
}

.ng-opp__swap {
    flex-shrink: 0;
    width: 44px;
    height: 44px;
    border-radius: 12px;
    border: none;
    background: var(--ng-terra);
    color: var(--text-on-accent);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    box-shadow: 0 2px 0 rgba(0, 0, 0, 0.10);
    transition: background 0.14s ease;
}

    .ng-opp__swap:hover {
        background: var(--ng-terra-dark);
        color: var(--text-on-status);
    }

/* ----- Score steppers ----- */
.ng-score {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    margin-top: 16px;
}

.ng-score__col {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 8px;
    align-items: center;
}

.ng-score__colon {
    align-self: center;
    margin-top: 60px;
    font-size: 1.875rem;
    font-weight: 300;
    color: var(--ng-ink-3);
}

.ng-step {
    height: 62px;
    width: 100%;
    border-radius: 14px;
    border: none;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: filter 0.12s ease, transform 0.08s ease;
}

    .ng-step:active {
        transform: scale(0.97);
    }

.ng-step--plus {
    background: var(--ng-terra);
    color: var(--text-on-accent);
    box-shadow: 0 2px 0 rgba(0, 0, 0, 0.10);
}

    .ng-step--plus:hover {
        filter: brightness(0.96);
    }

.ng-step--minus {
    background: var(--ng-gray-btn);
    color: var(--ng-ink-2);
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.04);
}

    .ng-step--plus .mud-icon-root,
    .ng-step--minus .mud-icon-root {
        font-size: 26px;
    }

.ng-score__value {
    height: 70px;
    width: 100%;
    border-radius: 14px;
    background: var(--surface-card);
    border: 1px solid var(--ng-card-border);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 2.75rem;
    font-weight: 700;
    color: var(--ng-ink);
    font-variant-numeric: tabular-nums;
    line-height: 1;
}

.ng-score__label {
    font-size: 0.78rem;
    color: var(--ng-ink-3);
    font-weight: 500;
    margin-top: 1px;
    text-align: center;
}

/* ----- Common chat row ----- */
.ng-chat {
    margin-top: 16px;
    padding-top: 14px;
    border-top: 1px solid var(--ng-card-border);
}

.ng-chat__title {
    font-size: 0.84rem;
    font-weight: 600;
    color: var(--ng-ink);
    margin-bottom: 8px;
}

.ng-chat__empty {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    border-radius: 12px;
    border: 1px solid var(--ng-card-border);
    background: var(--surface-card);
    font-size: 0.84rem;
    color: var(--ng-ink-3);
    font-style: italic;
}

.ng-chat__empty-icon {
    color: var(--tt-settings-tg-blue);
    flex-shrink: 0;
}

/* Bordered tap-row chat picker (replaces the dropdown field) */
.ng-chat__menu {
    width: 100%;
    display: block;
}

    .ng-chat__menu .mud-menu-activator {
        width: 100%;
    }

.ng-chat__row {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 10px 12px;
    border-radius: 12px;
    border: 1px solid var(--ng-card-border, var(--tt-settings-card-border));
    background: var(--surface-card);
    cursor: pointer;
    box-sizing: border-box;
}

.ng-chat__row-icon {
    color: var(--tt-settings-tg-blue);
    flex-shrink: 0;
}

.ng-chat__row-name {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 0.84rem;
    color: var(--tt-settings-ink);
}

.ng-chat__row-chevron {
    color: var(--tt-settings-ink-3);
    flex-shrink: 0;
}

/* ----- Hint pills (personal meetings, rating forecast) — both layouts ----- */
.ng-chips {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

.ng-chip {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 4px 10px;
    border-radius: 999px;
    background: var(--surface-page);
    border: 1px solid var(--border-card-warm);
    font-size: 12px;
    font-weight: 500;
    color: var(--text-secondary);
    white-space: nowrap;
}

.ng-chip--muted {
    color: var(--text-muted);
}

    .ng-chip .mud-icon-root {
        font-size: 14px;
        color: var(--text-muted);
    }

.ng-chip__sep {
    color: var(--text-muted);
}

.ng-chip__delta {
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.ng-chip__delta--up {
    color: var(--status-rating-up);
}

.ng-chip__delta--down {
    color: var(--status-rating-down);
}

/* ===== New Game page composition: one DOM, two layouts =====
   The desktop "scoreboard" layout (handoff newgame v3) is chosen by the width of the content column, not
   the viewport: the drawer takes 260px, so only a container query knows whether the table really fits. */
.ng-host {
    container: ng-page / inline-size;
    --tt-content-max: 1040px;
}

.ng-page,
.ng-finalized,
.ng-games {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

@container ng-page (width < 820px) {
    .ng-desk {
        display: none !important;
    }
}

@container ng-page (width >= 820px) {
    .ng-mob {
        display: none !important;
    }
}

/* An engine without container queries (old Android WebView) would show both layouts — keep it on the phone one. */
@supports not (container-type: inline-size) {
    .ng-desk {
        display: none !important;
    }
}

/* "Awaiting confirmation" heading — the phone keeps its centred h6 look, plus the counters. */
.ng-pending__head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 8px;
    margin-bottom: 8px;
}

.ng-pending__title {
    margin: 0;
    font-size: 1.25rem;
    font-weight: 500;
    line-height: 1.6;
    letter-spacing: 0.0075em;
    color: var(--action-primary);
}

.ng-pending__count {
    min-width: 22px;
    height: 22px;
    padding: 0 7px;
    border-radius: 11px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--action-primary);
    color: var(--text-on-accent);
    font-size: 12px;
    font-weight: 700;
    box-sizing: border-box;
}

.ng-pending__mine {
    font-size: 12px;
    font-weight: 600;
    color: var(--action-primary-pressed);
    white-space: nowrap;
}

/* ----- Desktop-only pieces (hidden on the phone by .ng-desk) ----- */

/* "Keep the screen on" as a checkbox button next to the title */
.ng-keep {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-shrink: 0;
    height: 38px;
    padding: 0 13px 0 11px;
    border-radius: 11px;
    border: 1px solid var(--border-card-warm);
    background: var(--surface-card);
    color: var(--text-heading-warm);
    font: inherit;
    cursor: pointer;
    transition: background 0.12s ease;
}

    .ng-keep:hover {
        background: var(--control-selected-tint);
    }

.ng-keep__box {
    width: 20px;
    height: 20px;
    box-sizing: border-box;
    border-radius: 6px;
    border: 2px solid var(--action-disabled-bg);
    background: var(--surface-card);
    color: var(--text-on-accent);
    display: flex;
    align-items: center;
    justify-content: center;
    transition: all 0.14s ease;
}

.ng-keep__box--on {
    border-color: var(--action-primary);
    background: var(--action-primary);
}

    .ng-keep__box .mud-icon-root {
        font-size: 16px;
    }

.ng-keep__label {
    font-size: 13.5px;
    font-weight: 500;
}

/* Always-open tip. Selectors outrank InfoPanel's scoped rules (bundle loads after app.css). */
.ng-tip .info-panel.ng-tip__static {
    padding: 13px 16px;
    gap: 12px;
}

.ng-tip .ng-tip__static .info-panel__body {
    font-size: 13.5px;
    line-height: 1.55;
    text-wrap: pretty;
}

.ng-tip__static b {
    color: var(--text-accent);
}

    .ng-tip__static b.ng-tip__lead {
        color: var(--text-heading-warm);
    }

/* Buttons sized for the mouse (the phone keeps its full-width MudButtons) */
.ng-btn {
    height: 38px;
    padding: 0 15px;
    border-radius: 10px;
    border: 1px solid transparent;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 7px;
    flex-shrink: 0;
    font: inherit;
    font-size: 13.5px;
    font-weight: 600;
    white-space: nowrap;
    cursor: pointer;
    transition: filter 0.12s ease;
}

    .ng-btn:hover:not(:disabled) {
        filter: brightness(0.955);
    }

    .ng-btn:disabled {
        opacity: 0.55;
        cursor: not-allowed;
    }

    .ng-btn .mud-icon-root {
        font-size: 17px;
    }

.ng-btn--primary {
    background: var(--action-primary);
    color: var(--text-on-accent);
    box-shadow: 0 1px 0 rgba(0, 0, 0, 0.12);
}

.ng-btn--confirm {
    background: var(--action-confirm);
    color: var(--text-on-accent);
    box-shadow: 0 1px 0 rgba(0, 0, 0, 0.12);
}

.ng-btn--ghost {
    background: var(--surface-card);
    color: var(--text-secondary);
    border-color: var(--border-card-warm);
}

.ng-btn--danger {
    background: var(--surface-card);
    color: var(--action-destructive-strong);
    border-color: color-mix(in srgb, var(--action-destructive-strong) 32%, transparent);
}

.ng-btn--lg {
    height: 44px;
    padding: 0 20px;
    font-size: 15px;
}

    .ng-btn--lg .mud-icon-root {
        font-size: 19px;
    }

.ng-btn--add {
    height: 44px;
    padding: 0 18px;
    font-size: 14.5px;
}

    .ng-btn--add .mud-icon-root {
        font-size: 18px;
    }

.ng-btn--send {
    height: 46px;
    padding: 0 26px;
    font-size: 15.5px;
    font-weight: 700;
}

/* Rating line under a name: value · TTAR · games (· hand) */
.ng-rating {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 7px;
    font-size: 13px;
    color: var(--text-muted);
}

.ng-rating__value {
    font-size: 14.5px;
    font-weight: 700;
    color: var(--action-primary);
    font-variant-numeric: tabular-nums;
}

.ng-rating__unit {
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.06em;
}

.ng-rating--small {
    gap: 6px;
    font-size: 12.5px;
}

    .ng-rating--small .ng-rating__value {
        font-size: 12.5px;
    }

    .ng-rating--small .ng-rating__unit {
        font-size: 9.5px;
        letter-spacing: 0.05em;
    }

/* Awaiting-confirmation row: player · score · status · actions */
.ng-pend-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 104px minmax(0, 182px) 246px;
    align-items: center;
    gap: 18px;
    padding: 13px 18px;
    background: var(--surface-card);
    transition: background 0.12s ease;
}

    .ng-pend-row:hover {
        background: var(--control-selected-tint);
    }

.ng-pend-row--in {
    background: var(--tint-clay-soft);
    box-shadow: inset 3px 0 0 var(--action-primary);
}

    .ng-pend-row--in:hover {
        background: var(--tint-clay-strip);
    }

.ng-pend-row--focused {
    box-shadow: inset 0 0 0 2px var(--focus-ring);
}

.ng-pend-row--in.ng-pend-row--focused {
    box-shadow: inset 3px 0 0 var(--action-primary), inset 0 0 0 2px var(--focus-ring);
}

.ng-pend-row__player {
    min-width: 0;
}

.ng-pending .ng-pend-row .ng-pend-row__name {
    font-size: 14.5px;
    font-weight: 600;
    color: var(--text-heading-warm);
}

.ng-pend-row__score {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 7px;
}

.ng-pend-row__num {
    font-size: 22px;
    font-weight: 700;
    line-height: 1;
    font-variant-numeric: tabular-nums;
    color: var(--text-heading-warm);
}

.ng-pend-row__num--win {
    color: var(--status-win);
}

.ng-pend-row__num--lose {
    color: var(--text-muted);
}

.ng-pend-row__colon {
    font-size: 16px;
    font-weight: 300;
    color: var(--text-muted);
}

.ng-pend-row__status {
    min-width: 0;
}

.ng-pend-row__state {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 12.5px;
    font-weight: 600;
    color: var(--text-muted);
}

.ng-pend-row--in .ng-pend-row__state {
    color: var(--action-primary-pressed);
}

    .ng-pend-row__state .mud-icon-root {
        font-size: 14px;
        flex-shrink: 0;
    }

.ng-pend-row__when {
    margin-top: 2px;
    font-size: 12px;
    font-style: italic;
    color: var(--text-muted);
}

/* A finished ladder's waiting game: a link back to the ladder (row and phone tile). */
.ng-pend-ladder {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    margin-top: 3px;
    font-size: 12px;
    font-weight: 600;
    color: var(--action-primary-pressed);
    text-decoration: none;
}

    .ng-pend-ladder .mud-icon-root {
        font-size: 14px;
        width: 14px;
        height: 14px;
    }

.ng-pend-ladder--tile {
    margin: 0;
    padding: 0 12px 8px;
}

.ng-pend-row__actions {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
}

/* Game card: two symmetric side panels with "versus" between them */
.ng-board {
    background: var(--surface-card-warm);
    border: 1px solid var(--border-card-warm);
    border-radius: 16px;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.03);
    padding: 18px 20px 20px;
    margin-bottom: 14px;
}

.ng-board__head {
    display: flex;
    align-items: center;
    min-height: 28px;
    margin-bottom: 13px;
}

.ng-board__title {
    font-size: 11.5px;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.ng-board__remove {
    margin-left: auto;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 5px 9px;
    border: none;
    border-radius: 8px;
    background: transparent;
    color: var(--action-destructive-strong);
    font: inherit;
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
}

    .ng-board__remove:hover {
        background: var(--tint-danger-hover);
    }

    .ng-board__remove .mud-icon-root {
        font-size: 17px;
    }

.ng-board__grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 68px minmax(0, 1fr);
    align-items: stretch;
}

.ng-board__vs {
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 13px;
    font-style: italic;
    color: var(--text-muted);
}

.ng-side {
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 13px;
    padding: 14px 16px 16px;
    border-radius: 14px;
    border: 1px solid var(--border-card-warm);
    background: var(--surface-card);
}

.ng-side--empty {
    align-items: center;
    justify-content: center;
    gap: 10px;
    min-height: 208px;
    padding: 22px;
    border-style: dashed;
    border-color: var(--action-disabled-bg);
    background: color-mix(in srgb, var(--surface-card) 50%, transparent);
    box-sizing: border-box;
}

.ng-side__empty-text {
    font-size: 13.5px;
    color: var(--text-muted);
}

.ng-side__player {
    display: flex;
    align-items: center;
    gap: 11px;
    min-width: 0;
}

.ng-side__info {
    flex: 1;
    min-width: 0;
}

.ng-side__cluster {
    flex: 1;
    min-width: 0;
}

.ng-board .ng-side .ng-side__name {
    display: block;
    font-size: 15.5px;
    font-weight: 700;
    color: var(--text-heading-warm);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.ng-side__info .ng-rating {
    margin-top: 2px;
}

.ng-side__hand {
    display: flex;
    align-items: center;
    gap: 8px;
}

.ng-side__hand-label {
    font-size: 12.5px;
    font-weight: 500;
    color: var(--text-muted);
}

/* Score: − [field] + with the caption under it */
.ng-sc {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
}

.ng-sc__row {
    display: flex;
    align-items: center;
    gap: 10px;
}

.ng-sc__step {
    width: 40px;
    height: 40px;
    flex-shrink: 0;
    border: none;
    border-radius: 11px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--action-neutral-warm);
    color: var(--text-secondary);
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.04);
    cursor: pointer;
    transition: filter 0.12s ease;
}

    .ng-sc__step:hover {
        filter: brightness(0.94);
    }

    .ng-sc__step .mud-icon-root {
        font-size: 20px;
    }

.ng-sc__step--plus {
    background: var(--action-primary);
    color: var(--text-on-accent);
    box-shadow: 0 1px 0 rgba(0, 0, 0, 0.12);
}

.ng-sc__input {
    width: 78px;
    height: 54px;
    box-sizing: border-box;
    padding: 0;
    border-radius: 12px;
    border: 1px solid var(--border-card-warm);
    background: var(--surface-page);
    outline: none;
    text-align: center;
    font: inherit;
    font-size: 32px;
    font-weight: 700;
    color: var(--text-heading-warm);
    font-variant-numeric: tabular-nums;
    transition: border-color 0.12s ease, box-shadow 0.12s ease;
}

    .ng-sc__input:focus {
        border-color: var(--action-primary);
        box-shadow: 0 0 0 3px var(--tint-clay-soft);
    }

.ng-sc__label {
    font-size: 12px;
    font-weight: 500;
    color: var(--text-muted);
}

.ng-board__chips {
    margin-top: 14px;
}

    .ng-board__chips .ng-chip {
        gap: 6px;
        padding: 5px 11px;
        font-size: 12.5px;
    }

/* Shared-chat row: caption + a select-like menu activator */
.ng-board__chat {
    display: flex;
    align-items: center;
    gap: 14px;
    margin-top: 16px;
    padding-top: 15px;
    border-top: 1px solid var(--border-card-warm);
}

.ng-board__chat-label {
    flex-shrink: 0;
    font-size: 13.5px;
    font-weight: 600;
    color: var(--text-heading-warm);
}

.ng-board__chat-menu {
    flex: 0 1 400px;
    min-width: 0;
}

    .ng-board__chat-menu .mud-menu-activator {
        width: 100%;
    }

.ng-board__chat-select {
    width: 100%;
    height: 42px;
    box-sizing: border-box;
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 0 12px;
    border-radius: 10px;
    border: 1px solid var(--border-card-warm);
    background: var(--surface-card);
    font: inherit;
    text-align: left;
    cursor: pointer;
    transition: background 0.12s ease;
}

    .ng-board__chat-select:hover {
        background: var(--control-selected-tint);
    }

.ng-board__chat-select--empty {
    flex: 0 1 400px;
    min-width: 0;
    cursor: default;
}

    .ng-board__chat-select--empty:hover {
        background: var(--surface-card);
    }

.ng-board__chat-name {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 13.5px;
    color: var(--text-heading-warm);
}

.ng-board__chat-select--empty .ng-board__chat-name {
    color: var(--text-muted);
    font-style: italic;
}

.ng-board__chat .ng-board__chat-tg {
    flex-shrink: 0;
    font-size: 20px;
    color: var(--action-telegram);
}

.ng-board__chat .ng-board__chat-chevron {
    flex-shrink: 0;
    font-size: 17px;
    color: var(--text-muted);
}

/* Bottom action row: add on the left, send (+ why it is disabled) on the right */
.ng-actions {
    display: flex;
    align-items: center;
    gap: 14px;
    margin-top: 4px;
}

.ng-actions__send {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: 14px;
    min-width: 0;
}

.ng-actions__hint {
    font-size: 13px;
    font-style: italic;
    color: var(--text-muted);
}

.ng-games__title {
    margin: 0 0 11px;
    font-size: 18px;
    font-weight: 700;
    color: var(--text-heading-warm);
}

.ng-games__count {
    font-weight: 500;
    color: var(--text-muted);
}

/* ----- Desktop re-arrangement of the shared blocks ----- */
@container ng-page (width >= 820px) {
    /* With the MudContainer's own padding this gives the design's 26 / 32 / 56 column padding. */
    .ng-page {
        gap: 26px;
        padding: 10px 8px 40px;
    }

    .ng-head {
        order: 1;
        display: flex;
        align-items: flex-start;
        gap: 24px;
    }

    .ng-tip {
        order: 2;
        margin-top: -8px;
    }

    .ng-finalized {
        order: 3;
    }

    .ng-pending {
        order: 4;
    }

    .ng-games {
        order: 5;
        gap: 0;
    }

    .ng-intro {
        flex: 1;
        min-width: 0;
        text-align: left;
    }

    .ng-intro__title {
        font-size: 30px;
        font-weight: 700;
        line-height: 1.2;
        letter-spacing: -0.5px;
        color: var(--text-heading-warm);
    }

    .ng-intro__desc {
        max-width: 660px;
        margin-top: 7px;
        font-size: 14.5px;
        line-height: 1.5;
        color: var(--text-secondary);
        text-wrap: pretty;
    }

    /* Lead + body read as one paragraph; Blazor drops the whitespace between the two <p>. */
    .ng-intro__lead,
    .ng-intro__body {
        display: inline;
        margin: 0;
        font-size: inherit;
        line-height: inherit;
        color: inherit;
    }

        .ng-intro__lead::after {
            content: " ";
        }

    .ng-pending__head {
        justify-content: flex-start;
        gap: 10px;
        margin-bottom: 11px;
    }

    .ng-pending__title {
        font-size: 18px;
        font-weight: 700;
        line-height: 1.3;
        letter-spacing: 0;
        color: var(--text-heading-warm);
    }

    .ng-pending__mine {
        font-size: 13px;
    }

    .ng-pending__list {
        overflow: hidden;
        border-radius: 14px;
        border: 1px solid var(--border-card-warm);
        background: var(--surface-card);
    }

    .ng-pending__item + .ng-pending__item {
        border-top: 1px solid var(--border-card-warm);
    }
}

/* ===== Opponent picker dialog (handoff SPEC §6) =====
   Three flex zones in one dialog: header+search (fixed) · list (scrolls) ·
   no-confirm legend (pinned footer). */
.ng-picker.mud-dialog {
    height: 90%;
    max-height: 90%;
    max-width: 580px;
    display: flex;
    flex-direction: column;
}

    /* Let the dialog paper be the flex column so the list zone can take flex:1. The header owns the
       top spacing (room for the grab handle), so keep the content's own top padding minimal. */
    .ng-picker .mud-dialog-content.ng-picker__content {
        flex: 1;
        min-height: 0;
        display: flex;
        flex-direction: column;
        overflow: hidden;
        padding-top: 6px;
        gap: 10px;
    }

/* Own header (title + close), drawn because the dialog uses NoHeader. */
.ng-picker__header {
    flex-shrink: 0;
}

.ng-picker__titlebar {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 4px 0 2px;
}

.ng-picker__title {
    flex: 1;
    min-width: 0;
    font-size: 1.125rem;
    font-weight: 700;
    color: var(--tt-settings-ink);
}

.ng-picker__close {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border: none;
    border-radius: 8px;
    background: transparent;
    color: var(--tt-settings-ink-3);
    cursor: pointer;
}

    .ng-picker__close:hover {
        background: var(--action-neutral-warm);
    }

.ng-picker__search {
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.ng-picker__list {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    margin: 0 -8px;
    padding: 0 8px;
}

/* ----- Recent opponents (collapsible chip strip) ----- */
.ng-recent {
    padding: 0 2px 6px;
}

.ng-recent__head {
    display: flex;
    align-items: center;
    gap: 5px;
    padding: 3px 2px;
    border: none;
    background: transparent;
    color: var(--tt-settings-ink-2);
    cursor: pointer;
}

.ng-recent__title {
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.07em;
    text-transform: uppercase;
}

.ng-recent__chevron {
    transition: transform 0.15s ease;
}

.ng-recent__chevron--collapsed {
    transform: rotate(-90deg);
}

.ng-recent__chips {
    display: flex;
    gap: 7px;
    flex-wrap: wrap;
    margin-top: 5px;
}

.ng-recent__chip {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 5px 11px 5px 5px;
    border-radius: 999px;
    background: var(--surface-card);
    border: 1px solid var(--tt-settings-card-border);
    cursor: pointer;
    text-align: left;
}

    .ng-recent__chip:hover {
        background: var(--action-neutral-warm);
    }

.ng-recent__chip--current {
    border-color: var(--tint-clay-border);
}

.ng-recent__chip-info {
    display: flex;
    flex-direction: column;
    line-height: 1.2;
}

.ng-recent__chip-name {
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--tt-settings-ink);
    white-space: nowrap;
}

.ng-recent__chip-meta {
    font-size: 0.6875rem;
    color: var(--tt-settings-ink-3);
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

/* ----- Player row ----- */
.ng-prow {
    display: flex;
    align-items: center;
    gap: 11px;
    width: 100%;
    padding: 10px 12px;
    border-radius: 12px;
    border: 1px solid transparent;
    background: transparent;
    margin-bottom: 3px;
    text-align: left;
    cursor: pointer;
    transition: background 0.1s ease;
}

    .ng-prow:hover {
        background: var(--action-neutral-warm);
    }

.ng-prow--selected {
    background: var(--surface-card);
    border-color: var(--tint-clay-border);
}

    .ng-prow--selected:hover {
        background: var(--surface-card);
    }

.ng-prow__cluster {
    flex: 1;
    min-width: 0;
}

.ng-prow__rating {
    font-size: 0.8125rem;
    font-weight: 700;
    color: var(--tt-settings-accent);
    font-variant-numeric: tabular-nums;
}

.ng-prow__unit {
    font-size: 0.59rem;
    font-weight: 700;
    letter-spacing: 0.05em;
    color: var(--tt-settings-ink-3);
}

.ng-prow__games,
.ng-prow__hand {
    font-size: 0.78rem;
    color: var(--tt-settings-ink-3);
}

.ng-prow__km {
    flex-shrink: 0;
    min-width: 58px;
    text-align: right;
    white-space: nowrap;
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--tt-settings-accent-dark);
    font-variant-numeric: tabular-nums;
}

/* Fixed-width check slot so rows don't shift when the selected mark appears. */
.ng-prow__check {
    width: 20px;
    flex-shrink: 0;
    display: flex;
    justify-content: flex-end;
    color: var(--tt-settings-accent);
}

.ng-prow-empty {
    text-align: center;
    font-size: 0.875rem;
    color: var(--tt-settings-ink-3);
    padding: 22px 8px;
}

/* ----- "Load more" loader row ----- */
.ng-more {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 9px;
    padding: 14px 8px 18px;
    color: var(--tt-settings-ink-2);
}

.ng-more__ring {
    width: 15px;
    height: 15px;
    border-radius: 50%;
    border: 2px solid var(--tt-settings-card-border);
    border-top-color: var(--tt-settings-accent);
    animation: ngSpin 0.7s linear infinite;
    display: block;
}

.ng-more__text {
    font-size: 0.78rem;
}

@keyframes ngSpin {
    to {
        transform: rotate(360deg);
    }
}

/* ----- "Cannot confirm" amber marker + pinned legend ----- */
.ng-noconfirm-icon {
    display: flex;
    flex-shrink: 0;
    color: var(--status-pending);
}

.ng-picker__actions {
    flex-shrink: 0;
    border-top: 1px solid var(--tt-settings-card-border);
}

/* No warning rows loaded → no legend content: collapse the footer entirely. */
.ng-picker__actions--empty {
    display: none;
}

.ng-noconfirm-legend {
    display: flex;
    align-items: center;
    gap: 7px;
    width: 100%;
    padding: 0 4px;
}

.ng-noconfirm-legend__text {
    font-size: 0.75rem;
    line-height: 1.35;
    color: var(--tt-settings-ink-2);
    text-wrap: pretty;
}

/* Narrow (mobile) layout — the picker becomes a bottom-sheet (SPEC §6 mobile shell / §9).
   Target the MudBlazor dialog container that hosts OUR paper (:has), so only this dialog
   drops to the bottom; other dialogs keep their centered position. */
@media (max-width: 959px) {
    .mud-dialog-container:has(> .ng-picker) {
        align-items: flex-end;
        justify-content: stretch;
    }

    .ng-picker.mud-dialog {
        /* Sheet is 94% of the area ABOVE the bottom-nav band (SPEC: sheet height 94%, gap on top).
           The bottom-nav band (z-index 1400) paints above the dialog overlay (z 1300), so the
           margin lifts the whole sheet by the nav height (64px) to keep the pinned legend footer
           visible above the nav rather than behind it. Height is 94% of the remaining (100%-64px)
           so the top gap that shows the backdrop is preserved. */
        height: calc((100% - 64px) * 0.94);
        max-height: calc((100% - 64px) * 0.94);
        width: 100%;
        max-width: 100%;
        margin: 0 0 64px;
        border-radius: 20px 20px 0 0;
        animation: ngSheetUp 0.26s cubic-bezier(0.2, 0.8, 0.2, 1);
        /* The positioning box of the grab handle (Sheet chrome below). */
        position: relative;
    }

    .ng-picker__header {
        padding-top: 14px;
    }
}

/* <MudDialog Class="mobile-sheet">: a centred dialog on the web, a bottom sheet on narrow screens, resting on
   --sheet-bottom (the bottom nav paints over dialogs). */
@media (max-width: 959px) {
    .mud-dialog-container:has(> .mobile-sheet) {
        align-items: flex-end;
        justify-content: stretch;
    }

    .mobile-sheet.mud-dialog {
        /* The header close button is anchored only by the transform MudBlazor's own open animation leaves behind;
           the sheet animation doesn't linger, so anchor it explicitly or it jumps to the viewport corner. */
        position: relative;
        width: 100%;
        max-width: 100%;
        max-height: calc(100% - var(--sheet-bottom) - 24px);
        margin: 0 0 var(--sheet-bottom);
        border-radius: 20px 20px 0 0;
        animation: ngSheetUp 0.26s cubic-bezier(0.2, 0.8, 0.2, 1);
    }

    /* Searchable lists: a fixed height, so filtering doesn't shrink the sheet and drag its search field down. */
    .mobile-sheet--tall.mud-dialog {
        height: calc(100% - var(--tt-appbar-height) - var(--sheet-bottom));
    }

    /* Room for the grab handle above the title; MudBlazor's header × follows the title down. */
    .mobile-sheet .mud-dialog-title {
        padding-top: 22px;
    }

        .mobile-sheet .mud-dialog-title .mud-button-close {
            top: 14px;
        }

    /* No title row (an untitled action sheet): the content makes that room itself. */
    .mobile-sheet.mud-dialog > .mud-dialog-content:first-child {
        padding-top: 22px;
    }
}

/* ── Sheet chrome (SheetGrip): the grab handle and the × every bottom sheet shares. The panel (data-sheet-panel, or a
   MudDialog paper) is their positioning box, so both stay put while the content scrolls under them. ── */
.tt-sheet-grip {
    display: contents;
}

[data-sheet-panel] {
    position: relative;
}

.tt-sheet-grabber,
.mobile-sheet.mud-dialog::before,
.ng-picker.mud-dialog::before {
    position: absolute;
    top: 8px;
    left: 50%;
    z-index: 3;
    width: 40px;
    height: 4px;
    margin-left: -20px;
    border-radius: 2px;
    background: var(--line-divider);
    pointer-events: none;
}

/* A MudDialog's content is its own scroller, so its handle is drawn on the paper instead (no box until content is set). */
@media (max-width: 959px) {
    .mobile-sheet.mud-dialog::before,
    .ng-picker.mud-dialog::before {
        content: '';
    }
}

@media (min-width: 960px) {
    .tt-sheet-grabber {
        display: none;
    }
}

.tt-sheet-close {
    position: absolute;
    top: 12px;
    right: 12px;
    z-index: 3;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    padding: 0;
    border: none;
    border-radius: 50%;
    /* Solid backing: the content scrolls under the button. */
    background: var(--surface-card);
    color: var(--text-muted);
    cursor: pointer;
}

    .tt-sheet-close:hover {
        background: var(--action-neutral-warm);
    }

/* While a sheet is open a pull on it is its own swipe, never the browser's pull-to-reload of the page behind it. */
html:has([data-tt-sheet]),
html:has([data-tt-sheet]) body {
    overscroll-behavior-y: none;
}

@keyframes ngSheetUp {
    from {
        transform: translateY(100%);
    }

    to {
        transform: translateY(0);
    }
}

/* ============================ Login redesign ============================
   High-fidelity element styles for the 5 login screens (prototype aa-auth.jsx).
   Structural chrome (topbar / hero band / centered column) lives in
   Components/LoginScreen.razor.css; these are the inner elements pages compose. */

.login-wordmark {
    font-weight: 800;
    letter-spacing: 1px;
    color: var(--tt-tertiary-soft);
    text-align: center;
    line-height: 1.1;
}

    .login-wordmark.lg {
        font-size: 42px;
    }

    .login-wordmark.sm {
        font-size: 32px;
    }

.login-tagline {
    font-size: 15px;
    font-weight: 600;
    color: var(--tt-settings-ink);
    text-align: center;
    margin-top: 8px;
    line-height: 1.35;
}

.login-title {
    font-size: 22px;
    font-weight: 700;
    color: var(--tt-game-text-name);
    text-align: center;
}

.login-prompt {
    font-size: 14px;
    line-height: 1.5;
    color: var(--tt-game-text-secondary);
    text-align: center;
    max-width: 330px;
    margin: 7px auto 0;
}

/* Field: white, radius 11, 1.5px border, 50 high, icon left, optional eye right. */
.login-field {
    position: relative;
    display: flex;
    align-items: center;
    height: 50px;
    border-radius: 11px;
    border: 1.5px solid var(--tt-game-card-separator);
    background: var(--surface-card);
    padding: 0 14px;
    box-sizing: border-box;
}

    .login-field:focus-within {
        border-color: var(--tt-settings-accent);
        box-shadow: 0 0 0 3px var(--tint-clay-soft);
    }

    .login-field .login-field-icon {
        color: var(--tt-gray-300);
        display: flex;
        flex-shrink: 0;
    }

    .login-field input {
        flex: 1;
        border: none;
        outline: none;
        background: transparent;
        font-family: var(--tt-font-family);
        font-size: 15px;
        color: var(--tt-game-text-name);
        margin-left: 10px;
        min-width: 0;
    }

        .login-field input::placeholder {
            color: var(--tt-gray-300);
        }

    .login-field .login-eye {
        background: none;
        border: none;
        cursor: pointer;
        color: var(--tt-game-text-muted);
        padding: 6px;
        display: flex;
        flex-shrink: 0;
    }

.login-field-label {
    display: block;
    font-size: 12.5px;
    font-weight: 600;
    color: var(--tt-game-text-secondary);
    margin: 0 0 6px 2px;
}

/* Buttons. */
.login-btn {
    width: 100%;
    min-height: 50px;
    border-radius: 11px;
    font-family: var(--tt-font-family);
    font-size: 15.5px;
    font-weight: 700;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    border: 1.5px solid transparent;
    padding: 0 16px;
    /* Some login buttons render as <a> (navigation before WASM hydration); the -primary/-secondary
       variants set an explicit color, so only the default link underline needs removing. */
    text-decoration: none;
}

    .login-btn:disabled {
        opacity: 0.5;
        cursor: default;
    }

.login-btn-primary {
    background: var(--tt-settings-accent);
    color: var(--text-on-accent);
    border-color: var(--tt-settings-accent);
}

.login-btn-tg {
    background: var(--tt-settings-tg-blue);
    color: var(--text-on-accent);
    border-color: var(--tt-settings-tg-blue);
}

.login-btn-secondary {
    background: var(--surface-card);
    color: var(--tt-settings-ink);
    border-color: var(--tt-settings-card-border);
    font-weight: 600;
}
/* Auth-method row: icon in a white circle + centered label (brand colors stay readable on terracotta). */
.login-btn-method {
    min-height: 52px;
    position: relative;
    padding: 0 14px;
}

.login-method-icon {
    width: 28px;
    height: 28px;
    border-radius: 14px;
    background: var(--surface-card);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    position: absolute;
    left: 14px;
}

    .login-method-icon.tg {
        background: var(--tt-settings-tg-blue);
    }

    .login-method-icon img {
        width: 18px;
        height: 18px;
    }

.login-method-label {
    flex: 1;
    text-align: center;
}

/* Inline link (clay-dark, weight 700). */
.login-link {
    background: none;
    border: none;
    cursor: pointer;
    color: var(--tt-settings-accent-dark);
    font-family: var(--tt-font-family);
    font-weight: 700;
    font-size: 13.5px;
    padding: 0;
    text-decoration: none;
}

    .login-link:hover {
        text-decoration: underline;
    }

/* Unconfirmed-email / generic alert plate. */
.login-alert {
    background: var(--tt-alert-error-bg);
    border: 1px solid var(--tt-alert-error-border);
    border-radius: 10px;
    padding: 11px 13px;
}

.login-alert-text {
    font-size: 13px;
    color: var(--tt-alert-error-text);
    line-height: 1.45;
}

/* Centered icon state block (check-email / sent). */
.login-state-icon {
    width: 72px;
    height: 72px;
    border-radius: 36px;
    background: var(--tint-clay-soft);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--tt-settings-accent-dark);
    margin: 0 auto 16px;
}

    .login-state-icon.tg {
        background: var(--tint-tg-soft);
        color: var(--tt-settings-tg-blue);
    }

/* Footer divider + privacy link. */
.login-divider {
    height: 1px;
    background: var(--tt-game-card-separator);
    margin: 22px 0 14px;
}

.login-privacy {
    display: block;
    text-align: center;
    font-size: 12.5px;
    color: var(--tt-game-text-muted);
    text-decoration: underline;
}

/* Login pages render inside MainLayout: drop the default content padding/centering so the
   hero band can span the full content width and the column centers itself. */
.mud-main-content.tt-main-content-left-aligned:has(.login-screen) {
    padding-left: 0;
    padding-right: 0;
}

/* Monochrome SVG icons rendered as CSS masks so they inherit currentColor (an <img>
   cannot). Used for Material Symbols glyphs missing from MudBlazor's icon set, so
   active/hover colours match the neighbouring MudIcons. Size matches MudIcon medium (24px). */
.tt-mask-icon {
    display: inline-block;
    width: 24px;
    height: 24px;
    background-color: currentColor;
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-position: center;
    mask-position: center;
    -webkit-mask-size: contain;
    mask-size: contain;
}

.tt-mask-icon--new-game {
    -webkit-mask-image: url('../images/new_game.svg');
    mask-image: url('../images/new_game.svg');
}

/* ============================================================================
   Home dashboard (authorized) — progress widgets (handoff "Главная / Dashboard" §6).
   One component set for both heads; the web grid is two columns and collapses to
   one on the phone. minmax(0,1fr) is REQUIRED — without it the achievements row and
   the heatmap force a horizontal overflow.
   ============================================================================ */
.dash-page {
    background: var(--surface-page);
    min-height: 100%;
}

.dash-page__inner {
    /* Left-aligned at the shared 860px, matching the other pages' unified width
       (.mud-container / .tt-settings-page) instead of centering with margin:0 auto. */
    max-width: 860px;
    margin: 0 auto 0 0;
    padding: 26px 24px 40px;
}

.dash-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 14px;
}

/* Header */
.dash-header {
    margin-bottom: 4px;
}

.dash-header__line {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}

.dash-header__greeting {
    font-size: 24px;
    font-weight: 800;
    color: var(--text-primary);
}

.dash-header__subtitle {
    font-size: 13.5px;
    color: var(--text-muted);
    margin: 4px 0 16px;
}

.dash-streak-badge {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    background: var(--status-win-tint);
    color: var(--status-win);
    font-size: 12.5px;
    font-weight: 700;
    padding: 3px 9px;
    border-radius: 999px;
}

.dash-streak-badge__icon {
    font-size: 14px !important;
    width: 14px !important;
    height: 14px !important;
    color: var(--status-win) !important;
}

/* Base card (DCard) */
.dash-card {
    background: var(--surface-card);
    border: 1px solid var(--border-card);
    border-radius: 15px;
    padding: 15px;
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.dash-card--wide {
    grid-column: 1 / -1;
}

.dash-card__head {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 8px;
    margin-bottom: 12px;
}

.dash-card__title {
    font-size: 14.5px;
    font-weight: 700;
    color: var(--text-primary);
}

.dash-skel {
    border-radius: 15px !important;
}

/* Shared bits */
.dash-kicker {
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 0.6px;
    text-transform: uppercase;
    color: var(--text-muted);
}

.dash-kicker--clay {
    color: var(--action-primary-pressed);
}

.dash-link {
    background: none;
    border: none;
    color: var(--action-primary-pressed);
    font-size: 13px;
    font-weight: 700;
    cursor: pointer;
    padding: 0;
    font-family: inherit;
    display: inline-flex;
    align-items: center;
    gap: 5px;
}

.dash-chip {
    font-weight: 700;
    font-size: 13px;
    padding: 4px 10px;
    border-radius: 6px;
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-variant-numeric: tabular-nums;
}

.dash-chip__icon {
    font-size: 14px !important;
    width: 14px !important;
    height: 14px !important;
    color: inherit !important;
}

/* Segment control (Week/Month/Year) */
.dash-seg {
    display: flex;
    background: var(--control-track);
    border-radius: 9px;
    padding: 3px;
    gap: 2px;
}

.dash-seg__btn {
    border: none;
    background: transparent;
    color: var(--text-meta-warm);
    font-weight: 700;
    font-size: 12.5px;
    padding: 6px 12px;
    border-radius: 7px;
    cursor: pointer;
    font-family: inherit;
}

.dash-seg__btn--on {
    background: var(--control-thumb);
    color: var(--action-primary-pressed);
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12);
}

/* Widget 1 — Rating */
.dash-rating__top {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 10px;
}

.dash-rating__figure {
    display: flex;
    align-items: flex-end;
    gap: 12px;
    margin-top: 8px;
    flex-wrap: wrap;
}

.dash-rating__value {
    font-size: 46px;
    font-weight: 800;
    color: var(--text-primary);
    line-height: 1;
    font-variant-numeric: tabular-nums;
}

.dash-rating__unit {
    font-size: 16px;
    font-weight: 600;
    color: var(--text-muted);
    align-self: flex-end;
    margin-bottom: 2px;
}

.dash-rating__rankpill {
    background: var(--tint-clay-soft);
    color: var(--action-primary-pressed);
    font-weight: 700;
    font-size: 13px;
    padding: 4px 11px;
    border-radius: 999px;
    margin-bottom: 7px;
}

.dash-rating__spacer {
    flex: 1;
}

.dash-rating__record {
    font-size: 12.5px;
    color: var(--text-muted);
    margin-bottom: 5px;
    display: flex;
    align-items: center;
    gap: 5px;
    font-variant-numeric: tabular-nums;
}

.dash-rating__record-icon {
    font-size: 14px !important;
    width: 14px !important;
    height: 14px !important;
    color: var(--action-primary-pressed) !important;
}

.dash-rating__deltarow {
    display: flex;
    align-items: center;
    gap: 9px;
    margin-top: 12px;
    flex-wrap: wrap;
}

.dash-rating__gamesnote {
    font-size: 12.5px;
    color: var(--text-muted);
}

/* Mini rating chart, matched to the player-card look: a bordered white card (prototype ChartCard)
   around the fixed-height sparkline. */
.dash-rating__spark {
    margin-top: 12px;
    height: 92px;
    background: var(--surface-card);
    border: 1px solid var(--border-card);
    border-radius: 10px;
    padding: 8px 12px;
    box-sizing: content-box;
}

/* Widget 2 — Quick actions */
.dash-quick {
    grid-column: 1 / -1;
    display: flex;
    flex-direction: row;
    gap: 10px;
}

.dash-quick__btn {
    flex: 1;
}

/* Widget 3 — Stats donut */
.dash-stats__top {
    display: flex;
    gap: 16px;
    align-items: center;
}

.dash-donut {
    width: 94px;
    height: 94px;
    border-radius: 50%;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
}

.dash-donut__core {
    width: 64px;
    height: 64px;
    border-radius: 50%;
    background: var(--surface-card);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
}

.dash-donut__pct {
    font-size: 22px;
    font-weight: 800;
    color: var(--text-primary);
    line-height: 1;
    font-variant-numeric: tabular-nums;
}

.dash-donut__label {
    font-size: 10px;
    color: var(--text-muted);
    font-weight: 600;
}

.dash-stats__legend {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-width: 0;
}

.dash-stats__row {
    display: flex;
    align-items: center;
    gap: 8px;
}

.dash-stats__marker {
    width: 10px;
    height: 10px;
    border-radius: 3px;
    flex-shrink: 0;
}

.dash-stats__name {
    font-size: 13px;
    color: var(--text-secondary);
    flex: 1;
}

.dash-stats__val {
    font-size: 14px;
    font-weight: 700;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
}

.dash-stats__tiles {
    display: flex;
    gap: 10px;
    margin-top: 14px;
}

.dash-tile {
    flex: 1;
    border-radius: 10px;
    padding: 9px 11px;
    min-width: 0;
}

.dash-tile--win {
    background: var(--status-win-tint);
}

.dash-tile--sunk {
    background: var(--control-track);
}

.dash-tile__label {
    font-size: 11.5px;
    font-weight: 700;
    display: flex;
    align-items: center;
    gap: 4px;
    color: var(--text-muted);
}

.dash-tile--win .dash-tile__label {
    color: var(--status-win);
}

.dash-tile__icon {
    font-size: 14px !important;
    width: 14px !important;
    height: 14px !important;
    color: var(--status-win) !important;
}

.dash-tile__value {
    font-size: 16.5px;
    font-weight: 800;
    color: var(--text-primary);
    margin-top: 2px;
}

/* Widget 4 — Rank progress */
.dash-rank__labels {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    margin-bottom: 8px;
}

.dash-rank__current {
    font-size: 14px;
    font-weight: 700;
    color: var(--action-primary-pressed);
}

.dash-rank__next {
    font-size: 14px;
    font-weight: 700;
    color: var(--text-disabled);
}

.dash-rank__track {
    height: 12px;
    border-radius: 6px;
    background: var(--control-track);
    overflow: hidden;
}

.dash-rank__fill {
    height: 100%;
    background: linear-gradient(90deg, var(--action-primary), var(--action-primary-pressed));
    border-radius: 6px;
}

.dash-rank__figures {
    display: flex;
    justify-content: space-between;
    margin-top: 8px;
}

.dash-rank__progress {
    font-size: 12.5px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

.dash-rank__remaining {
    font-size: 13px;
    font-weight: 700;
    color: var(--text-primary);
}

.dash-rank__pace {
    font-size: 12px;
    color: var(--text-muted);
    margin-top: 10px;
    line-height: 1.45;
}

/* Widget 6 — Quips */
.dash-quip {
    background: var(--control-selected-tint);
    border-color: var(--tint-clay-border);
}

.dash-quip__head {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 10px;
    gap: 8px;
}

.dash-quip__more-icon {
    font-size: 14px !important;
    width: 14px !important;
    height: 14px !important;
    color: var(--action-primary-pressed) !important;
}

.dash-quip__body {
    display: flex;
    gap: 13px;
    align-items: flex-start;
    flex: 1;
}

.dash-quip__emoji {
    font-size: 30px;
    line-height: 1;
}

.dash-quip__text {
    font-size: 15.5px;
    font-weight: 600;
    color: var(--text-primary);
    line-height: 1.45;
    flex: 1;
}

/* Widget 7 — Head-to-head. Only the avatar+name cluster (.pav-link) navigates, so the row itself
   carries no pointer cursor — the dead score/meetings zone must not look clickable. */
.dash-h2h__row {
    display: flex;
    align-items: center;
    gap: 11px;
    width: 100%;
    padding: 10px 0;
    text-align: left;
}

.dash-h2h__row:not(.dash-h2h__row--top) {
    border-top: 1px solid var(--border-hairline);
}

.dash-h2h__name {
    font-size: 14.5px;
    font-weight: 700;
    color: var(--text-primary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.dash-h2h__tag {
    font-size: 12px;
    font-weight: 700;
    margin-top: 1px;
}

.dash-h2h__right {
    text-align: right;
    flex-shrink: 0;
}

.dash-h2h__score {
    font-size: 17px;
    font-weight: 800;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
}

.dash-h2h__meetings {
    font-size: 11px;
    color: var(--text-muted);
}

/* Widget 8 — Recent games */
.dash-recent__row {
    display: flex;
    align-items: center;
    gap: 11px;
    width: 100%;
    padding: 9px 0;
    text-align: left;
}

.dash-recent__row:not(.dash-recent__row--top) {
    border-top: 1px solid var(--border-hairline);
}

/* PlayerAvatarView cluster fills the row between the avatar and the score block. */
.dash-recent__player,
.dash-h2h__player {
    flex: 1;
    min-width: 0;
}

.dash-recent__name {
    font-size: 14px;
    font-weight: 600;
    color: var(--text-primary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.dash-recent__date {
    font-size: 12px;
    color: var(--text-muted);
}

.dash-recent__right {
    text-align: right;
    flex-shrink: 0;
}

.dash-recent__score {
    font-weight: 700;
    font-size: 15px;
    font-variant-numeric: tabular-nums;
}

.dash-recent__delta {
    font-size: 12px;
    font-weight: 700;
}

/* Guest / external opponent in dashboard rows (recent / H2H): no TTAR profile → not clickable, marked. */
.dash-recent__row--unlinked,
.dash-h2h__row--unlinked {
    cursor: default;
}

.dash-guest-badge {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    flex-shrink: 0;
    font-size: 9.5px;
    font-weight: 700;
    line-height: 1.5;
    color: var(--tt-guest-pill-ink);
    background: var(--tt-guest-pill-bg);
    border: 1px dashed var(--tt-guest-border);
    border-radius: 4px;
    padding: 1px 6px 1px 4px;
    white-space: nowrap;
}

.dash-guest-icon {
    width: 11px;
    height: 11px;
    flex-shrink: 0;
}

/* External (RTTF) marker pill + globe avatar badge (slate-blue --tt-external-* tokens). */
.dash-external-pill {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    flex-shrink: 0;
    font-size: 9.5px;
    font-weight: 700;
    line-height: 1.5;
    color: var(--tt-external-ink);
    background: var(--tt-external-bg);
    border: 1px solid var(--tt-external-border);
    border-radius: 4px;
    padding: 1px 6px 1px 4px;
    white-space: nowrap;
}

.dash-external-icon {
    width: 11px;
    height: 11px;
    flex-shrink: 0;
}

/* Avatar wrapper so the globe badge can pin to the avatar's top-left corner. */
.dash-avatar-wrap {
    position: relative;
    display: inline-flex;
    flex-shrink: 0;
}

.dash-external-badge {
    position: absolute;
    left: -2px;
    top: -2px;
    width: 15px;
    height: 15px;
    border-radius: 50%;
    background: var(--tt-external-badge-bg);
    border: 1.5px solid var(--surface-card);
    display: flex;
    align-items: center;
    justify-content: center;
}

    .dash-external-badge svg {
        width: 9px;
        height: 9px;
    }

/* Widget 9 — Nearest tournament */
.dash-tour {
    display: flex;
    gap: 13px;
    width: 100%;
    cursor: pointer;
    text-align: left;
}

.dash-tour__body {
    flex: 1;
    min-width: 0;
}

.dash-tour__name {
    font-size: 15px;
    font-weight: 700;
    color: var(--text-primary);
}

.dash-tour__meta {
    font-size: 12.5px;
    color: var(--text-muted);
    margin-top: 3px;
}

.dash-tour__badge {
    margin-top: 8px;
}

/* Widget 11 — Clubs nearby */
.dash-venues {
    display: grid;
    gap: 8px;
}

.dash-venues--below {
    margin-top: 12px;
    padding-top: 12px;
    border-top: 1px solid var(--border-hairline);
}

.dash-venues__home {
    display: flex;
    align-items: center;
    gap: 12px;
    text-decoration: none;
}

.dash-venues__home-icon {
    width: 40px;
    height: 40px;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 10px;
    background: var(--tint-clay-soft);
    border: 1px solid var(--tint-clay-border);
    color: var(--action-primary-pressed);
}

.dash-venues__home-body {
    flex: 1;
    min-width: 0;
}

.dash-venues__kicker {
    display: block;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.5px;
    text-transform: uppercase;
    color: var(--text-muted);
}

.dash-venues__home-name {
    display: block;
    font-size: 15px;
    font-weight: 700;
    color: var(--text-primary);
    margin-top: 2px;
}

.dash-venues__item {
    display: block;
    min-width: 0;
    background: var(--surface-card-warm);
    border: 1px solid var(--border-card);
    border-radius: 10px;
    padding: 9px 10px;
    text-decoration: none;
}

.dash-venues__name {
    display: block;
    font-size: 13px;
    font-weight: 700;
    color: var(--text-primary);
    line-height: 1.25;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.dash-venues__meta {
    display: block;
    font-size: 11.5px;
    color: var(--text-muted);
    margin-top: 3px;
}

/* Widget 10 — Activity heatmap */
.dash-heatmap {
    display: grid;
    grid-template-columns: repeat(52, 1fr);
    grid-template-rows: repeat(7, 1fr);
    grid-auto-flow: column;
    gap: 2px;
    aspect-ratio: 52 / 7;
}

.dash-heatmap__cell {
    border-radius: 2px;
}

.dash-heatmap__legend {
    display: flex;
    align-items: center;
    gap: 5px;
    justify-content: flex-end;
    margin-top: 10px;
    font-size: 11.5px;
    color: var(--text-muted);
}

.dash-heatmap__cell--tapped {
    outline: 1.5px solid var(--text-muted);
    outline-offset: 1px;
}

.dash-heatmap__tip {
    margin-right: auto;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

.dash-heatmap__key {
    width: 11px;
    height: 11px;
    border-radius: 2px;
    display: inline-block;
}

.dash-heatmap__summary {
    font-size: 12.5px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

/* Newbie empty state + error */
.dash-newbie {
    align-items: flex-start;
    text-align: left;
}

.dash-newbie__title {
    font-size: 16px;
    font-weight: 700;
    color: var(--text-primary);
}

.dash-newbie__text {
    font-size: 13.5px;
    color: var(--text-secondary);
    margin-top: 6px;
    line-height: 1.5;
}

.dash-newbie__hint {
    font-size: 12.5px;
    color: var(--text-muted);
    margin-top: 10px;
}

.dash-error {
    background: var(--surface-card);
    border: 1px solid var(--border-card);
    border-radius: 15px;
    padding: 24px;
    text-align: center;
    color: var(--text-secondary);
}

/* Responsive: one column on the phone, tighter padding, stacked quick actions (~720px break) */
@media (max-width: 720px) {
    .dash-page__inner {
        padding: 16px 14px 30px;
    }

    .dash-grid {
        grid-template-columns: minmax(0, 1fr);
    }

    .dash-header__greeting {
        font-size: 20px;
    }

    .dash-quick {
        flex-direction: column;
    }
}

/* GeoPrompt panel: restyles InfoPanel clay/amber. GLOBAL not scoped — the panel carries InfoPanel's
   scope, so ::deep can't reach it; the extra class qualifiers outrank InfoPanel's own --ip-* rules. */
.geo-prompt.geo-prompt--prompt.info-panel {
    --ip-bg: var(--tint-clay-soft);
    --ip-border: var(--tint-clay-border);
    --ip-icon: var(--tone-brand-clay);
    --geo-disc: color-mix(in srgb, var(--tone-brand-clay) 13%, transparent);
    --geo-title: var(--tone-dark-clay-ink);
    --geo-text: var(--text-secondary);
}

.geo-prompt.geo-prompt--denied.info-panel {
    --ip-bg: var(--tone-tint-amber);
    --ip-border: var(--tone-border-warn);
    --ip-icon: var(--tone-warn-amber);
    --geo-disc: color-mix(in srgb, var(--tone-warn-amber) 14%, transparent);
    --geo-title: var(--tone-warn-ink);
    --geo-text: var(--tone-warn-ink-soft);
}

/* Disc behind the pin icon: a tinted circle wash around InfoPanel's icon. */
.geo-prompt.info-panel .info-panel__icon {
    box-sizing: content-box;
    width: 20px;
    height: 20px;
    padding: 5px;
    border-radius: 50%;
    background: var(--geo-disc);
}

/* Header title takes the tone's ink (clay/amber), not the default settings ink. */
.geo-prompt.info-panel .info-panel__summary {
    color: var(--geo-title);
    font-weight: 700;
    font-size: 0.875rem;
}

.geo-prompt .geo-prompt__text {
    font-size: 0.8125rem;
    line-height: 1.5;
    color: var(--geo-text);
    text-wrap: pretty;
}

/* CTA — clay button. Mobile/compact: full-width below the text. */
.geo-prompt .geo-prompt__cta {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 7px;
    width: 100%;
    margin-top: 10px;
    padding: 9px 14px;
    border: none;
    border-radius: 9px;
    background: var(--tone-brand-clay);
    color: var(--text-on-accent);
    font-size: 0.875rem;
    font-weight: 700;
    cursor: pointer;
}

.geo-prompt .geo-prompt__cta:hover {
    background: var(--tone-brand-clay-dark);
}

.geo-prompt .geo-prompt__cta-icon {
    font-size: 18px !important;
    color: var(--text-on-accent);
}

/* Wide (web) layout: auto-width CTA under the text, not stretched. */
.geo-prompt.geo-prompt--wide .geo-prompt__cta {
    width: auto;
    margin-top: 12px;
}

/* Compact (dialog/sheet): tighter collapsible body padding. */
.geo-prompt.geo-prompt--compact .info-panel__body--collapsible {
    padding: 0 12px 11px 43px;
}

/* ── Co-organizers editor (prototype CoOrganizersField) ──
   GLOBAL (not page-scoped) so the shared CoOrganizerField / CoOrganizerPickerModal components AND the detail
   page's Options sheet reuse one copy. Icons are plain selectors (no ::deep — global CSS has no page scope). */
.coorg-empty {
    font-size: 13.5px;
    color: var(--tt-game-text-muted);
    line-height: 1.45;
    margin-bottom: 10px;
}

.coorg-list {
    display: flex;
    flex-direction: column;
    gap: 10px;
    margin-bottom: 10px;
}

.coorg-card {
    border: 1px solid var(--tt-tour-card-border);
    border-radius: 10px;
    background: var(--surface-card);
    overflow: hidden;
}

.coorg-head {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 11px;
}

.coorg-id {
    flex: 1;
    min-width: 0;
}

.coorg-name {
    display: block;
    font-size: 14.5px;
    font-weight: 600;
    color: var(--tt-game-text-name);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.coorg-meta {
    font-size: 12.5px;
}

.coorg-rating {
    color: var(--tt-game-result-loss);
    font-weight: 700;
}

.coorg-games {
    color: var(--tt-game-text-muted);
}

.coorg-x {
    flex-shrink: 0;
    width: 30px;
    height: 30px;
    border-radius: 8px;
    border: 1px solid var(--tt-game-card-separator);
    background: var(--surface-card);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.coorg-x-icon {
    width: 15px;
    height: 15px;
    font-size: 15px;
    color: var(--tt-game-text-muted);
}

/* Finish-right toggle row: warm off-white when off, clay-tinted when on (prototype TinySwitch row —
   off is #fbfaf8, NOT the gray chip track). */
.coorg-finish {
    display: flex;
    align-items: center;
    gap: 11px;
    width: 100%;
    padding: 10px 11px;
    border: none;
    border-top: 1px solid var(--tt-settings-line);
    background: var(--tt-settings-card);
    cursor: pointer;
    text-align: left;
}

    .coorg-finish.on {
        /* Prototype CLAY_BG = rgba(brand-clay, .10) — the subtle warm tint, NOT the saturated registration
           chip color (--tt-tour-badge-clay-bg maps to the registration status bg, too heavy here). */
        background: var(--tint-clay-soft);
    }

    /* Read-only row (co-organizer viewer): shown for information only — no pointer, the switch reads as disabled. */
    .coorg-finish--ro {
        cursor: default;
    }

        .coorg-finish--ro .tiny-switch {
            opacity: .5;
        }

.coorg-finish-text {
    flex: 1;
    min-width: 0;
}

.coorg-finish-title {
    display: block;
    font-size: 13.5px;
    font-weight: 600;
    color: var(--tt-tour-ink-soft);
}

.coorg-finish.on .coorg-finish-title {
    color: var(--tt-tour-badge-clay-fg);
}

.coorg-finish-sub {
    display: block;
    font-size: 11.5px;
    color: var(--tt-game-text-muted);
    line-height: 1.4;
    margin-top: 1px;
}

.coorg-finish.on .coorg-finish-sub {
    color: var(--tt-tour-badge-clay-fg);
}

/* Pill switch (44×26). Knob slides right when on. */
.tiny-switch {
    position: relative;
    flex-shrink: 0;
    width: 44px;
    height: 26px;
    border-radius: 13px;
    border: 1.5px solid var(--tt-game-card-separator);
    background: var(--tt-tour-chip-bg);
    transition: background .15s, border-color .15s;
}

    .tiny-switch.on {
        background: var(--tt-settings-accent);
        border-color: var(--tt-settings-accent);
    }

.tiny-knob {
    position: absolute;
    top: 2px;
    left: 2px;
    width: 19px;
    height: 19px;
    border-radius: 10px;
    background: var(--text-on-accent);
    box-shadow: 0 1px 2px rgba(0, 0, 0, .18);
    transition: left .15s;
}

.tiny-switch.on .tiny-knob {
    left: 20px;
}

/* A setting the viewer may see but not change (e.g. a ladder's auto-finish without the finish right). */
.tiny-switch:disabled {
    opacity: .5;
    cursor: default;
}

/* "Add a co-organizer" — clay dashed pill matching the search-open trigger. */
.coorg-add {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 9px 13px;
    border: 1.5px solid var(--tt-settings-accent);
    border-radius: 8px;
    background: var(--tt-settings-accent-tint);
    color: var(--tt-settings-accent-dark);
    font-size: 13.5px;
    font-weight: 600;
    cursor: pointer;
}

.coorg-add-icon {
    width: 16px;
    height: 16px;
    font-size: 16px;
    color: var(--tt-settings-accent);
}

/* Co-organizer picker modal (mirrors the detail page's centered "Add participant" sheet):
   centered dialog on desktop, bottom-sheet on mobile. */
.coorg-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, calc(0.4 + var(--scrim-extra)));
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 1300;
}

.coorg-dialog {
    display: flex;
    flex-direction: column;
    width: 440px;
    max-width: 92vw;
    max-height: 88vh;
    background: var(--surface-card);
    border-radius: 14px;
    padding: 22px;
    box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
}

.coorg-dialog h3 {
    margin: 0 0 12px;
    /* Clears the corner × (SheetGrip). */
    padding-right: 28px;
    font-size: 17px;
    color: var(--tt-game-text-name);
}

.coorg-search-bar {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 9px 11px;
    border: 1px solid var(--tt-settings-line);
    border-radius: 10px;
}

.coorg-search-icon {
    width: 17px;
    height: 17px;
    font-size: 17px;
    color: var(--tt-game-text-muted);
}

.coorg-search-input {
    flex: 1;
    min-width: 0;
    border: none;
    outline: none;
    font-size: 14.5px;
    color: var(--tt-game-text-name);
    background: transparent;
}

/* Geo panel sits under the search bar with a small gap (mirrors the add-player sheet). */
.coorg-dialog .coorg-geo-prompt {
    margin-top: 10px;
}

/* Candidate list scrolls inside the dialog so the search bar / actions stay pinned. */
.coorg-cand-list {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    margin-top: 8px;
}

.coorg-cand {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 9px 11px;
    background: var(--surface-card);
    border: none;
    border-bottom: 1px solid var(--tt-settings-line);
    cursor: pointer;
    text-align: left;
}

/* last-of-type, not last-child: Virtualize appends a spacer <div> after the rows. */
.coorg-cand:last-of-type {
    border-bottom: none;
}

.coorg-cand.on {
    background: var(--tt-settings-accent-tint);
}

.coorg-cand-body {
    flex: 1;
    min-width: 0;
}

/* Geo distance: same warm brown as the player-search rows (.ng-prow__km). */
.coorg-dist {
    flex-shrink: 0;
    white-space: nowrap;
    font-size: 12.5px;
    font-weight: 600;
    color: var(--tt-settings-accent-dark);
    font-variant-numeric: tabular-nums;
}

.coorg-cand-add {
    width: 19px;
    height: 19px;
    font-size: 19px;
    color: var(--tt-settings-accent);
    flex-shrink: 0;
}

.coorg-search-empty {
    padding: 14px 12px;
    text-align: center;
    color: var(--tt-game-text-muted);
    font-size: 13.5px;
}

.coorg-search-note {
    padding: 9px 2px 0;
    font-size: 11.5px;
    color: var(--tt-game-text-muted);
    line-height: 1.4;
}

.coorg-search-actions {
    display: flex;
    gap: 8px;
    padding-top: 12px;
    margin-top: 12px;
    border-top: 1px solid var(--tt-settings-line);
}

.coorg-search-cancel {
    flex-shrink: 0;
    padding: 8px 14px;
    background: none;
    border: 1px solid var(--tt-settings-line);
    border-radius: 8px;
    color: var(--tt-game-text-muted);
    font-size: 13.5px;
    cursor: pointer;
}

.coorg-search-confirm {
    flex: 1;
    padding: 8px 14px;
    background: var(--tt-settings-accent);
    border: none;
    border-radius: 8px;
    color: var(--text-on-accent);
    font-size: 13.5px;
    font-weight: 600;
    cursor: pointer;
}

.coorg-search-confirm:disabled {
    opacity: 0.5;
    cursor: default;
}

/* Mobile: centered dialog becomes a bottom-sheet, matching the detail page's sheet behavior. */
@media (max-width: 959px) {
    .coorg-overlay {
        align-items: flex-end;
        bottom: var(--sheet-bottom);
    }

    .coorg-dialog {
        width: 100%;
        max-width: 100%;
        max-height: calc(100% - var(--tt-appbar-height));
        border-radius: 16px 16px 0 0;
    }
}

/* ── Finished-tournament results page (design_handoff_final_page) ──────────────────────────────
   Shared, NON-scoped classes: the section chrome (headline + hairline), the collapsed-block wrapper,
   the segment toggle, the "left hand" chip and the "you" chip. Scoped .razor.css can't reach child
   components, so the pieces every final-page sub-component shares live here. Desktop is a block in the
   content column; mobile bleeds edge-to-edge with a hairline between sections. */

.final-section {
    padding: 28px 0 0;
}

.final-section:first-child {
    padding-top: 0;
}

.final-section-title {
    margin: 0 0 10px;
    font-size: 18px;
    font-weight: 700;
    color: var(--text-primary);
    letter-spacing: -0.2px;
}

.final-section-head {
    display: flex;
    align-items: flex-end;
    gap: 10px;
    margin-bottom: 10px;
}

.final-section-head .final-section-title {
    flex: 1;
    min-width: 0;
    margin: 0;
}

.final-section-note {
    font-size: 12.5px;
    color: var(--text-muted);
    margin-top: 3px;
    line-height: 1.4;
}

/* The "left hand" chip — the same beige pill as the participants list / top players. A flex sibling of
   the name (flex-shrink:0), never inside the ellipsised name span, so the name truncates, not the chip. */
.final-hand-chip {
    flex-shrink: 0;
    font-size: 10.5px;
    font-weight: 600;
    color: var(--tt-game-hand-pill-text);
    background: var(--tt-game-hand-pill-bg);
    border: 1px solid var(--tt-game-hand-pill-border);
    border-radius: 4px;
    padding: 1px 6px;
    white-space: nowrap;
}

/* The "you" chip after the current player's name. */
.final-you-chip {
    flex-shrink: 0;
    font-size: 11px;
    font-weight: 700;
    color: var(--text-link);
    background: var(--tint-clay-soft);
    border-radius: 5px;
    padding: 2px 7px;
}

/* Segment toggle (List ⇄ Table) — the small pill switch. */
.final-seg {
    display: inline-flex;
    gap: 2px;
    background: var(--control-track);
    border-radius: 9px;
    padding: 3px;
}

.final-seg button {
    padding: 5px 11px;
    font-size: 12.5px;
    font-weight: 700;
    font-family: var(--tt-font-family);
    border: none;
    background: transparent;
    color: var(--text-muted);
    border-radius: 7px;
    cursor: pointer;
    white-space: nowrap;
}

.final-seg button.on {
    background: var(--control-thumb);
    color: var(--action-primary);
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12);
}

/* Collapsed block ("Protocol", "All matches", "Participants"): a card-button with a chevron. */
.final-block {
    padding: 26px 0 0;
}

.final-collapse-btn {
    width: 100%;
    display: flex;
    align-items: center;
    gap: 10px;
    background: var(--surface-card);
    border: 1px solid var(--border-card);
    border-radius: 12px;
    padding: 13px 14px;
    cursor: pointer;
    font-family: var(--tt-font-family);
    text-align: left;
}

.final-collapse-title {
    flex: 1;
    min-width: 0;
    font-size: 15px;
    font-weight: 700;
    color: var(--text-primary);
}

.final-collapse-count {
    color: var(--text-muted);
    font-weight: 600;
}

.final-collapse-note {
    display: block;
    font-size: 12px;
    font-weight: 500;
    color: var(--text-muted);
    margin-top: 2px;
}

.final-collapse-chevron {
    display: flex;
    transition: transform 0.2s;
    color: var(--text-muted);
}

.final-collapse-chevron.open {
    transform: rotate(90deg);
}

.final-collapse-body {
    padding-top: 10px;
}

/* List surface: desktop is a bordered card, mobile bleeds full width with hairlines. */
.final-panel {
    background: var(--surface-card);
    border: 1px solid var(--border-card);
    border-radius: 12px;
    overflow: hidden;
}

@media (max-width: 720px) {
    .final-section {
        background: var(--surface-card);
        padding: 18px 16px;
        border-top: 1px solid var(--border-card);
    }

    .final-section:first-child {
        border-top: none;
        padding-top: 14px;
    }

    .final-section-title {
        font-size: 17px;
    }

    .final-block {
        padding: 0 16px;
    }

    .final-panel {
        border-left: none;
        border-right: none;
        border-radius: 0;
    }
}

/* ════════════════════════════════════════════════════════════════════════════
   Help hint ("?" dot + popover). Global (not scoped) because the popover renders through the MudBlazor
   popover provider, outside the component's DOM scope where a scoped ::deep bundle would not reach it.
   Consumes role tokens like the rest of the palette. */
.help-hint-menu {
    display: inline-flex;
    vertical-align: middle;
}

.help-hint-dot {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    border: 1.3px solid var(--border-card);
    color: var(--text-muted);
    background: transparent;
    font-weight: 700;
    line-height: 1;
    cursor: pointer;
    flex-shrink: 0;
    user-select: none;
}

.help-hint-dot:hover {
    border-color: var(--action-primary);
    color: var(--action-primary-pressed);
    background: var(--tint-clay-soft);
}

.help-hint-pop {
    max-width: 272px;
    padding: 13px 14px 11px;
    display: flex;
    flex-direction: column;
    gap: 9px;
}

.help-hint-micro {
    font-size: 13.5px;
    line-height: 1.6;
    color: var(--text-secondary);
}

.help-hint-more {
    align-self: flex-start;
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: 13px;
    font-weight: 700;
    color: var(--action-primary-pressed);
    text-decoration: none;
}

/* A player NAME that opens the mini-profile when the name is rendered OUTSIDE PlayerAvatarView (its own
   cluster handles this itself). Used by the tournament participant / standings rows, whose name markup
   carries custom chips and so sits next to a ShowName="false" avatar. */
.pav-nameclick {
    cursor: pointer;
}

    .pav-nameclick:hover {
        text-decoration: underline;
    }

/* ── Venues: Leaflet map + teardrop marker ─────────────────────────────────
   Global (not scoped): Leaflet renders its panes/markers outside the component's
   scoped-CSS boundary, so these rules must live in the shared bundle. */
.vmap {
    width: 100%;
    height: 100%;
    min-height: 160px;
    border-radius: 12px;
    overflow: hidden;
    border: 1px solid var(--border-card);
    background: var(--surface-card-warm);
    z-index: 0;
}

/* Offline / no-JS fallback: a striped placeholder instead of a blank grey box. */
.vmap--offline {
    background: repeating-linear-gradient(135deg, var(--surface-page) 0 10px, var(--border-hairline) 10px 20px);
}

.vmap-pin-wrap {
    background: none;
    border: none;
}

.vmap-pin {
    width: 30px;
    height: 30px;
    border-radius: 50% 50% 50% 0;
    transform: rotate(-45deg);
    background: var(--action-primary);
    border: 2px solid var(--surface-card);
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
    display: flex;
    align-items: center;
    justify-content: center;
}

.vmap-pin__num {
    transform: rotate(45deg);
    color: var(--text-on-accent);
    font-weight: 700;
    font-size: 11px;
    font-family: Roboto, sans-serif;
    line-height: 1;
}

/* Directory pin variants (SCREENS §1 / README §0.3): white = directory-only (no online booking); the badge
   marks whether a free slot falls in the travel window. Clay booking pins keep the default .vmap-pin look. */
.vmap-pin--none {
    background: var(--surface-card);
    border-color: var(--status-inactive);
}

.vmap-pin--none .vmap-pin__num {
    color: var(--text-secondary);
}

.vmap-pin__badge {
    position: absolute;
    right: -2px;
    top: -2px;
    width: 11px;
    height: 11px;
    border-radius: 6px;
    border: 2px solid var(--surface-card);
}

.vmap-pin__badge--free {
    background: var(--status-win);
}

.vmap-pin__badge--later {
    background: var(--status-pending);
}

/* The pin of the card under the pointer (web) or of the tapped venue (narrow layouts): bigger and darker. */
.vmap-pin-active .vmap-pin {
    transform: rotate(-45deg) scale(1.22);
    background: var(--action-primary-pressed);
}

/* The pressed clay turns light at night. */
.vmap-pin-active .vmap-pin:not(.vmap-pin--none) .vmap-pin__num {
    color: var(--text-on-status);
}

.vmap-pin-active .vmap-pin--none {
    background: var(--surface-card);
    border-color: var(--action-primary);
}

/* "You are here" marker + return-to-me control. */
.vmap-me {
    position: relative;
    width: 40px;
    height: 40px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.vmap-me__halo {
    position: absolute;
    inset: 0;
    border-radius: 20px;
    background: color-mix(in srgb, var(--surface-distance-pin) 13%, transparent);
}

.vmap-me__dot {
    position: relative;
    width: 14px;
    height: 14px;
    border-radius: 8px;
    background: var(--surface-distance-pin);
    border: 2.5px solid var(--surface-card);
    box-shadow: 0 1px 4px rgba(0, 0, 0, .3);
}

.vmap-me-wrap {
    background: none;
    border: none;
}

/* Return-to-me control button (both engines share the icon color). */
.vmap-me-ctl a,
.vmap-me-ctl button {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    color: var(--text-neutral-strong);
    background: var(--surface-raised);
    cursor: pointer;
    border: none;
}

/* Off-screen state: the control turns clay to nudge the user back to their point (prototype .vmap-away). */
.vmap-me-ctl a.vmap-away,
.vmap-me-ctl button.vmap-away {
    color: var(--text-on-accent);
    background: var(--action-primary);
}

/* Night map. Raster OSM has no night style, so venue-map.leaflet.js tags its layer and it is inverted here (the
   Esri fallback switches to Dark Gray instead); the engines' own controls and tooltips are white in their lib CSS. */
@media screen {
    :root[data-theme="dark"] .vmap-osm-tiles {
        filter: invert(1) hue-rotate(180deg) brightness(.9) saturate(.55);
    }

    :root[data-theme="dark"] .vmap .leaflet-bar a:not(.vmap-away),
    :root[data-theme="dark"] .vmap .maplibregl-ctrl-group {
        background-color: var(--surface-raised);
        color: var(--text-primary);
    }

    :root[data-theme="dark"] .vmap .leaflet-bar a {
        border-bottom-color: var(--border-card);
    }

    :root[data-theme="dark"] .vmap .maplibregl-ctrl-group button + button {
        border-top-color: var(--border-card);
    }

    /* MapLibre's zoom glyphs are dark data-URI SVGs. */
    :root[data-theme="dark"] .vmap .maplibregl-ctrl-zoom-in .maplibregl-ctrl-icon,
    :root[data-theme="dark"] .vmap .maplibregl-ctrl-zoom-out .maplibregl-ctrl-icon {
        filter: invert(1);
    }

    :root[data-theme="dark"] .vmap .leaflet-tooltip {
        background-color: var(--surface-raised);
        border-color: var(--border-card);
        color: var(--text-primary);
    }

    :root[data-theme="dark"] .vmap .leaflet-tooltip-top::before {
        border-top-color: var(--surface-raised);
    }
}

/* MapLibre custom-marker wrapper. Leaflet uses .vmap-pin-wrap (divIcon); MapLibre has no divIcon, so it wraps
   the same .vmap-pin in its own element (anchor:'bottom' set in JS). Sizing only — visuals stay in .vmap-pin. */
.vmap-pin-wrap-ml {
    width: 30px;
    height: 38px;
    line-height: 0;
}

/* Admin section pages: widen the shared left-aligned content column to the design's 1080 (the global default is
   860). Global, not scoped — it sits on a MudContainer, which never carries a page's CSS-isolation attribute. */
.admin-page-host {
    --tt-content-max: 1080px;
}

/* Claim-moderation pills — global so the page and its dialogs (rendered outside the page's scoped CSS) share them. */
.claims-pill {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.2px;
    padding: 2px 7px;
    border-radius: 5px;
    white-space: nowrap;
    flex-shrink: 0;
}

.claims-pill--dispute {
    color: var(--text-warn);
    background: var(--alert-warn-bg);
    border: 1px solid var(--alert-warn-border);
}

.claims-pill--escalated {
    color: var(--text-warn);
    background: var(--alert-warn-bg);
    border: 1px solid var(--alert-warn-border);
}

.claims-pill--creator {
    color: var(--badge-qualifying-fg);
    background: var(--badge-qualifying-bg);
    border: 1px solid var(--badge-qualifying-border);
}

.claims-pill--role,
.claims-pill--muted {
    color: var(--text-label-warm);
    background: var(--control-track);
}

/* Unverified OSM/other import — same dashed warn look as the venue card's "not verified" badge. */
.claims-pill--import {
    color: var(--tone-warn-ink);
    background: var(--alert-warn-bg);
    border: 1px dashed var(--alert-warn-border);
}

.claims-nick {
    font-size: 13px;
    font-style: italic;
    color: var(--text-muted);
}

.claims-meta {
    font-size: 12.5px;
    color: var(--text-secondary);
}

/* Claim resolve dialog: the claim card (venue head + applicant block) the decision is taken on. */
.cr-card {
    border: 1px solid var(--border-card);
    border-radius: 11px;
    overflow: hidden;
}

.cr-card-venue {
    padding: 11px 13px;
}

.cr-card-claim {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 11px 13px;
    border-top: 1px solid var(--border-hairline);
    background: var(--surface-card-warm);
}

.cr-venue {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

.cr-venue-name {
    font-size: 14.5px;
    font-weight: 700;
    color: var(--text-primary);
}

.cr-venue-place {
    font-size: 12.5px;
    color: var(--text-secondary);
    margin-top: 2px;
    line-height: 1.4;
}

.cr-pills {
    display: flex;
    gap: 5px;
    flex-wrap: wrap;
}

.cr-fact {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    font-size: 13px;
    line-height: 1.45;
    color: var(--text-primary);
    overflow-wrap: anywhere;
}

.cr-fact--muted {
    color: var(--text-muted);
}

.cr-fact-icon {
    font-size: 15px !important;
    color: var(--text-muted);
    flex-shrink: 0;
    margin-top: 1px;
}

.cr-note {
    font-size: 12.5px;
    line-height: 1.5;
    border-radius: 10px;
    padding: 11px 13px;
    margin-top: 12px;
}

.cr-note--warn {
    background: var(--alert-warn-bg);
    border: 1px solid var(--alert-warn-border);
    color: var(--text-warn-soft);
}

.cr-note--info {
    background: var(--alert-info-bg);
    border: 1px solid var(--alert-info-border);
    color: var(--text-info);
}

.cr-field-label {
    font-size: 11.5px;
    font-weight: 700;
    letter-spacing: 0.5px;
    text-transform: uppercase;
    color: var(--text-muted);
    margin: 14px 0 7px;
}

.cr-reasons {
    display: flex;
    flex-wrap: wrap;
    gap: 7px;
}

.cr-reason {
    font-size: 12.5px;
    font-weight: 500;
    padding: 7px 12px;
    border-radius: 18px;
    cursor: pointer;
    border: 1px solid var(--border-card);
    background: var(--surface-card);
    color: var(--text-secondary);
    font-family: inherit;
}

    .cr-reason.on {
        font-weight: 700;
        border-color: var(--tint-clay-border);
        background: var(--tint-clay-soft);
        color: var(--text-filter-name);
    }

.cr-field-hint {
    display: flex;
    align-items: center;
    gap: 5px;
    font-size: 12px;
    color: var(--text-secondary);
    margin-top: 6px;
    line-height: 1.45;
}

.cr-lock-icon,
.cn-lock-icon {
    font-size: 13px !important;
    color: var(--text-muted);
}

.cr-footnote {
    font-size: 12px;
    color: var(--text-secondary);
    line-height: 1.45;
    margin-top: 14px;
}

/* Claim notes dialog. */
.cn-sub {
    font-size: 13px;
    color: var(--text-secondary);
    line-height: 1.45;
    margin-bottom: 10px;
}

.cn-empty {
    font-size: 13px;
    color: var(--text-muted);
    padding: 6px 0;
}

.cn-list {
    border: 1px solid var(--border-card);
    border-radius: 11px;
    overflow: hidden;
}

.cn-row {
    padding: 10px 12px;
    border-top: 1px solid var(--border-hairline);
}

.cn-row:first-child {
    border-top: none;
}

.cn-row-head {
    font-size: 12.5px;
    color: var(--text-secondary);
}

.cn-row-text {
    font-size: 13.5px;
    color: var(--text-primary);
    line-height: 1.45;
    margin-top: 2px;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

.cn-hint {
    display: flex;
    align-items: center;
    gap: 5px;
    font-size: 12px;
    color: var(--text-secondary);
    margin-top: 6px;
}

/* "Also available in your language" (LanguageOffer, web host App.razor, outside the layout): under the app bar, clear
   of the page action bars at the bottom; under the drawer and every overlay. */
.lang-offer {
    position: fixed;
    left: 50%;
    top: calc(var(--tt-appbar-height) + 8px);
    transform: translateX(-50%);
    z-index: calc(var(--z-page-bar) + 1);
    display: flex;
    align-items: center;
    gap: 12px;
    box-sizing: border-box;
    width: max-content;
    max-width: calc(100% - 32px);
    padding: 6px 6px 6px 16px;
    background: var(--surface-card);
    color: var(--text-primary);
    border: 1px solid var(--border-card);
    border-radius: var(--tt-border-radius);
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.16);
    font-family: var(--tt-font-family);
    font-size: var(--tt-font-size-body);
    line-height: 1.35;
}

.lang-offer[hidden] {
    display: none;
}

.lang-offer-text {
    flex: 1 1 auto;
    min-width: 0;
}

.lang-offer-switch {
    flex: 0 0 auto;
    padding: 6px 14px;
    border-radius: var(--tt-border-radius);
    background: var(--action-primary);
    color: var(--text-on-accent);
    font-weight: 500;
    text-decoration: none;
    white-space: nowrap;
}

.lang-offer-switch:hover,
.lang-offer-switch:focus-visible {
    background: var(--action-primary-pressed);
    color: var(--text-on-status);
}

.lang-offer-close {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: transparent;
    color: var(--text-secondary);
    cursor: pointer;
}

.lang-offer-close:hover {
    background: var(--surface-selected-row);
}

@media (max-width: 959px) {
    .lang-offer {
        left: 8px;
        right: 8px;
        transform: none;
        width: auto;
        max-width: none;
    }
}

@media print {
    .lang-offer {
        display: none;
    }
}

/* ═══════════════════════════════════════════════════════════════════════════
   Messages section — the bits several of its components share (design_handoff_messages TOKENS.md).
   Each component keeps its own scoped sheet; these classes cross component roots.
   ═══════════════════════════════════════════════════════════════════════════ */

/* A white rounded panel holding list rows (conversations, recipients) or an empty state. */
.chat-panel {
    background: var(--surface-card);
    border: 1px solid var(--border-card);
    border-radius: 14px;
    overflow: hidden;
}

/* The drill-down's way back ("All conversations", "Nearby chat"). */
.chat-back {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: var(--text-link);
    font-size: 14px;
    font-weight: 600;
    text-decoration: none;
    margin-bottom: 14px;
}

.chat-back:hover {
    text-decoration: underline;
}

/* The phone's "Write" button over the conversations list, above the bottom nav and the keyboard. */
.chat-fab {
    display: none;
}

@media (max-width: 959px) {
    .chat-panel {
        border-radius: 0;
        border-left: none;
        border-right: none;
        margin: 0 -16px;
    }

    .chat-fab {
        position: fixed;
        right: 14px;
        bottom: calc(var(--sheet-bottom) + 14px);
        z-index: var(--z-page-bar);
        display: inline-flex;
        align-items: center;
        gap: 8px;
        background: var(--action-primary);
        color: var(--text-on-accent);
        border: none;
        border-radius: 14px;
        padding: 13px 18px;
        font-size: 15px;
        font-weight: 600;
        text-decoration: none;
        box-shadow: 0 6px 18px color-mix(in srgb, var(--action-primary) 35%, transparent);
    }
}

/* ── TTAR ≈ other rating scales (Components/RatingEquiv) ─────────────────────────────────────────────
   Global, not scoped: the popover body renders in MudBlazor's popover provider. */
.eq-hover {
    display: inline-block;
}

/* The dotted underline wherever the number is live: under a mouse, and on touch only where a tap opens the sheet. */
.eq-hover.eq-hover--tap {
    cursor: pointer;
    text-decoration-line: underline;
    text-decoration-style: dotted;
    text-decoration-color: var(--border-separator);
    text-decoration-thickness: 1.5px;
    text-underline-offset: 4px;
}

@media (hover: hover) and (pointer: fine) {
    .eq-hover:not(.eq-hover--plain) {
        cursor: help;
        text-decoration-line: underline;
        text-decoration-style: dotted;
        text-decoration-color: var(--border-separator);
        text-decoration-thickness: 1.5px;
        text-underline-offset: 4px;
    }
}

.eq-pop.mud-popover {
    width: 300px;
    max-width: calc(100vw - 16px);
    background: var(--surface-raised);
    border: 1px solid var(--border-card);
    border-radius: 12px;
    box-shadow: 0 12px 32px rgba(0, 0, 0, .16);
    font-family: var(--tt-font-family);
    text-align: left;
    cursor: default;
    white-space: normal;
    text-decoration: none;
    animation: eq-in .13s ease;
}

.eq-pop-body {
    padding: 13px 14px 12px;
}

.eq-sheet {
    padding: 4px 2px 8px;
}

@keyframes eq-in {
    from { opacity: 0; margin-top: 4px; }
    to { opacity: 1; margin-top: 0; }
}

.eq-panel {
    display: flex;
    flex-direction: column;
    gap: 11px;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
}

.eq-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    flex-wrap: wrap;
    column-gap: 10px;
    row-gap: 6px;
}

.eq-head-num {
    white-space: nowrap;
}

.eq-admit {
    font-size: 12px;
    color: var(--text-muted);
    margin-right: 6px;
}

.eq-big {
    font-size: 20px;
    font-weight: 800;
    letter-spacing: -0.3px;
}

.eq-big--qual {
    color: var(--text-muted);
    font-style: italic;
}

.eq-unit {
    font-size: 11.5px;
    font-weight: 700;
    color: var(--text-muted);
}

.eq-rank {
    font-size: 12px;
    font-weight: 700;
    color: var(--action-primary-pressed);
    background: var(--tint-clay-soft);
    border-radius: 999px;
    padding: 3px 9px;
    white-space: nowrap;
}

.eq-qual {
    font-size: 11.5px;
    font-weight: 700;
    color: var(--badge-qualifying-fg);
    background: var(--badge-qualifying-bg);
    border-radius: 4px;
    padding: 2px 7px;
    white-space: nowrap;
}

.eq-qual-text {
    font-size: 13px;
    line-height: 1.5;
    color: var(--text-secondary);
}

/* Ruler: TTAR ticks on top, the rank bands with the mark (or the admission window), the chosen scale below. */
.eq-ruler {
    display: grid;
    grid-template-columns: 38px minmax(0, 1fr);
    column-gap: 8px;
    row-gap: 4px;
    align-items: center;
}

.eq-cap {
    font-size: 10px;
    font-weight: 800;
    letter-spacing: 0.5px;
    color: var(--text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.eq-ticks {
    position: relative;
    height: 13px;
}

.eq-tick {
    position: absolute;
    transform: translateX(-50%);
    font-size: 10.5px;
    font-weight: 500;
    line-height: 13px;
    color: var(--text-muted);
    white-space: nowrap;
}

.eq-tick--ttar {
    font-weight: 700;
    color: var(--text-secondary);
}

.eq-bands {
    position: relative;
    height: 10px;
}

.eq-band-row {
    display: flex;
    gap: 1px;
    height: 100%;
    border-radius: 5px;
    overflow: hidden;
}

.eq-band {
    background: var(--control-track);
}

.eq-band:nth-child(even) {
    background: var(--border-card);
}

.eq-band.eq-band--on {
    background: var(--tint-clay-border);
}

.eq-mark {
    position: absolute;
    top: -5px;
    bottom: -5px;
    width: 3px;
    margin-left: -1.5px;
    background: var(--action-primary-pressed);
    border-radius: 2px;
    box-shadow: 0 0 0 2px var(--surface-card);
}

.eq-window {
    position: absolute;
    top: -3px;
    bottom: -3px;
    border: 2px solid var(--action-primary);
    border-radius: 6px;
    background: var(--tint-clay-strip);
}

.eq-section {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.eq-label {
    font-size: 12px;
    color: var(--text-muted);
}

.eq-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 6px;
}

.eq-grid--single {
    grid-template-columns: minmax(0, 1fr);
}

.eq-cell {
    min-width: 0;
    border: 1px solid var(--border-hairline);
    border-radius: 8px;
    padding: 6px 9px 7px;
    background: var(--surface-card);
}

.eq-cell--on {
    border-color: var(--tint-clay-border);
    background: var(--tint-clay-soft);
}

.eq-cell-name {
    font-size: 10.5px;
    font-weight: 800;
    letter-spacing: 0.4px;
    color: var(--text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.eq-cell--on .eq-cell-name {
    color: var(--action-primary-pressed);
}

.eq-cell-note {
    font-weight: 500;
    letter-spacing: 0;
    color: var(--text-muted);
}

.eq-cell-value {
    margin-top: 1px;
    white-space: nowrap;
}

.eq-cell-value b {
    font-size: 15px;
    font-weight: 700;
}

.eq-approx {
    color: var(--text-muted);
    font-weight: 400;
}

.eq-seg {
    display: flex;
    gap: 2px;
    padding: 3px;
    border-radius: 9px;
    background: var(--control-track);
}

.eq-seg button {
    flex: 1;
    min-height: 30px;
    border: none;
    border-radius: 7px;
    background: transparent;
    color: var(--text-secondary);
    font: inherit;
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
}

.eq-seg button.on {
    background: var(--control-thumb);
    color: var(--action-primary-pressed);
    font-weight: 700;
    box-shadow: 0 1px 2px rgba(0, 0, 0, .08);
}

/* Clay and red labels reach only ~2.5-3.9 on the night thumb. */
:root[data-theme="dark"] .rate-seg-btn--on,
:root[data-theme="dark"] .hand-seg-btn--on,
:root[data-theme="dark"] .final-seg button.on,
:root[data-theme="dark"] .eq-seg button.on,
:root[data-theme="dark"] .dash-seg__btn--on {
    color: var(--text-primary);
}

.eq-foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 4px 10px;
}

.eq-note {
    flex: 1 1 160px;
    font-size: 12px;
    line-height: 1.45;
    color: var(--text-muted);
}

.eq-help-dot {
    width: 16px;
    height: 16px;
    font-size: 11px;
}

.eq-help {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin-top: -4px;
    padding: 9px 11px;
    border-radius: 8px;
    background: var(--control-track);
}

.eq-help .help-hint-micro {
    font-size: 12.5px;
    line-height: 1.5;
}
