/* ===== Design tokens (ELEVATION-PLAN.md Pillar 1 / Phase F1) =====
   Single source of truth for the visual vocabulary. Reference these via var()
   instead of hardcoding hex. The raw palette holds the exact legacy values so
   this layer is a value-preserving migration; the *semantic* tokens below sit
   on top and are what dark mode (Phase F2) remaps. New code should use the
   semantic tokens (--text, --surface, --border, --color-accent, …), not raw
   palette entries.

   Breakpoints can't be custom properties (media queries can't read var()).
   Canonical widths — reference these two everywhere:
     480px  = phone
     768px  = tablet / desktop split (the ScoreEntry desktop/mobile swap) */
:root {
    /* --- Raw palette (exact legacy values; prefer the semantic tokens) --- */
    --white: #fff;
    --gray-100: #f5f5f5;
    --gray-150: #f2f2f2;
    --gray-200: #eee;
    --gray-300: #e0e0e0;
    --gray-350: #ddd;
    --gray-400: #ccc;
    --gray-450: #bbb;
    --gray-500: #9e9e9e;
    --gray-600: #888;
    --gray-650: #666;
    --gray-700: #555;
    --slate-500: #6c757d;
    --surface-1: #f7f9fb;    /* faint blue-white panels */
    --surface-2: #f0f0f0;
    --surface-3: #f9f9f9;
    --ink: #1a1a1a;
    --navy: #2c3e50;         /* dominant brand navy (168 legacy uses) */
    --navy-dark: #1a252f;    /* navy pressed/hover */
    --green-500: #28a745;    /* THE brand green — one green, chosen 2026-07 */
    --red-500: #dc3545;
    --amber-500: #f39c12;
    --blue-500: #1e88e5;

    /* --- Semantic tokens (what pages should use; dark mode remaps these) --- */
    --color-accent: var(--green-500);
    --surface: var(--white);
    --surface-subtle: var(--gray-100);
    --surface-inverse: var(--navy);   /* solid dark chip/button/avatar ground (stays dark in dark mode) */
    --surface-selected: #e3f2fd;      /* pale-blue highlight for an expanded/selected table row (dark-remapped below) */
    --on-solid: #fff;                 /* text/icons on a solid colored/dark surface — never inverts */
    /* Ink on a SATURATED HUE ground (a --danger pill, a --slate-500 chip), as opposed to --on-solid,
       which sits on --navy and therefore never inverts. The hues brighten in dark mode — --danger
       goes #dc3545 → #f0666f — and white on those is ~2.8:1. This token flips instead: white in
       light, near-black in dark, which is what the dark-mode design actually draws. Amber is the
       exception and takes --navy: at #f39c12 it already needs dark ink in LIGHT mode too. */
    --on-hue: var(--white);
    --on-ink: var(--surface);         /* numeral on an --ink square mark: contrasts in both modes (white on dark, dark on light) */
    --text: var(--navy);
    --text-muted: var(--gray-650);
    --color-text-muted: var(--text-muted);  /* legacy alias (was an undefined ref) */
    --border: var(--gray-350);
    --color-border: var(--border);           /* legacy alias (was an undefined ref) */
    --border-strong: var(--gray-400);
    /* Ink for a control that is present but not currently usable — a disabled segment, a stepper
       at its bound, an overflow item the server would refuse — and for the trailing chevrons that
       are affordance rather than content. Deliberately NOT --border-strong, which several of these
       used to reach for: that's --gray-400, which inverts to #3c4550 and vanishes on a dark ground
       at ~1.6:1. --gray-500 stays clearly muted AND clearly legible in both themes, which matters
       because a greyed control still has to say what it is. */
    --ink-disabled: var(--gray-500);
    --danger: var(--red-500);
    --success: var(--green-500);
    --warning: var(--amber-500);
    --info: var(--blue-500);

    /* --- Elevation & hairline layer (Wagers pane redesign) ---
       A card on a *ground* rather than a 1px box on the same value as the page — which is what
       made the old pot table read flat. --surface-raised is the card, --page-ground is what it
       sits on, and the hairlines are the dividers inside it. Set explicitly in BOTH themes rather
       than derived from --white/--gray-*: dark mode wants a card LIGHTER than its ground, which
       the inverted neutral ramp can't express (it remaps --white to the page ground itself). */
    --surface-raised: var(--white);
    --page-ground: #eff1f4;
    --hairline: rgba(20, 26, 34, 0.10);
    --hairline-soft: rgba(20, 26, 34, 0.07);
    --control-fill: rgba(20, 26, 34, 0.04);
    --control-fill-strong: rgba(20, 26, 34, 0.09);
    --text-quiet: #79828e;            /* micro-caps labels, yardages, tertiary captions */
    /* A stage that HASN'T HAPPENED — quieter than --text-quiet, still legible. Deliberately not
       --ink-disabled, which means "present but not usable" and would say the wrong thing about a
       round that simply hasn't been started yet. Round hub's timeline card is the one caller. */
    --ink-future: #b6bcc4;
    --switch-knob-off: var(--white);  /* knob on an OFF track — light in both themes, like iOS */

    /* --- Champagne metal (leaderboard masthead + rail) ---
       A third meaning-bearing hue, added by the leaderboard redesign, and the discipline that
       makes it work is that it means exactly ONE thing: *standing*. Position on the board, the
       week you're looking at, a rare feat, the section labels that frame those. Green stays
       "live or money"; red stays "under par". Nothing else gets a hue.

       Light-mode values are a darker bronze rather than the dark theme's champagne: the same ink
       at #c9ad6e lands around 2:1 on white. The washes lighten correspondingly so a first-place
       tile reads as a tint in both themes instead of a stain in one. */
    --metal: #8a6d33;
    --metal-strong: #6f5624;
    /* The handoff proposed #9c8348 here; measured it lands at 3.65:1 on white, and this is the
       3rd-place numeral — 14px bold, which is below WCAG's large-text threshold and so needs
       4.5:1. Darkened just enough to clear it while staying lighter than --metal, which is what
       makes the podium taper read. */
    --metal-dim: #8f7238;
    --metal-line: rgba(138, 109, 51, 0.45);
    --metal-edge: rgba(138, 109, 51, 0.30);
    --metal-wash-18: rgba(138, 109, 51, 0.14);
    --metal-wash-16: rgba(138, 109, 51, 0.12);
    --metal-wash-10: rgba(138, 109, 51, 0.08);
    --metal-wash-07: rgba(138, 109, 51, 0.06);
    --metal-row-wash: linear-gradient(90deg, rgba(138, 109, 51, 0.07), transparent);
    /* The expanded scorecard's ground: the open row's wash at half strength, so the detail reads
       as a continuation of the row rather than a panel dropped inside the card. */
    --metal-wash-05: rgba(138, 109, 51, 0.05);
    /* The filled segment of a probability meter (the Odds page's head-to-head rows). It can't
       reuse --metal-wash-18, which is invisible as an 8px bar, and it can't be --metal, which
       reads as ink rather than as a fill. A win probability is a STANDING, so it has to be metal
       rather than accent — nothing on that screen is money. */
    --metal-meter: rgba(138, 109, 51, 0.55);
    /* An open board row takes the metal wash, not the pale-blue --surface-selected. "Metal means
       standing" — and blue was the one hue on this board that meant nothing. Indirected through
       its own token because --surface-selected is still right for the other tables that use it. */
    --row-open-wash: var(--metal-wash-10);

    /* Masthead grounds. --masthead-scrim does NOT invert: a photo header is a dark surface in
       both themes, which is why the ink over it is absolute rather than token-driven. */
    --masthead-ground: linear-gradient(180deg, #ffffff, #f3f5f8);
    --masthead-scrim: linear-gradient(180deg, rgba(10, 13, 16, 0.62), rgba(10, 13, 16, 0.80) 55%, rgba(10, 13, 16, 0.94));
    --rail-ground: #f6f8fa;

    /* Recap hero band. Same reasoning as --masthead-scrim, and deliberately NOT re-declared under
       [data-theme="dark"]: a hero is a dark surface in both themes, so the ground never flips and
       the ink over it is absolute hex (the dark-theme champagne / slate values, which are the
       correct ones on this ground in light mode too). */
    --recap-hero-ground: linear-gradient(180deg, #1c222a, #12161b);
    --recap-hero-edge: rgba(201, 173, 110, 0.30);

    /* Auth front door. Third member of the same family as --masthead-scrim and
       --recap-hero-ground, declared here and deliberately NOT re-declared under
       [data-theme="dark"]: the front door is a dark surface in both themes.

       That is the whole argument for the broadcast-dark direction. theme.js defaults the
       preference to `system` and resolves it against prefers-color-scheme, so a first-time
       visitor arrives on whichever theme their phone is set to — before the app has any
       preference of theirs to read. A ground that doesn't flip is one drawing to hold up rather
       than two, on the one screen that has to work for somebody who has never seen the app.

       The ink over it is absolute hex, declared as local custom properties on .afd-page in
       27-auth-front-door.css rather than scattered — the same shape .lvs-header and .dock use.
       Light mode's --metal (#8a6d33) is effectively invisible on this ground, which is why the
       champagne values are the drawn ones here in both themes. */
    --auth-ground: linear-gradient(180deg, #1c222a, #12161b);
    --auth-edge: rgba(201, 173, 110, 0.30);

    /* A primary button ON A DARK SURFACE, as a pair rather than a hex in a component.
       --navy deliberately doesn't invert (it doubles as the solid chip/avatar ground carrying
       --on-solid), so a navy button on a dark ground recedes into the page instead of leading
       it. These are scoped to that case and NOT the app-wide primary: on a light page --navy is
       still correct and re-pointing every .btn-primary at a near-white fill would be a different
       change than this one. Kept as a token pair so the next dark surface that needs a primary
       has somewhere to reach rather than pasting the hex a second time. */
    --btn-primary-ground: #eef1f4;
    --btn-primary-ink: #14181d;

    /* Score-state colors (carry meaning — keep distinct, esp. for F2 dark variants) */
    --score-birdie: var(--green-500);
    --score-eagle: var(--blue-500);
    --score-bogey: var(--amber-500);
    --under-par: var(--red-500);   /* scorecard convention already in use: under-par = red */
    --over-par: var(--text-muted);

    /* The pencil marks on a SELECTED score tile (mobile score entry, /score/{token}).
       The tile's ground is --surface-inverse, which is dark in BOTH themes, so these are
       absolute — the same reason .lvs-header declares its own ink. --under-par (#dc3545)
       is too dark to read as a 2px ring on navy, so the under mark is a lightened form of
       it; the over mark is a white wash, because "worse than par" is not a hue. */
    --score-mark-under: #f4a0a6;                 /* birdie / eagle ring — light form of --under-par */
    --score-mark-over: rgba(255, 255, 255, 0.55); /* bogey / double square */

    /* Scorecard marks + handicap stroke dots. The marks are hairline rings, not fills, so the
       numeral keeps --text and the dots can share the cell without being covered. --stroke-dot
       was a hardcoded #333 that vanished on the dark board; the rings are neutral on purpose —
       the scorecard adds no fourth hue. */
    --stroke-dot: #333;
    --mark-ring: rgba(20, 26, 34, 0.30);
    --mark-ring-outer: rgba(20, 26, 34, 0.12);
    --mark-under-ink: #c62733;
    /* The expanded scorecard's ground as an OPAQUE value — the double-bogey mark's inner gap ring
       has to PAINT the ground so the two lines read as two lines, and a wash over a surface can't
       do that: a translucent value there lets the outer ring show through and they merge. Keep in
       step with --metal-wash-05 over --surface-raised. */
    --psc-ground: #f9f8f5;

    /* --- Spacing scale --- */
    --space-1: 0.25rem;
    --space-2: 0.5rem;
    --space-3: 0.75rem;
    --space-4: 1rem;
    --space-5: 1.5rem;
    --space-6: 2rem;
    --space-8: 3rem;

    /* --- Radii --- */
    --radius-sm: 4px;
    --radius-md: 8px;
    --radius-lg: 12px;
    --radius-xl: 16px;
    --radius-pill: 999px;

    /* --- Shadows --- */
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.06);
    --shadow-md: 0 2px 8px rgba(0, 0, 0, 0.10);
    --shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.14);

    /* --- Typography --- */
    --font-sans: system-ui, Avenir, Helvetica, Arial, sans-serif;
    --font-weight-base: 400;
    --font-weight-medium: 500;
    --font-weight-semibold: 600;
    --font-weight-bold: 700;
    --text-xs: 0.75rem;
    --text-sm: 0.875rem;
    --text-base: 1rem;
    --text-lg: 1.125rem;
    --text-xl: 1.375rem;
    --text-2xl: 1.75rem;
}

/* ===== Layout primitives (spacing-grid utilities) =====
   Compose layout from these instead of hand-rolling flex/grid per page.
   All spacing snaps to the --space-* scale, so density/theme changes stay global.
   - .stack      : vertical flow, consistent gap between children (the "rows N apart" grid)
   - .cluster    : horizontal group that wraps, consistent gap (toolbars, chip/button rows)
   - .grid-cards : responsive card deck (repeat(auto-fill, minmax()), tokenized)
   ============================================================ */

/* Vertical rhythm. Default gap = --space-4 (16px). */
.stack {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}
.stack--tight { gap: var(--space-2); }   /* 8px  — dense forms, chip stacks */
.stack--snug  { gap: var(--space-3); }   /* 12px — default card internals   */
.stack--loose { gap: var(--space-6); }   /* 32px — page sections apart      */

/* Horizontal group; wraps by default, vertically centered. */
.cluster {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3);
}
.cluster--tight   { gap: var(--space-2); }
.cluster--between { justify-content: space-between; }   /* title <-> actions row */
.cluster--nowrap  { flex-wrap: nowrap; }

/* Responsive card deck. Override min column width per-use with --card-min. */
.grid-cards {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(var(--card-min, 280px), 1fr));
    gap: var(--space-4);
}
.grid-cards--wide   { --card-min: 340px; }
.grid-cards--narrow { --card-min: 220px; }

/* ===== Dark theme (ELEVATION-PLAN.md Phase F2) =====
   The light palette above is polarity-consistent: navy + dark greys are ALWAYS
   foreground, white + light greys are ALWAYS background. So dark mode is a pure
   inversion of the NEUTRAL ramp — every semantic token (--surface/--text/--border/…)
   derives from these palette entries, so surfaces, text and borders all flip
   coherently without editing a single use-site. Hues (accent/danger/warning/info)
   aren't inverted, only brightened so they stay legible on a dark ground; the
   score-state colors derive from those hues and follow automatically.

   js/theme.js stamps [data-theme="light"|"dark"] on <html> from the persisted
   preference (an inline snippet in index.html does it pre-paint to avoid FOUC).
   A WASM app can't run without JS, so there's no CSS-only prefers-color-scheme
   fallback to maintain — data-theme is always present. */
:root[data-theme="dark"] {
    color-scheme: dark;

    /* Neutrals — inverted ramp (background tones ⟷ foreground tones) */
    --white: #14181d;         /* base page ground (was the lightest surface) */
    --surface-3: #181d24;
    --gray-100: #1b2027;
    --surface-1: #1b2027;
    --gray-150: #1f242c;
    --gray-200: #262d36;
    --surface-2: #232a33;
    --gray-300: #2c333d;
    --gray-350: #323a45;
    --gray-400: #3c4550;
    --gray-450: #4a5460;
    --gray-500: #7a828c;
    --slate-500: #9aa3ad;
    --gray-600: #98a2ad;
    --gray-650: #aab2bc;
    --gray-700: #c2c9d1;
    --ink: #f0f2f4;
    --surface-selected: #1e2a3d;   /* muted navy tint so an expanded row reads as "selected" under light --text */

    /* Navy does NOT invert: it doubles as solid chip / button / avatar / active-pill
       backgrounds that carry white text, so it must stay dark. Text that used navy is
       migrated to --text (color:) and backgrounds to --surface-inverse; --text gets its
       own light value below. Navy as a solid ground reads as a raised dark-blue chip. */
    --text: #e6e9ec;
    --text-muted: #aab2bc;

    /* Hues — same identity, brighter for a dark ground */
    --green-500: #3ad160;
    --red-500: #f0666f;
    --amber-500: #f0a94b;
    --blue-500: #4ea3ef;

    /* Shadows read stronger on dark */
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
    --shadow-md: 0 2px 8px rgba(0, 0, 0, 0.5);
    --shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.6);

    /* Elevation layer — a card LIGHTER than the ground it sits on, which is the one place the
       inverted neutral ramp can't help (it remaps --white to the page ground). */
    --surface-raised: #171b21;
    --page-ground: #0f1216;
    --hairline: rgba(255, 255, 255, 0.07);
    --hairline-soft: rgba(255, 255, 255, 0.05);
    --control-fill: rgba(255, 255, 255, 0.04);
    --control-fill-strong: rgba(255, 255, 255, 0.10);
    --text-quiet: #6f7885;
    --ink-future: #5f6874;            /* quieter than --text-quiet, still off the ground */
    --switch-knob-off: #c8cfd8;

    /* Champagne metal — the values the design was drawn at. Same single meaning as in light
       mode (standing); only the polarity of the ink flips. */
    --metal: #c9ad6e;
    --metal-strong: #e8d6a8;
    --metal-dim: #b09a63;
    --metal-line: rgba(201, 173, 110, 0.40);
    --metal-edge: rgba(201, 173, 110, 0.22);
    --metal-wash-18: rgba(201, 173, 110, 0.18);
    --metal-wash-16: rgba(201, 173, 110, 0.16);
    --metal-wash-10: rgba(201, 173, 110, 0.10);
    --metal-wash-07: rgba(201, 173, 110, 0.07);
    --metal-row-wash: linear-gradient(90deg, rgba(201, 173, 110, 0.09), transparent);
    --metal-wash-05: rgba(201, 173, 110, 0.05);
    --metal-meter: rgba(201, 173, 110, 0.55);
    /* --row-open-wash is not re-declared: it points at --metal-wash-10, which re-themes here. */

    --stroke-dot: #c8cfd8;
    --mark-ring: rgba(255, 255, 255, 0.28);
    --mark-ring-outer: rgba(255, 255, 255, 0.14);
    --mark-under-ink: #f78b92;
    /* --metal-wash-05 (champagne @5%) over --surface-raised #171b21. The handoff prints #1a1d21,
       which doesn't composite: 201·0.05 + 23·0.95 = 31.9, not 26. A gap ring darker than the
       ground it is supposed to BE draws as a third hairline, which is the failure this token
       exists to avoid — so the arithmetic wins over the printed value. */
    --psc-ground: #202225;

    --masthead-ground: linear-gradient(180deg, #151a20, #101418);
    /* --masthead-scrim is deliberately NOT re-declared: a photo header is dark in both themes. */
    --rail-ground: #12161b;
}

/* ===== Icon font (self-hosted — ELEVATION-PLAN §4.4) =====
   Material Symbols Outlined is served from our own origin (fonts/…woff2) instead of
   fonts.googleapis.com at runtime. The Google fetch blanked every icon on first launch
   and offline (golf courses are dead zones); self-hosting makes icons render from the
   cached bundle. The @font-face + the .material-symbols-outlined utility class below are
   both lifted verbatim from Google's css2 payload — previously the ONLY source of both,
   so they must live here now. Full variable font (~3.9MB, cached once) rather than a glyph
   subset, because several components pick icon names dynamically (@item.Icon, @v.Icon, …)
   and an over-tight subset would silently blank them. */
@font-face {
    font-family: 'Material Symbols Outlined';
    font-style: normal;
    font-weight: 100 700;
    font-display: swap;
    src: url('../fonts/material-symbols-outlined.woff2') format('woff2');
}

.material-symbols-outlined {
    font-family: 'Material Symbols Outlined';
    font-weight: normal;
    font-style: normal;
    font-size: 24px;
    line-height: 1;
    letter-spacing: normal;
    text-transform: none;
    display: inline-block;
    white-space: nowrap;
    word-wrap: normal;
    direction: ltr;
    -webkit-font-feature-settings: 'liga';
    font-feature-settings: 'liga';
    -webkit-font-smoothing: antialiased;
}

/* ===== Reset & Base ===== */
*, *::before, *::after {
    box-sizing: border-box;
}

html, body {
    margin: 0;
    padding: 0;
    font-family: var(--font-sans);
    color: var(--text);
    background: var(--surface);
    line-height: 1.5;
    font-weight: var(--font-weight-base);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    /* App-like scroll: no rubber-band / pull-to-refresh bounce at the page edges
       (the update banner covers refresh), and a subtler on-brand tap flash. */
    overscroll-behavior-y: none;
    -webkit-tap-highlight-color: rgba(44, 62, 80, 0.12);
}

/* Reserve the scrollbar's gutter whether or not a scrollbar is being drawn, so that taking one
   away costs no layout. Every sheet and dialog in the app scroll-locks the page with
   `html:has(.modal-backdrop) { overflow: hidden }` (13-controls-overlays.css), which also removes
   the scrollbar — and #app-root is a 1280px CENTRED column, so on any viewport wider than that
   the whole app slid right by half the scrollbar's width the moment a sheet opened, and back on
   close. Reported against the account panel on the welcome screen, which is only where it is
   easiest to see: that screen has no full-bleed masthead pinned to the viewport edges to hide the
   movement behind. `overflow: hidden` still makes the element a scroll container, so the gutter
   survives the lock — that is the whole mechanism. Phones use overlay scrollbars, which reserve
   nothing, so this is a no-op there. */
html {
    scrollbar-gutter: stable;
}

h1, h2, h3, h4, h5, h6 {
    margin: 0;
}

a {
    color: var(--text);
    text-decoration: none;
}

h1:focus {
    outline: none;
}

/* ===== App Layout ===== */
#app-root {
    max-width: 1280px;
    margin: 0 auto;
    padding: 0;
    /* Safe-area insets (viewport-fit=cover): keep content clear of the notch /
       status bar at the top and of the rounded-corner gutters in landscape.
       Resolve to 0 on devices without insets, so this is harmless on desktop. */
    padding-top: env(safe-area-inset-top);
    padding-left: env(safe-area-inset-left);
    padding-right: env(safe-area-inset-right);
}

/* ===== Top Bar (auth info) ===== */
.top-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0.5rem 1rem;
    font-size: 0.85rem;
    color: var(--gray-650);
}

/* Leading brand wordmark — app identity + a one-tap shortcut home to the events list. */
.brand {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    color: var(--text);
    font-weight: 700;
    font-size: 0.95rem;
    letter-spacing: -0.01em;
}

.brand-icon {
    width: 1.5rem;
    height: 1.5rem;
    border-radius: 6px;
    display: block;
}

.brand:active {
    opacity: 0.6;
}

/* Account avatar — the only thing in the top bar now. Trailing initials button (Material 3
   pattern); tapping it opens the account bottom sheet below. */
.account-avatar-btn {
    width: 36px;
    height: 36px;
    border-radius: 50%;
    background: var(--navy);
    color: var(--on-solid);
    border: none;
    padding: 0;
    font-family: inherit;
    font-size: 0.8rem;
    font-weight: 700;
    line-height: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: box-shadow 0.15s ease, transform 0.1s ease;
}

.account-avatar-btn:hover {
    box-shadow: 0 0 0 3px rgba(44, 62, 80, 0.12);
}

.account-avatar-btn:active {
    transform: scale(0.96);
}

/* The account sheet's own chrome — .account-sheet-id / -avatar / -name / -email, the .more-link
   destination rows, .account-logout's #c0392b red and .theme-toggle-label — is GONE. The panel
   is .acc-* in 24-account.css now: one DOM that is a bottom sheet below 769px and a panel
   anchored to the avatar above it. Log out lost the red on purpose (it isn't destructive), and
   the four flat links collapsed to three destinations.

/* ===== Segmented control =====
   Track --gray-150, thumb --surface-inverse (navy never inverts, so the active segment reads as a
   raised chip in both themes), inactive ink --text-muted. Segments are flex:1 and therefore always
   equal width — labels must be short enough not to wrap. FOUR is the ceiling at 390px; five or
   more options is a SheetSelect, not a segmented control.

   One primitive, three former call sites: the rounds status filter, the round format switcher, and
   the appearance toggle that used to be .theme-toggle / .theme-toggle-opt (deleted with this). */
.segmented {
    display: flex;
    gap: var(--space-1);
    padding: 3px;
    background: var(--gray-150);
    border-radius: var(--radius-pill);
}
.segmented--square { gap: 6px; border-radius: var(--radius-md); }
.segmented__opt {
    flex: 1;
    min-width: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 5px;
    padding: 8px var(--space-1);
    border: none;
    border-radius: var(--radius-pill);
    background: none;
    color: var(--text-muted);
    font-family: inherit;
    font-size: 0.8rem;
    font-weight: var(--font-weight-semibold);
    cursor: pointer;
    transition: background 0.15s ease, color 0.15s ease;
    -webkit-tap-highlight-color: transparent;
}
.segmented--square .segmented__opt { border-radius: var(--radius-sm); padding: 9px var(--space-1); }
.segmented__opt.is-active { background: var(--surface-inverse); color: var(--on-solid); }
.segmented__opt:disabled { color: var(--ink-disabled); cursor: not-allowed; }
.segmented__opt .material-symbols-outlined { font-size: 17px; }

/* ===== Main Navigation ===== */
.main-nav {
    text-align: left;
    border-bottom: 4px solid var(--gray-300);
    position: relative;
}

.main-nav ul {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
}

.main-nav li {
    display: inline-block;
    margin-right: var(--space-5);
    padding-bottom: 0.8rem;
    position: relative;
    font-weight: 600;
    line-height: 1.1;
    font-size: 1.2rem;
}

.main-nav li a {
    text-decoration: none;
    color: var(--gray-500);
    padding-bottom: var(--space-2);
    transition: color 0.3s;
    font-weight: 600;
}

.main-nav li.active a {
    color: var(--text);
}

.main-nav li::after {
    content: '';
    position: absolute;
    bottom: -4px;
    left: 0;
    right: 0;
    height: 4px;
    background-color: transparent;
    z-index: 1;
}

.main-nav li.active::after {
    background-color: var(--navy);
}

/* ===== Admin Dropdown ===== */
.admin-menu {
    margin-left: auto;
    margin-right: 0;
    position: relative;
}

.admin-toggle {
    background: none;
    border: none;
    font-family: inherit;
    font-size: 1.2rem;
    font-weight: 600;
    color: var(--gray-500);
    cursor: pointer;
    padding: 0;
    display: flex;
    align-items: center;
    gap: 0.3rem;
    transition: color 0.3s;
}

.admin-menu.active .admin-toggle,
.admin-menu.open .admin-toggle {
    color: var(--text);
}

.admin-toggle:hover {
    color: var(--text);
}

.admin-gear {
    font-size: 1.1rem;
}

.admin-caret {
    font-size: 0.7rem;
    transition: transform 0.2s;
}

.admin-menu.open .admin-caret {
    transform: rotate(180deg);
}

.admin-backdrop {
    position: fixed;
    inset: 0;
    z-index: 99;
}

.admin-dropdown {
    position: absolute;
    top: calc(100% + 4px);
    right: 0;
    background: var(--surface);
    border: 1px solid var(--gray-300);
    border-radius: 6px;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
    list-style: none;
    padding: 0.4rem 0;
    margin: 0;
    min-width: 160px;
    z-index: 100;
    display: flex;
    flex-direction: column;
}

.admin-dropdown li {
    display: block;
    margin: 0;
    padding: 0;
    font-size: 0.95rem;
}

.admin-dropdown li.admin-group-header {
    padding: 0.5rem 1rem 0.25rem;
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--gray-500);
    cursor: default;
    pointer-events: none;
}

/* Separator + spacing between groups (skip the first group's header). */
.admin-dropdown li.admin-group-header:not(:first-child) {
    margin-top: 0.25rem;
    border-top: 1px solid var(--gray-200);
    padding-top: 0.5rem;
}

.admin-dropdown li::after {
    display: none;
}

.admin-dropdown li a {
    display: block;
    padding: 0.5rem 1rem;
    color: var(--text);
    font-weight: 600;
    text-decoration: none;
    transition: background-color 0.15s;
}

.admin-dropdown li a:hover {
    background-color: var(--gray-100);
}

.admin-dropdown li.active a {
    color: var(--text);
    background-color: var(--surface-2);
}

/* ===== Mobile Bottom Tab Bar =====
   The bar itself is 26-bottom-nav.css now — it became a floating, blurred pane with four stable
   tabs (Board · Round · Season · You) and a live-round dock above it, which is more than a base
   chrome rule should carry. What stays here is only the desktop default: hidden.

   .more-section / .more-link BELOW ARE NOT DEAD. The phone's "More" sheet went with the fifth tab,
   but EventRail's "Admin & setup" sheet renders the same .more-sheet markup at ≥769px, which is
   what stops any admin destination becoming rail-only. Check that caller before deleting them. */
.bottom-nav,
.bottom-nav-scrim {
    display: none;
}

.more-section {
    margin-bottom: 0.75rem;
}

.more-section:last-child {
    margin-bottom: 0;
}

/* Moment alerts in the account panel (MomentAlertsCard's second host). The panel's own framing
   moved to .acc-block--alerts in 24-account.css; what stays here is the one thing that isn't
   about the frame — an event name is longer than "Appearance" and has to ellipsise. */
.account-sheet-alerts .set-card__label {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.more-section-header {
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--gray-500);
    padding: 0.5rem 0 0.25rem;
}

.more-link {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    min-height: 44px;
    padding: 0.6rem 0.25rem;
    color: var(--text);
    font-weight: 600;
    text-decoration: none;
    border-bottom: 1px solid var(--surface-2);
}

.more-link:last-child {
    border-bottom: none;
}

.more-link.active {
    background: var(--gray-100);
}

.more-link .material-symbols-outlined {
    font-size: 20px;
    color: var(--gray-500);
}

@media (max-width: 768px) {
    /* The bottom bar is the phone's primary nav. On event routes .main-nav isn't rendered at
       all (NavMenu's RailMode — the desktop rail replaces it); this rule still covers any
       surface that mounts NavMenu without a rail. Admin lives in the rail's sheet either way. */
    .main-nav {
        display: none;
    }
}

/* ===== Main Content ===== */
main {
    padding: 1rem;
}

@media (max-width: 768px) {
    main {
        /* Horizontal padding stays at 1rem so page content lines up with the masthead,
           whose own inner gutter is --space-4 at this width. Only the vertical padding
           is tightened on phones. */
        padding: 0.5rem 1rem;
        /* Reserve room so the FLOATING bottom bar never covers the last rows of page content.
           69px of pane + the 14px it sits clear of the edge + the home-indicator inset. It was
           56px flat while the bar was an edge-to-edge strip; the pane is taller AND inset, so
           both numbers have to move together or the last row hides under it. */
        padding-bottom: calc(83px + env(safe-area-inset-bottom) + 0.75rem);
    }
}

/* ===== Shared Table Styles ===== */
.table-responsive {
    overflow-x: auto;
    position: relative;
}

.data-table {
    width: 100%;
    border-collapse: collapse;
    margin-top: var(--space-3);
    font-size: 0.75rem;
    border-style: none;
    margin-bottom: 1.5rem;
}

.data-table th {
    padding: var(--space-2);
    text-align: center;
    font-weight: bold;
    color: var(--gray-500);
    text-transform: uppercase;
    background-color: var(--surface);
    border-top: none;
    border-left: none;
    border-right: none;
    border-bottom: 2px solid var(--text);
}

.data-table th.sortable {
    cursor: pointer;
    user-select: none;
}

.data-table th.sortable:hover {
    background-color: var(--gray-100);
}

.data-table td {
    padding: var(--space-2);
    text-align: center;
    border-top: none;
    border-left: none;
    border-right: none;
    border-bottom: 1px solid var(--gray-350);
}

.data-table thead th {
    position: sticky;
    top: 0;
    z-index: 10;
    background-color: var(--surface);
}

.data-table tfoot td {
    font-weight: bold;
    border-top: 2px solid var(--text);
    border-bottom: none;
}

.data-table .text-left {
    text-align: left;
}

.data-table .text-right {
    text-align: right;
}

.data-table .player-row {
    cursor: pointer;
    transition: background-color 0.2s;
}

.data-table .player-row:hover {
    background-color: var(--gray-100);
}

/* Pending field rows (player grouped into the upcoming round but not yet teed off):
   dimmed slightly so the ranked field reads first, with the tee time emphasized. */
.data-table .player-row.pending-row {
    color: #777;
}

.data-table .player-row.pending-row .tee-time-cell {
    color: #1565c0;
    font-weight: 600;
    white-space: nowrap;
}

/* "Next tee time" note under a ranked player's name (mid-trip). */
.tee-time-note {
    font-size: 0.78rem;
    margin-top: 2px;
    white-space: nowrap;
}

/* ===== Score Coloring =====
   Traditional scorecard convention: under-par is red (birdies/eagles draw the eye),
   over-par is plain text. Applied app-wide — leaderboard, scorecard +/- columns,
   skins detail, etc. Even-par gets a muted green so a score of "E" still reads as
   "even" rather than blending with par. */
.under-par {
    color: #dc3545;
}

.even-par {
    color: var(--text);
}

.over-par {
    color: inherit;
}

/* Small over/under badge that sits next to the gross score in a single cell, used
   by the team / scramble results tables. Renders as "38 +1" with the +/- inheriting
   the colour from the score-class (under-par / even-par / over-par) applied by the
   page. Sized below the main score so the score still reads first on a narrow row. */
.score-ou-badge {
    display: inline-block;
    margin-left: 0.25rem;
    font-size: 0.85em;
    font-weight: 600;
    color: inherit;
}

.has-money {
    font-weight: bold;
}

/* ===== Position Arrows ===== */
.arrow {
    display: inline-flex;
    align-items: center;
}

.arrow.up {
    color: green;
}

.arrow.down {
    color: red;
}

.arrow .material-symbols-outlined {
    font-size: 0.8rem;
    font-weight: 600;
}

/* ===== Status Badges ===== */
.status-badge {
    display: inline-block;
    padding: 0.2rem 0.5rem;
    border-radius: 3px;
    font-size: 0.75rem;
    font-weight: 600;
    color: white;
}

.status-badge.active {
    background-color: var(--color-accent);
}

.status-badge.setup {
    background-color: #17a2b8;
}

.status-badge.finished {
    background-color: #ffc107;
    color: var(--text);
}

.status-badge.archived,
.status-badge.default {
    background-color: var(--slate-500);
}

.status-badge.in-progress {
    background-color: #dc3545;
}

.status-badge.scheduled {
    background-color: var(--slate-500);
}

.status-badge.inprogress {
    background-color: #dc3545;
}

/* `.calc-done` / `.calc-pending` are gone with the Results pane's Category / Status / Action
   table. The state is `.set-task` now — a WORD immediately left of the button, and for a game the
   round can't run, a lock pill naming the blocker. An italic "Pending" cell could never say why. */

/* ===== Round Pills ===== */
.round-pills {
    margin-bottom: 1.5rem;
}

.round-pills ul {
    display: flex;
    list-style: none;
    padding: 0;
    margin: 0;
    flex-wrap: wrap;
    gap: 0.5rem;
}

.round-pills li {
    padding: 0.4rem 1rem;
    border-radius: 1rem;
    cursor: pointer;
    font-size: 0.875rem;
    font-weight: 600;
    border: 1px solid var(--gray-350);
    transition: all 0.2s ease;
}

.round-pills li.active {
    background-color: var(--navy);
    color: white;
    border-color: var(--navy);
}

.round-pills li:hover:not(.active) {
    background-color: var(--gray-100);
    border-color: var(--gray-450);
}

@media (max-width: 768px) {
    .round-pills li {
        padding: 0.3rem 0.8rem;
        font-size: 0.8rem;
    }
}

/* ===== Auth & Form Styles ===== */
.auth-container {
    max-width: 400px;
    margin: 3rem auto;
    padding: 2rem;
}

.auth-card {
    background-color: var(--gray-150);
    border-radius: 8px;
    padding: 2rem;
    box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}

.auth-card h2 {
    text-align: center;
    margin-bottom: 1.5rem;
    font-size: 1.5rem;
}

.form-group {
    margin-bottom: 1rem;
}

.form-group label {
    display: block;
    margin-bottom: 0.25rem;
    font-size: 0.85rem;
    color: var(--gray-650);
    text-transform: uppercase;
}

.form-group input,
.form-group textarea,
.form-group select {
    width: 100%;
    padding: 0.6rem 0.75rem;
    border: 1px solid var(--gray-350);
    border-radius: 4px;
    font-size: 0.95rem;
    font-family: inherit;
    background: var(--surface);
    color: var(--text);
    transition: border-color 0.2s;
}

.form-group input:focus,
.form-group textarea:focus,
.form-group select:focus {
    outline: none;
    border-color: var(--navy);
}

.btn {
    display: inline-block;
    padding: 0.6rem 1.25rem;
    border: none;
    border-radius: 4px;
    font-size: 0.95rem;
    font-weight: 600;
    font-family: inherit;
    cursor: pointer;
    transition: background-color 0.2s, opacity 0.2s;
    text-align: center;
    text-decoration: none;
}

.btn:disabled {
    opacity: 0.6;
    cursor: not-allowed;
}

.btn-primary {
    background-color: var(--navy);
    color: white;
    width: 100%;
}

.btn-primary:hover:not(:disabled) {
    background-color: var(--navy-dark);
}

/* The green CTA. Distinct from .btn-primary (navy): green is reserved for the one primary
   action on a screen, which is why nav ink is never green. Ink is --white, not a literal
   #fff — --green-500 brightens to #3ad160 in dark mode, too light to carry white text. */
.btn-accent {
    background-color: var(--color-accent);
    /* --color-accent brightens to #3ad160 in dark, which is too light to carry white text at
       0.9rem/600 — --on-hue flips to near-black there. Same reason as the status stepper. */
    color: var(--on-hue);
}

.btn-accent:hover:not(:disabled) {
    background-color: color-mix(in srgb, var(--color-accent) 85%, black);
}

.btn-outline {
    background: transparent;
    border: 1px solid var(--navy);
    color: var(--text);
}

.btn-outline:hover:not(:disabled) {
    background-color: var(--gray-100);
}

.btn-small {
    padding: 0.3rem 0.75rem;
    font-size: 0.8rem;
}

.form-footer {
    text-align: center;
    margin-top: 1rem;
    font-size: 0.9rem;
    font-weight: 400;
}

.form-footer a {
    color: var(--text);
    font-weight: 600;
    text-decoration: underline;
}

.form-error {
    color: #dc3545;
    font-size: 0.85rem;
    margin-top: 0.5rem;
}

.form-info {
    background: #fffbea;
    border: 1px solid #f0d35a;
    color: #7a5c00;
    font-size: 0.9rem;
    font-weight: 600;
    padding: 0.6rem 0.75rem;
    border-radius: 6px;
    margin-bottom: 1rem;
}

.form-hint {
    color: var(--slate-500);
    font-size: 0.85rem;
    margin: 0.5rem 0 0;
}

.form-hint a {
    color: var(--text);
    text-decoration: underline;
}

/* Consequence callout inside a destructive confirm — heavier than .form-hint, because the
   point is that the reader should stop and take it in before clicking through. */
.form-warning {
    margin: var(--space-3) 0 0;
    padding: var(--space-3);
    border-left: 3px solid var(--warning);
    border-radius: var(--radius-sm);
    background: var(--surface-subtle);
    color: var(--text);
    font-size: 0.85rem;
    line-height: 1.45;
}

.scoring-mode-badge {
    display: inline-block;
    padding: 0.2rem 0.55rem;
    border-radius: 12px;
    font-size: 0.75rem;
    font-weight: 600;
    line-height: 1.4;
    letter-spacing: 0.02em;
    margin-left: 0.75rem;
    vertical-align: middle;
}

.scoring-mode-gross {
    background: var(--surface-2);
    color: var(--text);
}

.scoring-mode-net {
    background: #e3f2fd;
    color: #0d47a1;
}

/* Compact variant for the per-round Net column header — tighter padding and a small
   left margin so it sits flush next to the "R1" label. */
.net-column-pill {
    margin-left: 0.35rem;
    padding: 0.1rem 0.4rem;
    font-size: 0.7rem;
}

.checkbox-group {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 1rem;
}

.checkbox-group input[type="checkbox"] {
    width: auto;
}

.checkbox-group label {
    margin-bottom: 0;
    text-transform: none;
    font-size: 0.95rem;
    color: var(--text);
}

/* Touch-friendly toggle switch — a mobile-first replacement for .checkbox-group on settings
   forms. The whole row is the tap target (the <label> wraps everything); the native checkbox
   is visually hidden but still drives state, keyboard, and focus, so binding/a11y are intact. */
.switch-field {
    display: flex;
    align-items: center;
    gap: 1rem;
    min-height: 44px;
    margin-bottom: 1rem;
    cursor: pointer;
}

.switch-field__label {
    flex: 1;
    font-size: 0.95rem;
    color: var(--text);
}

/* Hide the native checkbox without dropping it from the a11y tree / tab order. */
.switch-field__input {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    margin: 0;
    pointer-events: none;
}

/* 51×31 with a 27px knob — the iOS scale the settings redesign standardised on (.set-switch in
   07-settings.css). The two were 1px apart for no reason, and the off-track was a hardcoded
   #cfd4da that never re-themed; both now read from tokens. */
.switch-field__track {
    position: relative;
    flex: 0 0 auto;
    width: 51px;
    height: 31px;
    border-radius: var(--radius-pill);
    background: color-mix(in srgb, var(--text) 14%, transparent);
    transition: background 0.2s ease;
}

.switch-field__track::after {
    content: "";
    position: absolute;
    top: 2px;
    left: 2px;
    width: 27px;
    height: 27px;
    border-radius: 50%;
    background: var(--switch-knob-off);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);
    transition: transform 0.2s ease;
}

.switch-field__input:checked ~ .switch-field__track {
    background: var(--color-accent);
}

.switch-field__input:checked ~ .switch-field__track::after {
    transform: translateX(20px);
}

.switch-field__input:focus-visible ~ .switch-field__track {
    outline: 2px solid var(--color-accent);
    outline-offset: 2px;
}

.switch-field__input:disabled ~ .switch-field__track {
    opacity: 0.5;
}

/* Inline auto-save feedback next to the "Menu tabs" settings header. */
.menu-tabs-status {
    margin-left: 0.6rem;
    font-size: 0.8rem;
    font-weight: 400;
    color: #8a9298;
}

.menu-tabs-status--saved {
    color: var(--color-accent);
}

/* ===== Event List =====
   `.event-grid`, `.event-row*` and `.event-chip` are GONE, along with EventListCard itself
   (design_handoff_account_surfaces). My events is one card per account of `.set-row` events now,
   with the live event pinned above as its own card — see `24-account.css`. What survives here is
   `.inline-spinner`, which the tapped row still uses, plus the hero and empty-state blocks below,
   which other screens render. */

/* Small spinner shown in place of the chevron on the tapped card (reuses @keyframes spin). */
.inline-spinner {
    display: inline-block;
    width: 20px;
    height: 20px;
    border: 2.5px solid rgba(44, 62, 80, 0.18);
    border-left-color: var(--navy);
    border-radius: 50%;
    animation: spin 0.8s linear infinite;
}

/* ===== Player Cards ===== */
/* NOTE: currently unused in markup — kept + tokenized rather than deleted.
   If revived, prefer `.grid-cards .grid-cards--narrow` in markup and drop this. */
.player-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: var(--space-4);
    margin-top: var(--space-4);
}

.player-card {
    background-color: var(--gray-150);
    border-radius: 8px;
    padding: 1rem;
    display: flex;
    align-items: center;
    gap: 0.75rem;
}

.player-avatar {
    width: 44px;
    height: 44px;
    border-radius: 50%;
    background-color: var(--navy);
    color: white;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.1rem;
    font-weight: 600;
    flex-shrink: 0;
}

.player-card .player-info {
    flex: 1;
}

.player-card .player-info .name {
    font-size: 1rem;
    font-weight: 600;
}

.player-card .player-info .role {
    font-size: 0.8rem;
    color: var(--gray-650);
    font-weight: 400;
}

/* ===== Hero / Landing ===== */
.hero {
    text-align: center;
    padding: 4rem 2rem;
}

.hero h1 {
    font-size: 2.5rem;
    margin-bottom: 0.5rem;
    color: var(--text);
}

.hero p {
    font-size: 1.2rem;
    color: var(--gray-650);
    margin-bottom: 2rem;
    font-weight: 400;
}

.hero-buttons {
    display: flex;
    gap: 1rem;
    justify-content: center;
}

.hero-buttons .btn {
    width: auto;
    padding: 0.75rem 2rem;
    font-size: 1rem;
}

/* ===== Section Headers ===== */
.page-title {
    font-size: 1.5rem;
    font-weight: 600;
    margin-bottom: 1rem;
    text-align: left;
}

/* ===== Empty State ===== */
.empty-state {
    padding: 2rem;
    text-align: center;
    color: var(--gray-650);
    font-style: italic;
    font-weight: 400;
}

/* ===== Loading Spinner ===== */
.loading-container {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 2rem;
    text-align: center;
}

.loading-spinner {
    border: 4px solid rgba(0, 0, 0, 0.1);
    width: 36px;
    height: 36px;
    border-radius: 50%;
    border-left-color: var(--navy);
    animation: spin 1s linear infinite;
    margin-bottom: 1rem;
}

@keyframes spin {
    0% { transform: rotate(0deg); }
    100% { transform: rotate(360deg); }
}

/* ===== Toasts (ELEVATION-PLAN §4.4) ===== */
/* Bottom-anchored, safe-area aware stack rendered by <ToastHost> (mounted once in MainLayout).
   Above every other layer (modals ~221, paywall ~2325) so a "Saved"/"Couldn't reach server"
   confirmation is never hidden behind a sheet. */
.toast-host {
    position: fixed;
    left: 0;
    right: 0;
    bottom: calc(env(safe-area-inset-bottom, 0px) + var(--space-4));
    z-index: 2500;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-2);
    padding: 0 var(--space-4);
    pointer-events: none;   /* the container ignores taps; individual toasts re-enable */
}

.toast {
    pointer-events: auto;
    display: flex;
    align-items: center;
    gap: var(--space-2);
    width: 100%;
    max-width: 420px;
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius-md);
    background: var(--surface-inverse);
    color: var(--on-solid);
    box-shadow: var(--shadow-lg);
    border-left: 4px solid var(--info);
    cursor: pointer;
    animation: toast-in 220ms cubic-bezier(0.16, 1, 0.3, 1);
}

.toast--success { border-left-color: var(--success); }
.toast--error   { border-left-color: var(--danger); }
.toast--warning { border-left-color: var(--warning); }
.toast--info    { border-left-color: var(--info); }

.toast__icon {
    font-size: 20px;
    flex-shrink: 0;
}
.toast--success .toast__icon { color: var(--success); }
.toast--error .toast__icon   { color: var(--danger); }
.toast--warning .toast__icon { color: var(--warning); }
.toast--info .toast__icon    { color: var(--info); }

.toast__message {
    flex: 1;
    font-size: 0.9rem;
    line-height: 1.3;
}

.toast__close {
    flex-shrink: 0;
    background: none;
    border: none;
    color: var(--on-solid);
    opacity: 0.6;
    font-size: 1.25rem;
    line-height: 1;
    padding: 0 var(--space-1);
    cursor: pointer;
}
.toast__close:hover { opacity: 1; }

/* Undo toast (ROUND-PAGE-PLAN.md Phase 5, tier 1). The action label is the whole confirmation for a
   reversible, private change, so it gets accent ink and real weight rather than the muted × it sits
   in place of. The countdown bar is the only honest way to say "this offer expires". */
.toast--action { position: relative; overflow: hidden; }

.toast__action {
    flex-shrink: 0;
    background: none;
    border: none;
    padding: var(--space-1) 0 var(--space-1) var(--space-2);
    color: var(--color-accent);
    font-family: inherit;
    font-size: 0.85rem;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.04em;
    text-transform: uppercase;
    cursor: pointer;
}

.toast__countdown {
    position: absolute;
    left: 0;
    bottom: 0;
    height: 3px;
    width: 100%;
    transform-origin: left center;
    background: color-mix(in srgb, var(--on-solid) 45%, transparent);
    animation-name: toast-countdown;
    animation-timing-function: linear;
    animation-fill-mode: forwards;
}

/* Pause on hover: the bar and the service's own timer stop together (ToastHost calls Pause/Resume),
   so the visual never disagrees with when the toast actually goes. */
.toast--action:hover .toast__countdown { animation-play-state: paused; }

@keyframes toast-countdown {
    from { transform: scaleX(1); }
    to   { transform: scaleX(0); }
}

@keyframes toast-in {
    from { opacity: 0; transform: translateY(12px) scale(0.98); }
    to   { opacity: 1; transform: translateY(0) scale(1); }
}

@media (prefers-reduced-motion: reduce) {
    .toast { animation: none; }
}

/* ===== Skeleton screens (ELEVATION-PLAN §4.4) ===== */
/* Content-shaped placeholders shown while the top read pages load, instead of a bare spinner —
   hides the WASM cold start behind a layout the eye recognizes. Rendered by <Skeleton>. Colors
   ride the neutral tokens so dark mode re-themes for free. */
.skeleton {
    background: var(--surface-subtle);
    background-image: linear-gradient(
        90deg,
        var(--surface-subtle) 25%,
        var(--surface-2) 37%,
        var(--surface-subtle) 63%);
    background-size: 400% 100%;
    animation: skeleton-shimmer 1.4s ease infinite;
    border-radius: var(--radius-sm);
}

.skeleton-block {
    height: 1rem;
    margin-bottom: var(--space-2);
}

/* A skeleton "row" that mirrors the leaderboard/list line: a rank/avatar chip, a flexible
   name line, and a trailing value. */
.skeleton-row {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3) 0;
    border-bottom: 1px solid var(--border);
}
.skeleton-row__chip { width: 28px; height: 28px; border-radius: var(--radius-pill); flex-shrink: 0; }
.skeleton-row__main { flex: 1; height: 0.9rem; max-width: 55%; }
.skeleton-row__val  { width: 3rem; height: 0.9rem; flex-shrink: 0; }

/* A skeleton card for dashboard/stat layouts. */
.skeleton-card {
    padding: var(--space-4);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    margin-bottom: var(--space-3);
}
.skeleton-card__title { width: 40%; height: 1.1rem; margin-bottom: var(--space-3); }

@keyframes skeleton-shimmer {
    0%   { background-position: 100% 50%; }
    100% { background-position: 0 50%; }
}

@media (prefers-reduced-motion: reduce) {
    .skeleton { animation: none; }
}

/* ===== Cold-start skeletons (handoffs/design_handoff_cold_start) =====
   The shapes the three cold-start destinations stand in for: the leaderboard, My events, and — in
   12-live-scoring.css, on that screen's own dark ground — the scoring card.

   THE RULE IS "REAL CHROME, SHIMMERING CONTENT". Draw everything that does not need a fetch; shimmer
   only what does. The card, its hairline, its radius and its shadow all exist regardless of data, so
   the shimmer sits INSIDE a finished container rather than pretending to be one. Greying out the
   brand, the tab bar and the card makes the app look less ready than it is.

   Two flat weights sit beside .skeleton, and which one a block gets is a statement:
     · SHIMMER — one value, arriving shortly. A name, a figure, a title.
     · .skel-flat — the count is unknown, not the value. The board's column heads, the week
       numerals, a state pill. Shimmering these promises an arrival that may never come.
     · .skel-faint — the last row of a list, so it fades out rather than ending abruptly. */

.skel-flat {
    background: var(--surface-2);
    border-radius: var(--radius-sm);
}

.skel-faint {
    background: var(--surface-subtle);
    border-radius: var(--radius-sm);
}

/* --- The leaderboard card ------------------------------------------------
   Geometry is the real board's, not an approximation: 14px/20px rows and a 30px position tile, so
   the swap to content moves nothing below it. */

.skel-board__head {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 13px 20px;
    border-bottom: 1px solid var(--hairline);
}
.skel-board__head > span { height: 9px; }
.skel-board__headend { margin-left: auto; }

.skel-board__row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 14px 20px;
    border-bottom: 1px solid var(--hairline-soft);
}
.skel-board__row:last-child { border-bottom: none; }

.skel-board__tile { flex: none; width: 30px; height: 30px; border-radius: 9px; }
.skel-board__body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 6px; }
.skel-board__name { height: 12px; }
.skel-board__sub  { height: 9px; }
.skel-board__fig  { flex: none; width: 30px; height: 12px; }

/* --- My events -----------------------------------------------------------
   The head is real (see MyEventsSkeleton) — only the count sentence and the rows are placeholders.
   The pill is a picture of the control, so it must not read as tappable. */

.skel-cta { pointer-events: none; }

.skel-purpose { height: 11px; width: 62%; margin-top: 9px; }

.skel-acctlabel { height: 10px; width: 46%; margin: 14px 20px 8px; }

.skel-evrow {
    display: flex;
    align-items: center;
    gap: 16px;
    min-height: 62px;
    padding: 12px 20px;
    border-top: 1px solid var(--hairline-soft);
}
.skel-evrow__glyph { flex: none; width: 24px; height: 24px; border-radius: 7px; }
.skel-evrow__body  { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 7px; }
.skel-evrow__name  { height: 13px; }
.skel-evrow__cap   { height: 9px; }
.skel-evrow__pill  { flex: none; width: 52px; height: 18px; border-radius: var(--radius-pill); }

@media (max-width: 768px) {
    .skel-acctlabel { margin: 15px 16px 8px; }
    .skel-evrow { gap: 14px; padding: 11px 16px; min-height: 60px; }
    .skel-board__head { padding: 12px 16px; }
    .skel-board__row  { padding: 13px 16px; }
}

/* --- The setting-card family ---------------------------------------------
   The shape every settings pane, account pane and round pane loads into, rendered by
   <SetPageSkeleton>. It is the widest-reach skeleton in the app — around forty screens.

   .skel-setcard and .skel-setrow are aliased into .set-card / .set-row over in 07-settings.css, so
   the card's border, radius, shadow and the row's 62px/14px/20px geometry have ONE definition and
   the swap to content moves nothing. They are separate class NAMES on purpose — see the note there,
   and .skel-board's against .board-card. Only the row's internals are declared here. */

.skel-setpage { display: flex; flex-direction: column; gap: 16px; }

.skel-setcard__label {
    display: block;
    height: 10px;
    width: 38%;
    max-width: 150px;
    margin: 16px 20px 8px;
}

/* The row itself carries .set-row, so its padding, gap and min-height — at BOTH widths — come from
   07-settings.css and are never restated here. Only the internals are declared. */
.skel-setrow__body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 8px; }
.skel-setrow__name { display: block; max-width: 100%; height: 12px; }
.skel-setrow__cap  { display: block; height: 9px; }
/* The right-hand cell never grows — a .set-row's control is flex:none, and a stretching placeholder
   would promise a control wider than the one that lands. */
.skel-setrow__ctl { flex: none; height: 24px; border-radius: var(--radius-pill); }

@media (max-width: 768px) {
    .skel-setcard__label { margin: 15px 16px 8px; }
}

/* The chrome-suppressed <main> a cold start heading for the scoring card renders through. The card
   owns the whole viewport, so main's usual gutters would inset a full-bleed screen. */
.cold-start-bare { padding: 0; }

/* --- The slow-web line ---------------------------------------------------
   Three seconds in, and only then. Full-bleed against main's 1rem gutter so it reads as the bottom
   edge of the chrome above rather than as an element of the page. It NEVER carries a number, even
   though the boot publishes one: a percentage invites you to watch it. */

.skel-slowline {
    position: relative;
    height: 2px;
    margin: 0 -1rem var(--space-3);
    overflow: hidden;
    background: var(--metal-wash-16);
}

.skel-slowline::after {
    content: "";
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    width: 40%;
    background: linear-gradient(90deg, transparent, var(--metal), transparent);
    animation: skel-crawl 1.6s linear infinite;
}

@keyframes skel-crawl {
    from { transform: translateX(-60%); }
    to   { transform: translateX(260%); }
}

@media (prefers-reduced-motion: reduce) {
    /* A static bar rather than a crawl — still "something is happening", no motion. */
    .skel-slowline::after {
        width: 30%;
        animation: none;
        background: var(--metal);
    }
}

/* Leaderboard position-change flash (ELEVATION-PLAN §4.4). Applied by leaderboard-motion.js to
   a .player-row whose rank changed on the last refresh; the tint fades out over ~1.2s. Motion is
   gated in JS (the class is never added under prefers-reduced-motion), so no media guard needed. */
@keyframes row-moved-flash {
    0%   { background-color: var(--surface-selected); }
    100% { background-color: transparent; }
}
.player-row.row-moved > td {
    animation: row-moved-flash 1.2s ease-out;
}

/* ===== Settings / Detail Panel ===== */
.detail-panel {
    background-color: var(--gray-150);
    border-radius: 8px;
    padding: 1.5rem;
    max-width: 500px;
}

.detail-panel h3 {
    margin-bottom: 1rem;
    font-size: 1.2rem;
}

.detail-row {
    display: flex;
    justify-content: space-between;
    padding: 0.4rem 0;
    border-bottom: 1px solid var(--gray-350);
    font-size: 0.9rem;
}

.detail-row:last-child {
    border-bottom: none;
}

.detail-row .label {
    color: var(--gray-650);
    font-weight: 400;
}

.detail-row .value {
    font-weight: 600;
}

/* `.create-btn` is GONE. Its only caller was Home's "+ New League / Trip", which the
   account-surfaces redesign replaced with `.acc-cta` — an accent pill in the page head at
   desktop width and a full-width one at the foot of the list on a phone, where the thumb is. */

/* ===== Settings Page ===== */
.settings-container {
    max-width: 500px;
}

/* The loading shape's wrapper on the screens that use .settings-container for their real content.
   A SEPARATE CLASS on purpose, the call .skel-board makes against .board-card: nine E2E tests
   (CourseSetupTests, TenantCourseSetupTests, RepeatUsageTests, WagerConfigTests) wait on
   `.settings-container` to mean "the page loaded", and a skeleton answering to it would let them
   proceed against shimmer. Width comes from the page, same as the real container's does. */
.skel-container {
    max-width: 500px;
}

/* A container hosted as a round-hub pane: the pane column already governs the width, and the
   500px above would squeeze a wide layout (the Wagers pane's six-column pot grid) into a third
   of the space it has. */
.settings-container--pane {
    max-width: none;
}

.settings-card {
    background-color: var(--gray-150);
    border-radius: 8px;
    padding: 1.5rem;
    margin-bottom: 1.5rem;
}

.settings-card h3 {
    font-size: 1.1rem;
    margin-bottom: 1rem;
    padding-bottom: 0.5rem;
    border-bottom: 1px solid var(--gray-350);
}

.settings-section {
    margin-bottom: 1.5rem;
}

.settings-section h3 {
    font-size: 1rem;
    margin-bottom: 0.75rem;
    padding-bottom: 0.4rem;
    border-bottom: 1px solid var(--gray-350);
}

.status-row {
    display: flex;
    align-items: center;
    gap: 1rem;
    margin-bottom: 0.75rem;
}

/* .status-pipeline / .pipeline-step are gone: four identical grey chips said nothing about which
   way the lifecycle moves. Event Settings → Status now draws .set-pipeline (below). */

.form-success {
    color: var(--color-accent);
    font-size: 0.85rem;
    margin-bottom: 0.75rem;
    font-weight: 600;
}

.clone-description {
    font-size: 0.9rem;
    color: var(--gray-650);
    margin-bottom: 0.75rem;
}

/* .danger-zone / .danger-text are gone with the inline two-step on /settings/danger: that page is
   a --danger-bordered .set-card carrying only the trigger, and the confirming is a ConfirmSheet. */

.danger-actions {
    display: flex;
    gap: 0.75rem;
    align-items: center;
}

.btn-danger {
    /* Tokens, not a raw hex + the white keyword: this is the tier-3 confirm button now, and on a
       dark page a stuck #dc3545 reads muddier than the --danger text sitting beside it. */
    background-color: var(--danger);
    color: var(--on-hue);
}

.btn-danger:hover:not(:disabled) {
    /* Darken-on-hover relative to whatever --danger currently is, rather than a fixed #c82333 that
       would go *backwards* against the brightened dark-mode red. */
    background-color: color-mix(in srgb, var(--danger) 85%, #000);
}

/* ===== Settings: drill-in hub + detail sub-pages =====
   Native-app "grouped list" pattern. The hub is a scannable list of labeled rows;
   each row links to its own detail page (real routes, so browser/hardware back
   works). Detail pages auto-save and show an inline status via .settings-save-status.
   Everything is built on semantic tokens so dark mode re-themes for free; the row
   icon tints are decorative (like the score-state / alert colors) and stay fixed. */
.settings-shell,
.settings-sub {
    max-width: 500px;
}

/* ── Two-pane master–detail (desktop) ──
   The rail (SettingsNav) + the detail pane live in one .settings-shell. On mobile it's a
   single centered column: sub-page shells show only the detail (rail hidden), the hub shell
   shows the rail AS the full-screen list (placeholder hidden) — i.e. exactly the drill-in we
   ship today. At ≥768px the shell becomes a grid with a persistent compact rail on the left
   and the routed detail on the right; the mobile markup is untouched, one breakpoint flips it. */
.settings-nav-title {
    font-size: 1.5rem;
    font-weight: var(--font-weight-semibold);
    margin-bottom: 1rem;
}
/* Mobile: sub-page shells hide the rail; the hub hides its desktop-only placeholder. */
.settings-shell:not(.settings-shell--hub) .settings-nav { display: none; }
.settings-detail--placeholder { display: none; }

.settings-placeholder {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    min-height: 320px;
    padding: var(--space-6);
    color: var(--text-muted);
    background: var(--surface-subtle);
    border: 1px dashed var(--border);
    border-radius: var(--radius-lg);
}
.settings-placeholder .material-symbols-outlined {
    font-size: 40px;
    opacity: 0.5;
    margin-bottom: var(--space-2);
}
.settings-placeholder-title {
    font-size: var(--text-lg);
    font-weight: var(--font-weight-semibold);
    color: var(--text);
    margin: 0 0 var(--space-1);
}
.settings-placeholder-sub {
    font-size: var(--text-sm);
    margin: 0;
}

@media (min-width: 768px) {
    .settings-shell {
        max-width: 880px;
        display: grid;
        grid-template-columns: minmax(240px, 264px) 1fr;
        gap: var(--space-6);
        align-items: start;
    }
    .settings-detail--placeholder { display: block; }
    /* Re-show the rail on the detail sub-pages: the mobile base rule hides it (full-screen
       detail on a phone), but on desktop the two-pane layout needs the persistent rail on
       every sub-page too, not just the hub — otherwise clicking a row drops back to a single
       detail column with no way back except the browser. */
    .settings-shell:not(.settings-shell--hub) .settings-nav { display: block; }
    /* The hub footnote spans the full width under both panes. */
    .settings-hub-foot { grid-column: 1 / -1; }

    /* ── Rail (Wagers pane design handoff) ──
       At this width .settings-nav stops being the hub's informative grouped list and becomes
       navigation, so it sheds the things that made it informative: the card frame, the tinted
       icon tile, the description, the chevron. What's left is a borderless 10px-radius row —
       19px glyph, 14px label — with the active route carrying an accent wash and an inset accent
       bar. The full rows still render below this breakpoint, where the rail IS the hub list.
       Every rule here is scoped to .settings-nav so the hub page, the round page's own section
       rows and everything else built on .settings-row are untouched.

       Both rails share it: RoundNav and SettingsNav are the same markup by design. */
    .settings-nav {
        position: sticky;
        top: var(--space-4);
        display: flex;
        flex-direction: column;
        gap: 2px;
    }
    /* The rail's own header is a label for the list, not a page title competing with the detail
       pane's <h2> — so it drops to micro-caps like the eyebrows below it. */
    .settings-nav-title {
        font-size: 11px;
        font-weight: var(--font-weight-bold);
        letter-spacing: 0.1em;
        text-transform: uppercase;
        color: var(--text-quiet);
        margin: 0;
        padding: 0 var(--space-3) var(--space-2);
    }
    .settings-nav .settings-group {
        display: flex;
        flex-direction: column;
        gap: 2px;
        background: none;
        border: none;
        border-radius: 0;
        overflow: visible;
        margin-bottom: 0;
    }
    .settings-nav .settings-eyebrow {
        font-size: 11px;
        letter-spacing: 0.1em;
        color: var(--text-quiet);
        padding: 14px var(--space-3) 6px;
    }
    .settings-nav .settings-row-sub,
    .settings-nav .settings-row-chev,
    .settings-nav .settings-row-value { display: none; }
    /* The hub list's inter-row hairline belongs to a card; these rows have no card. */
    .settings-nav .settings-row + .settings-row::before { display: none; }
    .settings-nav .settings-row {
        gap: var(--space-3);
        padding: 9px var(--space-3);
        border-radius: 10px;
    }
    .settings-nav .settings-row:hover {
        background: color-mix(in srgb, var(--text) 5%, transparent);
    }
    /* The glyph is already bare everywhere (see .settings-row-icon); the rail only tightens it —
       no fixed column, because the rail has no inline values or chevrons to line up against. */
    .settings-nav .settings-row-icon { width: auto; }
    .settings-nav .settings-row-icon .material-symbols-outlined { font-size: 19px; }
    .settings-nav .settings-row-title {
        font-size: var(--text-sm);
        font-weight: var(--font-weight-medium);
    }
    .settings-nav .settings-row.is-active {
        background: color-mix(in srgb, var(--color-accent) 10%, transparent);
        box-shadow: inset 2px 0 0 var(--color-accent);
    }
    .settings-nav .settings-row.is-active .settings-row-icon { color: var(--color-accent); }
    .settings-nav .settings-row.is-active .settings-row-title {
        color: var(--color-accent);
        font-weight: var(--font-weight-semibold);
    }
    /* Detail pane fills its column; the whole bar goes. Its two jobs are both covered here:
       the rail navigates, so the back button is redundant, and the bar's title is the same
       string as the <h2> directly beneath it — on a phone that's fine (the bar is sticky
       chrome that survives scrolling), but side by side on one desktop screen it just reads
       as the word printed twice. */
    .settings-detail .settings-sub { max-width: none; }
    .settings-detail .app-bar { display: none; }
}

.settings-eyebrow {
    font-size: var(--text-xs);
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-muted);
    padding: var(--space-4) var(--space-2) var(--space-2);
}

.settings-group {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    overflow: hidden;
    margin-bottom: var(--space-2);
}
.settings-group--spaced { margin-top: var(--space-5); }

/* .settings-group--form / .settings-group--danger are gone: every Event Settings sub-page is
   built on .set-card now (below), and a padded group wrapping bare .form-groups was the
   "stack of form controls" that design replaced. */

/* .settings-fieldset / .settings-field / __caption / __title are GONE. They were the halfway
   house between the old stacked form and the row system, and their last caller — /rounds/{id}/setup
   — moved onto .set-card / .set-row with the round-pane refresh (design_handoff_rounds). Nothing
   references them now; a settings-shaped screen picks a row kind from the block below. */

/* Tappable hub row */
.settings-row {
    /* The icon column's width, declared here because the inter-row hairline below indents past it
       and the two must not drift apart (it was a hardcoded 30px matching the old tile). */
    --row-icon-w: 26px;
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    text-decoration: none;
    color: var(--text);
    position: relative;
    transition: background 0.12s ease;
}
.settings-row + .settings-row::before {
    content: "";
    position: absolute;
    top: 0;
    left: calc(var(--space-4) + var(--row-icon-w) + var(--space-3));
    right: 0;
    height: 1px;
    background: var(--border);
}
.settings-row:hover { background: var(--surface-subtle); }
.settings-row:active { background: var(--surface-subtle); }

/* A row that runs an action instead of navigating. A real <button> rather than an <a href="#">
   so keyboard and screen-reader semantics stay honest; these resets make it sit flush with the
   anchor rows around it. */
.settings-row--button {
    width: 100%;
    text-align: left;
    border: none;
    background: none;
    font: inherit;
    cursor: pointer;
}
.settings-row--button:disabled { opacity: 0.6; cursor: not-allowed; }

/* A bare glyph on the row's own ground — no tinted tile, at any width. Eight saturated squares
   down a list read as eight labels competing with the titles beside them; the icon is a landmark
   for the row, not a second name for it. Colour is reserved for the rows where it MEANS something:
   a danger row below, and the rail's active row. The width stays fixed so the titles still line up
   in a column even though the tile that used to set it is gone. */
.settings-row-icon {
    flex: none;
    width: var(--row-icon-w, 26px);
    display: grid;
    place-items: center;
    color: var(--ink-disabled);
}
.settings-row-icon .material-symbols-outlined { font-size: 21px; }

.settings-row-body { flex: 1; min-width: 0; }
.settings-row-title {
    display: block;
    font-size: 0.97rem;
    font-weight: var(--font-weight-medium);
}
.settings-row-sub {
    display: block;
    font-size: var(--text-xs);
    color: var(--text-muted);
    margin-top: 2px;
    line-height: 1.35;
}
.settings-row-value {
    flex: none;
    font-size: var(--text-sm);
    color: var(--text-muted);
}
.settings-row-chev {
    flex: none;
    color: var(--ink-disabled);
    font-size: 20px;
}
/* Danger is one of the two meanings the icon is still allowed to carry, so it applies at every
   width — the rail used to need its own copy of this and no longer does. The rail's active row is
   the other, and at (0,3,0) it still outranks this. */
.settings-row--danger .settings-row-title { color: var(--danger); }
.settings-row--danger .settings-row-icon { color: var(--danger); }

/* An action the server would currently refuse (ROUND-PAGE-PLAN.md Phase 5, tier 4). Greyed but
   still tappable and still present — opening it explains the block and offers the nearest
   alternative. This is deliberately NOT `disabled`: a row that can't be pressed and doesn't say why
   is what sends commissioners hunting for a feature they're sure existed. */
.settings-row--muted .settings-row-icon { opacity: 0.45; }
.settings-row--muted .settings-row-title { color: var(--text-muted); }

.settings-hub-foot {
    font-size: var(--text-xs);
    color: var(--text-muted);
    padding: var(--space-3) var(--space-2) 0;
    line-height: 1.5;
}

/* The decorative .si-* row-icon tints were retired: every grouped list is flat and uncoloured now,
   phone included, so a tint had nothing left to say. The markup still emits the class names (they
   ride a `tint` argument through the Row/Action helpers in SettingsNav, RoundNav, RoundPage,
   RoundConfig and ConfirmSheet) and they are now inert — adding a new one styles nothing. Strip
   the argument when one of those helpers is next touched. */

/* ===================================================================================
   Setting cards — the row system (design_handoff_settings, turns 1b + 1d)
   ===================================================================================
   A settings page is CARDS OF ROWS, not a stack of form controls. Every row is the same
   flex line — name + caption on the left, exactly one control on the right — and only the
   right-hand cell changes between the ten kinds. That is the durable part of this block:
   any settings-shaped screen (Account settings, notification preferences, Round Setup)
   picks from the kinds below and writes no layout of its own.

   Two things this replaces, both of which made the old pages read as a raw edit form:
     - the `eyebrow → .settings-group--form → external .settings-note` triplet, which is why
       the section label and the group description now live INSIDE the card;
     - `1px #ddd on the same white as the page`. The pane sits on --page-ground so
       --surface-raised cards read as elevated. Same elevation layer the Wagers pane uses.

   Only free text keeps a visible input box. Everything else states its current value and
   opens the picker it already opened — SheetSelect, Segmented, StepperField and ConfirmSheet
   are unchanged components here, re-sized through variants rather than re-implemented. */

/* ── The ground ──
   Breaks out of main's gutters so the ground is edge-to-edge rather than a 1000px slab with
   white either side; the padding puts them back inside it. The mobile bottom margin/padding
   pair mirrors main's own tab-bar reservation, so the ground paints behind it too. */
.settings-ground {
    background: var(--page-ground);
    margin: -1rem -1rem 0;
    padding: 1rem 1rem var(--space-6);
    min-height: 70vh;
}

/* Local ink values, not app tokens: ink on a TINT of a hue. In light mode the hue itself is
   too light on its own 10% wash (--color-accent lands ~3:1), so it darkens — this is the
   `#1e7c35 / #c02c39 / #8a5a00` column of the handoff's token table. In dark mode the hues are
   already brightened for a dark ground, so darkening them is exactly backwards and they revert. */
.set-page {
    --ink-on-accent-tint: color-mix(in srgb, var(--color-accent) 80%, #000);
    --ink-on-danger-tint: color-mix(in srgb, var(--danger) 80%, #000);
    --ink-on-warning-tint: color-mix(in srgb, var(--warning) 42%, #000);
    display: flex;
    flex-direction: column;
    gap: 16px;
}
:root[data-theme="dark"] .set-page {
    --ink-on-accent-tint: var(--color-accent);
    --ink-on-danger-tint: var(--danger);
    --ink-on-warning-tint: var(--warning);
}

/* The bar is flush chrome, so the head below it needs the gap (mirrors .app-bar + .settings-sub-head). */
.app-bar + .set-page { margin-top: var(--space-4); }

/* ── Page head ── replaces .settings-sub-head.
   Every page gets a one-line purpose sentence; today only Clone had an Intro. */
.set-head {
    display: flex;
    align-items: flex-start;
    gap: var(--space-4);
    padding: 2px var(--space-1) 0;
}
.set-head__body { flex: 1; min-width: 0; }
.set-head__title {
    margin: 0;
    font-size: 30px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.025em;
    line-height: 1.1;
}
.set-head__purpose {
    margin: 7px 0 0;
    max-width: 52ch;
    font-size: 14px;
    color: var(--text-muted);
    line-height: 1.5;
}

/* Save chip — the page's answer, in four states. The error state is a real button because it
   carries the retry: "Couldn't save" with no way to try again is a dead end on a flaky course
   connection, which is exactly when auto-save fails. */
.set-chip {
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 12px 6px 9px;
    border: none;
    border-radius: var(--radius-pill);
    background: var(--control-fill);
    color: var(--text-muted);
    font-family: inherit;
    font-size: 12.5px;
    font-weight: var(--font-weight-semibold);
    white-space: nowrap;
}
.set-chip .material-symbols-outlined { font-size: 16px; }
.set-chip.is-saved {
    background: color-mix(in srgb, var(--color-accent) 10%, transparent);
    color: var(--ink-on-accent-tint);
}
.set-chip.is-error {
    background: color-mix(in srgb, var(--danger) 10%, transparent);
    color: var(--ink-on-danger-tint);
    cursor: pointer;
}
.set-chip.is-error u { text-decoration: underline; }
.set-chip.is-editing {
    background: color-mix(in srgb, var(--warning) 14%, transparent);
    color: var(--ink-on-warning-tint);
}
.set-chip.is-saving .material-symbols-outlined {
    animation: set-spin 1.1s linear infinite;
}
@keyframes set-spin { to { transform: rotate(360deg); } }

/* ── .set-card — the container ── */
/* .skel-setcard is SetPageSkeleton's placeholder, sharing this card's chrome so the swap to content
   is ink appearing and nothing moving. A SEPARATE CLASS on purpose, the call .skel-board makes
   against .board-card: `.set-card` is what a dozen E2E tests scope their waits to, and a
   placeholder answering to it would let one proceed against shimmer. */
.set-card,
.skel-setcard {
    background: var(--surface-raised);
    border: 1px solid var(--hairline);
    border-radius: 16px;
    box-shadow: 0 1px 2px rgba(20, 26, 34, 0.04), 0 8px 24px rgba(20, 26, 34, 0.05);
    overflow: hidden;
}
.set-card--danger { border-color: color-mix(in srgb, var(--danger) 28%, transparent); }

.set-card__label {
    display: block;
    padding: 16px 20px 4px;
    font-size: 11px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-quiet);
}
.set-card__label--danger { color: var(--danger); }

/* What the GROUP affects. Per-row captions say what each control does; this says what they
   have in common ("Both apply to spectators too"). */
.set-card__desc {
    margin: 0;
    padding: 4px 20px 12px;
    max-width: 56ch;
    font-size: 12.5px;
    color: var(--text-muted);
    line-height: 1.5;
}
/* A card that opens with a description gets a divider before its first row; one that opens
   with the label alone does not — the label is part of the first row's block. */
.set-card__desc + .set-row { border-top: 1px solid var(--hairline-soft); }

/* Free-form content inside a card (the recap dial, the status pipeline, the skip-weeks table). */
.set-card__body { padding: 10px 20px 16px; }

/* Footer: a cross-link, a consequence line, or the card's ONE primary action. */
.set-card__foot {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: 12px 20px;
    border-top: 1px solid var(--hairline-soft);
    background: color-mix(in srgb, var(--text) 2%, transparent);
    font-size: 12.5px;
    color: var(--text-muted);
    line-height: 1.5;
}
.set-card__foot > .material-symbols-outlined { flex: none; font-size: 16px; color: var(--ink-disabled); }
.set-card__foot-text { flex: 1; min-width: 0; }
.set-card__foot-title {
    font-size: 14px;
    font-weight: var(--font-weight-semibold);
    color: var(--text);
}

/* ── .set-row — the one row ──
   Left cell absorbs the slack and wraps its caption; every control in the right cell is
   flex:none + nowrap, because they carry fixed heights and a wrapped label would overflow
   the control rather than growing it. */
.set-row,
.skel-setrow {
    display: flex;
    align-items: center;
    gap: 20px;
    padding: 14px 20px;
    min-height: 62px;
}
.set-row + .set-row,
.skel-setrow + .skel-setrow { border-top: 1px solid var(--hairline-soft); }

.set-row__body { flex: 1; min-width: 0; }
.set-row__name {
    font-size: 15px;
    font-weight: var(--font-weight-semibold);
    color: var(--text);
}
.set-row__caption {
    margin: 3px 0 0;
    font-size: 12.5px;
    color: var(--text-muted);
    line-height: 1.45;
}
.set-row__control {
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: 10px;
    white-space: nowrap;
}
/* A leading glyph matching the thing the row controls — what makes a list of eight bare switch
   labels scannable (Menu & tabs). Ink is --ink-disabled: the glyph is a landmark, not a name. */
.set-row__glyph {
    flex: none;
    width: 24px;
    display: grid;
    place-items: center;
    color: var(--ink-disabled);
}
.set-row__glyph .material-symbols-outlined { font-size: 20px; }

/* An indented sub-row (Require my approval under Let players claim): dependency is visible
   without a nested card. */
.set-row--sub {
    padding-left: 44px;
    background: color-mix(in srgb, var(--text) 2%, transparent);
}
/* A row that can't apply here (Standings on a trip). Shown, explained by its caption, and
   never removed — the list must not change length between event types. */
.set-row--muted { opacity: 0.55; }

/* The control needs the card's full width: a two-sentence caption under a segmented control,
   or a dial. The row spans instead of splitting. */
.set-row--stack {
    display: block;
    padding: 10px 20px 16px;
    min-height: 0;
}
.set-row--stack .set-row__head {
    display: flex;
    align-items: center;
    gap: var(--space-4);
}
.set-row--stack .set-row__head .set-row__name { flex: 1; min-width: 0; }
.set-row--stack .set-row__caption { margin-top: 9px; line-height: 1.5; }

/* --stackctl: the head stacks too, so the control gets its own line.
   .set-row__head is a flex row whose control is `flex: none` and whose name absorbs the slack —
   right for a switch or a date pill, wrong for a three-segment Segmented, which measures ~280px
   at `padding: 7px 15px` and 13.5px semibold. In a narrow column (the round hub's side column is
   ~230px of content box) the name is squeezed below its min-content width and its words render
   UNDERNEATH the control. Question on one line, control beneath, caption under that — and the
   segments go `flex: 1` so three options read as equal thirds rather than three different widths.
   Also the better shape at 390px, where the same row was tight. */
.set-row--stack.set-row--stackctl .set-row__head { display: block; }
.set-row--stack.set-row--stackctl .segmented--set {
    display: flex;
    width: 100%;
    max-width: 400px;
    margin-top: 12px;
}
.set-row--stack.set-row--stackctl .segmented--set .segmented__opt {
    flex: 1;
    min-width: 0;
    padding: 9px 8px;
}

/* Press states. The row is not the control — focus and clicks land on the switch / button /
   field — so the wash is driven off the control's own :hover/:active rather than making a
   non-interactive row look tappable. Switch rows get none: the switch is the target. */
.set-row:has(.set-value:hover),
.set-row:has(.set-date:hover),
.set-row:has(.set-btn:hover) { background: color-mix(in srgb, var(--text) 3%, transparent); }
.set-row:has(.set-value:active),
.set-row:has(.set-date:active),
.set-row:has(.set-btn:active) { background: color-mix(in srgb, var(--text) 5%, transparent); }

/* Focus ring, shared by every control in a row's right-hand cell. */
.set-page :is(.set-field, .set-btn, .set-date, .set-copyfield, .set-affix__input, .set-slider__input):focus-visible {
    outline: none;
    border-color: color-mix(in srgb, var(--color-accent) 55%, transparent);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-accent) 13%, transparent);
}
.set-page .set-field:focus-visible,
.set-page .set-affix__input:focus-visible {
    background: color-mix(in srgb, var(--color-accent) 5%, var(--surface-raised));
}

/* ── row--switch ── 51×31, iOS scale. Replaces .switch-field's 52×32 on these pages. */
.set-switch {
    position: relative;
    flex: none;
    display: inline-flex;
    cursor: pointer;
}
.set-switch__input {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    margin: 0;
    pointer-events: none;
}
.set-switch__track {
    position: relative;
    display: block;
    width: 51px;
    height: 31px;
    border-radius: var(--radius-pill);
    background: color-mix(in srgb, var(--text) 14%, transparent);
    transition: background 0.14s ease;
}
.set-switch__track::after {
    content: "";
    position: absolute;
    top: 2px;
    left: 2px;
    width: 27px;
    height: 27px;
    border-radius: 50%;
    background: var(--switch-knob-off);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);
    transition: transform 0.14s ease;
}
.set-switch__input:checked ~ .set-switch__track { background: var(--color-accent); }
.set-switch__input:checked ~ .set-switch__track::after { transform: translateX(20px); }
.set-switch__input:focus-visible ~ .set-switch__track {
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-accent) 13%, transparent),
                0 0 0 1px color-mix(in srgb, var(--color-accent) 55%, transparent);
}
.set-switch__input:disabled ~ .set-switch__track { opacity: 0.5; }
.set-switch:has(.set-switch__input:disabled) { cursor: default; }

/* ── row--value ── the SheetSelect trigger with its field chrome removed: the row IS the field,
   so a second box drawn inside it is the look this design replaces. Same component, same sheet. */
.sheet-select-trigger--row {
    width: auto;
    min-height: 40px;
    height: 40px;
    gap: 6px;
    padding: 0 8px 0 14px;
    border: 1px solid transparent;
    border-radius: 11px;
    background: none;
    font-size: 14.5px;
    font-weight: var(--font-weight-medium);
    text-align: right;
}
.sheet-select-trigger--row:hover:not(:disabled) {
    border-color: transparent;
    background: color-mix(in srgb, var(--text) 4%, transparent);
}
.sheet-select-trigger--row:focus-visible,
.sheet-select-trigger--row.open {
    border-color: color-mix(in srgb, var(--color-accent) 55%, transparent);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-accent) 13%, transparent);
}
.sheet-select-trigger--row:disabled { background: none; }
.sheet-select-trigger--row .sheet-select-trigger__value { flex: none; overflow: visible; }
.sheet-select-trigger--row .sheet-select-trigger__caret { font-size: 20px; color: var(--ink-disabled); }
/* The option's detail line belongs in the SHEET here, not in the trigger: a row is a single
   line, and a second line in the right-hand cell would push the row past its own geometry. */
.sheet-select-trigger--row .sheet-select-trigger__sub { display: none; }

/* …unless the detail is the whole point of the choice, in which case it rides INLINE after the
   label in quiet ink rather than wrapping to a second line — "Black · 73.1 / 141", "Hole 7 · par 3,
   168 yds". Still one line, so the row keeps its geometry. Opt-in, and dropped below 768px where
   there is no room for it beside a caption. */
.sheet-select-trigger--row.sheet-select-trigger--detail .sheet-select-trigger__value {
    display: inline-flex;
    align-items: baseline;
    gap: 6px;
    font-variant-numeric: tabular-nums;
}
.sheet-select-trigger--row.sheet-select-trigger--detail .sheet-select-trigger__sub {
    display: inline;
    margin: 0;
    font-size: 13px;
    font-weight: var(--font-weight-normal);
    color: var(--text-quiet);
}
/* The swatch a tee row is chosen by — same 11px chip the sheet's own rows carry, with a hairline
   ring so a white tee still reads on a white card. */
.sheet-select-trigger__swatch {
    flex: none;
    width: 11px;
    height: 11px;
    margin-right: 2px;
    border-radius: 3px;
    box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--text) 22%, transparent);
}

/* ── row--segment ── the shared Segmented, compact, with a raised selected chip rather than the
   solid navy fill (a navy slab inside a row is louder than the row). */
.segmented--set {
    display: inline-flex;
    flex: none;
    gap: 2px;
    padding: 3px;
    border: 1px solid var(--hairline-soft);
    border-radius: 11px;
    background: color-mix(in srgb, var(--text) 5%, transparent);
}
.segmented--set .segmented__opt {
    flex: 0 0 auto;
    padding: 7px 15px;
    border-radius: 8px;
    font-size: 13.5px;
    font-weight: var(--font-weight-semibold);
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}
.segmented--set .segmented__opt.is-active {
    background: var(--surface-raised);
    box-shadow: 0 1px 2px rgba(20, 26, 34, 0.12);
    color: var(--text);
}

/* ── row--text ── the only kind that keeps a visible field. Saves on blur. */
.set-field {
    flex: none;
    width: 300px;
    height: 44px;
    padding: 0 14px;
    border: 1px solid var(--hairline);
    border-radius: 12px;
    background: var(--control-fill);
    font-family: inherit;
    font-size: 16px;
    font-weight: var(--font-weight-semibold);
    color: var(--text);
}
.set-field--sm { width: 220px; }
/* A field that failed keeps what you typed and says why, inline — never a toast. */
.set-field.is-invalid {
    border-color: color-mix(in srgb, var(--danger) 45%, transparent);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--danger) 10%, transparent);
}
.set-field-error {
    margin: 6px 0 0;
    font-size: 12px;
    font-weight: var(--font-weight-semibold);
    color: var(--ink-on-danger-tint);
}
.set-field-ok {
    margin: 6px 0 0;
    font-size: 12px;
    font-weight: var(--font-weight-semibold);
    color: var(--ink-on-accent-tint);
}

/* ── row--number ── the shared StepperField, sized down into a 62px row. */
.stepper-field--compact {
    display: inline-flex;
    padding: 3px;
    border: 1px solid var(--hairline-soft);
    border-radius: 12px;
    background: color-mix(in srgb, var(--text) 5%, transparent);
}
.stepper-field--compact .stepper-field__row { gap: 2px; }
.stepper-field--compact .stepper-field__btn {
    width: 38px;
    height: 38px;
    border: none;
    border-radius: 9px;
    background: var(--surface-raised);
    box-shadow: 0 1px 2px rgba(20, 26, 34, 0.12);
    font-size: 1.2rem;
}
.stepper-field--compact .stepper-field__btn:disabled { background: none; box-shadow: none; }
.stepper-field--compact .stepper-field__value { flex: none; min-width: 66px; }
.stepper-field--compact .stepper-field__number {
    font-size: 17px;
    font-weight: var(--font-weight-semibold);
}

/* ── row--date ── reads as WORDS, not 05/08/2026.
   The native input is transparent and covers the whole control, so the platform picker and the
   keyboard both still work — and its own picker indicator sits at the right edge, exactly under
   the edit_calendar glyph we draw. The wrapper's inline onclick calls showPicker() so a tap
   anywhere on the pill opens it; it throws harmlessly if the indicator already did. */
.set-date {
    position: relative;
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    height: 40px;
    padding: 0 10px 0 14px;
    border: 1px solid var(--hairline);
    border-radius: 11px;
    background: var(--control-fill);
    font-size: 14.5px;
    font-weight: var(--font-weight-semibold);
    color: var(--text);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    cursor: pointer;
}
.set-date:hover { background: var(--control-fill-strong); }
.set-date:focus-within {
    border-color: color-mix(in srgb, var(--color-accent) 55%, transparent);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-accent) 13%, transparent);
}
.set-date__glyph { font-size: 18px; color: var(--ink-disabled); }
.set-date__input {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    margin: 0;
    padding: 0 10px 0 14px;
    border: none;
    background: none;
    font: inherit;
    opacity: 0;
    cursor: pointer;
}
.set-date--empty { color: var(--text-muted); font-weight: var(--font-weight-medium); }
/* Two renderings of the same date. There is no room for "Fri, May 8 2026" beside a caption at
   390px, and shortening it in C# would shorten it on desktop too. */
.set-date__short { display: none; }

/* ── row--static ── present, explained, never a greyed input. */
.set-static {
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 11px;
    border-radius: var(--radius-pill);
    background: color-mix(in srgb, var(--text) 5%, transparent);
    color: var(--text-muted);
    font-size: 12.5px;
    font-weight: var(--font-weight-semibold);
}
.set-static .material-symbols-outlined { font-size: 15px; color: var(--ink-disabled); }

/* ── row--action / row--danger ── ghost by default; accent ONLY for the page's one primary
   action, outlined --danger for a destructive trigger (the sheet does the confirming). */
.set-btn {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 7px;
    height: 40px;
    padding: 0 15px;
    border: 1px solid color-mix(in srgb, var(--text) 14%, transparent);
    border-radius: 11px;
    background: var(--surface-raised);
    font-family: inherit;
    font-size: 13.5px;
    font-weight: var(--font-weight-semibold);
    color: var(--text);
    white-space: nowrap;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    transition: background 0.14s ease;
}
.set-btn:hover:not(:disabled) { background: color-mix(in srgb, var(--text) 4%, transparent); }
.set-btn:disabled { color: var(--ink-disabled); cursor: not-allowed; }
.set-btn .material-symbols-outlined { font-size: 17px; color: var(--text-muted); }
.set-btn--accent {
    border-color: transparent;
    background: var(--color-accent);
    color: var(--on-hue);
    font-weight: var(--font-weight-bold);
}
.set-btn--accent:hover:not(:disabled) { background: color-mix(in srgb, var(--color-accent) 88%, #000); }
.set-btn--accent .material-symbols-outlined { color: inherit; }
.set-btn--accent:disabled { background: var(--control-fill-strong); color: var(--ink-disabled); }
.set-btn--danger {
    border-color: color-mix(in srgb, var(--danger) 35%, transparent);
    color: var(--danger);
    font-weight: var(--font-weight-bold);
}
.set-btn--danger:hover:not(:disabled) { background: color-mix(in srgb, var(--danger) 7%, transparent); }
.set-btn--lg { height: 42px; padding: 0 18px; font-size: 14px; }
.set-btn--sm { height: 34px; padding: 0 12px; border-radius: 9px; font-size: 12.5px; }
.set-btn--icon { width: 40px; padding: 0; }

/* ── row--copy ── a URL or code to hand out: read-only field fills the row, Copy beside it.
   Regenerate / Revoke are demoted into the card footer — three same-weight buttons in a row
   is what .danger-actions used to draw, and it made "Revoke" look like "Copy". */
.set-row--copy { gap: 12px; }
.set-copyfield {
    flex: 1;
    min-width: 0;
    height: 44px;
    padding: 0 14px;
    border: 1px solid var(--hairline);
    border-radius: 12px;
    background: var(--control-fill);
    font-family: inherit;
    font-size: 13.5px;
    color: var(--text-muted);
    text-overflow: ellipsis;
}
/* The join code keeps .join-code-display's mono treatment, at the size the design draws. */
.set-row .join-code-display {
    flex: 1;
    margin: 0;
    padding: 0;
    background: none;
    font-size: 26px;
    letter-spacing: 0.30em;
    color: var(--text);
}

/* A prefixed field: the part of the URL that isn't editable is a static affix inside the
   control, rather than a second read-only "Shareable URL" input below it. */
.set-affix {
    display: flex;
    align-items: stretch;
    height: 46px;
    border: 1px solid var(--hairline);
    border-radius: 12px;
    background: var(--control-fill);
    overflow: hidden;
}
.set-affix__prefix {
    display: flex;
    align-items: center;
    padding: 0 4px 0 14px;
    font-size: 15px;
    color: var(--text-quiet);
    white-space: nowrap;
}
.set-affix__input {
    flex: 1;
    min-width: 0;
    padding: 0 12px;
    border: none;
    border-left: 1px solid var(--hairline-soft);
    background: var(--surface-raised);
    font-family: inherit;
    font-size: 16px;
    font-weight: var(--font-weight-semibold);
    color: var(--text);
}
.set-affix__input:disabled { background: var(--control-fill); color: var(--text-muted); }

/* ── Per-row confirmation ──
   Sits between the caption and the control, so it appears where you were looking. This is what
   makes auto-save believable on a phone, where the header chip is usually scrolled off. Card-local
   by design: toasts are for ephemeral outcomes, not form state. */
.set-saved {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: 12.5px;
    font-weight: var(--font-weight-semibold);
    color: var(--ink-on-accent-tint);
    animation: set-fade-in 0.15s ease;
}
.set-saved .material-symbols-outlined { font-size: 15px; }
@keyframes set-fade-in { from { opacity: 0; } to { opacity: 1; } }

/* ── row--slider ── the AI recap dial. Spans the card instead of splitting. */
.set-slider__head { display: flex; align-items: flex-end; gap: 12px; }
.set-slider__value {
    font-size: 44px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.03em;
    line-height: 1;
    font-variant-numeric: tabular-nums;
}
/* --metal because heat is a LEVEL, not money and not a score. */
.set-slider__word {
    padding-bottom: 5px;
    font-size: 15px;
    font-weight: var(--font-weight-semibold);
    color: var(--metal);
}
.set-slider__input {
    -webkit-appearance: none;
    appearance: none;
    width: 100%;
    height: 26px;
    margin: 18px 0 0;
    background: none;
    cursor: pointer;
}
.set-slider__input::-webkit-slider-runnable-track {
    height: 8px;
    border-radius: var(--radius-pill);
    background:
        linear-gradient(90deg, color-mix(in srgb, var(--color-accent) 85%, #000), var(--color-accent))
            0 / var(--fill, 50%) 100% no-repeat,
        var(--control-fill-strong);
}
.set-slider__input::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    width: 26px;
    height: 26px;
    margin-top: -9px;
    border: 1px solid var(--hairline);
    border-radius: 50%;
    background: var(--surface-raised);
    box-shadow: 0 2px 6px rgba(20, 26, 34, 0.22);
}
.set-slider__input::-moz-range-track {
    height: 8px;
    border-radius: var(--radius-pill);
    background:
        linear-gradient(90deg, color-mix(in srgb, var(--color-accent) 85%, #000), var(--color-accent))
            0 / var(--fill, 50%) 100% no-repeat,
        var(--control-fill-strong);
}
.set-slider__input::-moz-range-thumb {
    width: 26px;
    height: 26px;
    border: 1px solid var(--hairline);
    border-radius: 50%;
    background: var(--surface-raised);
    box-shadow: 0 2px 6px rgba(20, 26, 34, 0.22);
}
.set-slider__scale {
    display: flex;
    justify-content: space-between;
    margin-top: 12px;
    font-size: 11px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

/* ── The status pipeline ──
   Four cells: past quiet with a check, current an accent-washed pill with a dot, future
   hairline-outlined. Replaces .status-pipeline's four grey chips, which said nothing about
   direction. */
.set-pipeline { display: flex; align-items: center; gap: 6px; }
.set-pipeline__cell {
    flex: 1;
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 9px 12px;
    border-radius: 11px;
    box-shadow: inset 0 0 0 1px var(--hairline);
    color: var(--ink-disabled);
    font-size: 13px;
    font-weight: var(--font-weight-semibold);
}
.set-pipeline__cell.is-past {
    background: color-mix(in srgb, var(--text) 5%, transparent);
    box-shadow: none;
    color: var(--text-quiet);
}
.set-pipeline__cell.is-current {
    background: color-mix(in srgb, var(--color-accent) 12%, transparent);
    box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--color-accent) 35%, transparent);
    color: var(--ink-on-accent-tint);
    font-weight: var(--font-weight-bold);
}
.set-pipeline__cell .material-symbols-outlined { font-size: 17px; }
.set-pipeline__dot {
    flex: none;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--color-accent);
}
.set-pipeline__sep {
    flex: none;
    font-size: 17px;
    color: var(--ink-disabled);
    opacity: 0.55;
}

/* ── Responsive: the existing 768px breakpoint governs; nothing new. ── */
@media (max-width: 767px) {
    .settings-ground {
        /* Cancels and re-applies main's own bottom reserve so the ground runs to the foot of the
           screen. Both figures track the bar: 69px of floating pane + its 14px inset. */
        margin: -0.5rem -1rem calc(-1 * (83px + env(safe-area-inset-bottom) + 0.75rem));
        padding: 0.5rem 14px calc(83px + env(safe-area-inset-bottom) + 0.75rem + var(--space-6));
    }
    /* The bar breaks out of main's 1rem gutters by default; inside the ground the gutter is the
       ground's own 14px, so a -1rem breakout would overhang it by 2px on each side. */
    .settings-ground .app-bar { margin-left: -14px; margin-right: -14px; }
    .set-page { gap: 14px; }

    .set-head { flex-direction: column; align-items: flex-start; gap: 10px; padding: 0 var(--space-1); }
    .set-head__title { font-size: 32px; font-weight: var(--font-weight-bold); letter-spacing: -0.03em; }
    .set-head__purpose { margin-top: 8px; font-size: 13.5px; }

    .set-card,
    .skel-setcard { border-radius: 18px; }
    .set-card__label { padding: 15px 16px 4px; }
    .set-card__desc { padding: 4px 16px 12px; }
    .set-card__body { padding: 10px 16px 14px; }
    .set-card__foot { padding: 12px 16px; }

    .set-row,
    .skel-setrow { gap: 14px; padding: 13px 16px; min-height: 60px; }
    .set-row--sub { padding-left: 40px; }
    .set-row--stack { padding: 10px 16px 14px; }

    /* The right cell must not starve the left one. At 390px a full date pill or a long timezone
       label pushed the caption into a one-word column that read as broken text — so here the
       control shrinks and ellipsises, and the name + caption keep the width they need. */
    .set-row__body { min-width: 42%; }
    .set-row__control { flex: 0 1 auto; min-width: 0; }

    .sheet-select-trigger--row { max-width: 100%; padding: 0 4px 0 8px; }
    .sheet-select-trigger--row .sheet-select-trigger__value {
        flex: 1 1 auto;
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    /* row--date sheds its pill chrome here and reads as a value + glyph, like row--value: the
       row is already a bordered line on a card, and a second box inside it is what this design
       replaced. Same control, same picker. */
    .set-date {
        padding: 0 4px 0 8px;
        border-color: transparent;
        background: none;
        font-size: 15px;
    }
    .set-date:hover { background: none; }
    .set-date__input { padding: 0 4px 0 8px; }
    .set-date__long { display: none; }
    .set-date__short { display: inline; }

    /* row--text stacks its field full-width under the name; row--value keeps value + chevron
       on the right, which is what makes the list still read as a list.

       The field is `flex: 1; min-width: 0`, NOT `width: 100%`. `.set-field` is `flex: none`, so
       at 100% it claimed the whole stacked line and any sibling — the Add button on "Add a group
       by hand" — was pushed outside a card that is `overflow: hidden` and clipped to a sliver.
       Stacking the row alone doesn't help: a field that can't shrink eats the extra width too.
       Same shape and same fix as `.set-copyfield`, which sits beside a Copy button. A row whose
       cell holds only the field is unaffected — flex-grow fills it exactly as 100% did. */
    .set-row--text { display: block; padding: 10px 16px 14px; min-height: 0; }
    .set-row--text .set-row__control { display: flex; margin-top: 8px; }
    .set-row--text .set-field { flex: 1; min-width: 0; height: 46px; font-size: 17px; }
    .set-row--text .set-row__caption { margin-top: 8px; }

    .set-row--copy { display: block; padding: 12px 16px 14px; }
    .set-row--copy .set-copyfield { width: 100%; }
    .set-row--copy .set-row__control { display: flex; margin-top: 10px; }

    .set-pipeline { flex-wrap: wrap; }
    .set-pipeline__sep { display: none; }
    .set-pipeline__cell { flex: 1 1 calc(50% - 3px); }
}

@media (prefers-reduced-motion: reduce) {
    .set-switch__track,
    .set-switch__track::after,
    .set-btn { transition: none; }
    .set-saved,
    .set-chip.is-saving .material-symbols-outlined { animation: none; }
}

/* The detail column grows from 500 to 700px: the old cap is what made the pane feel thin beside
   a 264px rail. The rail itself is unchanged. Declared after the block above so it wins. */
@media (min-width: 768px) {
    .settings-shell {
        max-width: 1000px;
        grid-template-columns: minmax(240px, 264px) minmax(0, 700px);
    }
}

/* ===================================================================================
   Round-pane extensions to the row system (design_handoff_rounds, turns 1b/1c/1d)
   ===================================================================================
   Phase 2 of the settings refresh, not a second system. The ten kinds above cover the
   Setup pane outright; a round pane also lists PEOPLE and GAMES, and one pane's body is
   an 18-column grid — so the block gains three variants, one save-chip state and one
   lock rule, and nothing else.

   Everything here is scoped to a class the round panes add, or is a new name, so the
   eight Event Settings pages are untouched by it. */

/* ── The quiet status pill ──
   Replaces `.status-badge status-{status}` on a pane head. The solid badge is a
   white-on-colour slab that reads as an alert, and a Scheduled round is not an alert; it
   also carried a class mismatch (`status-scheduled` had no rule for several statuses), so
   half the statuses drew white text on nothing. LIVE is the one exception and matches
   `.app-bar__live`: a round being played IS the thing worth colouring. */
.set-status {
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 5px 11px 5px 9px;
    border-radius: var(--radius-pill);
    background: color-mix(in srgb, var(--text) 5%, transparent);
    color: var(--text-muted);
    font-size: 12px;
    font-weight: var(--font-weight-semibold);
    white-space: nowrap;
}
.set-status__dot {
    flex: none;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--ink-disabled);
}
.set-status--live {
    background: color-mix(in srgb, var(--color-accent) 12%, transparent);
    color: var(--ink-on-accent-tint);
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.04em;
}
.set-status--live .set-status__dot { background: var(--color-accent); }
.set-status--off { opacity: 0.75; }

/* ── Page head additions ──
   The title takes the status pill inline; the round line the pane header already rendered
   is demoted under the purpose sentence. Same .set-head, two more parts. */
.set-head__titlerow {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}
.set-head__round {
    margin: 5px 0 0;
    font-size: 13px;
    color: var(--text-quiet);
    line-height: 1.5;
}

/* ── The fifth chip state ──
   The Wagers pane's "Unsaved changes" pill, promoted to the shared chip and given a count.
   Action panes only (Groups, Par 3s, Results); it REPORTS — the footer button commits. */
.set-chip.is-pending {
    background: color-mix(in srgb, var(--warning) 14%, transparent);
    color: var(--ink-on-warning-tint);
    font-weight: var(--font-weight-bold);
}

/* ── The lock rule ──
   A frozen control is not deleted and not replaced by a separate read-only card. The row
   stays at 55%, its control becomes a `.set-static` lock pill holding the value, and its
   caption names the reason. `.set-row--muted` (above) does the dimming; what's added here
   is the warning-tinted card footer that carries the reason for the card as a whole,
   replacing the free-floating `.round-page-lock` paragraph under the page. */
.set-card__foot--warning {
    background: color-mix(in srgb, var(--warning) 12%, transparent);
    color: var(--ink-on-warning-tint);
}
.set-card__foot--warning > .material-symbols-outlined { color: var(--warning); }
.set-card__foot--warning a { color: inherit; }

/* A card whose whole subject is pending rather than wrong — the random team draw before the
   hat is pulled. --metal is a LEVEL/standing hue, not money and not an alert. */
.set-card--metal { border-color: color-mix(in srgb, var(--metal) 30%, transparent); }
.set-card__label--metal { color: var(--metal); }

/* ── row--task ──
   Something to run that has a state. The state is a WORD immediately left of the button —
   `check_circle` + Calculated in accent, or `schedule` + the reason it can't run yet in
   muted ink. That reason is what the old Category / Status / Action table's "Pending" cell
   could never say. */
.set-task {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: 12.5px;
    font-weight: var(--font-weight-semibold);
    color: var(--text-muted);
    white-space: nowrap;
}
.set-task .material-symbols-outlined { font-size: 15px; color: var(--ink-disabled); }
.set-task--done { color: var(--ink-on-accent-tint); }
.set-task--done .material-symbols-outlined { color: inherit; }

/* ── Money in a row's right cell ──
   A pot or a payout. 22px accent, always tabular; a game's own amount stays 15px and lives
   in the caption instead. --ink-on-accent-tint rather than raw --color-accent: this is ink
   on a card, and the hue on its own lands ~3:1 in light mode. */
.set-money {
    font-size: 22px;
    font-weight: var(--font-weight-semibold);
    color: var(--ink-on-accent-tint);
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.01em;
}
.set-money--sm { font-size: 15px; letter-spacing: 0; }

/* Tinted variants of the static pill: an amber count that is a nudge, not a failure. */
.set-static--warn {
    background: color-mix(in srgb, var(--warning) 14%, transparent);
    color: var(--ink-on-warning-tint);
}
.set-static--warn .material-symbols-outlined { color: inherit; }
.set-static--accent {
    background: color-mix(in srgb, var(--color-accent) 12%, transparent);
    color: var(--ink-on-accent-tint);
}
.set-static--accent .material-symbols-outlined { color: inherit; }
.set-static--num { font-variant-numeric: tabular-nums; font-weight: var(--font-weight-bold); }

/* A 36px square icon button — the ⋯ on a group or a member row, the outlined-danger remove
   on a recorded par 3. `.set-btn--icon` alone is the 40px form used in a card footer. */
.set-btn--icon.set-btn--sm { width: 36px; height: 36px; border-radius: 10px; }
.set-btn--icon .material-symbols-outlined { font-size: 19px; }
.set-btn--danger .material-symbols-outlined { color: inherit; }

/* `.set-card` is `overflow: hidden` so its rows clip to the radius — which also clips the
   anchored dropdown an OverflowMenu opens from inside a row. Lift the clip only while a menu is
   open, exactly as `.app-bar:has(.overflow-menu__panel)` does for the bar. The phone form is a
   fixed bottom sheet and was never affected. */
.set-card:has(.overflow-menu__panel) { overflow: visible; }

/* ── card--grid ──
   A card wrapping an EXISTING grid: the section label, a context header naming what the grid
   is showing, the untouched grid, then a footer. The grid keeps its own CSS — the card only
   frames it. Used by Scores and by the wager roster. */
.set-card__head {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 14px 20px;
    border-bottom: 1px solid var(--hairline-soft);
}
.set-card__head-body { flex: 1; min-width: 0; }
.set-card__head-eyebrow {
    display: block;
    font-size: 11px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-quiet);
    font-variant-numeric: tabular-nums;
}
.set-card__head-title {
    display: block;
    margin-top: 3px;
    font-size: 15px;
    font-weight: var(--font-weight-semibold);
    color: var(--text);
}
.set-card__head-caption {
    display: block;
    margin-top: 3px;
    font-size: 12.5px;
    color: var(--text-muted);
    line-height: 1.45;
}
/* An action that belongs to the whole card rather than to one row ("Everyone in"). flex:none, so
   a long caption beside it wraps rather than squeezing the button. */
.set-card__head-actions { flex: none; display: flex; gap: var(--space-2); }
/* The label sits directly above the head, so the head's own top padding is the gap. */
.set-card__label + .set-card__head { padding-top: 10px; }
/* The grid's own horizontal scroll stays inside the card rather than the page. */
.set-card__grid { overflow-x: auto; }

/* ── Compact pager ──
   Prev / next over a bounded set (group 2 of 4), in the same chrome as the compact stepper.
   Two same-weight buttons labelled "Previous group" / "Next group" said nothing about how
   many there were or where you are. */
.set-pager {
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: 2px;
    padding: 3px;
    border: 1px solid var(--hairline-soft);
    border-radius: 12px;
    background: color-mix(in srgb, var(--text) 5%, transparent);
}
.set-pager__btn {
    width: 38px;
    height: 38px;
    display: grid;
    place-items: center;
    border: none;
    border-radius: 9px;
    background: var(--surface-raised);
    box-shadow: 0 1px 2px rgba(20, 26, 34, 0.12);
    color: var(--text);
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
.set-pager__btn .material-symbols-outlined { font-size: 20px; }
.set-pager__btn:disabled { background: none; box-shadow: none; color: var(--ink-disabled); cursor: not-allowed; }
.set-pager__label {
    min-width: 52px;
    text-align: center;
    font-size: 13.5px;
    font-weight: var(--font-weight-semibold);
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

/* ── row--member ──
   A person inside a group. Name 15/600; the caption carries index · tee · opt-in state, which
   is what the three separate columns of the old grid were each saying alone. The right cell is
   the playing handicap as a MINI stepper plus one ⋯ — participation, tee override and opt-ins
   all move into that menu, so four groups stop being forty controls. */
.set-row--member { padding-top: 12px; padding-bottom: 12px; }
.set-row--member .set-row__control { gap: 10px; }
.set-member-label {
    font-size: 11px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-quiet);
}
/* A non-Active player: 55% with a WD · 9 / DNS / DQ pill where the stepper was. The row is
   never removed — "why is he not on the board?" is answered here or nowhere. */
.set-row--member.set-row--muted .set-member-label { display: none; }

/* The mini stepper: 32px squares at radius 8 around a 34px value. The `--compact` variant above
   is the 62px settings row's size; a member row also carries a ⋯ beside it, so it goes smaller
   again rather than pushing the name into a one-word column. */
.stepper-field--mini {
    display: inline-flex;
    padding: 3px;
    border: 1px solid var(--hairline-soft);
    border-radius: 12px;
    background: color-mix(in srgb, var(--text) 5%, transparent);
}
.stepper-field--mini .stepper-field__row { gap: 2px; }
.stepper-field--mini .stepper-field__btn {
    width: 32px;
    height: 32px;
    border: none;
    border-radius: 8px;
    background: var(--surface-raised);
    box-shadow: 0 1px 2px rgba(20, 26, 34, 0.12);
    font-size: 1.05rem;
}
.stepper-field--mini .stepper-field__btn:disabled { background: none; box-shadow: none; }
.stepper-field--mini .stepper-field__value { flex: none; min-width: 34px; }
.stepper-field--mini .stepper-field__number {
    font-size: 15px;
    font-weight: var(--font-weight-semibold);
}

/* ── The allowance row ──
   Spans the card: a 27px tabular value with the AllowanceCaption word beside it in --metal (a
   LEVEL, not money), then the compact stepper with auto-width preset chips, then the note as a
   plain caption. The component's own boxed --warning note is right on its own phone screen and
   far too loud inside a card of rows. */
.set-row__lead {
    flex: none;
    display: flex;
    align-items: baseline;
    gap: 8px;
}
.set-row__value-lg {
    font-size: 27px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.02em;
    font-variant-numeric: tabular-nums;
}
/* --metal because an allowance is a LEVEL, not money and not a score — the same reason the recap
   heat word takes it. */
.set-row__value-word {
    font-size: 12.5px;
    font-weight: var(--font-weight-semibold);
    color: var(--metal);
}

/* `stepper-field--line` is the third StepperField size, and the one that keeps the parts the
   `--compact` row variant has to drop. `--compact` is an inline pill sized to sit in a 62px row,
   so presets and a note have nowhere to go inside it; `--line` moves the pill chrome onto the
   button row and lays the presets out beside it with the note wrapping underneath. The component's
   own boxed --warning note is correct on its own phone screen and far too loud inside a card. */
.stepper-field--line {
    display: flex;
    align-items: center;
    gap: 14px;
    flex-wrap: wrap;
    margin-top: 12px;
}
.stepper-field--line .stepper-field__row {
    flex: none;
    gap: 2px;
    padding: 3px;
    border: 1px solid var(--hairline-soft);
    border-radius: 12px;
    background: color-mix(in srgb, var(--text) 5%, transparent);
}
.stepper-field--line .stepper-field__btn {
    width: 38px;
    height: 38px;
    border: none;
    border-radius: 9px;
    background: var(--surface-raised);
    box-shadow: 0 1px 2px rgba(20, 26, 34, 0.12);
    font-size: 1.2rem;
}
.stepper-field--line .stepper-field__btn:disabled { background: none; box-shadow: none; }
.stepper-field--line .stepper-field__value { flex: none; min-width: 62px; }
.stepper-field--line .stepper-field__number {
    font-size: 16px;
    font-weight: var(--font-weight-semibold);
}
.stepper-field--line .stepper-field__suffix { font-size: 16px; font-weight: var(--font-weight-semibold); }
.stepper-field--line .stepper-field__caption { display: none; }
.stepper-field--line .stepper-field__presets { margin-top: 0; gap: 6px; }
.stepper-field--line .stepper-field__preset {
    flex: 0 0 auto;
    height: 32px;
    padding: 0 12px;
    border-radius: 9px;
    border-color: color-mix(in srgb, var(--text) 12%, transparent);
    background: none;
    font-size: 13px;
    font-variant-numeric: tabular-nums;
}
.stepper-field--line .stepper-field__preset.is-active {
    border-color: color-mix(in srgb, var(--color-accent) 45%, transparent);
    background: color-mix(in srgb, var(--color-accent) 10%, transparent);
    color: var(--ink-on-accent-tint);
    font-weight: var(--font-weight-bold);
}
/* The note is the card's own caption here, wrapping to its own line under the control. */
.stepper-field--line .stepper-field__note {
    flex: 1 0 100%;
    margin-top: 0;
    padding: 0;
    background: none;
    border-radius: 0;
    font-size: 12.5px;
    line-height: 1.45;
}
.stepper-field--line .stepper-field__note .material-symbols-outlined { display: none; }

/* A free-text field narrower than the 300px default, for a row that also carries a button
   (Add a group, the par-3 note); --num is the bounded-number form beside a picker.

   A row using this MUST also be `.set-row--text`. An <input> has an automatic minimum size of
   roughly its 20-character min-content width and will not shrink past it, so in the phone
   right-hand cell (~194px at 390px, after `.set-row__body { min-width: 42% }`) the field holds
   its ground and anything beside it is pushed outside the cell — and `.set-card` is
   `overflow: hidden`, so it clips rather than scrolls. `--text` stacks the row below 768px and
   gives the pair the full card width. Deliberately NOT fixed with `min-width: 0` here: squeezing
   is the failure mode `.set-row__controls` exists to avoid, and a 40px text field is worse than
   a stacked row. */
.set-field--inline { width: 220px; height: 44px; }
.set-field--num { width: 110px; height: 44px; font-variant-numeric: tabular-nums; }

/* A tag under a card head's caption (the Par 3 scorer pill on a group card). */
.set-card__head-tag { margin-top: 6px; }

/* More than one control on a spanning row — the add-a-player line, which carries who, at what
   handicap and off which tee. They wrap rather than squeeze, because three controls plus a button
   do not fit a phone in one line and shrinking them all is how you get four unreadable ones. */
.set-row__controls {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    margin-top: 10px;
}

@media (max-width: 767px) {
    .set-head__round { font-size: 12.5px; }
    /* The detail suffix inside a value trigger has no room beside a caption at 390px. */
    .sheet-select-trigger--row.sheet-select-trigger--detail .sheet-select-trigger__sub { display: none; }

    .set-card__head { padding: 13px 16px; gap: 10px; }
    .set-card__label + .set-card__head { padding-top: 8px; }
    .set-row--member { padding: 12px 16px; }
    .set-row--member .set-row__control { gap: 8px; }
    /* The index drops into the caption and the stepper keeps the right cell — a member row that
       stacked would make a four-player group four screens long. */
    .set-row--member .set-member-label { display: none; }
    .set-field--inline { width: 100%; }
    .set-row__controls > .sheet-select-trigger--row { flex: 1 1 100%; justify-content: space-between; }
    .set-pager__btn { width: 36px; height: 36px; }
    .set-pager__label { min-width: 44px; }
}

/* ===== Top app bar =====
   The one back-navigation affordance, app-wide. Sticky so it survives a long scroll; ink is
   --text, NOT --color-accent — green means "primary action" everywhere else in this app, and a
   green nav control competes with the CTA it sits above. Title is the CURRENT screen in short
   form; the long name is the page's own <h2> below the bar. (iOS labels back with the parent,
   Material 3 doesn't. We're one PWA on both, and "Rounds" beside a heading reading "Tidewater
   Golf Club" is two competing titles at 390px — so: bare arrow, current title.)

   #app-root already applies padding-top: env(safe-area-inset-top), and a sticky element can't
   rise above its containing block's content edge — so top:0 lands below the notch. Do NOT add
   another inset here or the bar floats. */
.app-bar {
    position: sticky;
    top: 0;
    z-index: 50;
    display: flex;
    align-items: center;
    gap: var(--space-1);
    height: 56px;
    padding: 0 var(--space-1);
    background: var(--surface);
    border-bottom: 1px solid var(--gray-200);
}
.app-bar__back,
.app-bar__action {
    flex: none;
    width: 48px;               /* ≥ iOS 44pt and Material 48dp */
    height: 48px;
    display: grid;
    place-items: center;
    border: none;
    border-radius: 50%;
    background: none;
    color: var(--text);
    text-decoration: none;
    cursor: pointer;
    font-family: inherit;
}
/* Back is accent green, and it is the ONE exception to "green means primary action". A back
   chevron is not competing with the page's CTA — it's the iOS/handoff idiom, it reads as
   navigation rather than as a second button, and it makes the only always-present control on a
   drill-in findable at a glance. Trailing actions stay --text. */
.app-bar__back { color: var(--color-accent); }
.app-bar__back:hover,
.app-bar__action:hover { background: var(--surface-subtle); }
.app-bar__action .material-symbols-outlined { font-size: 24px; }
/* The iOS chevron reads larger than a full arrow at the same size, so it sits a notch smaller. */
.app-bar__back .material-symbols-outlined { font-size: 22px; }
.app-bar__title {
    flex: 1;
    min-width: 0;
    font-size: 1.0625rem;
    font-weight: var(--font-weight-semibold);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
/* Naming the PARENT rather than this screen: quiet, because the screen's own large title is
   directly below it and the two must not compete. */
.app-bar__title--parent {
    font-size: 15px;
    color: var(--text-muted);
}
/* Live chip — an in-progress round is the one thing worth flagging in the bar itself. */
.app-bar__live {
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: 5px;
    margin-right: var(--space-1);
    padding: 4px 10px;
    border-radius: var(--radius-pill);
    background: color-mix(in srgb, var(--danger) 12%, transparent);
    color: var(--danger);
    font-size: 0.72rem;
    font-weight: var(--font-weight-semibold);
}
.app-bar__live::before {
    content: "";
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--danger);
}
/* The bar is flush chrome, so the page's own heading needs the gap the old .settings-back
   link used to carry as a bottom margin. */
.app-bar + .settings-sub-head { margin-top: var(--space-4); }

/* Phones: break out of main's 1rem gutters so the bar is edge-to-edge. A sticky bar that
   stops 16px short of each edge lets the page scroll past in the gutters beside it, which
   reads as a rendering bug. Every container the bar sits in is full-width below 768px (the
   500px max-widths never bind at 390px), so the negative margin lands exactly on #app-root's
   content edge — which itself respects the landscape safe-area insets. */
@media (max-width: 767px) {
    .app-bar {
        margin-left: calc(-1 * var(--space-4));
        margin-right: calc(-1 * var(--space-4));
    }
}

/* ── Detail sub-page chrome ── */
.settings-sub-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-3);
    margin-bottom: var(--space-3);
}
.settings-sub-title {
    font-size: var(--text-2xl);
    font-weight: var(--font-weight-semibold);
    margin: 0;
}
.settings-save-status {
    flex: none;
    font-size: var(--text-xs);
    font-weight: var(--font-weight-semibold);
    color: var(--text-muted);
    min-height: 1em;
    transition: color 0.15s ease;
}
.settings-save-status.is-saved { color: var(--success); }
.settings-save-status.is-error { color: var(--danger); }

/* .settings-note went with the settings redesign: a free-floating paragraph BETWEEN cards is what
   the per-row caption and the card's own group description replaced. .settings-sub-intro stays —
   RoundPaneHeader still draws it. */
.settings-sub-intro {
    font-size: var(--text-sm);
    color: var(--text-muted);
    line-height: 1.5;
    margin: var(--space-2) var(--space-2) var(--space-4);
}

/* ===== Round Hub: one round, every tool for it =====
   The same grouped-list drill-in as Settings above, keyed on a round instead of the event, so it
   reuses .settings-nav / .settings-group / .settings-row wholesale — those are
   generic grouped-list primitives that happen to carry a settings- prefix. That reuse extends to
   the ≥768px rail rules in the Settings block above (compact rows, sticky, active highlight): they
   target .settings-nav unqualified, so RoundNav picks them up with no duplication here. */

/* ── The shell: rail + detail ──
   Mobile is a single column with NO rail: the round page's own status-driven sections are the
   navigation there, and showing the rail's static Play/Money list beneath them would offer the
   same five destinations twice. At ≥768px the rail returns as the left column of a two-pane
   master–detail — same markup, one breakpoint. Panes deliberately have no max-width: score
   entry's 18-column card needs the room. */
.round-shell { max-width: none; }
/* .round-shell--hubskel is the hub's loading shape, sharing the column width so the swap moves
   nothing. A SEPARATE MODIFIER on purpose, the call .skel-board makes against .board-card:
   `.round-shell--hub` is what RoundHubTests waits on to mean "the hub is here", and a skeleton
   answering to it lets the test proceed against placeholders. */
.round-shell--hub,
.round-shell--hubskel { max-width: 500px; }
.round-detail { min-width: 0; }

.round-shell .settings-nav { display: none; }

@media (min-width: 768px) {
    .round-shell {
        display: grid;
        grid-template-columns: minmax(220px, 250px) 1fr;
        gap: var(--space-6);
        align-items: start;
    }
    /* No cap. It used to be 880px, which at a 1280px window left the hub using less of the
       screen than the panes beside it and then divided its ~600px detail column into two ~290px
       columns — cards designed for a phone getting LESS room on desktop than on a phone. The
       rail column is still minmax(220px, 250px), so the hub simply fills the pane it has and
       .round-page-sections decides how many columns that is worth. */
    .round-shell--hub,
    .round-shell--hubskel { max-width: none; }
    /* A pane column matches the Settings detail pane at 700px (design_handoff_rounds § Responsive)
       — cards of rows read as a column, not a slab. Scores is the exception and keeps the room its
       18-hole grid needs; --wide is what ScoreEntry passes. */
    .round-shell--pane {
        max-width: 1000px;
        grid-template-columns: minmax(240px, 264px) minmax(0, 700px);
    }
    .round-shell--pane.round-shell--wide {
        max-width: 1420px;
        grid-template-columns: minmax(240px, 264px) minmax(0, 1100px);
    }
    /* The rail returns on pane pages too: without it, clicking a row on desktop would drop to a
       single column with no way back but the browser. (Same reasoning as the Settings shell.) */
    .round-shell .settings-nav { display: block; }
    /* Same as the Settings detail pane: the rail navigates (back is redundant) and the bar's
       title duplicates the pane heading right below it, so the bar goes entirely.
       :not(.round-page) is load-bearing — the round page's container carries BOTH classes, and
       its bar has to survive: it holds the LIVE chip and the overflow menu, which have nowhere
       else to go. It folds into the heading instead (see .round-page > .app-bar below). */
    .round-detail:not(.round-page) .app-bar { display: none; }
}

/* ===== Round page =====
   One page per round, ordered by what the commissioner needs at that moment: where the round is,
   the one action to take, then the tools grouped by why you'd reach for them. Replaces a settings
   sheet that was three form controls followed by eleven full-width .btn-outline buttons — no
   hierarchy (Start round looked like Landing page), no grouping, and Edit Round behind a second
   sheet opened from inside the first. */
/* The pane head, on the hub. Same geometry the five panes get from .set-head — 30px title with
   the status pill inline, a 14px purpose line, then the round line quiet beneath it — except the
   title is the course, because the round is this page's subject rather than its container. */
.round-page-head { padding: var(--space-3) var(--space-2) 0; }
.round-page-title {
    font-size: 30px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.025em;
    line-height: 1.1;
    margin: 0;
}
.round-page-head .set-head__purpose { margin-top: 7px; }
/* Dropped on desktop: the facts line below it now says what the round IS (date · tee · holes ·
   format · allowance), and the sentence was restating the page's own name in the width where the
   rail beside it already names the screen. It stays on the phone, where there is no rail and the
   bar says "Rounds". */
@media (min-width: 768px) {
    .round-page-head .set-head__purpose { display: none; }
}
.round-page-meta {
    display: flex;
    align-items: center;
    gap: 7px;
    flex-wrap: wrap;
    font-size: 13px;
    color: var(--text-quiet);
    line-height: 1.5;
    margin-top: 5px;
}
/* The ordinal, promoted from a word to a control (design_handoff_teams_format §5). Metal because
   "which round you're looking at" is a STANDING — the same thing the masthead's week rail means —
   not money and not under par. */
.round-switch {
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: 4px;
    height: 28px;
    padding: 0 6px 0 11px;
    border: 1px solid var(--metal-line);
    border-radius: var(--radius-pill);
    background: var(--metal-wash-16);
    font: inherit;
    font-size: 13px;
    font-weight: var(--font-weight-bold);
    color: var(--metal-strong);
    cursor: pointer;
}
.round-switch:hover { background: var(--metal-wash-18); }
.round-switch .material-symbols-outlined { font-size: 18px; }
.round-switch__rest { min-width: 0; }
.round-page--cancelled .round-switch { opacity: .75; }
/* The facts after the ordinal are separated by 12px hairlines rather than interpuncts — the line
   now carries five of them (date · tee · holes · format · allowance) and middle dots at that
   length read as one run-on string. */
.round-page-meta__rule {
    flex: none;
    width: 1px;
    height: 12px;
    background: var(--hairline);
}
/* The allowance is the fact the desktop line gained when the purpose sentence went; the phone
   still has that sentence AND states the allowance on the Setup row two inches below, so here it
   only wraps to a second line and leaves a dangling rule at the end of the first. Dropped with
   its own separator — "≤768px unchanged" is the rule this whole bundle follows. */
@media (max-width: 767px) {
    .round-page-meta > .round-switch__rest:last-child,
    .round-page-meta > .round-page-meta__rule:nth-last-child(2) { display: none; }
}

/* The sheet it opens. It writes almost nothing of its own — .modal-panel supplies the geometry and
   the row's dot is the rounds list's. */
.round-jump__list { margin-top: var(--space-2); }
.round-jump__row,
.round-jump__all {
    display: flex;
    align-items: center;
    gap: 12px;
    min-height: 44px;
    padding: 11px var(--space-2);
    border-top: 1px solid var(--hairline-soft);
    color: var(--text);
    text-decoration: none;
}
.round-jump__row.is-current {
    background: var(--metal-wash-10);
}
.round-jump__row.is-current .round-jump__title {
    font-weight: var(--font-weight-bold);
    color: var(--metal-strong);
}
.round-jump__body { flex: 1; min-width: 0; }
.round-jump__title {
    display: block;
    font-size: 1rem;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.01em;
}
.round-jump__sub {
    display: block;
    margin-top: 2px;
    font-size: 0.8rem;
    color: var(--text-muted);
}
.round-jump__check { flex: none; font-size: 21px; color: var(--metal); }
.round-jump__chev { flex: none; font-size: 20px; color: var(--ink-disabled); }
/* A metal rule, because what sits below it is a screen rather than a round. */
.round-jump__all {
    margin-top: var(--space-3);
    min-height: 48px;
    border-top: 1px solid var(--metal-edge);
}
.round-jump__all-icon { flex: none; font-size: 20px; color: var(--metal); }
@media (max-width: 767px) {
    .round-page-title {
        font-size: 32px;
        font-weight: var(--font-weight-bold);
        letter-spacing: -0.03em;
    }
}

/* One column of cards 16px apart, matching the panes. Declared here rather than beside the
   section rules below, because the ≥768px two-column rule has to come AFTER it — a media query
   adds no specificity, so a later base rule would win over it. */
.round-page-sections {
    display: flex;
    flex-direction: column;
    gap: 16px;
    margin-top: var(--space-4);
}
/* Cancelled reads as inactive whole-screen, rather than as a badge on a live-looking page. */
.round-page--cancelled .round-page-title { color: var(--text-muted); }
.round-page--cancelled .round-page-meta { color: var(--gray-500); }

/* ===== Timeline card + job card (design_handoff_round_status_timeline) =====
   These replaced .round-status-*, a single box holding a three-cell stepper above a hero line and
   the status's one primary action. Two problems, both reported from use: three equal cells with
   the current one filled is the shape of a Segmented, so the stepper read as a control people
   tried to tap; and settling the money is a MONEY job rather than a lifecycle one, which is how a
   finished round came to draw "Settled" next to a "Calculate" button.

   So: one card that is a passive record and never carries an action, and one card that carries
   the action and nothing else. */

/* ── The timeline. A record of three stages and when each happened. ── */
.round-tl-card {
    margin: var(--space-4) var(--space-2) 0;
    background: var(--surface-raised);
    border: 1px solid var(--hairline);
    border-radius: 16px;
    /* Deliberately lighter than .set-card's pair: this card is a record sitting under the page
       head, not one of the actionable cards below it. */
    box-shadow: 0 1px 2px rgba(20, 26, 34, 0.04);
    overflow: hidden;
}
/* A cancelled round reads inactive whole-card, matching .round-page--cancelled on the heading. */
.round-tl-card--cancelled {
    background: var(--surface-3);
    box-shadow: none;
}

.round-tl {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    align-items: start;
    padding: 14px 18px 12px;
}
.round-tl__stage {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 7px;
    min-width: 0;
}
/* The connector, drawn centre-to-centre from the PREVIOUS dot. One segment per gap rather than
   one bar across the card, which is what lets a cancelled round break only its last segment. */
.round-tl__stage + .round-tl__stage::before {
    content: '';
    position: absolute;
    top: 5px;
    left: -50%;
    right: 50%;
    height: 2px;
    background: var(--hairline);
}
/* The line visibly STOPS rather than reaching a stage that never happened. */
.round-tl__stage.is-cancelled::before {
    background: repeating-linear-gradient(90deg,
        color-mix(in srgb, var(--text) 18%, transparent) 0 3px, transparent 3px 7px);
}

.round-tl__dot {
    position: relative;          /* over the connector */
    width: 12px;
    height: 12px;
    border-radius: 50%;
    background: var(--ink-disabled);
}
.round-tl__glyph {
    position: relative;
    margin-top: -3px;
    font-size: 18px;
    color: var(--ink-disabled);
    /* Masks the dashed connector behind it — the card's own ground, whichever it is. */
    background: var(--surface-3);
}
.round-tl__label {
    font-size: 11px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    text-align: center;
    line-height: 1.3;            /* "Shortened thru 14" wraps to two lines at 390px */
    color: var(--text-quiet);
}
.round-tl__time {
    font-size: 11.5px;
    color: var(--ink-disabled);
    text-align: center;
}

/* The stage the round has LANDED on: solid ink, a soft ring, and a legible time. */
.round-tl__stage.is-current .round-tl__dot {
    background: var(--text);
    box-shadow: 0 0 0 4px color-mix(in srgb, var(--text) 12%, transparent);
}
.round-tl__stage.is-current .round-tl__label { color: var(--text); }
.round-tl__stage.is-current .round-tl__time { color: var(--text-muted); }

/* Live is the one accent thing on the screen — accent means live-or-money. Rides the app's
   shared 1.6s beat, which 10-scorecard.css declares and reduced-motion already gates. */
.round-tl__stage.is-live .round-tl__dot {
    background: var(--color-accent);
    box-shadow: 0 0 0 4px color-mix(in srgb, var(--color-accent) 16%, transparent);
    animation: winprob-pulse 1.6s ease-in-out infinite;
}
/* Ink on a TINT of the hue, written locally the way .rp-chip does — the round hub is not inside
   .set-page, so --ink-on-accent-tint isn't in scope. Light darkens (the accent lands ~3:1 on its
   own wash); dark reverts, because the hue is already brightened for a dark ground. */
.round-tl__stage.is-live .round-tl__label { color: color-mix(in srgb, var(--color-accent) 80%, #000); }
:root[data-theme="dark"] .round-tl__stage.is-live .round-tl__label { color: var(--color-accent); }
.round-tl__stage.is-live .round-tl__time { color: var(--text-muted); }

/* A stage that hasn't happened: a hollow ring, a quieter ink than --text-quiet, and NO time —
   nothing has happened, so nothing is claimed. */
.round-tl__stage.is-future .round-tl__dot {
    background: var(--surface-raised);
    border: 2px solid color-mix(in srgb, var(--text) 18%, transparent);
    box-sizing: border-box;
}
.round-tl__stage.is-future .round-tl__label { color: var(--ink-future); }

.round-tl__stage.is-cancelled .round-tl__label { text-decoration: line-through; }

/* The footnote strip: Shortened states the hole it settles off, Cancelled states what happens to
   the scores. Amber here means one thing — a fact the commissioner has to accept — and the
   cancelled strip therefore takes no hue at all. */
.round-tl__note {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 11px 16px;
    border-top: 1px solid var(--hairline-soft);
    font-size: 12.5px;
    line-height: 1.45;
    color: var(--text-muted);
}
.round-tl__note > .material-symbols-outlined { flex: none; font-size: 17px; color: var(--ink-disabled); }
.round-tl__note-text { flex: 1; min-width: 0; }
.round-tl__note--warning {
    background: color-mix(in srgb, var(--warning) 8%, transparent);
}
.round-tl__note--warning > .material-symbols-outlined { color: var(--warning); }

/* ── The job card. What the round owes you, and the one action about it. ── */
/* Metal edge and metal label, because "where this round stands" is a standing — the same meaning
   the week pill and the round switcher carry. */
.round-job {
    margin: var(--space-4) var(--space-2) 0;
    border-color: var(--metal-edge);
}
.round-job__label { color: var(--metal); }

.round-job__body {
    display: flex;
    align-items: flex-end;
    gap: var(--space-4);
    padding: 2px var(--space-4) 12px;
}
.round-job__text { flex: 1; min-width: 0; }
.round-job__headline {
    font-size: 19px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.01em;
    color: var(--text);
}
.round-job__sub {
    margin-top: 4px;
    font-size: 12.5px;
    line-height: 1.45;
    color: var(--text-muted);
}

/* Several figures make a row of their own under the text; a single one sits at the card's right
   edge beside it. Three cells beside a 19px headline don't fit 390px. */
.round-job__figures {
    display: flex;
    gap: 24px;
    padding: 0 var(--space-4) 14px;
}
.round-job__figures--end {
    flex: none;
    padding: 0;
    text-align: right;
}
.round-job__figlabel {
    font-size: 10.5px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-quiet);
}
.round-job__figvalue {
    margin-top: 3px;
    font-size: 22px;
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
    color: var(--text);
}
.round-job__figof {
    /* Razor collapses the leading space out of the markup, so the gap before "/ 22" is stated
       here rather than left to a text node that isn't there. */
    margin-left: 4px;
    font-size: 14px;
    font-weight: var(--font-weight-medium);
    color: var(--text-quiet);
}
/* Money is the one figure that takes a hue, and it is metal rather than accent: a pot that
   hasn't been paid out is a standing, not a payout. */
.round-job__figure--pot .round-job__figvalue { color: var(--metal-strong); }

.round-job__progress {
    height: 6px;
    border-radius: 3px;
    background: var(--gray-200);
    margin: 0 var(--space-4) 14px;
    overflow: hidden;
}
.round-job__progress span { display: block; height: 100%; background: var(--danger); }

/* The action is a FULL-WIDTH pill and the only button on the screen. Overrides .btn-primary's
   own width rule only to restate it — what this really overrides is the 10px inline pill the
   status band used, which read as one control among several. */
.round-job__action { padding: 0 var(--space-4) var(--space-4); }
.round-job__btn.btn {
    width: 100%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    border-radius: var(--radius-pill);
    padding: 13px 20px;
    font-size: 15px;
    font-weight: var(--font-weight-bold);
    white-space: nowrap;
}
.round-job__btn .material-symbols-outlined { font-size: 19px; }

/* The settled variant. Nothing is owed, so the card stops asking: the way back into the numbers
   is a quiet metal outline on a foot row and Recalculate is an inline link. No green anywhere —
   nothing is live and nothing is outstanding. */
.round-job__foot {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: 12px var(--space-4);
    border-top: 1px solid var(--hairline-soft);
}
.round-job__prompt {
    flex: 1;
    min-width: 0;
    font-size: 12.5px;
    line-height: 1.5;
    color: var(--text-muted);
}
.round-job__relink {
    border: none;
    background: none;
    padding: 0;
    font: inherit;
    font-weight: var(--font-weight-semibold);
    color: var(--metal-strong);
    text-decoration: underline;
    cursor: pointer;
}
.round-job__metal {
    flex: none;
    border: 1px solid var(--metal-line);
    border-radius: var(--radius-pill);
    padding: 9px 15px;
    background: var(--metal-wash-16);
    color: var(--metal-strong);
    font: inherit;
    font-size: 13px;
    font-weight: var(--font-weight-bold);
    white-space: nowrap;
    cursor: pointer;
}
.round-job__relink:disabled,
.round-job__metal:disabled { opacity: 0.55; cursor: default; }

@media (min-width: 768px) {
    /* The button stops being full-width — it is a pill beside the text at the width where the
       card is wide enough for the two to sit together. */
    .round-job__btn.btn {
        width: auto;
        padding: 13px 26px;
    }
}

/* ===== Rounds list =====
   Finding one round among thirty without scrolling past the one you're running. Replaces a
   four-column table whose every row carried an Open button and a Settings button — that pair is
   why a row needed ~100px of chrome. The whole row is the link now, so a row is 44px. */
/* .skel-roundslist is the list's loading shape. A SEPARATE CLASS for the reason .skel-board is one:
   RoundManagementTests waits on `.rounds-list` to mean "the list is here". */
.rounds-list,
.skel-roundslist { max-width: 640px; }
.rounds-list-search { margin: var(--space-3) var(--space-2) 0; }
.rounds-list-filter { padding: var(--space-3) var(--space-2) var(--space-2); }

/* The round being played can never be more than a thumb's reach from the top. */
.round-live-card {
    display: block;
    margin: 0 var(--space-2) var(--space-4);
    border: 1px solid var(--danger);
    border-radius: var(--radius-lg);
    overflow: hidden;
    text-decoration: none;
    color: var(--text);
}
.round-live-card__eyebrow {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 6px var(--space-4);
    background: color-mix(in srgb, var(--danger) 8%, transparent);
    font-size: 0.7rem;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.06em;
    color: var(--danger);
}
.round-live-card__dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--danger);
}
.round-live-card__label { white-space: nowrap; }
.round-live-card__thru { margin-left: auto; }
.round-live-card__body {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
}
.round-live-card__text { flex: 1; min-width: 0; }
.round-live-card__course { font-size: 1.05rem; font-weight: var(--font-weight-semibold); }
.round-live-card__sub {
    margin-top: 2px;
    font-size: var(--text-xs);
    color: var(--text-muted);
}
.round-live-card__cta {
    flex: none;
    padding: 8px var(--space-4);
    border-radius: var(--radius-pill);
    background: var(--danger);
    color: var(--on-hue);          /* --danger brightens in dark; white on it is ~2.8:1 */
    font-size: 0.85rem;
    font-weight: var(--font-weight-semibold);
    white-space: nowrap;
}

/* Sticky under the 56px app bar — with thirty rounds you need to know which month you're in. */
.rounds-list-header {
    position: sticky;
    top: 56px;
    z-index: 5;
    padding: 10px var(--space-4) 6px;
    background: var(--surface-1);
    border-top: 1px solid var(--border);
    border-bottom: 1px solid var(--border);
    font-size: 0.72rem;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.rounds-list-row {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    min-height: 44px;
    padding: var(--space-3) var(--space-4);
    text-decoration: none;
    color: var(--text);
}
.rounds-list-row + .rounds-list-row { border-top: 1px solid var(--border); }
.rounds-list-row:hover { background: var(--surface-subtle); }
/* Played rounds recede — they're an archive, not the job. */
.rounds-list-row.is-past { opacity: 0.6; }

/* The dot IS the status column: the sub-line already says the one thing that matters. */
.rounds-list-row__dot {
    flex: none;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--gray-400);
}
.rounds-list-row__dot.is-live { background: var(--danger); }
.rounds-list-row__dot.is-ready { background: var(--slate-500); }
/* "Scheduled, nothing set up yet" is the one dot that's a *neutral*, and the design's #ddd inverts
   to #323a45 — a dot you can't see reads as no dot at all, i.e. as a rendering gap rather than as
   a state. --gray-400 keeps it clearly dimmer than .is-ready while staying visible on both grounds. */
.rounds-list-row__dot.is-empty { background: var(--gray-400); }
.rounds-list-row__dot.is-finished { background: var(--amber-500); }
.rounds-list-row__dot.is-cancelled { background: var(--gray-500); }

.rounds-list-row__body { flex: 1; min-width: 0; }
.rounds-list-row__course {
    display: block;
    font-size: 1rem;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.01em;
}
.rounds-list-row__sub {
    display: block;
    margin-top: 2px;
    font-size: 0.8rem;
    color: var(--text-muted);
}
.rounds-list-row__flag {
    flex: none;
    padding: 3px 8px;
    border-radius: var(--radius-pill);
    background: color-mix(in srgb, var(--warning) 16%, transparent);
    color: var(--warning);
    font-size: 0.7rem;
    font-weight: var(--font-weight-bold);
}
.rounds-list-row__chev {
    flex: none;
    color: var(--ink-disabled);
    font-size: 20px;
}

.rounds-list-foot { padding: var(--space-5) var(--space-2) 0; }
.rounds-list-foot .btn {
    display: block;
    width: 100%;
    border-radius: var(--radius-pill);
    text-align: center;
}
/* Says what you are NOT being asked for yet, which is the whole difference between this door and
   the Quick round one above it (design_handoff_teams_format §4). */
.rounds-list-foot__note {
    margin: var(--space-2) 0 0;
    text-align: center;
    font-size: 12.5px;
    line-height: 1.5;
    color: var(--text-muted);
}

/* Quick round — the phone's permanent door into "we're playing now" (TEE-BOX-PLAN Phase 3).
   A row, not a second button: the foot below is deliberately one full-width button, and these are
   different questions — this is today, that is the calendar. Accent because starting a round is
   live-or-money; the rounds beside it are records. */
.rounds-list-quick {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin-top: var(--space-5);
    padding: var(--space-3) var(--space-4);
    border: 1px solid var(--color-accent);
    border-radius: var(--radius-lg);
    background: color-mix(in srgb, var(--color-accent) 8%, transparent);
    text-decoration: none;
    color: var(--text);
}

.rounds-list-quick > .material-symbols-outlined { color: var(--color-accent); }
.rounds-list-quick__body { display: flex; flex-direction: column; min-width: 0; }
.rounds-list-quick__title { font-weight: var(--font-weight-semibold); }
.rounds-list-quick__sub { font-size: 13px; color: var(--text-muted); }
.rounds-list-quick__chev { margin-left: auto; color: var(--ink-disabled); }

/* ── Desktop: the sections go side by side, and the bar's controls join the heading ──
   Below 768px the page is one column and the app bar is a real sticky bar. At 768px and up the
   rail is already navigating (see the shell rules above), so the bar has nothing left to be: its
   back button is hidden, and its title would sit directly above an <h2> saying the same thing in
   longer form. It stops being a bar and becomes the heading's action row — the LIVE chip and the
   more_vert land beside the course name, where the eye already is.

   .round-page is the grid; every child spans both columns except those two, which share row 1.
   The section pairs are the only thing that genuinely wants two columns, and they get their own
   grid so an eyebrow can never be separated from the group it labels. */
@media (min-width: 768px) {
    .round-page {
        display: grid;
        grid-template-columns: 1fr auto;
        /* `start`, not `end`: the head is three lines now (title + purpose + round line), and the
           bar's LIVE chip and ⋯ belong beside the TITLE. Bottom-aligning them left them floating
           level with the quiet round line, detached from the thing they act on. */
        align-items: start;
        column-gap: var(--space-4);
        align-content: start;
    }
    .round-page > * { grid-column: 1 / -1; }

    .round-page > .round-page-head { grid-column: 1; grid-row: 1; }
    .round-page > .app-bar {
        grid-column: 2;
        grid-row: 1;
        position: static;          /* nothing to stick to once it's part of the heading */
        height: auto;
        padding: 0 var(--space-2) 0 0;
        border-bottom: none;
        background: none;
        justify-content: flex-end;
        gap: var(--space-2);
    }
    /* The <h2> beside it is the title, in the form people actually read. */
    .round-page > .app-bar .app-bar__title { display: none; }

    /* auto-fit, not `1fr 1fr`: two columns when there is genuinely room for two and one
       full-width column when there isn't, with no new breakpoint to maintain. The fixed pair
       is what put a third section in a ragged second row and squeezed every card to ~290px. */
    .round-page-sections {
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
        gap: 16px var(--space-5);
        align-items: start;
    }

    /* Scheduled is composed rather than flowed: the setup card is the job, and "Your spot" +
       "Share" are a side column beside it. Explicit placement rather than order/flow, because
       the DOM order has to stay Your spot → Set up → Share for the phone, where the one
       player-facing section leads. */
    .round-page-sections--split {
        grid-template-columns: minmax(0, 1.35fr) minmax(300px, 1fr);
    }
    .round-page-sections--split > .rp-setup { grid-column: 1; grid-row: 1 / span 2; }
    .round-page-sections--split > .rp-spot { grid-column: 2; grid-row: 1; }
    .round-page-sections--split > .rp-share { grid-column: 2; grid-row: 2; }
    /* No RSVP row for this caller (a commissioner who doesn't play): Share takes the top of the
       side column and the setup card spans one row instead of two. */
    .round-page-sections--split:not(:has(.rp-spot)) > .rp-share { grid-row: 1; }
    .round-page-sections--split:not(:has(.rp-spot)) > .rp-setup { grid-row: 1; }
}

/* ── Your spot ──
   Metal-edged, because the one section on this page aimed at the person rather than the
   commissioner is a standing they hold, not money and not a live thing. */
.rp-spot.set-card { border-color: var(--metal-edge); }
.rp-spot .set-card__label { color: var(--metal); }

/* .round-page-eyebrow is gone: a section's label moved INSIDE its card as .set-card__label when
   the hub adopted the pane treatment, which is the same move the settings pages made when the
   eyebrow → group → external note triplet became one card.

   The rows inside stay .settings-row — they NAVIGATE, they aren't settings — so the card only
   drops the group's own frame, which would otherwise be a box drawn inside a box. */
.round-page-section.set-card { margin: 0 var(--space-2); }
.set-card > .settings-group {
    background: none;
    border: none;
    border-radius: 0;
    overflow: visible;
    margin-bottom: 0;
}
/* The label already owns the gap above the first row. */
.set-card > .settings-group > .settings-row:first-child { padding-top: 10px; }

/* ── The section rows, at desktop width ──
   The hub's cards are now as wide as the panes beside them, so the rows breathe to match the
   design's 16px/24px. Scoped to .round-page-sections: .settings-row also builds the settings
   hub list, the rail and half a dozen other screens, and this is a width decision about THIS
   page, not a change to the primitive. The hairline's indent is derived from the row's own
   horizontal padding, so it has to move with it or the two drift apart. */
@media (min-width: 768px) {
    .round-page-sections .settings-row { padding: 16px var(--space-5); }
    .round-page-sections .settings-row + .settings-row::before {
        left: calc(var(--space-5) + var(--row-icon-w) + var(--space-4));
    }
    .round-page-sections .settings-row { gap: var(--space-4); }
    .round-page-sections .settings-row-title {
        font-size: 15px;
        font-weight: var(--font-weight-semibold);
    }
    .round-page-sections .settings-row-sub { margin-top: 3px; font-size: 12.5px; line-height: 1.45; }
    .round-page-sections .set-card > .settings-group > .settings-row:first-child { padding-top: 16px; }
}

/* ── The state chip on a setup row ──
   Answers "is this step done?" without opening it. Accent means the step is configured — this is
   money-and-live's other half, "set and working" — and the Wagers row carries the pot total in
   metal instead, because what it has to say is a figure rather than a yes. Never both. */
.rp-chip {
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 10px;
    border-radius: var(--radius-pill);
    background: color-mix(in srgb, var(--color-accent) 12%, transparent);
    font-size: 11.5px;
    font-weight: var(--font-weight-bold);
    /* Ink on a TINT of the hue, the same pair .set-page declares as --ink-on-accent-tint: in
       light mode the accent lands ~3:1 on its own 12% wash, so it darkens; in dark mode the hue
       is already brightened for a dark ground and darkening it is exactly backwards. Written
       here rather than read from .set-page, which the round hub is not inside. */
    color: color-mix(in srgb, var(--color-accent) 80%, #000);
    white-space: nowrap;
}
:root[data-theme="dark"] .rp-chip { color: var(--color-accent); }
.rp-chip .material-symbols-outlined { font-size: 15px; }
.rp-money {
    flex: none;
    font-size: 13px;
    font-weight: var(--font-weight-bold);
    color: var(--metal-strong);
    font-variant-numeric: tabular-nums;
}
/* Says in plain language what this status has frozen, on the ROUND PAGE — where there is no row
   to hang the reason on, because the page's sections are navigation rather than settings.
   The panes no longer use it: on a pane a frozen row stays put at 55% with a lock pill and the
   reason moves into a warning-tinted .set-card__foot on the card it applies to
   (design_handoff_rounds § Locking). Don't reintroduce a page-level lock paragraph on a pane. */
.round-page-lock {
    font-size: var(--text-sm);
    color: var(--text-muted);
    line-height: 1.5;
    margin: var(--space-3) var(--space-2) 0;
}


/* Pane chrome (RoundPaneHeader): sits above a pane's own container, which is often much wider
   than the 500px .settings-sub — so it spans whatever its page uses rather than boxing itself in.
   No bottom margin: the head and the cards are now siblings inside one .set-page, whose 16px gap
   owns the spacing. */
.round-pane { max-width: none; }

/* ══ Players · Manage (.pm-*) ═════════════════════════════════════════════════════════════
   /events/{slug}/players/manage. The last event-level admin screen still drawn in the
   pre-overhaul vocabulary — .settings-card grey slabs, a two-column .data-table whose one real
   column carried four facts at once, and five .modal-panel forms built from label + input stacks.
   Source: handoffs/design_handoff_players_manage (screens 1a–1g).

   The block sits after 07-settings.css, so .set-card / .set-row / .set-btn / .set-field are in
   scope and the FORMS write no layout of their own — they are cards of rows, and .pm-* here is
   only the roster board, the two queue rows and the sheet chrome the rows sit in.

   Five rules the whole block obeys, from src/GolfTracker.UI/CLAUDE.md:

   · --metal means STANDING — the commissioner's row and pill, the "waiting on you" eyebrow and
     its count, the YOU pill, the card feet that frame those. --color-accent means LIVE OR MONEY,
     which here is "this spot is linked and working" plus the screen's ONE primary action.
     --danger is a destructive trigger or a real failure and nothing else.
   · A MISSING EMAIL IS NOT A HUE. It is --text-quiet, the words "No email", and a button that
     fixes it in place — the whole point of the Account column, since today that repair costs a
     kebab, an Edit sheet and a hunt for the field.
   · Elevation, not boxes: --surface-raised on the page, 1px --hairline, --radius-xl, the .set-card
     shadow pair. Dividers inside are --hairline-soft. The --gray-150 slab is gone.
   · The board is a CSS GRID, not a <table>, and every index, count and dollar is tabular-nums.
   · Every state says what it is in words — "No email", "2 of 3 rounds toward an index",
     "Already on the roster", "in 11 days" — never a bare dash and never a colour alone.

   The design's measured card paddings and the sub-grid pill/tile radii are the only raw-px
   spacing, matching 19-result-tabs.css, 20-courses.css and 21-handicaps.css. */

/* ── Page frame ──────────────────────────────────────────────────────────────────────────────
   The page IS a .set-page (it inherits the three --ink-on-*-tint locals and the 16px column);
   this only caps the measure. 940px is the design's, wider than the settings detail column
   because the board carries six columns and the account address must not ellipsise at 1280. */
.pm-page {
    max-width: 940px;
    min-width: 0;
}

/* At ≥769px the event rail navigates, so the back bar is redundant — the same call
   .cm-list-page and .settings-detail make. Below it there is no rail and nothing else on the
   screen says where this sits, which is why the bar carries "Admin & setup" at all. */
@media (min-width: 769px) {
    .pm-listpage > .app-bar { display: none; }
}

/* ── "Waiting on you" and "Inactive spots" — a whole card that is one tappable row ───────────
   Same shape both times: glyph · name + caption · count pill + chevron. The queues card is
   SUPPRESSED ENTIRELY when both queues are empty, which is most days; that is what stops two
   always-present cards pushing the roster below the fold. */
.pm-queue {
    display: flex;
    align-items: center;
    gap: 20px;
    width: 100%;
    padding: 14px 20px;
    min-height: 62px;
    border: none;
    background: none;
    font-family: inherit;
    color: inherit;
    text-align: left;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    transition: background 0.14s ease;
}

.pm-queue + .pm-queue { border-top: 1px solid var(--hairline-soft); }
.pm-queue:hover { background: color-mix(in srgb, var(--text) 3%, transparent); }
.pm-queue:active { background: color-mix(in srgb, var(--text) 5%, transparent); }

.pm-queue__glyph {
    flex: none;
    width: 24px;
    display: grid;
    place-items: center;
    color: var(--ink-disabled);
}

.pm-queue__glyph .material-symbols-outlined { font-size: 20px; }

/* The row is a <button>, so its cells are spans — each needs to be told it's a block or the
   caption runs on after the name. */
.pm-queue__body { flex: 1; min-width: 0; }

.pm-queue__name {
    display: block;
    font-size: 15px;
    font-weight: var(--font-weight-semibold);
    color: var(--text);
}

/* Carries the FACT, not the category: "One expires Thursday" rather than "3 pending". */
.pm-queue__caption {
    display: block;
    margin: 3px 0 0;
    font-size: 12.5px;
    line-height: 1.45;
    color: var(--text-muted);
}

.pm-queue__end {
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: 10px;
}

.pm-queue__end .material-symbols-outlined { font-size: 20px; color: var(--ink-disabled); }

/* The count. Metal only on the queue that is genuinely waiting on the commissioner — a link YOU
   handed out is not the same kind of outstanding, so it stays neutral. */
.pm-count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 26px;
    height: 26px;
    padding: 0 9px;
    border: 1px solid transparent;
    border-radius: var(--radius-pill);
    background: var(--control-fill);
    color: var(--text-muted);
    font-size: 13px;
    font-weight: var(--font-weight-bold);
    font-variant-numeric: tabular-nums;
}

.pm-count--metal {
    border-color: var(--metal-line);
    background: var(--metal-wash-16);
    color: var(--metal-strong);
}

/* ── The roster board ────────────────────────────────────────────────────────────────────────
   avatar · player · index · role · account · menu. The Account column is the one the old screen
   had no room for, and it is why the redesign exists: the state it reports is also repaired here. */
.pm-board { min-width: 0; }

.pm-board__head,
.pm-row {
    display: grid;
    grid-template-columns: 44px minmax(170px, 1fr) 84px 128px 216px 44px;
    column-gap: 12px;
    align-items: center;
}

.pm-board__head {
    padding: 11px 20px;
    border-top: 1px solid var(--hairline-soft);
    border-bottom: 1px solid var(--hairline);
    font-size: 10.5px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

.pm-board__head .pm-col--idx { text-align: right; }

.pm-row {
    padding: 13px 20px;
    border-bottom: 1px solid var(--hairline-soft);
    transition: background-color 0.14s ease;
}

.pm-row:last-of-type { border-bottom: none; }

/* Never blue: a hover is a surface change, not a selection. */
.pm-row:hover { background-color: color-mix(in srgb, var(--text) 3%, transparent); }

/* The signed-in commissioner's own row — the same wash and pill the money list uses. */
.pm-row--you { background-image: var(--metal-row-wash); }

.pm-avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    border-radius: 11px;
    background: var(--control-fill);
    font-size: 13px;
    font-weight: var(--font-weight-bold);
    color: var(--text-muted);
}

.pm-avatar--you {
    background: var(--metal-wash-18);
    color: var(--metal-strong);
}

.pm-player { min-width: 0; line-height: 1.3; }

.pm-name {
    font-size: 16px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.01em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.pm-you {
    display: inline-flex;
    align-items: center;
    margin-left: 6px;
    padding: 1px 6px;
    border: 1px solid var(--metal-line);
    border-radius: var(--radius-pill);
    background: var(--metal-wash-16);
    font-size: 9.5px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.08em;
    color: var(--metal-strong);
    vertical-align: 2px;
}

/* Only rendered when there is something real to say ("plays as 'Smitty'", "2 of 3 rounds toward
   an index"); the line collapses otherwise, which is what keeps a healthy roster quiet. */
.pm-sub {
    font-size: 11.5px;
    color: var(--text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.pm-idx {
    display: flex;
    align-items: baseline;
    justify-content: flex-end;
    gap: 5px;
    font-size: 17px;
    font-weight: var(--font-weight-bold);
    font-variant-numeric: tabular-nums;
}

.pm-idx--none { color: var(--ink-disabled); }

/* Replaces the status-badge "seed" that only ever appeared inside the edit modal. */
.pm-seed {
    font-size: 9.5px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

/* Player is PLAIN TEXT with no pill — badging the default makes the column noise. */
.pm-role {
    font-size: 13.5px;
    color: var(--text-muted);
    min-width: 0;
}

.pm-pill {
    display: inline-flex;
    align-items: center;
    padding: 4px 10px;
    border: 1px solid transparent;
    border-radius: var(--radius-pill);
    background: var(--control-fill);
    font-size: 11.5px;
    font-weight: var(--font-weight-semibold);
    color: var(--text-muted);
    white-space: nowrap;
}

.pm-pill--metal {
    border-color: var(--metal-line);
    background: var(--metal-wash-16);
    color: var(--metal-strong);
    font-weight: var(--font-weight-bold);
}

/* ── The Account cell, in three states ───────────────────────────────────────────────────── */
.pm-acct {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
    font-size: 12.5px;
    color: var(--text-muted);
}

.pm-acct .material-symbols-outlined { flex: none; font-size: 16px; }

.pm-acct__text {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Linked is the one state that earns the accent: the spot is working. */
.pm-acct--linked { color: var(--ink-on-accent-tint); }

.pm-acct--pending .material-symbols-outlined { color: var(--text-quiet); }

.pm-acct--none { gap: 9px; color: var(--text-quiet); }
.pm-acct--none .pm-acct__state { display: inline-flex; align-items: center; gap: 6px; }

/* The point of the column. 28px rather than .set-btn--sm's 34 so the cell keeps the row's
   13px/13px rhythm — a full-height button in a data cell reads as the row's primary action. */
.pm-addone {
    flex: none;
    height: 28px;
    padding: 0 10px;
    border-radius: 9px;
    font-size: 12px;
}

/* The row's ⋯ — the same trigger the round panes' member rows carry, 36px outlined. At ≥768px
   OverflowMenu's wrapper becomes a real positioned box (it anchors the dropdown), so the GRID
   item is the wrapper and the alignment belongs on it; below that the wrapper is display:contents
   and the button itself is the flex item. */
.pm-row > .overflow-menu { justify-self: end; }

.pm-rowmenu {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    padding: 0;
    border: 1px solid color-mix(in srgb, var(--text) 14%, transparent);
    border-radius: 10px;
    background: var(--surface-raised);
    color: var(--text-muted);
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    transition: background 0.14s ease;
}

.pm-rowmenu:hover,
.pm-rowmenu.is-open {
    background: color-mix(in srgb, var(--text) 5%, transparent);
    color: var(--text);
}

.pm-rowmenu .material-symbols-outlined { font-size: 19px; }

/* A card is overflow:hidden, so the open panel would be clipped — the trick 07-settings.css
   already carries for a settings row's menu. */
.set-card:has(.overflow-menu__panel) { overflow: visible; }

/* ── The board's foot — what the roster is made of, and what still needs chasing ──────────── */
.pm-foot {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    padding: 12px 20px;
    border-top: 1px solid var(--metal-edge);
    background: var(--metal-wash-05);
    font-size: 12.5px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

.pm-foot__end { margin-left: auto; }

/* Two renderings of the same totals; the breakpoint picks one. */
.pm-narrow { display: none; }

.pm-strong {
    color: var(--text);
    font-weight: var(--font-weight-semibold);
}

/* Deactivated spots, expanded under their own card at 55% — they used to sit interleaved in the
   roster, which on a 24-row list is four ghosts you scan past every time. */
.pm-inactive .pm-row { opacity: 0.55; }

/* ── The phone meta line ─────────────────────────────────────────────────────────────────────
   Role and account state, middot-separated, folded into the player cell. Both this and the two
   grid cells are in the DOM and each hides in its own media query — the row is a grid at one
   width and a flex line at the other, and toggling display on one of them would flatten it. */
.pm-meta {
    display: none;
    margin-top: 3px;
    align-items: center;
    gap: 7px;
    font-size: 11.5px;
    color: var(--text-muted);
    min-width: 0;
}

.pm-meta__sep {
    flex: none;
    width: 1px;
    height: 10px;
    background: var(--hairline);
}

.pm-meta .pm-acct { font-size: 11.5px; }
.pm-meta .pm-acct .material-symbols-outlined { font-size: 14px; }
.pm-meta__role--metal { color: var(--metal-strong); font-weight: var(--font-weight-semibold); }

/* At 390px the repair is an inline link, not a button — a 28px button beside an 11.5px meta line
   is the widest thing on the row. */
.pm-meta__fix {
    flex: none;
    padding: 0;
    border: none;
    background: none;
    font-family: inherit;
    font-size: 11.5px;
    font-weight: var(--font-weight-semibold);
    color: var(--metal-strong);
    text-decoration: none;
    cursor: pointer;
}

/* ═══ The sheets ══════════════════════════════════════════════════════════════════════════════
   ONE overlay pattern for all six, and it is the app's existing one: .modal-panel — a full-screen
   bottom sheet ≤480px, a centred dialog above it. What changes is the CONTENTS: .set-card rows
   instead of label + input.

   The sheet's own ground is --page-ground so the cards inside read as raised, which is the whole
   reason the forms could move onto .set-card at all. Every rule is .modal-panel.pm-sheet (0,2,0)
   rather than .pm-sheet, because 13-controls-overlays.css concatenates AFTER this partial and
   .modal-panel would otherwise win on source order. */
.modal-panel.pm-sheet {
    /* The tint inks .set-page declares — the sheet renders outside the page's element. */
    --ink-on-accent-tint: color-mix(in srgb, var(--color-accent) 80%, #000);
    --ink-on-danger-tint: color-mix(in srgb, var(--danger) 80%, #000);
    --ink-on-warning-tint: color-mix(in srgb, var(--warning) 42%, #000);
    padding: 0;
    background: var(--page-ground);
    display: flex;
    flex-direction: column;
}

/* The BODY owns the scroll (see .pm-sheet__body), so a panel that HAS one must not also be a
   scroller — two nested scrollers means a drag lands on whichever the browser picks. Guarded by
   :has(), because three of TeeRound's sheets wear .pm-sheet with their content directly on the
   panel: taking the panel's own overflow away from those would clip them with nothing to scroll. */
.modal-panel.pm-sheet:has(.pm-sheet__body) { overflow: hidden; }

:root[data-theme="dark"] .modal-panel.pm-sheet {
    --ink-on-accent-tint: var(--color-accent);
    --ink-on-danger-tint: var(--danger);
    --ink-on-warning-tint: var(--warning);
}

@media (min-width: 481px) {
    .modal-panel.pm-sheet {
        max-width: 560px;
        bottom: 6%;
        max-height: 86vh;
        border-radius: var(--radius-xl);
        box-shadow: var(--shadow-lg);
    }
    /* Confirmations and the single-purpose sheets. */
    .modal-panel.pm-sheet--narrow { max-width: 480px; }
}

/* Focus ring, the same one .set-page gives every control in a row's right-hand cell. */
.pm-sheet :is(.set-field, .set-btn, .set-copyfield, .pm-addone):focus-visible {
    outline: none;
    border-color: color-mix(in srgb, var(--color-accent) 55%, transparent);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-accent) 13%, transparent);
}

.pm-sheet__head {
    display: flex;
    align-items: flex-start;
    gap: 16px;
    padding: 20px 20px 14px;
}

.pm-sheet__head-body { flex: 1; min-width: 0; }

/* The eyebrow over "Requests to join" — metal, because the queue is a standing the commissioner
   holds, not money and not a fault. */
.pm-sheet__eyebrow {
    font-size: 11px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--metal);
}

.pm-sheet__title {
    margin: 0;
    font-size: 22px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.02em;
}

.pm-sheet__eyebrow + .pm-sheet__title { margin-top: 6px; }

.pm-sheet__purpose {
    margin: 6px 0 0;
    font-size: 13px;
    line-height: 1.5;
    color: var(--text-muted);
}

.pm-sheet__close {
    flex: none;
    width: 32px;
    height: 32px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: none;
    border-radius: 10px;
    background: none;
    color: var(--text-quiet);
    cursor: pointer;
}

.pm-sheet__close:hover { background: color-mix(in srgb, var(--text) 5%, transparent); }
.pm-sheet__close .material-symbols-outlined { font-size: 20px; }

/* Edit player's head is an IDENTITY BLOCK, not a subtitle string — the old .modal-subtitle ran
   name · status-badge · seed · local together on one line. */
.pm-sheet__avatar {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    border-radius: 14px;
    background: var(--control-fill);
    font-size: 15px;
    font-weight: var(--font-weight-bold);
    color: var(--text-muted);
}

.pm-sheet__pills {
    margin-top: 7px;
    display: flex;
    align-items: center;
    gap: 7px;
    flex-wrap: wrap;
}

.pm-sheet__pills .pm-pill--active {
    border-color: transparent;
    background: color-mix(in srgb, var(--color-accent) 10%, transparent);
    color: var(--ink-on-accent-tint);
    font-weight: var(--font-weight-bold);
}

.pm-sheet__pills .pm-pill .material-symbols-outlined { font-size: 14px; margin-right: 5px; }

/* The panel is a flex column, so EVERYTHING it holds is a flex item — and only the body is
   allowed to give up height. Head and tabs are chrome and stay put while the body scrolls; the
   grabber is ::before, empty, so its min-content height is 0 and it would be the first thing
   squeezed away; and the three TeeRound sheets that wear .pm-sheet with no body at all put their
   .set-cards here, where the same overflow:hidden clipping applies (below). */
.modal-panel.pm-sheet::before,
.modal-panel.pm-sheet > *:not(.pm-sheet__body) { flex: none; }

/* Segmented sits between the head and the cards; three modes, and four is the ceiling. */
.pm-sheet__tabs { padding: 0 20px 16px; }
.pm-sheet__tabs .segmented--set { display: flex; width: 100%; }
.pm-sheet__tabs .segmented--set .segmented__opt { flex: 1; }

.pm-sheet__body {
    flex: 1;
    min-height: 0;
    padding: 0 20px 20px;
    display: flex;
    flex-direction: column;
    gap: 14px;
    overflow-y: auto;
    /* Don't chain the scroll to the page behind the sheet. */
    overscroll-behavior: contain;
    /* NOT OPTIONAL. 13-controls-overlays.css puts touch-action:none on html/body while any
       .modal-backdrop is open, and only .modal-panel re-grants pan-y — to ITSELF. Moving the
       scroller inward without re-granting it here trades a clipped sheet for one that scrolls
       under a trackpad and refuses to move under a finger. */
    touch-action: pan-y;
}

/* THE CLIPPING BUG. The body is a column flex container and its children took the default
   flex-shrink: 1, so on a phone — where the sheet is capped to the viewport — content taller
   than the panel got COMPRESSED rather than scrolled. A .set-card is overflow:hidden, so each
   squeezed card clipped its own tail: the last rows weren't below the scroll, they were removed
   from it, which is why the sheet stopped short of Handicap index and Save changes. A card's
   height is its content's, always. */
.pm-sheet__body > * { flex: none; }

/* Actions: a note or a destructive trigger left, Cancel + primary right.

   IT OWNS ITS GUTTER, like the head and the body either side of it. `.modal-panel.pm-sheet` zeroes
   the panel's own padding — that is the whole premise of this block, three children that each inset
   themselves — and this one had no padding at all, so at every width the buttons sat flush against
   the panel's left, right and bottom edges. Reported on the wager-type sheet; it was every
   `.pm-sheet` in the app. */
.pm-sheet__actions {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    padding: 14px 20px 20px;
}

.pm-sheet__actions-note {
    font-size: 12.5px;
    color: var(--text-muted);
}

.pm-sheet__actions-end {
    margin-left: auto;
    display: flex;
    gap: 10px;
}

/* ── 1c · Paste a list: the lines the server refused ─────────────────────────────────────────
   The input VERBATIM on the left and the reason on the right, one row each. Today this is a
   .form-error block with a bulleted <ul>, which turns "which line was it?" into a re-read. */
.pm-issue {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 12px 20px;
    border-top: 1px solid var(--hairline-soft);
}

.pm-issue__input {
    flex: none;
    max-width: 55%;
    font-size: 14px;
    font-weight: var(--font-weight-semibold);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.pm-issue__why {
    flex: 1;
    min-width: 0;
    font-size: 12.5px;
    color: var(--ink-on-danger-tint);
}

/* The paste textarea, inside a .set-card__body. */
.pm-textarea {
    width: 100%;
    box-sizing: border-box;
    padding: 12px 14px;
    border: 1px solid var(--hairline);
    border-radius: 12px;
    background: var(--control-fill);
    font-family: inherit;
    font-size: 15px;
    line-height: 1.6;
    color: var(--text);
    resize: vertical;
}

.pm-textarea:focus-visible {
    outline: none;
    border-color: color-mix(in srgb, var(--color-accent) 55%, transparent);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-accent) 13%, transparent);
}

/* ── 1d · Edit player: the handicap row shows what it is replacing ──────────────────────────
   StepperField's Note convention applied to a field that can't be a stepper (0.1 steps over
   −10…54). "was 11.2" sits left of the input so the number being overwritten is on screen. */
.pm-was {
    font-size: 12px;
    font-weight: var(--font-weight-semibold);
    color: var(--text-quiet);
    font-variant-numeric: tabular-nums;
}

/* The one field on the screen with a state: an unlinked spot with nothing to link on. */
.set-field.pm-field--warn {
    border-color: color-mix(in srgb, var(--warning) 45%, transparent);
    background: color-mix(in srgb, var(--warning) 7%, transparent);
}

/* ── 1e · Requests to join ───────────────────────────────────────────────────────────────── */
.pm-claim {
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 16px 20px;
}

.pm-claim + .pm-claim { border-top: 1px solid var(--hairline-soft); }

.pm-claim__avatar {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border-radius: 13px;
    background: var(--control-fill);
    font-size: 14px;
    font-weight: var(--font-weight-bold);
    color: var(--text-muted);
}

.pm-claim__body { flex: 1; min-width: 0; }

.pm-claim__who {
    font-size: 15.5px;
    font-weight: var(--font-weight-semibold);
    line-height: 1.35;
}

/* "says he is" — the connective is the quiet half; the roster spot is the metal half. */
.pm-claim__says { font-weight: var(--font-weight-normal); color: var(--text-muted); }
.pm-claim__spot { color: var(--metal-strong); }

.pm-claim__meta {
    margin-top: 3px;
    font-size: 12.5px;
    color: var(--text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
}

.pm-claim__actions {
    flex: none;
    display: flex;
    gap: 8px;
}

.pm-claim__actions .set-btn { height: 36px; padding: 0 13px; border-radius: 10px; font-size: 12.5px; }

/* A card foot that frames a standing rather than a consequence takes the metal wash. */
.set-card__foot--metal {
    border-top-color: var(--metal-edge);
    background: var(--metal-wash-05);
}

/* ── 1e · Links you handed out ───────────────────────────────────────────────────────────── */
.pm-links__head,
.pm-links__row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 150px 110px 92px;
    column-gap: 12px;
    align-items: center;
}

.pm-links__head {
    padding: 11px 20px;
    border-bottom: 1px solid var(--hairline);
    font-size: 10.5px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

.pm-links__row {
    padding: 13px 20px;
    border-bottom: 1px solid var(--hairline-soft);
}

.pm-links__row:last-of-type { border-bottom: none; }

.pm-links__name {
    font-size: 15px;
    font-weight: var(--font-weight-semibold);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Replaces the raw RoleLabel: what the link GRANTS, in the words the grant sheet used. */
.pm-links__grants { font-size: 13px; color: var(--text-muted); }

/* Words, not yyyy-MM-dd. Amber only inside three days, which is the only time it is a job. */
.pm-expires {
    font-size: 13px;
    font-variant-numeric: tabular-nums;
    color: var(--text-muted);
}

.pm-expires--soon {
    color: var(--ink-on-warning-tint);
    font-weight: var(--font-weight-semibold);
}

.pm-links__row .set-btn { height: 34px; padding: 0 12px; border-radius: 9px; font-size: 12.5px; justify-self: end; }

/* ── 1f · Merge, step 1: which spot is the same person ───────────────────────────────────── */
.pm-merge {
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
    padding: 13px 20px;
    border: none;
    background: none;
    font-family: inherit;
    color: inherit;
    text-align: left;
    cursor: pointer;
    transition: background 0.14s ease;
}

.pm-merge + .pm-merge { border-top: 1px solid var(--hairline-soft); }
.pm-merge:hover:not(:disabled) { background: color-mix(in srgb, var(--text) 3%, transparent); }

/* A candidate the server would refuse is shown GREYED WITH THE REASON, never hidden — and it
   still opens, into the tier-4 explanation that offers the merge which would have worked. */
.pm-merge--blocked { opacity: 0.55; }

.pm-merge__body { flex: 1; min-width: 0; }

.pm-merge__name {
    display: block;
    font-size: 15px;
    font-weight: var(--font-weight-semibold);
}

.pm-merge__meta {
    display: block;
    margin-top: 2px;
    font-size: 12px;
    color: var(--text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
}

.pm-merge .material-symbols-outlined { flex: none; font-size: 20px; color: var(--ink-disabled); }

/* Step 2's way back to the list. The ConfirmSheet's action row is reserved for the two answers
   ("Keep both spots" / "Merge them"), so the third way out rides above the consequence list as a
   breadcrumb rather than becoming a same-weight third button beside them. */
.pm-backstep {
    padding: 0;
    border: none;
    background: none;
    font-family: inherit;
    font-size: 13px;
    font-weight: var(--font-weight-semibold);
    color: var(--metal-strong);
    cursor: pointer;
}

.pm-backstep:disabled { color: var(--ink-disabled); cursor: not-allowed; }

/* ── 1g · Claim link / Grant admin role ──────────────────────────────────────────────────────
   The role list IS the sheet rather than a SheetSelect inside it: five options each needing a
   sentence of explanation is past the point a trigger plus a second overlay earns its keep. */
.pm-role-row {
    display: flex;
    align-items: center;
    gap: 14px;
    width: 100%;
    padding: 13px 20px;
    border: none;
    background: none;
    font-family: inherit;
    color: inherit;
    text-align: left;
    cursor: pointer;
    transition: background 0.14s ease;
}

.pm-role-row + .pm-role-row { border-top: 1px solid var(--hairline-soft); }
.pm-role-row:hover { background: color-mix(in srgb, var(--text) 3%, transparent); }
.pm-role-row.is-picked { background: var(--metal-wash-05); }

.pm-radio {
    flex: none;
    width: 18px;
    height: 18px;
    border: 1.5px solid var(--border);
    border-radius: 50%;
    box-sizing: border-box;
    transition: border 0.14s ease;
}

.pm-role-row.is-picked .pm-radio {
    border: 5px solid var(--metal);
    background: var(--surface-raised);
}

.pm-role-row__body { flex: 1; min-width: 0; }

.pm-role-row__name {
    display: block;
    font-size: 14.5px;
    font-weight: var(--font-weight-semibold);
}

/* The sentence is why the list is the sheet rather than a SheetSelect inside one, so it gets its
   own line rather than running on after the role's name. */
.pm-role-row__grant {
    display: block;
    margin-top: 2px;
    font-size: 12.5px;
    line-height: 1.45;
    color: var(--text-muted);
}

/* The generated state replaces the sheet's body. */
.pm-mark {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border-radius: 13px;
    background: var(--metal-wash-18);
    color: var(--metal-strong);
}

.pm-mark--accent {
    background: color-mix(in srgb, var(--color-accent) 12%, transparent);
    color: var(--ink-on-accent-tint);
}

.pm-mark .material-symbols-outlined { font-size: 21px; }

.pm-copyrow {
    display: flex;
    align-items: center;
    gap: 12px;
}

.pm-copyrow .set-copyfield { height: 48px; }
.pm-copyrow .set-btn { height: 48px; border-radius: 12px; }

/* ── Responsive: two breakpoints, matching the app ───────────────────────────────────────── */
@media (max-width: 768px) {
    /* The roster row goes two-line: avatar · (name / role + account) · index · ⋯. The Account
       column folds into the meta line, where the state is the WORD "Linked" rather than the
       address — except while it is pending, when the address IS the fact. */
    .pm-board__head { display: none; }

    .pm-row {
        display: flex;
        align-items: center;
        gap: 12px;
        padding: 11px 16px;
        border-bottom: none;
        border-top: 1px solid var(--hairline-soft);
    }

    .pm-row .pm-avatar { flex: none; width: 36px; height: 36px; }
    .pm-player { flex: 1; }
    .pm-name { font-size: 15.5px; }
    .pm-meta { display: flex; }
    .pm-role,
    .pm-acct--cell { display: none; }

    .pm-idx { flex: none; flex-direction: column; align-items: flex-end; gap: 0; }

    .pm-rowmenu { width: 32px; height: 32px; }
    .pm-rowmenu .material-symbols-outlined { font-size: 18px; }

    .pm-queue { gap: 12px; padding: 12px 16px; }
    .pm-foot { padding: 12px 16px; font-size: 12px; }
    .pm-wide { display: none; }
    .pm-narrow { display: inline; }
    .pm-queue__caption.pm-narrow { display: block; }

    /* The primary action becomes a full-width 46px button under the purpose line. */
    .pm-head-action { width: 100%; height: 46px; justify-content: center; font-size: 15px; }
    .set-head:has(> .pm-head-action) { flex-direction: column; align-items: stretch; }

    /* Grants and Expires ride the name; Revoke keeps its column. */
    .pm-links__head { display: none; }
    .pm-links__row {
        grid-template-columns: minmax(0, 1fr) 92px;
        row-gap: 3px;
        padding: 12px 16px;
    }
    .pm-links__name { grid-column: 1; }
    .pm-links__grants { grid-column: 1; grid-row: 2; }
    .pm-expires { grid-column: 1; grid-row: 3; }
    .pm-links__row .set-btn { grid-column: 2; grid-row: 1 / span 3; }
}

@media (max-width: 480px) {
    /* Fields go full-width with the label above — the 55/45 row split does not survive 390px,
       which is the same inversion .set-row already makes below 768px. */
    .pm-sheet .set-row {
        display: block;
        padding: 10px 16px 12px;
        min-height: 0;
    }
    .pm-sheet .set-row__caption { margin-bottom: 8px; }
    .pm-sheet .set-row__control { display: flex; width: 100%; margin-top: 8px; }
    .pm-sheet .set-field,
    .pm-sheet .set-field--inline,
    .pm-sheet .set-field--num { width: 100%; height: 46px; }
    .pm-sheet .set-card__label,
    .pm-sheet .set-card__desc,
    .pm-sheet .set-card__foot,
    .pm-sheet .set-card__body { padding-left: 16px; padding-right: 16px; }

    /* A row whose control is a value picker or a lock pill stays one line — a full-width
       SheetSelect trigger under its own label is two rows of chrome for one word. */
    .pm-sheet .set-row:has(> .set-row__control > .sheet-select-trigger--row),
    .pm-sheet .set-row:has(> .set-row__control > .set-static),
    .pm-sheet .set-row:has(> .set-row__control > .set-btn) {
        display: flex;
        align-items: center;
        gap: 16px;
        padding: 12px 16px;
        min-height: 56px;
    }
    .pm-sheet .set-row:has(> .set-row__control > .sheet-select-trigger--row) .set-row__control,
    .pm-sheet .set-row:has(> .set-row__control > .set-static) .set-row__control,
    .pm-sheet .set-row:has(> .set-row__control > .set-btn) .set-row__control {
        display: inline-flex;
        width: auto;
        margin-top: 0;
    }

    .pm-sheet__head { padding: 22px 16px 12px; }
    .pm-sheet__title { font-size: 21px; }
    .pm-sheet__tabs { padding: 0 16px 14px; }
    .pm-sheet__body { padding: 0 16px 16px; }

    /* The actions DOCK to the foot on a raised bar above the safe-area inset: primary 48px
       full-width under the thumb, Cancel beneath it as a borderless 44px row.

       NO NEGATIVE MARGIN. It had `margin: 0 -16px -16px`, which is what a block breaking out of a
       padded parent needs — and this parent has `padding: 0`. So the bar hung 16px off each edge
       and its own 16px padding merely put the buttons back level with them: a full-width Save
       touching both sides of the screen, with the bottom 16px clipped by the panel's
       `overflow: hidden`. The bar is full-bleed because it IS the panel's width, not because it
       breaks out of anything. */
    .pm-sheet__actions {
        position: sticky;
        bottom: 0;
        margin: 0;
        padding: 14px 16px calc(16px + env(safe-area-inset-bottom));
        border-top: 1px solid var(--hairline);
        background: var(--surface-raised);
        flex-direction: column-reverse;
        align-items: stretch;
        gap: 10px;
    }
    .pm-sheet__actions-note { order: 1; text-align: center; }
    .pm-sheet__actions-end {
        margin-left: 0;
        flex-direction: column-reverse;
        gap: 10px;
    }
    .pm-sheet__actions .set-btn { width: 100%; height: 48px; border-radius: 12px; font-size: 15px; }
    .pm-sheet__actions .set-btn:not(.set-btn--accent):not(.set-btn--danger) {
        height: 44px;
        border-color: transparent;
        background: none;
        color: var(--text-muted);
    }

    .pm-claim { flex-wrap: wrap; padding: 14px 16px; }
    .pm-claim__actions { width: 100%; }
    .pm-claim__actions .set-btn { flex: 1; }

    .pm-copyrow { flex-direction: column; align-items: stretch; }
    .pm-copyrow .set-btn { width: 100%; }
}

.invite-row {
    display: flex;
    gap: 0.75rem;
    align-items: flex-end;
}

.invite-btn {
    width: auto;
    white-space: nowrap;
    height: 38px;
}

/* `.member-table`, `.member-cell*`, `.member-name*`, `.member-index`, `.member-row-meta`,
   `.member-inactive-tag`, `.player-avatar.small`, `.claim-tag*`, `.claim-request*` and
   `.commissioner-badge` are GONE — the roster is a CSS grid on `.pm-*` now (see the block at the
   top of this file), the claim state is the Account column, and a self-claim is a `.pm-claim` row
   inside the Requests-to-join sheet. `.row-actions*` is gone too as of
   DASHBOARD-RETIREMENT-PLAN.md Phase 3 — LeagueTeams moved to `OverflowMenu` with the League
   redesign, which left EventDashboard as its last caller, and that page is retired.
   `.inactive-row` survives: it's shared with WagerConfig, EventResults, CutManagement and
   ScoreEntry. */

.role-select {
    padding: 0.25rem 0.4rem;
    border: 1px solid var(--gray-350);
    border-radius: 4px;
    font-size: 0.8rem;
    font-family: inherit;
    background: var(--surface);
    color: var(--text);
    cursor: pointer;
}

.role-select:focus {
    outline: none;
    border-color: var(--navy);
}

.toggle-btn {
    white-space: nowrap;
}

.inactive-row {
    opacity: 0.55;
}

/* Card header with a heading on the left and an action button on the right
   (e.g. the Rounds list "+ Add Round" trigger). Wraps gracefully on narrow
   phones so the button drops below the heading instead of squashing it. */
.card-header-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    flex-wrap: wrap;
    margin-bottom: 1rem;
}

.card-header-row h3 {
    margin: 0;
}

/* Compact "add new" pill — overrides .btn-primary's full width so it sits inline
   in a card header. The leading "+" reads as a clear create affordance. */
.btn-add {
    width: auto;
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.5rem 1rem;
    border-radius: 999px;
}

.btn-add-icon {
    font-size: 1.15em;
    line-height: 1;
    font-weight: 700;
}

@media (max-width: 480px) {
    /* Full-width on phones so the tap target spans the card. */
    .card-header-row .btn-add {
        width: 100%;
        justify-content: center;
    }
}

/* Footer actions inside a bottom-sheet form (e.g. Add Round): stack full-width
   so the primary + Cancel are even-width with a clear gap, matching the
   per-round Settings sheet. Without this, .btn-primary's width:100% leaves the
   outline button auto-width and crammed beside it. */
.sheet-actions {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    margin-top: 1rem;
}

.sheet-actions .btn {
    width: 100%;
    margin: 0;
}

@media (max-width: 768px) {
    .invite-row {
        flex-direction: column;
        align-items: stretch;
    }

    .invite-row .form-group {
        width: 100% !important;
    }

    .invite-btn {
        width: 100%;
    }
}

/* ===== Course Setup ===== */
.course-mgmt-table th,
.course-mgmt-table td {
    font-size: 0.85rem;
}

.course-detail-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 1rem;
    padding-bottom: 0.5rem;
    border-bottom: 1px solid var(--gray-350);
}

.course-detail-header h3 {
    margin-bottom: 0;
    border-bottom: none;
    padding-bottom: 0;
}

.tee-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 0.75rem;
    padding-bottom: 0.5rem;
    border-bottom: 1px solid var(--gray-350);
}

.tee-header h3 {
    margin-bottom: 0;
    border-bottom: none;
    padding-bottom: 0;
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.tee-color-dot {
    display: inline-block;
    width: 14px;
    height: 14px;
    border-radius: 50%;
    border: 1px solid var(--gray-400);
}

.tee-details {
    font-weight: 400;
    font-size: 0.8rem;
    color: var(--gray-650);
}

.tee-actions {
    display: flex;
    gap: 0.5rem;
}

.hole-grid {
    margin-bottom: 1rem;
}

.hole-table {
    margin-bottom: 0;
}

.hole-table th,
.hole-table td {
    font-size: 0.8rem;
    padding: 0.3rem 0.5rem;
    text-align: center;
}

.hole-number {
    font-weight: 600;
    width: 40px;
}

.hole-input {
    width: 60px;
    padding: 0.2rem 0.3rem;
    border: 1px solid var(--gray-350);
    border-radius: 4px;
    font-size: 0.8rem;
    font-family: inherit;
    text-align: center;
}

.hole-input:focus {
    outline: none;
    border-color: var(--navy);
}

.nine-summary td {
    border-top: 2px solid var(--gray-400);
    background-color: var(--surface-3);
}

.total-summary td {
    border-top: 2px solid var(--navy);
    background-color: var(--gray-200);
}

/* ===== Group Assignment =====
   `.group-header`, `.group-name-label`, `.group-member-count`, `.group-member-table`,
   `.unassigned-players`, `.unassigned-badge` and `.assign-player-select` are GONE. The pane is
   cards of rows now (design_handoff_rounds, 1c): a group is a `.set-card` whose head carries the
   number, tee time and scorer pill; a player in it is a `.set-row--member`; and the unassigned
   list is one permanent row with an amber count pill rather than a card of name badges that only
   appeared when the count was non-zero.

   `.group-card` survives as the per-group hook (it rides the `.set-card`) — several E2E suites
   count groups by it, and it reads better than `.set-card:nth-of-type(n)`.

   ── Collapsed groups, the field card and the phone chip row ──
   handoffs/design_handoff_groups_collapsible. Two prefixes: `.ga-*` for the pane's own new
   furniture and `.group-card__*` for the card, which extends the hook that was already there.
   Neither prefix appears in any later partial — `09-` concatenates before `13-` and `22-`, and
   both of those have caught a prefix collision here before.

   Three things worth knowing before editing this block:

   - **A group head is drawn twice and both drawings are in the DOM**, each hidden in its own
     media query. The desktop eyebrow ends on the player count and the tee time sits in a
     right-hand cell; the phone has no right-hand cell to spare beside four names, so the tee
     time folds into the eyebrow instead. A test therefore has to say which one it means.
   - **The head is a `<button>` spanning the card**, so it is the whole tap target and Enter and
     Space toggle it for free. Nothing else may go on that row — the group's ⋯ is in the expanded
     card's foot precisely because a second control there would compete with the expand.
   - **The names line truncates in CSS, never in C#**, so a wide window shows more of it. On a
     phone it wraps to two lines and clamps rather than ellipsing on one. */

/* ── The phone chip row ── two actions and the ⋯, and it MUST fit 390px without scrolling
   sideways: 118 + 119 + 38 plus two 8px gaps ends at x=351. No overflow-x, no scroll snap. */
.ga-actions {
    display: flex;
    align-items: center;
    gap: var(--space-2);
}
/* OverflowMenu wraps its trigger, so the flex item here is that wrapper, not the button. */
.ga-actions .overflow-menu { flex: none; display: flex; }
.ga-chip {
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: 5px;
    height: 38px;
    padding: 0 13px;
    border: 1px solid color-mix(in srgb, var(--text) 14%, transparent);
    border-radius: var(--radius-pill);
    background: var(--surface-raised);
    font: inherit;
    font-size: 13px;
    font-weight: var(--font-weight-semibold);
    color: var(--text);
    white-space: nowrap;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
.ga-chip .material-symbols-outlined { font-size: 17px; color: var(--text-muted); }
.ga-chip--accent {
    border-color: transparent;
    background: var(--color-accent);
    color: var(--on-hue);
    font-weight: var(--font-weight-bold);
}
.ga-chip--accent .material-symbols-outlined { color: inherit; }
.ga-chip--icon { width: 38px; padding: 0; justify-content: center; }
.ga-chip--icon .material-symbols-outlined { font-size: 19px; color: var(--text); }

/* ── The unassigned strip ── phone only. It REPORTS, so it left the button row; and it is never
   abbreviated to "2 out", which reads as a filter chip and doesn't say what is out. Absent
   entirely when nobody is unassigned, unlike the desktop row that is always present. */
.ga-out {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 11px 14px;
    border: 1px solid color-mix(in srgb, var(--warning) 35%, transparent);
    border-radius: 12px;
    background: color-mix(in srgb, var(--warning) 10%, transparent);
    font: inherit;
    text-align: left;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
.ga-out .material-symbols-outlined { flex: none; font-size: 18px; color: var(--ink-on-warning-tint); }
.ga-out .material-symbols-outlined:last-child { font-size: 20px; }
.ga-out__text {
    flex: 1;
    min-width: 0;
    font-size: 13px;
    font-weight: var(--font-weight-semibold);
    color: var(--ink-on-warning-tint);
    line-height: 1.4;
}

/* ── "The field" ── the list's own controls, in a card, so they scroll away with the list. The
   head and the search box read as one block, hence no divider between them. */
.ga-field .set-card__head {
    padding-bottom: 12px;
    border-bottom: none;
}
.ga-search {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 0 20px 16px;
}
.ga-search > .material-symbols-outlined { flex: none; font-size: 20px; color: var(--ink-disabled); }
.ga-search__input { flex: 1; min-width: 0; width: auto; }
.ga-field__note .set-card__foot-text { font-weight: var(--font-weight-semibold); }

/* ── The collapsed group card ── */
.group-card__head {
    display: flex;
    align-items: center;
    gap: 14px;
    width: 100%;
    padding: 13px 16px 13px 20px;
    border: none;
    background: none;
    font: inherit;
    text-align: left;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
.group-card__head:hover { background: color-mix(in srgb, var(--text) 3%, transparent); }
.group-card__head:active { background: color-mix(in srgb, var(--text) 5%, transparent); }
.group-card__head:focus-visible {
    outline: none;
    background: color-mix(in srgb, var(--color-accent) 7%, transparent);
    box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--color-accent) 40%, transparent);
}

.group-card__num {
    flex: none;
    display: grid;
    place-items: center;
    width: 32px;
    height: 32px;
    border-radius: 9px;
    background: var(--control-fill);
    font-size: 13.5px;
    font-weight: var(--font-weight-bold);
    font-variant-numeric: tabular-nums;
    color: var(--text);
}
.group-card__text { flex: 1; min-width: 0; }
.group-card__eyebrow {
    display: block;
    font-size: 11px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-quiet);
    font-variant-numeric: tabular-nums;
}
.group-card__eyebrow--narrow { display: none; }
.group-card__names {
    display: block;
    margin-top: 3px;
    font-size: 14.5px;
    font-weight: var(--font-weight-medium);
    color: var(--text);
    line-height: 1.35;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.group-card__right {
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: 10px;
}
/* The Par 3 card holder and whoever is entering — on the HEAD, because which of twenty groups
   holds either is exactly what you want without opening one. */
.group-card__pill {
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 5px 10px;
    border-radius: var(--radius-pill);
    background: color-mix(in srgb, var(--text) 5%, transparent);
    font-size: 11.5px;
    font-weight: var(--font-weight-bold);
    color: var(--text-muted);
    white-space: nowrap;
}
.group-card__pill .material-symbols-outlined { font-size: 15px; color: inherit; }
.group-card__pill--accent {
    background: color-mix(in srgb, var(--color-accent) 10%, transparent);
    color: var(--ink-on-accent-tint);
}
.group-card__tee {
    font-size: 13.5px;
    font-weight: var(--font-weight-semibold);
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.group-card__chev { font-size: 22px; color: var(--ink-disabled); }
.group-card.is-open .group-card__chev { color: var(--text-muted); }

/* The body's own first divider — its rows take `.set-row + .set-row` from there down. */
.group-card__panel { border-top: 1px solid var(--hairline-soft); }

@media (max-width: 768px) {
    /* The desktop card is not rendered here; the chip row and the strip are. */
    .ga-build { display: none; }
    .ga-field__collapse { display: none; }
    .ga-search { padding: 0 16px 14px; }

    .group-card__head { gap: 12px; padding: 12px 12px 12px 16px; }
    .group-card__num { width: 30px; height: 30px; font-size: 13px; }
    .group-card__eyebrow { letter-spacing: 0.08em; }
    .group-card__eyebrow--wide { display: none; }
    .group-card__eyebrow--narrow { display: block; }
    /* Two lines rather than one ellipsed name — a phone card has the height and the head has no
       right-hand cell competing for the width. */
    .group-card__names {
        font-size: 14px;
        white-space: normal;
        display: -webkit-box;
        -webkit-line-clamp: 2;
        -webkit-box-orient: vertical;
    }
    .group-card__right { gap: 8px; }
    /* The phone eyebrow already carries the tee time. */
    .group-card__tee { display: none; }
}

@media (min-width: 769px) {
    .ga-actions { display: none; }
    .ga-out { display: none; }
}

.handicap-input {
    width: 60px;
    padding: 0.25rem 0.4rem;
    border: 1px solid var(--gray-350);
    border-radius: 4px;
    font-size: 0.85rem;
    font-family: inherit;
    text-align: center;
}

.handicap-input:focus {
    outline: none;
    border-color: var(--navy);
}

.name-edit-form {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
}

.name-edit-form input {
    padding: 0.25rem 0.4rem;
    border: 1px solid var(--gray-350);
    border-radius: 4px;
    font-size: 0.9rem;
    font-family: inherit;
}

.name-edit-form input:focus {
    outline: none;
    border-color: var(--navy);
}

/* The Blazor boot ring (.loading-progress / .loading-progress-text) lived here. It is GONE:
   handoffs/design_handoff_cold_start replaced it with the brand hold, whose styles are inline in
   each host's index.html because that screen paints before this stylesheet is guaranteed to exist.
   On iOS and Android the framework is already on disk, so the percentage was measuring a download
   that wasn't happening — and on the web a number invites you to watch it. No percentage anywhere,
   on any platform. */

/* ===== Blazor Error UI ===== */
#blazor-error-ui {
    color-scheme: light only;
    background: lightyellow;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    box-sizing: border-box;
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
}

#blazor-error-ui .dismiss {
    cursor: pointer;
    position: absolute;
    right: 0.75rem;
    top: 0.5rem;
}

.blazor-error-boundary {
    background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
    padding: 1rem 1rem 1rem 3.7rem;
    color: white;
}

.blazor-error-boundary::after {
    content: "An error has occurred."
}

/* ===== Filter Controls ===== */
.filter-controls {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.6rem;
    margin: 1rem 0;
}

/* Inside the filter row the badge sits on its own line under the selector, so it
   aligns flush-left with the selector and tables rather than carrying its inline gap. */
.filter-controls .scoring-mode-badge {
    margin-left: 0;
}

/* ===== Course Info ===== */
.course-info {
    margin: 0.5rem 0 1rem 1rem;
    text-align: left;
}

.course-info h4 {
    font-size: 1.1rem;
    color: var(--text);
    margin: 0;
    font-weight: 600;
}

.skins-summary {
    margin-bottom: 1.5rem;
}

.skins-section-heading {
    font-size: 1.1rem;
    color: var(--text);
    margin: 1.5rem 0 0.5rem;
    font-weight: 600;
    text-align: left;
}

.skins-summary .skins-section-heading {
    margin-top: 0;
}

/* Compact 3-column roll-up — stays a real table on phones (it fits) instead of
   collapsing to cards like the per-hole table. */
.skins-summary__table {
    margin-bottom: 0;
}

.skins-summary__table th:not(.text-left),
.skins-summary__table td:not(.text-left) {
    text-align: center;
    white-space: nowrap;
}

/* ═══ RSVPs — .rsv-* (Shared/RoundAttendanceDialog.razor) ═════════════════════════════════════
   The last dialog on the round page still drawn in the pre-overhaul vocabulary: a .modal-panel
   wrapping a .data-table with a native <select> per row and a Clear button in an Actions column.
   It rides .modal-panel.pm-sheet now, so the shell, the 560px cap, the phone bottom-sheet form and
   the tint inks all come from the block above — everything here is the two cards' own drawing.

   ONE hue, used the way the app uses it everywhere else: --color-accent means LIVE, so "in" is
   accent and "maybe" is a TINT of the same accent rather than a second colour. A maybe is not a
   standing (--metal) and it is not something anyone must act on (--warning); reaching for either
   would spend a meaning the rest of the app depends on. "Out" is neutral grey, and "no answer" is
   the empty track — an absence drawn as an absence. */

/* ── The tally card ─────────────────────────────────────────────────────────────────────────
   Replaces "6 Yes · 2 Maybe · 1 No · 3 No response", which asked the commissioner to add up four
   numbers to learn the one thing they came for: is the field settled? */
.rsv-tally { padding: 16px 20px; }

.rsv-tally__head {
    display: flex;
    align-items: baseline;
    gap: 8px;
}
.rsv-tally__fig {
    font-size: 26px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.02em;
    color: var(--text);
    font-variant-numeric: tabular-nums;
}
.rsv-tally__of {
    font-size: 14px;
    color: var(--text-muted);
}

.rsv-bar {
    display: flex;
    margin-top: 12px;
    height: 8px;
    border-radius: var(--radius-pill);
    background: color-mix(in srgb, var(--text) 6%, transparent);
    overflow: hidden;
}
/* The 2px separation is carved OUT of each segment by a transparent border rather than added
   between them with a gap: gaps would push the row past 100% and clip the last segment's tail.
   background-clip keeps the fill off the border so the track shows through it. */
.rsv-bar__seg {
    flex: none;
    border-right: 2px solid transparent;
    background-clip: padding-box;
    transition: width 0.18s ease;
}
.rsv-bar__seg:last-child { border-right: 0; }
.rsv-bar__seg--yes { background-color: var(--color-accent); }
.rsv-bar__seg--maybe { background-color: color-mix(in srgb, var(--color-accent) 35%, transparent); }
/* Neutral, and --border-strong is the one that reads correctly in BOTH themes here. */
.rsv-bar__seg--no { background-color: var(--border-strong); }

.rsv-legend {
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
    margin-top: 12px;
}
.rsv-legend__item {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    white-space: nowrap;
    font-size: 12.5px;
    color: var(--text-muted);
}
.rsv-legend__item b {
    font-weight: var(--font-weight-semibold);
    color: var(--text);
    font-variant-numeric: tabular-nums;
}
.rsv-legend__item--quiet,
.rsv-legend__item--quiet b { color: var(--text-quiet); }

.rsv-dot {
    flex: none;
    width: 8px;
    height: 8px;
    border-radius: 3px;
}
.rsv-dot--yes { background: var(--color-accent); }
.rsv-dot--maybe { background: color-mix(in srgb, var(--color-accent) 35%, transparent); }
.rsv-dot--no { background: var(--border-strong); }
/* Hollow: nothing has been said, so nothing is filled in. */
.rsv-dot--none { border: 1px solid color-mix(in srgb, var(--text) 18%, transparent); }

/* ── The field card ─────────────────────────────────────────────────────────────────────── */
.rsv-row {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 11px 20px;
    border-top: 1px solid var(--hairline-soft);
}
.rsv-row__body { flex: 1; min-width: 0; }
.rsv-row__name {
    font-size: 15px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.01em;
    color: var(--text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
/* Notes when there are any, otherwise the status as a phrase — never blank, because a bare row
   under a name reads as missing data rather than as "no answer". */
.rsv-row__sub {
    font-size: 11.5px;
    color: var(--text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.rsv-row__sub.is-quiet { color: var(--text-quiet); }

/* ── The three-way ──────────────────────────────────────────────────────────────────────────
   .segmented--set's shape, hand-drawn rather than hosting <Segmented>, for two reasons that
   component can't serve: the active segment's INK differs per state (accent for in, plain for
   maybe, muted for out — a maybe should not read as loudly as an in), and tapping the active
   segment CLEARS the answer, which a value-bound segmented has no way to express. That clear is
   the whole Actions column, gone. */
.rsv-seg {
    flex: none;
    display: inline-flex;
    gap: 2px;
    padding: 3px;
    border: 1px solid var(--hairline-soft);
    border-radius: 11px;
    background: color-mix(in srgb, var(--text) 5%, transparent);
}
.rsv-seg.is-busy { opacity: 0.5; }

.rsv-seg__opt {
    padding: 7px 13px;
    border: none;
    border-radius: 8px;
    background: transparent;
    color: var(--text-quiet);
    font-family: inherit;
    font-size: 12.5px;
    font-weight: var(--font-weight-semibold);
    white-space: nowrap;
    cursor: pointer;
}
.rsv-seg__opt:disabled { cursor: not-allowed; }
.rsv-seg__opt:hover:not(:disabled):not(.is-on) { color: var(--text-muted); }
.rsv-seg__opt.is-on {
    background: var(--surface-raised);
    box-shadow: 0 1px 2px rgba(20, 26, 34, 0.12);
    font-weight: var(--font-weight-bold);
}
.rsv-seg__opt--yes.is-on { color: var(--ink-on-accent-tint); }
.rsv-seg__opt--maybe.is-on { color: var(--text); }
.rsv-seg__opt--no.is-on { color: var(--text-muted); }

.rsv-seg__opt:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-accent) 20%, transparent);
}

/* The chase foot's glyph is metal because the FOOT is — a standing the commissioner holds. Scoped
   to this sheet rather than to .set-card__foot--metal, whose other three call sites (the players
   screen's queues) were drawn with the default --ink-disabled glyph. */
.rsv-foot > .material-symbols-outlined { color: var(--metal); }

.rsv-error { padding: 0 4px; }

.rsv-note {
    margin: 0 4px;
    font-size: 12.5px;
    line-height: 1.5;
    color: var(--text-quiet);
}

/* At 390px the row is avatar + name + three segments, and the segments are flex:none, so it is
   the NAME that would be squeezed to a column. Tighten the control instead: the labels stay
   whole, which is the part that has to be readable at arm's length on a first tee. */
@media (max-width: 480px) {
    .rsv-row { gap: 10px; padding: 11px 14px; }
    .rsv-seg__opt { padding: 7px 9px; }
    /* The label and the foot follow the rows in, or the card's left edge zig-zags. */
    .rsv-sheet .set-card__label { padding-left: 14px; padding-right: 14px; }
    .rsv-sheet .set-card__foot { padding-left: 14px; padding-right: 14px; }
    .rsv-tally { padding: 14px; }
    .rsv-legend { gap: 12px; }
}

/* ═══ Add players — .sms-sheet (SheetMultiSelect's Variant="Sheet") ═══════════════════════════
   The picker behind Group assignment's "Add players" row. It was full-width bordered boxes on
   white — the "1px #ddd on the same white as the page" this design system exists to replace — with
   a navy .btn-primary commit and nothing anywhere saying WHICH group was being filled or how many
   spots it had. It rides .modal-panel.pm-sheet now, so the sheet's ground, the 560px cap and the
   phone bottom-sheet form all come from the block above.

   Everything here is written under .modal-panel.pm-sheet (0,2,0) or .sms-sheet, deliberately:
   13-controls-overlays.css concatenates AFTER this partial and owns the plain .sms-* look, which
   must survive untouched for the default variant. */

/* The panel's own scroll went to the body with the .pm-sheet fix; the foot is a flex SIBLING of
   that body rather than a sticky child, so it docks by being last in the column. */
.modal-panel.pm-sheet > .sms-foot {
    flex: none;
    position: static;
    margin: 0;
    padding: 12px 20px calc(12px + env(safe-area-inset-bottom));
    border-top: 1px solid var(--hairline);
    background: var(--surface-raised);
}
.modal-panel.pm-sheet > .sms-foot .sms-foot__count { font-size: 13px; }

/* Accent, not navy: this commits the thing the sheet is for. Navy is the pre-overhaul primary and
   on a --page-ground sheet it reads as chrome rather than as the action. */
.modal-panel.pm-sheet .sms-foot__go--accent {
    min-height: 44px;
    padding: 0 18px;
    border: none;
    border-radius: 11px;
    background: var(--color-accent);
    color: var(--on-hue);
    font-family: inherit;
    font-size: 14px;
    font-weight: var(--font-weight-bold);
    cursor: pointer;
}
.modal-panel.pm-sheet .sms-foot__go--accent:hover:not(:disabled) {
    background: color-mix(in srgb, var(--color-accent) 88%, #000);
}
/* Disabled still says what it is: --ink-disabled stays legible in both themes where
   --border-strong disappears on the dark ground. */
.modal-panel.pm-sheet .sms-foot__go--accent:disabled {
    background: var(--control-fill-strong);
    color: var(--ink-disabled);
    cursor: not-allowed;
}

/* ── The capacity strip ─────────────────────────────────────────────────────────────────────
   Who is in, who is about to be, and what is still empty — as chips, so "am I about to make a
   fivesome?" is answered without counting names. */
/* Wraps, because a group can go over capacity — five chips beside a name at 390px is a second
   line, not a squeezed one. */
.sms-cap__chips {
    gap: 6px;
    flex-wrap: wrap;
    justify-content: flex-end;
}

.sms-cap__chip {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    border-radius: 11px;
    background: var(--control-fill);
    font-size: 12px;
    font-weight: var(--font-weight-bold);
    color: var(--text-muted);
}
/* Accent wash: these are the ones the tap will put in — live, not yet settled. */
.sms-cap__chip--adding {
    background: color-mix(in srgb, var(--color-accent) 14%, transparent);
    color: var(--ink-on-accent-tint);
}
/* Dashed and unlabelled, because an empty spot has no name to print. */
.sms-cap__chip--empty {
    border: 1px dashed color-mix(in srgb, var(--text) 20%, transparent);
    background: none;
}

/* ── Search + quick picks, in the sheet's field chrome ─────────────────────────────────────── */
.modal-panel.pm-sheet .sms-search {
    margin: 0;
    padding: 10px 13px;
    border: 1px solid var(--hairline-soft);
    border-radius: 12px;
    background: var(--control-fill);
}
.modal-panel.pm-sheet .sms-search .material-symbols-outlined { font-size: 19px; }
.modal-panel.pm-sheet .sms-search .sheet-search__input { font-size: 14.5px; }

.modal-panel.pm-sheet .sms-picks { margin: 0; gap: 8px; }
.modal-panel.pm-sheet .sms-pick {
    min-height: 34px;
    padding: 0 12px;
    border: 1px solid var(--hairline);
    border-radius: var(--radius-pill);
    background: var(--control-fill);
    font-size: 12.5px;
}
.modal-panel.pm-sheet .sms-pick.is-on {
    border-color: var(--color-accent);
    background: color-mix(in srgb, var(--color-accent) 12%, transparent);
    color: var(--ink-on-accent-tint);
    font-weight: var(--font-weight-bold);
}
.modal-panel.pm-sheet .sms-pick--clear {
    border-color: transparent;
    background: none;
    color: var(--text-muted);
    font-weight: var(--font-weight-medium);
}

/* ── One card per RSVP section ─────────────────────────────────────────────────────────────
   The heading used to be quiet grey text with no count and no way to take the whole set. It is a
   card header now: the section's colour, its size, and a one-tap verb. */
.sms-sec__head {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 14px 20px 10px;
}
.sms-sec__dot {
    flex: none;
    width: 8px;
    height: 8px;
    border-radius: 3px;
    /* No section colour supplied — a neutral dot, never a missing one. */
    background: color-mix(in srgb, var(--text) 16%, transparent);
}
.modal-panel.pm-sheet .sms-sec__label {
    flex: 1;
    min-width: 0;
    padding: 0;
    font-size: 11px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-quiet);
}
.sms-sec__all {
    flex: none;
    border: none;
    background: none;
    padding: 0;
    font-family: inherit;
    font-size: 12px;
    font-weight: var(--font-weight-semibold);
    color: var(--ink-on-accent-tint);
    cursor: pointer;
}
/* When it would take the section back OUT, it stops reading as an offer. */
.sms-sec__all.is-clear { color: var(--text-quiet); }

/* ── The rows ─────────────────────────────────────────────────────────────────────────────── */
.modal-panel.pm-sheet .sms-row {
    display: flex;
    align-items: center;
    gap: 14px;
    width: 100%;
    padding: 11px 20px;
    border: none;
    border-top: 1px solid var(--hairline-soft);
    background: none;
    font-family: inherit;
    text-align: left;
    cursor: pointer;
    transition: background 0.14s ease;
}
/* An unsectioned list is one card with no header, so its first row has nothing to be divided
   from. (With RSVPs on the round the header is always there and every row keeps its rule.) */
.sms-sec > .sms-row:first-child { border-top: none; }
.modal-panel.pm-sheet .sms-row:disabled { opacity: 0.55; cursor: not-allowed; }
.modal-panel.pm-sheet .sms-row:hover:not(:disabled) { background: color-mix(in srgb, var(--text) 3%, transparent); }
/* The wash AND the box are both present: the box is what says "tick me", the wash is what says
   "picked". Either alone is ambiguous next to a single-select list two taps away. */
.modal-panel.pm-sheet .sms-row.is-on { background: color-mix(in srgb, var(--color-accent) 7%, transparent); }

.modal-panel.pm-sheet .sms-row .sms-box { border-radius: 7px; }
.modal-panel.pm-sheet .sms-row .sms-box:not(.is-on) { border-color: var(--border-strong); }

.sms-row__body { flex: 1; min-width: 0; }
.sms-row__name {
    display: block;
    font-size: 15px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.01em;
    color: var(--text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.sms-row__sub {
    display: block;
    font-size: 11.5px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}
.sms-row__sub.is-quiet { color: var(--text-quiet); }

.sms-empty {
    margin: 0 4px;
    font-size: 13px;
    color: var(--text-quiet);
    text-align: center;
}

.sms-note {
    margin: 0 4px;
    font-size: 12.5px;
    line-height: 1.5;
    color: var(--text-quiet);
}

@media (max-width: 480px) {
    .modal-panel.pm-sheet .sms-row { gap: 10px; padding: 11px 14px; }
    .sms-sec__head { padding: 14px 14px 10px; }
    .modal-panel.pm-sheet > .sms-foot { padding-left: 16px; padding-right: 16px; }
    /* The phone stacking the plain variant uses, kept: the primary lands under the thumb. */
    .modal-panel.pm-sheet > .sms-foot { flex-direction: column; align-items: stretch; gap: 8px; }
    .modal-panel.pm-sheet > .sms-foot .sms-foot__count { flex: none; text-align: center; }
    .modal-panel.pm-sheet > .sms-foot .sms-foot__go { width: 100%; min-height: 48px; }
}

/* ===== Mobile Hide ===== */
@media (max-width: 768px) {
    .mobile-hide {
        display: none;
    }
}

/* ===== Player Detail (Leaderboard Expansion) =====
   Scope the flush padding to the DIRECT detail cell only. A descendant
   selector (`.player-detail-row td`) leaks `padding:0 !important` into every
   nested table — including the scorecard — and overrides its cell padding,
   crushing the score rows together. The detail row has a single colspan td. */
.player-detail-row > td {
    padding: 0 !important;
    border-bottom: 1px solid var(--gray-350);
}

.player-detail-cell {
    padding: 0 !important;
}

.player-detail {
    background-color: var(--gray-150);
    padding: 1rem;
    width: 100%;
    box-sizing: border-box;
}

.data-table .player-row.active {
    background-color: var(--surface-selected);
}

.close-button-wrapper {
    display: flex;
    justify-content: flex-end;
}

.close-button {
    background: none;
    border: 1px solid var(--gray-650);
    border-radius: 50%;
    font-size: 1.5rem;
    cursor: pointer;
    color: var(--gray-650);
    padding: 0;
    margin: 0;
    width: 32px;
    height: 32px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.close-button:hover {
    background-color: var(--gray-300);
}

/* The leaderboard expansion's header, avatar, name block and .sub-nav tab strip were retired by
   the scorecard refresh — see the .psc-* block further down. ScrambleResultsView still renders
   .player-detail / .close-button above, which is why those stay. */

/* ===== Scorecard ===== */
.scorecard {
    overflow-x: auto;
    overflow-y: hidden;
    margin-bottom: 1.5rem;
    width: 100%;
}

/* The middot-separated course line moved to .psc-course (hairline rules, name first). */

.desktop-scorecard {
    display: block;
}

.mobile-scorecard {
    display: none;
}

.scorecard-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.85rem;
    border-top: 3px solid var(--navy);
    table-layout: fixed;
}

.scorecard-table .out-column,
.scorecard-table .in-column,
.scorecard-table .total-column {
    background-color: var(--gray-200);
    width: 2.5rem;
}

.scorecard-table thead tr th {
    color: var(--gray-500);
    text-transform: uppercase;
}

.scorecard-table th,
.scorecard-table td {
    padding: 0.85rem 0.5rem;
    text-align: center;
    border-bottom: 1px solid var(--gray-350);
    border-left: none;
    border-right: none;
    min-width: 2.5rem;
}

.scorecard-table .hole-header,
.scorecard-table .heading-cell {
    width: auto;
    min-width: 3.5rem;
    max-width: 4rem;
    text-align: left;
    padding-left: 0.5rem;
    white-space: nowrap;
}

.scorecard-table td:first-child,
.scorecard-table thead tr th:first-child {
    text-align: left;
}

.scorecard-table th {
    background-color: var(--gray-100);
    font-weight: 600;
}

.heading-cell {
    color: var(--gray-500);
    text-transform: uppercase;
    font-weight: 600;
    text-align: left;
}

.heading-cell.dark {
    color: var(--text);
}

.par-row,
.yards-row {
    background-color: var(--surface-3);
    color: var(--gray-500);
}

.scorecard-table .par-row td {
    border-bottom: 2px solid var(--gray-400);
    padding-bottom: 0.85rem;
}

/* HCP (stroke index) row under PAR — same muted block, slightly smaller digits.
   It takes over the par block's heavy divider; when present, the PAR row's own
   border softens so PAR + HCP read as one header block. */
.scorecard-table .hcp-row {
    background-color: var(--surface-3);
    color: var(--gray-500);
}

.scorecard-table .hcp-row td {
    border-bottom: 2px solid var(--gray-400);
    font-size: 0.9em;
}

.scorecard-table tr.par-row:has(+ tr.hcp-row) td {
    border-bottom: 1px solid var(--gray-350);
}

.scorecard-table .score-row td {
    padding-top: 1rem;
    padding-bottom: 1rem;
    position: relative;
}

/* `tr.net-row` (specificity 0,2,2) intentionally outranks `.scorecard-table
   .score-row td` (0,2,1) so the net row keeps its own generous top padding —
   the score marks are absolutely-positioned and vertically centered, so each
   row must be tall enough or adjacent marks (gross vs net) overlap. */
/* Padding kept symmetric so the numeral stays vertically centred inside the
   mark — the mark is centred on the cell's padding box, so unequal top/bottom
   padding would shift the text off-centre. */
.scorecard-table tr.net-row td {
    padding-top: 0.85rem;
    padding-bottom: 0.85rem;
    font-style: italic;
    color: var(--gray-700);
}

/* ===== Score Indicators (Circles & Squares) =====
   Broadcast-style scorecard marks: birdie = filled red circle, eagle-or-better
   = filled red double circle, bogey = black square outline, double-bogey-or-worse
   = black double square. The shapes are drawn with pseudo-elements that sit BEHIND
   the numeral (z-index:-1). The score-entry table reuses these classes but hides
   the shapes (see `.score-entry-table .birdie::before { display:none }` below), so
   the fill / numeral-colour rules are scoped with :not(.score-entry-table). */
.birdie,
.eagle,
.bogey,
.double-bogey {
    position: relative;
    z-index: 1;
}

.birdie::before {
    content: '';
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 26px;
    height: 26px;
    border-radius: 50%;
    background-color: #d32f2f;
    z-index: -1;
}

.eagle::before, .eagle::after {
    content: '';
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    border-radius: 50%;
    z-index: -1;
}

/* eagle: outer ring + inner filled disc = double circle */
.eagle::before {
    width: 32px;
    height: 32px;
    border: 1.5px solid #d32f2f;
}

.eagle::after {
    width: 26px;
    height: 26px;
    background-color: #d32f2f;
}

.bogey::before {
    content: '';
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 26px;
    height: 26px;
    background-color: var(--ink);
    z-index: -1;
}

/* double bogey: concentric rings from the outside in — thin black border,
   thin white border, then the black fill. Done on a single border-box square:
   the black `border` is the outer ring, the inset white box-shadow is the
   middle ring, and the black `background` is the fill. */
.double-bogey::before {
    content: '';
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    z-index: -1;
    width: 26px;
    height: 26px;
    box-sizing: border-box;
    background-color: var(--ink);
    border: 1.5px solid var(--ink);
    box-shadow: inset 0 0 0 1.5px var(--white);
}

/* All four marks are filled (red circles / --ink squares), so the numeral must
   contrast with its fill. The red circles never invert → white numeral (--on-solid).
   The --ink squares DO invert (dark in light mode, light in dark mode) → the numeral
   must invert with them (--on-ink = --surface: white on the dark square, dark on the
   light one). Excluded from the score-entry table, which hides the shapes entirely. */
.scorecard-table:not(.score-entry-table) .birdie,
.scorecard-table:not(.score-entry-table) .eagle {
    color: var(--on-solid);
    font-weight: 700;
}

.scorecard-table:not(.score-entry-table) .bogey,
.scorecard-table:not(.score-entry-table) .double-bogey {
    color: var(--on-ink);
    font-weight: 700;
}

.scorecard-table .birdie,
.scorecard-table .eagle,
.scorecard-table .par,
.scorecard-table .bogey,
.scorecard-table .double-bogey {
    background-color: inherit;
}

/* ===== Scorecard Scoring Key (legend) ===== */
.scorecard-legend {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 1rem 1.5rem;
    margin-top: 1.25rem;
    padding-top: 1rem;
    border-top: 1px solid var(--gray-200);
    font-size: 0.8rem;
    color: var(--gray-700);
}

.scorecard-legend .legend-item {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    white-space: nowrap;
}

.scorecard-legend .legend-swatch {
    flex: 0 0 auto;
    width: 14px;
    height: 14px;
    box-sizing: border-box;
}

/* Birdie: filled red circle */
.scorecard-legend .birdie-swatch {
    border-radius: 50%;
    background-color: #d32f2f;
}

/* Eagle or better: filled red double circle (disc + outer ring via box-shadow) */
.scorecard-legend .eagle-swatch {
    width: 10px;
    height: 10px;
    margin: 2px;
    border-radius: 50%;
    background-color: #d32f2f;
    box-shadow: 0 0 0 1.5px var(--white), 0 0 0 3px #d32f2f;
}

/* Bogey: filled black square */
.scorecard-legend .bogey-swatch {
    background-color: var(--ink);
}

/* Double bogey or worse: black border, white border, then black fill */
.scorecard-legend .double-bogey-swatch {
    box-sizing: border-box;
    background-color: var(--ink);
    border: 1.5px solid var(--ink);
    box-shadow: inset 0 0 0 1.5px var(--white);
}

@media (max-width: 768px) {
    .scorecard-legend {
        gap: 0.6rem 1rem;
        font-size: 0.72rem;
    }
}

/* ===== Handicap Stroke Dots =====
   Sourced from the scorecard's per-hole strokes-received map, so they render on every hole the
   player gets (or gives back) a stroke — including holes with no score yet and a completely
   empty pre-round card. Two placements: tucked into the cell's top-right once a score lands,
   centred in the cell before that. The cell must be position:relative for either to anchor. */
.stroke-dots {
    display: flex;
    gap: 2px;
    position: absolute;
    top: 6px;
    right: 5px;
}

/* No score yet on this hole: center the dots under the hole instead of the top-right corner. */
.stroke-dots.stroke-dots-centered {
    top: 50%;
    left: 50%;
    right: auto;
    transform: translate(-50%, -50%);
    justify-content: center;
}

/* --stroke-dot rather than the old hardcoded #333, which was invisible on the dark board.
   .giving (a plus handicap handing strokes back) stays on the under-par red in both themes. */
.stroke-dot {
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background-color: var(--stroke-dot);
}

.stroke-dot.giving {
    background-color: var(--under-par);
}

/* .player-stat-boxes / .stat-box are gone: the Scorecard tab's four boxes became the .psc-rail
   baseline rail and the Stats tab's became the standing rail / phone tiles. .stat-label and
   .stat-value went with them once EventDashboard — their last caller — was retired
   (DASHBOARD-RETIREMENT-PLAN.md Phase 3). */

/* .stat-section and .stats-detail-table are gone — the Stats tab is now the standing rail +
   scoring spread + performance row, and Highlights is the ledger list. Both are .psc-* below. */

/* ===== Money Leader Section ===== */
.money-leader-section {
    margin: var(--space-5) 0;
    text-align: left;
}

.money-leader-section h2 {
    margin-bottom: var(--space-3);
    font-size: 1.5rem;
    color: var(--text);
}

.leader-card {
    background-color: var(--gray-150);
    border-radius: 8px;
    padding: var(--space-5);
    box-shadow: 0 2px 4px rgba(0,0,0,0.1);
    max-width: 500px;
}

.leader-name {
    font-size: 1.4rem;
    font-weight: bold;
    margin-bottom: var(--space-1);
}

.leader-total {
    font-size: 1.8rem;
    font-weight: bold;
    margin-bottom: var(--space-4);
}

.leader-details {
    display: flex;
    justify-content: space-between;
    flex-wrap: wrap;
}

.leader-detail {
    margin-right: var(--space-5);
    margin-bottom: var(--space-3);
}

.detail-label {
    color: var(--gray-650);
    margin-right: var(--space-1);
    text-transform: uppercase;
    font-weight: 600;
}

.detail-value {
    font-weight: bold;
}

/* ===== Player Rankings Section ===== */
.player-rankings-section {
    margin: var(--space-6) 0;
    text-align: left;
}

.player-rankings-section h3 {
    margin-bottom: var(--space-4);
    font-size: 1.2rem;
    color: var(--text);
}

.rankings-table-wrapper {
    max-width: 500px;
}

.rankings-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.9rem;
}

.rankings-table th,
.rankings-table td {
    padding: var(--space-2) var(--space-3);
    border-bottom: 1px solid var(--gray-350);
    text-align: left;
}

.rankings-table th {
    font-weight: bold;
    color: var(--gray-650);
    text-transform: uppercase;
    font-size: 0.8rem;
}

.rankings-table th:last-child,
.rankings-table td:last-child {
    text-align: right;
}

/* ===== Sort Indicator ===== */
.sort-indicator {
    margin-left: 3px;
    font-size: 0.7rem;
}

.participation-indicator {
    margin-left: 0.4rem;
    font-size: 0.75rem;
    color: #777;
    font-weight: 600;
    letter-spacing: 0.02em;
}

.skipped-pot {
    color: var(--gray-600);
    font-style: italic;
    font-size: 0.85rem;
}

/* Live win-probability chip on the leaderboard (ELEVATION-PLAN L2). A compact accent pill next to
   the player's name showing their current chance to win; updates as scores are entered. */
.winprob-chip {
    display: inline-block;
    margin-left: var(--space-2);
    padding: 0.05rem 0.4rem;
    border-radius: var(--radius-pill);
    background: var(--color-accent);
    color: var(--on-solid);
    font-size: 0.7rem;
    font-weight: 700;
    line-height: 1.4;
    letter-spacing: 0.02em;
    vertical-align: middle;
    white-space: nowrap;
}

.winprob-legend {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin-bottom: var(--space-3);
    font-size: 0.8rem;
    color: var(--text-muted);
}

.winprob-legend__dot {
    width: 0.55rem;
    height: 0.55rem;
    border-radius: var(--radius-pill);
    background: var(--color-accent);
    flex-shrink: 0;
    animation: winprob-pulse 1.6s ease-in-out infinite;
}

@keyframes winprob-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.35; }
}

.moment-chip {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-1) var(--space-3) var(--space-1) var(--space-1);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-pill);
    white-space: nowrap;
    flex-shrink: 0;
    animation: moment-pop 0.35s ease-out;
}

/* Rarer feats get a colored rim so an eagle/ace pops out of a run of birdies. */
.moment-chip--eagle,
.moment-chip--albatross { border-color: var(--color-accent); }
.moment-chip--ace { border-color: var(--warning); }

.moment-chip__badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.6rem;
    height: 1.6rem;
    border-radius: var(--radius-pill);
    background: var(--surface-subtle);
    font-size: 0.85rem;
    flex-shrink: 0;
}

.moment-chip__text {
    display: flex;
    flex-direction: column;
    line-height: 1.15;
}

.moment-chip__text strong { font-size: 0.8rem; }

.moment-chip__detail {
    font-size: 0.68rem;
    color: var(--text-muted);
}

@keyframes moment-pop {
    from { opacity: 0; transform: translateY(-3px) scale(0.96); }
    to { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
    .moment-chip { animation: none; }
}

/* Odds-page form / course-fit badges. Small tinted pills flagging players the past-performance
   model nudged (recent form or history at this venue). Hover shows the stroke detail. */
.odds-form-badges {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1);
    margin-top: var(--space-1);
}

.form-badge {
    display: inline-block;
    padding: 0.05rem 0.4rem;
    border: none;
    border-radius: var(--radius-pill);
    font-family: inherit;
    font-size: 0.72rem;
    font-weight: 600;
    line-height: 1.5;
    white-space: nowrap;
}

/* The badge is a <button> in the odds table (tap opens a detail sheet); a plain <span> elsewhere. */
button.form-badge { cursor: pointer; }

.form-badge--hot { background: color-mix(in srgb, var(--danger) 16%, transparent); color: var(--danger); }
.form-badge--cold { background: color-mix(in srgb, var(--info) 16%, transparent); color: var(--info); }
.form-badge--venue-good { background: color-mix(in srgb, var(--color-accent) 16%, transparent); color: var(--color-accent); }
.form-badge--venue-bad { background: color-mix(in srgb, var(--text-muted) 16%, transparent); color: var(--text-muted); }

/* Badge-detail bottom sheet (tap-to-explain on the odds page). */
.badge-detail { padding: var(--space-3) var(--space-4) var(--space-4); }
.badge-detail-row {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    margin-bottom: var(--space-3);
}
.badge-detail-row .form-badge { align-self: flex-start; }
.badge-detail-row p { margin: 0; color: var(--text); line-height: 1.45; }
.badge-detail-note {
    margin: 0;
    padding-top: var(--space-2);
    border-top: 1px solid var(--border);
    color: var(--text-muted);
    font-size: 0.85em;
}

/* The AI round recap's old vocabulary — .recap-card / -meta / -actions / -actions-hint / -empty —
   lived here and had exactly one caller. The recap redesign replaced all five (23-recap.css), so
   they are deleted rather than left as a second way to draw the same screen. */

.info-note {
    margin-top: 0.75rem;
    padding: 0.5rem 0.75rem;
    background: var(--surface-3);
    border-left: 3px solid var(--gray-600);
    color: var(--gray-700);
    font-size: 0.9rem;
}

/* The Course Stats table lived here — .course-stats-table, .summary-row / .out-row / .in-row /
   .total-row, and .course-under-par / .course-over-par. All gone: the screen is a grid board on
   the leaderboard's language now (25-course-stats.css). The two colour rules were also backwards
   for this app — green meant "under par" on the one screen where --under-par (red) is the
   convention everywhere else — so they were not carried forward. */

/* ===== Scorecard Mobile ===== */
@media (max-width: 768px) {
    .desktop-scorecard {
        display: none;
    }

    .mobile-scorecard {
        display: block;
    }

    .scorecard-table.front-nine {
        margin-bottom: 0;
    }

    .scorecard-table.back-nine {
        border-top: 3px solid var(--navy);
        margin-top: 0;
    }

    .scorecard-table th,
    .scorecard-table td {
        padding: 0.7rem 0.1rem;
    }

    .scorecard-table .score-row td {
        padding-top: 0.9rem;
        padding-bottom: 0.9rem;
    }

    /* Net row keeps clear separation from the gross row above (see desktop note);
       symmetric so the numeral stays centred inside the mark. */
    .scorecard-table tr.net-row td {
        padding-top: 0.8rem;
        padding-bottom: 0.8rem;
    }

    .scorecard-table {
        font-size: 0.7rem;
    }

    .scorecard-table .hole-header,
    .scorecard-table .heading-cell {
        min-width: 3rem;
        max-width: 3.5rem;
    }

    .scorecard-table .hole-header {
        min-width: 100px;
    }

    /* Leaderboard mobile scorecard: table-layout is fixed, so only explicit widths on
       the header row size the columns — everything else splits the leftover evenly.
       The label and totals columns only need ~2rem at this font size; every pixel
       trimmed here goes to the nine hole columns so score marks stop crowding. */
    .mobile-scorecard .scorecard-table .hole-header {
        width: 2.2rem;
        min-width: 0;
        max-width: none;
    }

    .mobile-scorecard .scorecard-table .out-column,
    .mobile-scorecard .scorecard-table .in-column,
    .mobile-scorecard .scorecard-table .total-column {
        width: 2rem;
        min-width: 0;
    }

    /* Marks step down a touch in the stacked tables (numerals keep their size) so
       adjacent circles/squares clear each other in the narrower back-nine cells. */
    .mobile-scorecard .birdie::before,
    .mobile-scorecard .bogey::before {
        width: 20px;
        height: 20px;
    }

    .mobile-scorecard .eagle::before {
        width: 26px;
        height: 26px;
    }

    .mobile-scorecard .eagle::after {
        width: 20px;
        height: 20px;
    }

    .mobile-scorecard .double-bogey::before {
        width: 22px;
        height: 22px;
    }

    .birdie::before,
    .bogey::before {
        width: 22px;
        height: 22px;
    }

    /* eagle: inner disc matches the birdie circle (22px) so it isn't visually
       smaller; outer ring sits 6px outside it to read as a double circle. */
    .eagle::before {
        width: 28px;
        height: 28px;
    }

    .eagle::after {
        width: 22px;
        height: 22px;
    }

    .double-bogey::before {
        width: 24px;
        height: 24px;
    }

    .stroke-dots {
        top: 3px;
        right: 2px;
        gap: 1px;
    }

    .stroke-dot {
        width: 4px;
        height: 4px;
    }

    .leader-details {
        flex-direction: column;
    }

    .leader-detail {
        margin-bottom: var(--space-2);
    }

    .course-info h4 {
        font-size: 1rem;
    }
}

/* ===== Score Entry ===== */
.score-entry-card {
    max-width: 100%;
    overflow-x: auto;
}

.score-entry-table .score-input {
    width: 100%;
    box-sizing: border-box;
    padding: 0.2rem;
    text-align: center;
    border: 1px solid var(--gray-350);
    border-radius: 3px;
    font-size: 0.85rem;
    background: var(--white);
    -moz-appearance: textfield;
}

.score-entry-table .score-input::-webkit-outer-spin-button,
.score-entry-table .score-input::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

.score-entry-table .score-input:focus {
    outline: none;
    border-color: var(--navy);
    box-shadow: 0 0 0 2px rgba(44, 62, 80, 0.15);
}

.score-entry-table .ndb-exceeded .score-input {
    border-color: #e67e22;
    background: #fff3e0;
    color: #b35900;
    font-weight: 600;
}

.score-entry-table .ndb-exceeded .score-input:focus {
    border-color: #e67e22;
    box-shadow: 0 0 0 2px rgba(230, 126, 34, 0.25);
}

.ndb-legend {
    margin-top: 0.5rem;
    font-size: 0.8rem;
    color: var(--slate-500);
}

.ndb-legend .ndb-swatch {
    display: inline-block;
    width: 0.85rem;
    height: 0.85rem;
    background: #fff3e0;
    border: 1px solid #e67e22;
    border-radius: 2px;
    vertical-align: middle;
    margin-right: 0.35rem;
}

.score-entry-table .birdie::before,
.score-entry-table .eagle::before,
.score-entry-table .eagle::after,
.score-entry-table .bogey::before,
.score-entry-table .double-bogey::before,
.score-entry-table .double-bogey::after {
    display: none;
}

.score-entry-table .score-input::placeholder {
    color: transparent;
}

.score-entry-table td {
    padding: 0.35rem 0.15rem;
}

.score-entry-table .player-name-cell {
    width: 160px;
    min-width: 160px;
    max-width: 160px;
    overflow: hidden;
    white-space: normal;
    font-size: 0.85rem;
    line-height: 1.15;
    vertical-align: middle;
    padding: 0.4rem 0.5rem;
}

.score-entry-table .player-name-line {
    font-weight: 600;
    color: var(--text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.score-entry-table .player-meta-line {
    display: flex;
    gap: 0.35rem;
    align-items: center;
    flex-wrap: wrap;
    margin-top: 0.15rem;
    font-size: 0.7rem;
    color: var(--slate-500);
    text-transform: none;
    font-weight: 500;
}

.score-entry-table .player-hcp-chip {
    background: var(--surface-2);
    color: var(--text);
    border-radius: 3px;
    padding: 0 0.35rem;
    line-height: 1.4;
    letter-spacing: 0;
}

.score-entry-table .player-meta-line .tee-indicator {
    color: var(--slate-500);
    font-size: 0.7rem;
}

.score-entry-table .player-status-line {
    margin-top: 0.2rem;
}

/* Override the .scorecard-table .hole-header max-width inside score entry so
   the player-name column has room for full names + Hcp chip. */
.score-entry-table .hole-header {
    width: 160px;
    min-width: 160px;
    max-width: 160px;
}

/* Net row inside score entry: per-hole net value with small "net" label, italic muted styling. */
.score-entry-table .net-row td {
    padding-top: 0.15rem;
    padding-bottom: 0.5rem;
    border-bottom: 1px solid var(--gray-350);
    font-style: italic;
    color: var(--gray-700);
    background-color: var(--surface-3);
}

.score-entry-table .score-row td {
    border-bottom: none;
}

.score-entry-table .net-row .net-cell {
    line-height: 1;
}

.score-entry-table .net-row .net-label {
    display: block;
    font-size: 0.55rem;
    color: var(--gray-500);
    text-transform: uppercase;
    letter-spacing: 0.03em;
    font-style: normal;
    line-height: 1;
    margin-bottom: 0.1rem;
}

.score-entry-table .net-row .net-value {
    display: block;
    font-size: 0.8rem;
    font-style: normal;
    font-weight: 500;
}

.score-entry-table .net-row .out-column,
.score-entry-table .net-row .in-column,
.score-entry-table .net-row .total-column {
    font-style: normal;
    font-weight: 600;
}

.score-entry-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-top: 1rem;
    padding-top: 0.75rem;
    border-top: 1px solid var(--gray-200);
}

/* Inside a .set-card (the Scores pane's card--grid) the card has no padding of its own — the
   label, the head and the foot each carry theirs — so the two blocks that sit loose between the
   grid and the footer take the card's 20px gutter here rather than hugging its edges. The grid
   itself is deliberately untouched; this is framing, not a restyle of the scorecard. */
.set-card > .score-entry-actions {
    margin-top: 0;
    padding: 12px 20px;
    border-top-color: var(--hairline-soft);
}
.set-card > .ndb-legend { padding: 0 20px 12px; margin-top: 0; }
.set-card > .scorecard { padding: 0 20px; }

@media (max-width: 767px) {
    .set-card > .score-entry-actions { padding: 12px 16px; }
    .set-card > .ndb-legend { padding: 0 16px 12px; }
    .set-card > .scorecard { padding: 0 16px; }
}

/* `.group-nav` / `.group-nav-label` are gone: the two same-weight ← Prev / Next → buttons became
   one `.set-pager` in the card's context header, reading "2 / 4". The arrows never said how many
   groups there were, which is the fact you need before you start tabbing through them. */

.save-indicator {
    color: var(--color-accent);
    font-size: 0.75rem;
    margin-left: 0.25rem;
}

/* .over-par / .under-par are defined once near the top of this file under
   "Score Coloring" — traditional scorecard convention: under-par is red, over-par
   is default text. The earlier override here that inverted them has been removed. */

/* ===== Score Entry — Mobile (touch-optimized, hole-by-hole) ===== */
.score-entry-mobile {
    display: none;
}

.mobile-group-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    padding-bottom: 0.75rem;
    margin-bottom: 0.5rem;
    border-bottom: 1px solid var(--gray-200);
}

.mobile-group-label {
    font-weight: 600;
    color: var(--text);
    font-size: 0.95rem;
    text-align: center;
    flex: 1;
}

.mobile-hole-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 0.5rem 0;
}

.mobile-hole-display {
    text-align: center;
    flex: 1;
}

.mobile-hole-number {
    font-size: 1.4rem;
    font-weight: 700;
    color: var(--text);
    line-height: 1.2;
}

.mobile-hole-par {
    font-size: 0.9rem;
    color: var(--gray-650);
    margin-top: 0.1rem;
}

.mobile-hole-yardage {
    font-size: 1.6rem;
    font-weight: 700;
    color: var(--text);
    margin-top: 0.35rem;
    line-height: 1.1;
}

.mobile-hole-tee {
    font-size: 0.85rem;
    color: var(--gray-700);
    margin-top: 0.05rem;
}

.mobile-hole-other-tees {
    font-size: 0.75rem;
    color: var(--gray-600);
    margin-top: 0.25rem;
    line-height: 1.3;
}

.mobile-arrow-btn {
    width: 48px;
    height: 48px;
    border-radius: 8px;
    border: 1px solid var(--gray-400);
    background: var(--white);
    color: var(--text);
    font-size: 1.2rem;
    font-weight: 600;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    transition: background 0.15s;
}

.mobile-arrow-btn:disabled {
    opacity: 0.35;
    cursor: not-allowed;
}

.mobile-arrow-btn:not(:disabled):active {
    background: var(--surface-2);
}

.mobile-hole-arrow {
    background: var(--navy);
    color: white;
    border-color: var(--navy);
}

.mobile-hole-arrow:not(:disabled):active {
    background: var(--navy-dark);
}

.mobile-progress-track {
    height: 4px;
    background: var(--gray-300);
    border-radius: 2px;
    margin: 0.25rem 0 0.75rem;
    overflow: hidden;
}

.mobile-progress-fill {
    height: 100%;
    background: var(--color-accent);
    transition: width 0.3s;
}

.mobile-player-card {
    padding: 0.75rem 0;
    border-bottom: 1px solid var(--gray-200);
}

.mobile-player-card:last-of-type {
    border-bottom: none;
}

.mobile-player-card.inactive {
    opacity: 0.55;
}

.mobile-player-header {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 0.5rem;
    margin-bottom: 0.5rem;
}

.mobile-player-name {
    /* Allow the name column to shrink/wrap so a long name + WD/DNS badge doesn't push
       the running totals off the row. (Not ellipsis — that would clip the status badge.) */
    min-width: 0;
    font-weight: 600;
    color: var(--text);
    font-size: 1rem;
}

.mobile-player-running {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 0.15rem;
    font-size: 0.85rem;
}

.mobile-running-line {
    display: flex;
    gap: 0.4rem;
    align-items: baseline;
}

.mobile-running-net {
    font-size: 0.8rem;
    color: var(--gray-700);
}

.mobile-running-net-label {
    text-transform: uppercase;
    font-size: 0.65rem;
    letter-spacing: 0.05em;
    color: var(--gray-600);
    font-weight: 600;
}

.mobile-running-total {
    font-weight: 700;
    color: var(--text);
}

.mobile-running-ou {
    font-weight: 600;
}

.mobile-running-holes {
    color: var(--gray-600);
    font-size: 0.8rem;
}

/* Inline stroke dots next to a player's name (score entry / live scoring). Plain round dots,
   no pill container: black .stroke-dot when receiving, red .stroke-dot.giving when a plus
   handicap gives a stroke back. Slightly larger than the leaderboard cell dots so they read
   next to name text. */
.stroke-dots-inline {
    display: inline-flex;
    gap: 3px;
    margin-left: 0.4rem;
    vertical-align: middle;
}

.stroke-dots-inline .stroke-dot {
    width: 7px;
    height: 7px;
}

.mobile-quick-pick {
    display: flex;
    gap: 0.4rem;
    align-items: center;
}

/* Flex-centred rather than relying on a button's own text-align: the selected state puts a
   block-level .score-mark inside, which text-align cannot centre. Geometry is unchanged. */
.mobile-pick-btn {
    flex: 1;
    min-width: 0;
    height: 52px;
    border-radius: 8px;
    border: 2px solid var(--gray-350);
    background: var(--surface);
    color: var(--text);
    font-size: 1.3rem;
    font-weight: 700;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    user-select: none;
    transition: transform 0.1s, background 0.15s;
}

.mobile-pick-btn:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

.mobile-pick-btn:not(:disabled):active {
    transform: scale(0.95);
}

/* No .par-btn rule: outlining the tile whose value equals par read as "already selected", and
   people left holes unentered believing they were in. Par is not special until it is tapped. */

.mobile-pick-btn.selected {
    background: var(--surface-inverse);
    border-color: var(--surface-inverse);
    color: var(--on-solid);
}

/* The mark, at this surface's 52px tile. Rules for which borders draw live in
   12-live-scoring.css beside .score-mark — one definition, two hosts. */
.mobile-pick-btn .score-mark { width: 34px; height: 34px; }
.mobile-pick-btn .score-mark__inner { width: 26px; height: 26px; }
.mobile-pick-expanded-btn .score-mark { width: 30px; height: 30px; }
.mobile-pick-expanded-btn .score-mark__inner { width: 23px; height: 23px; }

.mobile-pick-btn.ndb-warning {
    box-shadow: inset 0 0 0 2px var(--warning);
}

.mobile-pick-more {
    width: 52px;
    height: 52px;
    border-radius: 8px;
    border: 2px dashed var(--gray-400);
    background: var(--surface-3);
    color: var(--gray-600);
    font-size: 1.2rem;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}

.mobile-pick-more:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

.mobile-pick-more.expanded {
    border-style: solid;
    border-color: var(--navy);
    background: var(--gray-200);
}

/* The more-tile with an out-of-range score: a selected tile, not coloured text on a dashed one. */
.mobile-pick-more.selected {
    border-style: solid;
    background: var(--surface-inverse);
    border-color: var(--surface-inverse);
    color: var(--on-solid);
    font-weight: 700;
}

.mobile-pick-expanded {
    display: grid;
    grid-template-columns: repeat(6, 1fr);
    gap: 0.35rem;
    margin-top: 0.5rem;
}

.mobile-pick-expanded-btn {
    flex: none;
    height: 44px;
    font-size: 1.05rem;
}

.mobile-ndb-warning {
    margin-top: 0.5rem;
    padding: 0.4rem 0.6rem;
    background: #fff3e0;
    border-left: 3px solid #e67e22;
    color: #b35900;
    font-size: 0.8rem;
    border-radius: 0 4px 4px 0;
}

.mobile-inactive-note {
    color: var(--gray-600);
    font-size: 0.85rem;
    font-style: italic;
    padding: 0.25rem 0;
}

@media (max-width: 768px) {
    .score-entry-table .score-input {
        font-size: 0.75rem;
    }

    .score-entry-table .player-name-cell {
        min-width: 70px;
        max-width: 100px;
        font-size: 0.7rem;
    }

    .score-entry-table td {
        padding: 0.25rem 0.1rem;
    }

    .score-entry-desktop {
        display: none;
    }

    .score-entry-mobile {
        display: block;
    }
}

/* ===== Setup Guide ===== */
/* Get-started banner shown on an empty leaderboard for the commissioner. */
.setup-cta-banner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    background: var(--surface-2);
    border: 1px solid #cfe3fb;
    border-radius: 8px;
    padding: 1rem 1.25rem;
    margin-bottom: 1rem;
}

.setup-cta-text h3 {
    margin: 0 0 0.25rem;
    color: var(--text);
}

.setup-cta-text p {
    margin: 0;
    color: var(--gray-700);
    font-size: 0.92rem;
}

.setup-cta-banner .btn {
    flex: 0 0 auto;
}

.setup-cta-actions {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex-wrap: wrap;
}

.setup-step-wizard-hint {
    margin-top: 0.25rem;
    font-size: 0.8rem;
    color: var(--text-muted);
}

.setup-step-wizard-hint a {
    color: var(--color-accent);
}

.setup-intro {
    color: var(--gray-650);
    margin: 0 0 1rem;
    line-height: 1.5;
}

.setup-progress {
    margin-bottom: 1.25rem;
}

.setup-progress-bar {
    height: 8px;
    background: var(--surface-2);
    border-radius: 999px;
    overflow: hidden;
}

.setup-progress-fill {
    height: 100%;
    background: var(--color-accent);
    border-radius: 999px;
    transition: width 0.3s ease;
}

.setup-progress-label {
    margin-top: 0.4rem;
    font-size: 0.85rem;
    color: var(--gray-600);
    font-weight: 500;
}

.setup-steps {
    list-style: none;
    margin: 0 0 1.25rem;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}

.setup-step {
    display: flex;
    align-items: center;
    gap: 1rem;
    background: var(--surface);
    border: 1px solid var(--gray-300);
    border-radius: 8px;
    padding: 1rem;
}

.setup-step.next {
    border-color: var(--navy);
    box-shadow: 0 2px 8px rgba(44, 62, 80, 0.12);
}

.setup-step-marker {
    flex: 0 0 auto;
    width: 2rem;
    height: 2rem;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 700;
    background: var(--surface-2);
    color: #607d8b;
}

.setup-step.complete .setup-step-marker {
    background: var(--color-accent);
    color: white;
}

.setup-step.next .setup-step-marker {
    background: var(--navy);
    color: white;
}

.setup-step-body {
    flex: 1 1 auto;
    min-width: 0;
}

.setup-step-title {
    font-weight: 600;
    color: var(--text);
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.setup-step-pill {
    font-size: 0.65rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    background: var(--navy);
    color: white;
    padding: 0.1rem 0.4rem;
    border-radius: 999px;
}

.setup-step-blurb {
    font-size: 0.9rem;
    color: var(--gray-650);
    margin-top: 0.2rem;
    line-height: 1.4;
}

.setup-step-action {
    flex: 0 0 auto;
}

.setup-step-optional {
    border: none;
    padding: 0;
}

.setup-footer {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    margin-top: 0.5rem;
}

@media (max-width: 600px) {
    .setup-step {
        flex-wrap: wrap;
    }

    .setup-step-action {
        flex-basis: 100%;
    }

    .setup-step-action .btn {
        width: 100%;
    }
}

/* ===== Live Scoring (Mobile) =====
   The on-course screen (/score/{token}) plus the pieces the anonymous Landing page
   borrows from it. Redesigned per handoffs/design_handoff_mobile_scoring: a broadcast
   header on a dark ground, one raised card of player rows on a page ground, a pinned
   metal contest strip that opens a bottom sheet, and a fixed bottom bar.

   Everything below the header references semantic tokens. The header itself is a DARK
   SURFACE IN BOTH THEMES — the same rule --masthead-scrim follows — so its ink is
   absolute hex, declared once as local custom properties on .lvs-header rather than
   scattered through the block. Light mode's --metal (#8a6d33) would be all but
   invisible on a #10151a ground, which is why the champagne values are the drawn ones
   in both themes here. */

.minimal-layout {
    max-width: 480px;
    margin: 0 auto;
    padding: 0;
    min-height: 100dvh;
    background: var(--surface);
}

/* Loading state */
.live-loading {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    min-height: 100dvh;
    gap: 1rem;
    color: var(--text-muted);
}

/* Invalid state */
.live-invalid {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    min-height: 100dvh;
    padding: 2rem;
    text-align: center;
}

.live-invalid-icon {
    font-size: 3rem;
    margin-bottom: 1rem;
}

.live-invalid h2 {
    font-size: 1.3rem;
    margin-bottom: 0.5rem;
    color: var(--text);
}

.live-invalid p {
    color: var(--text-muted);
    font-size: 0.95rem;
    line-height: 1.5;
}

/* ===== Landing page (anonymous, list of in-progress rounds + group scoring links) =====
   Kept on its own vocabulary — the scoring redesign is out of scope for it, and these
   three .live-confirm-* rules are its header + empty-state card. */
.live-confirm-header {
    text-align: center;
    margin-bottom: 1.5rem;
}

.live-confirm-icon {
    font-size: 2.5rem;
    margin-bottom: 0.5rem;
}

.live-confirm-header h2 {
    font-size: 1.3rem;
    color: var(--text);
    margin: 0;
}

.live-confirm-card {
    background: var(--surface-subtle);
    border-radius: var(--radius-md);
    padding: 1rem 1.25rem;
    margin-bottom: 1rem;
}

.landing-page {
    padding: 1.5rem 1rem 2rem;
    max-width: 600px;
    margin: 0 auto;
}

.landing-subtitle {
    color: var(--text-muted);
    font-size: 0.95rem;
    margin-top: 0.25rem;
}

.landing-empty {
    color: var(--text-muted);
    font-size: 0.95rem;
    margin: 0;
}

.landing-round {
    margin-bottom: 1.75rem;
}

.landing-round-header {
    display: flex;
    align-items: baseline;
    gap: 0.5rem;
    flex-wrap: wrap;
    padding: 0 0.25rem 0.5rem;
    border-bottom: 1px solid var(--border);
    margin-bottom: 0.75rem;
}

.landing-round-day {
    font-weight: 700;
    color: var(--text);
    font-size: 1rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.landing-round-course {
    font-weight: 600;
    color: var(--text);
    font-size: 1.05rem;
}

/* Accent, because a round being played right now is the app's one "live" meaning. Sits beside the
   Scramble pill, which is a neutral solid — a format is not a state. */
.landing-round-live {
    font-size: 0.75rem;
    font-weight: 700;
    background: var(--color-accent);
    color: var(--on-hue);
    padding: 0.15rem 0.5rem;
    border-radius: var(--radius-sm);
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.landing-round-format {
    font-size: 0.75rem;
    background: var(--surface-inverse);
    color: var(--on-solid);
    padding: 0.15rem 0.5rem;
    border-radius: var(--radius-sm);
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.landing-group-link {
    display: block;
    background: var(--surface-subtle);
    border-radius: var(--radius-md);
    padding: 0.9rem 1rem;
    margin-bottom: 0.6rem;
    color: var(--text);
    text-decoration: none;
    border: 1px solid transparent;
    transition: background 0.15s, border-color 0.15s;
}

.landing-group-link:hover,
.landing-group-link:active {
    background: var(--gray-300);
    border-color: var(--surface-inverse);
}

.landing-group-title {
    font-weight: 600;
    font-size: 1rem;
    color: var(--text);
    margin-bottom: 0.25rem;
}

.landing-group-players {
    color: var(--text-muted);
    font-size: 0.95rem;
}

.landing-group-cta {
    margin-top: 0.5rem;
    color: var(--text);
    font-size: 0.85rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

/* ===================================================================
   THE HOLE SCREEN
   =================================================================== */

.live-scoring {
    display: flex;
    flex-direction: column;
    min-height: 100dvh;
    background: var(--page-ground);
}

/* --- A. Broadcast header ------------------------------------------------ */

.lvs-header {
    /* Dark in both themes — see the file header. These are the design's drawn values. */
    --lvs-ink: #fff;
    --lvs-ink-2: #c8cfd8;
    --lvs-ink-3: #aab2bc;
    --lvs-ink-4: #98a1ad;
    --lvs-metal: #c9ad6e;
    --lvs-metal-bright: #f2e4bf;
    --lvs-metal-line: rgba(201, 173, 110, 0.45);
    --lvs-metal-edge: rgba(201, 173, 110, 0.30);
    --lvs-metal-wash: rgba(201, 173, 110, 0.22);
    --lvs-under: #f78b92;
    --lvs-live: #3ad160;
    --lvs-live-ink: #9df0b4;
    --lvs-hairline: rgba(255, 255, 255, 0.18);
    /* The cold-start skeleton's shimmer pair. It cannot use the neutral ramp for the same reason
       the ink above is absolute: --surface-subtle is a LIGHT block, and this header is dark in both
       themes. Declared here beside --lvs-metal so the header's whole vocabulary is in one place. */
    --lvs-skel: #2a323b;
    --lvs-skel-lit: #39424d;

    position: sticky;
    top: 0;
    z-index: 50;
    padding: 0 var(--space-4);
    background: linear-gradient(180deg, #182027, #10151a);
    border-bottom: 1px solid var(--lvs-metal-edge);
    font-variant-numeric: tabular-nums;
}

/* Utility row — day, where you are, and whether the round is live. */
.lvs-util {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    height: 24px;
    min-width: 0;
}

.lvs-util__day {
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--lvs-metal);
    white-space: nowrap;
}

.lvs-util__rule {
    flex: none;
    width: 1px;
    height: 11px;
    background: var(--lvs-hairline);
}

.lvs-util__where {
    font-size: 11.5px;
    color: var(--lvs-ink-2);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* `.lvs-util__where--btn` is gone. The group line used to become the way out of scoring for the
   holder, which put the exit in the chrome, drew it as a dropdown chevron, and deleted it outright
   at five players — the dense header renders no group line at all. The exit is `.lvs-scorer`, in
   the card body, below. */

.lvs-live {
    margin-left: auto;
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 3px 9px 3px 7px;
    border-radius: var(--radius-pill);
    background: rgba(58, 209, 96, 0.18);
    border: 1px solid rgba(58, 209, 96, 0.42);
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: var(--lvs-live-ink);
}

.lvs-live__dot {
    width: 6px;
    height: 6px;
    border-radius: var(--radius-pill);
    background: var(--lvs-live);
    animation: lvs-live-pulse 2.4s ease-in-out infinite;
}

@keyframes lvs-live-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.35; }
}

@media (prefers-reduced-motion: reduce) {
    .lvs-live__dot { animation: none; }
}

/* Hole block — the numeral, the par chip and thru. */
.lvs-holeline {
    display: flex;
    align-items: flex-end;
    gap: 13px;
    padding: 4px 0 10px;
}

.lvs-hole {
    display: flex;
    align-items: baseline;
    gap: 7px;
}

.lvs-hole__label {
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--lvs-ink-3);
}

.lvs-hole__num {
    font-size: 46px;
    font-weight: 600;
    line-height: 0.85;
    letter-spacing: -0.04em;
    color: var(--lvs-ink);
}

.lvs-holemeta {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    padding-bottom: 2px;
    min-width: 0;
}

.lvs-parchip {
    align-self: flex-start;
    padding: 2px 8px;
    border-radius: 6px;
    background: var(--lvs-metal-wash);
    border: 1px solid var(--lvs-metal-line);
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--lvs-metal-bright);
    white-space: nowrap;
}

.lvs-holefacts {
    font-size: 12px;
    color: var(--lvs-ink-2);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.lvs-thru {
    margin-left: auto;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 2px;
    padding-bottom: 2px;
}

.lvs-thru__label {
    font-size: 9.5px;
    font-weight: 700;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--lvs-ink-3);
}

.lvs-thru__value {
    font-size: 16px;
    font-weight: 600;
    color: var(--lvs-ink);
    white-space: nowrap;
}

.lvs-thru__of {
    font-size: 11.5px;
    color: var(--lvs-ink-4);
}

/* The LEADING chip — this is the results affordance, not a decoration. */
/* The two-on-two standing (TEE-BOX-PLAN Phase 2). Inside the header, so it reads the header's own
   local ink rather than semantic tokens — this surface is dark in both themes.

   METAL, not the live green: being 2 up is a STANDING. Green here means live-or-money, and a match
   can be won without a pot at all. Same call the Matches tab's winner chip makes. */
.lvs-match {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 4px 8px;
    padding: 6px 11px;
    margin-bottom: 7px;
    border-radius: var(--radius-lg);
    border: 1px solid var(--lvs-metal-edge);
    background: var(--lvs-metal-wash);
}

.lvs-match__standing {
    font-size: 15px;
    font-weight: 800;
    letter-spacing: 0.04em;
    color: var(--lvs-metal-bright);
}

.lvs-match__who {
    font-size: 13px;
    font-weight: var(--font-weight-medium);
    color: var(--lvs-ink-2);
}

/* Pushed right so "thru 7" lands in the same place whether or not a leader is named. */
.lvs-match__thru {
    margin-left: auto;
    font-size: 12px;
    color: var(--lvs-ink-4);
}

/* A finished match stops shouting — it is a record now, not a thing in progress. */
.lvs-match--final { background: rgba(255, 255, 255, 0.06); border-color: rgba(255, 255, 255, 0.14); }
.lvs-match--final .lvs-match__standing { color: var(--lvs-metal); }

.lvs-lead {
    display: flex;
    align-items: center;
    gap: 9px;
    width: 100%;
    box-sizing: border-box;
    min-height: 40px;
    padding: 7px 11px;
    margin-bottom: 9px;
    border-radius: var(--radius-lg);
    border: 1px solid rgba(255, 255, 255, 0.14);
    background: rgba(255, 255, 255, 0.07);
    text-decoration: none;
    -webkit-tap-highlight-color: transparent;
}

.lvs-lead:active { background: rgba(255, 255, 255, 0.12); }

.lvs-lead__label {
    flex: none;
    font-size: 9.5px;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--lvs-metal);
}

.lvs-lead__body {
    display: inline-flex;
    align-items: baseline;
    gap: 7px;
    min-width: 0;
}

.lvs-lead__pos {
    font-size: 10.5px;
    font-weight: 700;
    color: var(--lvs-metal);
}

.lvs-lead__name {
    font-size: 13.5px;
    font-weight: 600;
    color: var(--lvs-ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.lvs-lead__score {
    font-size: 15px;
    font-weight: 700;
    color: var(--lvs-ink);
}

.lvs-lead__score.under-par { color: var(--lvs-under); }

.lvs-lead__thru {
    font-size: 11px;
    color: var(--lvs-ink-4);
    white-space: nowrap;
}

.lvs-lead__more {
    margin-left: auto;
    font-size: 17px;
    color: var(--lvs-ink-3);
}

/* Progress — one segment per played hole. Entered = live green, current = metal,
   remaining = a white wash. Replaces the old single-fill progress bar. */
.lvs-progress {
    display: flex;
    gap: 2px;
    padding-bottom: 9px;
}

.lvs-progress__seg {
    flex: 1;
    height: 3px;
    border-radius: 2px;
    background: rgba(255, 255, 255, 0.16);
}

.lvs-progress__seg--done { background: var(--lvs-live); }
.lvs-progress__seg--current { background: var(--lvs-metal); }

/* Dense variant — five or more players. One 44px line: numeral, par, the facts, and a
   compact leader chip. The card's tiles shrink with it (.lvs-card--dense). */
.lvs-header--dense .lvs-dense {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    height: 44px;
    min-width: 0;
}

.lvs-dense__num {
    font-size: 26px;
    font-weight: 600;
    line-height: 1;
    letter-spacing: -0.03em;
    color: var(--lvs-ink);
}

.lvs-dense__par {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--lvs-metal);
    white-space: nowrap;
}

.lvs-dense__facts {
    font-size: 11.5px;
    color: var(--lvs-ink-2);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.lvs-lead--mini {
    width: auto;
    margin: 0 0 0 auto;
    min-height: 34px;
    padding: 5px 9px;
    border-radius: 9px;
    flex: none;
}

.lvs-lead--mini .lvs-lead__label { font-size: 9.5px; letter-spacing: 0.09em; }
.lvs-lead--mini .lvs-lead__name { font-size: 12.5px; }
.lvs-lead--mini .lvs-lead__score { font-size: 13px; }

/* --- B. Contest strip --------------------------------------------------- */

.lvs-body {
    flex: 1;
    padding: 10px 12px 0;
    /* Reserve room for the fixed bottom bar, including its safe-area inset, so the last
       row's tiles aren't hidden behind it. */
    padding-bottom: calc(86px + env(safe-area-inset-bottom));
}

.ctp-strip {
    display: flex;
    align-items: center;
    gap: 9px;
    width: 100%;
    box-sizing: border-box;
    min-height: 42px;
    padding: 9px 11px;
    margin-bottom: 10px;
    border-radius: 13px;
    border: 1px solid var(--metal-line);
    background: var(--metal-wash-16);
    font-family: inherit;
    text-align: left;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}

.ctp-strip__glyph {
    flex: none;
    font-size: 19px;
    color: var(--metal);
}

.ctp-strip__body {
    display: flex;
    align-items: baseline;
    gap: 7px;
    min-width: 0;
    flex-wrap: wrap;
}

.ctp-strip__label {
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--metal);
    white-space: nowrap;
}

.ctp-strip__value {
    font-size: 13px;
    font-weight: 600;
    color: var(--text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ctp-strip__pill {
    margin-left: auto;
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: 3px;
    padding: 5px 10px;
    border-radius: var(--radius-pill);
    background: var(--metal);
    color: var(--on-hue);
    font-size: 11.5px;
    font-weight: 700;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

/* Once a winner is recorded the pill stops being the money and becomes the verb. */
.ctp-strip__pill--set {
    background: var(--metal-wash-18);
    color: var(--metal-strong);
}

.ctp-strip__pill .material-symbols-outlined { font-size: 14px; }

/* --- C. Player card ----------------------------------------------------- */

.lvs-card {
    background: var(--surface-raised);
    border: 1px solid var(--hairline);
    border-radius: var(--radius-xl);
    box-shadow: 0 4px 14px rgba(16, 22, 30, 0.06);
    overflow: hidden;
}

:root[data-theme="dark"] .lvs-card { box-shadow: var(--shadow-md); }

.lvs-row {
    padding: 9px 12px 11px;
    border-bottom: 1px solid var(--hairline-soft);
}

.lvs-row:last-child { border-bottom: none; }

.lvs-card--dense .lvs-row { padding: 8px 12px 10px; }

.lvs-row__head {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-bottom: 7px;
    flex-wrap: wrap;
}

.lvs-card--dense .lvs-row__head { margin-bottom: 6px; }

.lvs-row__name {
    font-size: 15px;
    font-weight: 600;
    letter-spacing: -0.01em;
    color: var(--text);
}

.lvs-card--dense .lvs-row__name { font-size: 14.5px; }

.lvs-row__saved {
    font-size: 14px;
    color: var(--color-accent);
}

.lvs-row__roster {
    font-size: 11px;
    color: var(--text-muted);
    margin: -3px 0 7px;
}

.lvs-figs {
    margin-left: auto;
    display: inline-flex;
    align-items: baseline;
    gap: 6px;
    font-variant-numeric: tabular-nums;
}

.lvs-figs__gross {
    font-size: 16.5px;
    font-weight: 600;
    color: var(--text);
}

.lvs-card--dense .lvs-figs__gross { font-size: 15.5px; }

.lvs-figs__ou {
    font-size: 12.5px;
    font-weight: 600;
    color: var(--text-muted);
}

.lvs-figs__ou.under-par { color: var(--under-par); }

.lvs-figs__net {
    font-size: 11px;
    color: var(--text-quiet);
}

/* Tile row — four scores around par plus the "more" tile. */
.lvs-tiles {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: 7px;
}

.lvs-card--dense .lvs-tiles { gap: 6px; }

/* .lvs-skel__tile is the cold-start placeholder, sharing this geometry so the swap moves nothing.
   It is a SEPARATE CLASS on purpose: .lvs-tile is what a test clicks to enter a score, and a
   skeleton answering to that selector would hand a <span> to a click that expects a button. */
.lvs-tile,
.lvs-skel__tile {
    height: 50px;
    border-radius: 12px;
    border: 1px solid var(--hairline);
    background: var(--control-fill);
    font-family: inherit;
    font-size: 19px;
    font-weight: 600;
    color: var(--text);
    font-variant-numeric: tabular-nums;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: transform 0.12s;
    -webkit-tap-highlight-color: transparent;
    user-select: none;
}

.lvs-card--dense .lvs-tile {
    height: 46px;
    border-radius: 11px;
    font-size: 18px;
}

.lvs-tile:active { transform: scale(0.96); }

/* A selected tile is ONE treatment at every score — the navy solid, white ink. Which score it
   was is the mark inside it, not the fill: the amber and red steps this replaces were 2.2:1
   and 4.0:1, and the worst hole of the day was the least readable cell on the screen. */
.lvs-tile.is-selected {
    background: var(--surface-inverse);
    border-color: var(--surface-inverse);
    color: var(--on-solid);
    font-weight: 700;
    box-shadow: 0 2px 8px rgba(16, 22, 30, 0.18);
}

/* 10-scorecard.css draws the printed card's marks off BARE .birdie / .eagle / .bogey selectors,
   as FILLED pseudo-elements at z-index -1 — and because those rules also set `z-index: 1`, the
   element is its own stacking context, so the fill paints OVER the tile's background rather than
   behind it. A selected tile carries those same class names, so it was already picking up a red
   disc on a birdie and an --ink square on a bogey (which inverts, so in dark mode it swallowed
   the numeral whole). The score-entry TABLE has opted out of them since it was written; these two
   surfaces never did. One definition, three hosts — the mobile tiles draw the marks below and
   nothing else. Suppressed here rather than rescoped in 10-, which the printed card still needs.  */
.lvs-tile::before,
.lvs-tile::after,
.mobile-pick-btn::before,
.mobile-pick-btn::after,
.mobile-pick-more::before,
.mobile-pick-more::after {
    display: none;
}

/* The mark. Two nested spans always render; how many of them draw a border is the score.
   Geometry is the paper card's: a circle for under par, a square for over. */
.score-mark,
.score-mark__inner {
    display: grid;
    place-items: center;
    border: 2px solid transparent;
    box-sizing: border-box;
}
.score-mark { width: 34px; height: 34px; }
.score-mark__inner { width: 26px; height: 26px; }

/* Under par — circles, in the lightened red. One for a birdie, two for an eagle or better. */
.birdie > .score-mark,
.eagle > .score-mark,
.eagle .score-mark__inner {
    border-color: var(--score-mark-under);
    border-radius: var(--radius-pill);
}

/* Over par — squares, in a white wash. One for a bogey, two for a double or worse; it caps at
   two, so a 9 and an 11 wear the same mark. The escalation a bad hole needs is contrast, and
   the flat navy fill already gives it that. */
.bogey > .score-mark,
.double-plus > .score-mark,
.double-plus .score-mark__inner {
    border-color: var(--score-mark-over);
}
.bogey > .score-mark { border-radius: 6px; }
.double-plus > .score-mark { border-radius: 7px; }
.double-plus .score-mark__inner { border-radius: 5px; }

/* par-score draws no mark at all — par is the baseline, and the fill already says "entered". */

/* Dense (5+ players): the 46px tile takes the mark down one step with it. */
.lvs-card--dense .score-mark { width: 32px; height: 32px; }
.lvs-card--dense .score-mark__inner { width: 24px; height: 24px; }

/* The expanded 44px grid, same step. */
.lvs-expanded .score-mark { width: 30px; height: 30px; }
.lvs-expanded .score-mark__inner { width: 23px; height: 23px; }

.lvs-tile--more,
.lvs-skel__tile--dashed {
    border-style: dashed;
    border-color: rgba(20, 26, 34, 0.22);
    background: transparent;
}

/* :not(.is-selected) is load-bearing — this selector outranks .lvs-tile--more.is-selected below,
   so without it a selected more-tile keeps a pale outline over its navy fill in dark mode. */
:root[data-theme="dark"] .lvs-tile--more:not(.is-selected),
:root[data-theme="dark"] .lvs-skel__tile--dashed { border-color: rgba(255, 255, 255, 0.18); }

.lvs-tile--more .material-symbols-outlined {
    font-size: 19px;
    color: var(--text-quiet);
}

.lvs-tile--more.is-open {
    border-style: solid;
    border-color: var(--metal-line);
    background: var(--metal-wash-10);
}

/* An out-of-range score rides the more-tile as a real selected tile now, not coloured text on
   a dashed one. The dashed border stays for the empty state. */
.lvs-tile--more.is-selected {
    border-style: solid;
    background: var(--surface-inverse);
    border-color: var(--surface-inverse);
    color: var(--on-solid);
}

.lvs-expanded {
    display: grid;
    grid-template-columns: repeat(6, 1fr);
    gap: 6px;
    margin-top: 8px;
}

.lvs-expanded .lvs-tile {
    height: 44px;
    border-radius: 10px;
    font-size: 16px;
}

/* --- Match play chrome, restyled onto the card -------------------------- */

.lvs-matchtoggle {
    display: flex;
    gap: 3px;
    padding: 3px;
    margin-bottom: 10px;
    border-radius: var(--radius-lg);
    background: var(--control-fill-strong);
}

.lvs-matchtoggle button {
    flex: 1;
    min-height: 34px;
    border: none;
    border-radius: 9px;
    background: transparent;
    font-family: inherit;
    font-size: 12.5px;
    font-weight: 500;
    color: var(--text-muted);
    cursor: pointer;
}

.lvs-matchtoggle button.is-active {
    background: var(--surface-raised);
    font-weight: 600;
    color: var(--text);
    box-shadow: var(--shadow-sm);
}

.lvs-matchhead {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-1);
    padding: 9px 12px 7px;
    background: var(--control-fill);
    border-bottom: 1px solid var(--hairline-soft);
}

.lvs-matchhead__slot {
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--metal);
}

.lvs-matchhead__names {
    font-size: 12.5px;
    font-weight: 600;
    color: var(--text);
}

.lvs-matchhead__names .mb-vs {
    color: var(--text-quiet);
    font-weight: 500;
    margin: 0 2px;
}

.match-status-pill {
    display: inline-flex;
    align-items: center;
    padding: 1px 8px;
    border-radius: var(--radius-pill);
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: 0.03em;
    color: var(--on-hue);
}

.match-status-pill.up { background: var(--color-accent); }
.match-status-pill.down { background: var(--danger); }
.match-status-pill.as { background: var(--slate-500); }

.match-flag {
    font-size: 9.5px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--metal);
}

.match-opponent {
    font-size: 11.5px;
    font-weight: 500;
    color: var(--text-quiet);
}

.match-hole-result {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
    border-radius: 5px;
    font-size: 10px;
    font-weight: 700;
    color: var(--on-hue);
}

.match-hole-result.mhr-w { background: var(--color-accent); }
.match-hole-result.mhr-l { background: var(--danger); }
.match-hole-result.mhr-h { background: var(--slate-500); }

.team-lownet-line {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-top: 10px;
    padding: 10px 12px;
    background: var(--surface-raised);
    border: 1px solid var(--hairline);
    border-radius: 13px;
    font-size: 12.5px;
    font-variant-numeric: tabular-nums;
}

.team-lownet-line .tln-label {
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    color: var(--metal);
}

.team-lownet-line .tln-team { color: var(--text-muted); font-weight: 600; }
.team-lownet-line .tln-team.leading { color: var(--color-accent); font-weight: 700; }
.team-lownet-line .tln-sep { color: var(--text-quiet); }

/* --- D. Fixed bottom bar ------------------------------------------------ */

.hole-nav {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    max-width: 480px;
    margin: 0 auto;
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 10px 12px;
    /* Clear the iPhone home indicator so Prev / hole jump / Next stay tappable. */
    padding-bottom: calc(0.75rem + env(safe-area-inset-bottom));
    background: var(--surface-raised);
    border-top: 1px solid var(--hairline);
    box-shadow: 0 -2px 12px rgba(16, 22, 30, 0.07);
    z-index: 40;
}

.lvs-bar__prev {
    flex: none;
    width: 54px;
    height: 52px;
    border-radius: 14px;
    border: 1px solid var(--hairline);
    background: var(--control-fill);
    font-family: inherit;
    cursor: pointer;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 1px;
    -webkit-tap-highlight-color: transparent;
}

.lvs-bar__prev .material-symbols-outlined {
    font-size: 19px;
    color: var(--text);
}

.lvs-bar__prev span:last-child {
    font-size: 8.5px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

.lvs-bar__prev:disabled {
    opacity: 0.45;
    cursor: not-allowed;
}

.lvs-bar__prev:disabled .material-symbols-outlined { color: var(--ink-disabled); }

.lvs-bar__hole {
    flex: none;
    height: 52px;
    padding: 0 12px;
    border-radius: 14px;
    border: 1px solid var(--hairline);
    background: var(--surface-raised);
    font-family: inherit;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    -webkit-tap-highlight-color: transparent;
}

.lvs-bar__hole .material-symbols-outlined {
    font-size: 18px;
    color: var(--text-quiet);
}

.lvs-bar__hole span:last-child {
    font-size: 14px;
    font-weight: 600;
    color: var(--text);
    white-space: nowrap;
}

/* Next is neutral until every player on the hole has a score, then it turns accent —
   that colour change IS the "all in" signal, which is why there's no separate banner. */
.lvs-bar__next {
    flex: 1;
    height: 52px;
    border-radius: 14px;
    border: 1px solid var(--hairline);
    background: var(--control-fill);
    color: var(--text);
    font-family: inherit;
    font-size: 15.5px;
    font-weight: 600;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-1);
    -webkit-tap-highlight-color: transparent;
}

.lvs-bar__next.is-ready {
    border-color: transparent;
    background: var(--color-accent);
    color: var(--on-hue);
    box-shadow: 0 4px 14px color-mix(in srgb, var(--color-accent) 30%, transparent);
}

.lvs-bar__next .material-symbols-outlined { font-size: 19px; }

/* --- The scoring claim: the note, the inert card, the take-over ----------
   design_handoff_bottom_nav §5–§7. These live HERE, beside the tiles they modify, rather than in
   26-bottom-nav.css: that partial owns the bar and the dock, and a rule that changes what a score
   tile looks like belongs next to the score tile. */

/* One row above the contest strip. Metal because "where you left off" is a standing fact — and
   because the same treatment carries the watching note, which is the other answer to the same
   question ("why am I looking at this hole?"). */
.lvs-claim {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin-bottom: 10px;
    padding: 9px 12px;
    border-radius: 13px;
    background: var(--metal-wash-16);
    border: 1px solid var(--metal-line);
    font-size: 12.5px;
    font-weight: var(--font-weight-semibold);
    color: var(--metal-strong);
}

.lvs-claim .material-symbols-outlined { flex: none; font-size: 18px; }

/* ── The scorer row (design_handoff_scoring_claim_exit §1) ─────────────────────────────────────
   Same slot and same treatment as .lvs-claim, because it answers the same question — who is
   entering, and why am I looking at this hole. It differs in carrying the one control that puts
   the card down, which is why it is a row of its own rather than another .lvs-claim form.

   It lives in the BODY. The exit used to hang off the header's group line, and the dense header
   drops that line entirely at five players, so the holder of a five-ball had no way to stop. A row
   here cannot be deleted by density — it gets tighter instead. */
.lvs-scorer {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin-bottom: 10px;
    /* Asymmetric: the trailing button's own padding lands the row's right edge on the same optical
       inset as .lvs-claim's 12px. */
    padding: 7px 7px 7px 12px;
    border-radius: 13px;
    background: var(--metal-wash-16);
    border: 1px solid var(--metal-line);
    font-size: 12.5px;
    font-weight: var(--font-weight-semibold);
    color: var(--metal-strong);
}

.lvs-scorer .material-symbols-outlined { flex: none; font-size: 18px; color: var(--metal); }

.lvs-scorer__label { overflow: hidden; text-overflow: ellipsis; }

/* No verb to offer: nobody holds it, the link holds it and this isn't the phone driving it, or
   somebody else is entering. Metal means "this card is yours to put down", so a row without a Stop
   must not wear it — on this screen metal is standing, not decoration. */
.lvs-scorer--quiet {
    background: var(--control-fill);
    border: 1px dashed var(--hairline);
    color: var(--text-muted);
}

.lvs-scorer--quiet .material-symbols-outlined { color: var(--text-quiet); }

.lvs-scorer__stop {
    margin-left: auto;
    flex: none;
    height: 34px;
    padding: 0 12px;
    border-radius: 9px;
    border: 1px solid var(--hairline);
    background: var(--control-fill);
    font-family: inherit;
    font-size: 12.5px;
    font-weight: 700;
    color: var(--text);
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}

.lvs-scorer__stop:disabled { opacity: .55; cursor: default; }

/* Five or more players: one step tighter, so the tile grid still clears the fixed bar on a
   390x844 phone. The row shrinks; it never disappears. That is the whole point of moving it out
   of the header. */
.lvs-scorer--dense {
    padding: 6px 6px 6px 11px;
    border-radius: 12px;
    font-size: 12px;
}

.lvs-scorer--dense .material-symbols-outlined { font-size: 17px; }

.lvs-scorer--dense .lvs-scorer__stop {
    height: 32px;
    padding: 0 11px;
    border-radius: 8px;
    font-size: 12px;
}

/* A holder who has gone quiet for 25 minutes. Amber, because this is the one thing on the screen
   a person has to act on — and it never blocks: the tiles stay inert, the button just gets louder.
   --navy ink, per the amber rule: white on #f39c12 is unreadable in light mode. */
.lvs-claim--stale {
    background: color-mix(in srgb, var(--warning) 16%, transparent);
    border-color: color-mix(in srgb, var(--warning) 45%, transparent);
    color: var(--navy);
}

/* Inert tiles for a watcher. UNSELECTED ones go quiet; SELECTED ones keep their full score colour,
   because the whole reason a watcher opens this screen is to check that their 5 got entered. Greying
   the answer out would defeat the screen. --ink-disabled, not --border-strong: a greyed control
   still has to say what it is. */
.lvs-card--locked .lvs-tile:not(.is-selected) {
    background: var(--control-fill);
    border-color: var(--hairline-soft);
    color: var(--ink-disabled);
    font-weight: 500;
    cursor: default;
}

.lvs-card--locked .lvs-tile:active { transform: none; }

/* The watcher's one verb, in place of Next and the hole jump. Quiet metal while the holder is
   keeping up; solid once they've gone quiet — a louder offer, never a block. */
.lvs-takeover {
    flex: 1;
    height: 52px;
    border-radius: 14px;
    border: 1px solid var(--metal-line);
    background: var(--metal-wash-16);
    color: var(--metal-strong);
    font-family: inherit;
    font-size: 15.5px;
    font-weight: 700;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    -webkit-tap-highlight-color: transparent;
}

.lvs-takeover .material-symbols-outlined { font-size: 20px; }

.lvs-takeover.is-urgent {
    border-color: transparent;
    background: var(--metal);
    color: var(--on-hue);
    box-shadow: 0 4px 14px color-mix(in srgb, var(--metal) 30%, transparent);
}

.lvs-takeover:disabled { opacity: 0.6; cursor: default; }

/* --- Errors + sync ------------------------------------------------------ */

.live-error {
    margin-bottom: 10px;
    padding: 10px 12px;
    border-radius: 13px;
    background: color-mix(in srgb, var(--danger) 12%, transparent);
    border: 1px solid color-mix(in srgb, var(--danger) 35%, transparent);
    color: var(--danger);
    font-size: 12.5px;
    line-height: 1.4;
}

.live-sync-banner {
    display: flex;
    align-items: center;
    gap: 9px;
    margin-bottom: 10px;
    padding: 11px 12px;
    border-radius: 13px;
    background: color-mix(in srgb, var(--warning) 12%, transparent);
    border: 1px solid color-mix(in srgb, var(--warning) 35%, transparent);
    color: var(--lvs-warn-ink, #8a6212);
    font-size: 12.5px;
    line-height: 1.4;
}

:root[data-theme="dark"] .live-sync-banner { --lvs-warn-ink: var(--warning); }

.live-sync-banner.fatal {
    background: color-mix(in srgb, var(--danger) 12%, transparent);
    border-color: color-mix(in srgb, var(--danger) 35%, transparent);
    color: var(--danger);
}

.live-sync-banner-text { flex: 1; }

.live-sync-banner-btn {
    flex: none;
    min-height: 36px;
    background: var(--danger);
    color: var(--on-hue);
    border: none;
    padding: 0 14px;
    border-radius: 10px;
    font-family: inherit;
    font-size: 12.5px;
    font-weight: 600;
    cursor: pointer;
}

.live-sync-spinner {
    width: 15px;
    height: 15px;
    border: 2px solid currentColor;
    border-top-color: transparent;
    border-radius: 50%;
    animation: live-sync-spin 0.9s linear infinite;
    flex-shrink: 0;
}

@keyframes live-sync-spin {
    to { transform: rotate(360deg); }
}

@media (prefers-reduced-motion: reduce) {
    .live-sync-spinner { animation-duration: 3s; }
}

/* ===================================================================
   THE CONTEST SHEET (par 3 / longest drive / any observed game)
   Built on .modal-panel, so drag-to-dismiss and the scroll lock come along.
   13-controls-overlays.css concatenates AFTER this partial, so every rule is
   written .modal-panel.ctp-sheet to win on specificity rather than on order —
   the same call .pm-sheet makes in 09-players-courses.css.
   =================================================================== */

.modal-panel.ctp-sheet {
    padding: 8px 0 var(--space-4);
    padding-bottom: calc(var(--space-4) + env(safe-area-inset-bottom));
    border-radius: 22px 22px 0 0;
    background: var(--surface-raised);
}

/* The panel's own ::before grabber only exists at ≤480px; the sheet draws its own so
   the head sits the same distance from it on a tablet. */
.modal-panel.ctp-sheet::before { display: none; }

.ctp-sheet__grab {
    width: 38px;
    height: 4px;
    border-radius: var(--radius-pill);
    background: rgba(20, 26, 34, 0.18);
    margin: 0 auto 14px;
}

:root[data-theme="dark"] .ctp-sheet__grab { background: rgba(255, 255, 255, 0.20); }

.ctp-sheet__head {
    padding: 0 18px 14px;
    border-bottom: 1px solid var(--hairline-soft);
}

.ctp-sheet__eyebrow {
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--metal);
    margin-bottom: 5px;
}

.ctp-sheet__titlerow {
    display: flex;
    align-items: baseline;
    gap: 9px;
}

.ctp-sheet__title {
    font-size: 20px;
    font-weight: 600;
    letter-spacing: -0.02em;
    color: var(--text);
}

.ctp-sheet__amount {
    margin-left: auto;
    font-size: 15px;
    font-weight: 700;
    color: var(--color-accent);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.ctp-sheet__sub {
    font-size: 12.5px;
    color: var(--text-muted);
    margin-top: var(--space-1);
}

.ctp-sheet__list {
    display: flex;
    flex-direction: column;
}

.ctp-row {
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
    box-sizing: border-box;
    min-height: 64px;
    padding: 13px 18px;
    border: none;
    border-bottom: 1px solid var(--hairline-soft);
    background: var(--surface-raised);
    font-family: inherit;
    text-align: left;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}

.ctp-row:disabled { opacity: 0.55; cursor: not-allowed; }

.ctp-row__disc {
    flex: none;
    width: 38px;
    height: 38px;
    border-radius: var(--radius-pill);
    background: var(--control-fill-strong);
    color: var(--text);
    font-size: 12.5px;
    font-weight: 700;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.ctp-row__text {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.ctp-row__name {
    font-size: 16px;
    font-weight: 600;
    color: var(--text);
}

.ctp-row__sub {
    font-size: 11.5px;
    color: var(--text-quiet);
}

.ctp-row__check {
    margin-left: auto;
    flex: none;
    font-size: 22px;
    color: var(--metal);
}

.ctp-row.is-selected {
    background: var(--metal-wash-16);
    box-shadow: inset 3px 0 0 var(--metal);
}

.ctp-row.is-selected .ctp-row__disc { background: var(--metal); color: var(--on-hue); }
.ctp-row.is-selected .ctp-row__name { font-weight: 700; color: var(--metal-strong); }
.ctp-row.is-selected .ctp-row__sub { color: var(--metal); }

.ctp-sheet__foot {
    display: flex;
    gap: 9px;
    padding: 14px 18px 0;
}

.ctp-sheet__note {
    flex: 1;
    min-width: 0;
    height: 48px;
    padding: 0 13px;
    border: 1px solid var(--hairline);
    border-radius: 13px;
    /* 16px so iOS doesn't zoom-focus this field. */
    font-size: 16px;
    font-family: inherit;
    background: var(--control-fill);
    color: var(--text);
    box-sizing: border-box;
}

.ctp-sheet__note:disabled { color: var(--ink-disabled); }

.ctp-sheet__noq {
    flex: none;
    height: 48px;
    padding: 0 16px;
    border-radius: 13px;
    border: 1px solid var(--hairline);
    background: var(--surface-raised);
    font-family: inherit;
    font-size: 13.5px;
    font-weight: 600;
    color: var(--text-muted);
    cursor: pointer;
    white-space: nowrap;
}

.ctp-sheet__noq.is-selected {
    background: var(--metal-wash-16);
    border-color: var(--metal-line);
    color: var(--metal-strong);
}

.ctp-sheet__noq:disabled { opacity: 0.55; cursor: not-allowed; }

.ctp-sheet__error {
    padding: 12px 18px 0;
    color: var(--danger);
    font-size: 12.5px;
}

/* ===================================================================
   SUPPORTING STATES — start / not started / round complete
   Same language as the hole screen: a dark head over a raised card.
   =================================================================== */

.lvs-state {
    padding: var(--space-4) var(--space-3) var(--space-6);
    min-height: 100dvh;
    box-sizing: border-box;
    background: var(--page-ground);
}

.lvs-statecard {
    background: var(--surface-raised);
    border: 1px solid var(--hairline);
    border-radius: 20px;
    overflow: hidden;
    box-shadow: 0 4px 14px rgba(16, 22, 30, 0.06);
}

.lvs-statecard__head {
    /* Dark in both themes, like the hole screen's header. */
    padding: 22px 20px 20px;
    background: linear-gradient(180deg, #182027, #10151a);
    border-bottom: 1px solid rgba(201, 173, 110, 0.30);
}

.lvs-statecard__eyebrow {
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: #c9ad6e;
    margin-bottom: var(--space-2);
}

.lvs-statecard__title {
    margin: 0;
    font-size: 26px;
    font-weight: 600;
    letter-spacing: -0.02em;
    color: #fff;
}

.lvs-statecard__sub {
    font-size: 13px;
    color: #c8cfd8;
    margin-top: 6px;
}

.lvs-statecard__body { padding: var(--space-4) 18px; }

.lvs-plist { display: flex; flex-direction: column; }

.lvs-plist__row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 11px 0;
    border-bottom: 1px solid var(--hairline-soft);
}

.lvs-plist__row:last-child { border-bottom: none; }

.lvs-plist__disc {
    flex: none;
    width: 32px;
    height: 32px;
    border-radius: var(--radius-pill);
    background: var(--control-fill-strong);
    color: var(--text);
    font-size: 11.5px;
    font-weight: 700;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.lvs-plist__name {
    font-size: 15px;
    font-weight: 600;
    color: var(--text);
}

.lvs-plist__meta {
    margin-left: auto;
    font-size: 12px;
    color: var(--text-quiet);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.lvs-primary {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    box-sizing: border-box;
    min-height: 56px;
    margin-top: var(--space-4);
    border-radius: var(--radius-xl);
    border: none;
    background: var(--color-accent);
    color: var(--on-hue);
    font-family: inherit;
    font-size: 16.5px;
    font-weight: 700;
    cursor: pointer;
    text-decoration: none;
    -webkit-tap-highlight-color: transparent;
}

.lvs-secondary {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    box-sizing: border-box;
    min-height: 48px;
    margin-top: 9px;
    border-radius: 15px;
    border: 1px solid var(--hairline);
    background: transparent;
    color: var(--text);
    font-family: inherit;
    font-size: 14.5px;
    font-weight: 600;
    cursor: pointer;
    text-decoration: none;
    -webkit-tap-highlight-color: transparent;
}

.lvs-resultslink {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    min-height: 44px;
    margin-top: var(--space-3);
    font-size: 13.5px;
    font-weight: 600;
    color: var(--metal);
    text-decoration: none;
}

.lvs-resultslink .material-symbols-outlined { font-size: 17px; }

.lvs-notice {
    display: flex;
    align-items: flex-start;
    gap: 9px;
    margin-top: var(--space-4);
    padding: 12px 13px;
    border-radius: 13px;
    background: color-mix(in srgb, var(--warning) 12%, transparent);
    border: 1px solid color-mix(in srgb, var(--warning) 35%, transparent);
    color: var(--lvs-warn-ink, #8a6212);
    font-size: 12.5px;
    line-height: 1.45;
}

:root[data-theme="dark"] .lvs-notice { --lvs-warn-ink: var(--warning); }

.lvs-notice strong { display: block; margin-bottom: 2px; }

.lvs-notice .material-symbols-outlined { font-size: 18px; flex: none; }

/* Round-complete leaderboard of the group. Metal = standing, and only the top two
   numerals carry it — position is the one thing on this card that IS a standing. */
.lvs-final {
    display: grid;
    grid-template-columns: 30px 1fr auto auto;
    column-gap: 12px;
    align-items: center;
    padding: 11px 0;
    border-bottom: 1px solid var(--hairline-soft);
    font-variant-numeric: tabular-nums;
}

.lvs-final:last-child { border-bottom: none; }

.lvs-final__pos {
    width: 28px;
    height: 28px;
    border-radius: 9px;
    font-size: 13.5px;
    font-weight: 600;
    color: var(--text-muted);
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.lvs-final__pos--1 {
    background: var(--metal-wash-18);
    color: var(--metal-strong);
    font-weight: 700;
}

.lvs-final__pos--2 {
    background: var(--metal-wash-10);
    color: var(--metal);
    font-weight: 700;
}

.lvs-final__name { font-size: 15px; font-weight: 600; color: var(--text); }
.lvs-final__total { font-size: 17px; font-weight: 600; color: var(--text); }
.lvs-final__ou { font-size: 13px; font-weight: 600; color: var(--text-muted); }
.lvs-final__ou.under-par { color: var(--under-par); }
.lvs-final__partial { font-size: 11.5px; color: var(--warning); }

/* ===================================================================
   SCORING RETURN BAR (rendered by MainLayout when a ?scorer= / ?scoring=
   breadcrumb is present — the one thing the scorer's leaderboard adds)
   =================================================================== */

/* The bar is a container, not the link: the dismiss × is a <button>, which may not nest
   inside an <a>. Without the ×, .scoring-return__back fills it and the rendering is
   identical to the single-element version this replaced. */
.scoring-return {
    position: sticky;
    top: 0;
    z-index: 60;
    display: flex;
    align-items: center;
    min-height: 46px;
    padding: 0 10px;
    background: var(--color-accent);
    color: var(--on-hue);
}

.scoring-return__back {
    flex: 1;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: var(--space-2);
    min-height: 46px;
    color: inherit;
    text-decoration: none;
    -webkit-tap-highlight-color: transparent;
}

.scoring-return .material-symbols-outlined { font-size: 21px; }

/* 40px target pulled 6px past the container's padding, so it reaches the screen edge without
   the label's 10px inset moving when the × isn't there. */
.scoring-return__dismiss {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    margin-left: var(--space-2);
    margin-right: -6px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: transparent;
    color: inherit;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}

.scoring-return__dismiss:active { background: rgba(255, 255, 255, 0.18); }

.scoring-return__label {
    font-size: 15px;
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.scoring-return__pill {
    margin-left: auto;
    flex: none;
    display: inline-flex;
    align-items: center;
    padding: 4px 10px;
    border-radius: var(--radius-pill);
    background: rgba(255, 255, 255, 0.18);
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    font-variant-numeric: tabular-nums;
}

/* In dark mode --on-hue is near-black, so the translucent white pill ground would
   fight it; a dark wash keeps the same "quieter than the label" relationship. */
:root[data-theme="dark"] .scoring-return__pill { background: rgba(0, 0, 0, 0.18); }
:root[data-theme="dark"] .scoring-return__dismiss:active { background: rgba(0, 0, 0, 0.18); }

/* ===== The cold-start skeleton (handoffs/design_handoff_cold_start §3) =====
   Rendered by Shared/ScoringSkeleton.razor, which replaced .live-loading on this screen — a spinner
   and "Loading scoring session…" on a full-height white page, which coming off a dark launch screen
   was the brightest thing on the phone at 7pm on a tee box.

   Everything here re-uses the real screen's classes and only fills them differently, so the swap to
   content is ink appearing and nothing moving: same header height, same card, same tile grid, same
   bottom bar. What is added is the two shimmer weights for the DARK ground and the empty forms of
   three controls whose shape is certain while their contents are not.

   (.live-loading itself STAYS: Pages/Scores/Landing.razor is deliberately not redesigned and is
   still its caller — the handoff's delete list is wrong about that one.) */

/* Shimmer on the header's dark ground. Same 1.4s curve as .skeleton, different ramp. */
.lvs-hskel {
    display: block;
    border-radius: var(--radius-sm);
    background: var(--lvs-skel);
    background-image: linear-gradient(
        90deg,
        var(--lvs-skel) 25%,
        var(--lvs-skel-lit) 37%,
        var(--lvs-skel) 63%);
    background-size: 400% 100%;
    animation: skeleton-shimmer 1.4s ease infinite;
}

/* The flat weight, on the same ground: a count, not a value. */
.lvs-hflat {
    display: block;
    border-radius: var(--radius-sm);
    background: #262d36;
}

@media (prefers-reduced-motion: reduce) {
    .lvs-hskel { animation: none; }
}

.lvs-skel__day     { width: 52px; height: 8px; }
.lvs-skel__where   { width: 96px; height: 8px; }
.lvs-skel__holenum { width: 40px; height: 34px; border-radius: 7px; }
.lvs-skel__facts   { width: 84px; height: 9px; }
.lvs-skel__thru    { width: 34px; height: 13px; }
.lvs-skel__lead    { flex: 1; height: 11px; }

/* The par chip with nothing in it. The 48 × 15 shape is certain — "Par 4" is not. */
.lvs-parchip--empty {
    display: block;
    width: 48px;
    height: 15px;
    padding: 0;
}

/* The LEADING chip's container is real — border, ground, label and glyph — because it is furniture
   and not a figure. Only its body is a placeholder, and it is inert here: it is a link on the real
   screen, and a results link that resolves to nothing yet is worse than no link. */
.lvs-lead--skel { pointer-events: none; }

.lvs-skel__name { height: 13px; }
.lvs-skel__figs { margin-left: auto; width: 46px; height: 14px; }

/* EMPTY TILES, NOT SHIMMER BARS. There are always five at a fixed height, so draw five. Their
   numerals are par-relative and genuinely unknown; shimmering a rectangle where an obviously-shaped
   control goes is what makes a skeleton look cheap. Geometry is shared with .lvs-tile above; the
   class is separate so nothing can click one by mistake. */
.lvs-skel__tile {
    pointer-events: none;
    color: transparent;
}

.lvs-bar--inert { pointer-events: none; }

/* Prev takes the disabled look it would have on hole 1 — the honest state before anything loads. */
.lvs-bar__prev.lvs-bar--inert { opacity: 0.45; }

.lvs-skel__barlabel { width: 38px; height: 11px; }
.lvs-skel__barnext  { width: 54px; height: 12px; }

/* Six seconds in. Not "the page is slow" — "your scores are safe", which is the only sentence worth
   reading with a group waiting on the tee. Warning tint rather than metal: metal on this screen
   means a standing or a card that is yours to put down, and this is neither. */
.lvs-claim--waiting {
    background: color-mix(in srgb, var(--warning) 12%, transparent);
    border-color: color-mix(in srgb, var(--warning) 40%, transparent);
    color: var(--navy);
}

.lvs-claim--waiting .material-symbols-outlined { color: var(--warning); }

:root[data-theme="dark"] .lvs-claim--waiting { color: var(--text); }
/* ===== Share Links Modal ===== */

.modal-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.4);
    z-index: 200;
}

/* Background scroll-lock: while any bottom sheet / modal dialog is open (each renders a
   .modal-backdrop), freeze the page behind it so touch/scroll can't move the background.
   The sheet itself stays scrollable via .modal-panel's own overflow-y + overscroll-behavior.
   Keyed off the backdrop with :has() so every current and future sheet is covered with no
   per-component wiring. overscroll-behavior:none also kills iOS rubber-band chaining.

   This takes the page's scrollbar away with it, which on a desktop browser would re-centre
   #app-root's 1280px column and slide the whole app sideways. `scrollbar-gutter: stable` on html
   (02-base-chrome.css) is what keeps that width reserved — the two rules only work as a pair. */
html:has(.modal-backdrop),
body:has(.modal-backdrop) {
    overflow: hidden;
    overscroll-behavior: none;
    touch-action: none;
}

.modal-panel {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    background: var(--surface);
    border-radius: 12px 12px 0 0;
    padding: 1.5rem;
    /* Keep the sheet's bottom content above the home indicator on devices with a
       bottom inset; collapses to the base 1.5rem on everything else. */
    padding-bottom: calc(1.5rem + env(safe-area-inset-bottom));
    z-index: 201;
    max-height: 80vh;
    overflow-y: auto;
    /* Scrolling inside a sheet shouldn't chain to / bounce the page behind it. */
    overscroll-behavior: contain;
    /* The background lock sets touch-action:none on body; re-enable vertical panning here so
       the sheet's own content stays scrollable on touch (touch-action isn't inherited, but be
       explicit so a long sheet never gets stuck). */
    touch-action: pan-y;
    box-shadow: 0 -4px 20px rgba(0, 0, 0, 0.15);
}

/* Grabber handle — the visual cue that a bottom sheet can be swiped down to
   dismiss (drag handled by js/sheet-dismiss.js). Only in bottom-sheet mode. */
@media (max-width: 480px) {
    /* Bottom sheets span the full phone width. Several dialogs carry an inline
       max-width sized for the desktop centered-dialog variant (e.g. settings 420px,
       shorten 360px); without this override that cap shrinks the sheet while left:0
       pins it to the left, leaving a gap on the right. !important is required to
       beat the inline style. */
    .modal-panel {
        max-width: none !important;
    }

    .modal-panel::before {
        content: '';
        display: block;
        width: 36px;
        height: 4px;
        margin: -0.5rem auto 0.75rem;
        border-radius: 2px;
        background: var(--gray-400);
    }
}

.modal-panel-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 0.5rem;
}

.modal-panel-header h3 {
    margin: 0;
    font-size: 1.1rem;
}

.modal-close-btn {
    background: none;
    border: none;
    font-size: 1.5rem;
    cursor: pointer;
    color: var(--gray-650);
    padding: 0.25rem 0.5rem;
}

.modal-subtitle {
    color: var(--gray-650);
    font-size: 0.85rem;
    margin-bottom: 1rem;
}

.link-row {
    margin-bottom: 1rem;
    padding-bottom: 1rem;
    border-bottom: 1px solid var(--gray-200);
}

.link-row:last-of-type {
    border-bottom: none;
}

.link-group-name {
    font-weight: 600;
    font-size: 0.9rem;
    margin-bottom: 0.4rem;
    color: var(--text);
}

.link-players {
    font-weight: 400;
    color: var(--gray-650);
}

.link-url-row {
    display: flex;
    gap: 0.5rem;
    align-items: center;
}

.link-input {
    flex: 1;
    font-size: 0.75rem;
    padding: 0.4rem 0.6rem;
    border: 1px solid var(--gray-350);
    border-radius: 4px;
    background: var(--surface-3);
    color: var(--gray-650);
    font-family: monospace;
}

@media (min-width: 481px) {
    .modal-panel {
        max-width: 500px;
        left: 50%;
        transform: translateX(-50%);
        bottom: 10%;
        border-radius: 12px;
    }
}

/* Full-screen variant for dense, multi-field forms (e.g. edit round): on phones
   take the whole screen instead of an 80vh sheet so long forms aren't cramped.
   On tablet/desktop it falls through to the centered-dialog rules above. */
@media (max-width: 480px) {
    .modal-panel--full {
        top: 0;
        max-height: none;
        border-radius: 0;
        /* Clear the status bar / notch now that the panel reaches the top edge.
           The bottom inset is already inherited from .modal-panel. */
        padding-top: calc(1.5rem + env(safe-area-inset-top));
    }
}

/* ===== Overflow menu (ROUND-PAGE-PLAN.md Phase 6a, design 4a) =====
   Bottom sheet below 768px, anchored dropdown at or above it — a top-right menu is the worst reach
   on a phone. Same markup both ways: the sheet form rides .modal-panel (so it inherits the
   backdrop, the scroll lock and the drag-to-dismiss grabber), and the desktop rules re-anchor it
   to the trigger and drop the header the dropdown doesn't need. Rendered by <OverflowMenu>. */
.overflow-menu { display: contents; }

.overflow-menu__panel {
    /* .modal-panel's 1.5rem padding is for prose; a menu's rows own their own inset. The bottom
       gap is not symmetry — the last row here is Delete, and flush against the screen edge is
       where a home-indicator swipe turns into a mis-tap. */
    padding: 0 0 calc(var(--space-4) + env(safe-area-inset-bottom));
}

@media (max-width: 480px) {
    /* .modal-panel's grabber assumes the panel's own 1.5rem top padding, which this one drops. */
    .overflow-menu__panel::before { margin: var(--space-3) auto var(--space-2); }
}

.overflow-menu__head { padding: var(--space-1) var(--space-5) 10px; }
.overflow-menu__head-title {
    font-size: 1.05rem;
    font-weight: var(--font-weight-semibold);
}
.overflow-menu__head-sub {
    font-size: var(--text-sm);
    color: var(--text-muted);
    margin-top: 2px;
}

.overflow-menu__item {
    display: flex;
    align-items: center;
    gap: 14px;
    width: 100%;
    min-height: 48px;
    padding: 13px var(--space-5);
    border: none;
    background: none;
    color: var(--text);
    font-family: inherit;
    text-align: left;
    cursor: pointer;
}
.overflow-menu__item:hover { background: var(--surface-subtle); }
.overflow-menu__item > .material-symbols-outlined {
    flex: none;
    font-size: 22px;
    color: var(--slate-500);
}
.overflow-menu__item-body { flex: 1; min-width: 0; }
.overflow-menu__item-label {
    display: block;
    font-size: 1rem;
    font-weight: var(--font-weight-medium);
}
.overflow-menu__item-sub {
    display: block;
    font-size: var(--text-sm);
    color: var(--text-muted);
    margin-top: 1px;
    line-height: 1.4;
}
/* Names the events an item applies to, so it doesn't look like it went missing on the others. */
.overflow-menu__item-tag {
    flex: none;
    font-size: 0.65rem;
    font-weight: var(--font-weight-semibold);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--gray-500);
}

/* The destructive block sits behind a deliberate break rather than one tap from the surface: a
   band on the phone, where 48px rows need a real gap, and a hairline in the dropdown. */
.overflow-menu__item.starts-group {
    border-top: 8px solid var(--surface-subtle);
    margin-top: var(--space-2);
}
.overflow-menu__item.is-danger .overflow-menu__item-label,
.overflow-menu__item.is-danger > .material-symbols-outlined { color: var(--danger); }

/* Greyed but still there and still tappable — opening it explains the block (Phase 5, tier 4).
   Deliberately not `disabled`: a row that can't be pressed and doesn't say why is what sends
   commissioners hunting for a feature they're sure existed. Beats .is-danger on purpose — an
   unavailable Delete shouldn't shout in red. */
.overflow-menu__item.is-unavailable > .material-symbols-outlined,
.overflow-menu__item.is-unavailable .overflow-menu__item-label,
.overflow-menu__item.is-unavailable.is-danger > .material-symbols-outlined,
.overflow-menu__item.is-unavailable.is-danger .overflow-menu__item-label { color: var(--ink-disabled); }

.overflow-menu__trigger.is-open { background: var(--surface-subtle); }

/* The menu's panel is a descendant of .app-bar, and the bar is `position:sticky; z-index:50` —
   which makes it a STACKING CONTEXT. So the panel's z-index:201 is only 201 *within the bar*, and
   the whole bar loses to the phone's .bottom-nav at z-index:150: the sheet's last rows render
   underneath the tab bar, un-tappable. On a menu whose last row is Delete, that's the row you can't
   reach. Lift the bar's own context while the menu is open (the same :has() pattern the sheet
   scroll-lock uses), and let it drop back when it closes so the bar can't cover the nav. */
.app-bar:has(.overflow-menu__panel) { z-index: 210; }

@media (min-width: 768px) {
    /* Anchored to the trigger, not to the viewport. display:contents leaves nothing to position
       against, so the wrapper becomes a real box here. */
    .overflow-menu {
        display: block;
        position: relative;
        flex: none;
    }
    .overflow-menu__panel {
        position: absolute;
        top: calc(100% + var(--space-1));
        right: 0;
        left: auto;
        bottom: auto;
        transform: none;
        width: 266px;
        max-width: 266px;
        max-height: none;
        padding: var(--space-1) 0;
        border: 1px solid var(--border);
        border-radius: var(--radius-lg);
        box-shadow: var(--shadow-lg);
    }
    /* The dropdown is visibly attached to the bar, so it doesn't need to name its subject. */
    .overflow-menu__head { display: none; }
    /* Click-outside catcher only — dimming the page for a dropdown reads as a modal. */
    .overflow-menu__scrim { background: transparent; }

    .overflow-menu__item {
        min-height: 44px;
        padding: 11px var(--space-4);
        gap: var(--space-3);
    }
    .overflow-menu__item > .material-symbols-outlined { font-size: 20px; }
    .overflow-menu__item-label { font-size: 0.925rem; }
    .overflow-menu__item.starts-group {
        border-top: 1px solid var(--gray-200);
        margin-top: var(--space-1);
        padding-top: 12px;
    }
}

/* ===== Confirmation sheet (ROUND-PAGE-PLAN.md Phase 5) =====
   One component for all four tiers; the tier only changes the chrome. Rendered by <ConfirmSheet>,
   driven by RoundConfirmations. Tier 2 deliberately gets NO colour here — a reversible action that
   borrows the danger palette is what teaches people to ignore the sheet that genuinely can't be
   undone. Only .confirm-sheet--danger goes red. */
.confirm-sheet__head {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin-bottom: var(--space-2);
}

.confirm-sheet__icon {
    flex: none;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    display: grid;
    place-items: center;
    background: var(--gray-150);
    color: var(--text-muted);
}
.confirm-sheet__icon .material-symbols-outlined { font-size: 20px; }

/* color-mix, not a baked rgba(): a wash computed against white is invisible on a dark ground. */
.confirm-sheet--danger .confirm-sheet__icon {
    background: color-mix(in srgb, var(--danger) 12%, transparent);
    color: var(--danger);
}
.confirm-sheet--accent .confirm-sheet__icon {
    background: color-mix(in srgb, var(--color-accent) 12%, transparent);
    color: var(--color-accent);
}

.confirm-sheet__title {
    margin: 0;
    font-size: 1.25rem;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.01em;
}

.confirm-sheet__sub {
    margin: 0 0 var(--space-4);
    font-size: 0.9rem;
    color: var(--text-muted);
    line-height: 1.55;
}

/* The consequence list. Real counts, one per line — "this will delete related data" tells a
   commissioner nothing and gets tapped through. */
.confirm-lines {
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    overflow: hidden;
}

.confirm-lines__head {
    padding: 9px var(--space-4);
    background: var(--surface-subtle);
    border-bottom: 1px solid var(--gray-200);
    font-size: 0.7rem;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.confirm-line {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: var(--space-3) 14px;
    font-size: 0.875rem;
    line-height: 1.5;
}
.confirm-line + .confirm-line { border-top: 1px solid var(--gray-200); }
.confirm-line .material-symbols-outlined { flex: none; font-size: 19px; color: var(--slate-500); }
.confirm-line--loss .material-symbols-outlined { color: var(--danger); }
/* The accent line answers the question actually in the user's head ("is the expensive thing at
   risk?") and is why tier 3 doesn't need a typed confirmation. It is not optional decoration. */
.confirm-line--safe .material-symbols-outlined { color: var(--color-accent); }

/* Pot breakdown in the finish → calculate prompt (design 5e). The total's 2px rule matches
   .data-table tfoot, so the same "this is the sum" signal is used in both places. */
.confirm-pot {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 11px 14px;
    font-size: 0.875rem;
}
.confirm-pot + .confirm-pot { border-top: 1px solid var(--gray-200); }
.confirm-pot__label { flex: 1; font-weight: var(--font-weight-medium); }
.confirm-pot__amount { color: var(--text-muted); font-variant-numeric: tabular-nums; }
.confirm-pot--total { border-top: 2px solid var(--text) !important; }
.confirm-pot--total .confirm-pot__label,
.confirm-pot--total .confirm-pot__amount { font-weight: var(--font-weight-bold); color: var(--text); }

.confirm-sheet__alt-head {
    font-size: 0.7rem;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-muted);
    padding: 0 2px var(--space-2);
}

.confirm-sheet__note {
    display: flex;
    align-items: flex-start;
    gap: 9px;
    margin-top: var(--space-3);
}
.confirm-sheet__note .material-symbols-outlined { flex: none; font-size: 18px; color: var(--slate-500); }
.confirm-sheet__note p {
    margin: 0;
    font-size: 0.8rem;
    color: var(--text-muted);
    line-height: 1.5;
}

.confirm-actions {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    margin-top: 18px;
}
.confirm-actions .btn { width: 100%; }

@media (min-width: 768px) {
    .confirm-sheet { max-width: 440px; border-radius: 14px; box-shadow: var(--shadow-lg); }
    /* Inline, right-aligned, destructive LAST — the reverse of the stacked phone order, where the
       primary sits on top under the thumb. row-reverse gets that from the same DOM order. */
    .confirm-actions {
        flex-direction: row-reverse;
        justify-content: flex-start;
    }
    .confirm-actions .btn { width: auto; }
}

/* Inline "Week ▾" picker trigger. Named for the rounds list it started on; that list moved to a
   segmented control, but the per-week result tabs (leaderboard, course stats, odds, live scoring)
   still use this shape — a week list runs to 20–40 options, which is a sheet, not a segment. */
.round-filter {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.85rem;
}

.round-filter-label {
    font-size: 0.8rem;
    text-transform: uppercase;
    font-weight: 600;
    color: var(--gray-650);
}

.round-filter-btn {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    background: var(--surface);
    border: 1px solid var(--gray-350);
    border-radius: 6px;
    padding: 0.45rem 0.7rem;
    font-size: 0.9rem;
    font-weight: 600;
    color: var(--text);
    cursor: pointer;
}

.round-filter-caret {
    color: var(--gray-600);
    font-size: 0.7rem;
}

/* Filter options inside the bottom sheet. */
.filter-options {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
}

.filter-option {
    width: 100%;
    text-align: left;
    background: var(--surface);
    border: 1px solid var(--gray-300);
    border-radius: 8px;
    padding: 0.85rem 1rem;
    font-size: 1rem;
    font-weight: 600;
    color: var(--text);
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}

.filter-option:hover {
    border-color: var(--navy);
}

.filter-option.active {
    border-color: var(--navy);
    background: var(--surface-1);
}

.filter-option:disabled {
    color: var(--gray-450);
    cursor: not-allowed;
    background: var(--surface-3);
}

/* Compact chip-grid variant of the option sheet — for pickers whose options have short labels
   (the per-week selectors). 20–40 weeks wrap into a few rows of tappable chips instead of a
   long scroll of full-width rows. Scoped via a modifier so the default full-width list (status
   filters, view switcher, SheetSelect) is unaffected. The full course label moves to each
   chip's tooltip + the subtitle under the trigger. */
.filter-options--grid {
    flex-direction: row;
    flex-wrap: wrap;
    gap: 0.5rem;
}

.filter-options--grid .filter-option {
    width: auto;
    flex: 0 0 auto;
    min-width: 4.25rem;
    text-align: center;
    padding: 0.7rem 0.85rem;
    font-size: 0.95rem;
}

/* ===== Stepper field =====
   A bounded numeric sized for a thumb: two 52px round buttons flanking a large tabular value, the
   presets people actually pick, and a consequence note. Replaces <input type="number"> for the
   handicap allowance, whose spinner arrows were a ~10px target and whose keyboard could type a
   value the field doesn't accept. */
.stepper-field__row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
}
.stepper-field__btn {
    flex: none;
    width: 52px;
    height: 52px;
    display: grid;
    place-items: center;
    border: 1px solid var(--border);
    border-radius: 50%;
    background: var(--surface);
    color: var(--text);
    font-family: inherit;
    font-size: 1.5rem;
    font-weight: var(--font-weight-semibold);
    line-height: 1;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
.stepper-field__btn:hover:not(:disabled) { background: var(--surface-subtle); }
.stepper-field__btn:disabled { color: var(--ink-disabled); cursor: not-allowed; }

.stepper-field__value { flex: 1; min-width: 0; text-align: center; }
.stepper-field__number {
    font-size: 2.75rem;
    font-weight: var(--font-weight-bold);
    line-height: 1;
    font-variant-numeric: tabular-nums;   /* the value must not jog as digits change */
}
.stepper-field__suffix {
    font-size: 1.4rem;
    font-weight: var(--font-weight-bold);
    color: var(--text-muted);
}
.stepper-field__caption {
    margin-top: var(--space-1);
    font-size: var(--text-sm);
    color: var(--text-muted);
}

.stepper-field__presets {
    display: flex;
    gap: var(--space-2);
    margin-top: var(--space-4);
}
.stepper-field__preset {
    flex: 1;
    padding: 9px var(--space-1);
    border: 1px solid var(--border);
    border-radius: var(--radius-pill);
    background: var(--surface);
    color: var(--text-muted);
    font-family: inherit;
    font-size: 0.85rem;
    font-weight: var(--font-weight-semibold);
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
.stepper-field__preset.is-active {
    background: var(--surface-inverse);
    border-color: var(--surface-inverse);
    color: var(--on-solid);
}
.stepper-field__preset:disabled { opacity: 0.6; cursor: not-allowed; }

.stepper-field__note {
    display: flex;
    align-items: flex-start;
    gap: 0.6rem;
    margin-top: var(--space-4);
    padding: 12px 14px;
    background: var(--surface-1);
    border-radius: 10px;
    font-size: var(--text-sm);
    color: var(--text-muted);
    line-height: 1.5;
}
.stepper-field__note .material-symbols-outlined {
    flex: none;
    font-size: 20px;
    color: var(--warning);
}

/* ── SheetSelect's richer rows ──
   Scoped to .sheet-option so the plain .filter-option lists elsewhere (status filters, view
   switchers) keep the border-and-tint selected look they already have. A picker row can carry a
   colour swatch, a muted line of the numbers that actually drive the choice, and a section
   heading; the selected row gets an accent wash plus a trailing check rather than a border, since
   at a glance a tick reads as "this one" far faster than a slightly different outline. */
.sheet-option {
    display: flex;
    align-items: center;
    gap: 0.65rem;
    min-height: 48px;
}
.sheet-option__swatch {
    flex: none;
    width: 14px;
    height: 14px;
    border-radius: 50%;
    /* The ring is what makes a white or cream tee visible on a white sheet. */
    box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.25);
}
.sheet-option__body { flex: 1; min-width: 0; }
.sheet-option__label { display: block; }
.sheet-option__sub {
    display: block;
    margin-top: 2px;
    font-size: 0.8rem;
    font-weight: var(--font-weight-base);
    color: var(--text-muted);
    /* Yardage / rating / slope line up column-wise down the list. */
    font-variant-numeric: tabular-nums;
}
.sheet-option.active {
    border-color: var(--border);
    background: color-mix(in srgb, var(--color-accent) 8%, transparent);
}
.sheet-option__check {
    flex: none;
    font-size: 20px;
    color: var(--color-accent);
}
.sheet-option-group {
    padding: var(--space-3) var(--space-1) var(--space-1);
    font-size: 0.72rem;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-muted);
}
.sheet-option-group:first-child { padding-top: var(--space-1); }

.sheet-select-trigger__sub {
    display: block;
    margin-top: 2px;
    font-size: 0.8rem;
    font-weight: var(--font-weight-base);
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

.sheet-search {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: var(--space-3);
    padding: 10px 12px;
    background: var(--gray-150);
    border-radius: 10px;
    color: var(--text-muted);
}
.sheet-search .material-symbols-outlined { font-size: 20px; }
.sheet-search__input {
    flex: 1;
    min-width: 0;
    border: none;
    background: none;
    color: var(--text);
    /* 16px keeps parity with the iOS focus-zoom guard on real inputs. */
    font-size: 1rem;
    font-family: inherit;
}
.sheet-search__input:focus { outline: none; }

.sheet-select-intro,
.sheet-select-foot,
.sheet-select-empty {
    font-size: var(--text-sm);
    color: var(--text-muted);
    line-height: 1.5;
    margin: 0 var(--space-1) var(--space-3);
}
.sheet-select-foot { margin: var(--space-3) var(--space-1) 0; }
.sheet-select-empty { margin: var(--space-4) var(--space-1); text-align: center; }

/* ── SheetMultiSelect ──
   Rides SheetSelect's rows (.sheet-option, its swatch, sub-line and group headings) and adds the
   three things a many-pick needs that a one-pick doesn't: a box that says "tick me", bulk chips,
   and a docked commit bar. The selected wash comes free from .sheet-option.active. */

/* The box is the affordance — an accent wash alone reads as "current", which is what a
   single-select row means, and the two lists sit two taps apart on the same pane. */
.sms-box {
    flex: none;
    display: grid;
    place-items: center;
    width: 22px;
    height: 22px;
    border: 1.5px solid var(--border-strong);
    border-radius: 6px;
    background: var(--surface);
    transition: background-color 120ms ease, border-color 120ms ease;
}
.sms-box .material-symbols-outlined {
    font-size: 17px;
    color: transparent;
    transition: color 120ms ease;
}
.sms-box.is-on {
    background: var(--color-accent);
    border-color: var(--color-accent);
}
/* --on-hue, not --on-solid: the accent brightens in dark mode, where white ink on it lands ~2.8:1. */
.sms-box.is-on .material-symbols-outlined { color: var(--on-hue); }

/* A row is a checkbox, so it must not also look like a link. */
.sms-option { text-align: left; }

/* Bulk verbs. Ghost pills on --control-fill so they read as a filter strip above the list rather
   than as four competing buttons; the lit state is the accent wash the rows use, so "this chip is
   satisfied" and "this row is picked" are visibly the same fact. */
.sms-picks {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin: 0 var(--space-1) var(--space-3);
}
.sms-pick {
    min-height: 34px;
    padding: 0 0.7rem;
    border: 1px solid var(--hairline);
    border-radius: 999px;
    background: var(--control-fill);
    color: var(--text);
    font-size: 0.82rem;
    font-family: inherit;
    font-weight: var(--font-weight-semibold);
    cursor: pointer;
    white-space: nowrap;
}
.sms-pick:hover { background: var(--control-fill-strong); }
.sms-pick.is-on {
    border-color: var(--color-accent);
    background: color-mix(in srgb, var(--color-accent) 12%, transparent);
    color: var(--color-accent);
}
.sms-pick--clear { color: var(--text-muted); font-weight: var(--font-weight-base); }

/* Docked to the panel's foot the way .pm-sheet__actions docks, and for the same reason: .modal-panel
   is the scroll container, so a footer in normal flow leaves with the twentieth row. The negative
   margins cancel the panel's 1.5rem padding (and its safe-area inset) so the bar reaches the edges
   instead of floating in a gutter. */
.sms-foot {
    position: sticky;
    bottom: calc(-1.5rem - env(safe-area-inset-bottom));
    z-index: 1;
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin: var(--space-3) -1.5rem calc(-1.5rem - env(safe-area-inset-bottom));
    padding: var(--space-3) 1.5rem calc(var(--space-3) + env(safe-area-inset-bottom));
    border-top: 1px solid var(--hairline);
    background: var(--surface);
}
.sms-foot__count {
    flex: 1;
    min-width: 0;
    font-size: var(--text-sm);
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}
.sms-foot__go { flex: none; min-height: 44px; }

/* Under the thumb on a phone: the commit button spans the bar with the count above it, so the
   primary lands where the hand already is rather than in the far corner. Plain `column`, not the
   `column-reverse` .pm-sheet__actions uses — that file's DOM order is the other way round. */
@media (max-width: 480px) {
    .sms-foot {
        flex-direction: column;
        align-items: stretch;
        gap: var(--space-2);
    }
    .sms-foot__count { flex: none; text-align: center; }
    .sms-foot__go { width: 100%; min-height: 48px; }
}

/* The escape hatch at the bottom of a picker — "the thing I want isn't in this list". Accent ink
   because it's the one action in a sheet otherwise made entirely of choices. */
.sheet-select-add {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    min-height: 48px;
    margin-top: var(--space-2);
    padding: 0 var(--space-1);
    color: var(--color-accent);
    font-weight: var(--font-weight-semibold);
    text-decoration: none;
}

/* ===== Unified dropdown (SheetSelect) =====
   Bordered-field trigger: looks like a text input so it reads unambiguously as a form control,
   with a chevron as the "this opens" affordance. Full-width, 44px tap target. The matching bottom
   sheet reuses .modal-panel + .filter-options above. */
.sheet-select-trigger {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    width: 100%;
    min-height: 44px;
    padding: 0.55rem 0.5rem 0.55rem 0.85rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 8px;
    /* 16px keeps parity with the iOS focus-zoom guard on real inputs. */
    font-size: 1rem;
    font-family: inherit;
    font-weight: 500;
    color: var(--text);
    text-align: left;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    transition: border-color 0.15s, box-shadow 0.15s;
}

/* Width modifier for inline / filter placements that shouldn't be full-bleed. */
.sheet-select-trigger--auto {
    width: auto;
    min-width: 12rem;
}

.sheet-select-trigger:hover:not(:disabled) {
    border-color: var(--gray-500);
}

.sheet-select-trigger:focus-visible,
.sheet-select-trigger.open {
    outline: none;
    border-color: var(--navy);
    box-shadow: 0 0 0 3px rgba(44, 62, 80, 0.12);
}

.sheet-select-trigger:disabled {
    background: var(--gray-100);
    color: var(--gray-500);
    cursor: not-allowed;
}

.sheet-select-trigger__value {
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.sheet-select-trigger__value.placeholder {
    color: var(--gray-500);
    font-weight: 400;
}

.sheet-select-trigger__caret {
    flex-shrink: 0;
    color: var(--text-muted);
    font-size: 1.4rem;
}

.sheet-select-trigger:disabled .sheet-select-trigger__caret {
    color: var(--gray-450);
}

/* Stacked variant: a SheetSelect opened from inside an already-open .modal-panel (z-index 201)
   must layer above it. Standalone usage is unaffected (just a higher z than the page). */
.modal-backdrop--stacked {
    z-index: 220;
}

.modal-panel--stacked {
    z-index: 221;
}

/* ===== Unified inline/in-table dropdown (.native-select) =====
   Compact native <select> styled to match the SheetSelect trigger — used for dense in-table
   micro-selects (per-player tee, position pairings, attendance) where a full bottom sheet would be
   heavy. appearance:none + an inline chevron SVG so the caret looks identical across OSes. */
.native-select {
    appearance: none;
    -webkit-appearance: none;
    background-color: var(--surface);
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23667085' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 0.5rem center;
    background-size: 1rem;
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 0.4rem 1.9rem 0.4rem 0.6rem;
    font-size: 0.9rem;
    font-family: inherit;
    color: var(--text);
    min-height: 36px;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    transition: border-color 0.15s, box-shadow 0.15s;
}

.native-select:hover:not(:disabled) {
    border-color: var(--gray-500);
}

.native-select:focus {
    outline: none;
    border-color: var(--navy);
    box-shadow: 0 0 0 2px rgba(44, 62, 80, 0.12);
}

.native-select:disabled {
    background-color: var(--gray-100);
    color: var(--gray-500);
    cursor: not-allowed;
    opacity: 1;
}

/* Set-matchups dialog pairing rows — the two team pickers share the row width and shrink
   (min-width:0 → the trigger label truncates) so long team names never overflow the modal. */
.pairing-row {
    padding: 0.6rem 0;
    border-bottom: 1px solid var(--gray-200);
}

.pairing-row:last-child {
    border-bottom: none;
}

.pairing-label {
    font-size: 0.68rem;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--gray-500);
    margin-bottom: 0.35rem;
}

.pairing-selects {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.pairing-selects .sheet-select-trigger {
    flex: 1 1 0;
    min-width: 0;
}

.pairing-vs {
    flex: 0 0 auto;
    color: var(--gray-500);
    font-weight: 600;
    font-size: 0.85rem;
}

/* ===== Round Setup wizard ===== */
.wiz-steps {
    display: flex;
    gap: 0.4rem;
    margin-bottom: 1rem;
    flex-wrap: wrap;
}

.wiz-step {
    flex: 1;
    min-width: 70px;
    text-align: center;
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.02em;
    color: var(--gray-500);
    padding: 0.4rem 0.3rem;
    border-bottom: 3px solid var(--gray-300);
}

.wiz-step.active {
    color: var(--text);
    border-bottom-color: var(--navy);
}

.wiz-step.done {
    color: var(--color-accent);
    border-bottom-color: var(--color-accent);
}

.wiz-search-row {
    display: flex;
    gap: 0.5rem;
    margin-bottom: 1rem;
}

.wiz-search-input {
    flex: 1;
    padding: 0.7rem 0.85rem;
    border: 1px solid var(--gray-350);
    border-radius: 6px;
    font-size: 1rem;
}

.wiz-search-input:focus {
    outline: none;
    border-color: var(--navy);
}

.wiz-search-btn {
    width: auto;
    flex: 0 0 auto;
    padding-left: 1.25rem;
    padding-right: 1.25rem;
}

.wiz-resolving {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    color: var(--gray-650);
    padding: 1rem 0;
}

.wiz-results {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.wiz-result {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    width: 100%;
    text-align: left;
    background: var(--surface);
    border: 1px solid var(--gray-300);
    border-radius: 8px;
    padding: 0.85rem 1rem;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}

.wiz-result:hover {
    border-color: var(--navy);
    background: var(--surface-1);
}

.wiz-result:active {
    transform: scale(0.99);
}

.wiz-result-main {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.wiz-result-name {
    font-weight: 600;
    color: var(--text);
}

.wiz-result-sub {
    font-size: 0.8rem;
    color: #777;
    margin-top: 0.15rem;
}

.wiz-tag {
    flex: 0 0 auto;
    font-size: 0.65rem;
    text-transform: uppercase;
    font-weight: 700;
    color: var(--color-accent);
    background: var(--surface-2);
    border-radius: 999px;
    padding: 0.2rem 0.55rem;
}

.wiz-selected {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    background: var(--gray-150);
    border-radius: 8px;
    padding: 0.75rem 1rem;
    margin-bottom: 1rem;
}

.wiz-selected-label {
    font-size: 0.7rem;
    text-transform: uppercase;
    color: var(--gray-600);
    font-weight: 600;
}

.wiz-selected-name {
    font-weight: 600;
    color: var(--text);
}

/* Segmented control — large, easy-to-tap toggle row. */
.seg-control {
    display: flex;
    gap: 0;
    border: 1px solid var(--gray-400);
    border-radius: 8px;
    overflow: hidden;
}

.seg-option {
    flex: 1;
    background: var(--surface);
    border: none;
    border-right: 1px solid var(--gray-400);
    padding: 0.7rem 0.5rem;
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--gray-700);
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}

.seg-option:last-child {
    border-right: none;
}

.seg-option.active {
    background: var(--navy);
    color: white;
}

.seg-option:disabled {
    color: var(--gray-450);
    cursor: not-allowed;
    background: var(--gray-100);
}

/* Tee picker — tappable cards. */
.wiz-tees {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.tee-card {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.2rem;
    width: 100%;
    text-align: left;
    background: var(--surface);
    border: 2px solid var(--gray-300);
    border-radius: 8px;
    padding: 0.7rem 0.9rem;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}

.tee-card.active {
    border-color: var(--navy);
    background: var(--surface-1);
}

.tee-card-name {
    font-weight: 600;
    color: var(--text);
    display: flex;
    align-items: center;
    gap: 0.4rem;
}

.tee-dot {
    width: 12px;
    height: 12px;
    border-radius: 50%;
    border: 1px solid rgba(0, 0, 0, 0.2);
    display: inline-block;
}

.tee-card-meta {
    font-size: 0.8rem;
    color: #777;
}

/* Big tappable pick-one cards (event type on the create form, etc.) — tee-card visual language. */
.choice-cards {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.choice-card {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.2rem;
    width: 100%;
    text-align: left;
    background: var(--surface);
    border: 2px solid var(--gray-300);
    border-radius: var(--radius-md);
    padding: 0.7rem 0.9rem;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}

.choice-card.selected {
    border-color: var(--color-accent);
    background: var(--surface-1);
}

/* In-flight only (a preset is being applied), never a permanent unavailable state — those get
   an explanation, not a greyed card. */
.choice-card:disabled {
    opacity: 0.55;
    cursor: default;
}

.choice-card-title {
    font-weight: 600;
    color: var(--text);
}

.choice-card-blurb {
    font-size: 0.8rem;
    color: var(--text-muted);
}

.wiz-advanced-toggle {
    background: none;
    border: none;
    color: var(--text);
    font-weight: 600;
    font-size: 0.9rem;
    cursor: pointer;
    padding: 0.5rem 0;
}

.wiz-advanced {
    border-top: 1px solid var(--gray-200);
    padding-top: 0.75rem;
    margin-bottom: 0.5rem;
}

.wiz-actions {
    display: flex;
    gap: 0.75rem;
    margin-top: 1rem;
}

.wiz-actions .btn {
    flex: 1;
}

.wiz-next {
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
}

.wiz-section {
    border-top: 1px solid var(--gray-200);
    margin-top: 1rem;
    padding-top: 0.75rem;
}

.wiz-copy-row {
    display: flex;
    gap: 0.5rem;
    align-items: center;
    margin-top: 0.35rem;
}

.wiz-copy-row .link-input {
    flex: 1;
}

.wiz-copy-row .btn {
    width: auto;
    flex: 0 0 auto;
}

.wiz-hint {
    font-size: 0.78rem;
    color: var(--gray-600);
    margin-top: 0.35rem;
}

/* Players checklist — large tap rows. */
.wiz-players-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    margin-bottom: var(--space-2);
}

.wiz-players-head .btn {
    width: auto;
    flex: 0 0 auto;
}

.wiz-players {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    margin-bottom: 0.75rem;
}

.wiz-player {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    background: var(--surface);
    border: 1px solid var(--gray-300);
    border-radius: 8px;
    padding: 0.7rem 0.9rem;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}

.wiz-player.checked {
    border-color: var(--navy);
    background: var(--surface-1);
}

.wiz-player input[type="checkbox"] {
    width: 20px;
    height: 20px;
    flex: 0 0 auto;
    accent-color: var(--navy);
}

.wiz-player-name {
    flex: 1;
    font-weight: 600;
    color: var(--text);
}

.wiz-player-hcp {
    flex: 0 0 auto;
    font-size: 0.8rem;
    color: #777;
    font-variant-numeric: tabular-nums;
}

.wiz-addplayer-btn {
    width: auto;
}

/* First-run event wizard (ONBOARDING-PLAN Phase 2) — roster with inline handicaps + multi-date pick. */
.wiz-roster {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    margin-bottom: 0.75rem;
}

.wiz-roster-row {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    background: var(--surface);
    border: 1px solid var(--gray-300);
    border-radius: 8px;
    padding: 0.6rem 0.85rem;
}

.wiz-roster-name {
    flex: 1;
    font-weight: 600;
    color: var(--text);
}

/* Template card "Includes: …" summary line (ONBOARDING-PLAN 4.1). */
.wiz-tpl-includes {
    display: block;
    margin-top: 0.35rem;
    font-size: 0.72rem;
    font-weight: 600;
    color: var(--color-accent);
    letter-spacing: 0.01em;
}

.wiz-hcp-field input {
    width: 68px;
    padding: 0.4rem 0.5rem;
    text-align: center;
    border: 1px solid var(--gray-350);
    border-radius: 6px;
    font-variant-numeric: tabular-nums;
}

.wiz-dates {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    margin-bottom: 0.5rem;
}

.wiz-date-row {
    display: flex;
    align-items: center;
    gap: 0.6rem;
}

.wiz-date-num {
    flex: 0 0 auto;
    min-width: 52px;
    font-size: 0.78rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.02em;
    color: var(--text-muted);
}

.wiz-date-row input[type="date"] {
    flex: 1;
    padding: 0.55rem 0.7rem;
    border: 1px solid var(--gray-350);
    border-radius: 6px;
    font-size: 0.95rem;
}

.wiz-date-remove {
    flex: 0 0 auto;
    background: none;
    border: none;
    color: var(--gray-600);
    font-size: 1rem;
    cursor: pointer;
    padding: 0.25rem 0.4rem;
    line-height: 1;
}

.wiz-date-remove:hover {
    color: var(--danger);
}

/* Home empty state gets a CTA button — keep it out of the italic run. */
.empty-state .btn {
    font-style: normal;
    margin-top: 0.75rem;
}

.wiz-groupbuild {
    border-top: 1px solid var(--gray-200);
    margin-top: 1rem;
    padding-top: 0.5rem;
}

/* Manual in-wizard group assignment. */
.wiz-manual {
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
}

.wiz-mgroup {
    background: var(--surface);
    border: 1px solid var(--gray-300);
    border-radius: 8px;
    padding: 0.7rem 0.9rem;
}

.wiz-mgroup-head {
    font-weight: 600;
    color: var(--text);
    margin-bottom: 0.4rem;
}

.wiz-mgroup-members {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    margin-bottom: 0.5rem;
}

.wiz-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    background: var(--surface-2);
    border-radius: 999px;
    padding: 0.25rem 0.3rem 0.25rem 0.7rem;
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--text);
}

.wiz-chip-x {
    border: none;
    background: var(--gray-300);
    color: var(--text);
    border-radius: 50%;
    width: 18px;
    height: 18px;
    line-height: 1;
    font-size: 0.7rem;
    cursor: pointer;
    padding: 0;
}

.wiz-massign-btn {
    width: auto;
}

/* Player-picker bottom sheet (manual grouping). */
.wiz-pick-list {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    margin-bottom: 1rem;
}

.wiz-pick {
    width: 100%;
    text-align: left;
    background: var(--surface);
    border: 1px solid var(--gray-300);
    border-radius: 8px;
    padding: 0.85rem 1rem;
    font-size: 1rem;
    font-weight: 600;
    color: var(--text);
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}

.wiz-pick:hover {
    border-color: var(--navy);
    background: var(--surface-1);
}

.wiz-pick:active {
    transform: scale(0.99);
}

.wiz-unassigned {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
    font-size: 0.85rem;
    color: var(--gray-700);
    padding: 0.5rem 0.2rem 0;
}

/* Round Pot Allocation: a game switched off for this one round (WAGER-MODEL-PLAN Phase 8a).
   Muted, never hidden — a row you can't see is a game you can't turn back on, which is the
   same reasoning that keeps a blocked overflow-menu item on screen. The Playing cell keeps
   full contrast because it's the way back; --ink-disabled rather than --border-strong so the
   greyed row still says what it is on a dark ground. */
.data-table tr.pot-row--off > td { color: var(--ink-disabled); }
.data-table tr.pot-row--off > td:first-child { color: var(--text); }

/* Wager toggles. */
.wiz-wagers {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    margin-bottom: 1rem;
}

.wiz-wager {
    background: var(--surface);
    border: 1px solid var(--gray-300);
    border-radius: 8px;
    padding: 0.7rem 0.9rem;
}

.wiz-wager.on {
    border-color: var(--navy);
    background: var(--surface-1);
}

.wiz-wager-head {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    cursor: pointer;
}

.wiz-wager-label {
    font-weight: 600;
    color: var(--text);
}

.wiz-wager-amount {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    margin-top: 0.6rem;
}

.wiz-amount-prefix {
    font-weight: 600;
    color: var(--gray-700);
}

.wiz-wager-amount input {
    width: 8rem;
}

.wiz-wager-pots {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    margin-top: 0.6rem;
}

.wiz-pot {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
}

.wiz-pot-label {
    font-size: 0.7rem;
    text-transform: uppercase;
    color: var(--gray-600);
    font-weight: 600;
}

.wiz-pot .wiz-wager-amount {
    margin-top: 0;
}

.wiz-pot .wiz-wager-amount input {
    width: 6rem;
}

.wiz-wager-scoring {
    margin-top: 0.75rem;
}

.wiz-wager-scoring .seg-control {
    margin-top: 0.25rem;
}

.wiz-back {
    background: none;
    border: none;
    color: var(--text);
    font-weight: 600;
    font-size: 0.85rem;
    cursor: pointer;
    padding: 0 0 0.5rem;
}

.wiz-back:disabled {
    color: var(--gray-450);
    cursor: not-allowed;
}

/* Review list (Done stage). */
.wiz-review {
    margin: 0 0 1rem;
}

.wiz-review > div {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.5rem 0;
    border-bottom: 1px solid var(--gray-200);
}

.wiz-review dt {
    font-size: 0.75rem;
    text-transform: uppercase;
    color: var(--gray-600);
    font-weight: 600;
    margin: 0;
}

.wiz-review dd {
    margin: 0;
    text-align: right;
    color: var(--text);
    font-weight: 600;
}

/* The navy "Back to Score Entry" banner is gone — the scorer's return affordance is now
   .scoring-return in 12-live-scoring.css, which names the hole it goes back to. */

/* The scoring screen's two results links are gone with the same redesign: the header's
   .live-leaderboard-btn is now the LEADING chip (.lvs-lead) and the supporting screens'
   .live-leaderboard-link is .lvs-resultslink — both in 12-live-scoring.css. */

/* ===== League pages ===== */
.form-row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    align-items: flex-end;
    margin-bottom: var(--space-3);
}

.form-group-grow {
    flex: 1 1 240px;
}

.member-chip {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    padding: 2px 8px;
    border: 1px solid #d1d5db;
    border-radius: 12px;
    margin-right: var(--space-2);
    margin-bottom: var(--space-1);
    background: var(--surface-3);
    font-size: 0.8rem;
}

.captain-tag {
    display: inline-block;
    background: #1e40af;
    color: white;
    padding: 1px 6px;
    border-radius: 3px;
    font-size: 0.65rem;
    font-weight: bold;
}

.chip-action {
    background: none;
    border: 1px solid #c7ccd4;
    color: #374151;
    cursor: pointer;
    font-size: 0.62rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.02em;
    line-height: 1;
    padding: 2px 5px;
    border-radius: 3px;
}

.chip-action:hover {
    border-color: #1e40af;
    color: #1e40af;
}

.member-remove {
    background: none;
    border: none;
    color: #6b7280;
    cursor: pointer;
    font-size: 1rem;
    line-height: 1;
    padding: 0 2px;
}

.member-remove:hover {
    color: #b91c1c;
}

.add-member {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    margin-top: var(--space-1);
}

/* The SheetSelect trigger is width:100% by default, which would push the captain
   checkbox + Add button past the (narrow, on mobile) table cell. Let it flex-shrink
   and wrap the controls below it on small screens instead of overrunning. */
.add-member .sheet-select-trigger {
    width: auto;
    flex: 1 1 150px;
    min-width: 0;
}

.captain-checkbox {
    font-size: 0.8rem;
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
}

.col-actions {
    width: 1%;
    white-space: nowrap;
}

.inactive-row {
    opacity: 0.5;
}

.button-row {
    display: flex;
    gap: var(--space-3);
    margin-top: var(--space-3);
}

.status-warning {
    background: #fef3c7;
    color: #92400e;
    padding: 2px 8px;
    border-radius: 4px;
    font-size: 0.75rem;
    font-weight: 600;
}

.standings-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-4);
}

.standings-grid .span-full {
    grid-column: 1 / -1;
}

.standings-grid .card-title {
    margin-top: 0;
    margin-bottom: var(--space-3);
}

.col-rank {
    width: 40px;
    text-align: center;
}

.col-numeric {
    text-align: right;
    font-variant-numeric: tabular-nums;
}

@media (max-width: 768px) {
    .standings-grid {
        grid-template-columns: 1fr;
    }
}

/* ===== Match-play matchup chips + detail ===== */
.matchup-chips {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}

.matchup-chip {
    display: inline-block;
    padding: 2px 10px;
    border: 1px solid #d1d5db;
    border-radius: 12px;
    background: var(--surface-2);
    color: var(--text);
    font-size: 0.8rem;
    text-decoration: none;
}

.matchup-chip:hover {
    background: var(--gray-200);
    border-color: var(--gray-500);
}

.matchup-header {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-5);
    padding: var(--space-4) 0;
}

.matchup-header .team-score {
    text-align: center;
    flex: 0 1 220px;
}

.matchup-header .team-name {
    font-size: 1rem;
    color: #374151;
}

.matchup-header .team-points {
    font-size: 2.5rem;
    font-weight: 700;
    color: #111827;
    line-height: 1;
    margin-top: var(--space-1);
}

.matchup-header .vs {
    color: var(--gray-500);
    font-weight: 600;
    font-size: 0.875rem;
}

.matchup-header .overridden-tag {
    font-size: 0.7rem;
    color: #92400e;
    margin-top: var(--space-1);
}

.adjustment-reason {
    font-size: 0.8rem;
    color: #6b7280;
    margin-left: var(--space-2);
    font-style: italic;
}

.slot-summary {
    color: #6b7280;
    font-size: 0.875rem;
    margin-bottom: var(--space-2);
}

/* Running match standing badge on the matchup detail slot sections (Phase 4). */
.slot-standing {
    display: inline-block;
    margin-bottom: var(--space-2);
    padding: 2px 10px;
    border-radius: 12px;
    background: #eef2ff;
    color: #3730a3;
    font-size: 0.85rem;
    font-weight: 700;
}

.data-table.compact {
    font-size: 0.8rem;
}

.data-table tr.winner-a td {
    background: #dcfce7;
}

.data-table tr.winner-b td {
    background: #fee2e2;
}

.hole-winner {
    text-align: center;
    color: #6b7280;
    font-weight: 600;
}

.status-success {
    background: #dcfce7;
    color: #166534;
    padding: 2px 8px;
    border-radius: 4px;
    font-size: 0.75rem;
    font-weight: 600;
}

.group-tee-time {
    display: inline-block;
    margin-left: var(--space-2);
    padding: 2px 8px;
    background: #eff6ff;
    border: 1px solid #bfdbfe;
    border-radius: 12px;
    color: #1e3a8a;
    font-size: 0.75rem;
    font-weight: 600;
    vertical-align: middle;
}

/* ===== Pairing sheet ===== */
.pairing-sheet-actions {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: var(--space-3);
}

.pairing-sheet {
    max-width: 920px;
    margin: 0 auto;
}

.pairing-sheet-header {
    text-align: center;
    margin-bottom: var(--space-4);
    padding-bottom: var(--space-3);
    border-bottom: 1px solid var(--gray-200);
}

.pairing-sheet-header h1 {
    margin: 0;
    font-size: 1.25rem;
}

.pairing-sheet-header .course-line {
    color: #6b7280;
    font-size: 0.85rem;
}

.pairing-card {
    border: 1px solid #d1d5db;
    border-radius: 8px;
    padding: var(--space-3) var(--space-4);
    margin-bottom: var(--space-3);
    page-break-inside: avoid;
    break-inside: avoid;
}

.pairing-card-header {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    margin-bottom: var(--space-2);
    font-weight: 600;
}

.pairing-card-header .group-number {
    font-size: 1rem;
}

.pairing-card-header .tee-time {
    font-size: 1.1rem;
    color: var(--text);
}

.pairing-table {
    margin: 0;
    font-size: 0.85rem;
}

@media print {
    .no-print, .main-nav, header, footer { display: none !important; }
    body { background: var(--surface); padding: 0; }
    .pairing-card {
        box-shadow: none;
        border-color: var(--gray-500);
    }
}

/* ===== Touch Targets (P1.2) =====
   Bring high-frequency interactive controls up toward the ~44px touch minimum.
   The close button is safe to enlarge everywhere; the rest are scoped to mobile
   so desktop table/toolbar density is unchanged. Bottom-nav items (56px) and
   .more-link (44px) are already sized in the nav section. */
.modal-close-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 44px;
    min-height: 44px;
}

/* Public results / schedule layout. Defined globally (NOT in a page <style>) so the
   registration pages that reuse these classes — PublicSchedule, SlotPicker — are styled
   on a cold load, not only while EventResults.razor happens to be in the render tree.
   EventResults keeps only its @media print overrides locally. */
.results-page { max-width: 960px; margin: 0 auto; padding: 1.5rem; }
.results-header { margin-bottom: 2rem; }
.results-header h1 { margin-bottom: 0.25rem; }
.results-flight, .results-money, .results-side-games, .results-rounds { margin-bottom: 2.5rem; }
.results-round { margin-bottom: 0.5rem; }
.results-round summary { cursor: pointer; padding: 0.5rem 0; font-weight: 500; }
.results-footer { margin-top: 3rem; padding-top: 1rem; border-top: 1px solid var(--gray-350); text-align: center; }

/* Small helpers flagged undefined in the Tier-1 audit (rendered as default block before). */
.tiebreak-tag { font-size: 0.7rem; color: var(--gray-600); white-space: nowrap; }
/* .account-group / .account-group-header are GONE — they existed only for Home's multi-account
   branch, and the account-surfaces redesign made the grouped shape the ONLY shape, drawn as a
   .set-card per account in 24-account.css. */

@media (max-width: 480px) {
    .results-page { padding: 0.75rem; }
    /* Long label/value rows wrap instead of crowding on a narrow phone. */
    .detail-row { flex-wrap: wrap; }
}

/* Touch-target sweep — ≤768px only (desktop density unchanged): secondary nav / disclosure
   elements that were below the 44px floor (Tier-1 audit P2). */
@media (max-width: 768px) {
    .sub-nav li a {
        display: inline-flex;
        align-items: center;
        min-height: 44px;
    }

    .results-round summary {
        min-height: 44px;
        padding: 0.75rem 0;
    }

}

@media (max-width: 768px) {
    /* Buttons grow via vertical padding so the label stays centered (inline-block).
       Horizontal padding is left untouched. */
    .btn {
        padding-top: 0.8rem;
        padding-bottom: 0.8rem;
    }

    .btn-small {
        padding-top: 0.7rem;
        padding-bottom: 0.7rem;
    }

    /* Result / week pills: guarantee height and vertically center the label
       (+ in-progress / upcoming markers). */
    .round-pills li {
        min-height: 40px;
        display: inline-flex;
        align-items: center;
    }

}

/* ===== Responsive card tables (mobile) — P1.3 =====
   Opt-in via class "data-table--cards" on a .data-table. On phones each row
   collapses to a card and each cell becomes a labelled row (label pulled from
   the cell's data-label attribute). Desktop renders the normal table. */

/* card-only content is mobile-card-only; hidden in the desktop table. The matching
   "show in card" rule lives in the @media block below. */
.card-only {
    display: none;
}

/* Mobile-only totals summary card (Skins / Money List). On phones the spreadsheet-style
   tfoot reads as a second table, so we hide it (table gets .data-table--summary) and show
   this purpose-built summary instead. Desktop keeps the tfoot and hides this card. */
.totals-summary-card {
    display: none;
}

@media (max-width: 768px) {
    .data-table--cards thead {
        display: none;
    }

    .data-table--cards,
    .data-table--cards tbody,
    .data-table--cards tfoot,
    .data-table--cards tr,
    .data-table--cards td {
        display: block;
        width: 100%;
    }

    .data-table--cards tr {
        display: flex;
        flex-direction: column;
        border: 1px solid var(--gray-350);
        border-radius: 8px;
        padding: 0.25rem 0.85rem 0.6rem;
        margin-bottom: 0.85rem;
        background: var(--white);
    }

    .data-table--cards td {
        border: none;
        padding: 0.5rem 0;
        min-height: 44px;
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        justify-content: space-between;
        gap: 0.4rem 0.75rem;
    }

    /* Row label, left-aligned, from the cell's data-label. */
    .data-table--cards td::before {
        content: attr(data-label);
        font-weight: 600;
        font-size: 0.8rem;
        color: var(--gray-650);
        white-space: nowrap;
    }

    /* First cell is the card header: name, no label, divider beneath. Floated to
       the top of the card even when it isn't the first column in the source table
       (e.g. the Skins "Winner" column sits after Hole/Par). */
    .data-table--cards td.card-title {
        order: -1;
        justify-content: flex-start;
        font-size: 1rem;
        font-weight: 700;
        color: var(--text);
        border-bottom: 1px solid var(--gray-200);
        margin-bottom: 0.25rem;
    }

    .data-table--cards td.card-title::before {
        display: none;
    }

    /* Action-only cells (Set all button, kebab) — right-aligned, no label.
       Reset any desktop width:1% (e.g. .member-table td.actions-cell) so the card
       cell spans full width and the kebab doesn't overflow off the card's edge. */
    .data-table--cards td.card-actions {
        justify-content: flex-end;
        width: 100%;
    }

    .data-table--cards td.card-actions::before {
        display: none;
    }

    /* DNS/DQ member cards keep their muted treatment. */
    .data-table--cards tr.inactive-row {
        opacity: 0.6;
    }

    /* A table footer (totals) row reads as a distinct summary card. */
    .data-table--cards tfoot tr {
        background: var(--gray-100);
        border-color: var(--gray-450);
    }

    /* Expandable scorecard detail rows (Scramble Results) carry their own nested
       table — opt them out of the card chrome so the scorecard renders normally
       below the group card instead of as another labelled flex row. */
    .data-table--cards tr.player-detail-row {
        border: none;
        border-radius: 0;
        padding: 0;
        background: transparent;
    }

    .data-table--cards td.player-detail-cell {
        display: block;
        padding: 0;
        min-height: 0;
    }

    .data-table--cards td.player-detail-cell::before {
        display: none;
    }

    /* Par-3 per-hole rule editor (WagerConfig) carries its own grid — opt it out of the
       card chrome so it renders as a normal block beneath the pot card. */
    .data-table--cards tr.per-hole-rules-row {
        border: none;
        border-radius: 0;
        padding: 0;
        margin: -0.5rem 0 0.85rem;
        background: transparent;
    }

    .data-table--cards tr.per-hole-rules-row td {
        display: block;
        padding: 0;
        min-height: 0;
    }

    .data-table--cards tr.per-hole-rules-row td::before {
        display: none;
    }

    /* Card-density helpers (used by the per-hole/per-group detail tables: Skins,
       Team/Scramble Results). They let one set of markup serve a full desktop table
       and a tight mobile card without duplicating the row logic:
         .card-hidden  — a cell or span that drops out of the card (kept on desktop)
         .card-only    — a span shown ONLY in the card (hidden on desktop, see base rule)
         .card-emphasis— a cell rendered as a label-less prominent line (e.g. the winner)
         .card-trailing— pushes content (e.g. payout) to the right edge of the title row */
    .data-table--cards .card-hidden {
        display: none;
    }

    .data-table--cards .card-only {
        display: inline;
    }

    .data-table--cards td.card-emphasis {
        font-weight: 600;
        color: var(--text);
        justify-content: flex-start;
        padding-top: 0;
    }

    .data-table--cards td.card-emphasis::before {
        display: none;
    }

    .data-table--cards td.card-title .card-trailing {
        margin-left: auto;
        font-weight: 700;
        color: var(--text);
    }

    /* Wager opt-in checkboxes become touch switches inside the cards. The base
       <input type=checkbox> is untouched on desktop (this rule is mobile-only). */
    .wager-toggle {
        appearance: none;
        -webkit-appearance: none;
        flex: 0 0 auto;
        width: 46px;
        height: 28px;
        margin: 0;
        border-radius: 14px;
        background: var(--gray-400);
        position: relative;
        cursor: pointer;
        transition: background 0.2s;
    }

    .wager-toggle::after {
        content: '';
        position: absolute;
        top: 3px;
        left: 3px;
        width: 22px;
        height: 22px;
        border-radius: 50%;
        background: var(--white);
        box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
        transition: transform 0.2s;
    }

    .wager-toggle:checked {
        background: var(--navy);
    }

    .wager-toggle:checked::after {
        transform: translateX(18px);
    }

    .wager-toggle:focus-visible {
        outline: 2px solid var(--navy);
        outline-offset: 2px;
    }

    .wager-toggle:disabled {
        opacity: 0.5;
        cursor: default;
    }

    /* Toolbars (round picker, add-group, add-player) stack so their selects and
       buttons get full-width touch targets instead of cramming side by side. */
    .invite-row {
        flex-direction: column;
        align-items: stretch;
    }

    .invite-row .form-group {
        width: 100% !important;
    }

    .invite-row .invite-btn,
    .invite-row .btn {
        width: 100%;
    }

    /* Totals summary card — replaces the tfoot on phones for Skins / Money List. */
    .data-table--summary tfoot {
        display: none;
    }

    .totals-summary-card {
        display: block;
        background: var(--gray-150);
        border: 1px solid var(--gray-350);
        border-left: 4px solid var(--navy);
        border-radius: 8px;
        padding: 0.75rem 1rem;
        margin: 0 0 1rem;
    }

    .totals-summary-card__heading {
        font-size: 0.75rem;
        font-weight: 700;
        text-transform: uppercase;
        letter-spacing: 0.04em;
        color: var(--gray-650);
        margin-bottom: 0.5rem;
    }

    .totals-summary-row {
        display: flex;
        justify-content: space-between;
        align-items: baseline;
        padding: 0.25rem 0;
        font-size: 0.95rem;
        color: var(--text);
    }

    .totals-summary-row .totals-summary-row__label {
        color: var(--gray-650);
    }

    .totals-summary-row--grand {
        border-top: 1px solid var(--gray-400);
        margin-top: 0.4rem;
        padding-top: 0.5rem;
        font-weight: 700;
        font-size: 1.15rem;
    }

    /* Single-row summary cards (Pot total, Skins total) have nothing above the grand
       row, so the separator line is spurious — drop it when it's the first child. */
    .totals-summary-row--grand:first-child {
        border-top: none;
        margin-top: 0;
        padding-top: 0;
    }
}

/* ===== iOS focus-zoom guard (mobile) — P2.2 =====
   Mobile Safari zooms the whole page whenever a focused field's font-size is
   < 16px. Several inputs here use 0.85rem, so force 16px on phones. The
   :not() selectors raise specificity above the per-class font-sizes (e.g.
   .handicap-input) and skip the wager toggle / radios. */
@media (max-width: 768px) {
    input:not([type="checkbox"]):not([type="radio"]),
    select,
    textarea {
        font-size: 16px;
    }
}

/* ===== Schedule List (PublicSchedule) =====
   One row per round: a course/event thumbnail (placeholder until images exist) on the
   left, then name / location / date stacked on the right. Skip weeks reuse the same row
   in a muted variant. */
.schedule-list {
    margin-top: 1rem;
}

.schedule-row {
    display: flex;
    align-items: center;
    gap: 0.9rem;
    padding: 0.75rem 0;
    border-bottom: 1px solid var(--gray-200);
}

.schedule-row:last-child {
    border-bottom: none;
}

/* Round rows open the leaderboard; skip rows stay inert. The negative margin lets the hover
   wash extend past the text while keeping the content aligned with the header. */
.schedule-row--link {
    cursor: pointer;
    margin: 0 -0.5rem;
    padding-left: 0.5rem;
    padding-right: 0.5rem;
    border-radius: 10px;
    transition: background 0.15s ease;
}

.schedule-row--link:hover {
    background: var(--surface-3);
}

.schedule-row--link:active {
    background: var(--surface-2);
}

.schedule-row--link:focus-visible {
    outline: 2px solid var(--color-accent);
    outline-offset: 2px;
}

.schedule-go {
    margin-left: auto;
    display: flex;
    align-items: center;
    color: #c2c7d0;
}

.schedule-thumb {
    width: 64px;
    height: 64px;
    flex-shrink: 0;
    border-radius: 10px;
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: center;
    /* Soft fairway-green wash behind the placeholder icon. */
    background: linear-gradient(135deg, #e8f5ec, #d3ebd9);
}

.schedule-thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.schedule-thumb .material-symbols-outlined {
    font-size: 1.9rem;
    color: #4a9d5f;
}

.schedule-info {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
}

.schedule-name {
    font-size: 1.05rem;
    font-weight: 700;
    color: var(--text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.schedule-location {
    font-size: 0.85rem;
    font-weight: 500;
    color: #6a7480;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.schedule-date {
    font-size: 0.85rem;
    font-weight: 600;
    color: #8a929b;
}

/* Skip weeks — muted, no fairway wash, italic label. */
.schedule-thumb--skip {
    background: var(--surface-2);
}

.schedule-thumb--skip .material-symbols-outlined {
    color: #9aa3ad;
}

.schedule-row--skip .schedule-name {
    font-weight: 600;
    font-style: italic;
    color: #6a7480;
}

/* ===== Sign-in screen (focused, centered single-column auth) =====
   Distinct from the older .auth-card box: this is the front-door experience for
   /login and /register — brand wordmark up top, big heading, filled inputs, a
   prominent primary action, then a secondary path (register / back to sign in). */
.auth-screen {
    width: 100%;
    max-width: 380px;
    margin: 0 auto;
    padding: 2.5rem 0 1rem;
    display: flex;
    flex-direction: column;
    min-height: calc(100vh - 2rem);
}

.auth-screen__body {
    flex: 1;
}

.auth-brand {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    color: var(--text);
    font-weight: 700;
    font-size: 1.1rem;
    letter-spacing: -0.01em;
    text-decoration: none;
    margin-bottom: 2.75rem;
}

.auth-brand .material-symbols-outlined {
    font-size: 1.7rem;
    color: var(--color-accent);
}

.auth-brand:active {
    opacity: 0.6;
}

.auth-heading {
    font-size: 2rem;
    font-weight: 700;
    color: var(--ink);
    letter-spacing: -0.02em;
    margin: 0 0 1.75rem;
}

/* One-line context under the heading (forgot/reset pages). */
.auth-blurb {
    color: var(--gray-700);
    font-size: 0.95rem;
    line-height: 1.5;
    margin: -0.5rem 0 1.5rem;
}

.auth-success {
    background: #e7f6ec;
    border: 1px solid #a8dcb9;
    color: #1f7a3d;
    font-size: 0.9rem;
    font-weight: 600;
    padding: 0.7rem 0.85rem;
    border-radius: 8px;
    margin-bottom: 1.25rem;
}

.auth-field {
    margin-bottom: 1.1rem;
}

.auth-field label {
    display: block;
    font-size: 0.82rem;
    font-weight: 600;
    color: var(--gray-700);
    margin-bottom: 0.4rem;
}

.auth-input-wrap {
    position: relative;
}

.auth-field input {
    width: 100%;
    padding: 0.85rem 0.9rem;
    border: 1px solid transparent;
    border-radius: 8px;
    background: var(--surface-2);
    font-size: 1rem;
    font-family: inherit;
    color: var(--ink);
    transition: border-color 0.15s, background 0.15s;
}

/* Room for the eye toggle so long values don't run under it. */
.auth-input-wrap input {
    padding-right: 3rem;
}

.auth-field input:focus {
    outline: none;
    border-color: var(--navy);
    background: var(--white);
}

.auth-eye {
    position: absolute;
    right: 0.4rem;
    top: 50%;
    transform: translateY(-50%);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: none;
    border: none;
    cursor: pointer;
    color: #8a8a8a;
    padding: 0.45rem;
    border-radius: 50%;
}

.auth-eye:hover {
    color: var(--text);
}

.auth-eye .material-symbols-outlined {
    font-size: 1.3rem;
}

.auth-submit {
    width: 100%;
    padding: 0.9rem;
    border: none;
    border-radius: 8px;
    background: var(--navy);
    color: var(--on-solid);
    font-size: 1rem;
    font-weight: 600;
    font-family: inherit;
    cursor: pointer;
    margin-top: 0.6rem;
    transition: background 0.15s, opacity 0.15s;
}

.auth-submit:hover:not(:disabled) {
    background: var(--navy-dark);
}

.auth-submit:disabled {
    opacity: 0.6;
    cursor: not-allowed;
}

/* Sub-label under an auth input (e.g. the optional event code on register). */
.auth-field-hint {
    margin-top: var(--space-1);
    font-size: 0.8rem;
    line-height: 1.35;
    color: var(--text-muted);
}

/* The password rules, drawn under the field from the first frame rather than after a rejected
   submit. Same four rules and the same wording as the front door's .afd-rules — this block is a
   second CHROME for them, not a second rule set: both render from Services/PasswordRules, which
   mirrors the server's Identity options. Wrapping chips rather than a stacked list, so the submit
   button stays above the fold on a phone.

   A met rule takes --color-accent, which is the app's own "this is satisfied" tick. An unmet one
   is quiet ink and deliberately not --danger: nothing is wrong yet, the box is simply empty. */
.auth-rules {
    margin: var(--space-2) 0 0;
    padding: 0;
    list-style: none;
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1) var(--space-3);
}

.auth-rule {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: 0.78rem;
    line-height: 1.3;
    color: var(--text-muted);
}

.auth-rule__mark {
    font-size: 15px;
    line-height: 1;
    color: var(--border-strong);
}

.auth-rule.is-met { color: var(--text); }

.auth-rule.is-met .auth-rule__mark { color: var(--color-accent); }

/* ===== Claim welcome (MEMBER-CLAIM-PLAN.md Phase 6) =====
   The "we found you" screen after an email match claims a roster spot. */
.claim-welcome-icon {
    display: flex;
    justify-content: center;
    margin-bottom: var(--space-3);
}

.claim-welcome-icon .material-symbols-outlined {
    font-size: 3rem;
    color: var(--color-accent);
}

.claim-history {
    display: flex;
    justify-content: center;
    gap: var(--space-6);
    margin: var(--space-5) 0 var(--space-3);
    padding: var(--space-4) var(--space-3);
    background: var(--surface-subtle);
    border-radius: var(--radius-md);
}

.claim-history__stat {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-1);
}

.claim-history__value {
    font-size: 1.6rem;
    font-weight: 700;
    color: var(--text);
    line-height: 1;
}

.claim-history__label {
    font-size: 0.75rem;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

.claim-welcome-note {
    margin: 0 0 var(--space-5);
    text-align: center;
    font-size: 0.85rem;
    color: var(--text-muted);
}

/* Multi-event claim: one tappable row per event. */
.claim-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    margin: var(--space-4) 0 var(--space-2);
}

.claim-list__item {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    width: 100%;
    min-height: 44px;
    padding: var(--space-3) var(--space-4);
    text-align: left;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    cursor: pointer;
    font-family: inherit;
}

.claim-list__item:disabled {
    opacity: 0.6;
    cursor: default;
}

.claim-list__name {
    font-weight: 600;
    color: var(--text);
}

.claim-list__meta {
    font-size: 0.82rem;
    color: var(--text-muted);
}

/* Secondary path under a primary empty state (e.g. "joining someone else's league?"). */
.empty-state-secondary {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-3);
    padding: 0 var(--space-4) var(--space-6);
    text-align: center;
    color: var(--text-muted);
    font-size: 0.9rem;
}

.empty-state-secondary p {
    margin: 0;
}

.auth-link-row {
    text-align: center;
    margin-top: 1.35rem;
}

.auth-link-row a {
    color: var(--text);
    font-size: 0.95rem;
    font-weight: 500;
    text-decoration: underline;
}

/* Labeled rule separating the primary sign-in from the secondary register path. */
.auth-divider {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin: 2rem 0 1.4rem;
    color: #9aa3ad;
    font-size: 0.82rem;
}

.auth-divider::before,
.auth-divider::after {
    content: "";
    flex: 1;
    height: 1px;
    background: var(--gray-200);
}

.auth-secondary {
    display: block;
    width: 100%;
    padding: 0.85rem;
    border: 1px solid #cfcfd4;
    border-radius: 8px;
    background: var(--white);
    color: var(--text);
    font-size: 1rem;
    font-weight: 600;
    font-family: inherit;
    cursor: pointer;
    text-align: center;
    text-decoration: none;
    transition: background 0.15s;
}

.auth-secondary:hover {
    background: var(--surface-3);
}

.auth-error {
    background: #fdecea;
    border: 1px solid #f5c2c0;
    color: #b3261e;
    font-size: 0.875rem;
    padding: 0.7rem 0.85rem;
    border-radius: 8px;
    margin-bottom: 1rem;
}

/* A new password can miss three rules at once, and three sentences run together read as a
   paragraph nobody finishes. One line each, so the count is visible before the words are. */
.auth-error__list {
    margin: 0;
    padding-left: 1.15em;
    line-height: 1.5;
}

.auth-error__list li + li { margin-top: 3px; }

.auth-info {
    background: #fffbea;
    border: 1px solid #f0d35a;
    color: #7a5c00;
    font-size: 0.9rem;
    font-weight: 600;
    padding: 0.7rem 0.85rem;
    border-radius: 8px;
    margin-bottom: 1rem;
}

.auth-footer {
    text-align: center;
    color: #9aa3ad;
    font-size: 0.8rem;
    padding-top: 2rem;
}

/* Join-with-a-code screen: the code input reads as a code (spaced, centered, uppercase),
   and the post-resolve actions are anchors styled as the primary/secondary buttons. */
.join-code-input {
    text-align: center;
    text-transform: uppercase;
    letter-spacing: 0.3em;
    font-size: 1.3rem !important;
    font-weight: 700 !important;
}

.join-code-input::placeholder {
    letter-spacing: 0.3em;
    font-weight: 400;
    color: #b8b8bd;
}

.join-action {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    margin-bottom: 0.85rem;
    text-decoration: none;
}

.join-action .material-symbols-outlined {
    font-size: 1.25rem;
}

/* Big monospaced code chip on the Event Settings → Event Code card. */
.join-code-display {
    display: inline-block;
    font-family: "SFMono-Regular", ui-monospace, "Cascadia Mono", Menlo, Consolas, monospace;
    font-size: 1.9rem;
    font-weight: 700;
    letter-spacing: 0.35em;
    padding: 0.6rem 0.5rem 0.6rem 0.85rem;
    margin: 0.25rem 0 1rem;
    background: var(--surface-2);
    border-radius: 8px;
    color: var(--ink);
}

/* Legal links pinned in the auth-screen footer (login / register). */
.auth-legal-links {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.55rem;
    flex-wrap: wrap;
    margin-bottom: 0.5rem;
}

.auth-legal-links a {
    color: var(--text);
    font-weight: 500;
    text-decoration: underline;
}

.auth-legal-links span {
    color: #c4c9ce;
}

/* ── Legal documents (Terms of Service, Privacy Policy) ───────────────── */
.legal-page {
    max-width: 720px;
    margin: 0 auto;
    padding: 2rem 1.25rem 3rem;
    color: #2b2f33;
    line-height: 1.65;
}

.legal-brand {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    color: var(--text);
    font-weight: 700;
    font-size: 1.1rem;
    letter-spacing: -0.01em;
    text-decoration: none;
    margin-bottom: 1.75rem;
}

.legal-brand .material-symbols-outlined {
    font-size: 1.7rem;
    color: var(--color-accent);
}

.legal-page h1 {
    font-size: 2rem;
    font-weight: 700;
    color: var(--ink);
    letter-spacing: -0.02em;
    margin: 0 0 0.4rem;
}

.legal-meta {
    color: #8a9298;
    font-size: 0.85rem;
    margin: 0 0 1.5rem;
}

.legal-lede {
    font-size: 1.02rem;
    color: #41474c;
    margin: 0 0 1.75rem;
}

.legal-toc {
    background: var(--surface-3);
    border: 1px solid #e6e8ea;
    border-radius: 10px;
    padding: 1rem 1.25rem 1rem 2.4rem;
    margin: 0 0 2.25rem;
}

.legal-toc ol {
    margin: 0;
    padding: 0;
    columns: 2;
    column-gap: 1.5rem;
}

.legal-toc li {
    margin: 0.2rem 0;
    font-size: 0.9rem;
    break-inside: avoid;
}

.legal-toc a {
    color: var(--text);
    text-decoration: none;
}

.legal-toc a:hover {
    text-decoration: underline;
}

.legal-page section {
    margin: 0 0 1.75rem;
    scroll-margin-top: 1rem;
}

.legal-page h2 {
    font-size: 1.2rem;
    font-weight: 700;
    color: var(--ink);
    margin: 0 0 0.6rem;
}

.legal-page p {
    margin: 0 0 0.85rem;
}

.legal-page ul {
    margin: 0 0 0.85rem;
    padding-left: 1.4rem;
}

.legal-page li {
    margin: 0.35rem 0;
}

.legal-page a {
    color: #1d6f3a;
}

/* Highlighted statement (e.g. the wagering "record-keeping tool only" callout). */
.legal-callout {
    background: var(--surface-2);
    border-left: 4px solid var(--color-accent);
    border-radius: 0 8px 8px 0;
    padding: 0.85rem 1rem;
}

/* All-caps warranty / liability blocks — slightly smaller and muted. */
.legal-emphatic {
    font-size: 0.85rem;
    color: #51585d;
    letter-spacing: 0.01em;
}

.legal-footer {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.6rem;
    flex-wrap: wrap;
    margin-top: 2.5rem;
    padding-top: 1.5rem;
    border-top: 1px solid #e6e8ea;
    font-size: 0.92rem;
}

.legal-footer a {
    color: var(--text);
    font-weight: 500;
    text-decoration: underline;
}

.legal-footer span {
    color: #c4c9ce;
}

@media (max-width: 560px) {
    .legal-toc ol {
        columns: 1;
    }
}

/* The AI recap "heat" dial was a plain accent-tinted range slider here; it is .set-slider in
   07-settings.css now — a 44px tabular value, a word label and a drawn 8px track. */


/* ===================================================================================
   ===== Wagers pane (round pot allocation) =====
   Wagers pane design handoff — turn 1b (modernized layout) + turn 2a (Rules column).

   The old screen was a .data-table--summary: 2px rules, centred cells, the totals in a <tfoot>
   and the buy-in reconciliation as a red .form-error at the very bottom. Three things changed:

   1. The money answers moved ABOVE the rows (.wager-summary / .wager-msummary) — whether the
      round balances is knowable before reading a single row.
   2. The table chrome went away. Same columns, but a CSS grid on a raised card with hairline
      dividers; alignment does the work the borders were doing. Controls match their job —
      a switch for on/off, a segmented control for two exclusive options, a $-affixed tabular
      field for money.
   3. `Par+ to win` and `Par 3 rule` collapsed into one `Rules` cell that STATES its value and
      opens a focused dialog. Both old columns existed for one game each and were otherwise em
      dashes; the cell is never empty, so the grid still answers "how is this set up?" unopened.

   Everything here goes through semantic tokens (--surface-raised, --hairline, --control-fill,
   --text-quiet …) so light mode and dark mode both work; the mock's hardcoded dark hexes live in
   the token block, not here.
   =================================================================================== */

/* The ground the cards sit on. Full-bleed on a phone (cards carry their own side margins,
   mirroring the mock's 14px inset); a padded, rounded panel once there is room beside it. */
.wagers-pane {
    background: var(--page-ground);
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    margin: 0 -1rem;
    padding: var(--space-3) var(--space-3) 0;
    /* Clear the fixed .wager-stickybar. The tab bar below it is already reserved by main's own
       bottom padding, so only the bar's own height is added here. */
    padding-bottom: calc(64px + var(--space-4));
}

@media (min-width: 768px) {
    .wagers-pane {
        margin: 0;
        border-radius: var(--radius-xl);
        padding: var(--space-5);
        gap: var(--space-5);
    }
}

/* ── Heading block ──
   GONE, and the `.round-pane--wagers` class with it. The 30px title, the quiet status pill and
   the muted intro this pane introduced became the DEFAULT pane head when the round panes moved
   onto the setting-card system (design_handoff_rounds § Page head) — so an override that says
   "be like the other panes" now says nothing. RoundPaneHeader draws it for every pane.

   What this pane still owns is its own body, below. */

@media (max-width: 767px) {
    /* The pane sits inside .settings-ground, whose phone gutter is 14px rather than main's 1rem.
       .wagers-pane's own -1rem full-bleed would overhang that by 2px on each side, so it takes
       the ground's gutter instead — same correction .settings-ground .app-bar carries. */
    .settings-ground .wagers-pane { margin-left: -14px; margin-right: -14px; }
}

/* ── Summary strip (desktop) ──
   One cell, because there is one question: what is this round worth. It carried four — full
   buy-in, unallocated, an allocated-% bar — against an event-level target that fed no
   calculation and was wrong on any event betting a different amount week to week
   (WAGER-SCOPE-PLAN Phase 1). The --nodiff / --solo modifiers went with them, as did
   .wager-bar, .wager-summary__cell--bar / __barhead / __barpct and __value--warn. */
.wager-summary {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: var(--space-4);
    background: var(--surface-raised);
    border: 1px solid var(--hairline);
    border-radius: var(--radius-xl);
    overflow: hidden;
}

.wager-summary__cell { padding: 18px 20px; }

.wager-summary__label,
.micro-caps {
    font-size: 10.5px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

.wager-summary__value {
    margin-top: 6px;
    font-size: 28px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.02em;
    font-variant-numeric: tabular-nums;
    color: var(--text);
}
.wager-summary__value--accent { color: var(--color-accent); }

.wager-summary__caption { font-size: 12px; color: var(--text-muted); }

/* ── Summary card (phone) ── */
.wager-msummary {
    padding: 16px 18px;
    border-radius: 18px;
    background: var(--surface-raised);
    border: 1px solid var(--hairline);
}
.wager-msummary__top {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: var(--space-3);
}
.wager-msummary__total {
    font-size: 34px;
    font-weight: var(--font-weight-bold);
    line-height: 1.1;
    letter-spacing: -0.03em;
    color: var(--color-accent);
    font-variant-numeric: tabular-nums;
}
/* __of ("of $400 buy-in"), the progress bar and __note went with the buy-in — see the desktop
   strip's note above. What is left is the total, which is the whole answer. */

/* The count that used to be the desktop strip's caption only. On the phone card it rides the
   total's baseline rather than a line of its own — the card is already the tallest thing on the
   pane. */
.wager-msummary__games { font-size: 12px; color: var(--text-muted); }

/* ── Add a game rides the pot-total card ──
   It used to be a lone ghost button BELOW the pots, the opt-ins line and (on a phone) six game
   cards — past the fold on every round, which is a strange place for the one action that changes
   the number at the top. A tinted call-to-action card of its own was drawn and rejected: adding a
   one-off is rare, so a permanent block of chrome ahead of the money isn't earned. Riding the
   summary puts the action beside the figure it moves and adds no card.

   The button is the one accent-tinted control on the pane, which is honest — this is money — and
   it is a TINT rather than a fill, so it doesn't compete with "Save pots". */
.wager-summary__add {
    flex: none;
    max-width: 250px;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 8px;
    padding: 18px 20px;
}

.wager-addgame {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    height: 40px;
    padding: 0 16px;
    border: 1px solid color-mix(in srgb, var(--color-accent) 45%, transparent);
    border-radius: 11px;
    background: color-mix(in srgb, var(--color-accent) 8%, transparent);
    font-family: inherit;
    font-size: 13.5px;
    font-weight: var(--font-weight-bold);
    color: var(--ink-on-accent-tint);
    white-space: nowrap;
    cursor: pointer;
}
.wager-addgame:hover:not(:disabled) { background: color-mix(in srgb, var(--color-accent) 14%, transparent); }
.wager-addgame:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; }
.wager-addgame:disabled { opacity: 0.55; cursor: not-allowed; }
.wager-addgame .material-symbols-outlined { font-size: 18px; }

.wager-addgame__note {
    font-size: 12px;
    color: var(--text-muted);
    text-align: right;
    line-height: 1.45;
}

/* Phone: the same two things as a footer under a hairline, note left and button right. */
.wager-msummary__foot {
    margin-top: 14px;
    padding-top: 14px;
    border-top: 1px solid var(--hairline-soft);
    display: flex;
    align-items: center;
    gap: var(--space-3);
}
.wager-msummary__prompt {
    flex: 1;
    min-width: 0;
    font-size: 12.5px;
    color: var(--text-muted);
    line-height: 1.45;
}
.wager-msummary__foot .wager-addgame {
    height: 42px;
    border-radius: 12px;
    font-size: 14px;
}

/* ── Pots card (desktop grid) ── */
.pots-card {
    background: var(--surface-raised);
    border: 1px solid var(--hairline);
    border-radius: var(--radius-xl);
    overflow: hidden;
    box-shadow: var(--shadow-lg);
}

.pots-row {
    display: grid;
    grid-template-columns: 40px minmax(150px, 1fr) 118px 118px 116px 168px;
    column-gap: 14px;
    align-items: center;
    padding: 14px 20px;
    border-bottom: 1px solid var(--hairline-soft);
    transition: background 140ms ease;
}
.pots-row:last-of-type { border-bottom: none; }
/* Grid items stretch by default, which would pull the pill-shaped controls to their full column
   width and undo the "control sized to its job" the redesign is about. The Game cell is the one
   that SHOULD fill its column. */
.pots-row > * { justify-self: start; }
.pots-row > .pot-game { justify-self: stretch; }
.pots-row--head {
    border-bottom: 1px solid var(--hairline);
    padding-top: 12px;
    padding-bottom: 12px;
}
.pots-row:not(.pots-row--head):hover {
    background: color-mix(in srgb, var(--text) 3%, transparent);
}
/* "This one is configured" — the row a Rules dialog has actually been used on. */
.pots-row--tuned { background: color-mix(in srgb, var(--color-accent) 5%, transparent); }
.pots-row--off .pot-game__name,
.pots-row--off .money-field,
.pots-row--off .segmented { opacity: 0.55; }
.pots-row--na { opacity: 0.45; }

.pot-game {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}
.pot-game__name {
    font-size: 15px;
    font-weight: var(--font-weight-semibold);
    color: var(--text);
}
.pot-game__sub { font-size: 12px; color: var(--text-muted); }
.pot-game__badges { display: inline-flex; gap: 6px; flex-wrap: wrap; margin-top: 2px; }

.pots-foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    padding: 16px 20px;
    background: color-mix(in srgb, var(--text) 3%, transparent);
    border-top: 1px solid var(--hairline);
}
.pots-foot__label {
    font-size: 12.5px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-muted);
}
.pots-foot__value {
    font-size: 22px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.02em;
    color: var(--color-accent);
    font-variant-numeric: tabular-nums;
}

/* ── Switch ──
   Three sizes, one component: 40×24 in the desktop grid, 44×26 in the Rules dialog, 51×31
   (iOS scale) on a phone card where it is the primary target. */
.switch {
    position: relative;
    flex: none;
    display: inline-block;
    width: 40px;
    height: 24px;
    padding: 0;
    border: none;
    border-radius: var(--radius-pill);
    background: var(--control-fill-strong);
    cursor: pointer;
    transition: background 140ms ease;
    -webkit-tap-highlight-color: transparent;
}
.switch__knob {
    position: absolute;
    top: 2px;
    left: 2px;
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background: var(--switch-knob-off);
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
    transition: left 140ms ease, background 140ms ease;
}
.switch.is-on { background: var(--color-accent); }
.switch.is-on .switch__knob { left: 18px; background: #fff; }
.switch:disabled { opacity: 0.4; cursor: not-allowed; }
.switch:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; }

.switch--md { width: 44px; height: 26px; }
.switch--md .switch__knob { width: 22px; height: 22px; }
.switch--md.is-on .switch__knob { left: 20px; }

.switch--lg { width: 51px; height: 31px; }
.switch--lg .switch__knob { width: 27px; height: 27px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.35); }
.switch--lg.is-on .switch__knob { left: 22px; }

/* ── Compact segmented (Funding: Fixed / Per player) ──
   A variant of the shared Segmented rather than a one-off: two mutually-exclusive options that
   should both stay visible is exactly what that component is for, it just needed tightening to
   sit in a 118px grid cell. It also drops the solid navy is-active fill for a raised tint — a
   navy slab inside a row is louder than the row. */
.segmented--compact {
    display: inline-flex;
    gap: 0;
    padding: 2px;
    background: var(--control-fill);
    border: 1px solid var(--hairline);
    border-radius: 9px;
}
.segmented--compact .segmented__opt {
    flex: 0 0 auto;
    padding: 5px 8px;
    border-radius: 7px;
    font-size: 11.5px;
    white-space: nowrap;
}
.segmented--compact .segmented__opt.is-active {
    background: var(--control-fill-strong);
    color: var(--text);
}
.segmented--roomy { border-radius: 11px; }
.segmented--roomy .segmented__opt { padding: 7px 12px; font-size: 13px; border-radius: 9px; }

/* Full-width variant for the Rules dialog, where the control owns its row. */
.segmented--wide { display: flex; padding: 3px; border-radius: 12px; }
.segmented--wide .segmented__opt { flex: 1; padding: 9px 12px; border-radius: 9px; font-size: 13.5px; }

/* ── Money field ──
   Tabular figures, a $ affix inside the field and right-aligned digits, so amounts line up
   column-wise and a wrong value is visible at a glance. */
.money-field {
    box-sizing: border-box;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    width: 118px;
    height: 40px;
    padding: 0 10px;
    border-radius: 10px;
    background: var(--control-fill);
    border: 1px solid var(--control-fill-strong);
    transition: border-color 140ms ease, box-shadow 140ms ease, background 140ms ease;
}
.money-field__affix { font-size: 13px; color: var(--text-muted); }
.money-field__input {
    flex: 1;
    min-width: 0;
    width: 100%;
    border: none;
    background: none;
    padding: 0;
    text-align: right;
    font-family: inherit;
    font-size: 15px;
    font-weight: var(--font-weight-semibold);
    color: var(--text);
    font-variant-numeric: tabular-nums;
    appearance: textfield;
    -moz-appearance: textfield;
}
.money-field__input::-webkit-outer-spin-button,
.money-field__input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.money-field__input:focus { outline: none; }
.money-field:focus-within {
    background: color-mix(in srgb, var(--color-accent) 6%, transparent);
    border-color: color-mix(in srgb, var(--color-accent) 55%, transparent);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-accent) 12%, transparent);
}
.money-field--disabled { opacity: 0.45; }
.money-field--lg { width: 132px; height: 44px; padding: 0 14px; border-radius: 12px; }
.money-field--lg .money-field__affix { font-size: 14px; }
.money-field--lg .money-field__input { font-size: 17px; }

.pot-perplayer { display: flex; flex-direction: column; gap: 2px; }
.pot-perplayer__calc { font-size: 12px; color: var(--text-muted); font-variant-numeric: tabular-nums; }

/* ── Scoring pill ──
   Shows the RESOLVED value ("Net") with the mechanism whispering underneath ("inherited"),
   rather than the old option text "Inherit (Net)" — the value is what is being read. */
.scoring-cell { display: inline-flex; flex-direction: column; min-width: 0; }
.scoring-cell .sheet-select-trigger {
    position: relative;
    width: auto;
    min-width: 0;
    min-height: 0;
    padding: 7px 6px 7px 10px;
    gap: 5px;
    border: none;
    border-radius: 9px;
    background: var(--control-fill);
    font-size: 13px;
    font-weight: var(--font-weight-medium);
}
.scoring-cell .sheet-select-trigger:hover:not(:disabled) { background: var(--control-fill-strong); }
.scoring-cell .sheet-select-trigger:focus-visible,
.scoring-cell .sheet-select-trigger.open {
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--color-accent) 40%, transparent);
}
.scoring-cell .sheet-select-trigger__caret { font-size: 16px; color: var(--text-quiet); }
/* The "inherited" caption reads under the pill, not inside it. */
.scoring-cell .sheet-select-trigger__sub {
    position: absolute;
    left: 10px;
    bottom: -13px;
    margin: 0;
    font-size: 10.5px;
    color: var(--text-quiet);
}
.scoring-cell--inherited { padding-bottom: 13px; }

.pot-notscored { font-size: 13px; color: var(--ink-disabled); }

/* ── Rules cell ──
   States the value, so the grid answers "how is this round set up?" without opening anything.
   The accent treatment is what makes a configured game findable at a glance. */
.rules-cell {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 7px 10px 7px 12px;
    border-radius: 10px;
    border: 1px solid var(--control-fill-strong);
    background: none;
    font-family: inherit;
    white-space: nowrap;
    cursor: pointer;
    transition: background 140ms ease, border-color 140ms ease;
    -webkit-tap-highlight-color: transparent;
}
.rules-cell__label { font-size: 12.5px; color: var(--text-muted); }
.rules-cell .material-symbols-outlined { font-size: 17px; color: var(--text-quiet); }
.rules-cell:hover { background: var(--control-fill); }
.rules-cell:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; }

.rules-cell--set {
    border-color: color-mix(in srgb, var(--color-accent) 45%, transparent);
    background: color-mix(in srgb, var(--color-accent) 8%, transparent);
}
.rules-cell--set .rules-cell__label { font-weight: var(--font-weight-semibold); color: var(--text); }
.rules-cell--set .material-symbols-outlined { color: var(--color-accent); }

/* A game whose schema declares nothing still says so, rather than showing an empty cell. */
.rules-cell--none {
    border-color: transparent;
    cursor: default;
    padding-left: 0;
}
.rules-cell--none .rules-cell__label { color: var(--ink-disabled); }
.rules-cell--none:hover { background: none; }

/* ── Opt-ins foot ──
   What replaced the buy-in callout (an amber advice block about the diff, plus a Distribute-evenly
   button) — WAGER-SCOPE-PLAN Phase 1. It keeps the one thing on that block worth keeping: this
   pane is a documented door to the opt-ins drill-in, and the link used to render only when a
   buy-in happened to be set. Quiet by design — nothing here is a fault, a standing or money, so
   it takes no hue; the link is the page's existing accent text button. */
/* A cross-link on the pane ground: the sentence, then the verb under it as a real button.

   It was a flex ROW — sentence left, an accent text link pushed to the right edge. At any width
   where the sentence wraps (both of them do at 390px, and the contests one does on a laptop too)
   that link sits at the end of a paragraph in the same size type, three shades of green from the
   words above it, and reads as the last few words of the sentence rather than as somewhere to go.
   Under it, a `.set-btn` is unambiguously a control and gets a 40px target instead of a 13px one.

   Still no hue: a cross-link is not a standing, not money and not a fault. */
.wager-optins {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-2);
    padding: 2px 4px;
}
.wager-optins__text {
    margin: 0;
    max-width: 62ch;
    font-size: 13px;
    color: var(--text-muted);
    line-height: 1.5;
}

/* ── One-off game ──
   The escape hatch: a bet made on the tee that must not become a permanent row on every future
   round. The button and its note used to live here, as a lone `.btn-ghost` BELOW the pots — they
   ride the pot-total card now (`.wager-summary__add` / `.wager-msummary__foot` above), so the
   action sits beside the number it changes instead of past the fold. */

/* A one-off's ⋯ — Rename and Remove, which have nowhere else to live: the event's Wager Types
   table carries both and is catalog-only by design. Catalog rows get no menu at all rather than a
   blocked one, so this only ever renders beside the scope badge. The card clips its corners, so it
   lifts while a panel is open — the same trick `.set-card:has(…)` and `.app-bar:has(…)` use. */
.pot-game__menu {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    margin-left: 2px;
    border: none;
    border-radius: 8px;
    background: none;
    color: var(--text-quiet);
    cursor: pointer;
}
.pot-game__menu:hover { background: var(--control-fill); color: var(--text); }
.pot-game__menu:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; }
.pot-game__menu .material-symbols-outlined { font-size: 18px; }
.pots-card:has(.overflow-menu__panel) { overflow: visible; }

/* The pot row's marker for a game that only runs here. Quiet ink on the existing badge shape —
   it says "this one is temporary", which is not a standing and not a warning. */
.pot-game__scope {
    display: inline-block;
    padding: 1px 7px;
    border-radius: var(--radius-pill);
    background: var(--control-fill);
    font-size: 11px;
    font-weight: var(--font-weight-semibold);
    color: var(--text-muted);
}

@media (max-width: 767px) {
    .wager-optins { padding: 2px 2px; }
}

.btn-ghost {
    padding: 8px 12px;
    border-radius: 10px;
    border: 1px solid var(--control-fill-strong);
    background: none;
    font-family: inherit;
    font-size: 13px;
    font-weight: var(--font-weight-semibold);
    color: var(--text);
    cursor: pointer;
    transition: background 140ms ease;
}
.btn-ghost:hover:not(:disabled) { background: var(--control-fill); }
.btn-ghost:disabled { color: var(--ink-disabled); cursor: not-allowed; }

/* `.btn-text-accent` is deleted. Its only two callers were the cross-links above, and both are
   `.set-btn` now — an accent text link at the end of a wrapping sentence read as part of the
   sentence, which is what it was reported as. Don't reintroduce it: a verb on these panes is a
   button, and accent on this screen means live-or-money. */

/* ── Action bar (desktop) ── */
.wager-actionbar {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 14px 18px;
    border-radius: 14px;
    background: color-mix(in srgb, var(--surface-raised) 90%, transparent);
    border: 1px solid var(--hairline);
    backdrop-filter: blur(8px);
}
.wager-actionbar .sheet-select-trigger {
    width: auto;
    min-width: 0;
    min-height: 0;
    padding: 9px 8px 9px 12px;
    border-radius: 10px;
    border-color: var(--control-fill-strong);
    background: none;
    font-size: 13px;
    font-weight: var(--font-weight-semibold);
    color: var(--text-muted);
}
.wager-actionbar__status { margin-left: auto; font-size: 13px; color: var(--text-muted); }
.wager-actionbar__status.is-saved { color: var(--success); }
.wager-actionbar__status.is-error { color: var(--danger); }

/* Not full-width, and not navy: a full-bleed navy slab reads like a form from a template and
   competes with nothing. Green is the one accent, and it sits on the one primary action. */
.btn-save-pots {
    padding: 11px 20px;
    border: none;
    border-radius: 11px;
    background: var(--color-accent);
    color: var(--on-hue);
    font-family: inherit;
    font-size: 14.5px;
    font-weight: var(--font-weight-bold);
    cursor: pointer;
    white-space: nowrap;
}
.btn-save-pots:disabled { opacity: 0.6; cursor: not-allowed; }

/* ── Phone: game cards ──
   Five games × six labelled rows is a wall on a 390px screen. Collapsed cards carry name,
   amount and status; tapping expands one at a time. Most weeks the only edit is an amount. */
.wager-section-label { padding: var(--space-1) var(--space-1) 0; }

.wager-mcards { display: flex; flex-direction: column; gap: 8px; }

.wager-mcard {
    border-radius: 18px;
    background: var(--surface-raised);
    border: 1px solid var(--hairline);
    overflow: hidden;
}
.wager-mcard--tuned { border-color: color-mix(in srgb, var(--color-accent) 35%, transparent); }
.wager-mcard--na { opacity: 0.5; }

.wager-mcard__head {
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
    padding: 12px 16px;
    border: none;
    background: none;
    font-family: inherit;
    text-align: left;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
.wager-mcard--open .wager-mcard__head { padding: 14px 16px; }
.wager-mcard__id { flex: 1; display: flex; flex-direction: column; gap: 2px; min-width: 0; }
/* An expanded card's head is a container (it carries the switch), so the name/sub half becomes
   its own button — tapping the title is what collapses the card back. */
.wager-mcard__idbtn {
    border: none;
    background: none;
    padding: 0;
    font-family: inherit;
    text-align: left;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
.wager-mcard__name { font-size: 17px; font-weight: var(--font-weight-semibold); color: var(--text); }

/* The one-off's ⋯ on a phone card. It sits beside the switch rather than inside the name (that
   half is a <button>), and the card is `overflow: hidden`, so the panel needs the same clip lift
   `.pots-card` and `.set-card` take. The marker beside the name shrinks a little here: the phone
   name line has a switch and a menu to its right, where the desktop cell has only the menu. */
.wager-mcard__menu { flex: none; margin-left: -4px; }
.wager-mcard:has(.overflow-menu__panel) { overflow: visible; }
.wager-mcard__name .pot-game__scope { margin-left: 6px; font-size: 10px; vertical-align: middle; }
.wager-mcard__sub { font-size: 12px; color: var(--text-muted); }
.wager-mcard__amount {
    font-size: 17px;
    font-weight: var(--font-weight-semibold);
    color: var(--text);
    font-variant-numeric: tabular-nums;
}
.wager-mcard__chev { font-size: 20px; color: var(--text-quiet); }

.wager-mrow {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    width: 100%;
    min-height: 56px;
    padding: 12px 16px;
    border: none;
    border-top: 1px solid var(--hairline-soft);
    background: none;
    font-family: inherit;
    text-align: left;
}
.wager-mrow__label { font-size: 15px; color: var(--text); opacity: 0.88; }
.wager-mrow__sub { display: block; font-size: 12px; color: var(--text-quiet); }
.wager-mrow__value {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 14px;
    color: var(--text-muted);
}
.wager-mrow__value .material-symbols-outlined { font-size: 18px; color: var(--text-quiet); }
button.wager-mrow { cursor: pointer; -webkit-tap-highlight-color: transparent; }

/* ── Phone: sticky action bar ──
   Sits directly above .bottom-nav, which it must never cover. The bar is a floating 69px pane
   inset 14px from the edge now, so the clearance is 83px — see 26-bottom-nav.css. */
.wager-stickybar {
    position: fixed;
    left: 0;
    right: 0;
    bottom: calc(83px + env(safe-area-inset-bottom));
    /* Above .bottom-nav-scrim (149), not below it: the scrim's whole job is fading BOARD ROWS into
       the floating bar, and it covers the bottom 96px — which is exactly where this bar sits. At
       140 it rendered behind the fade and read as disabled. */
    z-index: 151;
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 16px;
    background: color-mix(in srgb, var(--surface) 86%, transparent);
    backdrop-filter: blur(12px);
    border-top: 1px solid var(--hairline);
}
.wager-stickybar__total { display: flex; flex-direction: column; }
.wager-stickybar__amount {
    font-size: 17px;
    font-weight: var(--font-weight-semibold);
    color: var(--color-accent);
    font-variant-numeric: tabular-nums;
}
.wager-stickybar .btn-save-pots {
    margin-left: auto;
    padding: 13px 22px;
    border-radius: 13px;
    font-size: 15px;
}

/* ── Desktop / phone swap. Same 768px breakpoint the rest of the app uses.
   Both sides HIDE inside a media query rather than one side toggling display:none ⟷ block —
   .wager-summary is a grid and .wager-actionbar is a flex, and a blanket display:block would
   flatten them the moment the desktop rule re-showed them. ── */
@media (max-width: 767px) {
    .wager-desktop { display: none; }
}
@media (min-width: 768px) {
    .wager-phone { display: none; }
}

/* ===== Rules dialog (turn 2a) =====
   Built on .modal-backdrop / .modal-panel so Escape, backdrop-close and the phone bottom-sheet
   form all come along; restyled to the raised-card values. The rejected alternative was an
   in-place expanding row: no context switch, but the grid grows and shrinks under the cursor and
   the panel is capped at the pot row's width, which stops working the moment a game declares more
   than three or four settings. */
.rules-dialog {
    background: var(--surface-raised);
    padding: 0;
    padding-bottom: env(safe-area-inset-bottom);
    overflow: hidden;
    display: flex;
    flex-direction: column;
}
.rules-dialog__header {
    display: flex;
    align-items: flex-start;
    gap: 14px;
    padding: 22px 24px 18px;
    border-bottom: 1px solid var(--hairline);
}
/* Tile tint reuses the si-* row tints via an inline --rules-tint, so the dialog matches the rail. */
.rules-dialog__tile {
    flex: none;
    width: 38px;
    height: 38px;
    border-radius: 11px;
    display: grid;
    place-items: center;
    background: color-mix(in srgb, var(--rules-tint, var(--slate-500)) 16%, transparent);
    color: var(--rules-tint, var(--slate-500));
}
.rules-dialog__tile .material-symbols-outlined { font-size: 20px; }
.rules-dialog__id { flex: 1; display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.rules-dialog__title {
    margin: 0;
    font-size: 18px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.01em;
    color: var(--text);
}
.rules-dialog__sub { font-size: 13px; color: var(--text-muted); }
.rules-dialog__close {
    flex: none;
    border: none;
    background: none;
    padding: 0;
    color: var(--text-quiet);
    cursor: pointer;
}
.rules-dialog__close .material-symbols-outlined { font-size: 22px; }

.rules-dialog__body {
    padding: 20px 24px;
    display: flex;
    flex-direction: column;
    gap: 20px;
    overflow-y: auto;
}
.rules-section { display: flex; flex-direction: column; gap: 8px; }
.rules-section__label { font-size: 13px; font-weight: var(--font-weight-semibold); color: var(--text); }
.rules-section__caption { font-size: 12.5px; line-height: 1.5; color: var(--text-muted); }
.rules-section__scope {
    font-size: 11px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

/* A boolean setting is a row card with the state described in words — "Off — the closest tee
   shot wins regardless of score" says more than an unlabelled unchecked box ever did. */
.rules-boolcard {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 14px 16px;
    border-radius: 14px;
    background: var(--control-fill);
    border: 1px solid var(--hairline);
}
.rules-boolcard__id { flex: 1; display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.rules-boolcard__title { font-size: 14px; font-weight: var(--font-weight-semibold); color: var(--text); }
.rules-boolcard__state { font-size: 12.5px; color: var(--text-muted); }

.rules-holehead { display: flex; align-items: baseline; gap: 8px; }
.rules-count-pill {
    display: inline-flex;
    padding: 2px 8px;
    border-radius: var(--radius-pill);
    background: color-mix(in srgb, var(--color-accent) 14%, transparent);
    color: var(--color-accent);
    font-size: 11px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.04em;
}
.rules-reset {
    margin-left: auto;
    border: none;
    background: none;
    padding: 0;
    font-family: inherit;
    font-size: 12.5px;
    font-weight: var(--font-weight-semibold);
    color: var(--text-muted);
    cursor: pointer;
}
.rules-reset:disabled { color: var(--ink-disabled); cursor: not-allowed; }

.hole-rule-list {
    border-radius: 14px;
    border: 1px solid var(--hairline);
    overflow: hidden;
}
.hole-rule-row { display: flex; align-items: center; gap: 12px; padding: 12px 16px; }
.hole-rule-row + .hole-rule-row { border-top: 1px solid var(--hairline-soft); }
.hole-rule-row--set { background: color-mix(in srgb, var(--color-accent) 5%, transparent); }
.hole-rule-row__tile {
    flex: none;
    width: 30px;
    height: 30px;
    border-radius: 9px;
    display: grid;
    place-items: center;
    background: var(--control-fill-strong);
    font-size: 13px;
    font-weight: var(--font-weight-bold);
    color: var(--text);
    font-variant-numeric: tabular-nums;
}
.hole-rule-row--set .hole-rule-row__tile {
    background: color-mix(in srgb, var(--color-accent) 16%, transparent);
    color: var(--color-accent);
}
.hole-rule-row__name { flex: 1; font-size: 13.5px; color: var(--text); min-width: 0; }
.hole-rule-row__yards { color: var(--text-quiet); }
.hole-rule-row .native-select {
    flex: none;
    min-height: 0;
    padding: 7px 26px 7px 10px;
    border: none;
    border-radius: 9px;
    background-color: var(--control-fill);
    background-position: right 0.35rem center;
    font-size: 12.5px;
    color: var(--text-muted);
}
.hole-rule-row--set .native-select {
    background-color: color-mix(in srgb, var(--color-accent) 10%, transparent);
    border: 1px solid color-mix(in srgb, var(--color-accent) 35%, transparent);
    font-weight: var(--font-weight-semibold);
    color: var(--text);
}

.rules-dialog__footer {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 16px 24px;
    padding-bottom: calc(16px + env(safe-area-inset-bottom));
    border-top: 1px solid var(--hairline);
    background: color-mix(in srgb, var(--text) 2%, transparent);
}
.rules-dialog__note { font-size: 12.5px; color: var(--text-muted); }
.rules-dialog__footer .btn-ghost { margin-left: auto; padding: 10px 16px; border-radius: 11px; }
.rules-dialog__save {
    padding: 10px 20px;
    border: none;
    border-radius: 11px;
    background: var(--color-accent);
    color: var(--on-hue);
    font-family: inherit;
    font-size: 13.5px;
    font-weight: var(--font-weight-bold);
    cursor: pointer;
}
.rules-dialog__save:disabled { opacity: 0.6; cursor: not-allowed; }

.modal-backdrop--rules { background: rgba(6, 8, 10, 0.62); backdrop-filter: blur(3px); }

@media (min-width: 481px) {
    .rules-dialog {
        max-width: 540px;
        border-radius: 20px;
        border: 1px solid var(--hairline);
        box-shadow: 0 32px 80px rgba(0, 0, 0, 0.45);
        max-height: 84vh;
    }
}
@media (max-width: 480px) {
    /* The phone form is the same content as a bottom sheet: full-width controls, 56px rows and a
       sticky Save at the bottom, which the flex column plus the footer's own padding give. */
    .rules-dialog { max-height: 86vh; }
    .rules-dialog::before { display: none; }
    .rules-dialog__footer { position: sticky; bottom: 0; background: var(--surface-raised); }
}

/* ══ Awarded games — name the winner (.awg-*) ══════════════════════════════════════════════
   The Custom ("Awarded" tier) pots: games the app cannot score, so the commissioner says who won.
   This was the last block on the pane still on the pre-overhaul vocabulary — a grey
   `.settings-card` holding an <h3>, a `.data-table` of bare browser inputs and a full-width navy
   "Save Winners". Two defects, and the second is the one that made it unreadable: consecutive
   games were separated by the SAME hairline that separates rows within a game, so two forms ran
   together with nothing saying where one ended.

   So the heading moves out onto the pane as a section label — the move `.wager-section-label`
   already makes for "Games this round" — and each game becomes its own card with its own Save.
   Nothing left to mistake for a row divider, and saving one game no longer implies committing the
   next one. */

/* The block is a SIBLING of `.wagers-pane`, not a child — the pane ends on its own primary action.
   So it repeats that block's insets exactly, or its cards sit 2px out on a phone and 24px out at
   desktop width, which reads as two screens stacked rather than one. */
.awg {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    margin: 0 -1rem;
    padding: 0 var(--space-3);
}
@media (max-width: 767px) {
    .settings-ground .awg { margin-left: -14px; margin-right: -14px; }
}
@media (min-width: 768px) {
    .awg { margin: 0; padding: 0 var(--space-5); }
}

.awg__label { padding: 2px 4px; }
.awg__intro {
    margin: 6px 0 0;
    font-size: 12.5px;
    color: var(--text-muted);
    line-height: 1.5;
}

.awg-card {
    background: var(--surface-raised);
    border: 1px solid var(--hairline);
    border-radius: 18px;
    box-shadow: var(--shadow-lg);
    overflow: hidden;
}

.awg-card__head {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: 14px 16px;
}
.awg-card__name {
    flex: 1;
    min-width: 0;
    font-size: 17px;
    font-weight: var(--font-weight-semibold);
    color: var(--text);
}
/* Accent, because a pot IS money — the one hue this block spends, and the figure it names is the
   one being divided by everything below it. */
.awg-card__pot {
    flex: none;
    padding: 5px 11px;
    border-radius: var(--radius-pill);
    background: color-mix(in srgb, var(--color-accent) 12%, transparent);
    color: var(--ink-on-accent-tint);
    font-size: 12px;
    font-weight: var(--font-weight-bold);
    font-variant-numeric: tabular-nums;
}

/* One winner. FLAT markup — name, amount, remove, payout line, note — reflowed by `order` on a
   phone and placed on a grid at desktop width, so there is one input per field rather than two
   drawings of the same row fighting over the same binding. */
.awg-winner {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    column-gap: var(--space-3);
    row-gap: 0;
    padding: 12px 16px;
    border-top: 1px solid var(--hairline-soft);
}
.awg-winner__name {
    order: 1;
    flex: 1 1 auto;
    min-width: 0;
    font-size: 15px;
    font-weight: var(--font-weight-semibold);
    color: var(--text);
}
/* The pane's own money field, sized for a card row rather than a grid cell. */
.awg-winner .money-field { order: 2; flex: none; width: 104px; height: 40px; border-radius: 11px; }
.awg-winner .money-field__input { font-size: 15px; }

/* The payout in words. It replaces the block-level paragraph that used to explain even splitting
   in the abstract — this says what THIS person is owed, and on a pot where somebody typed a
   figure it says the blank rows pay nothing, which is the one thing the old form hid. */
.awg-winner__share {
    order: 4;
    flex: 1 1 100%;
    margin: 6px 0 0;
    font-size: 12.5px;
    color: var(--text-muted);
}

.awg-note {
    order: 5;
    flex: 1 1 100%;
    width: 100%;
    height: 40px;
    margin-top: 10px;
    padding: 0 12px;
    border: 1px solid var(--hairline);
    border-radius: 11px;
    background: var(--control-fill);
    font-family: inherit;
    font-size: 13.5px;
    color: var(--text);
}
.awg-note::placeholder { color: var(--ink-disabled); }
.awg-note:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 1px; }

/* Remove is a 34px icon button, not a red "Remove" text button: taking a name off a list nobody
   has saved yet is not destructive, and --danger spent here is --danger meaning less elsewhere. */
.awg-remove {
    order: 3;
    flex: none;
    width: 34px;
    height: 34px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: none;
    border-radius: 9px;
    background: none;
    color: var(--text-quiet);
    cursor: pointer;
}
.awg-remove:hover { background: var(--control-fill); color: var(--text); }
.awg-remove:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; }
.awg-remove .material-symbols-outlined { font-size: 19px; }

.awg-card__add {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: 12px 16px;
    border-top: 1px solid var(--hairline-soft);
}
.awg-card__status {
    flex: 1;
    min-width: 0;
    font-size: 13px;
    color: var(--text-muted);
}
/* A trigger RESTYLE of the existing SheetSelect, not a second control: a 34px ghost chip that
   reads as a verb. The caret goes because the label is already the action, and the placeholder
   takes full ink for the same reason — it isn't standing in for a value, it IS the label.
   Written `.sheet-select-trigger.awg-addwinner` so it beats 13-controls-overlays.css, which is a
   single class and concatenates before this file. */
.sheet-select-trigger.awg-addwinner {
    flex: none;
    width: auto;
    min-height: 34px;
    height: 34px;
    justify-content: flex-start;
    gap: 7px;
    padding: 0 12px;
    border: 1px solid var(--control-fill-strong);
    border-radius: 9px;
    background: var(--surface-raised);
    font-size: 12.5px;
    font-weight: var(--font-weight-semibold);
    color: var(--text);
}
.sheet-select-trigger.awg-addwinner .sheet-select-trigger__value,
.sheet-select-trigger.awg-addwinner .sheet-select-trigger__value.placeholder {
    flex: none;
    color: var(--text);
}
.sheet-select-trigger.awg-addwinner .sheet-select-trigger__caret { display: none; }
/* Greyed still has to say what it is — `--ink-disabled`, never a border-strength token. */
.sheet-select-trigger.awg-addwinner:disabled,
.sheet-select-trigger.awg-addwinner:disabled .sheet-select-trigger__value,
.sheet-select-trigger.awg-addwinner:disabled .sheet-select-trigger__lead {
    background: none;
    color: var(--ink-disabled);
}
.sheet-select-trigger.awg-addwinner .sheet-select-trigger__lead {
    font-size: 17px;
    color: var(--text-muted);
}

/* The footer is rendered ONLY while that game carries local edits, which is the one behaviour
   change in this block — the old form always showed a Save button whether or not anything had
   changed, so it could not tell you that something needed saving. Warning tint, because unsaved
   winners are money that hasn't moved; the ink is the pane's own --ink-on-warning-tint. */
.awg-card__save {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: 12px 16px;
    border-top: 1px solid var(--hairline-soft);
    background: color-mix(in srgb, var(--warning) 12%, transparent);
    color: var(--ink-on-warning-tint);
}
.awg-card__unsaved {
    flex: 1;
    min-width: 0;
    font-size: 12.5px;
    font-weight: var(--font-weight-semibold);
    line-height: 1.5;
}
/* width:auto overrides .btn's width:100% — this one sits beside a sentence, not under it. */
.awg-save {
    flex: none;
    width: auto;
    height: 40px;
    padding: 0 16px;
    border: none;
    border-radius: 11px;
    background: var(--color-accent);
    color: var(--on-hue);
    font-family: inherit;
    font-size: 14px;
    font-weight: var(--font-weight-bold);
    cursor: pointer;
}
.awg-save:hover:not(:disabled) { background: color-mix(in srgb, var(--color-accent) 88%, #000); }
.awg-save:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; }
.awg-save:disabled { opacity: 0.6; cursor: not-allowed; }

/* Desktop: the same five elements on one row — name with the payout demoted under it, then the
   note, the amount and remove. A grid rather than a second markup, so the fields keep one binding
   apiece; the payout's row collapses to nothing on a winner whose amount is typed. */
@media (min-width: 768px) {
    .awg-winner {
        display: grid;
        grid-template-columns: minmax(0, 1fr) 150px 112px 34px;
        align-items: center;
        align-content: center;
        column-gap: var(--space-4);
        row-gap: 2px;
        min-height: 62px;
    }
    .awg-winner__name { grid-column: 1; grid-row: 1; }
    .awg-winner__share { grid-column: 1; grid-row: 2; margin: 0; }
    .awg-note { grid-column: 2; grid-row: 1 / span 2; width: auto; margin-top: 0; }
    .awg-winner .money-field { grid-column: 3; grid-row: 1 / span 2; width: auto; }
    .awg-remove { grid-column: 4; grid-row: 1 / span 2; }
}

/* ══ Wager opt-ins (.wor-*) ════════════════════════════════════════════════════════════════
   /rounds/{id}/wagering/roster — who is paying into which pot. A row is a PLAYER and the control
   is one chip per game, not a cell in a players × types matrix: a matrix needs a header row to be
   readable, and a header row cannot stay aligned with chips that wrap. The chips carry the labels
   instead, so the same markup works at 1100px and at 390px with nothing hidden.

   Accent on a filled chip is the app's "live or money" meaning used literally — a pot this player
   is buying into. Out is quiet ink on the plain control fill; it is not a danger or a warning. */

.wor-row {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 12px 20px;
    border-bottom: 1px solid var(--hairline-soft);
}

/* The card foot draws its own top rule, so the last row must not double it. */
.wor-row:last-of-type { border-bottom: none; }

.wor-row__who { flex: 1 1 auto; min-width: 0; }

.wor-row__name {
    display: block;
    font-size: 15px;
    font-weight: var(--font-weight-semibold);
    color: var(--text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.wor-row__sub {
    display: block;
    margin-top: 2px;
    font-size: 12px;
    color: var(--text-quiet);
}

/* A player in nothing is a legitimate state (a walker, a guest not playing for money), so it is
   quieted rather than flagged. */
.wor-row.is-out .wor-row__name { color: var(--text-muted); }

.wor-row__games {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: 6px;
    flex: 0 1 auto;
}

.wor-chip {
    display: inline-flex;
    align-items: center;
    min-height: 32px;
    padding: 0 12px;
    border: 1px solid var(--hairline);
    border-radius: 999px;
    background: var(--control-fill);
    font-family: inherit;
    font-size: 12.5px;
    font-weight: var(--font-weight-semibold);
    color: var(--ink-disabled);
    cursor: pointer;
    white-space: nowrap;
    transition: background 0.14s ease, color 0.14s ease, border-color 0.14s ease;
}

.wor-chip:hover { background: var(--control-fill-strong); }

.wor-chip.is-in {
    background: color-mix(in srgb, var(--color-accent) 14%, transparent);
    border-color: color-mix(in srgb, var(--color-accent) 38%, transparent);
    color: color-mix(in srgb, var(--color-accent) 72%, var(--text));
}

.wor-chip.is-in:hover { background: color-mix(in srgb, var(--color-accent) 22%, transparent); }

/* A text button, not a third chip — it acts on the row rather than naming a game, and giving it
   chip chrome made every row read as having one more game than it has. */
.wor-row__all {
    flex: none;
    min-width: 52px;
    height: 32px;
    padding: 0 10px;
    border: none;
    border-radius: var(--radius-md);
    background: none;
    font-family: inherit;
    font-size: 12.5px;
    font-weight: var(--font-weight-semibold);
    color: var(--color-accent);
    cursor: pointer;
}

.wor-row__all:hover { background: var(--control-fill); }

@media (max-width: 768px) {
    /* Name and the row verb on the first line, the chips wrapping full-width under them. Ordered
       by flex rather than by a second DOM: the chips must be able to take the whole width, which
       they cannot while they share a line with a name that also wants to grow. */
    .wor-row { flex-wrap: wrap; row-gap: 10px; padding: 12px 16px; }
    .wor-row__who { order: 1; }
    .wor-row__all { order: 2; }
    .wor-row__games { order: 3; flex: 1 1 100%; justify-content: flex-start; }
    .wor-chip { min-height: 36px; }
}

/* Everything above animates at 120–160ms; honour the OS preference. */
@media (prefers-reduced-motion: reduce) {
    .switch,
    .switch__knob,
    .pots-row,
    .money-field,
    .rules-cell,
    .wor-chip { transition: none; }
}


/* ═══════════════════════════════════════════════════════════════════════════════════════════════
   EVENT SETTINGS → WAGERING (`.wgs-*`)                    handoffs/design_handoff_wagering_settings

   `/events/{slug}/settings/wagering` was the last screen in Event Settings on the pre-redesign
   vocabulary — a `.settings-card` slab, a centred `.data-table` of raw checkboxes, `.form-row` /
   `.form-group` pairs and two full-width navy `Save` slabs. It is `.set-card` rows now, it
   auto-saves, and a GAME is a card while a SPLIT is a row.

   Almost nothing new was needed: the card, the row, the switch, the segmented control, the stepper,
   the pill, the ghost chip, the section label and the save chip all already exist. What follows is
   the whole of the addition — six rules, and the prefix is checked against every LATER partial
   (18- through 32-) before it was picked, which is the trap `.ls-` and `.pm-sheet` have both sprung.
   ═══════════════════════════════════════════════════════════════════════════════════════════════ */

/* The two section labels sit on the pane GROUND, not inside a card — the same move
   `.wager-section-label` already makes for "Games this round" one screen over. */
.wgs-section { padding: 2px 0 0; }

.wgs-sectionnote {
    margin: 6px 0 0;
    padding: 0 var(--space-1);
    max-width: 56ch;
    font-size: 12.5px;
    color: var(--text-muted);
    line-height: 1.5;
}

/* The library's own sections come from `WagerGameTemplateDto.Section` and change BETWEEN rows, so
   this one is inside a card and needs the row gutter rather than the ground's — which means the
   SAME gutter as `.set-card__label` and `.set-row`, at both widths. It was a flat 20px, so on a
   phone (where the card drops to 16px) every section heading sat 4px right of the "Add a game"
   label above it and of the game names below it. */
.wgs-libsection {
    padding: 14px 20px 2px;
    border-top: 1px solid var(--hairline-soft);
}

/* Mirrors `.modal-panel.pm-sheet .sms-search`'s geometry so the two searches in the app match. */
.wgs-search {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 0 20px 12px;
    height: 44px;
    padding: 0 14px;
    border: 1px solid var(--hairline);
    border-radius: 12px;
    background: var(--control-fill);
}
.wgs-search .material-symbols-outlined { font-size: 19px; color: var(--ink-disabled); }
/* `appearance: none` is not cosmetic here. A bare `input[type=search]` keeps WebKit's own search
   chrome, which draws a SECOND magnifying glass inside the field — so on iOS the row read as two
   search icons side by side, ours in the box and Safari's just to its right. The type stays
   `search` for the keyboard's Search key; only the platform decoration goes. */
.wgs-search input {
    flex: 1;
    min-width: 0;
    appearance: none;
    -webkit-appearance: none;
    border: none;
    background: none;
    font-family: inherit;
    font-size: 14.5px;
    color: var(--text);
}
.wgs-search input::-webkit-search-decoration,
.wgs-search input::-webkit-search-results-button,
.wgs-search input::-webkit-search-results-decoration { display: none; }
.wgs-search input:focus { outline: none; }

/* The card's gutter is 16px below 768px (`.set-card__label`, `.set-row`), so the search box and
   every section heading follow it there or they sit 4px out of line with the card's own label. */
@media (max-width: 768px) {
    .wgs-libsection { padding-left: 16px; padding-right: 16px; }
    .wgs-search { margin-left: 16px; margin-right: 16px; }
}

/* A switched-off game is the WHOLE card at 55% — the `.set-row--muted` value — and it is never
   removed and never hidden behind a filter. "We're not playing it this year" is a state worth
   seeing, and its caption says what survives. */
.wgs-card--off { opacity: 0.55; }

/* The holes beside a split's name. Inline rather than a caption: the row is one line, and the
   name and the holes are one fact ("Back 9, holes 10–18"). */
.wgs-holes {
    margin-left: var(--space-2);
    font-size: 12.5px;
    font-weight: var(--font-weight-regular);
    color: var(--text-muted);
}

/* "How it's decided" on the wager-type sheet. Its left cells are LABELS for the pills opposite,
   not settings in their own right, so they read quieter than a `.set-row__name` normally does. */
.wgs-fact .set-row__name {
    font-size: 13.5px;
    font-weight: var(--font-weight-medium);
    color: var(--text-muted);
}

/* A split row carries THREE controls — the settings chip, the switch and the ⋯ — and at 390px that
   is about 40px more than the row has. `.set-row__body` holds 42% (07-settings.css, so a caption is
   never squeezed into a one-word column) and every control is `flex: none`, so the overflow lands
   on the right-hand end and the card's `overflow: hidden` cuts the ⋯ clean off at the edge.

   The CHIP gives up its label first, down to the bare `tune` glyph, and the switch never gives up
   anything: the switch is what the row is for, and a shrunk one reads as broken where a shortened
   chip reads as a chip. The value the label carried is one tap away inside the sheet, and the
   button keeps its aria-label, so nothing is lost that isn't recoverable.

   Scoped to `.wgs-split` rather than `.set-row--member`, which the Groups pane also uses. */
@media (max-width: 768px) {
    .wgs-split .wgs-chip__label { display: none; }
    .wgs-split .wgs-chip {
        width: 36px;
        height: 36px;
        padding: 0;
        border-radius: 10px;
    }
    .wgs-split .wgs-chip .material-symbols-outlined { font-size: 19px; }
}
/* ==========================================================================================
   LEADERBOARD REDESIGN — masthead, navigation rail, board grid
   (design_handoff_leaderboard/README.md, turns 4a / 4b / 5a / 5b)

   The screen used to stack five bands of chrome before the first score: .top-bar →
   .tournament-header → .main-nav → .view-switcher → .moments-ticker → the week picker → the
   table. Two of those were horizontal navs of near-equal weight with nothing saying which was
   destinations and which was lenses. That, not the tab styling, is what read as dated.

   What replaces them:
     • one broadcast masthead carrying the event identity, the week rail and a Leading / Pot
       stat rail on a champagne-metal edge;
     • one vertical navigation rail (≥769px) that is both navs at once, grouped "this week" and
       "the season", with admin pinned to its foot;
     • a board that is a CSS grid on a raised card rather than a <table>.

   Colour discipline that has to survive edits here: METAL means *standing* (position, the week
   you're on, a rare feat, section labels). GREEN means *live or money*. RED means *under par*,
   per the existing scorecard convention. Nothing else gets a hue.
   ========================================================================================== */

/* ── Masthead ───────────────────────────────────────────────────────────────────────────── */
.masthead {
    background: var(--masthead-ground);
    background-size: cover;
    background-position: center;
    border-bottom: 1px solid var(--metal-edge);
}

/* The scrim only does work over a photo; on the gradient ground it is an inert wrapper, which
   is what keeps the two treatments geometrically identical (§ 4b: "a switch between image and
   no image shifts nothing"). */
.masthead--photo .masthead__scrim { background: var(--masthead-scrim); }

.masthead__inner {
    max-width: 1280px;
    margin: 0 auto;
    padding: 0 var(--space-5);
}

/* Utility row — 50px, the old .top-bar folded in. */
.mh-utility {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    height: 50px;
}

.mh-brand { display: block; line-height: 0; }
.mh-brand img { display: block; width: 24px; height: 24px; border-radius: 7px; }
.mh-brand:active { opacity: 0.6; }

.mh-wordmark,
.mh-eventtype {
    font-size: 11px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.14em;
    text-transform: uppercase;
    white-space: nowrap;
}
.mh-wordmark { color: var(--text-quiet); }
.mh-eventtype { color: var(--text-muted); }

/* Hairline-weight separator, not an affordance — it is drawn at border strength on purpose. */
.mh-utility-sep {
    font-size: 16px;
    color: var(--border);
}

.mh-utility-end {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

/* The chip is a <button> now — it opens the Course conditions panel (.wx-* at the foot of this
   file). It is also drawn from the FIRST paint as a placeholder, because the coordinate it needs
   arrives with the tournament status: without a placeholder the slot is empty until that returns
   and the row visibly reflows when the reading lands. */
.mh-weather {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 6px 11px;
    border-radius: 9px;
    background: var(--control-fill);
    border: 1px solid transparent;   /* reserved, so the open state's hairline costs no width */
    font-family: inherit;
    font-size: 12.5px;
    color: var(--text-muted);
    white-space: nowrap;
}
button.mh-weather { cursor: pointer; }
button.mh-weather:active { transform: scale(0.98); }

/* Open: a metal wash and a metal hairline, the language the rest of the masthead already speaks. */
.mh-weather.is-open {
    background: var(--metal-wash-16);
    border-color: var(--metal-edge);
}

/* The glyph takes metal because it is a label for a reading, not a state. */
.mh-weather__glyph { font-size: 16px; color: var(--metal); }
.mh-weather__temp { display: none; }   /* phone swaps these two — see the 768px block */
.mh-weather__caret { font-size: 14px; color: var(--text-quiet); }

/* Unreachable: the provider didn't answer. Quiet rather than alarming — nothing on the page
   depended on it — but still a button, because the panel behind it explains and offers a retry. */
.mh-weather--off { color: var(--text-quiet); }
.mh-weather--off .mh-weather__glyph { color: var(--ink-disabled); }

/* Loading. Not focusable and not tappable; this is the state that stops the row moving. */
.mh-weather--loading { cursor: default; }
.mh-weather--loading .mh-weather__glyph { animation: wx-pulse 1.6s ease-in-out infinite; }
.mh-weather__bar {
    display: block;
    width: 104px;
    height: 9px;
    border-radius: var(--radius-pill);
    background: linear-gradient(90deg, var(--hairline-soft) 0%, var(--hairline) 50%, var(--hairline-soft) 100%);
    background-size: 180px 100%;
    animation: wx-shimmer 1.2s linear infinite;
}

@keyframes wx-pulse {
    0%, 100% { opacity: 0.35; }
    50% { opacity: 0.8; }
}

@keyframes wx-shimmer {
    from { background-position: -180px 0; }
    to { background-position: 180px 0; }
}

@media (prefers-reduced-motion: reduce) {
    .mh-weather--loading .mh-weather__glyph,
    .mh-weather__bar { animation: none; }
}

.mh-avatar {
    width: 32px;
    height: 32px;
    border-radius: var(--radius-pill);
    border: none;
    padding: 0;
    background: var(--surface-2);
    color: var(--text);
    font-family: inherit;
    font-size: 11.5px;
    font-weight: var(--font-weight-bold);
    line-height: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: box-shadow 0.15s ease, transform 0.1s ease;
}
.mh-avatar:hover { box-shadow: 0 0 0 3px var(--control-fill-strong); }
.mh-avatar:active { transform: scale(0.96); }

/* Title block. The 14px gap under the <h1> and the 10px above it are specified explicitly in
   the handoff ("do not tighten these") — they are what make the band read as a masthead rather
   than a page heading. */
.mh-title-block {
    display: flex;
    flex-direction: column;
    gap: 14px;
    padding: 10px 0 18px;
}

.mh-title {
    margin: 0;
    font-size: 36px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.03em;
    line-height: 1.05;
    color: var(--text);
    /* Event names are user text and need not contain spaces. At 36px (27px on a phone) one long
       token runs straight off the viewport and takes the whole page into horizontal scroll —
       the masthead is full-bleed, so nothing else clips it. `anywhere` breaks mid-token only
       when there is no other option, so ordinary multi-word names still wrap on spaces. */
    overflow-wrap: anywhere;
}

.mh-meta {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}

.mh-livepill {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 3px 10px 3px 8px;
    border-radius: var(--radius-pill);
    background: color-mix(in srgb, var(--color-accent) 12%, transparent);
    border: 1px solid color-mix(in srgb, var(--color-accent) 30%, transparent);
}
.mh-livepill__dot {
    width: 6px;
    height: 6px;
    border-radius: var(--radius-pill);
    background: var(--color-accent);
    animation: winprob-pulse 1.6s ease-in-out infinite;
}
.mh-livepill__text {
    font-size: 11px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: color-mix(in srgb, var(--color-accent) 70%, var(--text));
}
/* Scheduled / complete drop the accent entirely — the pill is a state, and green here would
   claim a round is live when it isn't. Same neutral the Wagers pane uses. */
.mh-livepill--quiet {
    background: color-mix(in srgb, var(--slate-500) 14%, transparent);
    border-color: color-mix(in srgb, var(--slate-500) 28%, transparent);
}
.mh-livepill--quiet .mh-livepill__dot { background: var(--slate-500); animation: none; }
.mh-livepill--quiet .mh-livepill__text { color: var(--text-muted); }

/* ── The same pill, as the week picker (handoffs/design_handoff_week_selector) ────────────
   The numeral rail that used to sit on its own line below this said "week 9" a second time, and
   cost ~44px to do it. Making the status pill the button spends no line at all and makes the
   target BIGGER rather than smaller — this is the one thing on the masthead meant to be hit.

   What earns the tap is the metal tint and the caret: a pill that reads as status has to say it
   opens something. Metal because the week you are looking at is a STANDING; the dot stays green
   because that is about the round being live, which is a different fact. */
.mh-livepill--picker {
    height: 34px;
    padding: 0 10px 0 12px;
    gap: 8px;
    background: var(--metal-wash-16);
    border-color: var(--metal-line);
    font-family: inherit;
    cursor: pointer;
    white-space: nowrap;
    flex-shrink: 0;
    transition: background 0.14s ease;
}
.mh-livepill--picker .mh-livepill__text { color: var(--metal-strong); }
.mh-livepill--picker:hover { background: var(--metal-wash-18); }
.mh-livepill__caret { font-size: 18px; color: var(--metal); flex-shrink: 0; }
/* A scheduled or complete week keeps the quiet slate treatment it has always had — but the border
   and the caret stay metal, because the affordance must not come and go with whether a round
   happens to be live. */
.mh-livepill--picker.mh-livepill--quiet {
    background: color-mix(in srgb, var(--slate-500) 12%, transparent);
    border-color: var(--metal-line);
}
.mh-livepill--picker.mh-livepill--quiet:hover {
    background: color-mix(in srgb, var(--slate-500) 18%, transparent);
}
/* Explicit, because --picker's metal ink is declared after --quiet's muted one at equal
   specificity and would otherwise win on source order. A scheduled week is not a standing. */
.mh-livepill--picker.mh-livepill--quiet .mh-livepill__text { color: var(--text-muted); }

.mh-meta__course {
    font-size: 13.5px;
    color: color-mix(in srgb, var(--text) 88%, transparent);
    /* The pill is flex-shrink:0, so the course name is what gives on a narrow meta line. */
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.mh-meta__sub { font-size: 13.5px; color: var(--text-muted); }
/* "12 → 6 after the cut". The field size is a true count that tells a false story once a cut has
   run, so the arrow phrase replaces it and takes the metal weight — a cut is a standing. */
.mh-meta__cut { font-weight: var(--font-weight-semibold); color: var(--metal); }
/* Before the cut runs: one affordance saying it is coming. */
.mh-meta__cutnote {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: 12.5px;
    font-weight: var(--font-weight-semibold);
    color: var(--metal);
    white-space: nowrap;
}
.mh-meta__cutnote .material-symbols-outlined { font-size: 15px; }

.mh-hairline {
    width: 1px;
    height: 14px;
    background: var(--hairline);
    flex-shrink: 0;
}
.mh-hairline--stat { height: 18px; margin: 0 var(--space-4); }

/* ── Metal edge: the stat rail ───────────────────────────────────────────────────────────
   It used to carry the week rail too — a horizontal scroller of numerals with an "All N" button
   pinned over a fade at its right. Both are gone: the status pill on the meta line above is the
   week picker now (handoffs/design_handoff_week_selector), which is ~44px of masthead back and
   removes the one thing on this band that depended on the document not being wider than the
   viewport. One flex row at every width; the phone's stat rail supplies its own rule and padding. */
.mh-edge {
    display: flex;
    align-items: center;
    gap: 5px;
    padding-bottom: 12px;
}

/* Stat rail. Read-only furniture, not a widget: no card, no border, no background, and
   baseline-aligned so the figures sit on the same line as their labels. */
.mh-stats {
    margin-left: auto;
    display: flex;
    /* Centred, not baseline-aligned, at THIS level only: the ticker is an overflow:hidden box, so
       it synthesises its baseline from its bottom margin edge and would drag the LEADING label
       ~4px low. Each half keeps its own internal baseline alignment, which is what actually makes
       the figures read as furniture rather than a widget. */
    align-items: center;
    min-width: 0;
}
.mh-stat {
    display: flex;
    align-items: baseline;
    gap: 9px;
    min-width: 0;
}
/* The label sits beside the ticker box, so it centres against it rather than chasing a baseline
   the box doesn't really have. */
.mh-stat--leading { align-items: center; }
.mh-stat__label {
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--text-quiet);
    white-space: nowrap;
}
.mh-stat__label--metal { color: var(--metal); }
.mh-stat__pot {
    font-size: 18px;
    font-weight: var(--font-weight-semibold);
    color: var(--color-accent);
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.02em;
}
.mh-stat__pot-short { display: none; }   /* phone abbreviates to whole dollars */
/* "skins funded by 6 · was $120" — one caption under the POT figure when the cut halved a
   per-player pot. It wraps to its own line rather than making .mh-stat a column, so the
   label/figure row above it is untouched. */
.mh-stat--pot { flex-wrap: wrap; justify-content: flex-end; }
.mh-stat__potnote {
    flex-basis: 100%;
    text-align: right;
    font-size: 10.5px;
    color: var(--text-quiet);
}

/* Rotating LEADING ticker. Every line is in the DOM inside a one-line viewport and the strip is
   translated by whole lines, so the motion is a single CSS transition rather than a keyframe
   race with a C# timer. --mh-tick-ms must stay in step with TickerSlideMs in EventMasthead. */
.mh-ticker {
    --mh-tick-h: 22px;
    --mh-tick-ms: 700ms;
    height: var(--mh-tick-h);
    overflow: hidden;
    min-width: 0;
}
.mh-ticker__strip {
    display: flex;
    flex-direction: column;
    /* Eased in AND out: a ticker line is always mid-journey to the reader, so a curve that leaves
       fast (the old 420ms cubic-bezier(0.32, 0.72, 0, 1)) reads as a jump rather than a glide. */
    transition: transform var(--mh-tick-ms) cubic-bezier(0.4, 0, 0.2, 1);
}
/* The one frame where the strip snaps from the repeated leader back to line 0. */
.mh-ticker__strip.is-instant { transition: none; }
.mh-ticker__line {
    display: flex;
    align-items: center;
    height: var(--mh-tick-h);
    white-space: nowrap;
}
/* The pos / name / score share a baseline with each other, but that group is then centred in the
   line box AS A WHOLE. Baseline-aligning them straight against the fixed-height line flushes the
   group to its top edge, which left the tall score sitting ~1px below the LEADING label centred
   beside it — the two font sizes have to be centred the same way to read as one line. */
.mh-ticker__row {
    display: flex;
    align-items: baseline;
    gap: 9px;
    min-width: 0;
}
.mh-ticker__pos {
    font-size: 11px;
    font-weight: var(--font-weight-bold);
    color: var(--metal);
    font-variant-numeric: tabular-nums;
}
.mh-ticker__name {
    font-size: 14.5px;
    font-weight: var(--font-weight-semibold);
    color: var(--text);
    overflow: hidden;
    text-overflow: ellipsis;
    min-width: 0;   /* without this the name can't shrink, so it clips instead of ellipsing */
}
.mh-ticker__score {
    font-size: 18px;
    font-weight: var(--font-weight-bold);
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.02em;
    color: var(--text);
}
.mh-ticker__score.is-under { color: var(--under-par); }
.mh-ticker__thru { font-size: 12px; color: var(--text-muted); }

/* Photo masthead: ink steps up one level and the two hues brighten so they clear a mid-tone
   image. These values are ABSOLUTE rather than tokenised because the scrim is dark in both
   themes — a photo header is a dark surface even in light mode. */
.masthead--photo .mh-title { color: #fff; text-shadow: 0 1px 24px rgba(0, 0, 0, 0.5); }
.masthead--photo .mh-wordmark { color: #aab2bc; }
.masthead--photo .mh-eventtype,
.masthead--photo .mh-meta__course { color: #eef1f4; }
.masthead--photo .mh-meta__sub,
.masthead--photo .mh-ticker__thru { color: #c8cfd8; }
.masthead--photo .mh-ticker__name { color: #fff; }
.masthead--photo .mh-ticker__score.is-under { color: #f78b92; }
.masthead--photo .mh-stat__pot { color: #7ee29a; }
.masthead--photo .mh-stat__label { color: #aab2bc; }
.masthead--photo .mh-stat__potnote { color: #aab2bc; }
.masthead--photo .mh-meta__cut,
.masthead--photo .mh-meta__cutnote { color: #e0c88c; }
.masthead--photo .mh-stat__label--metal { color: #e0c88c; }
.masthead--photo .mh-weather,
.masthead--photo .mh-avatar {
    background: rgba(10, 13, 16, 0.45);
    border-color: rgba(255, 255, 255, 0.16);
    color: #eef1f4;
}
.masthead--photo .mh-hairline { background: rgba(255, 255, 255, 0.18); }
.masthead--photo .mh-livepill {
    background: rgba(58, 209, 96, 0.18);
    border-color: rgba(58, 209, 96, 0.42);
}
.masthead--photo .mh-livepill__text { color: #9df0b4; }
/* As the picker, on the photo ground: champagne rather than the light theme's bronze, which is
   invisible over a scrim. Absolute hex for the reason the whole block is — a photo header is a
   dark surface in both themes. */
.masthead--photo .mh-livepill--picker,
.masthead--photo .mh-livepill--picker.mh-livepill--quiet {
    background: rgba(201, 173, 110, 0.24);
    border-color: rgba(201, 173, 110, 0.55);
}
.masthead--photo .mh-livepill--picker:hover,
.masthead--photo .mh-livepill--picker.mh-livepill--quiet:hover {
    background: rgba(201, 173, 110, 0.34);
}
.masthead--photo .mh-livepill--picker .mh-livepill__text { color: #f2e4bf; }
.masthead--photo .mh-livepill--picker.mh-livepill--quiet .mh-livepill__text { color: #dfe4ea; }
.masthead--photo .mh-livepill__caret { color: #e0c88c; }
.masthead { border-bottom-color: var(--metal-edge); }
.masthead--photo { border-bottom-color: rgba(201, 173, 110, 0.30); }

/* ── Event shell: rail + content ─────────────────────────────────────────────────────────
   Below the breakpoint the rail collapses (not narrows) and the phone keeps .bottom-nav. */
.event-shell { min-width: 0; }
.event-shell > .settings-nav { display: none; }

@media (min-width: 769px) {
    .event-shell {
        display: grid;
        grid-template-columns: 236px minmax(0, 1fr);
        align-items: start;
    }
    /* Settings and the Round hub bring their own rail; ours stands down there (see
       MainLayout.HideEventRail) and the content takes the full width. */
    .event-shell--norail { display: block; }
    .event-shell > .settings-nav {
        display: flex;
        position: sticky;
        top: var(--space-4);
        padding: 18px 12px;
        background: var(--rail-ground);
        border-right: 1px solid var(--hairline);
        min-height: 560px;
    }
    .event-shell > main { padding: 20px var(--space-5) 26px; min-width: 0; }
    /* .settings-ground breaks out of main's gutters to run edge-to-edge, and its own rule in
       07-settings.css does that with `margin: -1rem -1rem 0` — correct at ≤768px, where main is
       `0.5rem 1rem`, and 8px short on each side HERE, where main is 24px. The ground therefore
       stopped short of the masthead above it, which is the sliver the round hub showed.

       Scoped to the event shell on purpose, NOT applied globally to .settings-ground: main is
       still `padding: 1rem` on every non-event route (My events, /events/create, the round
       wizard), where the -1rem breakout is exactly right and a -24px one would overhang.
       These numbers are the line above's — change one and change both. */
    .event-shell > main .settings-ground {
        margin: -20px calc(-1 * var(--space-5)) 0;
        padding: 20px var(--space-5) var(--space-6);
    }
}

/* The event rail is RoundNav's vocabulary promoted to event level — .settings-nav gives it the
   compact rail treatment for free (see the Settings block). Only the active ink changes: on this
   screen metal means "the standing you're looking at", so the accent wash becomes a metal one.
   Scoped to --metal so RoundNav and SettingsNav keep their accent. */
@media (min-width: 768px) {
    .settings-nav--metal .settings-row.is-active {
        background: var(--metal-wash-10);
        box-shadow: inset 2px 0 0 var(--metal);
    }
    .settings-nav--metal .settings-row.is-active .settings-row-icon { color: var(--metal-strong); }
    .settings-nav--metal .settings-row.is-active .settings-row-title {
        color: color-mix(in srgb, var(--metal) 18%, var(--text));
    }
    /* The view rows are <button>s reusing an anchor row style — reset button chrome. */
    .settings-nav button.settings-row {
        width: 100%;
        border: none;
        background: none;
        font: inherit;
        text-align: left;
        cursor: pointer;
    }
    /* The rail's first eyebrow sits flush with the top padding; the ones after it need the
       space that separates one group from the last row of the previous one. */
    .settings-nav .settings-eyebrow--first { padding-top: 0; }
    .event-rail__foot {
        margin-top: auto;
        padding-top: 18px;
        border-top: 1px solid var(--hairline);
    }
    .event-rail__foot .settings-row-chev { display: inline-block; color: var(--ink-disabled); }
    /* Trailing value pill (a game's pot). Shown only where the number is already loaded — the
       rail never fetches for itself. */
    .rail-pill {
        margin-left: auto;
        display: inline-flex;
        padding: 2px 7px;
        border-radius: var(--radius-pill);
        background: color-mix(in srgb, var(--color-accent) 14%, transparent);
        font-size: 10.5px;
        font-weight: var(--font-weight-bold);
        color: color-mix(in srgb, var(--color-accent) 70%, var(--text));
        font-variant-numeric: tabular-nums;
    }
}

/* ── Board control row ───────────────────────────────────────────────────────────────────
   Moments capsule, flight filter, and the one admin affordance. What used to be three bands. */
/* Wraps so the phone can put Moments on its own row beneath the mode controls, using flex order
   and nothing else — one DOM order at every width, and desktop is untouched. */
.board-controls {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-3);
    margin-bottom: 14px;
    min-width: 0;
}
.board-controls__end {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex-shrink: 0;
}

.segmented--compact { padding: 3px; border-radius: 10px; background: var(--control-fill); }
.segmented--compact .segmented__opt {
    padding: 5px 11px;
    border-radius: 7px;
    font-size: 12px;
    font-weight: var(--font-weight-medium);
}
.segmented--compact .segmented__opt.is-active {
    background: var(--control-fill-strong);
    color: var(--text);
    font-weight: var(--font-weight-semibold);
}

.board-manage {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 7px 11px;
    border-radius: 9px;
    background: var(--control-fill);
    border: 1px solid var(--control-fill-strong);
    font-size: 12.5px;
    color: var(--text);
    white-space: nowrap;
}
.board-manage .material-symbols-outlined { font-size: 16px; color: var(--text-quiet); }
.board-manage:hover { background: var(--control-fill-strong); }

.board-final { margin-bottom: var(--space-3); }

/* Moments capsule — one quiet capsule on the control row, not a band above the board. */
.moments-capsule {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 12px 8px 10px;
    border-radius: 11px;
    background: var(--surface-raised);
    border: 1px solid var(--hairline);
    font-family: inherit;
    cursor: pointer;
    min-width: 0;
    overflow: hidden;
}
.moments-capsule__label {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 10.5px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-quiet);
    white-space: nowrap;
}
.moments-capsule__dot {
    width: 6px;
    height: 6px;
    border-radius: var(--radius-pill);
    background: var(--color-accent);
    animation: winprob-pulse 1.6s ease-in-out infinite;
}
.moments-capsule__item {
    font-size: 13px;
    color: var(--text-muted);
    white-space: nowrap;
}
.moments-capsule__item.is-newest { color: color-mix(in srgb, var(--text) 88%, transparent); }
/* An ace or albatross takes metal so the rare feat is the one that catches the eye. */
.moments-capsule__item.is-rare { color: var(--metal-strong); }
.moments-capsule__item strong { font-weight: var(--font-weight-semibold); }
.moments-capsule__more {
    display: inline-flex;
    padding: 2px 8px;
    border-radius: var(--radius-pill);
    background: color-mix(in srgb, var(--color-accent) 14%, transparent);
    font-size: 11px;
    font-weight: var(--font-weight-bold);
    color: color-mix(in srgb, var(--color-accent) 70%, var(--text));
}
/* Desktop keeps the inline capsule beside the mode controls, where a chevron would read as a
   dropdown; the phone row is wide enough for it to read as "there's more behind this". */
.moments-capsule__chev { display: none; }

.moments-feed__list { display: flex; flex-direction: column; }
.moments-feed__row {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-1);
    border-bottom: 1px solid var(--hairline-soft);
}
.moments-feed__row:last-child { border-bottom: none; }
.moments-feed__badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 2rem;
    border-radius: var(--radius-pill);
    background: var(--surface-subtle);
    flex-shrink: 0;
}
.moments-feed__text { display: flex; flex-direction: column; line-height: 1.25; min-width: 0; }
.moments-feed__detail { font-size: 0.78rem; color: var(--text-muted); }

/* The alert preference, docked below the feed (DASHBOARD-RETIREMENT-PLAN.md Phase 1). It is
   .set-card / .set-row from 07-settings.css and writes NO layout of its own — the card already
   carries its own ground, border and shadow, so all that's needed here is the gap that separates
   it from the last highlight. */
.moments-feed__alerts { margin-top: var(--space-5); }

/* ── Board card ──────────────────────────────────────────────────────────────────────────
   CSS grid rows on a raised card. The column template is handed down as --board-cols /
   --board-cols-md / --board-cols-sm by the page (BoardColumnVars), because the cumulative
   board's column count is the event's round count and a media query can't read a Razor
   expression. Everything else about the shape lives here. */
/* .skel-board is the cold-start placeholder, sharing this card's chrome so the swap to content is
   ink appearing and nothing moving. It is a SEPARATE CLASS on purpose: .board-card means "the board
   is here", and several tests wait on it as the page-loaded signal — a skeleton answering to it
   would let them proceed against placeholders. */
.board-card,
.skel-board {
    background: var(--surface-raised);
    border: 1px solid var(--hairline);
    border-radius: var(--radius-xl);
    box-shadow: var(--shadow-lg);
    overflow: hidden;
    min-width: 0;
}

.board-head,
.board-row {
    display: grid;
    grid-template-columns: var(--board-cols);
    column-gap: 12px;
    align-items: center;
}

.board-head {
    padding: 11px 20px;
    border-bottom: 1px solid var(--hairline);
    font-size: 10.5px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-quiet);
}
.board-col-sortable { cursor: pointer; user-select: none; }
.board-col-sortable:hover { color: var(--text-muted); }

.board-row {
    padding: 14px 20px;
    border-bottom: 1px solid var(--hairline-soft);
    cursor: pointer;
    transition: background 0.14s ease;
}
.board-row:last-child { border-bottom: none; }
.board-row:hover { background: color-mix(in srgb, var(--text) 3%, transparent); }
/* Open row: the metal wash, not the pale blue. Hover stays a neutral tint — never blue.
   background-COLOR, not the shorthand: the shorthand would reset background-image and kill the
   leader row's --metal-row-wash gradient whenever row 1 is the open row. */
.board-row.is-open { background-color: var(--row-open-wash); }
/* Same warm near-white the rail's active label uses, so "you're reading this one" is one idea. */
.board-row.is-open .board-player__name { color: color-mix(in srgb, var(--metal) 18%, var(--text)); }
/* The leader's row carries a wash that fades out to the right — it says "this is the top of the
   board" without adding a second position marker. */
.board-row[data-pos="1"] { background-image: var(--metal-row-wash); }

.board-cell { min-width: 0; }
.board-cell.is-right { text-align: right; justify-self: end; }
.board-dash { color: var(--ink-disabled); }

.board-pos { display: flex; align-items: center; gap: 4px; }
.pos-tile {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    border-radius: 9px;
    font-size: 14.5px;
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
    color: var(--text-muted);
    flex-shrink: 0;
}
/* Metal weight tapers across the podium; 4th and below carry none at all. */
.pos-tile--1 { background: var(--metal-wash-18); font-weight: var(--font-weight-bold); color: var(--metal-strong); }
.pos-tile--2 { background: var(--metal-wash-10); font-weight: var(--font-weight-bold); color: var(--metal); }
.pos-tile--3 { background: var(--metal-wash-07); font-size: 14px; font-weight: var(--font-weight-bold); color: var(--metal-dim); }
.pos-tile--pending { color: var(--text-quiet); }

.board-player { display: flex; flex-direction: column; line-height: 1.3; min-width: 0; }
.board-player__name {
    font-size: 16px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.01em;
    color: var(--text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.board-row.is-pending .board-player__name {
    font-weight: var(--font-weight-medium);
    color: var(--text-muted);
}
.board-player__sub {
    font-size: 11.5px;
    color: var(--text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.board-row.is-pending .board-player__sub { color: var(--text-quiet); }
/* A player with no group, no movement, no moment and no tee time has nothing to say on the
   second line — collapse it rather than leaving the name floating half a line high. */
.board-player__sub:empty { display: none; }
/* Separators are CSS so any subset of group / movement / moment / tee time reads correctly. */
.board-player__sub > * + *::before { content: " · "; color: var(--text-quiet); }
.board-move.is-up { color: var(--color-accent); }
.board-move.is-down { color: var(--under-par); }
.board-moment { color: var(--color-accent); }
.board-moment.is-rare { color: var(--metal-strong); }

.board-last3 { display: flex; gap: 4px; }
.hole-tile {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    border-radius: 7px;
    font-size: 12px;
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
    flex-shrink: 0;
}
.hole-tile--under {
    background: color-mix(in srgb, var(--color-accent) 16%, transparent);
    color: color-mix(in srgb, var(--color-accent) 70%, var(--text));
    font-weight: var(--font-weight-bold);
}
.hole-tile--eagle {
    background: color-mix(in srgb, var(--color-accent) 28%, transparent);
    color: color-mix(in srgb, var(--color-accent) 40%, var(--text));
    font-weight: var(--font-weight-bold);
}
.hole-tile--par { background: var(--control-fill); color: color-mix(in srgb, var(--text) 88%, transparent); }
.hole-tile--over {
    background: color-mix(in srgb, var(--under-par) 14%, transparent);
    color: color-mix(in srgb, var(--under-par) 65%, var(--text));
}

.board-thru { font-size: 14px; color: var(--text-muted); font-variant-numeric: tabular-nums; }

.board-topar {
    font-size: 17px;
    font-weight: var(--font-weight-bold);
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.015em;
    color: var(--text-muted);
}
/* Under par is red, per the existing scorecard convention; even par is quiet, not green. */
.board-topar.under-par { color: var(--under-par); }
.board-topar.even-par {
    font-weight: var(--font-weight-semibold);
    color: color-mix(in srgb, var(--text) 88%, transparent);
}

/* Gross and Net are one cell each, carrying the exact score with the to-par figure beneath it.
   The board used to spend three columns — To par, Strokes, Net — on nearly the same fact, and
   still never printed the actual strokes a net score was. Only the to-par line takes a hue. */
.board-score {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    line-height: 1.15;
}
.board-score__fig {
    font-size: 17px;
    font-weight: var(--font-weight-bold);
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.015em;
    color: var(--text);
}
/* Net's figure is the quieter of the two — gross is the ranking. */
.board-score--net .board-score__fig {
    font-weight: var(--font-weight-semibold);
    color: color-mix(in srgb, var(--text) 88%, transparent);
}
.board-score__par {
    font-size: 11.5px;
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
    color: var(--text-muted);
}
/* Under par is red; even and over par stay quiet. The exact-strokes figure never takes a hue. */
.board-score__par.under-par { color: var(--under-par); }

.board-cell.col-day {
    font-size: 14px;
    font-variant-numeric: tabular-nums;
    color: var(--text);
}
.board-cell.col-day.under-par { color: var(--under-par); }

/* ── The cut (handoffs/design_handoff_leaderboard_cut) ───────────────────────────────────
   A tournament that cuts after day 2 used to take this board from twelve rows to six with
   nothing on the screen connecting the two. Three things say it now: a projected LINE drawn
   between the last qualifier and the first player outside it while the cut round is still to
   run, a collapsed BAND holding the eliminated field once it has, and a bubble chip on the last
   row still inside.

   ALL OF IT IS METAL. A cut is a standing — it is not money (--color-accent) and it is not
   under par (--under-par). The one accent on this screen is the purse, which is money. */

/* The line is a flex child of .board-card, not a row of its grid: it spans the card and its
   contents have nothing to line up with above or below. */
.cut-line {
    display: flex;
    align-items: center;
    gap: 10px;
    /* 9px is a deliberate sub-grid value — the line has to read as thinner than a player row
       (14px) while still clearing the dashed rules on both sides of it. */
    padding: 9px 20px;
    background: var(--metal-wash-07);
    /* Dashed, because this is a forecast. The band below is the same geometry with a solid
       border, and that is the whole visual difference between a projection and a fact. */
    border-top: 1px dashed var(--metal-line);
    border-bottom: 1px dashed var(--metal-line);
}
.cut-line__glyph { flex: none; font-size: 15px; color: var(--metal); }
.cut-line__label {
    flex: none;
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--metal);
    white-space: nowrap;
}
.cut-line__rule,
.cut-band__rule {
    flex: none;
    width: 1px;
    height: 12px;
    background: var(--metal-line);
}
.cut-line__text {
    min-width: 0;
    font-size: 12px;
    font-variant-numeric: tabular-nums;
    color: var(--text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.cut-line__count {
    margin-left: auto;
    flex: none;
    font-size: 11px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

/* The last player still inside the line. */
.cut-bubble {
    display: inline-flex;
    align-items: center;
    margin-left: 6px;
    padding: 2px 7px;
    border-radius: var(--radius-pill);
    background: var(--metal-wash-18);
    border: 1px solid var(--metal-edge);
    font-size: 9.5px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--metal-strong);
    vertical-align: middle;
}
/* "needs 6 shots to make the cut" — quiet, and rendered only inside ten strokes of the line.
   A row fifteen back is not playing to a number. */
.board-needs { color: var(--text-quiet); }

/* The band: the line's geometry promoted to a control, and the LAST child of the card so the
   eliminated rows appear beneath it inside the same board. */
.cut-band {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 13px 20px;
    background: var(--metal-wash-07);
    border: none;
    border-top: 1px solid var(--metal-line);
    font-family: inherit;
    text-align: left;
    cursor: pointer;
}
.cut-band:hover { background: var(--metal-wash-10); }
.cut-band:focus-visible { outline: 2px solid var(--metal); outline-offset: -2px; }
.cut-band__glyph { flex: none; font-size: 16px; color: var(--metal); }
.cut-band__label {
    flex: none;
    font-size: 10.5px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--metal);
    white-space: nowrap;
}
.cut-band__text {
    min-width: 0;
    font-size: 12.5px;
    color: var(--text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.cut-band__toggle {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    margin-left: auto;
    flex: none;
    font-size: 12px;
    font-weight: var(--font-weight-semibold);
    color: var(--metal-strong);
}
.cut-band__toggle .material-symbols-outlined { font-size: 18px; }

/* An eliminated row reuses the row grid with muted values. It carries no .pos-tile and no
   data-pos, so it can never take the leader wash or a podium weight — they hold no position in
   the tournament any more. */
.board-row--cut { padding: 12px 20px; }
.board-cut-dash { font-size: 14.5px; color: var(--ink-disabled); }
.board-row--cut .board-player__name {
    font-size: 15px;
    font-weight: var(--font-weight-medium);
    color: var(--text-muted);
}
.board-row--cut .board-player__sub { font-size: 11px; color: var(--text-quiet); }
.board-row--cut .board-cell.col-day { font-size: 13.5px; color: var(--text-muted); }
.board-row--cut .board-score__fig {
    font-size: 15px;
    font-weight: var(--font-weight-semibold);
    color: var(--text-muted);
}
/* The to-par line LOSES ITS HUE here. An eliminated player's score is a record, not a standing,
   and red on it would say they are still chasing something. */
.board-row--cut .board-score__par,
.board-row--cut .board-score__par.under-par,
.board-row--cut .board-score__par.even-par {
    font-size: 11px;
    font-weight: var(--font-weight-semibold);
    color: var(--text-quiet);
}

/* ── The purse ───────────────────────────────────────────────────────────────────────────
   Green, because accent means money — the one hue on this block that isn't metal. An unpaid row
   is an em dash, NEVER $0.00: the second is a payout of nothing, the first is no payout. */
.board-purse {
    font-size: 15px;
    font-weight: var(--font-weight-bold);
    font-variant-numeric: tabular-nums;
    color: color-mix(in srgb, var(--color-accent) 74%, var(--text));
}
.board-purse .board-dash { font-weight: var(--font-weight-semibold); color: var(--ink-disabled); }
.board-head .board-purse {
    font-size: 10.5px;
    font-weight: var(--font-weight-bold);
    color: var(--text-quiet);
}

.board-final { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; }
.board-purse-chip {
    display: inline-flex;
    align-items: baseline;
    gap: var(--space-2);
    padding: 7px 13px;
    border-radius: 9px;
    background: color-mix(in srgb, var(--color-accent) 10%, transparent);
    border: 1px solid color-mix(in srgb, var(--color-accent) 26%, transparent);
}
.board-purse-chip__label {
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: color-mix(in srgb, var(--color-accent) 74%, var(--text));
}
.board-purse-chip__fig {
    font-size: 15px;
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
    color: color-mix(in srgb, var(--color-accent) 74%, var(--text));
}
.board-purse-chip__detail { font-size: 12px; color: var(--text-muted); }

/* ── The phone board's two-line player cell (design 2g) ──────────────────────────────────
   All four pieces are in the DOM at every width and each hides in its own media query — the
   call the players roster and the Wagers pane both make, and the same consequence: a test has
   to say which drawing it means. */
.board-player__line { display: flex; align-items: baseline; gap: 6px; min-width: 0; }
.board-player__trail { display: none; }
.board-rounds { display: none; }
.board-hd-narrow { display: none; }
.cut-narrow { display: none; }

/* One tile per round, in day order. Deliberately the per-week board's .hole-tile vocabulary
   re-pointed at rounds rather than a second tile system. */
.rd-tile {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 28px;
    height: 20px;
    padding: 0 5px;
    border-radius: 6px;
    background: var(--control-fill);
    font-size: 11.5px;
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
    color: var(--text);
    flex: none;
}
/* The round in play shows its RUNNING to-par instead of a stroke total, and takes the metal
   treatment — which round you are in the middle of is a standing. */
.rd-tile--live {
    background: var(--metal-wash-10);
    border: 1px solid var(--metal-line);
    font-weight: var(--font-weight-bold);
    color: var(--metal-strong);
}
/* A round this player didn't play — a post-cut round, or a late joiner. */
.rd-tile--none { color: var(--ink-disabled); }

/* ── The expanded player scorecard ("Ledger") ────────────────────────────────────────────
   A plain block sibling of the row, so it spans the card without being part of any row's grid.
   It is styled as PART of the board rather than a panel dropped inside it: a champagne-metal
   rule opens it and it sits on the open row's wash at half strength. No inner card, no second
   background colour, no radius, no shadow.

   Everything below is prefixed .psc-* and used only by LeaderboardPage. The older .scorecard* /
   .player-detail* / .close-button rules are deliberately left alone — ScrambleResultsView and
   ScoreEntry still render those, and this refresh is scoped to the leaderboard route.

   Source: design_handoff_scorecard/ (turn 1c, plus 2a/2b/2c for the empty card + stroke dots). */
.board-detail {
    background: var(--metal-wash-05);
    border-top: 1px solid var(--metal-edge);
    border-bottom: 1px solid var(--hairline-soft);
    padding: 18px 20px 20px;
    cursor: default;
}

/* Header: eyebrow · hairline · name · handicap line, then the tabs and close at the right.
   The 70px initials disc that used to lead this row is gone — the name is the row you clicked. */
.psc-head {
    display: flex;
    align-items: center;
    gap: 12px;
}

.psc-eyebrow {
    flex-shrink: 0;
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--metal);
}

.psc-rule {
    flex: 0 0 auto;
    width: 1px;
    height: 12px;
    background: var(--hairline);
}

.psc-rule--metal { background: var(--metal-line); }

/* flex-shrink:0 + nowrap is load-bearing: the name is otherwise the only shrinkable item in a
   nowrap row and collapses to min-content, wrapping out of its box onto the course line. */
.psc-name {
    flex-shrink: 0;
    white-space: nowrap;
    font-size: 19px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.02em;
    color: var(--text);
}

/* This is the item that gives way when the row runs out of room. */
.psc-hcp {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 11.5px;
    font-variant-numeric: tabular-nums;
    color: var(--text-muted);
}

/* Tabs: a metal-underlined micro row. The inactive bar is present but transparent, so nothing
   shifts on selection. Replaces .sub-nav, whose 4px --gray-300 baseline and --navy active
   segment were both invisible on the dark ground. */
.psc-tabs {
    margin-left: auto;
    display: flex;
    align-items: flex-end;
    gap: 18px;
    flex-shrink: 0;
}

.psc-tab {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 5px;
    padding: 0;
    border: 0;
    background: none;
    cursor: pointer;
    font-family: inherit;
    font-size: 12.5px;
    font-weight: var(--font-weight-medium);
    color: var(--text-muted);
}

.psc-tab__bar {
    width: 100%;
    height: 2px;
    border-radius: 2px;
    background: transparent;
}

.psc-tab.is-active {
    font-weight: var(--font-weight-semibold);
    color: var(--metal-strong);
}

.psc-tab.is-active .psc-tab__bar { background: var(--metal); }
.psc-tab:hover { color: var(--text); }
.psc-tab:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 3px; border-radius: 4px; }

.psc-close {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    margin-left: 6px;
    padding: 0;
    border: 0;
    border-radius: 8px;
    background: none;
    color: var(--text-quiet);
    cursor: pointer;
}

.psc-close .material-symbols-outlined { font-size: 18px; line-height: 1; }
.psc-close:hover { background: var(--control-fill); color: var(--text-muted); }
.psc-close:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; }

/* Course / tee / yardage / rating / slope. Middots replaced by hairline rules. */
.psc-course {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 9px;
    margin: 12px 0 14px;
    font-size: 12px;
    color: var(--text-muted);
}

.psc-course > span {
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

.psc-course__name {
    font-size: 12.5px;
    font-weight: var(--font-weight-semibold);
    color: var(--text);
}

/* What makes the stroke dots legible to a player who has never noticed them. */
.psc-strokes-chip {
    margin-left: auto;
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 4px 9px;
    border-radius: 8px;
    background: var(--control-fill);
    font-size: 11px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.psc-strokes-chip__dot {
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background: var(--stroke-dot);
}

.psc-strokes-chip--giving .psc-strokes-chip__dot { background: var(--under-par); }

/* ── The grid ────────────────────────────────────────────────────────────────────────────
   A CSS grid rather than a <table>: it needs no <td> padding to hit the drawn row heights, and
   a fixed-height cell is what lets the stroke dots anchor to the cell instead of the row.
   Every column the table had is still here — 1–9 / Out / 10–18 / In / Tot. */
.psc-grid {
    font-variant-numeric: tabular-nums;
}

/* Desktop: the 18-hole card. Phone stacks two nines (below). */
.psc-grid--18 {
    --psc-cols: 56px repeat(9, 1fr) 42px repeat(9, 1fr) 42px 48px;
    border-top: 1px solid var(--metal-edge);
}

.psc-grid--9 { display: none; }

.psc-row {
    display: grid;
    grid-template-columns: var(--psc-cols);
    align-items: stretch;
    text-align: center;
}

.psc-cell {
    position: relative;
    min-width: 0;
    display: flex;
    align-items: center;
    justify-content: center;
}

.psc-lab {
    justify-content: flex-start;
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

/* Out / In / Tot are separated by vertical metal hairlines, not grey blocks. Out takes both
   edges because it sits between the two nines. */
.psc-sum { border-left: 1px solid var(--metal-edge); }
.psc-sum--out { border-right: 1px solid var(--metal-edge); }

.psc-dash { color: var(--ink-disabled); }

.psc-row--head {
    height: 32px;
    border-bottom: 1px solid var(--hairline-soft);
    font-size: 10.5px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.08em;
    color: var(--text-quiet);
}

.psc-row--head .psc-sum { color: var(--metal); }

.psc-row--par {
    height: 30px;
    border-bottom: 1px solid var(--hairline-soft);
    font-size: 12.5px;
    color: var(--text-muted);
}

.psc-row--par .psc-sum {
    font-weight: var(--font-weight-semibold);
    color: var(--metal);
}

.psc-row--hcp {
    height: 28px;
    border-bottom: 1px solid var(--hairline-soft);
    font-size: 11px;
    color: var(--text-quiet);
}

.psc-row--gross {
    height: 54px;
    font-size: 15px;
    font-weight: var(--font-weight-semibold);
    color: var(--text);
}

.psc-row--gross .psc-lab { color: color-mix(in srgb, var(--text) 88%, transparent); }

.psc-row--gross .psc-sum {
    font-weight: var(--font-weight-bold);
    color: var(--metal-strong);
}

/* No italics: slanted tabular figures are the other thing that dated this table. The net row
   also carries no score marks — at 38px a 30px ring would collide with the gross row above,
   and this line is a quiet reference to the row that does carry them. */
.psc-row--net {
    height: 38px;
    border-top: 1px solid var(--hairline-soft);
    font-size: 13px;
    color: var(--text-muted);
}

.psc-row--net .psc-sum {
    font-weight: var(--font-weight-semibold);
    color: var(--metal);
}

/* ── Score marks: hairline rings, not fills ──────────────────────────────────────────────
   Same convention as before — under par is red, over par is neutral, eagle+ and double+ double
   the ring — but the numeral keeps its own ink instead of being inverted onto a solid. They are
   inline-flex boxes with a box-shadow rather than absolutely-positioned pseudo-elements, which
   is what lets a stroke dot share the cell without being covered. */
.psc-mark {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: 6px;
    /* The box centres a LINE box, which carries descender space — so every numeral sat ~2px low
       inside its own ring. Affects bogey, birdie, eagle and double alike. */
    line-height: 1;
    box-shadow: inset 0 0 0 1.5px var(--mark-ring);
    color: var(--text);
}

/* Two lines INSIDE the box rather than a ring outside it. The outer ring sat at --mark-ring-outer
   (12% ink, 3px out) and read as a soft shadow rather than a second line, which made a double
   hard to tell apart from a bogey at a glance. The footprint is unchanged — 28px, sharing a 1fr
   hole column with a stroke dot — and the insets leave 22.5px of clear inner box for the numeral.
   The middle ring is the detail's own ground and must stay OPAQUE (see --psc-ground). */
.psc-mark--double {
    font-weight: var(--font-weight-bold);
    box-shadow: inset 0 0 0 1.25px var(--mark-ring),
                inset 0 0 0 2.5px var(--psc-ground),
                inset 0 0 0 3.75px var(--mark-ring);
}

.psc-mark--birdie,
.psc-mark--eagle {
    width: 30px;
    height: 30px;
    border-radius: 50%;
    box-shadow: inset 0 0 0 1.5px var(--under-par);
    color: var(--mark-under-ink);
    font-weight: var(--font-weight-bold);
}

.psc-mark--eagle {
    box-shadow: inset 0 0 0 1.5px var(--under-par),
                0 0 0 2.5px color-mix(in srgb, var(--under-par) 35%, transparent);
}

/* ── Legend + stat rail ──────────────────────────────────────────────────────────────────
   The four --gray-100 stat cards become one baseline-aligned rail, mirroring the masthead's
   Leading/Pot rail. The legend (or, on an unplayed card, the tee-off note) shares its row. */
.psc-foot {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 20px;
    margin-top: 16px;
    padding-top: 14px;
    border-top: 1px solid var(--hairline-soft);
}

.psc-legend {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 16px;
    font-size: 11.5px;
    color: var(--text-muted);
}

.psc-legend__item {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    white-space: nowrap;
}

.psc-swatch {
    flex: 0 0 auto;
    width: 14px;
    height: 14px;
    border-radius: 4px;
    box-shadow: inset 0 0 0 1.5px var(--mark-ring);
}

.psc-swatch--double {
    box-shadow: inset 0 0 0 1.25px var(--mark-ring),
                inset 0 0 0 2.5px var(--psc-ground),
                inset 0 0 0 3.75px var(--mark-ring);
}

.psc-swatch--birdie,
.psc-swatch--eagle {
    width: 15px;
    height: 15px;
    border-radius: 50%;
    box-shadow: inset 0 0 0 1.5px var(--under-par);
}

.psc-swatch--eagle {
    box-shadow: inset 0 0 0 1.5px var(--under-par),
                0 0 0 2.5px color-mix(in srgb, var(--under-par) 35%, transparent);
}

.psc-note {
    font-size: 12.5px;
    color: var(--text-muted);
}

.psc-note strong {
    font-weight: var(--font-weight-semibold);
    color: var(--text);
}

.psc-rail {
    margin-left: auto;
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 9px;
}

.psc-rail__label {
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

/* The first label is the metal one — position is standing, and standing is what metal means. */
.psc-rail__label--lead { color: var(--metal); }

.psc-rail__fig {
    font-size: 18px;
    font-weight: var(--font-weight-bold);
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.02em;
    color: var(--text-muted);
}

.psc-rail__fig--pos { color: var(--text); }
/* Pre-round: every figure is an em dash, and a dash is not a value — it goes disabled-quiet. */
.psc-rail__fig--empty { color: var(--ink-disabled); }
.psc-rail__fig.under-par { color: var(--under-par); }
.psc-rail__fig .arrow.up { color: var(--color-accent); }
.psc-rail__fig .arrow.down { color: var(--under-par); }

.psc-rail__sep {
    align-self: center;
    width: 1px;
    height: 16px;
    margin: 0 7px;
    background: var(--hairline);
}

/* ── Stats & Highlights tabs ─────────────────────────────────────────────────────────────
   Same vocabulary as the scorecard tab: hairline rules instead of table chrome, metal for
   standing, the same ring marks for the score categories, no inner cards and no grey slabs.
   Source: design_handoff_tabs/ (frames 3a–3d). */

/* The row under the header carrying the course line (Stats) or the summary rail (Highlights),
   with the round pills pushed to its right edge. */
.psc-toprow {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 9px;
    margin-top: 12px;
    font-size: 12px;
    color: var(--text-muted);
}

.psc-toprow--rail { align-items: flex-end; }
.psc-toprow > span { white-space: nowrap; font-variant-numeric: tabular-nums; }
.psc-pills { margin-left: auto; }

/* The pills keep their component; only their skin changes, and it changes for all three tabs
   so the control doesn't read as two different things depending which one you're on. Scoped
   to .board-detail — .round-pills also builds the per-week chips on eight other tabs, where
   the navy active pill is still the right answer. */
.board-detail .round-pills { margin: 12px 0 0; }
.psc-pills .round-pills { margin: 0; }
.board-detail .round-pills ul { gap: 6px; }

.board-detail .round-pills li {
    display: inline-flex;
    align-items: center;
    height: 24px;
    padding: 0 11px;
    border: 0;
    border-radius: var(--radius-pill);
    background: none;
    font-size: 11.5px;
    font-weight: var(--font-weight-medium);
    color: var(--text-muted);
}

.board-detail .round-pills li.active {
    background: var(--metal-wash-10);
    box-shadow: inset 0 0 0 1px var(--metal-line);
    font-weight: var(--font-weight-semibold);
    color: var(--metal-strong);
}

.board-detail .round-pills li:hover:not(.active) {
    background: var(--control-fill);
    color: var(--text);
}

/* Stacked variant of the rail: label over figure. The scorecard tab's rail runs them inline
   because it shares a line with the legend; here the rail owns its row, which is what every
   drawn frame stacks. Same tokens, same separators, same order either way. */
.psc-rail--stacked {
    align-items: flex-end;
    gap: 0;
}

.psc-rail__cell {
    display: flex;
    flex-direction: column;
    gap: 5px;
}

.psc-rail--stacked .psc-rail__sep {
    align-self: flex-end;
    margin: 0 7px 3px;
}

/* Highlights puts its rail at the left of the row and the pills at the right. */
.psc-rail--lead { margin-left: 0; }

/* Stats' standing rail owns a row of its own, on a hairline rule. It is its own block here
   rather than a flex item, so margin-left:auto can't right-align it — justify-content does. */
.psc-rail--section {
    justify-content: flex-end;
    margin-top: 16px;
    padding-top: 14px;
    border-top: 1px solid var(--hairline-soft);
}

.psc-sec {
    margin-top: 18px;
    padding-top: 14px;
    border-top: 1px solid var(--hairline-soft);
}

/* The scoring spread opens on metal, the way the scorecard grid does. */
.psc-sec--metal { border-top-color: var(--metal-edge); }

.psc-sec__head {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 9px;
    margin-bottom: 12px;
}

.psc-sec__label {
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--metal);
}

.psc-sec__note {
    font-size: 11.5px;
    color: var(--text-quiet);
}

/* Five categories as five columns, each headed by the same ring the scorecard draws for it.
   That mark is the point of the section: it ties the count back to the card. */
.psc-spread { display: grid; grid-template-columns: repeat(5, 1fr); }

.psc-spread__col {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 9px;
    padding: 0 10px;
    min-width: 0;
}

.psc-spread__col + .psc-spread__col { border-left: 1px solid var(--hairline-soft); }

.psc-spread .psc-mark {
    width: 25px;
    height: 25px;
    font-size: 11px;
    font-weight: var(--font-weight-semibold);
}

.psc-spread .psc-mark--birdie,
.psc-spread .psc-mark--eagle {
    width: 26px;
    height: 26px;
    font-weight: var(--font-weight-bold);
}

/* Par draws no mark on the scorecard, so it draws none here — but it keeps the box, or the
   five baselines under it stop lining up. */
.psc-spread__par {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    font-size: 11px;
    font-weight: var(--font-weight-semibold);
    color: var(--text-quiet);
}

.psc-spread__count {
    font-size: 24px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.02em;
    font-variant-numeric: tabular-nums;
    color: var(--text);
}

.psc-spread__count--zero { color: var(--text-quiet); }

.psc-spread__label {
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-quiet);
    white-space: nowrap;
}

/* Decoration for the count, not a second data channel — no ticks, no labels, no percentage. */
.psc-meter {
    width: 100%;
    height: 2px;
    border-radius: 2px;
    background: var(--hairline);
    overflow: hidden;
}

.psc-meter__fill {
    display: block;
    height: 100%;
    border-radius: 2px;
    background: var(--mark-ring);
}

.psc-meter__fill--under { background: var(--under-par); }
/* The stroke-dot neutral, pulled back: at full strength light mode's #333 makes the pars bar
   the loudest thing in the row, which inverts the point — red is what should stand out. */
.psc-meter__fill--par { background: color-mix(in srgb, var(--stroke-dot) 70%, transparent); }

/* Four baseline cells. grid-auto-flow, so dropping Front/back (which is per-round only) leaves
   three even columns rather than a hole where the fourth was. */
.psc-perf {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
}

.psc-perf__cell {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 0 16px;
    min-width: 0;
}

.psc-perf__cell:first-child { padding-left: 0; }
.psc-perf__cell:last-child { padding-right: 0; }
.psc-perf__cell + .psc-perf__cell { border-left: 1px solid var(--hairline-soft); }

.psc-perf__label {
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

.psc-perf__fig {
    font-size: 20px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.02em;
    font-variant-numeric: tabular-nums;
    color: var(--text);
}

.psc-perf__suffix {
    font-size: 12px;
    font-weight: var(--font-weight-medium);
    letter-spacing: 0;
    color: var(--text-quiet);
}

/* ── Highlights ledger ───────────────────────────────────────────────────────────────── */
.psc-ledger {
    margin-top: 16px;
    border-top: 1px solid var(--metal-edge);
}

.psc-group {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 12px 0 8px;
}

.psc-hl + .psc-group { padding-top: 16px; }

.psc-group__label {
    flex-shrink: 0;
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--metal);
}

.psc-group__meta {
    font-size: 11.5px;
    font-variant-numeric: tabular-nums;
    color: var(--text-quiet);
}

.psc-group__rule {
    flex: 1;
    height: 1px;
    background: var(--hairline-soft);
}

/* Not interactive — no hover affordance, deliberately. */
.psc-hl {
    display: grid;
    grid-template-columns: 44px 1fr auto;
    align-items: center;
    gap: 14px;
    padding: 11px 4px;
    border-bottom: 1px solid var(--hairline-soft);
}

.psc-hl:last-child { border-bottom: none; }

.psc-ledger .psc-mark {
    width: 34px;
    height: 34px;
    font-size: 14.5px;
}

.psc-hl__body {
    display: flex;
    flex-direction: column;
    gap: 3px;
    min-width: 0;
}

.psc-hl__title {
    font-size: 14.5px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.01em;
    color: var(--text);
}

.psc-hl__meta {
    font-size: 11.5px;
    font-variant-numeric: tabular-nums;
    color: var(--text-quiet);
}

.psc-hl__topar {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 3px;
}

.psc-hl__fig {
    font-size: 15px;
    font-weight: var(--font-weight-bold);
    font-variant-numeric: tabular-nums;
    color: var(--under-par);
}

.psc-hl__caption {
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

/* Empty state — the same hairline-ring shape as the marks, so it reads as part of the family
   rather than as a line of grey text where a list should be. */
.psc-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    padding: 22px 0;
    text-align: center;
}

.psc-empty__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    border-radius: 50%;
    box-shadow: inset 0 0 0 1.5px var(--hairline);
    color: var(--text-quiet);
}

.psc-empty__icon .material-symbols-outlined { font-size: 18px; line-height: 1; }

.psc-empty__title {
    font-size: 13.5px;
    font-weight: var(--font-weight-semibold);
    color: var(--text-muted);
}

.psc-empty__note {
    font-size: 11.5px;
    color: var(--text-quiet);
}

/* Labels that abbreviate at 390px. Both are in the DOM; the breakpoint picks one. */
.psc-narrow { display: none; }

/* ── Phone (≤768px): two stacked nines on ONE column template ────────────────────────────
   Both nines share the template so hole 9 sits directly above hole 18 and Out sits above In;
   the front nine carries a trailing empty cell where the back nine has Tot. */
@media (max-width: 768px) {
    .board-detail { padding: 14px; }

    .psc-head { flex-wrap: wrap; gap: 9px; }
    .psc-eyebrow { font-size: 9.5px; }
    .psc-rule--metal { height: 11px; }
    .psc-name { font-size: 16.5px; }
    /* Three lines at 390px: name (with close), then the handicap line, then the tab row. */
    .psc-close { order: 1; margin-left: auto; }
    .psc-hcp {
        order: 2;
        flex-basis: 100%;
        margin-top: -5px;
    }
    .psc-tabs {
        order: 3;
        flex-basis: 100%;
        margin: 1px 0 0;
        border-bottom: 1px solid var(--hairline-soft);
    }
    .psc-tab { gap: 6px; }

    /* Today's mobile rule, kept: no rules, name on its own line, flex gap separates. */
    .psc-course {
        gap: 4px 10px;
        margin: 10px 0;
        font-size: 11px;
    }
    .psc-course .psc-rule { display: none; }
    .psc-course__name {
        flex-basis: 100%;
        font-size: 11.5px;
    }
    .psc-strokes-chip {
        margin-left: 0;
        padding: 0;
        gap: 6px;
        background: none;
        font-size: 11px;
        font-weight: var(--font-weight-base);
        letter-spacing: normal;
        text-transform: none;
    }
    .psc-strokes-chip__dot { width: 4px; height: 4px; }

    .psc-grid--18 { display: none; }
    .psc-grid--9 {
        display: block;
        --psc-cols: 28px repeat(9, 1fr) 28px 30px;
    }
    .psc-nine { border-top: 1px solid var(--metal-edge); }
    .psc-nine--back { margin-top: 10px; }

    .psc-lab {
        font-size: 9px;
        letter-spacing: 0.08em;
    }
    .psc-row--head { height: 26px; font-size: 9.5px; letter-spacing: normal; }
    .psc-row--par { height: 26px; font-size: 11px; }
    .psc-row--hcp { height: 24px; font-size: 10px; }
    .psc-row--gross { height: 44px; font-size: 13.5px; }
    .psc-row--net { height: 32px; font-size: 12px; }

    /* ~27px hole columns: marks cap at 22/20px or neighbours read as crammed. */
    .psc-mark { width: 20px; height: 20px; border-radius: 5px; }
    .psc-mark--double {
        box-shadow: inset 0 0 0 1px var(--mark-ring),
                    inset 0 0 0 2px var(--psc-ground),
                    inset 0 0 0 3px var(--mark-ring);
        font-size: 12px;
    }
    /* border-radius has to be restated: the .psc-mark rule above sets 5px and lands later in the
       sheet than the base circle, so without this a phone draws every birdie as a square. */
    .psc-mark--birdie,
    .psc-mark--eagle { width: 22px; height: 22px; border-radius: 50%; }

    .psc-foot { gap: 12px; margin-top: 12px; padding-top: 11px; }
    .psc-legend { gap: 10px; font-size: 11px; }
    .psc-note { font-size: 11.5px; }
    .psc-rail { gap: 8px; }
    .psc-rail__label { font-size: 9.5px; }
    .psc-rail__fig { font-size: 16px; }
    .psc-rail__sep { height: 14px; margin: 0 5px; }

    /* ── Stats & Highlights at 390px ─────────────────────────────────────────────────── */
    .psc-toprow { gap: 6px 9px; margin-top: 10px; font-size: 11px; }
    .psc-toprow .psc-course__name { flex-basis: 100%; font-size: 11.5px; }
    .psc-toprow .psc-rule { display: none; }
    .psc-pills { margin-left: 0; flex-basis: 100%; }
    .board-detail .round-pills { margin-top: 10px; }

    /* Stats' standing rail becomes a 2×2 tile grid — a baseline rail does not fit 390px. */
    .psc-rail--section {
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: 8px;
        margin-top: 12px;
        padding-top: 0;
        border-top: 0;
    }
    .psc-rail--section .psc-rail__cell {
        gap: 3px;
        padding: 9px 11px;
        border-radius: 10px;
        background: var(--control-fill);
    }
    .psc-rail--section .psc-rail__sep { display: none; }
    .psc-rail--section .psc-rail__label { font-size: 9.5px; letter-spacing: 0.1em; }
    .psc-rail--section .psc-rail__fig { font-size: 17px; }

    .psc-sec { margin-top: 14px; padding-top: 12px; }
    .psc-sec__head { margin-bottom: 10px; }

    /* All five columns stay — the shape of a round is the point. The meters go: at ~66px a
       2px bar is noise, not information. */
    .psc-spread__col { gap: 7px; padding: 0; }
    .psc-spread .psc-mark {
        width: 19px;
        height: 19px;
        border-radius: 5px;
        font-size: 9.5px;
        box-shadow: inset 0 0 0 1.25px var(--mark-ring);
    }
    .psc-spread .psc-mark--double {
        box-shadow: inset 0 0 0 1.25px var(--mark-ring),
                    inset 0 0 0 2.5px var(--psc-ground),
                    inset 0 0 0 3.75px var(--mark-ring);
    }
    .psc-spread .psc-mark--birdie,
    .psc-spread .psc-mark--eagle {
        width: 20px;
        height: 20px;
        border-radius: 50%;
        box-shadow: inset 0 0 0 1.25px var(--under-par);
    }
    .psc-spread .psc-mark--eagle {
        box-shadow: inset 0 0 0 1.25px var(--under-par),
                    0 0 0 2px color-mix(in srgb, var(--under-par) 35%, transparent);
    }
    .psc-spread__par { width: 20px; height: 20px; font-size: 9.5px; }
    .psc-spread__count { font-size: 17px; }
    .psc-spread__label { font-size: 8.5px; letter-spacing: 0.06em; }
    .psc-meter { display: none; }
    .psc-wide { display: none; }
    .psc-narrow { display: inline; }

    .psc-perf {
        grid-auto-flow: row;
        grid-template-columns: 1fr 1fr;
        gap: 10px 8px;
    }
    .psc-perf__cell {
        gap: 3px;
        padding: 0;
        border-left: 0;
    }
    .psc-perf__cell + .psc-perf__cell { border-left: 0; }
    .psc-perf__label { font-size: 9.5px; }
    .psc-perf__fig { font-size: 16px; }
    .psc-perf__suffix { font-size: 11px; }

    .psc-ledger { margin-top: 12px; }
    .psc-group { gap: 8px; padding: 10px 0 6px; }
    .psc-hl + .psc-group { padding-top: 14px; }
    .psc-group__meta { font-size: 11px; }
    .psc-hl {
        grid-template-columns: 34px 1fr auto;
        gap: 11px;
        padding: 9px 2px;
    }
    .psc-ledger .psc-mark {
        width: 28px;
        height: 28px;
        border-radius: 50%;
        font-size: 13px;
        box-shadow: inset 0 0 0 1.25px var(--under-par);
    }
    .psc-ledger .psc-mark--eagle {
        box-shadow: inset 0 0 0 1.25px var(--under-par),
                    0 0 0 2px color-mix(in srgb, var(--under-par) 35%, transparent);
    }
    .psc-hl__body { gap: 2px; }
    .psc-hl__title { font-size: 13.5px; }
    .psc-hl__meta { font-size: 11px; }
    .psc-hl__fig { font-size: 14px; }
    .psc-hl__caption { display: none; }
}

/* Between 769px and ~1000px the widest optional column goes first. */
@media (max-width: 1000px) {
    .board-head,
    .board-row { grid-template-columns: var(--board-cols-md); }
    .board--week .col-last3 { display: none; }
}

/* ── Phone (≤768px) ─────────────────────────────────────────────────────────────────────── */
@media (max-width: 768px) {
    .masthead__inner { padding: 0 var(--space-4); }
    .mh-utility { height: 48px; gap: 9px; }
    .mh-brand img { width: 22px; height: 22px; border-radius: 6px; }
    /* The wordmark and the chevron go; the event-type label alone carries the context. */
    .mh-wordmark,
    .mh-utility-sep { display: none; }
    .mh-eventtype { font-size: 10px; letter-spacing: 0.13em; }
    .mh-weather { padding: 0; background: none; border-color: transparent; font-size: 11.5px; gap: 6px; }
    .mh-weather__glyph { font-size: 15px; }
    .mh-weather__full { display: none; }
    .mh-weather__temp { display: inline; }
    /* The open state keeps its wash but re-earns the padding it just gave up, or the wash would
       be drawn tight against the glyph. */
    .mh-weather.is-open { padding: 4px 8px; border-color: var(--metal-edge); }
    /* The placeholder matches what the phone actually shows: the temperature alone, not the
       condition + wind line. A 104px bar here would reserve room nothing arrives to fill. */
    .mh-weather__bar { width: 40px; height: 8px; }
    .mh-avatar { width: 30px; height: 30px; font-size: 11px; }

    .mh-title-block { gap: 11px; padding: 6px 0 14px; }
    .mh-title { font-size: 27px; line-height: 1.08; }
    /* ONE row, no wrap: the pill and the course, and that is the whole meta line at 390px. */
    .mh-meta { gap: var(--space-2); flex-wrap: nowrap; }
    .mh-meta__course { font-size: 11.5px; }
    /* Date + field size are desktop-only at 390px — and its divider goes with it. */
    .mh-meta__sub,
    .mh-hairline--sub { display: none; }
    .mh-livepill { padding: 2px var(--space-2); }
    .mh-livepill__dot { width: 5px; height: 5px; }
    .mh-livepill__text { font-size: 10px; letter-spacing: 0.06em; }
    .mh-livepill--picker { height: 32px; padding: 0 9px 0 11px; gap: 7px; }
    .mh-livepill--picker .mh-livepill__text { font-size: 11px; }
    .mh-livepill--picker .mh-livepill__dot { width: 6px; height: 6px; }
    .mh-livepill__caret { font-size: 17px; }

    /* The edge is the stat rail alone now, so there is nothing to split — it keeps its own rule
       and padding and the wrapper adds none. */
    .mh-edge { display: block; padding-bottom: 0; }
    .mh-stats {
        margin-left: 0;
        padding: 9px 0 11px;
        border-top: 1px solid var(--hairline-soft);
        gap: var(--space-2);
        /* Line 2 of the split edge is its own row; both halves sit on one line, so baseline the
           pot against the ticker box's own centred group rather than stretching. */
        align-items: center;
    }
    .mh-stat--pot { margin-left: auto; }
    .mh-hairline--stat { display: none; }
    .mh-stat__label { font-size: 9.5px; }
    .mh-ticker { --mh-tick-h: 20px; }
    .mh-ticker__name { font-size: 13.5px; }
    .mh-ticker__score { font-size: 17px; }
    .mh-ticker__thru { display: none; }
    .mh-stat__pot { font-size: 15px; }
    .mh-stat__pot-full { display: none; }
    .mh-stat__pot-short { display: inline; }

    /* Board: POS / PLAYER / THRU / GROSS / NET. Last 3 holes is dropped — it's one tap away in
       the player detail, and the two score cells are what people check from a cart. */
    .board-head,
    .board-row { grid-template-columns: var(--board-cols-sm); column-gap: var(--space-2); }
    .board-head { padding: 9px 14px; font-size: 10px; letter-spacing: 0.09em; }
    .board-row { padding: 12px 14px; }
    /* .col-strokes survives the players board losing its Strokes column: the TEAMS board still
       uses it for the best-ball column its --board-cols-sm drops. Grep before deleting it. */
    .col-last3,
    .col-strokes { display: none; }
    .board--cumulative .col-day { display: none; }
    .pos-tile { width: 26px; height: 26px; font-size: 13px; }
    .pos-tile--3 { font-size: 12.5px; }
    .board-player__name { font-size: 14.5px; }
    .board-player__sub { font-size: 10.5px; }
    .board-thru { font-size: 12.5px; }
    .board-topar { font-size: 15px; }
    .board-score__fig { font-size: 15px; }
    .board-score__par { font-size: 10.5px; }
    .board-detail { padding: 0 14px var(--space-3); }

    /* ── The cumulative board at 390px (design 2g) ────────────────────────────────────────
       The R# columns are hidden here, which used to leave "272" alone in the right-hand cell
       reading like a single round's score. The three tracks stay; what the middle and right
       ones hold changes. */
    .board-hd-wide { display: none; }
    .board-hd-narrow { display: inline; }

    /* Middle track: name + ONE trailing item on line 1, a tile per round on line 2. */
    .board--cumulative .board-row { padding: 11px 14px; }
    .board--cumulative .board-player { gap: 5px; }
    .board--cumulative .board-player__trail {
        display: inline;
        flex: none;
        font-size: 10.5px;
        color: var(--text-muted);
    }
    /* The purse is the one trailing item that is money, so it is the one that takes accent. */
    .board--cumulative .board-player__trail.is-money {
        font-size: 11px;
        font-weight: var(--font-weight-bold);
        font-variant-numeric: tabular-nums;
        color: color-mix(in srgb, var(--color-accent) 74%, var(--text));
    }
    .board--cumulative .board-player__sub { display: none; }
    .board--cumulative .board-rounds { display: flex; gap: 4px; }

    /* Right track becomes TO PAR. The exact total isn't lost — it is the first figure of the
       expanded scorecard this row already opens. The pending row's em dash has to survive, so
       the fig is hidden by :not(.board-dash) rather than outright. */
    .board--cumulative .board-score__fig:not(.board-dash) { display: none; }
    .board--cumulative .board-score__par {
        font-size: 17px;
        font-weight: var(--font-weight-bold);
        letter-spacing: -0.015em;
        color: var(--text);
    }
    .board--cumulative .board-score__par.under-par { color: var(--under-par); }
    .board--cumulative .board-score__par.even-par {
        color: color-mix(in srgb, var(--text) 88%, transparent);
    }
    /* Purse is a desktop column: --board-cols-sm declares no track for it, and a visible cell
       with no track pushes every later cell up a column. The figure rides the player's own line
       here instead. */
    .board-purse { display: none; }

    /* The cut line and band, tightened. The line's trailing count goes — there is no room, and
       the two figures either side of it are on the screen already. */
    .cut-wide { display: none; }
    .cut-narrow { display: inline; }
    .cut-line { padding: 8px 14px; gap: 8px; }
    .cut-line__label { font-size: 9.5px; letter-spacing: 0.11em; }
    .cut-line__count { display: none; }
    .cut-band { padding: 12px 14px; gap: 8px; }
    .cut-band__label { font-size: 10px; }
    .cut-band__text { font-size: 11.5px; }
    .board-row--cut { padding: 11px 14px; }
    .board--cumulative .board-row--cut .board-player__trail { display: inline; }
    .board-purse-chip { padding: 6px 11px; }
    .board-purse-chip__detail { display: none; }

    /* Two rows: the mode controls, then Moments full-width beneath them. The capsule was the only
       shrinkable item on a row of flex-shrink:0 controls, so at 390px it clipped to a green dot and
       the word MOMENTS — no highlight text, and nothing reading as tappable. Done with order +
       flex-basis so the DOM order (and desktop) is unchanged. */
    .board-controls { gap: var(--space-2); }
    .board-controls__end {
        order: 1;
        flex: 1 0 100%;
        margin-left: 0;
    }
    /* With no Teams control on this round, Manage is the only child and still sits right. */
    .board-controls__end > .board-manage { margin-left: auto; }
    /* THE PAGE MUST NOT BE WIDER THAN THE VIEWPORT, and this row is the only thing that ever made
       it so. .board-controls__end is flex: 1 0 100%, but every child was flex-shrink: 0 + nowrap,
       so the row's min-content width exceeded 390px and the DOCUMENT picked up horizontal
       overflow — which, while the masthead carried a full-bleed week rail, laid that rail out at
       page width and slid the last week under the pinned "All N" button. The rail is gone, but a
       page that scrolls sideways is a defect on its own. Everything here has to be able to give. */
    .board-controls__end { min-width: 0; }
    .board-controls__end > * { min-width: 0; }
    .board-manage { min-width: 0; flex-shrink: 1; overflow: hidden; }
    .board-manage__label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

    .moments-capsule {
        order: 2;
        flex: 1 0 100%;
        width: 100%;
        padding: 10px 12px;
        border-radius: 12px;
        gap: 9px;
        box-shadow: var(--shadow-sm);
        text-align: left;
    }
    .moments-capsule__item { font-size: 12.5px; }
    /* The newest moment is what gets the room the full width bought. */
    .moments-capsule__item.is-newest {
        flex: 1;
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
    }
    /* One headline moment at 390px; the rest are behind the count. */
    .moments-capsule__item:not(.is-newest) { display: none; }
    .moments-capsule__label,
    .moments-capsule__more { flex-shrink: 0; }
    .moments-capsule__chev {
        display: inline-block;
        font-size: 18px;
        color: var(--text-quiet);
        flex-shrink: 0;
    }
    .board-manage { padding: 6px 9px; font-size: 12px; }
}

/* Below 480px the Manage label drops to its glyph rather than ellipsing to two characters — the
   link carries the same words as its aria-label, so nothing is lost but the width. */
@media (max-width: 480px) {
    .board-manage__label { display: none; }
    .board-manage { padding: 6px; }
}

/* Phone view pills — the stand-in for the rail's per-week group. A horizontally-scrollable row,
   no sheet and no open/closed state: the list is short and the pills are the control. */
.view-pills { display: none; }

@media (max-width: 768px) {
    .view-pills {
        display: flex;
        gap: 6px;
        overflow-x: auto;
        scrollbar-width: none;
        margin-bottom: var(--space-3);
        padding-bottom: 2px;
    }
    .view-pills::-webkit-scrollbar { display: none; }
    .view-pill {
        padding: 7px 12px;
        border: none;
        border-radius: var(--radius-pill);
        background: var(--control-fill);
        color: var(--text-muted);
        font-family: inherit;
        font-size: 12.5px;
        font-weight: var(--font-weight-medium);
        white-space: nowrap;
        cursor: pointer;
        transition: background 0.14s ease, color 0.14s ease;
    }
    .view-pill.is-active {
        background: var(--control-fill-strong);
        color: var(--text);
        font-weight: var(--font-weight-semibold);
    }
    /* The bottom bar's metal active treatment folded into 26-bottom-nav.css with the rest of the
       bar when it became a floating pane — the active item is a metal chip now, not just metal
       ink, and splitting one item's look across two partials is how a rule goes stale. */
}

@media (prefers-reduced-motion: reduce) {
    .mh-ticker__strip { transition: none; }
    .mh-livepill__dot,
    .moments-capsule__dot { animation: none; }
    .board-row,
    .mh-livepill--picker,
    .view-pill { transition: none; }
}

/* ══════════════════════════════════════════════════════════════════════════════════════════
   THE WEEK SHEET (.wk-*) — "Jump to a week", what the masthead's status pill opens
   (handoffs/design_handoff_week_selector, screen 3)
   ══════════════════════════════════════════════════════════════════════════════════════════
   It replaced a chip grid of "Wk 1 ● / Wk 2 …" that could say nothing beyond the numeral. A row
   has room for the date and the course, which is what makes "the week we played Ironwood" findable
   without opening three of them.

   Colour discipline is the file's: --metal is the standing (the week you are on, the number tile,
   the selected rail), --color-accent is live. NOTHING else takes a hue, and there is deliberately
   NO score and no position column — this is navigation, and the board one tap away is where the
   figures belong.

   The panel zeroes .modal-panel's own padding so rows can run edge to edge, and each block owns
   its gutter — the call .wx-panel and .acc-panel both make. Rendered by Shared/WeekSheet.razor. */

.modal-panel.wk-sheet {
    --wk-inset: 20px;
    padding: 0;
    padding-bottom: env(safe-area-inset-bottom);
    background: var(--surface-raised);
}

/* The grabber is drawn by .modal-panel::before with a -0.5rem top margin that assumed the sheet's
   own padding; with padding zeroed it needs its own room. Same fix .wx-panel carries. */
@media (max-width: 480px) {
    .modal-panel.wk-sheet::before { margin: 10px auto 2px; }
}

.wk-head {
    display: flex;
    align-items: baseline;
    gap: 10px;
    flex-wrap: wrap;
    padding: 16px var(--wk-inset) 10px;
}
.wk-head__title {
    margin: 0;
    font-size: 17.6px;
    font-weight: var(--font-weight-semibold);
    color: var(--text);
}
/* "9 weeks · Wednesdays" — the cadence is the one fact about a season the numerals never carried. */
.wk-head__sub { font-size: 12px; color: var(--text-quiet); }

.wk-list { display: flex; flex-direction: column; }

/* 56px, comfortably over the 44px minimum: this is a list read on a tee box. */
.wk-row {
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
    padding: 12px var(--wk-inset);
    background: none;
    border: none;
    /* The selected marker is a rail on the leading edge, so every row reserves its width or the
       list would step sideways as the selection moves. */
    border-left: 3px solid transparent;
    border-bottom: 1px solid var(--hairline-soft);
    font-family: inherit;
    text-align: left;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
.wk-row:last-child { border-bottom: none; }
.wk-row:hover { background: var(--control-fill); }
.wk-row.is-selected {
    background: var(--metal-wash-10);
    border-left-color: var(--metal);
}
.wk-row.is-selected:hover { background: var(--metal-wash-16); }

.wk-row__tile {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border-radius: 10px;
    background: var(--control-fill);
    color: var(--text-muted);
    font-size: 14px;
    font-weight: var(--font-weight-bold);
    font-variant-numeric: tabular-nums;
}
.wk-row__tile.is-selected { background: var(--metal-wash-18); color: var(--metal-strong); }
.wk-row__tile .material-symbols-outlined { font-size: 18px; }

.wk-row__body {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
    flex: 1;
}
.wk-row__title {
    display: flex;
    align-items: center;
    gap: 7px;
    font-size: 14.5px;
    font-weight: var(--font-weight-semibold);
    color: var(--text);
}
.wk-row__sub {
    font-size: 11.5px;
    color: var(--text-quiet);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.wk-row__check { flex: none; font-size: 18px; color: var(--metal); }

/* Final and Scheduled are the same neutral treatment: neither is a state anybody must act on, and
   a second hue here would compete with the one that means live. */
.wk-badge {
    flex: none;
    padding: 1px 7px;
    border-radius: var(--radius-pill);
    background: var(--control-fill);
    color: var(--text-quiet);
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.06em;
    text-transform: uppercase;
}
.wk-badge--live {
    background: color-mix(in srgb, var(--color-accent) 12%, transparent);
    color: color-mix(in srgb, var(--color-accent) 72%, var(--text));
}

/* ══════════════════════════════════════════════════════════════════════════════════════════
   COURSE CONDITIONS (.wx-*) — what the masthead's weather chip opens
   (handoffs/design_handoff_weather_details, screens 1a / 1b / 1c)
   ══════════════════════════════════════════════════════════════════════════════════════════
   ONE DOM, two presentations, the shape .acc-panel already runs: a .modal-panel bottom sheet
   below 769px, an anchored 372px panel above it. Two DOMs would be two copies of the provenance
   sentence — the one load-bearing block on the surface — and the one nobody looked at would rot.

   Colour: metal for the eyebrow and the condition glyphs, and NOTHING else takes a hue. Rain
   likelihood, wind strength and temperature are all ink weight. An earlier draft coloured rain
   blue, which breaks the discipline stated at the top of this file.

   The panel zeroes .modal-panel's own padding and lets each block own its gutter through
   --wx-inset, the same call .acc-panel.modal-panel makes — that is what lets the stat grid's
   hairline rules run edge to edge at both widths without a negative-margin breakout. */

.wx-panel.modal-panel {
    --wx-inset: 1.5rem;
    padding: 0;
    padding-bottom: env(safe-area-inset-bottom);
    background: var(--surface-raised);
}

/* The grabber is drawn by .modal-panel::before with a -0.5rem top margin that assumed the sheet's
   own padding. With padding zeroed it needs its own room — the same fix .acc-panel carries. */
@media (max-width: 480px) {
    .wx-panel.modal-panel::before { margin: 10px auto 2px; }
}

/* ── Head ── */
.wx-head {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
    padding: 16px var(--wx-inset) 12px;
}

.wx-head__text { flex: 1; min-width: 0; }

.wx-eyebrow {
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--metal);
}

.wx-title {
    margin: 5px 0 0;
    font-size: 1.1rem;          /* .modal-panel-header h3's size; the panel takes 17px at >=769px */
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.015em;
    color: var(--text);
}

.wx-loc {
    margin-top: 2px;
    font-size: 12px;
    color: var(--text-muted);
}

.wx-close { flex: none; align-self: flex-start; padding: 0 0.25rem; }

/* ── Provenance ──
   The reason the surface exists: the chip is top-right of a page that never says where its
   reading comes from, and on a trip the reader is frequently nowhere near the course. */
.wx-prov {
    display: flex;
    align-items: flex-start;
    gap: 9px;
    margin: 0 var(--wx-inset);
    padding: 9px 11px;
    border-radius: 10px;
    background: var(--metal-wash-07);
}

.wx-prov__glyph { flex: none; margin-top: 1px; font-size: 16px; color: var(--metal); }

.wx-prov__text { font-size: 12px; line-height: 1.45; color: var(--text-muted); }
.wx-prov__text strong { font-weight: var(--font-weight-semibold); color: var(--text); }

/* ── Current ── */
.wx-current {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    padding: 18px var(--wx-inset) 14px;
}

.wx-current__glyph { flex: none; font-size: 52px; color: var(--metal); }
.wx-current__text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.wx-current__row { display: flex; align-items: baseline; gap: var(--space-2); }

.wx-temp {
    font-size: 40px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.03em;
    line-height: 1;
    color: var(--text);
    font-variant-numeric: tabular-nums;
}

.wx-feels { font-size: 13px; color: var(--text-quiet); }
.wx-cond { font-size: 14px; color: var(--text); }

/* A refresh in flight shimmers the block it is about to replace. The panel does not close and
   does not collapse to a spinner — what is on screen is still the last true reading. */
.wx-current.is-refreshing { animation: wx-pulse 1.2s ease-in-out infinite; }

/* ── Stat grid ──
   1px gaps drawn as the grid's own background, so the rules are the ground showing through. */
.wx-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 1px;
    background: var(--hairline-soft);
    border-top: 1px solid var(--hairline-soft);
    border-bottom: 1px solid var(--hairline-soft);
}

.wx-cell { background: var(--surface-raised); padding: 11px var(--wx-inset); }

.wx-cell__label {
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

.wx-cell__value {
    margin-top: 3px;
    font-size: 15px;
    font-weight: var(--font-weight-semibold);
    color: var(--text);
}

/* ── Rest of the round ── */
.wx-hours { padding: 14px var(--wx-inset) 4px; }

.wx-hours__label {
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

/* The column count comes inline from C#: the provider can hand back fewer than five near the
   edge of its window, and five columns holding three tiles reads as a rendering fault. */
.wx-hours__grid { display: grid; gap: 6px; margin-top: 10px; }

.wx-hour {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 5px;
    min-width: 0;
    padding: 9px 0;
    border-radius: 10px;
    background: var(--control-fill);
}

.wx-hour__time { font-size: 11px; color: var(--text-quiet); }
.wx-hour__glyph { font-size: 20px; color: var(--metal); }

.wx-hour__temp {
    font-size: 13px;
    font-weight: var(--font-weight-semibold);
    color: var(--text);
    font-variant-numeric: tabular-nums;
}

/* Precip carries NO hue. A likely hour is stated at full ink and full weight, an unlikely one
   recedes. WeatherView.LikelyPrecipPercent owns where the line sits. */
.wx-hour__precip { font-size: 10.5px; color: var(--text-quiet); }
.wx-hour__precip.is-likely { color: var(--text); font-weight: var(--font-weight-bold); }

/* ── Unreachable, opened ── */
.wx-fail {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
    padding: 16px var(--wx-inset) 4px;
}

.wx-fail__glyph { flex: none; margin-top: 1px; font-size: 22px; color: var(--ink-disabled); }
.wx-fail__text { min-width: 0; }

.wx-fail__title {
    font-size: 14px;
    font-weight: var(--font-weight-semibold);
    color: var(--text);
}

.wx-fail__body {
    margin-top: 4px;
    font-size: 12.5px;
    line-height: 1.5;
    color: var(--text-muted);
}

/* ── Foot ── */
.wx-foot {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 14px var(--wx-inset) 16px;
}

.wx-stamp { flex: 1; min-width: 0; font-size: 11.5px; color: var(--text-quiet); }

.wx-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-left: auto;          /* holds the button right when the stamp is absent (failure state) */
    padding: 8px 12px;
    border-radius: 9px;
    background: var(--control-fill);
    border: 1px solid var(--control-fill-strong);
    font-family: inherit;
    font-size: 12.5px;
    color: var(--text);
    cursor: pointer;
}

.wx-btn:disabled { cursor: default; opacity: 0.6; }
.wx-btn__glyph { font-size: 15px; color: var(--text-quiet); }

/* ── The panel at >=769px ──
   It hangs off the chip rather than sliding up. #app-root is a 1280px centred column, so the
   anchor is that column's gutter and not the viewport's — a plain `right: 24px` would leave it
   clear of its own chip at 1920px. 58px is 8px below the 50px utility row.

   `.modal-panel` centres itself at >=481px with `left: 50%; transform: translateX(-50%)`, and
   clearing `left` alone leaves the transform in place, landing the panel half its own width off
   the chip. That is why `transform: none` is explicit and the keyframes animate translateY only. */
@media (min-width: 769px) {
    .wx-panel.modal-panel {
        --wx-inset: 18px;
        position: fixed;
        left: auto;
        bottom: auto;
        top: calc(58px + env(safe-area-inset-top));
        right: calc(max(0px, (100vw - 1280px) / 2) + var(--space-5));
        width: 372px;
        max-width: calc(100vw - 2 * var(--space-5));
        max-height: calc(100vh - 88px);
        overflow: hidden auto;
        border: 1px solid var(--hairline);
        border-radius: var(--radius-xl);
        box-shadow: var(--shadow-lg);
        transform: none;
        animation: wx-panel-in 0.12s ease-out;
    }

    .wx-title { font-size: 17px; }

    /* Still the .modal-panel's immediate previous sibling and still the outside-click target — it
       just stops dimming the page, because a panel anchored to its trigger doesn't take the
       screen over. */
    .wx-backdrop { background: transparent; }
}

@keyframes wx-panel-in {
    from { opacity: 0; transform: translateY(4px); }
    to { opacity: 1; transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
    .wx-panel.modal-panel { animation: none; }
    .wx-current.is-refreshing { animation: none; opacity: 0.6; }
}
/* ══ 19 · Result tabs — Money List, Skins, Par 3s, Groups, Scrambles ═══════════════════════
   The five other views LeaderboardPage hosts behind ?tab=. They rendered the legacy .data-table
   from 03-tables-badges.css while the board beside them was a raised card on a ground; this
   partial carries the leaderboard's language across all five so the whole /leaderboard surface
   reads as one screen. Source: design_handoff_leaderboard_tabs/ (screens 1a–1e).

   Three rules the whole block obeys, from src/GolfTracker.UI/CLAUDE.md:
   · --metal-* means STANDING, --color-accent means LIVE OR MONEY, --under-par means UNDER PAR.
     A tie / carry / ineligible state is neutral, never a fourth hue.
   · Elevation, not boxes: --surface-raised on --page-ground, 1px --hairline, --radius-xl,
     --shadow-lg. Dividers inside are --hairline-soft.
   · Every board is a CSS grid, not a <table>. Data-driven column counts arrive as a
     --rt-cols custom property published from C#, the same call BoardColumnVars made.

   Prefix is .rt-* for the shared vocabulary, then .ml- / .sk- / .p3- / .gp- / .sc- per screen. */

/* ── Shared: control row ─────────────────────────────────────────────────────────────────── */

.rt-controls {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    flex-wrap: wrap;
    margin-bottom: 14px;
}

.rt-controls__end {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex-wrap: wrap;
}

/* The round/week scope keeps RoundPills — the picker itself is unchanged (it owns the per-week
   week chips and the phone sheet). What changes is the chrome: on the control row it reads as
   the segmented track the design draws rather than as a band of loose pills. */
.rt-controls .round-pills { margin: 0; }

.rt-controls .round-pills ul {
    display: flex;
    gap: 3px;
    padding: 3px;
    margin: 0;
    border-radius: 10px;
    background: var(--control-fill);
    list-style: none;
    overflow-x: auto;
    scrollbar-width: none;
}

.rt-controls .round-pills ul::-webkit-scrollbar { display: none; }

.rt-controls .round-pills li {
    padding: 5px 11px;
    border: none;
    border-radius: 7px;
    background: transparent;
    font-size: 12px;
    font-weight: var(--font-weight-medium);
    color: var(--text-muted);
    white-space: nowrap;
    cursor: pointer;
    transition: background 0.14s ease, color 0.14s ease;
}

.rt-controls .round-pills li:hover:not(.active) { color: var(--text); }

.rt-controls .round-pills li.active {
    background: var(--control-fill-strong);
    color: var(--text);
    font-weight: var(--font-weight-semibold);
}

/* The mode chip — "Scored net · $30 a skin", "Net · best ball 2 · front / back / total". It
   replaces .scoring-mode-badge's coloured pill: the mode is context, not an alert, and the
   per-skin / per-pot figure beside it is what makes every other number on the page checkable. */
.rt-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 10px;
    border-radius: var(--radius-md);
    background: var(--control-fill);
    font-size: 11.5px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--text-muted);
    white-space: nowrap;
}

/* Naming the subject of the screen (the round a Par 3 / Scramble board is about) is standing,
   not money — so it takes the metal wash rather than the neutral fill. */
.rt-chip--metal {
    padding: 6px 11px;
    border: 1px solid var(--metal-line);
    border-radius: var(--radius-md);
    background: var(--metal-wash-16);
    font-size: 12.5px;
    letter-spacing: normal;
    text-transform: none;
    color: var(--metal-strong);
}

.rt-note {
    font-size: 12.5px;
    color: var(--text-muted);
}

/* ── Shared: cards, heads, feet ──────────────────────────────────────────────────────────── */

.rt-stack {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    min-width: 0;
}

.rt-card {
    background: var(--surface-raised);
    border: 1px solid var(--hairline);
    border-radius: var(--radius-xl);
    box-shadow: var(--shadow-lg);
    overflow: hidden;
    min-width: 0;
}

.rt-cardhead {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    flex-wrap: wrap;
    padding: 14px 20px 12px;
}

.rt-eyebrow {
    flex-shrink: 0;
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--metal);
}

.rt-eyebrow--quiet { color: var(--text-quiet); }

.rt-rule {
    width: 1px;
    height: 12px;
    background: var(--metal-line);
    flex-shrink: 0;
}

.rt-cardhead__end {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: 14px;
    font-size: 12.5px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

/* Every card closes on what the numbers above it don't say — what's still out, what carried,
   how many players haven't cashed. Metal ground because it frames standing, above a metal rule. */
.rt-foot {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    padding: 12px 20px;
    border-top: 1px solid var(--metal-edge);
    background: var(--metal-wash-05);
    font-size: 12.5px;
    color: var(--text-muted);
}

.rt-foot__end {
    margin-left: auto;
    font-variant-numeric: tabular-nums;
}

.rt-strong {
    color: var(--text);
    font-weight: var(--font-weight-semibold);
}

/* The warning a skins round carries when holes fell under the minimum-player threshold. It is
   a fact about the settlement, so it lives in the card's foot rather than as a .form-warning
   block stacked underneath — but it keeps a warning tint so it isn't read as ordinary context. */
.rt-foot--warning {
    border-top-color: var(--warning);
    background: color-mix(in srgb, var(--warning) 10%, transparent);
}

/* ── Shared: stat rail ───────────────────────────────────────────────────────────────────── */

.rt-rail {
    display: grid;
    grid-template-columns: repeat(var(--rt-rail-cols, 4), 1fr);
}

.rt-rail__cell {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 16px 20px 18px;
    border-left: 1px solid var(--hairline);
    min-width: 0;
}

.rt-rail__cell:first-child { border-left: none; }

/* Cell 1 is the standing cell on every rail that has one — most skins, low total, front pot. */
.rt-rail__cell--lead { background: var(--metal-wash-05); }
.rt-rail__cell--lead .rt-rail__label { color: var(--metal); }

.rt-rail__top {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex-wrap: wrap;
}

.rt-rail__label {
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

.rt-rail__fig {
    font-size: 27px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.03em;
    font-variant-numeric: tabular-nums;
    color: var(--text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.rt-rail__fig--money { color: var(--color-accent); }

.rt-rail__sub {
    font-size: 11.5px;
    color: var(--text-muted);
}

/* ── Shared: grid boards ─────────────────────────────────────────────────────────────────── */

.rt-head,
.rt-row {
    display: grid;
    grid-template-columns: var(--rt-cols);
    column-gap: 12px;
    align-items: center;
}

.rt-head {
    padding: 11px 20px;
    border-bottom: 1px solid var(--hairline);
    font-size: 10.5px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

.rt-head__sortable {
    cursor: pointer;
    user-select: none;
    background: none;
    border: none;
    padding: 0;
    font: inherit;
    letter-spacing: inherit;
    text-transform: inherit;
    color: inherit;
}

.rt-head__sortable:hover { color: var(--text-muted); }
.rt-head__sortable.is-right { text-align: right; }

.rt-row {
    padding: 13px 20px;
    border-bottom: 1px solid var(--hairline-soft);
    transition: background 0.14s ease;
}

.rt-row:hover { background: color-mix(in srgb, var(--text) 3%, transparent); }
.rt-row--click { cursor: pointer; }

/* background-COLOR, not the shorthand — the shorthand resets background-image and would kill the
   leader row's --metal-row-wash whenever row 1 is also the open row. Same trap .board-row hit. */
.rt-row.is-open { background-color: var(--row-open-wash); }
.rt-row.is-open .rt-name { color: color-mix(in srgb, var(--metal) 18%, var(--text)); }
.rt-row.is-leader { background-image: var(--metal-row-wash); }

/* A board's total line. It stays a .rt-row so the figures land under their own columns — the
   .rt-foot treatment on its own is a flex row and would collapse the grid. */
.rt-row--foot {
    border-bottom: none;
    border-top: 1px solid var(--metal-edge);
    background: var(--metal-wash-05);
    font-variant-numeric: tabular-nums;
}

.rt-row--foot:hover { background: var(--metal-wash-05); }
.rt-row--foot .rt-cell { font-size: 13.5px; }

.rt-cell { min-width: 0; }
.rt-cell.is-right { text-align: right; justify-self: end; }
.rt-num { font-variant-numeric: tabular-nums; }

.rt-player {
    display: flex;
    flex-direction: column;
    line-height: 1.3;
    min-width: 0;
}

.rt-name {
    font-size: 16px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.01em;
    color: var(--text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.rt-sub {
    font-size: 11.5px;
    color: var(--text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.rt-sub:empty { display: none; }

/* A 24px position tile for the money bar's podium; .pos-tile itself (30px, 18-leaderboard.css)
   is what the rows use, so the taper across --metal-wash-18/10/07 is defined once. */
.pos-tile--sm {
    width: 24px;
    height: 24px;
    border-radius: var(--radius-md);
    font-size: 12.5px;
}

.pos-tile--xs {
    width: 26px;
    height: 26px;
    border-radius: var(--radius-md);
    font-size: 13px;
}

/* ── Shared: state pills ─────────────────────────────────────────────────────────────────── */

.rt-state {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 3px 10px 3px 8px;
    border: 1px solid transparent;
    border-radius: var(--radius-pill);
    background: var(--control-fill);
    font-size: 10.5px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: var(--text-muted);
    white-space: nowrap;
}

.rt-state__dot {
    width: 6px;
    height: 6px;
    border-radius: var(--radius-pill);
    background: var(--ink-disabled);
    flex-shrink: 0;
}

/* Green only where a round is genuinely in progress — on a scheduled or finished round it would
   claim play is happening. Same pulse the masthead's live pill uses. */
.rt-state--live {
    background: color-mix(in srgb, var(--color-accent) 12%, transparent);
    border-color: color-mix(in srgb, var(--color-accent) 30%, transparent);
    color: color-mix(in srgb, var(--color-accent) 70%, var(--text));
}

.rt-state--live .rt-state__dot {
    background: var(--color-accent);
    animation: winprob-pulse 1.6s ease-in-out infinite;
}

@media (prefers-reduced-motion: reduce) {
    .rt-state--live .rt-state__dot { animation: none; }
}

/* ── Shared: legend ──────────────────────────────────────────────────────────────────────── */

.rt-legend {
    display: flex;
    align-items: center;
    gap: 14px;
    flex-wrap: wrap;
    font-size: 11.5px;
    color: var(--text-muted);
}

.rt-legend__item {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

.rt-legend__sw {
    width: 11px;
    height: 11px;
    border-radius: 3px;
    background: var(--control-fill-strong);
}

.rt-legend__sw--won { background: color-mix(in srgb, var(--color-accent) 28%, transparent); }
.rt-legend__sw--carry { background: var(--metal-wash-18); }

/* ══ 1a · Money List ═══════════════════════════════════════════════════════════════════════
   A player asks "am I up, and where did it come from?"; a commissioner asks "does the pot
   balance?". The bar answers both above the rows, so neither needs a scroll. */

.ml-bar {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 300px;
}

.ml-bar__left { padding: 16px 20px 18px; min-width: 0; }
.ml-bar__left .rt-eyebrow { display: block; margin-bottom: 12px; }

.ml-podium {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
}

.ml-pod {
    display: flex;
    flex-direction: column;
    gap: 5px;
    padding: 0 18px;
    border-left: 1px solid var(--hairline-soft);
    min-width: 0;
}

.ml-pod:first-child { border-left: none; padding-left: 0; }

.ml-pod__top {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    min-width: 0;
}

.ml-pod__name {
    font-size: 15.5px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.01em;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ml-pod__fig {
    font-size: 27px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.03em;
    font-variant-numeric: tabular-nums;
    color: var(--text);
}

/* Only the leader's figure is money-green. Second and third are standing, and the tile already
   says so — colouring all three would make the hue mean "a number" instead of "the money". */
.ml-pod--1 .ml-pod__fig { color: var(--color-accent); }

.ml-pod__sub {
    font-size: 11.5px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

.ml-settle {
    padding: 16px 20px 18px;
    border-left: 1px solid var(--hairline);
    background: var(--metal-wash-05);
    min-width: 0;
}

.ml-settle__row {
    display: flex;
    align-items: baseline;
    gap: var(--space-2);
    margin-top: 10px;
}

.ml-settle__fig {
    font-size: 27px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.03em;
    font-variant-numeric: tabular-nums;
    color: var(--color-accent);
}

.ml-settle__of {
    font-size: 13px;
    color: var(--text-muted);
}

.ml-settle__meter {
    height: 4px;
    border-radius: 2px;
    background: var(--control-fill-strong);
    overflow: hidden;
    margin: 12px 0 10px;
}

.ml-settle__meter span {
    display: block;
    height: 100%;
    border-radius: 2px;
    background: var(--color-accent);
}

.ml-settle__line {
    display: flex;
    justify-content: space-between;
    gap: var(--space-2);
    font-size: 12px;
    color: var(--text-muted);
}

/* The mix bar — one hue at three strengths, because every segment is money. A second hue here
   would say "these are different kinds of thing", which is exactly what they aren't. */
.ml-mix {
    display: flex;
    height: 8px;
    border-radius: 4px;
    overflow: hidden;
    background: var(--control-fill);
}

.ml-mix__seg { display: block; height: 100%; }
.ml-mix__seg--1 { background: var(--color-accent); }
.ml-mix__seg--2 { background: color-mix(in srgb, var(--color-accent) 55%, transparent); }
.ml-mix__seg--3 { background: color-mix(in srgb, var(--color-accent) 28%, transparent); }

.ml-money {
    font-size: 14px;
    font-variant-numeric: tabular-nums;
    color: var(--text);
}

.ml-money.is-zero { color: var(--ink-disabled); }

.ml-perround {
    font-size: 13px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

.ml-total {
    font-size: 17px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.015em;
    font-variant-numeric: tabular-nums;
    color: var(--color-accent);
}

.ml-foot {
    border-top: 1px solid var(--metal-edge);
    background: var(--metal-wash-05);
    font-variant-numeric: tabular-nums;
}

.ml-foot .rt-cell { font-size: 13.5px; font-weight: var(--font-weight-semibold); }
.ml-foot .ml-total { font-size: 17px; }

/* The expanded ledger rides .board-detail + .psc-head from 18-leaderboard.css — same shape, same
   reason: it is a SIBLING of the row, never a child, so a click inside it can't bubble back
   through the row toggle. */
.ml-ledger { border-top: 1px solid var(--metal-edge); }

.ml-ledger__row {
    display: grid;
    grid-template-columns: 56px minmax(0, 1fr) 160px 100px;
    column-gap: 14px;
    align-items: center;
    padding: 10px 2px;
    border-bottom: 1px solid var(--hairline-soft);
}

.ml-ledger__row--total {
    border-bottom: none;
    padding: 12px 2px 0;
}

.ml-ledger__day {
    font-size: 11px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

.ml-ledger__game { font-size: 14px; font-weight: var(--font-weight-medium); }

.ml-ledger__detail {
    font-size: 12px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

.ml-ledger__amt {
    text-align: right;
    font-size: 15px;
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
    color: var(--color-accent);
}

.ml-ledger__label { font-size: 13px; font-weight: var(--font-weight-semibold); }

.ml-ledger__grand {
    text-align: right;
    font-size: 17px;
    font-weight: var(--font-weight-bold);
    font-variant-numeric: tabular-nums;
    color: var(--color-accent);
}

.ml-close {
    margin-left: auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border: none;
    border-radius: 50%;
    background: transparent;
    color: var(--text-quiet);
    cursor: pointer;
}

.ml-close:hover { background: var(--control-fill); color: var(--text); }
.ml-close .material-symbols-outlined { font-size: 18px; }

/* The mix bar rides under the name on a phone, where its own column is gone — 96×5px, same
   segments, so "where it came from" survives the breakpoint that drops the game columns. */
.ml-show-sm { display: none; }

.ml-mix--mini {
    height: 5px;
    width: 96px;
    border-radius: 3px;
    margin-top: 5px;
    flex: none;
}

.ml-foot { border-bottom: none; }
.ml-foot__note { font-size: 12px; font-weight: var(--font-weight-base); color: var(--text-muted); }

.ml-ledger-wrap { cursor: default; }

.ml-ledger__name-lg {
    font-size: 19px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.02em;
}

.ml-ledger__meta {
    font-size: 11.5px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}


/* ══ 1b · Skins ════════════════════════════════════════════════════════════════════════════
   The player board leads and the hole-by-hole run is secondary. Skins settle last, so nothing
   here pulses — this is a settlement view, not a live one. */

/* pos · player · skins taken · count · won. The chip column is the one that goes on a phone —
   which day each skin came on is the detail, and the count beside it is the answer. */
.sk-board {
    --rt-cols: 54px minmax(150px, 1fr) 300px 70px 110px;
    --rt-cols-sm: 40px minmax(0, 1fr) 44px 68px;
}

.sk-board .rt-row { padding: 12px 20px; }

.sk-chips {
    display: flex;
    gap: 5px;
    flex-wrap: wrap;
}

.sk-chip {
    display: inline-flex;
    align-items: center;
    height: 26px;
    padding: 0 8px;
    border-radius: 7px;
    background: var(--control-fill);
    font-size: 11.5px;
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
    color: var(--text-muted);
    white-space: nowrap;
}

/* A skin taken on the day currently in scope. Accent because it is this settlement's money;
   older days stay neutral so the selected day reads out of the row at a glance. */
.sk-chip--today {
    background: color-mix(in srgb, var(--color-accent) 16%, transparent);
    color: color-mix(in srgb, var(--color-accent) 70%, var(--text));
}

.sk-count {
    font-size: 17px;
    font-weight: var(--font-weight-bold);
    font-variant-numeric: tabular-nums;
}

.sk-money {
    font-size: 17px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.015em;
    font-variant-numeric: tabular-nums;
    color: var(--color-accent);
}

/* The hole strip — 18 cells on one metal rule, each saying in words what happened there. */
.sk-strip {
    display: grid;
    grid-template-columns: repeat(var(--sk-cols, 18), 1fr);
    border-top: 1px solid var(--metal-edge);
}

.sk-strip__cell {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 7px;
    padding: 12px 4px 14px;
    border-left: 1px solid var(--hairline-soft);
    min-width: 0;
}

.sk-strip__cell:first-child { border-left: none; }
.sk-strip__cell--carry { background: var(--metal-wash-05); }

.sk-strip__hole {
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.06em;
    color: var(--text-quiet);
    font-variant-numeric: tabular-nums;
}

.sk-strip__par { font-size: 9.5px; color: var(--text-quiet); }

.sk-strip__tile {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    border-radius: 9px;
    background: var(--control-fill);
    font-size: 12.5px;
    font-weight: var(--font-weight-bold);
    font-variant-numeric: tabular-nums;
    color: var(--ink-disabled);
}

.sk-strip__tile--won {
    background: color-mix(in srgb, var(--color-accent) 16%, transparent);
    color: color-mix(in srgb, var(--color-accent) 70%, var(--text));
}

.sk-strip__tile--carry {
    background: var(--metal-wash-18);
    color: var(--metal-strong);
}

.sk-strip__who {
    font-size: 10.5px;
    font-weight: var(--font-weight-semibold);
    color: var(--text-quiet);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 100%;
}

.sk-strip__who--won { color: var(--text); }
.sk-strip__who--carry { color: var(--metal); }/* ══ 1c · Contests ═════════════════════════════════════════════════════════════════════════
   One card per contested hole on the round in scope, then the trip ledger beneath. This tab IS
   live: the pots resolve as groups come through.

   The prefix stays .p3-* though the tab is no longer par-3-only — a par 3 contest, a longest
   drive and a closest-to-the-pin on named holes are one shape and now share one tab, and renaming
   forty selectors to say so would be churn with a collision risk and no user-visible payoff.
   Nothing in a LATER partial claims .p3-, which is the check that matters here. */

.p3-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 14px;
}

.p3-card { display: flex; flex-direction: column; }

.p3-card.is-live {
    border-color: color-mix(in srgb, var(--color-accent) 32%, transparent);
}

.p3-head {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    padding: 13px 18px;
    border-bottom: 1px solid var(--hairline);
}

.p3-card.is-live .p3-head {
    background: color-mix(in srgb, var(--color-accent) 5%, transparent);
}

.p3-head__hole {
    font-size: 19px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.02em;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.p3-head__meta {
    font-size: 12px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.p3-head .rt-state { margin-left: auto; }

.p3-body {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    padding: 16px 18px 14px;
}

.p3-mark {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border-radius: var(--radius-lg);
    background: var(--control-fill);
    color: var(--ink-disabled);
    flex-shrink: 0;
}

.p3-mark .material-symbols-outlined { font-size: 20px; }
.p3-mark--final { background: var(--metal-wash-18); color: var(--metal-strong); }

.p3-mark--live {
    background: color-mix(in srgb, var(--color-accent) 16%, transparent);
    color: color-mix(in srgb, var(--color-accent) 70%, var(--text));
}

.p3-who {
    display: flex;
    flex-direction: column;
    gap: 3px;
    min-width: 0;
}

.p3-who__eyebrow {
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--metal);
}

.p3-who__eyebrow--live { color: color-mix(in srgb, var(--color-accent) 70%, var(--text)); }
.p3-who__eyebrow--open { color: var(--text-quiet); }

.p3-who__name {
    font-size: 22px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.02em;
    overflow: hidden;
    text-overflow: ellipsis;
}

.p3-who__name--open { color: var(--ink-disabled); }

.p3-dist {
    margin-left: auto;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 3px;
    text-align: right;
}

.p3-dist__fig {
    font-size: 28px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.03em;
    font-variant-numeric: tabular-nums;
}

.p3-dist__fig--none { color: var(--ink-disabled); }
.p3-dist__sub { font-size: 11px; color: var(--text-quiet); }

.p3-card .rt-foot { margin-top: auto; padding: 11px 18px; font-size: 12px; }

.p3-pay {
    font-size: 15px;
    font-weight: var(--font-weight-bold);
    font-variant-numeric: tabular-nums;
    color: var(--text-muted);
}

.p3-pay--paid { color: var(--color-accent); }

/* The trip ledger. A hole still in play carries the metal wash and reads "in play" — it is a
   standing statement about an unfinished contest, not a zero. */
/* The column template is PUBLISHED FROM C# (ContestsView.ColumnVars), not declared here: the
   ledger gains a Contest column only when the event runs more than one contest, so the count is
   data. The same call BoardColumnVars and the Money List make.

   Whichever list applies, it declares exactly as many tracks as that width has VISIBLE cells —
   a .p3-hide-sm cell drops out of auto-placement. The sm list once declared three against four
   surviving cells, so they placed day → 56px, HOLE → 1fr, winner → 92px, paid → an implicit auto
   track: the widest column on the phone was "Hole 7" and the name it pushed aside was the answer.
   The md list tightens the fixed columns at the intermediate width, where the 1fr name column was
   down to ~15px at 481. The values below are the fallback for a ledger rendered without the
   inline style. */
.p3-ledger {
    --rt-cols: 70px 90px minmax(0, 1fr) 120px 110px;
    --rt-cols-md: 58px 68px minmax(0, 1fr) 96px 88px;
    --rt-cols-sm: 54px 56px minmax(0, 1fr) 76px;
}

/* The contest's name, in its own column at width and folded under the hole number on a phone.
   Two contests can hold the same hole number on one round, so dropping the name outright would
   make two ledger rows identical. Both drawings are in the DOM, each hidden in its own media
   query — the rule the players roster and the Wagers pane both follow. */
.p3-ledger__game {
    font-size: 13px;
    color: var(--text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.p3-ledger__gamesub {
    display: none;
    font-size: 11px;
    color: var(--text-quiet);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.p3-ledger .rt-head {
    border-top: 1px solid var(--metal-edge);
    border-bottom: 1px solid var(--hairline-soft);
    padding: 9px 20px;
}

.p3-ledger .rt-row { padding: 11px 20px; }
.p3-ledger .rt-row.is-open { background-color: var(--metal-wash-10); }

.p3-ledger__day {
    font-size: 11px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-quiet);
    white-space: nowrap;
}

.p3-ledger__hole {
    font-size: 13.5px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.p3-ledger__name {
    font-size: 15px;
    font-weight: var(--font-weight-semibold);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.p3-ledger__dist { font-size: 14px; font-variant-numeric: tabular-nums; }
.p3-ledger__dist--none { color: var(--ink-disabled); }

.p3-ledger__pay {
    font-size: 15px;
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
    color: var(--color-accent);
}

.p3-ledger__pay--open { color: var(--text-muted); font-weight: var(--font-weight-medium); }

/* ══ 1d · Groups ═══════════════════════════════════════════════════════════════════════════
   Both jobs the tab already had: best-ball results while and after they play, and the pairings
   before they tee off. Live — the standing between groups moves as scores land. */

.gp-cards {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 14px;
}

.gp-card { display: flex; flex-direction: column; }

.gp-head {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    padding: 13px 18px;
    border-bottom: 1px solid var(--hairline);
}

.gp-head--leader { background-image: var(--metal-row-wash); }

.gp-head__name {
    font-size: 18px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.02em;
    white-space: nowrap;
}

.gp-head__tee {
    font-size: 12px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.gp-head .rt-state { margin-left: auto; }

.gp-players {
    display: flex;
    gap: 6px;
    flex-wrap: wrap;
    padding: 8px 18px 12px;
}

.gp-sides {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    border-top: 1px solid var(--metal-edge);
    margin-top: auto;
}

.gp-side {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 11px 16px 13px;
    border-left: 1px solid var(--hairline-soft);
    min-width: 0;
}

.gp-side:first-child { border-left: none; }
.gp-side--lead { background: color-mix(in srgb, var(--color-accent) 6%, transparent); }
.gp-side--lead .gp-side__label { color: color-mix(in srgb, var(--color-accent) 70%, var(--text)); }

.gp-side__label {
    font-size: 9.5px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

.gp-side__row {
    display: flex;
    align-items: baseline;
    gap: 7px;
}

.gp-side__fig {
    font-size: 20px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.02em;
    font-variant-numeric: tabular-nums;
}

.gp-side__ou {
    font-size: 13px;
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
    color: var(--text-muted);
}

.gp-side__ou.is-under { color: var(--under-par); }

/* The pot line is what replaced six numeric columns: "won $180" / "leading $180" / "2nd ·
   missed" / "— skipped —". A state that says what it is in words needs no colour of its own. */
.gp-side__pot {
    font-size: 11px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

.gp-side__pot.is-money { color: var(--color-accent); }
.gp-side__pot.is-skipped { color: var(--ink-disabled); }

/* Pairings — the "before they tee off" half. On a Scheduled round this card IS the tab. */
.gp-pairings {
    --rt-cols: 96px 92px minmax(0, 1fr) 130px;
    /* On a phone the chips need the full width, so the row stacks: group name, then the
       four names under it. A 96px chip column turns every pairing into four lines. */
    --rt-cols-sm: minmax(0, 1fr);
}

.gp-pairings .rt-row {
    padding: 11px 20px;
    border-bottom: none;
    border-top: 1px solid var(--hairline-soft);
    cursor: default;
}

.gp-pairing__group { font-size: 14.5px; font-weight: var(--font-weight-semibold); }

.gp-pairing__tee {
    font-size: 13px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

.gp-pairing__chips {
    display: flex;
    gap: 6px;
    flex-wrap: wrap;
}

.gp-chip {
    display: inline-flex;
    align-items: center;
    height: 24px;
    padding: 0 9px;
    border-radius: var(--radius-pill);
    background: var(--control-fill);
    font-size: 12px;
    font-weight: var(--font-weight-medium);
    color: var(--text);
    white-space: nowrap;
}

/* The side that took the match (TEE-BOX-PLAN Phase 2). Metal, because winning a match is a
   STANDING — accent on these chips would mean money, and a halved match pays nobody while still
   being fully funded, so the two are not the same statement. */
.gp-chip--win {
    background: var(--metal-wash-16);
    color: var(--metal-strong);
    font-weight: 700;
}

.gp-pairing__hcp {
    text-align: right;
    font-size: 12px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

/* The hat-draw placeholder and the shortened-round note keep their existing copy; only the
   surface changed. */
.gp-notice {
    padding: 16px 20px;
    font-size: 13px;
    color: var(--text-muted);
    line-height: 1.5;
}/* ══ 1e · Scrambles ════════════════════════════════════════════════════════════════════════
   Same shape as Groups because ScrambleResultsView already was: front / back / total with an
   over-under and a pot per side, and a row that expands into the team's card. There is no net
   column and no per-team payout total — the design does not invent one. */

.sc-board {
    --rt-cols: 54px minmax(150px, 1fr) repeat(3, 116px);
    --rt-cols-sm: 34px minmax(0, 1fr) repeat(3, 52px);
}

.sc-side {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 2px;
}

.sc-side__row {
    display: flex;
    align-items: baseline;
    gap: 6px;
}

.sc-side__fig {
    font-size: 17px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.015em;
    font-variant-numeric: tabular-nums;
}

.sc-side__ou {
    font-size: 12.5px;
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
    color: var(--text-muted);
}

.sc-side__ou.is-under { color: var(--under-par); }

.sc-side__pot {
    font-size: 11px;
    font-variant-numeric: tabular-nums;
    color: var(--ink-disabled);
}

.sc-side__pot.is-money { color: var(--color-accent); }

/* The team card. Two nines on ONE column template so hole 9 sits above hole 18 and Out above
   In. Marks are the leaderboard's hairline rings (.psc-mark), not filled chips. */
.sc-card {
    --sc-cols: 56px repeat(9, 1fr) 46px;
    font-variant-numeric: tabular-nums;
}

.sc-card__grid {
    display: grid;
    grid-template-columns: var(--sc-cols);
    text-align: center;
    border-top: 1px solid var(--metal-edge);
}

.sc-card__grid + .sc-card__grid { border-top-color: var(--hairline-soft); }

.sc-card__lbl,
.sc-card__cell {
    display: flex;
    align-items: center;
    justify-content: center;
    min-width: 0;
}

.sc-card__lbl {
    justify-content: flex-start;
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

.sc-card__lbl--scr { color: var(--text); }

.sc-card__cell--hole { height: 30px; font-size: 10.5px; font-weight: var(--font-weight-bold); color: var(--text-quiet); }
.sc-card__cell--par { height: 28px; font-size: 12.5px; color: var(--text-muted); }
.sc-card__cell--scr { height: 50px; }

.sc-card__sum {
    border-left: 1px solid var(--metal-edge);
    color: var(--metal);
}

.sc-card__sum--hole { height: 30px; font-size: 10.5px; font-weight: var(--font-weight-bold); }
.sc-card__sum--par { height: 28px; font-size: 12.5px; font-weight: var(--font-weight-semibold); }

.sc-card__sum--scr {
    height: 50px;
    font-size: 15px;
    font-weight: var(--font-weight-bold);
    color: var(--metal-strong);
}

.sc-card .psc-mark { font-size: 15px; font-weight: var(--font-weight-semibold); }

.sc-card__foot {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    flex-wrap: wrap;
    margin-top: 14px;
    padding-top: 12px;
    border-top: 1px solid var(--hairline-soft);
    font-size: 11.5px;
    color: var(--text-muted);
}

.sc-card__legend {
    display: inline-flex;
    align-items: center;
    gap: 7px;
}

.sc-card__sw {
    width: 15px;
    height: 15px;
    border-radius: 50%;
    box-shadow: inset 0 0 0 1.5px var(--under-par);
}

.sc-card__sw--bogey {
    width: 14px;
    height: 14px;
    border-radius: 4px;
    box-shadow: inset 0 0 0 1.5px var(--mark-ring);
}

.sc-card__summary { margin-left: auto; font-variant-numeric: tabular-nums; }/* ══ Responsive ════════════════════════════════════════════════════════════════════════════
   Two breakpoints, matching the app: 1000px and 768px. Everything above is the ≥1001px shape. */

@media (max-width: 1000px) {
    /* Hole cards and group cards go one per row — two 1fr columns at 900px squeezes a 28px
       distance figure against a 22px name. */
    .p3-grid,
    .gp-cards { grid-template-columns: 1fr; }

    /* The money bar's settlement cell stops being a 300px sidebar and stacks under the podium. */
    .ml-bar { grid-template-columns: minmax(0, 1fr); }

    .ml-settle {
        border-left: none;
        border-top: 1px solid var(--hairline);
    }

    /* $/rd is the first column to go — it is derivable from the two beside it. The template
       itself is a custom property so a board whose column count is data-driven can publish all
       three from C#; a media query can't read a Razor expression, and an inline style carries
       no breakpoint. Same call BoardColumnVars made for the leaderboard. */
    .rt-head,
    .rt-row { grid-template-columns: var(--rt-cols-md, var(--rt-cols)); }

    .rt-rail { grid-template-columns: repeat(2, 1fr); }
    .rt-rail__cell:nth-child(-n + 2) { border-top: none; }
    .rt-rail__cell:nth-child(odd) { border-left: none; }
    .rt-rail__cell:nth-child(n + 3) { border-top: 1px solid var(--hairline); }
}

@media (max-width: 768px) {
    .rt-stack { gap: 12px; }

    .rt-controls { gap: var(--space-2); margin-bottom: 12px; }
    .rt-controls__end { margin-left: 0; }

    /* The metal hairline separates an eyebrow from the line beside it — once the head wraps
       there is nothing to its right to separate, so it reads as a stray tick. */
    .rt-rule { display: none; }
    .rt-cardhead { padding: 12px 14px 10px; gap: var(--space-2); }
    .rt-cardhead__end { gap: 10px; font-size: 11px; }
    .rt-foot { padding: 10px 14px; font-size: 11.5px; }
    .rt-head,
    .rt-row { grid-template-columns: var(--rt-cols-sm, var(--rt-cols-md, var(--rt-cols))); }

    .rt-head { padding: 9px 14px; font-size: 10px; letter-spacing: 0.09em; }
    .rt-row { padding: 11px 14px; column-gap: 8px; }
    .rt-name { font-size: 14.5px; }
    .rt-sub { font-size: 10.5px; }

    /* Money List drops the game columns and $/rd — they are in the expanded ledger. */
    .ml-board .ml-hide-sm { display: none; }
    .ml-board .ml-show-sm { display: flex; }
    .ml-total { font-size: 16px; }
    .ml-foot .rt-cell { font-size: 12.5px; }

    .ml-ledger__row {
        grid-template-columns: 52px minmax(0, 1fr) 84px;
        column-gap: 10px;
    }

    .ml-ledger__detail { display: none; }
    .ml-foot__note { display: none; }
    /* The detail header is eyebrow · name · close on one line at 390 — the sub-line it carries
       beside the name is already the row's own sub-line, two lines above it. */
    .ml-ledger__meta { display: none; }
    .ml-ledger__name-lg { font-size: 17px; }

    .ml-bar__left { padding: 14px 16px 16px; }
    .ml-podium { grid-template-columns: 1fr; gap: 12px; }

    .ml-pod {
        padding: 0;
        border-left: none;
        border-top: 1px solid var(--hairline-soft);
        padding-top: 12px;
    }

    .ml-pod:first-child { border-top: none; padding-top: 0; }
    .ml-settle { padding: 14px 16px 16px; }

    /* Skins: the player board sheds the chip column, and the 18-hole strip splits into two
       nines — the same front/back split .psc-grid--9 makes on the scorecard. */
    .sk-board .sk-hide-sm { display: none; }
    .sk-count, .sk-money { font-size: 15px; }

    /* Two rows of nine, back nine under front — the same split .psc-grid--9 makes. The 18
       cells simply reflow, so nothing about the markup changes at the breakpoint. */
    .sk-strip { grid-template-columns: repeat(9, 1fr); }
    .sk-strip__cell:nth-child(10) { border-left: none; }
    .sk-strip__cell:nth-child(n + 10) { border-top: 1px solid var(--metal-edge); }
    .sk-strip__cell { gap: 5px; padding: 9px 2px 11px; }
    .sk-strip__hole { font-size: 9.5px; }
    .sk-strip__par { display: none; }
    .sk-strip__tile { width: 26px; height: 26px; border-radius: var(--radius-md); font-size: 11.5px; }
    .sk-strip__who { font-size: 9px; }

    /* Par 3: head at 16px/11px, body at 17px name / 22px distance, chasers dropped. */
    .p3-head { padding: 11px 14px; gap: 9px; }
    .p3-head__hole { font-size: 16px; }
    .p3-head__meta { font-size: 11px; }
    .p3-body { padding: 12px 14px; gap: 12px; }
    .p3-mark { display: none; }
    .p3-who__eyebrow { font-size: 9.5px; }
    .p3-who__name { font-size: 17px; }
    .p3-dist__fig { font-size: 22px; }
    .p3-dist__sub { display: none; }
    .p3-card .rt-foot { padding: 9px 14px; font-size: 11.5px; }
    .p3-pay { font-size: 14px; }
    .p3-grid { gap: 10px; }

    .p3-ledger .rt-head, .p3-ledger .rt-row { padding: 10px 14px; }
    .p3-ledger .p3-hide-sm { display: none; }
    /* The Contest column goes; its name reappears under the hole number, because two contests can
       hold the same hole on one round and the rows would otherwise be identical. */
    .p3-ledger__gamesub { display: block; }

    /* Groups: the side cells stay three across — they are the answer the tab exists for. */
    .gp-cards { gap: 10px; }
    .gp-head { padding: 11px 14px; gap: 9px; }
    .gp-head__name { font-size: 15px; }
    .gp-players { padding: 8px 14px 10px; }
    .gp-side { padding: 9px 10px 11px; }
    .gp-side__fig { font-size: 17px; }
    .gp-side__ou { font-size: 12px; }
    .gp-side__pot { font-size: 10px; }

    .gp-pairings .rt-row { padding: 10px 14px; row-gap: 6px; }
    .gp-pairings .gp-hide-sm { display: none; }
    .gp-pairing__chips { margin-top: 6px; }

    /* Scrambles: F / B / Tot at 14.5px over a 9.5px pot line. */
    .sc-board .rt-row { column-gap: 6px; }
    .sc-side__row { gap: 0; flex-direction: column; align-items: flex-end; }
    .sc-side__fig { font-size: 14.5px; }
    .sc-side__ou { display: none; }
    .sc-side__pot { font-size: 9.5px; }

    .sc-card { --sc-cols: 40px repeat(9, 1fr) 38px; }
    .sc-card__lbl { font-size: 9px; letter-spacing: 0.06em; }
    .sc-card .psc-mark { font-size: 13px; }
    .sc-card__cell--scr, .sc-card__sum--scr { height: 42px; }
    .sc-card__sum--scr { font-size: 13px; }
}
/* ══ 20 · Course management — list, drill-in, scorecard editor, add sheet ══════════════════
   /events/{slug}/courses/manage and /events/{slug}/courses/{courseId}. The last high-traffic
   admin surface still built as a stack of .settings-card forms on the legacy .data-table; this
   partial carries it into the language the leaderboard and its result tabs already speak.
   Source: design_handoff_courses/ (screens 1a–1e).

   Four rules the whole block obeys, from src/GolfTracker.UI/CLAUDE.md:

   · --metal-* means THE THING YOU'RE STANDING ON (the selected course in the rail, section
     eyebrows, the tee a round is scored off). --color-accent means the primary action and a
     passing check. --under-par/--danger is destructive only. And --warning amber is used for
     EXACTLY ONE THING here: data that is incomplete or disagrees with itself. That is the whole
     reason it earns a hue — nothing else on these screens is amber.
   · Elevation, not boxes: --surface-raised on --page-ground, 1px --hairline, --radius-xl,
     --shadow-lg. Dividers inside are --hairline-soft.
   · The scorecard is a CSS grid, not a <table>. Same call the leaderboard and the result tabs made.
   · Every state says what it is in words — "1 tee missing", "Index clash", "Card disagrees",
     "Not scheduled". Never a bare dot, never a colour alone.

   Prefix is .cm-* throughout. Sub-grid hairlines (1–4px) are the only raw-px spacing, per the
   --space-* rule. */

/* ── Page frame ──────────────────────────────────────────────────────────────────────────── */

/* Local ink on a TINT of amber, mirroring .set-page's block: in light mode the hue on its own
   14% wash lands ~2.5:1, so the ink darkens to the #a56a05 the design draws. In dark mode the
   hue is already brightened for a dark ground, so darkening it is exactly backwards.

   Declared on all three containers rather than on .cm-page alone, because a card and a sheet are
   also rendered outside a page (the editor expands in place; the sheets are fixed to the viewport)
   and a warning that loses its ink is unreadable. Layout stays on .cm-page only. */
.cm-page,
.cm-card,
.cm-sheet {
    --cm-warn-wash: color-mix(in srgb, var(--warning) 14%, transparent);
    --cm-warn-line: color-mix(in srgb, var(--warning) 34%, transparent);
    /* 65%, not the 42% .set-page uses for its own warning ink: this hue does real work here — it is
       the only thing that says a scorecard disagrees — and 42% lands close enough to --text that a
       glance can't tell an amber figure from a black one. 65% is the design's #a56a05. */
    --cm-warn-ink: color-mix(in srgb, var(--warning) 65%, #000);
}

:root[data-theme="dark"] :is(.cm-page, .cm-card, .cm-sheet) {
    --cm-warn-ink: var(--warning);
}

.cm-page {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    min-width: 0;
}

.cm-head {
    display: flex;
    align-items: flex-start;
    gap: var(--space-4);
}

.cm-head__body { min-width: 0; flex: 1; }

.cm-head__title {
    margin: 0 0 4px;
    font-size: 27px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.03em;
    line-height: 1.1;
}

.cm-head__purpose {
    margin: 0;
    font-size: 13.5px;
    color: var(--text-muted);
}

.cm-head__end {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex: none;
}

/* The page's ONE primary. Accent means live-or-money and the primary action; nothing else on
   these screens is green except a passing check. */
.cm-primary {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 10px 16px;
    border: none;
    border-radius: var(--radius-lg);
    background: var(--color-accent);
    color: var(--on-hue);
    font-family: inherit;
    font-size: 13.5px;
    font-weight: var(--font-weight-semibold);
    white-space: nowrap;
    cursor: pointer;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
    transition: filter 0.14s ease;
}

.cm-primary .material-symbols-outlined { font-size: 18px; }
.cm-primary:hover { filter: brightness(0.95); }
.cm-primary:disabled { opacity: 0.55; cursor: default; }

/* A section action — the .board-manage shape, reused so a secondary control on this screen and
   one on the leaderboard can't drift. --strong is the slightly louder sibling (Add tee). */
.cm-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 7px 11px;
    border-radius: 9px;
    border: 1px solid var(--control-fill-strong);
    background: var(--control-fill);
    color: var(--text);
    font-family: inherit;
    font-size: 12.5px;
    white-space: nowrap;
    cursor: pointer;
}

.cm-btn .material-symbols-outlined { font-size: 16px; color: var(--text-quiet); }
.cm-btn:hover { background: var(--control-fill-strong); }
.cm-btn:disabled { opacity: 0.5; cursor: default; }

.cm-btn--strong {
    border-color: transparent;
    background: var(--control-fill-strong);
    font-weight: var(--font-weight-semibold);
    padding: 7px 12px;
}

.cm-btn--strong .material-symbols-outlined { color: inherit; }

/* ── Cards ───────────────────────────────────────────────────────────────────────────────── */

.cm-card {
    background: var(--surface-raised);
    border: 1px solid var(--hairline);
    border-radius: var(--radius-xl);
    box-shadow: var(--shadow-lg);
    overflow: hidden;
    min-width: 0;
}

/* A card whose subject is in play — metal, not amber, because being played is a STANDING and
   not a fault. */
.cm-card--metal { border-color: var(--metal-edge); }

/* A card whose subject disagrees with itself. The one amber card on the screen. */
.cm-card--warn { border-color: var(--cm-warn-line); }

.cm-card__foot {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    padding: 13px 20px;
    border-top: 1px solid var(--metal-edge);
    background: var(--metal-wash-05);
    font-size: 12.5px;
    color: var(--text-muted);
}

.cm-card__foot-end { margin-left: auto; }

/* A card is `overflow: hidden` so its rows clip to the radius — which also clips the anchored
   dropdown an OverflowMenu opens from inside a tee head. Lift the clip only while a menu is open,
   exactly as `.set-card:has(…)` and `.app-bar:has(…)` do. The phone form is a fixed bottom sheet
   and was never affected. */
.cm-card:has(.overflow-menu__panel) { overflow: visible; }

/* ── Setup rail (1a) ─────────────────────────────────────────────────────────────────────── */

.cm-rail {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
}

.cm-rail__cell {
    display: flex;
    flex-direction: column;
    padding: 16px 20px 18px;
    border-left: 1px solid var(--hairline);
    min-width: 0;
}

.cm-rail__cell:first-child { border-left: none; }

/* Cell 1 frames what this trip has — standing, so it takes the metal wash. */
.cm-rail__cell--lead { background: var(--metal-wash-05); }
.cm-rail__cell--lead .cm-rail__label { color: var(--metal); }

.cm-rail__label {
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

.cm-rail__fig {
    margin-top: 8px;
    font-size: 27px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.03em;
    line-height: 1.05;
    font-variant-numeric: tabular-nums;
    color: var(--text);
}

.cm-rail__figs {
    display: flex;
    align-items: baseline;
    gap: 9px;
    margin-top: 8px;
}

.cm-rail__figs .cm-rail__fig { margin-top: 0; }

.cm-rail__of {
    font-size: 15px;
    font-weight: var(--font-weight-medium);
    color: var(--text-muted);
}

.cm-rail__sub {
    margin-top: 5px;
    font-size: 11.5px;
    color: var(--text-muted);
}

.cm-rail__sub a { color: var(--metal-strong); text-decoration: underline; }

.cm-rail__bar {
    height: 4px;
    border-radius: 2px;
    background: var(--control-fill-strong);
    overflow: hidden;
    margin: 10px 0 6px;
}

.cm-rail__bar > span {
    display: block;
    height: 100%;
    border-radius: 2px;
    background: var(--metal);
}

/* ── Chips ───────────────────────────────────────────────────────────────────────────────── */

.cm-chip {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 3px 9px;
    border: 1px solid transparent;
    border-radius: var(--radius-pill);
    background: var(--control-fill);
    font-size: 11px;
    font-weight: var(--font-weight-semibold);
    color: var(--text-muted);
    white-space: nowrap;
}

/* The one amber on the screen: data that is incomplete or disagrees with itself. */
.cm-chip--warn {
    background: var(--cm-warn-wash);
    border-color: var(--cm-warn-line);
    color: var(--text);
}

/* In play is a standing, not a fault. */
.cm-chip--metal {
    background: var(--metal-wash-16);
    border-color: var(--metal-line);
    color: var(--metal-strong);
}

.cm-chip--caps {
    padding: 2px 8px;
    font-size: 10.5px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

/* One 13px dot per tee, in that tee's own ColorHex. The inset ring is what SheetSelect's swatch
   uses, so a white tee still reads. */
.cm-swatches {
    display: inline-flex;
    align-items: center;
    gap: 3px;
}

.cm-swatch {
    width: 13px;
    height: 13px;
    border-radius: var(--radius-pill);
    box-shadow: inset 0 0 0 1px rgba(20, 26, 34, 0.22);
    flex: none;
}

.cm-swatch--lg { width: 16px; height: 16px; }
.cm-swatch--sm { width: 9px; height: 9px; }

/* ── Course list (1a) ────────────────────────────────────────────────────────────────────── */

.cm-list__head,
.cm-row {
    display: grid;
    grid-template-columns: minmax(200px, 1fr) 168px 128px 152px 116px 40px;
    column-gap: 14px;
    align-items: center;
}

.cm-list__head {
    padding: 11px 20px;
    border-bottom: 1px solid var(--hairline);
    font-size: 10.5px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

/* The WHOLE row is the link — the same call /rounds/manage made. There is no per-row Edit button
   and no per-row Delete; deleting a course is a menu item on the course it belongs to. */
.cm-row {
    padding: 14px 20px;
    border-bottom: 1px solid var(--hairline-soft);
    color: inherit;
    text-decoration: none;
    transition: background 0.14s ease;
}

.cm-row:last-of-type { border-bottom: none; }
.cm-row:hover { background: color-mix(in srgb, var(--text) 3%, transparent); }

/* background-COLOR, not the shorthand — the shorthand resets background-image and would kill the
   wash on a course whose round is live. Same trap .board-row and .rt-row hit. */
.cm-row--live { background-image: var(--metal-row-wash); }
.cm-row--live .cm-played { color: var(--text); }

.cm-course {
    display: flex;
    flex-direction: column;
    line-height: 1.32;
    min-width: 0;
}

.cm-course__name {
    font-size: 16px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.01em;
    color: var(--text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.cm-course__place {
    font-size: 11.5px;
    color: var(--text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.cm-tees-cell {
    display: flex;
    align-items: center;
    gap: 7px;
    min-width: 0;
}

.cm-tees-cell__count {
    font-size: 12.5px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* Par · yardage is the DEFAULT tee's — the one a round would land on. */
.cm-par {
    text-align: right;
    font-size: 13.5px;
    font-variant-numeric: tabular-nums;
    color: var(--text-muted);
}

/* "Not scheduled" in --ink-disabled is what makes a course obviously safe to delete. */
.cm-played {
    font-size: 12.5px;
    color: var(--text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.cm-played--none { color: var(--ink-disabled); }

/* Both phone-only lines are in the DOM at every width and hide here, rather than being toggled
   from C#: the row is a grid, and an extra grid item at desktop width would claim a column. */
.cm-summary,
.cm-row__mline { display: none; }

.cm-chev {
    display: flex;
    justify-content: flex-end;
    color: var(--ink-disabled);
}

.cm-chev .material-symbols-outlined { font-size: 20px; }

/* ── Course rail (1b) ────────────────────────────────────────────────────────────────────────
   The master half of the drill-in's master–detail. It replaces the event rail at ≥769px (the
   layout stands that one down, exactly as it does for Settings and the round hub), because
   fixing four courses in a row must not cost four round trips through the list. */

.cm-rail-nav {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.cm-rail-nav__label {
    padding: 0 12px 6px;
    font-size: 11px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

.cm-rail-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 9px 12px;
    border: none;
    border-radius: 10px;
    background: none;
    font-family: inherit;
    color: inherit;
    text-decoration: none;
    text-align: left;
    cursor: pointer;
}

.cm-rail-row:hover { background: color-mix(in srgb, var(--text) 4%, transparent); }

.cm-rail-row.is-active {
    background: var(--metal-wash-10);
    box-shadow: inset 2px 0 0 var(--metal);
}

.cm-rail-row.is-active .cm-rail-row__label {
    font-weight: var(--font-weight-semibold);
    color: var(--metal-strong);
}

.cm-rail-row__label {
    flex: 1;
    min-width: 0;
    font-size: 13.5px;
    color: var(--text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* A 6px amber dot on a course with an open fault. It is never the only signal — the row it leads
   to states the fault in words. */
.cm-rail-row__flag {
    width: 6px;
    height: 6px;
    border-radius: var(--radius-pill);
    background: var(--warning);
    flex: none;
}

.cm-rail-add {
    margin-top: 14px;
    border: 1px dashed var(--control-fill-strong);
    color: var(--text-muted);
}

.cm-rail-add .material-symbols-outlined { font-size: 18px; color: var(--ink-disabled); }

.cm-rail-nav__foot {
    margin-top: var(--space-5);
    padding-top: var(--space-4);
    border-top: 1px solid var(--hairline);
}

/* ── Course detail head (1b) ─────────────────────────────────────────────────────────────── */

.cm-eyebrow {
    font-size: 11px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-quiet);
    margin-bottom: 6px;
}

.cm-eyebrow--metal { color: var(--metal); letter-spacing: 0.12em; font-size: 10px; }

.cm-meta {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    font-size: 13.5px;
    color: var(--text-muted);
}

.cm-meta__rule {
    width: 1px;
    height: 13px;
    background: var(--hairline);
    flex: none;
}

.cm-meta__src {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 12.5px;
}

.cm-meta__src .material-symbols-outlined { font-size: 15px; color: var(--text-quiet); }

/* The scheduled-round warning. The SECOND sentence is the load-bearing half — it says which edits
   are dangerous and which aren't, which is the difference between a warning and a nag. */
.cm-warnband {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
    padding: 13px 16px;
    border: 1px solid var(--cm-warn-line);
    border-radius: var(--radius-lg);
    background: var(--cm-warn-wash);
    font-size: 13px;
    line-height: 1.5;
    text-wrap: pretty;
}

.cm-warnband > .material-symbols-outlined {
    font-size: 19px;
    color: var(--cm-warn-ink);
    flex: none;
    margin-top: 1px;
}

.cm-warnband strong { font-weight: var(--font-weight-semibold); }
.cm-warnband span { color: var(--text-muted); }

/* ── Section rule + actions (1b) ─────────────────────────────────────────────────────────── */

.cm-section {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    flex-wrap: wrap;
    margin-top: 4px;
}

.cm-section__rule {
    height: 1px;
    flex: 1;
    min-width: var(--space-5);
    background: var(--metal-edge);
}

.cm-section__count {
    font-size: 12.5px;
    color: var(--text-muted);
}

/* ── Tee cards (1b) ──────────────────────────────────────────────────────────────────────── */

.cm-tee__head {
    display: grid;
    grid-template-columns: minmax(160px, 1fr) 118px 118px 118px 132px 36px;
    column-gap: 14px;
    align-items: center;
    padding: 14px 18px;
    border-bottom: 1px solid var(--hairline);
}

.cm-tee__head--metal { background: var(--metal-wash-05); }

.cm-tee__id {
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
}

.cm-tee__names {
    display: flex;
    flex-direction: column;
    line-height: 1.3;
    min-width: 0;
}

.cm-tee__name {
    font-size: 17px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.02em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.cm-tee__sub {
    font-size: 11.5px;
    color: var(--text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* The three numbers a commissioner is checking against a paper card, so they get columns rather
   than the run-on "72.1 / 130 · 6681 yds · Par 72" string the old header carried. */
.cm-stat {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.cm-stat__label {
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.11em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

.cm-stat__fig {
    font-size: 15px;
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
}

.cm-stat__fig--warn { color: var(--cm-warn-ink); }

.cm-tee__menu { display: flex; justify-content: flex-end; }

/* The phone's 3-up stat strip is in the DOM at every width and hides here, for the same reason
   .cm-row__mline does — the head is a grid, so its stat cells can't move into a second container. */
.cm-tee__stats { display: none; }

/* The note strip: what's true about this tee and what to do next, attached to the tee it's about.
   It replaces the <details> disclosures and the loose .form-hint paragraphs. */
.cm-note {
    display: flex;
    align-items: center;
    gap: 9px;
    flex-wrap: wrap;
    padding: 11px 18px;
    border-bottom: 1px solid var(--hairline-soft);
    font-size: 12.5px;
    color: var(--text-muted);
}

.cm-note > .material-symbols-outlined { font-size: 17px; flex: none; }
.cm-note__text { flex: 1; min-width: 12ch; }
.cm-note__cta { margin-left: auto; background: var(--surface); font-weight: var(--font-weight-semibold); font-size: 12px; }

.cm-note--good > .material-symbols-outlined { color: var(--color-accent); }
.cm-note--quiet > .material-symbols-outlined { color: var(--text-quiet); }

.cm-note--fault {
    background: var(--cm-warn-wash);
    border-bottom-color: var(--cm-warn-line);
}

.cm-note--fault > .material-symbols-outlined { color: var(--cm-warn-ink); }
.cm-note--fault .cm-note__text { color: var(--text); }

/* Collapsed front-nine strip on the in-play tee. It is a REASSURANCE, not an editor — it says
   "there is a card here" without opening one. */
.cm-strip {
    display: grid;
    grid-template-columns: 44px repeat(9, 1fr) 52px;
    font-variant-numeric: tabular-nums;
}

.cm-strip__cell {
    padding: 7px 2px;
    text-align: center;
    font-size: 11.5px;
    color: var(--text-muted);
}

.cm-strip__cell--label {
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

.cm-strip__cell--rule { border-bottom: 1px solid var(--hairline-soft); }

.cm-strip__cell--out {
    border-left: 1px solid var(--metal-edge);
    background: var(--metal-wash-05);
    font-weight: var(--font-weight-semibold);
    color: var(--metal-strong);
}

/* ── Scorecard editor (1c) ───────────────────────────────────────────────────────────────── */

.cm-sc__head {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    flex-wrap: wrap;
    padding: 14px 18px;
    border-bottom: 1px solid var(--metal-edge);
    background: var(--metal-wash-05);
}

.cm-sc__name {
    font-size: 17px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.02em;
}

.cm-sc__rule {
    width: 1px;
    height: 13px;
    background: var(--metal-line);
    flex: none;
}

/* The tee's own totals, on screen beside the card totals they're being checked against. */
.cm-sc__totals {
    font-size: 12.5px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

.cm-sc__actions {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

/* Cancel and Save sit side by side in a card head, so the primary drops to the section-action
   height rather than towering over the ghost button next to it. */
.cm-sc__actions .cm-primary { padding: 7px 13px; font-size: 12.5px; }

/* Kept and PROMOTED — it's the fastest path from a paper card and it was buried inside the
   editing branch. Same parser as before: split on space/tab/comma/semicolon, take the first 18. */
.cm-sc__paste {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    padding: 11px 18px;
    border-bottom: 1px solid var(--hairline);
}

.cm-sc__paste-label {
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.11em;
    text-transform: uppercase;
    color: var(--text-quiet);
    white-space: nowrap;
}

.cm-sc__paste-field {
    flex: 1;
    min-width: 12ch;
    height: 34px;
    padding: 0 11px;
    border: 1px solid var(--border);
    border-radius: 9px;
    background: var(--surface);
    font-family: inherit;
    font-size: 13px;
    color: var(--text);
    font-variant-numeric: tabular-nums;
}

.cm-sc__hint { font-size: 11.5px; color: var(--text-muted); }

/* Two nines, one column template, front above back — holes read ACROSS, the way every paper
   scorecard has always read. The 18-row vertical table it replaces is a shape no card has had. */
.cm-sc__grid {
    display: grid;
    grid-template-columns: 78px repeat(9, 1fr) 66px;
    font-variant-numeric: tabular-nums;
}

.cm-sc__grid + .cm-sc__grid { border-top: 1px solid var(--metal-edge); }

.cm-sc__cell {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 48px;
    padding: 0 6px;
    border-bottom: 1px solid var(--hairline-soft);
}

.cm-sc__cell--head {
    min-height: 34px;
    background: var(--control-fill);
    border-bottom: 1px solid var(--hairline);
    font-size: 12px;
    font-weight: var(--font-weight-bold);
    color: var(--text-quiet);
}

.cm-sc__cell--rowlabel {
    justify-content: flex-start;
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

.cm-sc__cell--sum {
    border-left: 1px solid var(--metal-edge);
    background: var(--metal-wash-05);
    font-size: 15px;
    font-weight: var(--font-weight-bold);
    color: var(--metal-strong);
}

.cm-sc__cell--sumhead {
    border-left: 1px solid var(--metal-edge);
    background: var(--metal-wash-10);
    font-size: 10px;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--metal);
}

.cm-sc__box {
    width: 100%;
    height: 34px;
    padding: 0 4px;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--surface);
    font-family: inherit;
    font-size: 14px;
    text-align: center;
    color: var(--text);
    font-variant-numeric: tabular-nums;
    -moz-appearance: textfield;
    appearance: textfield;
}

/* The spinner arrows are a ~10px target and their keyboard can type a value the field won't take;
   the paste row and the keypad are the real input paths here. */
.cm-sc__box::-webkit-outer-spin-button,
.cm-sc__box::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

.cm-sc__box:focus-visible {
    outline: none;
    border-color: color-mix(in srgb, var(--color-accent) 55%, transparent);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-accent) 13%, transparent);
}

.cm-sc__box.is-warn { border-color: var(--cm-warn-line); background: var(--cm-warn-wash); }

/* The whole point of the screen. Both checks are pure client-side arithmetic; neither needs an
   endpoint, and neither blocks a save. */
.cm-sc__checks {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    border-top: 1px solid var(--metal-edge);
    background: var(--metal-wash-05);
}

.cm-sc__check {
    padding: 14px 18px;
    border-left: 1px solid var(--hairline);
    min-width: 0;
}

.cm-sc__check:first-child { border-left: none; }

.cm-sc__check-figs {
    display: flex;
    align-items: baseline;
    gap: 10px;
    margin-top: 7px;
}

.cm-sc__check-fig {
    font-size: 22px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.02em;
    font-variant-numeric: tabular-nums;
}

.cm-sc__verdict {
    display: flex;
    align-items: flex-start;
    gap: var(--space-2);
    margin-top: 9px;
    font-size: 13px;
    line-height: 1.45;
    text-wrap: pretty;
}

.cm-sc__verdict > .material-symbols-outlined { font-size: 18px; flex: none; }
.cm-sc__verdict--ok > .material-symbols-outlined { color: var(--color-accent); }
.cm-sc__verdict--ok { font-size: 13.5px; }
.cm-sc__verdict--bad > .material-symbols-outlined { color: var(--cm-warn-ink); }

/* ── Add-a-course sheet (1d) ─────────────────────────────────────────────────────────────────
   One sheet, one search, one order of preference. Replaces three cards of identical visual
   weight, two of which were usually empty. */

/* Built on .modal-backdrop / .modal-panel so Escape, backdrop-close and the phone bottom-sheet
   form all come along, then restyled to the raised-card values — the same call .rules-dialog made. */
.cm-sheet {
    background: var(--surface-raised);
    padding: 0;
    padding-bottom: env(safe-area-inset-bottom);
    overflow: hidden;
    display: flex;
    flex-direction: column;
}

/* 481px is where .modal-panel itself becomes a centred dialog, so the wider cap has to land on
   the same breakpoint — not on the 768px one the rest of this file uses. */
@media (min-width: 481px) {
    .cm-sheet { max-width: 560px; bottom: 8%; }
}

.cm-sheet__head {
    padding: 18px 20px 14px;
    border-bottom: 1px solid var(--hairline);
}

.cm-sheet__title-row {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin-bottom: var(--space-3);
}

.cm-sheet__title {
    margin: 0;
    font-size: 19px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.02em;
}

.cm-search {
    display: flex;
    align-items: center;
    gap: 10px;
    height: 44px;
    padding: 0 13px;
    border: 1px solid var(--metal-line);
    border-radius: 11px;
    background: var(--surface);
}

.cm-search:focus-within { box-shadow: 0 0 0 3px var(--metal-wash-10); }
.cm-search > .material-symbols-outlined { font-size: 20px; color: var(--text-quiet); flex: none; }

.cm-search__input {
    flex: 1;
    min-width: 0;
    border: none;
    background: none;
    font-family: inherit;
    font-size: 15px;
    color: var(--text);
}

.cm-search__input:focus { outline: none; }

.cm-spin {
    font-size: 18px;
    color: var(--text-quiet);
    flex: none;
    animation: cm-spin 1.1s linear infinite;
}

@keyframes cm-spin { to { transform: rotate(360deg); } }

@media (prefers-reduced-motion: reduce) {
    .cm-spin { animation: none; }
}

.cm-sheet__explain {
    margin: 10px 0 0;
    font-size: 12.5px;
    line-height: 1.5;
    color: var(--text-muted);
}

.cm-sheet__body { max-height: 46vh; overflow-y: auto; }

/* "The worldwide catalog didn't answer, so this list is partial."
   Deliberately NOT amber: on these screens amber means exactly one thing — a scorecard that is
   incomplete or disagrees with itself — and spending it on a transient upstream outage is what
   makes the hue stop meaning anything. It isn't a fault in the commissioner's data and there is
   nothing for them to fix, so it reads as quiet information on the control fill. */
.cm-notice {
    display: flex;
    align-items: flex-start;
    gap: var(--space-2);
    margin: var(--space-3) var(--space-4) 0;
    padding: var(--space-3);
    border: 1px solid var(--hairline);
    border-radius: var(--radius-md);
    background: var(--control-fill);
    color: var(--text-muted);
    font-size: 12.5px;
    line-height: 1.45;
}

.cm-notice .material-symbols-outlined {
    font-size: 18px;
    flex: none;
    color: var(--ink-disabled);
}

/* One list under two GroupHeadings, exactly as SheetSelectOption.GroupHeading already does
   elsewhere — the caller's ordering determines the sections and nothing is re-sorted behind it. */
.cm-group {
    padding: 13px 20px 6px;
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

.cm-group--metal { color: var(--metal); padding-top: 11px; }

.cm-result {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: 12px 20px;
    border-bottom: 1px solid var(--hairline-soft);
}

/* "Did I already add this?" is the question the fourth card used to answer by being read. */
.cm-result--have { background: var(--metal-wash-05); padding: 11px 20px; }

.cm-result__body {
    display: flex;
    flex-direction: column;
    line-height: 1.32;
    flex: 1;
    min-width: 0;
}

.cm-result__name {
    font-size: 15px;
    font-weight: var(--font-weight-semibold);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.cm-result__sub {
    font-size: 11.5px;
    color: var(--text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.cm-sheet__foot {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 14px 20px;
    border-top: 1px solid var(--metal-edge);
    background: var(--metal-wash-05);
    font-size: 12.5px;
    color: var(--text-muted);
}

.cm-sheet__foot .cm-btn { margin-left: auto; }

/* Manual entry is the escape hatch, not the third card down. */
.cm-manual {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    padding: 16px 20px;
}

.cm-manual__row { display: flex; gap: 10px; flex-wrap: wrap; }
.cm-manual__row > .cm-field { flex: 1; min-width: 9ch; }

.cm-field {
    display: flex;
    flex-direction: column;
    gap: 5px;
}

.cm-field__label {
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.11em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

.cm-field input,
.cm-field select {
    height: 40px;
    padding: 0 12px;
    border: 1px solid var(--border);
    border-radius: 9px;
    background: var(--surface);
    font-family: inherit;
    font-size: 14px;
    color: var(--text);
    min-width: 0;
}

.cm-field input:focus-visible {
    outline: none;
    border-color: color-mix(in srgb, var(--color-accent) 55%, transparent);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-accent) 13%, transparent);
}

.cm-field--num input { font-variant-numeric: tabular-nums; }
.cm-field--num { max-width: 12ch; }

/* A colour well, not a text box — the swatch IS the value, so it fills the control. */
.cm-field input[type="color"] {
    width: 56px;
    padding: 3px;
    cursor: pointer;
}

/* The one checkbox on these screens. It keeps the .set-row shape — name and caption on the left,
   the control beside them — rather than the bare "☐ label" the old form used, because the caption
   is where "18-hole rounds off this tee are refused" has to live. */
.cm-check {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    cursor: pointer;
}

.cm-check input[type="checkbox"] {
    width: 20px;
    height: 20px;
    flex: none;
    margin-top: 1px;
    accent-color: var(--color-accent);
}

.cm-check__name {
    display: block;
    font-size: 14px;
    font-weight: var(--font-weight-medium);
}

.cm-check__caption {
    display: block;
    margin-top: 3px;
    font-size: 11.5px;
    line-height: 1.45;
    color: var(--text-muted);
}

/* ── Course details rows (1b) ────────────────────────────────────────────────────────────────
   Name / City / State / Country / Website. Auto-save on blur with the per-row .set-saved tick,
   per the settings convention — the standalone "Save Course" button is gone. */

.cm-detail-row {
    display: flex;
    align-items: center;
    gap: 20px;
    padding: 12px 20px;
    border-bottom: 1px solid var(--hairline-soft);
}

.cm-detail-row__body { flex: 1; min-width: 0; }

/* Name over caption, the .set-row shape — as inline spans the caption ran on after the name and
   the row read as one sentence. */
.cm-detail-row__name {
    display: block;
    font-size: 14.5px;
    font-weight: var(--font-weight-medium);
}

.cm-detail-row__caption {
    display: block;
    margin-top: 2px;
    font-size: 11.5px;
    color: var(--text-muted);
}

.cm-detail-row__control {
    flex: none;
    display: flex;
    align-items: center;
    gap: 10px;
}

.cm-detail-row__input {
    width: 280px;
    height: 38px;
    padding: 0 12px;
    border: 1px solid var(--border);
    border-radius: 9px;
    background: var(--surface);
    font-family: inherit;
    font-size: 14px;
    color: var(--text);
}

.cm-detail-row__input:focus-visible {
    outline: none;
    border-color: color-mix(in srgb, var(--color-accent) 55%, transparent);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-accent) 13%, transparent);
}

.cm-card__note {
    padding: 12px 20px;
    background: var(--metal-wash-05);
    font-size: 12px;
    color: var(--text-muted);
}

/* ── Responsive ──────────────────────────────────────────────────────────────────────────────
   Two breakpoints, matching the app: 1000px and 768px. */

@media (max-width: 1000px) {
    /* Four 27px figures don't survive a narrow column either — two rows of two do. */
    .cm-rail { grid-template-columns: repeat(2, 1fr); }
    .cm-rail__cell:nth-child(3) { border-left: none; }
    .cm-rail__cell:nth-child(n + 3) { border-top: 1px solid var(--hairline); }

    /* Played drops; the three tee stat cells stay, because they're the answer the card exists for. */
    .cm-list__head,
    .cm-row { grid-template-columns: minmax(180px, 1fr) 150px 116px 116px 36px; }

    .cm-played,
    .cm-col--played { display: none; }

    .cm-tee__head { grid-template-columns: minmax(140px, 1fr) 104px 104px 104px 120px 36px; column-gap: 10px; }
}

@media (max-width: 768px) {
    .cm-head { flex-direction: column; gap: var(--space-3); }
    .cm-head__title { font-size: 24px; }
    .cm-head__end { margin-left: 0; width: 100%; }
    .cm-primary { flex: 1; justify-content: center; }

    /* The setup rail collapses to ONE summary line — four 27px figures do not survive 390px, and
       the list's own chips already carry the detail. */
    .cm-rail { display: none; }

    .cm-summary,
    .cm-row__mline { display: flex; }

    .cm-summary {
        align-items: center;
        gap: 8px;
        flex-wrap: wrap;
        padding: 12px 14px;
        font-size: 12.5px;
        color: var(--text-muted);
    }

    .cm-list__head { display: none; }

    .cm-row {
        display: flex;
        flex-direction: column;
        align-items: stretch;
        gap: 7px;
        padding: 13px 14px;
        position: relative;
    }

    .cm-course__name { font-size: 15.5px; white-space: normal; }
    .cm-row .cm-chev { position: absolute; top: 14px; right: 10px; }
    .cm-course { padding-right: var(--space-5); }
    .cm-par { text-align: left; }

    /* Swatches, tee count, par and yardage collapse onto one line under the name. */
    .cm-row__mline {
        display: flex;
        align-items: center;
        gap: 8px;
        flex-wrap: wrap;
        font-size: 12.5px;
        color: var(--text-muted);
        font-variant-numeric: tabular-nums;
    }

    .cm-card__foot { padding: 12px 14px; }

    /* Detail: the rows become one-line value rows that open a sheet. */
    .cm-detail-row { gap: 12px; padding: 12px 14px; }
    .cm-detail-row__caption { display: none; }
    .cm-detail-row__input { width: 100%; min-width: 0; height: 42px; font-size: 16px; }
    .cm-detail-row__control { flex: 1; min-width: 0; }

    .cm-meta { font-size: 12.5px; }

    /* Each tee card keeps its head (swatch · name · chip · ⋯) and drops to a 3-up stat strip.
       The note strip survives verbatim — it's the only thing on the screen that tells you
       something is wrong. */
    .cm-tee__head {
        display: flex;
        align-items: center;
        gap: 9px;
        padding: 12px 14px;
        border-bottom: none;
    }

    .cm-tee__name { font-size: 15.5px; letter-spacing: -0.01em; }
    .cm-tee__sub { display: none; }
    .cm-tee__id { flex: 1; }

    .cm-tee__head .cm-stat { display: none; }

    .cm-tee__stats {
        display: grid;
        grid-template-columns: repeat(3, 1fr);
        border-top: 1px solid var(--hairline-soft);
    }

    .cm-tee__stats .cm-stat { padding: 10px 12px; border-left: 1px solid var(--hairline-soft); }
    .cm-tee__stats .cm-stat:first-child { border-left: none; }
    .cm-stat__label { font-size: 9.5px; }
    .cm-stat__fig { font-size: 14px; }

    .cm-note { padding: 10px 14px; border-top: 1px solid var(--hairline-soft); border-bottom: none; }
    .cm-note__cta { margin-left: 0; }

    /* The collapsed strip is desktop reassurance; on a phone the chip and note already say it. */
    .cm-strip { display: none; }

    .cm-section { gap: 10px; }

    /* The grid transposes to 18 rows behind a Front / Back Segmented, with 44px inputs — the
       hit-target floor. */
    .cm-sc__grid { display: none; }
    .cm-sc__checks { grid-template-columns: 1fr; }
    .cm-sc__check { border-left: none; border-top: 1px solid var(--hairline); }
    .cm-sc__check:first-child { border-top: none; }

    .cm-sc__head { padding: 12px 14px; }
    .cm-sc__totals { flex-basis: 100%; }
    .cm-sc__actions { margin-left: auto; }

    .cm-sc__paste { padding: 10px 14px; }
    .cm-sc__paste-label { flex-basis: 100%; }
    .cm-sc__hint { display: none; }
}

/* The transposed phone card. Both forms are in the DOM and each hides inside its own media query
   rather than one toggling display:none — the desktop form is a grid and a blanket `block` would
   flatten it. Same call the Wagers pane made for .wager-desktop / .wager-phone. */
.cm-sc__phone { display: none; }

@media (max-width: 768px) {
    .cm-sc__phone { display: block; }

    .cm-sc__prow {
        display: grid;
        grid-template-columns: 46px 1fr 1fr 1fr;
        column-gap: 8px;
        align-items: center;
        padding: 8px 12px;
        border-bottom: 1px solid var(--hairline-soft);
    }

    .cm-sc__prow--head {
        padding: 9px 12px;
        border-bottom: 1px solid var(--hairline);
        font-size: 10px;
        font-weight: var(--font-weight-bold);
        letter-spacing: 0.1em;
        text-transform: uppercase;
        color: var(--text-quiet);
        text-align: center;
    }

    .cm-sc__prow--head > :first-child { text-align: left; }

    .cm-sc__prow--sum {
        background: var(--metal-wash-05);
        border-top: 1px solid var(--metal-edge);
        font-variant-numeric: tabular-nums;
        text-align: center;
        font-weight: var(--font-weight-bold);
        color: var(--metal-strong);
    }

    .cm-sc__prow--sum > :first-child { text-align: left; }

    .cm-sc__pnum {
        font-size: 14px;
        font-weight: var(--font-weight-semibold);
        font-variant-numeric: tabular-nums;
    }

    .cm-sc__phone .cm-sc__box { height: 44px; font-size: 15px; border-radius: 9px; }
}

@media (prefers-reduced-motion: reduce) {
    .cm-row,
    .cm-primary { transition: none; }
}

/* ── Shell ───────────────────────────────────────────────────────────────────────────────────
   The drill-in reuses .settings-shell for its two-pane master–detail (and for the breakpoint that
   hides the rail below 768px), but the settings detail column is capped at 700px and a tee card's
   six columns need ~750. Declared after 07-settings.css so it wins, and doubled up on the class so
   specificity doesn't depend on file order alone. */
@media (min-width: 768px) {
    .settings-shell.settings-shell--wide {
        max-width: 1180px;
        grid-template-columns: minmax(220px, 248px) minmax(0, 1fr);
    }
}

/* At ≥769px the event rail (list) or the course rail (drill-in) navigates, so the back bar is
   redundant — the same call .settings-detail .app-bar makes for the settings drill-in. */
@media (min-width: 769px) {
    .cm-list-page > .app-bar { display: none; }
}
/* ══ 21 · Handicaps — list, player history, seed & adjust ══════════════════════════════════
   /events/{slug}/handicaps and /events/{slug}/handicaps/{memberId}. The last event-scoped
   screens still rendering the pre-overhaul .settings-card + .data-table vocabulary; this partial
   carries them into the language the leaderboard (18) and the five result tabs (19) speak.
   Source: design_handoff_handicaps/ (screens 1a–1d).

   Four rules the whole block obeys, from src/GolfTracker.UI/CLAUDE.md:

   · NO FIGURE ON THESE SCREENS IS COLOURED. --metal means standing, --color-accent means
     live-or-money, --under-par means under par — and a handicap index is none of the three. A low
     index is not winning, so there is deliberately no podium tile, no rank column and no green.
     Metal appears only as section eyebrows, the metal hairline rules, the YOU pill, the sparkline
     stroke and the COUNTING-DIFFERENTIAL treatment — which differentials define the index is the
     one thing on these screens that resembles a standing.
   · --warning amber is the one addition, and it is confined to "a commissioner must act": the
     attention card, the Needs-an-index chip, and the consequence footers on the two write sheets.
     It never appears on a healthy row.
   · Elevation, not boxes: --surface-raised on --page-ground, 1px --hairline, --radius-xl,
     --shadow-lg. Dividers inside are --hairline-soft.
   · Boards are CSS grids, not <table>. Every figure is tabular-nums. Every state says what it is
     in words — "no rounds yet", "dropped", "Needs an index", "plays off scratch" — never a bare em
     dash and never a colour alone.

   Prefix is .hc-* throughout. Sub-grid hairlines and the design's measured card paddings are the
   only raw-px spacing, matching 19-result-tabs.css and 20-courses.css. */

/* Local ink on a TINT of amber, the same shape .cm-page and .set-page use: at #f39c12 the hue on
   its own 12% wash lands around 2.4:1 in light mode, so the ink darkens to the #8a5a06 the design
   draws. In dark mode the hue is already brightened for a dark ground and darkening it would be
   exactly backwards. Declared on the sheet too, which renders outside the page. */
.hc-page,
.hc-card,
.hc-sheet {
    --hc-warn-wash: rgba(243, 156, 18, 0.12);
    --hc-warn-tint: rgba(243, 156, 18, 0.07);
    --hc-warn-row: rgba(243, 156, 18, 0.05);
    --hc-warn-line: rgba(243, 156, 18, 0.28);
    --hc-warn-edge: rgba(243, 156, 18, 0.32);
    --hc-warn-ink: #8a5a06;
}

:root[data-theme="dark"] :is(.hc-page, .hc-card, .hc-sheet) {
    --hc-warn-ink: var(--warning);
}

/* ── Page frame ──────────────────────────────────────────────────────────────────────────── */

.hc-page {
    display: flex;
    flex-direction: column;
    gap: 14px;
    min-width: 0;
}

/* Control row: the page names itself (the masthead carries the EVENT name, not the page name),
   the scope filter sits beside it, actions right. */
.hc-controls {
    display: flex;
    align-items: center;
    gap: var(--space-3);
}

.hc-title {
    margin: 0;
    font-size: 22px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.02em;
}

.hc-controls__end {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex: none;
}

/* Every panel on both screens. */
.hc-card {
    background: var(--surface-raised);
    border: 1px solid var(--hairline);
    border-radius: var(--radius-xl);
    box-shadow: var(--shadow-lg);
    overflow: hidden;
    min-width: 0;
}

/* A card's head: metal eyebrow · metal hairline · a plain sentence. Identical to .rt-cardhead's
   job; kept local because these heads carry a right-hand legend the result tabs' don't. */
.hc-head {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    padding: 12px 22px;
    border-bottom: 1px solid var(--hairline);
}

.hc-eyebrow {
    flex: none;
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--metal);
}

.hc-rule {
    flex: none;
    width: 1px;
    height: 12px;
    background: var(--metal-line);
}

.hc-head__note {
    font-size: 12.5px;
    color: var(--text-muted);
}

.hc-head__end {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: 7px;
    font-size: 11px;
    color: var(--text-quiet);
}

.hc-strong {
    color: var(--text);
    font-weight: var(--font-weight-semibold);
}

/* ── 1a · Overview rail ──────────────────────────────────────────────────────────────────── */

.hc-rail { display: grid; grid-template-columns: repeat(4, 1fr); }

.hc-rail__cell {
    padding: 16px 20px 18px;
    border-left: 1px solid var(--hairline);
    min-width: 0;
}

.hc-rail__cell:first-child { border-left: none; }

/* Cell 1 frames the one thing on this rail that is a standing — how much of the field is on a
   real index — so it takes the metal wash and a metal label. The other three stay neutral. */
.hc-rail__cell--lead { background: var(--metal-wash-05); }
.hc-rail__cell--lead .hc-rail__label { color: var(--metal); }

.hc-rail__label {
    display: block;
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

.hc-rail__fig {
    display: block;
    margin-top: var(--space-2);
    font-size: 27px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.03em;
    font-variant-numeric: tabular-nums;
    color: var(--text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.hc-rail__of {
    font-size: 17px;
    font-weight: var(--font-weight-semibold);
    color: var(--text-muted);
    letter-spacing: 0;
}

.hc-rail__sub {
    display: block;
    margin-top: var(--space-1);
    font-size: 11.5px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

/* Below 1000px four 27px figures don't survive side by side; the same three facts read fine as
   one line, and the board underneath carries the detail. */
.hc-summary {
    display: none;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
    padding: 12px 16px;
    font-size: 12.5px;
    color: var(--text-muted);
}

/* ── 1a · Attention card ─────────────────────────────────────────────────────────────────── */

.hc-attn__head {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    padding: 12px 20px;
    border-bottom: 1px solid var(--hairline);
    background: var(--hc-warn-tint);
}

.hc-attn__head .material-symbols-outlined { font-size: 19px; color: var(--warning); }

.hc-attn__title {
    font-size: 13.5px;
    font-weight: var(--font-weight-semibold);
    color: var(--text);
}

.hc-attn__why {
    font-size: 12px;
    color: var(--text-muted);
}

/* The bulk action. Metal because it is a text action rather than a button, and metal is the one
   ink on these screens that reads as "act on the board" without borrowing the amber. */
.hc-attn__all {
    margin-left: auto;
    border: none;
    background: none;
    padding: 0;
    font-family: inherit;
    font-size: 12.5px;
    font-weight: var(--font-weight-semibold);
    color: var(--metal-strong);
    cursor: pointer;
}

.hc-attn__all:hover { text-decoration: underline; }

.hc-attn__row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.3fr) 128px;
    column-gap: 14px;
    align-items: center;
    padding: 11px 20px;
    border-bottom: 1px solid var(--hairline-soft);
}

.hc-attn__row:last-child { border-bottom: none; }

.hc-attn__who {
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
}

.hc-attn__name {
    font-size: 15px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.01em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.hc-attn__reason {
    font-size: 12.5px;
    color: var(--text-muted);
    min-width: 0;
}

.hc-avatar {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: var(--radius-pill);
    background: var(--control-fill-strong);
    color: var(--text);
    font-size: 11.5px;
    font-weight: var(--font-weight-bold);
}

/* ── Buttons: the .board-manage shape, so a control here and one on the leaderboard can't drift ── */

.hc-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 7px 11px;
    border-radius: 9px;
    border: 1px solid var(--control-fill-strong);
    background: var(--control-fill);
    color: var(--text);
    font-family: inherit;
    font-size: 12.5px;
    white-space: nowrap;
    cursor: pointer;
    transition: background 0.14s ease;
}

.hc-btn .material-symbols-outlined { font-size: 16px; color: var(--text-quiet); }
.hc-btn:hover { background: var(--control-fill-strong); }
.hc-btn:disabled { opacity: 0.55; cursor: default; }
.hc-btn--strong { font-weight: var(--font-weight-semibold); }

/* A 32px square — the history page's prev/next pair. */
.hc-iconbtn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border-radius: 9px;
    border: 1px solid var(--control-fill-strong);
    background: var(--control-fill);
    color: var(--text-muted);
    cursor: pointer;
    transition: background 0.14s ease;
}

.hc-iconbtn .material-symbols-outlined { font-size: 18px; }
.hc-iconbtn:hover { background: var(--control-fill-strong); }
.hc-iconbtn:disabled { opacity: 0.4; cursor: default; }

/* The one solid action, on the sheets and the adjustment card. --navy stays dark in both themes,
   so its ink is --on-solid; it is NOT accent, because applying a handicap change is not money. */
.hc-primary {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 7px;
    padding: 8px 16px;
    border: none;
    border-radius: var(--radius-lg);
    background: var(--surface-inverse);
    color: var(--on-solid);
    font-family: inherit;
    font-size: 13px;
    font-weight: var(--font-weight-semibold);
    white-space: nowrap;
    cursor: pointer;
    transition: filter 0.14s ease;
}

.hc-primary:hover { filter: brightness(1.15); }
.hc-primary:disabled { opacity: 0.55; cursor: default; }

/* ── 1a · Player index board ─────────────────────────────────────────────────────────────── */

/* Fixed column count, so all three templates live in CSS — only a board whose column count is
   data-driven (the Money List's games, the cumulative board's rounds) needs them from C#. */
.hc-board__head,
.hc-row {
    display: grid;
    grid-template-columns: minmax(170px, 1fr) 88px 96px 112px 72px 76px 116px 34px;
    column-gap: 12px;
    align-items: center;
}

.hc-board__head {
    padding: 11px 20px;
    border-bottom: 1px solid var(--hairline);
    font-size: 10.5px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

.hc-sort {
    border: none;
    background: none;
    padding: 0;
    font: inherit;
    letter-spacing: inherit;
    text-transform: inherit;
    color: inherit;
    text-align: right;
    cursor: pointer;
    user-select: none;
}

.hc-sort:hover { color: var(--text-muted); }

.hc-row {
    width: 100%;
    padding: 12px 20px;
    border: none;
    border-bottom: 1px solid var(--hairline-soft);
    background: none;
    font-family: inherit;
    text-align: left;
    color: inherit;
    cursor: pointer;
    transition: background 0.14s ease;
}

.hc-row:hover { background: color-mix(in srgb, var(--text) 3%, transparent); }

/* background-COLOR, not the shorthand: the shorthand resets background-image, and the YOU row and
   a no-index row can be the same row. Same trap .board-row and .rt-row hit. */
.hc-row--you { background-color: var(--metal-wash-10); }
.hc-row--needs { background-color: var(--hc-warn-row); }

.hc-player {
    display: flex;
    flex-direction: column;
    line-height: 1.3;
    min-width: 0;
}

.hc-name {
    font-size: 16px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.01em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.hc-you {
    margin-left: 7px;
    display: inline-flex;
    padding: 1px 6px;
    border-radius: var(--radius-pill);
    background: var(--metal-wash-16);
    border: 1px solid var(--metal-line);
    font-size: 9.5px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--metal-strong);
    vertical-align: 2px;
}

.hc-sub {
    font-size: 11.5px;
    color: var(--text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.hc-idx {
    text-align: right;
    font-size: 20px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.02em;
    font-variant-numeric: tabular-nums;
    color: var(--text);
}

.hc-idx--none { color: var(--ink-disabled); }

.hc-delta {
    text-align: right;
    font-size: 13.5px;
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
    color: var(--text-muted);
}

.hc-delta--flat { color: var(--text-quiet); font-weight: var(--font-weight-medium); }

.hc-spark {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 26px;
}

.hc-spark svg { display: block; }

.hc-nospark { font-size: 11px; color: var(--ink-disabled); }

.hc-num {
    text-align: right;
    font-size: 14px;
    font-variant-numeric: tabular-nums;
    color: var(--text-muted);
}

.hc-num--zero { color: var(--ink-disabled); }

/* Source. A calculated index prints the plain word — it is the normal case and a chip on every
   row would say nothing. Only the three exceptions are chipped. */
.hc-source {
    justify-self: end;
    font-size: 12.5px;
    color: var(--text-muted);
    white-space: nowrap;
}

.hc-chip {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 3px 9px;
    border-radius: 7px;
    border: 1px solid transparent;
    font-size: 11px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: 0.03em;
}

.hc-chip--seed {
    background: var(--control-fill);
    border-color: var(--control-fill-strong);
    color: var(--text-muted);
}

/* The amount lives in the row's sub-line, not in the chip — a chip reading "Adjusted −0.4" is two
   facts in a space sized for one. */
.hc-chip--adjusted {
    background: var(--control-fill-strong);
    color: var(--text);
}

.hc-chip--needs {
    background: var(--hc-warn-wash);
    border-color: var(--hc-warn-edge);
    color: var(--hc-warn-ink);
}

.hc-chip--scope {
    background: var(--control-fill);
    color: var(--text-muted);
}

/* The counting-differential pill — the one place metal appears on a figure's behalf, because
   which differentials define the index IS a standing. Replaces the old raw green row tint, which
   spent the money hue on something that is not money. */
.hc-chip--counts {
    background: var(--metal-wash-18);
    border-color: var(--metal-edge);
    color: var(--metal-strong);
}

.hc-chip--counts .material-symbols-outlined { font-size: 14px; }

.hc-kebab { justify-self: end; }

/* The row is the link, so the ⋯ has to stop its own clicks reaching it. */
.hc-row .overflow-menu { display: inline-flex; }

.hc-rowmenu {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    border: none;
    border-radius: 8px;
    background: none;
    color: var(--ink-disabled);
    cursor: pointer;
}

.hc-rowmenu:hover { background: var(--control-fill); color: var(--text-muted); }
.hc-rowmenu .material-symbols-outlined { font-size: 18px; }

/* A card's closing sentence, on the metal ground the result tabs' .rt-foot uses. */
.hc-foot {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    padding: 13px 20px;
    border-top: 1px solid var(--metal-edge);
    background: var(--metal-wash-05);
    font-size: 13px;
    color: var(--text-muted);
}

.hc-foot__end {
    margin-left: auto;
    font-variant-numeric: tabular-nums;
}

/* Empty panels keep their head and their eyebrow, so an empty card still looks like the card it
   is. Shape is .psc-empty from 18-leaderboard.css; this only gives it room. */
.hc-empty { padding: 34px 24px 30px; }
.hc-empty .psc-empty__note { max-width: 260px; text-wrap: pretty; }

/* ── 1b · Back row ───────────────────────────────────────────────────────────────────────── */

.hc-backrow {
    display: flex;
    align-items: center;
    gap: 10px;
}

.hc-backrow__pos {
    font-size: 12.5px;
    color: var(--text-muted);
}

.hc-backrow__end {
    margin-left: auto;
    display: flex;
    gap: 6px;
}

/* ── 1b · Identity card ──────────────────────────────────────────────────────────────────── */

.hc-ident { display: grid; grid-template-columns: minmax(0, 1fr) 400px; }

.hc-ident__main { padding: 18px 22px 20px; min-width: 0; }

.hc-ident__chips {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    margin-bottom: 10px;
}

.hc-ident__who {
    display: flex;
    align-items: center;
    gap: 14px;
    min-width: 0;
}

.hc-tile {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 52px;
    height: 52px;
    border-radius: 14px;
    background: var(--control-fill-strong);
    color: var(--text);
    font-size: 18px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.01em;
}

.hc-ident__names {
    display: flex;
    flex-direction: column;
    line-height: 1.15;
    min-width: 0;
}

.hc-ident__name {
    margin: 0;
    font-size: 30px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.025em;
}

.hc-ident__meta { font-size: 12.5px; color: var(--text-muted); }

/* The equation. The whole page in one line: calculated − adjustment = the index actually in use,
   and beside it what that means in strokes. With no adjustment the strip collapses to the single
   "Index in use" cell — a "− 0.0" term would invent a decision nobody made. */
.hc-eq {
    display: flex;
    align-items: stretch;
    margin-top: 20px;
    border: 1px solid var(--hairline);
    border-radius: var(--radius-lg);
    overflow: hidden;
}

.hc-eq__cell { padding: 12px 18px; flex: none; }
.hc-eq__cell--fill { background: var(--control-fill); }

.hc-eq__label {
    display: block;
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

.hc-eq__fig {
    display: block;
    margin-top: 5px;
    font-size: 25px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.03em;
    font-variant-numeric: tabular-nums;
}

.hc-eq__op {
    display: flex;
    align-items: center;
    padding: 0 var(--space-1);
    font-size: 19px;
    color: var(--ink-disabled);
}

.hc-eq__use {
    flex: 1;
    padding: 12px 20px;
    background: var(--metal-wash-05);
    border-left: 1px solid var(--metal-edge);
    min-width: 0;
}

.hc-eq__use .hc-eq__label { color: var(--metal); }

.hc-eq__useline {
    display: flex;
    align-items: baseline;
    gap: 10px;
    flex-wrap: wrap;
    margin-top: 2px;
}

.hc-eq__big {
    font-size: 38px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.035em;
    font-variant-numeric: tabular-nums;
    line-height: 1.05;
}

/* "course 13 · playing 13 at Tidewater white" — the single most useful number on the page. An
   index means nothing to most players; strokes do. Absent when no round resolves, never zeroed. */
.hc-eq__plays { font-size: 12.5px; color: var(--text-muted); }

/* The chart pane. */
.hc-chartpane {
    padding: 18px 22px 20px;
    border-left: 1px solid var(--hairline);
    background: var(--metal-wash-05);
    min-width: 0;
}

.hc-chartpane__top {
    display: flex;
    align-items: baseline;
    gap: 10px;
}

.hc-chartpane__delta {
    margin-left: auto;
    font-size: 13.5px;
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
}

.hc-chart { display: block; margin-top: 10px; max-width: 100%; }

.hc-chart__axis {
    display: flex;
    justify-content: space-between;
    margin-top: 2px;
    font-size: 11px;
    color: var(--text-quiet);
    font-variant-numeric: tabular-nums;
}

/* The only place the app explains the soft cap, and it earns its line. */
.hc-chart__note {
    margin-top: 10px;
    font-size: 11.5px;
    line-height: 1.45;
    color: var(--text-muted);
    text-wrap: pretty;
}

.hc-idfoot {
    display: grid;
    grid-template-columns: repeat(var(--hc-idfoot-cols, 4), 1fr);
    border-top: 1px solid var(--hairline);
}

.hc-idfoot__cell {
    padding: 12px 22px;
    border-left: 1px solid var(--hairline-soft);
    min-width: 0;
}

.hc-idfoot__cell:first-child { border-left: none; }

.hc-idfoot__label {
    display: block;
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

.hc-idfoot__fig {
    display: block;
    margin-top: 3px;
    font-size: 17px;
    font-weight: var(--font-weight-bold);
    font-variant-numeric: tabular-nums;
}

.hc-idfoot__of {
    font-size: 13px;
    font-weight: var(--font-weight-medium);
    color: var(--text-muted);
}

.hc-idfoot__word {
    display: block;
    margin-top: 5px;
    font-size: 13.5px;
    font-weight: var(--font-weight-semibold);
}

.hc-idfoot__word--quiet { color: var(--text-muted); }

/* On a phone the adjustment collapses to a row at the foot of this card, opening the sheet. */
.hc-adjustrow {
    display: none;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 12px 16px;
    border: none;
    border-top: 1px solid var(--hairline);
    background: var(--control-fill);
    font-family: inherit;
    text-align: left;
    color: inherit;
    cursor: pointer;
}

.hc-adjustrow__name { font-size: 13.5px; font-weight: var(--font-weight-semibold); }
.hc-adjustrow__val { font-size: 13px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.hc-adjustrow .material-symbols-outlined { margin-left: auto; font-size: 19px; color: var(--ink-disabled); }

/* ── 1b · Manual adjustment card ─────────────────────────────────────────────────────────── */

/* One .set-row, not a form: name + caption left, exactly one control right. */
.hc-adjust {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 300px;
    column-gap: var(--space-5);
    align-items: center;
    padding: 16px 22px;
}

.hc-adjust__name { font-size: 14.5px; font-weight: var(--font-weight-semibold); }

.hc-adjust__caption {
    margin-top: 3px;
    max-width: 520px;
    font-size: 12.5px;
    line-height: 1.5;
    color: var(--text-muted);
    text-wrap: pretty;
}

.hc-adjust__control { justify-self: end; }

.hc-preview {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    padding: 12px 22px;
    border-top: 1px solid var(--hairline-soft);
    background: var(--control-fill);
    font-variant-numeric: tabular-nums;
}

.hc-preview__label { font-size: 13px; color: var(--text-muted); }
.hc-preview__sum { font-size: 14px; font-weight: var(--font-weight-semibold); }

.hc-preview__result {
    font-size: 17px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.015em;
}

.hc-preview__actions {
    margin-left: auto;
    display: flex;
    gap: var(--space-2);
}

/* The consequence footer. RecomputeMaterializedPlayingHandicapsAsync happens invisibly today — a
   commissioner nudging an index mid-round has no idea it moves live net scores. */
.hc-consequence {
    display: flex;
    align-items: flex-start;
    gap: 9px;
    padding: 11px 22px;
    border-top: 1px solid var(--hc-warn-line);
    background: var(--hc-warn-tint);
    font-size: 12px;
    line-height: 1.5;
    color: var(--text-muted);
    text-wrap: pretty;
}

.hc-consequence .material-symbols-outlined {
    flex: none;
    margin-top: 1px;
    font-size: 17px;
    color: var(--warning);
}

/* ── 1b · Index timeline ─────────────────────────────────────────────────────────────────── */

.hc-tl__head,
.hc-tl__row {
    display: grid;
    grid-template-columns: 120px 84px 96px 78px 86px 100px minmax(0, 1fr);
    column-gap: 12px;
    align-items: center;
}

.hc-tl__head {
    padding: 10px 22px;
    border-bottom: 1px solid var(--hairline);
    font-size: 10.5px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

.hc-tl__row {
    padding: 11px 22px;
    border-bottom: 1px solid var(--hairline-soft);
}

.hc-tl__row:last-child { border-bottom: none; }
.hc-tl__row--newest { background: var(--metal-wash-05); }

.hc-tl__date { font-size: 13.5px; font-variant-numeric: tabular-nums; }
.hc-tl__row--newest .hc-tl__date { font-weight: var(--font-weight-semibold); }

.hc-tl__idx {
    text-align: right;
    font-size: 16px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.015em;
    font-variant-numeric: tabular-nums;
}

.hc-tl__num {
    text-align: right;
    font-size: 13.5px;
    font-variant-numeric: tabular-nums;
    color: var(--text-muted);
}

.hc-tl__delta {
    text-align: right;
    font-size: 13px;
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
    color: var(--text-muted);
}

.hc-tl__src { justify-self: end; }

.hc-tl__trigger {
    padding-left: 14px;
    border-left: 1px solid var(--hairline-soft);
    font-size: 13px;
    color: var(--text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* The phone's disclosure. Hidden above 768px, where the full timeline just renders. */
.hc-disclose {
    display: none;
    width: 100%;
    padding: 12px 16px;
    border: none;
    border-top: 1px solid var(--hairline-soft);
    background: var(--control-fill);
    font-family: inherit;
    font-size: 13px;
    font-weight: var(--font-weight-semibold);
    color: var(--text-muted);
    cursor: pointer;
}

/* ── 1b · Scoring record ─────────────────────────────────────────────────────────────────── */

.hc-legend__swatch {
    display: inline-block;
    width: 11px;
    height: 11px;
    border-radius: 3px;
    background: var(--control-fill);
    vertical-align: -1px;
}

.hc-legend__swatch--counts {
    background: var(--metal-wash-18);
    border: 1px solid var(--metal-edge);
}

.hc-rec__head,
.hc-rec__row {
    display: grid;
    grid-template-columns: 104px minmax(0, 1fr) 74px 116px 96px 68px 96px;
    column-gap: 12px;
    align-items: center;
}

.hc-rec__head {
    padding: 10px 22px;
    border-bottom: 1px solid var(--hairline);
    font-size: 10.5px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

.hc-rec__row {
    padding: 12px 22px;
    border-bottom: 1px solid var(--hairline-soft);
}

.hc-rec__row:last-child { border-bottom: none; }
.hc-rec__row--counts { background: var(--metal-wash-05); }

.hc-rec__date { font-size: 13.5px; font-variant-numeric: tabular-nums; color: var(--text-muted); }

.hc-rec__course {
    display: flex;
    flex-direction: column;
    line-height: 1.3;
    min-width: 0;
}

.hc-rec__name {
    font-size: 15px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.01em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.hc-rec__sub {
    font-size: 11.5px;
    color: var(--text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.hc-rec__ags {
    text-align: right;
    font-size: 15px;
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
}

.hc-rec__cr {
    text-align: right;
    font-size: 13.5px;
    font-variant-numeric: tabular-nums;
    color: var(--text-muted);
}

.hc-est {
    margin-left: 6px;
    display: inline-flex;
    padding: 1px 5px;
    border-radius: var(--radius-sm);
    border: 1px solid var(--border);
    background: var(--control-fill);
    font-size: 10px;
    font-weight: var(--font-weight-semibold);
    color: var(--text-quiet);
}

.hc-rec__diff {
    text-align: right;
    font-size: 16px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.015em;
    font-variant-numeric: tabular-nums;
    color: var(--text-muted);
}

.hc-rec__diff--counts { color: var(--text); }

.hc-rec__holes {
    text-align: right;
    font-size: 13px;
    font-variant-numeric: tabular-nums;
    color: var(--text-muted);
}

.hc-rec__counts { justify-self: end; }
.hc-dropped { font-size: 11.5px; color: var(--text-quiet); }

/* The phone's second sub-line ("Aug 9 · 84 · 18 holes") and the DIFF caption under the
   differential. Both are in the DOM at every width and each hides in its own media query — the
   same call .wager-desktop / .wager-phone and the scorecard editor make, because a blanket
   display:block on a grid child would flatten the row. */
.hc-rec__msub,
.hc-rec__difflabel { display: none; }

.hc-rec__difflabel {
    text-align: right;
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

/* ── 1c · Seed & adjust sheets ───────────────────────────────────────────────────────────── */

/* Rides .modal-panel, so the backdrop, Escape, the drag-to-dismiss handle and the ≥481px
   centred-dialog form all come along. */
.hc-sheet {
    background: var(--surface-raised);
    padding: 0;
    padding-bottom: env(safe-area-inset-bottom);
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.hc-sheet__title-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 18px 4px;
}

.hc-sheet__title {
    margin: 0;
    font-size: 18px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.02em;
}

.hc-sheet__explain {
    margin: 0;
    padding: 0 18px 12px;
    font-size: 12.5px;
    line-height: 1.5;
    color: var(--text-muted);
    text-wrap: pretty;
}

.hc-block {
    margin: 0 18px 14px;
    border: 1px solid var(--hairline);
    border-radius: 14px;
    overflow: hidden;
}

.hc-block__who {
    display: flex;
    align-items: center;
    gap: 11px;
    padding: 12px 14px;
    border-bottom: 1px solid var(--hairline-soft);
}

.hc-block__who .hc-avatar { width: 32px; height: 32px; font-size: 12px; }

.hc-block__names {
    display: flex;
    flex-direction: column;
    line-height: 1.3;
    min-width: 0;
}

.hc-block__name {
    font-size: 15px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.01em;
}

.hc-block__scope { font-size: 11.5px; color: var(--text-muted); }

.hc-block__field {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 14px;
}

.hc-block__labels {
    display: flex;
    flex-direction: column;
    line-height: 1.35;
    min-width: 0;
}

.hc-block__label { font-size: 14px; font-weight: var(--font-weight-semibold); }
.hc-block__bounds { font-size: 11.5px; color: var(--text-muted); }
.hc-block__stepper { margin-left: auto; flex: none; }

/* Translating the abstract index into what the player actually plays off. */
.hc-block__plays {
    padding: 11px 14px;
    border-top: 1px solid var(--hairline-soft);
    background: var(--metal-wash-05);
    font-size: 12.5px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

.hc-block__result {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    padding: 12px 14px;
    border-top: 1px solid var(--hairline-soft);
    background: var(--metal-wash-05);
    font-variant-numeric: tabular-nums;
}

.hc-block__resultsum { font-size: 12.5px; color: var(--text-muted); }

.hc-block__resultfig {
    font-size: 22px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.025em;
}

.hc-block__resultplays { margin-left: auto; font-size: 11.5px; color: var(--text-muted); }

.hc-amber {
    display: flex;
    align-items: flex-start;
    gap: 9px;
    margin: 0 18px 14px;
    padding: 10px 12px;
    border: 1px solid var(--hc-warn-line);
    border-radius: var(--radius-lg);
    background: var(--hc-warn-tint);
    font-size: 11.5px;
    line-height: 1.5;
    color: var(--text-muted);
    text-wrap: pretty;
}

.hc-amber .material-symbols-outlined {
    flex: none;
    margin-top: 1px;
    font-size: 16px;
    color: var(--warning);
}

/* Neither sheet is destructive, so neither goes through ConfirmSheet — but the primary still
   carries the value it will write ("Seed 14.0"), which is what makes the tap safe without one. */
.hc-sheet__actions {
    display: flex;
    gap: 9px;
    padding: 0 18px 18px;
}

.hc-sheet__actions .hc-btn,
.hc-sheet__actions .hc-primary {
    flex: 1;
    justify-content: center;
    height: 46px;
    border-radius: var(--radius-lg);
    font-size: 14px;
    font-weight: var(--font-weight-semibold);
}

.hc-sheet__actions .hc-primary { flex: 1.4; }

/* ── ≤1000px: drop the two columns the history page already answers ──────────────────────── */

@media (max-width: 1000px) {
    .hc-board__head,
    .hc-row { grid-template-columns: minmax(150px, 1fr) 84px 92px 108px 116px 34px; }

    .hc-col--low,
    .hc-col--rounds { display: none; }

    .hc-ident { grid-template-columns: minmax(0, 1fr); }
    .hc-chartpane { border-left: none; border-top: 1px solid var(--hairline); }
    .hc-eq { flex-wrap: wrap; }
    .hc-eq__use { flex: 1 1 100%; border-left: none; border-top: 1px solid var(--metal-edge); }

    .hc-rail { display: none; }
    .hc-summary { display: flex; }
}

/* ── ≤768px: the phone layouts ───────────────────────────────────────────────────────────── */

@media (max-width: 768px) {
    .hc-page { gap: 12px; }
    .hc-title { font-size: 19px; }

    /* Scope moves to the scrollable .view-pills row (18-leaderboard.css) below the title. */
    .hc-controls__scope { display: none; }

    /* The amber pill is the one scope chip that carries a hue, because it is the one that says
       something is wrong. */
    .view-pill--warn {
        background: var(--hc-warn-wash);
        color: var(--hc-warn-ink);
        font-weight: var(--font-weight-semibold);
    }

    .hc-attn__head { padding: 11px 14px; }
    .hc-attn__why { display: none; }
    .hc-attn__all { font-size: 12px; }

    /* The reason moves onto the sub-line — three columns don't fit, and the reason is the row. */
    .hc-attn__row {
        grid-template-columns: 26px minmax(0, 1fr) auto;
        column-gap: 10px;
        padding: 10px 14px;
    }

    .hc-attn__who { display: contents; }
    .hc-avatar {
        width: 26px;
        height: 26px;
        font-size: 11px;
        grid-column: 1;
        grid-row: 1 / span 2;
    }

    .hc-attn__name {
        grid-column: 2;
        font-size: 14.5px;
    }

    .hc-attn__reason {
        grid-column: 2;
        grid-row: 2;
        font-size: 11px;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }

    .hc-attn__row .hc-btn {
        grid-column: 3;
        grid-row: 1 / span 2;
        padding: 6px 10px;
        font-size: 12px;
    }

    /* Board: name + sub · sparkline · index over delta. Low, Rounds and Source drop; Source
       survives inside the sub-line, which is where it was most useful anyway. */
    .hc-board__head,
    .hc-row {
        grid-template-columns: minmax(0, 1fr) 56px 74px;
        column-gap: 10px;
    }

    .hc-board__head { padding: 9px 14px; font-size: 10px; }
    .hc-row { padding: 11px 14px; }

    .hc-col--low,
    .hc-col--rounds,
    .hc-col--source,
    .hc-col--kebab { display: none; }

    .hc-name { font-size: 15px; }
    .hc-sub { font-size: 11px; }
    .hc-spark { height: 20px; }

    /* Index over delta in one right-hand cell — placement rather than a second DOM form, since
       the two figures are the same two figures. */
    .hc-player,
    .hc-spark { grid-row: 1 / span 2; }
    .hc-player { grid-column: 1; }
    .hc-spark { grid-column: 2; }
    .hc-idx { grid-column: 3; grid-row: 1; font-size: 18px; }
    .hc-delta { grid-column: 3; grid-row: 2; font-size: 11px; }

    /* The header is one row, so it places its three surviving cells by column. */
    .hc-board__head .hc-col--player { grid-column: 1; }
    .hc-board__head .hc-col--spark { grid-column: 2; text-align: center; }
    .hc-board__head .hc-col--index { grid-column: 3; }
    .hc-col--delta { display: none; }

    .hc-foot { padding: 11px 14px; font-size: 12px; }

    /* Identity card stacks; the index leads at phone scale. */
    .hc-ident__main { padding: 16px 16px 14px; }
    .hc-tile { width: 44px; height: 44px; border-radius: 12px; font-size: 15px; }
    .hc-ident__name { font-size: 22px; }
    .hc-ident__chips { display: none; }

    .hc-eq { display: none; }

    .hc-mindex {
        display: flex;
        align-items: flex-end;
        gap: 12px;
        margin-top: 16px;
    }

    .hc-mindex__fig {
        font-size: 46px;
        font-weight: var(--font-weight-bold);
        letter-spacing: -0.04em;
        line-height: 0.95;
        font-variant-numeric: tabular-nums;
    }

    .hc-mindex__side {
        display: flex;
        flex-direction: column;
        line-height: 1.35;
        padding-bottom: 4px;
        min-width: 0;
    }

    .hc-mindex__label {
        font-size: 11.5px;
        font-weight: var(--font-weight-bold);
        letter-spacing: 0.1em;
        text-transform: uppercase;
        color: var(--metal);
    }

    .hc-mindex__sum { font-size: 12px; color: var(--text-muted); font-variant-numeric: tabular-nums; }

    .hc-mplays { margin-top: var(--space-2); font-size: 12px; color: var(--text-muted); }

    .hc-chartpane {
        padding: 0 16px 14px;
        border-top: none;
        background: none;
    }

    .hc-chartpane__top { display: none; }
    .hc-chart { margin-top: 14px; }
    .hc-chart__note { display: none; }

    /* Three cells at 390px, whatever the page asked for. Setting the template directly (rather
       than the custom property, which the page sets inline and would therefore win) and dropping
       the fourth cell — which only exists when a cap applied, and Caps is the one worth keeping. */
    .hc-idfoot { grid-template-columns: repeat(3, 1fr); }
    .hc-idfoot__cell:nth-child(4) { display: none; }
    .hc-idfoot__cell { padding: 10px 12px; }
    .hc-idfoot__label { font-size: 9.5px; letter-spacing: 0.1em; }
    .hc-idfoot__fig { font-size: 15px; }
    .hc-idfoot__word { font-size: 13px; }

    /* The adjustment card becomes a row on the identity card, opening the sheet. */
    .hc-adjustcard { display: none; }
    .hc-adjustrow { display: flex; }

    /* Timeline: date · index · change, behind a disclosure. Folding is a class on the card rather
       than a render gate, so the desktop table above isn't folded by the same flag. */
    .hc-disclose { display: block; }
    .hc-card:not(.hc-tl--open) .hc-tl__head,
    .hc-card:not(.hc-tl--open) .hc-tl__row { display: none; }

    .hc-tl__head,
    .hc-tl__row {
        grid-template-columns: minmax(0, 1fr) 74px 74px;
        column-gap: 10px;
        padding-left: 14px;
        padding-right: 14px;
    }

    .hc-tl__col--low,
    .hc-tl__col--rounds,
    .hc-tl__col--src,
    .hc-tl__col--trigger { display: none; }

    .hc-head { padding: 11px 14px; }
    .hc-head__end { display: none; }

    /* Scoring record: course + "date · AGS · holes" · a diff stack · a check tile or "dropped". */
    .hc-rec__head { display: none; }

    .hc-rec__row {
        grid-template-columns: minmax(0, 1fr) 68px 62px;
        column-gap: 10px;
        padding: 11px 14px;
    }

    .hc-rec__date,
    .hc-rec__ags,
    .hc-rec__cr,
    .hc-rec__holes { display: none; }

    .hc-rec__name { font-size: 14.5px; }
    .hc-rec__sub { display: none; }
    .hc-rec__msub { display: block; }

    .hc-rec__course { grid-column: 1; grid-row: 1 / span 2; }
    .hc-rec__diff { grid-column: 2; grid-row: 1; }
    .hc-rec__difflabel { display: block; grid-column: 2; grid-row: 2; }
    .hc-rec__counts { grid-column: 3; grid-row: 1 / span 2; }

    /* The pill becomes a tile — at 62px the word doesn't fit and the tick carries it. */
    .hc-chip--counts .hc-chip__word { display: none; }

    .hc-chip--counts {
        justify-content: center;
        width: 26px;
        height: 26px;
        padding: 0;
        border-radius: var(--radius-md);
    }

    .hc-chip--counts .material-symbols-outlined { font-size: 15px; }
}

/* Above the phone breakpoint the phone-only cells stay out of the DOM's way. Both forms are
   rendered — a blanket display:block would flatten the grids, the call .wager-desktop /
   .cm-scorecard already make. */
@media (min-width: 769px) {
    .hc-mindex,
    .hc-mplays { display: none; }
    .hc-narrowonly { display: none; }
}

@media (max-width: 768px) {
    .hc-wideonly { display: none; }
}

@media (prefers-reduced-motion: reduce) {
    .hc-row,
    .hc-btn,
    .hc-iconbtn,
    .hc-primary { transition: none; }
}
/* ══ 22 · League — Teams, Schedule, Sub Pool, Backsheet, Matchup detail ═══════════════════════
   The four League destinations (the `League` group in EventNav.AdminGroups) plus the matchup
   detail a schedule pairing chip links to. They were the last event-scoped screens rendering
   .page-title + .settings-card + .data-table from 03-tables-badges.css and 07-settings.css; this
   partial carries them into the language the leaderboard (18), the result tabs (19), the courses
   screens (20) and the handicaps screens (21) speak.
   Source: handoffs/design_handoff_league_pages (screens 1a–1e).

   Filed as 22-, not the handoff's 20-: 20-courses.css and 21-handicaps.css already exist. The
   requirement was "after 19-result-tabs.css", which this satisfies. It also lands after
   13-controls-overlays.css, so .lg-sheet needs none of the .modal-panel.pm-sheet specificity
   trick 09-players-courses.css does.

   Five rules the whole block obeys, from src/GolfTracker.UI/CLAUDE.md:

   · --metal-* means STANDING — position, the week you're on, the eyebrows framing standing, the
     team leading a matchup. --color-accent means LIVE OR MONEY. --under-par means under par.
     --warning amber is the one extension and it is confined to A ROSTER PROBLEM THE COMMISSIONER
     MUST FIX (an open seat, a missing A-slot, an unpaired position night, an adjusted matchup).
     It is warning semantics, not a fourth decorative hue. Nothing else here gets a colour.
   · Elevation, not boxes: --surface-raised on --page-ground, 1px --hairline, --radius-xl,
     --shadow-lg. Dividers inside are --hairline-soft. Sub-cards on phone drop to 14px radius.
   · Boards are CSS grids, never <table>. Every figure is tabular-nums.
   · Every state says what it is in words — "Open seat", "No A-slot", "Position night",
     "not measured", "Never used" — never a bare em dash and never a colour alone.
   · Admin gets no visual downgrade. Same quality bar as the leaderboard.

   Prefix is .lg-* for anything more than one screen uses, then .lt- (Teams), .ls- (Schedule),
   .sp- (Sub Pool), .bs- (Backsheet) and .md- (Matchup detail). Sub-grid hairlines and the
   design's measured card paddings are the only raw-px spacing, matching 19/20/21.

   The print sheet at the foot of this file is the ONE place that leaves the token set, and it is
   deliberate: metal and green do not print legibly on a clubhouse laser printer and carry no
   meaning in monochrome, so the printed backsheet earns hierarchy from weight and rule instead. */

/* Local ink on a TINT of amber — the same shape .cm-page, .set-page and .hc-page use. At #f39c12
   the hue on its own 12% wash lands about 2.4:1 in light mode, so the ink darkens to the #a86a05
   the design draws. In dark mode the hue is already brightened for a dark ground and darkening it
   would be exactly backwards. Declared on the sheet too, which renders outside the page. */
.lg-page,
.lg-card,
.lg-sheet {
    --lg-warn-wash: rgba(243, 156, 18, 0.12);
    --lg-warn-tint: rgba(243, 156, 18, 0.05);
    --lg-warn-line: rgba(243, 156, 18, 0.34);
    --lg-warn-edge: rgba(243, 156, 18, 0.38);
    --lg-warn-ink: #a86a05;

    /* The live tier, identical to .mh-livepill's — a chip that says "being played right now"
       must be the same chip on the masthead, the schedule and a matchup. */
    --lg-live-wash: color-mix(in srgb, var(--color-accent) 12%, transparent);
    --lg-live-soft: color-mix(in srgb, var(--color-accent) 10%, transparent);
    --lg-live-line: color-mix(in srgb, var(--color-accent) 30%, transparent);
    --lg-live-ink: #2f8a48;
}

:root[data-theme="dark"] :is(.lg-page, .lg-card, .lg-sheet) {
    --lg-warn-ink: var(--warning);
    --lg-live-ink: var(--color-accent);
}

/* ── Page frame ──────────────────────────────────────────────────────────────────────────── */

.lg-page {
    display: flex;
    flex-direction: column;
    gap: 14px;
    min-width: 0;
}

/* Page head: the masthead carries the EVENT name, so this names the page, states the rule that
   governs it, and puts the actions right. */
.lg-head {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    flex-wrap: wrap;
}

.lg-title {
    margin: 0;
    font-size: 22px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.02em;
}

.lg-headnote {
    font-size: 13px;
    color: var(--text-muted);
    min-width: 0;
}

.lg-head__end {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex: none;
}

/* Every panel on all five screens. */
.lg-card {
    background: var(--surface-raised);
    border: 1px solid var(--hairline);
    border-radius: var(--radius-xl);
    box-shadow: var(--shadow-lg);
    overflow: hidden;
    min-width: 0;
}

.lg-card--warn { border-color: var(--lg-warn-edge); }
.lg-card--metal { border-color: var(--metal-edge); }

/* A card's head: eyebrow · hairline rule · a plain sentence · an optional right-hand legend. */
.lg-cardhead {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    padding: 13px 20px;
    border-bottom: 1px solid var(--hairline);
}

.lg-cardhead--metal { background: var(--metal-wash-05); }

.lg-eyebrow {
    flex: none;
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--metal);
}

/* Quiet variant: an eyebrow that labels something which is NOT a standing (money leaders, skins,
   the override panel) doesn't get to borrow the metal. */
.lg-eyebrow--quiet { color: var(--text-quiet); }

.lg-rule {
    flex: none;
    width: 1px;
    height: 12px;
    background: var(--metal-line);
}

.lg-rule--quiet { background: var(--hairline); }

.lg-cardnote { font-size: 13px; color: var(--text-muted); }

.lg-cardhead__end {
    margin-left: auto;
    font-size: 11.5px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

.lg-strong {
    color: var(--text);
    font-weight: var(--font-weight-semibold);
}

/* The sentence a card closes on, over the metal wash and behind a metal edge. */
.lg-foot {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    padding: 12px 20px;
    border-top: 1px solid var(--metal-edge);
    background: var(--metal-wash-05);
    font-size: 12.5px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

.lg-foot__end { margin-left: auto; }

/* ── Stat rail: four cells, cell 1 grounded when it frames a standing ─────────────────────── */

.lg-rail { display: grid; grid-template-columns: repeat(4, 1fr); }
.lg-rail--3 { grid-template-columns: repeat(3, 1fr); }

.lg-rail__cell {
    padding: 16px 20px 18px;
    border-left: 1px solid var(--hairline);
    min-width: 0;
}

.lg-rail__cell:first-child { border-left: none; }

.lg-rail__cell--lead { background: var(--metal-wash-05); }
.lg-rail__cell--lead .lg-rail__label { color: var(--metal); }

.lg-rail__label {
    display: block;
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

.lg-rail__fig {
    display: block;
    margin: var(--space-2) 0 var(--space-1);
    font-size: 27px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.03em;
    font-variant-numeric: tabular-nums;
    color: var(--text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* A cell whose value is a NAME rather than a count — the backsheet's low net. Same slot, lighter
   weight, no tabular figures, because a name is not a number. */
.lg-rail__name {
    display: block;
    margin: var(--space-2) 0 var(--space-1);
    font-size: 22px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.02em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.lg-rail__fig--money { color: var(--color-accent); }
.lg-rail__fig--live { color: var(--color-accent); }
.lg-rail__fig--warn { color: var(--warning); }
.lg-rail__fig--none { color: var(--ink-disabled); }

.lg-rail__sub {
    display: block;
    font-size: 11.5px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

/* Below 1000px four 27px figures don't survive side by side; the same facts read fine as one
   line and the board underneath carries the detail. Same call .hc-summary makes. */
.lg-summary {
    display: none;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
    padding: 12px 16px;
    font-size: 12.5px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

/* ── Buttons: the .board-manage shape, so a control here and one on the leaderboard can't drift ─ */

.lg-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 7px 11px;
    border-radius: 9px;
    border: 1px solid var(--control-fill-strong);
    background: var(--control-fill);
    color: var(--text);
    font-family: inherit;
    font-size: 12.5px;
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
    transition: background 0.14s ease;
}

.lg-btn .material-symbols-outlined { font-size: 16px; color: var(--text-quiet); }
.lg-btn:hover { background: var(--control-fill-strong); }
.lg-btn:disabled { opacity: 0.55; cursor: default; }
.lg-btn--strong { font-weight: var(--font-weight-semibold); }

/* THE metal primary, and the one new button treatment the handoff introduces. It is what a green
   primary would be on a money screen, moved to the hue that means "this is the record of record" —
   adding a team is not a payout. --on-solid rather than --on-hue: the metal ramp does not brighten
   the way --color-accent and --danger do, and white is right on it in both themes. */
.lg-btn--metal {
    border-color: var(--metal-strong);
    background: var(--metal);
    color: var(--on-solid);
    font-weight: var(--font-weight-semibold);
}

.lg-btn--metal .material-symbols-outlined { color: var(--on-solid); }
.lg-btn--metal:hover { background: var(--metal-strong); }

/* A row-level ghost, smaller than .lg-btn — the sub board's Edit / Save / Cancel. */
.lg-btn--sm {
    padding: 6px 10px;
    border-radius: var(--radius-md);
    font-size: 12px;
    font-weight: var(--font-weight-semibold);
}

/* ── Pills: one family, five states, and every one of them says a word ────────────────────── */

.lg-pill {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 3px 9px;
    border-radius: var(--radius-pill);
    border: 1px solid transparent;
    font-size: 10.5px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    white-space: nowrap;
    transition: background 0.14s ease;
}

.lg-pill--final,
.lg-pill--neutral {
    background: var(--control-fill);
    color: var(--text-muted);
}

.lg-pill--sched {
    background: transparent;
    border-color: var(--hairline);
    color: var(--text-quiet);
}

.lg-pill--live {
    background: var(--lg-live-wash);
    border-color: var(--lg-live-line);
    color: var(--lg-live-ink);
}

.lg-pill--warn {
    background: var(--lg-warn-wash);
    border-color: var(--lg-warn-line);
    color: var(--lg-warn-ink);
}

.lg-pill--metal {
    background: var(--metal-wash-10);
    border-color: var(--metal-line);
    color: var(--metal-strong);
}

/* The pulsing dot. Rides the leaderboard's existing 1.6s winprob-pulse so a live chip beats at the
   same rate everywhere; settlement views (Teams, Sub Pool, Backsheet) never render one. */
.lg-dot {
    flex: none;
    width: 6px;
    height: 6px;
    border-radius: var(--radius-pill);
    background: var(--color-accent);
    animation: winprob-pulse 1.6s ease-in-out infinite;
}

/* ── Position tile: the podium taper, shared by both backsheet season boards ──────────────── */

.lg-pos {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    border-radius: var(--radius-md);
    font-size: 12.5px;
    font-weight: var(--font-weight-bold);
    font-variant-numeric: tabular-nums;
    background: transparent;
    color: var(--text-muted);
}

.lg-pos--1 { background: var(--metal-wash-18); color: var(--metal-strong); }
.lg-pos--2 { background: var(--metal-wash-10); color: var(--metal); }
.lg-pos--3 { background: var(--metal-wash-07); color: var(--metal-dim); }

/* ── Avatar (Sub Pool, and the backsheet's sub roster) ────────────────────────────────────── */

.lg-avatar {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    border-radius: var(--radius-pill);
    background: var(--control-fill);
    color: var(--text-quiet);
    font-size: 11.5px;
    font-weight: var(--font-weight-bold);
}

/* ── Hover: never a blue tint ────────────────────────────────────────────────────────────── */

.lg-hover { transition: background 0.14s ease; }
.lg-hover:hover { background: color-mix(in srgb, var(--text) 3%, transparent); }

/* ══ 1a · League Teams ════════════════════════════════════════════════════════════════════ */

.lt-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 14px;
}

.lt-card {
    background: var(--surface-raised);
    border: 1px solid var(--hairline);
    border-radius: var(--radius-xl);
    box-shadow: var(--shadow-lg);
    overflow: hidden;
    min-width: 0;
}

/* A team with an open seat or no A-slot. Amber on the border and a 5% head wash — enough to find
   from across the grid, not enough to read as an error state. */
.lt-card--warn { border-color: var(--lg-warn-edge); }
.lt-card--warn .lt-card__head { background: var(--lg-warn-tint); }

/* Deactivated is NOT amber: ending a team is a legitimate end state, not a fault. */
.lt-card--off { opacity: 0.62; }
.lt-card--off .lt-card__head { background: var(--control-fill); }
.lt-card--off .lt-num { background: var(--control-fill); color: var(--ink-disabled); }

.lt-card__head {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 12px 14px;
    border-bottom: 1px solid var(--hairline);
}

.lt-num {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    border-radius: 9px;
    font-size: 14.5px;
    font-weight: var(--font-weight-bold);
    font-variant-numeric: tabular-nums;
    background: var(--metal-wash-10);
    color: var(--metal-strong);
}

.lt-name {
    flex: 1;
    min-width: 0;
    font-size: 16px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.01em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.lt-flag {
    flex: none;
    padding: 2px 8px;
    font-size: 9.5px;
    letter-spacing: 0.08em;
}

/* Row-level overflow trigger — the card head's ⋯ and the one on a player row. A card is
   overflow:hidden, so an open panel lifts the clip, the same trick .set-card:has(…) and
   .app-bar:has(…) use. */
.lg-rowmenu {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    border: none;
    border-radius: var(--radius-md);
    background: none;
    color: var(--text-quiet);
    cursor: pointer;
}

.lg-rowmenu:hover { background: var(--control-fill); color: var(--text-muted); }
.lg-rowmenu .material-symbols-outlined { font-size: 18px; }

.lt-kebab { flex: none; display: inline-flex; }
.lt-card:has(.overflow-menu__panel) { overflow: visible; }

/* The player row's ⋯ is smaller and only appears when there is something to do with the row. */
.lt-slot .lg-rowmenu { width: 26px; height: 26px; }
.lt-slot .lg-rowmenu .material-symbols-outlined { font-size: 16px; }

.lt-body { padding: 4px 14px 10px; }

.lt-slot {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 9px 0;
    border-bottom: 1px solid var(--hairline-soft);
}

/* An empty seat is a ROW, not an absence — so the card is always the same height and "who is
   missing" is answered by reading, not by counting. */
.lt-slot--add {
    border: none;
    background: none;
    width: 100%;
    padding: 9px 0;
    font-family: inherit;
    text-align: left;
    border-bottom: 1px solid var(--hairline-soft);
    cursor: pointer;
}

.lt-slot__tile {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    border-radius: 7px;
    border: 1px solid transparent;
    background: var(--control-fill);
    color: var(--text-quiet);
    font-size: 11px;
    font-weight: var(--font-weight-bold);
}

/* Only the A tile reads as elevated; both are the same box, which is what makes the difference
   legible as a rank rather than as two unrelated chips. */
.lt-slot__tile--a {
    background: var(--metal-wash-18);
    border-color: var(--metal-line);
    color: var(--metal-strong);
}

.lt-slot__tile--add {
    background: transparent;
    border: 1px dashed var(--metal-line);
    color: var(--metal);
}

.lt-slot__name {
    flex: 1;
    min-width: 0;
    font-size: 14.5px;
    font-weight: var(--font-weight-medium);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.lt-slot__name--a { font-weight: var(--font-weight-semibold); }
.lt-slot__name--add { color: var(--ink-disabled); }

.lt-slot__hcp {
    flex: none;
    font-size: 12px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

.lt-foot {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 9px 0 2px;
    font-size: 11.5px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

/* The fix path. The health rail counts the problem; the card offers the way out of it. */
.lt-fix {
    margin-left: auto;
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 4px 9px;
    border-radius: var(--radius-md);
    border: 1px solid var(--metal-line);
    background: var(--metal-wash-10);
    color: var(--metal-strong);
    font-family: inherit;
    font-size: 11.5px;
    font-weight: var(--font-weight-semibold);
    white-space: nowrap;
    cursor: pointer;
}

.lt-fix:hover { background: var(--metal-wash-16); }

/* Phone roster-health card: one figure, a seats-filled bar, then the two problem counts. The bar
   fill is --metal because how much of the roster is whole is a STANDING, not money. */
.lt-health { padding: 14px 16px 16px; }

.lt-health__fig {
    display: flex;
    align-items: baseline;
    gap: var(--space-2);
    margin-top: var(--space-2);
}

.lt-health__num {
    font-size: 32px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.03em;
    font-variant-numeric: tabular-nums;
}

.lt-health__cap { font-size: 13px; color: var(--text-muted); }

.lt-health__bar {
    display: flex;
    height: 8px;
    border-radius: var(--radius-sm);
    overflow: hidden;
    background: var(--control-fill);
    margin: 12px 0 10px;
}

.lt-health__fill {
    display: block;
    height: 100%;
    background: var(--metal);
}

.lt-health__foot,
.lg-minifoot {
    display: flex;
    justify-content: space-between;
    gap: 10px;
    padding-top: 10px;
    border-top: 1px solid var(--hairline-soft);
    font-size: 11.5px;
    color: var(--text-muted);
}

/* The count that closes a windowed phone list. */
.lg-more {
    font-size: 11.5px;
    color: var(--text-quiet);
    text-align: center;
    padding-top: 2px;
}

/* ══ 1b · League Schedule ═════════════════════════════════════════════════════════════════ */

/* The season as one object, and the answer to "where are we". */
.ls-progress { padding: 16px 20px 18px; }

.ls-progress__head {
    display: flex;
    align-items: baseline;
    gap: 10px;
    flex-wrap: wrap;
}

.ls-progress__from { margin-left: auto; font-size: 12px; color: var(--text-muted); }
.ls-progress__to { font-size: 12px; color: var(--text-muted); }

.ls-bars {
    display: flex;
    gap: 3px;
    margin: 12px 0 10px;
}

.ls-bar {
    flex: 1;
    height: 10px;
    border-radius: 3px;
    background: var(--control-fill-strong);
}

.ls-bar--played { background: var(--metal); }
.ls-bar--live { background: var(--color-accent); box-shadow: 0 0 0 2px var(--lg-live-line); }
/* A future position night is metal-washed so the two unpaired weeks are visible from across the
   room — the one thing on this bar that is neither played nor merely pending. */
.ls-bar--position { background: var(--metal-wash-18); }
.ls-bar--cancelled { background: var(--control-fill); }

.ls-progress__foot {
    display: flex;
    justify-content: space-between;
    gap: 10px;
    font-size: 12px;
    color: var(--text-muted);
}

/* The week list. */
.ls-head,
.ls-row {
    display: grid;
    grid-template-columns: 64px 92px 74px 108px minmax(0, 1fr);
    column-gap: 12px;
    align-items: center;
    padding: 11px 20px;
}

.ls-head {
    border-bottom: 1px solid var(--hairline);
    font-size: 10.5px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

.ls-row { border-bottom: 1px solid var(--hairline-soft); }
.ls-row--live { background: var(--metal-wash-07); }

.ls-week {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: 9px;
    font-size: 13.5px;
    font-weight: var(--font-weight-bold);
    font-variant-numeric: tabular-nums;
    background: var(--control-fill);
    color: var(--text-quiet);
}

.ls-week--played { background: var(--metal-wash-10); color: var(--metal-strong); }
/* Tonight is the one solid tile on the screen. */
.ls-week--live { background: var(--metal); color: var(--on-solid); }

.ls-date {
    font-size: 13.5px;
    font-variant-numeric: tabular-nums;
    color: var(--text);
}

.ls-date--future { color: var(--text-quiet); }
.ls-side { font-size: 12px; color: var(--text-muted); }

.ls-chips {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 5px;
    min-width: 0;
}

/* A pairing chip. Putting the result ON the chip is what turns the season table into a season
   record — the week list stops being a list of dates and becomes what happened. */
.ls-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    height: 24px;
    padding: 0 8px;
    border-radius: 7px;
    border: 1px solid transparent;
    background: var(--control-fill);
    color: var(--text);
    font-size: 11.5px;
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
    text-decoration: none;
    white-space: nowrap;
    transition: background 0.14s ease;
}

.ls-chip:hover { background: var(--control-fill-strong); color: var(--text); }

.ls-chip--live {
    background: var(--lg-live-soft);
    border-color: var(--lg-live-line);
    color: var(--lg-live-ink);
}

.ls-chip--live:hover { color: var(--lg-live-ink); }

.ls-chip--future {
    background: transparent;
    border-color: var(--hairline);
    color: var(--text-muted);
}

.ls-chip--future:hover { color: var(--text-muted); }

.ls-chip__score { font-weight: var(--font-weight-bold); color: var(--text-muted); }
.ls-chip__score--won { color: var(--metal-strong); }

.ls-posnote { font-size: 11.5px; color: var(--text-muted); }
.ls-nochips { font-size: 11.5px; color: var(--text-quiet); }

/* ── 1b · Import the season ──────────────────────────────────────────────────────────────── */

.ls-import__head {
    padding: 18px 22px 14px;
    border-bottom: 1px solid var(--hairline);
}

.ls-import__title {
    margin: 7px 0 0;
    font-size: 20px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.02em;
}

.ls-import__desc {
    margin: 5px 0 0;
    font-size: 13px;
    line-height: 1.55;
    color: var(--text-muted);
    max-width: 640px;
    text-wrap: pretty;
}

.ls-code {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 12px;
    background: var(--control-fill);
    padding: 1px 5px;
    border-radius: var(--radius-sm);
}

.ls-import__body {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 300px;
}

.ls-import__left { padding: 16px 22px 18px; min-width: 0; }

.ls-import__label {
    font-size: 10.5px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-quiet);
    margin: 15px 0 8px;
}

/* Monospace at 1.9 line-height so a pasted grid stays legible AS a grid — the single change that
   makes a 23-row paste checkable before it is committed. */
.ls-textarea {
    display: block;
    width: 100%;
    box-sizing: border-box;
    border: 1px solid var(--control-fill-strong);
    border-radius: var(--radius-lg);
    background: var(--control-fill);
    color: var(--text);
    padding: 13px 15px;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 12.5px;
    line-height: 1.9;
    resize: vertical;
}

.ls-textarea:focus-visible {
    outline: none;
    border-color: color-mix(in srgb, var(--color-accent) 55%, transparent);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-accent) 13%, transparent);
}

.ls-import__actions {
    display: flex;
    gap: 9px;
    margin-top: 14px;
}

.ls-import__actions .lg-btn { padding: 10px 16px; border-radius: var(--radius-lg); font-size: 13.5px; }

/* The parse preview. A FAILURE renders in this same panel, in --under-par, with the parser's own
   message verbatim — it replaced a .form-error stacked under the card, which said the same thing
   nowhere near the thing it was about. */
.ls-preview {
    padding: 16px 20px 18px;
    border-left: 1px solid var(--hairline);
    background: var(--metal-wash-05);
    min-width: 0;
}

.ls-preview__fig {
    display: flex;
    align-items: baseline;
    gap: var(--space-2);
    margin-top: 10px;
}

.ls-preview__num {
    font-size: 27px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.03em;
    font-variant-numeric: tabular-nums;
    color: var(--color-accent);
}

.ls-preview__num--bad { color: var(--under-par); }
.ls-preview__cap { font-size: 13px; color: var(--text-muted); text-wrap: pretty; }

.ls-preview__rows {
    display: flex;
    flex-direction: column;
    gap: 9px;
    margin-top: 14px;
    padding-top: 13px;
    border-top: 1px solid var(--hairline-soft);
    font-size: 12.5px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

.ls-preview__row { display: flex; justify-content: space-between; gap: 10px; }

.ls-preview__note {
    margin-top: 14px;
    padding-top: 13px;
    border-top: 1px solid var(--metal-edge);
    font-size: 11.5px;
    line-height: 1.6;
    color: var(--text-muted);
    text-wrap: pretty;
}

/* Phone "Up next" card. */
.ls-next { padding: 14px 16px 16px; }

.ls-next__fig {
    display: flex;
    align-items: baseline;
    gap: 9px;
    margin-top: var(--space-2);
    flex-wrap: wrap;
}

.ls-next__num {
    font-size: 32px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.03em;
    font-variant-numeric: tabular-nums;
}

.ls-next__meta { font-size: 12.5px; color: var(--text-muted); margin-top: var(--space-1); }
.ls-next .ls-bars { gap: 2px; }
.ls-next .ls-bar { height: 8px; border-radius: 2px; }

/* Phone week card. */
.ls-mcard { padding: 12px 14px 13px; }

.ls-mcard__head {
    display: flex;
    align-items: center;
    gap: 9px;
}

.ls-mcard__date {
    font-size: 14.5px;
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
}

.ls-mcard__head .lg-pill { margin-left: auto; }
.ls-mcard .ls-chips { margin-top: 10px; }
.ls-mcard .ls-week { width: 26px; height: 26px; border-radius: var(--radius-md); font-size: 13px; }

/* ══ 1c · Sub Pool ════════════════════════════════════════════════════════════════════════ */

.sp-head,
.sp-row {
    display: grid;
    grid-template-columns: minmax(160px, 1fr) 150px 116px 128px 92px 146px;
    column-gap: 14px;
    align-items: center;
    padding: 12px 20px;
}

.sp-head {
    padding: 11px 20px;
    border-bottom: 1px solid var(--hairline);
    font-size: 10.5px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

.sp-row { border-bottom: 1px solid var(--hairline-soft); }
.sp-row--lead { background: var(--metal-wash-05); }

.sp-who {
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
}

.sp-name {
    font-size: 15.5px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.01em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.sp-phone {
    font-size: 13px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* The column that earns the redesign: the figure over the micro-caps line naming where it came
   from. Two subs showing the same number are not the same sub if one of them is derived. */
.sp-plays {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    line-height: 1.3;
    text-align: right;
}

.sp-idx {
    font-size: 16px;
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
    color: var(--text);
}

.sp-idx--none { color: var(--ink-disabled); }

.sp-src {
    font-size: 10.5px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

/* Metal ONLY on the USGA source: which of the two numbers is the real one is the closest thing on
   this screen to a standing. The derived line stays quiet. */
.sp-src--usga { color: var(--metal); }

.sp-last {
    font-size: 12.5px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

.sp-scores {
    text-align: right;
    font-size: 14px;
    font-variant-numeric: tabular-nums;
    color: var(--text);
}

.sp-scores--zero { color: var(--ink-disabled); }

.sp-actions {
    display: flex;
    justify-content: flex-end;
    gap: 6px;
}

/* Inline edit keeps the row where it is and moves nothing below it — the stepper sits in the
   Plays-off cell on a metal-lined field, and column 6 is 146px so Save + Cancel both fit.

   The --mini variant carries its own border and ground, so the metal tint goes on the component
   root rather than on __row. At 32 + 34 + 32 plus its padding it lands just inside the 116px
   Plays-off column, which is why that column keeps its width when the row flips to editing. */
.sp-editfield .stepper-field--mini {
    border-color: var(--metal-line);
    background: var(--metal-wash-05);
}

.sp-editfield .stepper-field__number { color: var(--metal-strong); }

/* Phone sub card. */
.sp-mcard { padding: 12px 14px 13px; }

.sp-mcard__top {
    display: flex;
    align-items: center;
    gap: 10px;
}

.sp-mcard__names {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    line-height: 1.3;
}

.sp-mcard__plays {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    line-height: 1.25;
    flex: none;
}

.sp-mcard__plays .sp-idx { font-size: 17px; font-weight: var(--font-weight-bold); }
.sp-mcard__plays .sp-src { font-size: 9.5px; }

.sp-mcard__foot {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 11px;
    padding-top: 10px;
    border-top: 1px solid var(--hairline-soft);
    font-size: 11.5px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

.sp-mcard__foot .lg-btn { margin-left: auto; }

/* ══ 1d · Backsheet ═══════════════════════════════════════════════════════════════════════ */

/* The control row. The week SheetSelect became a RoundPills strip — the league already thinks in
   weeks, and a dropdown to change week on a page whose whole subject is one week is a tap too
   many. .lg-weekstrip re-chromes the shared picker rather than forking it, the same call
   .rt-controls .round-pills makes. */
.bs-controls {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    flex-wrap: wrap;
}

.lg-weekstrip { min-width: 0; }

.lg-weekstrip .round-pills { margin: 0; }

.lg-weekstrip .round-pills ul {
    display: flex;
    gap: 3px;
    padding: 3px;
    margin: 0;
    list-style: none;
    border-radius: var(--radius-lg);
    background: var(--control-fill);
    overflow-x: auto;
}

.lg-weekstrip .round-pills li {
    padding: 5px 11px;
    border: none;
    border-radius: 7px;
    background: none;
    font-size: 12px;
    font-weight: var(--font-weight-medium);
    color: var(--text-muted);
    white-space: nowrap;
    cursor: pointer;
}

.lg-weekstrip .round-pills li.active {
    background: var(--control-fill-strong);
    color: var(--text);
    font-weight: var(--font-weight-semibold);
}

.bs-controls__end {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex: none;
}

/* Matchups — the main object of the screen. */
.bs-mrow {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 62px 34px 62px minmax(0, 1fr) 168px;
    column-gap: 12px;
    align-items: center;
    padding: 13px 20px;
    border-bottom: 1px solid var(--hairline-soft);
}

.bs-team {
    display: flex;
    align-items: baseline;
    gap: var(--space-2);
    min-width: 0;
}

.bs-team--right { justify-content: flex-start; }

.bs-teamnum {
    flex: none;
    font-size: 12px;
    font-weight: var(--font-weight-bold);
    color: var(--text-quiet);
    font-variant-numeric: tabular-nums;
}

.bs-teamname {
    font-size: 15px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.01em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.bs-pts {
    font-size: 19px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.02em;
    font-variant-numeric: tabular-nums;
    color: var(--text-muted);
}

.bs-pts--a { text-align: right; }
.bs-pts--won { font-weight: var(--font-weight-bold); color: var(--metal-strong); }
.bs-pts--level { color: var(--text); }

.bs-vs {
    text-align: center;
    font-size: 11px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--ink-disabled);
}

.bs-status {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 3px;
}

/* The reason is never hidden — it is the answer to the only question anyone asks about a
   backsheet, which is why an adjusted row prints it under the pill rather than behind a tooltip. */
.bs-reason {
    font-size: 11px;
    color: var(--text-muted);
    text-align: right;
    text-wrap: pretty;
}

/* Two boards side by side: the same object read two ways. */
.bs-boards {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 14px;
}

.bs-brow {
    display: grid;
    grid-template-columns: 34px minmax(0, 1fr) 84px 68px;
    column-gap: 10px;
    align-items: center;
    padding: 9px 18px;
    border-bottom: 1px solid var(--hairline-soft);
}

.bs-brow--lead { background: var(--metal-wash-05); }

.bs-bname {
    display: flex;
    flex-direction: column;
    line-height: 1.3;
    min-width: 0;
}

.bs-bname__name {
    font-size: 14.5px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.01em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.bs-bname__team {
    font-size: 11px;
    color: var(--text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.bs-bfig {
    text-align: right;
    font-size: 17px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.015em;
    font-variant-numeric: tabular-nums;
}

.bs-bfig--money { color: var(--color-accent); }

.bs-btrail {
    text-align: right;
    font-size: 12.5px;
    font-variant-numeric: tabular-nums;
    color: var(--text-muted);
}

/* Tonight's money. */
.bs-skinrow {
    display: grid;
    grid-template-columns: 56px minmax(0, 1fr) 90px 78px;
    column-gap: 10px;
    align-items: center;
    padding: 10px 18px;
    border-bottom: 1px solid var(--hairline-soft);
}

.bs-p3row {
    display: grid;
    grid-template-columns: 56px minmax(0, 1fr) 116px 78px;
    column-gap: 10px;
    align-items: center;
    padding: 10px 18px;
    border-bottom: 1px solid var(--hairline-soft);
}

.bs-hole {
    font-size: 11px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

.bs-player {
    font-size: 14.5px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.01em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.bs-detail {
    text-align: right;
    font-size: 13px;
    font-variant-numeric: tabular-nums;
    color: var(--text-muted);
}

/* A par 3 nobody measured says so, in words, rather than leaving the cell blank. */
.bs-detail--none { color: var(--ink-disabled); }

.bs-amount {
    text-align: right;
    font-size: 15px;
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
    color: var(--color-accent);
}

/* Sub roster on the backsheet is the 1c board minus the availability column. */
.bs-subrow {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 150px 116px 92px;
    column-gap: 14px;
    align-items: center;
    padding: 10px 20px;
    border-bottom: 1px solid var(--hairline-soft);
}

.bs-trophyrow {
    display: grid;
    grid-template-columns: 70px minmax(0, 1fr) 120px 110px;
    column-gap: 12px;
    align-items: center;
    padding: 10px 20px;
    border-bottom: 1px solid var(--hairline-soft);
}

.bs-place {
    font-size: 12.5px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

/* Phone: matchups as two-line cards, the status pill on the second line's third track sized for
   "Adjusted", with the reason beneath. */
.bs-mcard { padding: 11px 15px; border-bottom: 1px solid var(--hairline-soft); }

.bs-mcard__line {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 44px 74px;
    align-items: center;
    gap: 6px;
}

.bs-mcard__line + .bs-mcard__line { margin-top: 3px; }

.bs-mcard__name {
    font-size: 13.5px;
    font-weight: var(--font-weight-semibold);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.bs-mcard__pts {
    text-align: right;
    font-size: 16px;
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
    color: var(--text-muted);
}

.bs-mcard__pts--won { font-weight: var(--font-weight-bold); color: var(--metal-strong); }
.bs-mcard__pts--level { color: var(--text); }
.bs-mcard__slot { text-align: right; }
.bs-mcard__slot .lg-pill { font-size: 9px; padding: 2px 7px; letter-spacing: 0.05em; }
.bs-mcard__reason { font-size: 11px; color: var(--text-muted); margin-top: 5px; }

/* Phone low-net card. */
.bs-low { padding: 14px 16px 15px; }

.bs-low__name {
    font-size: 24px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.02em;
    margin: var(--space-2) 0 3px;
}

.bs-low__meta { font-size: 12.5px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.bs-low__foot { margin-top: 12px; }
.bs-money { color: var(--color-accent); font-weight: var(--font-weight-bold); }

.bs-shortrow {
    display: grid;
    grid-template-columns: 30px minmax(0, 1fr) 56px;
    column-gap: 9px;
    align-items: center;
    padding: 9px 15px;
    border-bottom: 1px solid var(--hairline-soft);
}

.bs-shortrow .lg-pos { width: 24px; height: 24px; border-radius: 7px; font-size: 12px; }

.bs-shortrow__name {
    font-size: 14px;
    font-weight: var(--font-weight-semibold);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.bs-shortrow__fig {
    text-align: right;
    font-size: 16px;
    font-weight: var(--font-weight-bold);
    font-variant-numeric: tabular-nums;
}

/* ══ 1e · Matchup detail ══════════════════════════════════════════════════════════════════ */

.md-head {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    flex-wrap: wrap;
}

.md-head__title {
    margin: 0;
    font-size: 32px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.03em;
    line-height: 1.05;
}

.md-head__meta {
    margin-left: auto;
    font-size: 13px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

.md-hero {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 150px minmax(0, 1fr);
    align-items: center;
    padding: 22px 26px 20px;
}

.md-side {
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-width: 0;
}

.md-side--right { align-items: flex-end; text-align: right; }

.md-side__who {
    display: flex;
    align-items: center;
    gap: 9px;
    min-width: 0;
    max-width: 100%;
}

.md-teamnum {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: 9px;
    background: var(--control-fill);
    color: var(--text-muted);
    font-size: 13.5px;
    font-weight: var(--font-weight-bold);
    font-variant-numeric: tabular-nums;
}

.md-teamnum--lead { background: var(--metal-wash-18); color: var(--metal-strong); }

.md-teamname {
    font-size: 22px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.02em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    min-width: 0;
}

/* The one 52px figure in the app outside the masthead. Metal for the side ahead, muted for the
   side behind, plain --text when level — the score IS the standing. */
.md-points {
    font-size: 52px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.04em;
    line-height: 1;
    font-variant-numeric: tabular-nums;
    color: var(--text-muted);
}

.md-points--lead { color: var(--metal-strong); }
.md-points--level { color: var(--text); }

.md-from { font-size: 12px; color: var(--text-muted); text-wrap: pretty; }

/* An override keeps the same figure and adds the computed one beneath — same information the old
   .overridden-tag carried, put back into the hierarchy. */
.md-override { font-size: 11.5px; color: var(--text-muted); font-variant-numeric: tabular-nums; }

.md-center {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 7px;
}

.md-center__vs {
    font-size: 11px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--ink-disabled);
}

.md-center__rule { width: 1px; height: 52px; background: var(--hairline); }
.md-center__stake { font-size: 11px; color: var(--text-muted); }

.md-herofoot {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    padding: 11px 26px;
    border-top: 1px solid var(--metal-edge);
    background: var(--metal-wash-05);
    font-size: 12.5px;
    color: var(--text-muted);
}

.md-herofoot__end { margin-left: auto; }

.md-slots {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 14px;
}

.md-slot__players {
    font-size: 14px;
    font-weight: var(--font-weight-semibold);
    min-width: 0;
}

.md-slot__v { color: var(--ink-disabled); font-weight: var(--font-weight-medium); }

.md-slot__standing {
    margin-left: auto;
    font-size: 13px;
    font-weight: var(--font-weight-bold);
    color: var(--text-muted);
    white-space: nowrap;
}

.md-slot__standing--lead { color: var(--metal-strong); }

/* The hole strip replaces an eight-column .data-table. Column count comes from C# as --md-holes,
   because a nine-hole league round and an eighteen-hole one are the same component. */
.md-strip {
    display: grid;
    grid-template-columns: repeat(var(--md-holes, 9), 1fr);
    border-bottom: 1px solid var(--hairline-soft);
}

.md-hole {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    padding: 10px 2px 11px;
    border-left: 1px solid var(--hairline-soft);
    min-width: 0;
}

.md-hole:first-child { border-left: none; }
/* A decided hole washes its whole cell, so the shape of the match reads before any number does. */
.md-hole--decided { background: var(--metal-wash-05); }

.md-hole__n {
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.06em;
    color: var(--text-quiet);
}

/* Net is the number shown, because net is what wins the hole. Gross and the stroke given are in
   the cell's title, and the foot line says so in words. */
.md-tile {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    border-radius: var(--radius-md);
    font-size: 13px;
    font-weight: var(--font-weight-medium);
    font-variant-numeric: tabular-nums;
    background: transparent;
    color: var(--text-muted);
}

.md-tile--won { background: var(--metal-wash-18); color: var(--metal-strong); font-weight: var(--font-weight-bold); }
.md-tile--halved { background: var(--control-fill); color: var(--text-muted); font-weight: var(--font-weight-semibold); }

.md-mark { font-size: 11px; color: var(--metal); line-height: 1; }
.md-mark--halved { color: var(--ink-disabled); }

.md-slotfoot {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    padding: 11px 18px;
    font-size: 12px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

.md-slotfoot__end { margin-left: auto; }

/* Low net beside the override panel. */
.md-lower {
    display: grid;
    grid-template-columns: 360px minmax(0, 1fr);
    gap: 14px;
}

.md-net {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 14px 18px;
    border-bottom: 1px solid var(--hairline-soft);
}

.md-net--lead { background: var(--metal-wash-05); }

.md-net__name {
    flex: 1;
    min-width: 0;
    font-size: 15px;
    font-weight: var(--font-weight-semibold);
    color: var(--text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.md-net--lead .md-net__name { color: var(--text); }

.md-net__fig {
    flex: none;
    font-size: 24px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.03em;
    font-variant-numeric: tabular-nums;
    color: var(--text-muted);
}

.md-net--lead .md-net__fig { color: var(--metal-strong); }

/* The override panel is .set-row-shaped — name + caption left, one control right — because it is
   a set of settings, not a form. It writes no layout of its own beyond these three rows. */
.md-arow {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 13px 18px;
    border-bottom: 1px solid var(--hairline-soft);
}

.md-arow__body {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    line-height: 1.3;
}

.md-arow__name { font-size: 14.5px; font-weight: var(--font-weight-semibold); }
.md-arow__cap { font-size: 11.5px; color: var(--text-muted); font-variant-numeric: tabular-nums; }

.md-arow__control {
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: 9px;
}

.md-to { font-size: 11px; color: var(--ink-disabled); }

.md-reason {
    display: flex;
    flex-direction: column;
    gap: 7px;
    padding: 13px 18px;
}

.md-reason__label { font-size: 14.5px; font-weight: var(--font-weight-semibold); }

.md-reason__req {
    font-weight: var(--font-weight-medium);
    color: var(--text-muted);
    font-size: 12px;
}

.md-reason__input {
    display: block;
    width: 100%;
    box-sizing: border-box;
    padding: 11px 12px;
    border: 1px solid var(--control-fill-strong);
    border-radius: var(--radius-lg);
    background: var(--control-fill);
    color: var(--text);
    font-family: inherit;
    font-size: 14px;
}

.md-reason__input:focus-visible {
    outline: none;
    border-color: color-mix(in srgb, var(--color-accent) 55%, transparent);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-accent) 13%, transparent);
}

/* Field validation stays inline, next to the input it is about. */
.md-reason__error { font-size: 12px; color: var(--under-par); }

.md-aactions {
    display: flex;
    gap: 9px;
    padding: 2px 18px 16px;
}

.md-aactions .lg-btn { padding: 10px 16px; border-radius: var(--radius-lg); font-size: 13.5px; }

/* Phone hero. */
.md-mhero {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 60px;
    align-items: center;
    padding: 14px 16px 10px;
}

.md-mhero + .md-mhero { padding: 0 16px 14px; border-bottom: 1px solid var(--hairline-soft); }

.md-mhero__names {
    display: flex;
    flex-direction: column;
    line-height: 1.3;
    min-width: 0;
}

.md-mhero__name {
    font-size: 15.5px;
    font-weight: var(--font-weight-semibold);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.md-mhero__sub { font-size: 11.5px; color: var(--text-muted); }

.md-mhero__pts {
    text-align: right;
    font-size: 34px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.03em;
    font-variant-numeric: tabular-nums;
    color: var(--text-muted);
}

.md-mhero__pts--lead { color: var(--metal-strong); }
.md-mhero__pts--level { color: var(--text); }

.md-mstatus {
    padding: 10px 16px;
    background: var(--metal-wash-05);
    font-size: 11.5px;
    color: var(--text-muted);
}

/* ══ Sheets: .set-card rows inside the app's own .modal-panel ═════════════════════════════ */

/* Grounds the panel on --page-ground so the .set-cards inside read as raised, exactly the shape
   .pm-sheet establishes. 22- concatenates AFTER 13-controls-overlays.css, so these need no
   .modal-panel prefix to win on source order. */
.lg-sheet {
    padding: 0;
    background: var(--page-ground);
    display: flex;
    flex-direction: column;
}

@media (min-width: 481px) {
    .lg-sheet {
        max-width: 520px;
        bottom: 6%;
        max-height: 86vh;
        border-radius: var(--radius-xl);
        box-shadow: var(--shadow-lg);
    }
}

.lg-sheet__head {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 18px 20px 14px;
}

.lg-sheet__title {
    margin: 0;
    font-size: 19px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.02em;
}

.lg-sheet__close {
    margin-left: auto;
    flex: none;
    width: 32px;
    height: 32px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: none;
    border-radius: 10px;
    background: none;
    color: var(--text-quiet);
    cursor: pointer;
}

.lg-sheet__close:hover { background: color-mix(in srgb, var(--text) 5%, transparent); }
.lg-sheet__close .material-symbols-outlined { font-size: 20px; }

.lg-sheet__body {
    flex: 1;
    min-height: 0;
    padding: 0 20px 20px;
    display: flex;
    flex-direction: column;
    gap: 14px;
    overflow-y: auto;
}

/* Actions stack full-width — metal primary over an outline cancel, the primary under the thumb. */
.lg-sheet__actions {
    display: flex;
    flex-direction: column;
    gap: 9px;
}

.lg-sheet__actions .lg-btn {
    justify-content: center;
    height: 46px;
    border-radius: var(--radius-lg);
    font-size: 15px;
    font-weight: var(--font-weight-semibold);
}

.lg-sheet :is(.set-field, .ls-textarea):focus-visible {
    outline: none;
    border-color: color-mix(in srgb, var(--color-accent) 55%, transparent);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-accent) 13%, transparent);
}

/* ══ Responsive — two breakpoints, matching the app ═══════════════════════════════════════ */

/* Both forms of every dual layout are in the DOM and each hides inside its OWN media query: the
   wide form is a grid and a blanket display:block would flatten it. Same call .wager-desktop /
   .wager-phone and the players roster make. */
.lg-narrow { display: none; }

/* Both responsive blocks are scoped to `screen` ON PURPOSE. A US Letter page at 14mm margins has a
   content box around 710px, so an unscoped max-width query would fire when printing and hand the
   clubhouse wall the 390px phone layout — no stat rail, no matchup grid, two-line cards. The print
   sheet at the foot of this file wants the WIDE markup, re-templated. */
@media screen and (max-width: 1000px) {
    .lt-grid { grid-template-columns: repeat(2, 1fr); }
    .md-slots { grid-template-columns: minmax(0, 1fr); }
    .md-lower { grid-template-columns: minmax(0, 1fr); }
    .bs-boards { grid-template-columns: minmax(0, 1fr); }

    /* The schedule drops Side; the sub board drops Phone. Both are recoverable one tap away and
       neither is what the screen is for. */
    .ls-head,
    .ls-row { grid-template-columns: 64px 92px 108px minmax(0, 1fr); }
    .ls-col--side { display: none; }

    .sp-head,
    .sp-row { grid-template-columns: minmax(160px, 1fr) 116px 128px 92px 146px; }
    .sp-col--phone { display: none; }

    .lg-rail { display: none; }
    .lg-summary { display: flex; }

    .ls-import__body { grid-template-columns: minmax(0, 1fr); }
    .ls-preview { border-left: none; border-top: 1px solid var(--hairline); }
}

@media screen and (max-width: 768px) {
    .lg-page { gap: 12px; }

    .lg-head { gap: var(--space-2); }
    .lg-headnote { flex: 1 1 100%; order: 3; }
    .lg-head__end { margin-left: 0; }

    .lg-wide { display: none; }
    .lg-narrow { display: block; }

    /* Cards stack one per row at 14px radius — the phone form of every board on these screens. */
    .lt-grid { grid-template-columns: minmax(0, 1fr); gap: 10px; }
    .lt-card { border-radius: 14px; box-shadow: var(--shadow-md); }
    .lt-card__head { padding: 11px 13px; border-bottom-color: var(--hairline-soft); }
    .lt-num { width: 26px; height: 26px; border-radius: var(--radius-md); font-size: 13px; }
    .lt-name { font-size: 15px; }
    .lt-body { padding: 2px 13px 9px; }
    .lt-slot,
    .lt-slot--add { gap: 9px; padding: 8px 0; }
    .lt-slot__tile { width: 20px; height: 20px; border-radius: 6px; font-size: 10.5px; }
    .lt-slot__name { font-size: 14px; }

    .lg-card { border-radius: 14px; }

    .ls-head,
    .sp-head,
    .bs-mrow,
    .bs-brow,
    .bs-skinrow,
    .bs-p3row,
    .bs-subrow,
    .bs-trophyrow,
    .sp-row,
    .ls-row { display: none; }

    .md-hero { grid-template-columns: minmax(0, 1fr); padding: 0; }
    .md-head__title { font-size: 22px; }
    .md-head__meta { margin-left: 0; flex: 1 1 100%; }

    /* The strip compresses rather than splitting: a nine-hole league round is the common case and
       nine cells survive 390px. An eighteen-hole round splits into two nines, exactly as
       .psc-grid--9 does, by re-declaring --md-holes at the call site. */
    .md-hole { gap: 3px; padding: 9px 0 10px; }
    .md-tile { width: 22px; height: 22px; border-radius: 7px; font-size: 11.5px; }
    /* The mark between the two tiles goes; the tiles' own weight already says who won the hole,
       and at 390px nine cells need every pixel. */
    .md-mark { display: none; }

    .lg-sheet__body { padding: 0 16px 16px; }
    .lg-sheet__head { padding: 14px 16px 12px; }
}

/* Everything honours a reduced-motion preference. */
@media (prefers-reduced-motion: reduce) {
    .lg-dot { animation: none; }
    .lg-btn,
    .lg-pill,
    .ls-chip,
    .lg-hover { transition: none; }
}

/* ══ The print sheet ══════════════════════════════════════════════════════════════════════
   US Letter at 96dpi, one page for a 12-team league, and the ONE place this design leaves the
   token set. Metal and green do not print legibly on a clubhouse laser printer and carry no
   meaning in monochrome, so hierarchy here comes from WEIGHT AND RULE, not hue: #1b1f24 text,
   #4b5563 / #6b7280 secondary, #d4d7dc box rules, #e5e7eb / #eef0f2 row rules.

   The masthead and footer are print-only DOM (.bs-printonly). Everything else is the screen's own
   markup re-templated here — duplicating every row into a second DOM would give two places for a
   number to be wrong. page-break-inside: avoid per section is kept from the stylesheet this
   replaces, so a 20-team league breaks BETWEEN sections rather than mid-board. */

.bs-printonly { display: none; }

@media print {
    /* Chrome off. */
    .no-print,
    .masthead,
    .event-shell > .settings-nav,
    .settings-nav,
    .app-bar,
    .bottom-nav,
    .bottom-nav-scrim,
    .dock,
    .toast-host,
    nav,
    header,
    .nav-menu,
    .navmenu,
    .layout-sidebar { display: none !important; }

    body, #app-root { background: #fff !important; }

    .bs-printonly { display: block; }
    .bs-screenonly { display: none !important; }

    /* min-height is what lets the footer's margin-top:auto pin it to the foot of the page. */
    .lg-page {
        gap: 20px;
        min-height: 100vh;
        color: #1b1f24;
        padding: 0;
        font-size: 11.5px;
    }

    /* The phone forms never print — every board prints in its wide form. .lg-wide needs no rule:
       only the screen-scoped ≤768px query hides it, so it keeps its natural display here (which
       matters, because .md-hero.lg-wide is a grid and a blanket `block` would flatten it). */
    .lg-narrow { display: none !important; }

    /* A card stops being a card: no ground, no shadow, no radius. */
    .lg-card,
    .lt-card {
        background: #fff !important;
        border: 1px solid #d4d7dc !important;
        border-radius: 0 !important;
        box-shadow: none !important;
        page-break-inside: avoid;
        break-inside: avoid;
    }

    /* Section labels: black rule under a grey micro-cap, which is what replaces the metal. */
    .lg-cardhead {
        padding: 0 0 5px;
        border-bottom: 1px solid #1b1f24 !important;
        background: none !important;
    }

    .lg-eyebrow,
    .lg-eyebrow--quiet {
        font-size: 9.5px;
        letter-spacing: 0.14em;
        color: #6b7280 !important;
    }

    .lg-rule, .lg-rule--quiet { display: none; }
    .lg-cardnote, .lg-cardhead__end { font-size: 10px; color: #6b7280 !important; }

    .lg-foot {
        border-top: 1px solid #d4d7dc !important;
        background: none !important;
        padding: 6px 2px;
        font-size: 10.5px;
        color: #6b7280 !important;
    }

    .lg-strong { color: #1b1f24 !important; }

    /* The four-up glance strip inside a single box. */
    .lg-rail { display: grid !important; }
    .lg-rail__cell { padding: 9px 12px; border-left: 1px solid #d4d7dc !important; background: none !important; }
    .lg-rail__label { font-size: 8.5px; letter-spacing: 0.13em; color: #6b7280 !important; }
    .lg-rail__fig, .lg-rail__name { margin: 3px 0 0; font-size: 15px; font-weight: 600; color: #1b1f24 !important; letter-spacing: 0; }
    .lg-rail__sub { font-size: 10px; color: #6b7280 !important; }
    .lg-summary { display: none !important; }

    /* Matchups, full width and tighter. */
    .bs-mrow {
        grid-template-columns: minmax(0, 1fr) 44px 22px 44px minmax(0, 1fr) 150px;
        column-gap: 8px;
        padding: 6px 2px;
        border-bottom: 1px solid #e5e7eb !important;
        font-size: 11.5px;
    }

    .bs-teamnum { color: #6b7280 !important; font-size: 11.5px; }
    .bs-teamname { font-size: 11.5px; font-weight: 400; }
    .bs-pts { font-size: 11.5px; font-weight: 700 !important; color: #1b1f24 !important; letter-spacing: 0; }
    .bs-vs { font-size: 9px; color: #9ca3af !important; }
    .bs-status { flex-direction: row; gap: 4px; }
    .bs-reason, .bs-status .lg-pill { font-size: 10px; color: #6b7280 !important; }

    .lg-pill {
        background: none !important;
        border: none !important;
        color: #6b7280 !important;
        padding: 0;
        font-size: 10px;
        letter-spacing: 0.04em;
    }

    .lg-dot { display: none; }

    /* Two season boards side by side, then skins and par 3s side by side. */
    .bs-boards { grid-template-columns: repeat(2, 1fr) !important; gap: 28px; }

    .bs-brow {
        grid-template-columns: 20px minmax(0, 1fr) 46px 56px;
        column-gap: 8px;
        padding: 4.5px 2px;
        border-bottom: 1px solid #eef0f2 !important;
        background: none !important;
        font-size: 11.5px;
    }

    .lg-pos {
        width: auto;
        height: auto;
        background: none !important;
        color: #6b7280 !important;
        font-size: 11.5px;
        font-weight: 400;
        justify-content: flex-start;
    }

    .bs-bname__name { font-size: 11.5px; font-weight: 400; }
    .bs-bname__team { display: none; }
    .bs-bfig { font-size: 11.5px; font-weight: 700; color: #1b1f24 !important; letter-spacing: 0; }
    .bs-btrail { font-size: 11.5px; color: #6b7280 !important; }

    .bs-skinrow { grid-template-columns: 46px minmax(0, 1fr) 52px 52px; }
    .bs-p3row { grid-template-columns: 46px minmax(0, 1fr) 80px 52px; }

    .bs-skinrow,
    .bs-p3row,
    .bs-subrow,
    .bs-trophyrow {
        column-gap: 8px;
        padding: 4.5px 2px;
        border-bottom: 1px solid #eef0f2 !important;
        font-size: 11.5px;
    }

    .bs-hole { font-size: 11.5px; letter-spacing: 0; color: #6b7280 !important; }
    .bs-player { font-size: 11.5px; font-weight: 400; }
    .bs-detail { font-size: 11.5px; color: #6b7280 !important; }
    .bs-detail--none { color: #9ca3af !important; }
    .bs-amount { font-size: 11.5px; font-weight: 700; color: #1b1f24 !important; }

    /* The print masthead: league name over the title, the date block right, a 2px rule under. */
    .bs-print__head {
        display: flex;
        align-items: flex-end;
        gap: 14px;
        border-bottom: 2px solid #1b1f24;
        padding-bottom: 12px;
    }

    .bs-print__league {
        font-size: 9.5px;
        font-weight: 700;
        letter-spacing: 0.16em;
        text-transform: uppercase;
        color: #6b7280;
    }

    .bs-print__title {
        margin: 5px 0 0;
        font-size: 29px;
        font-weight: 600;
        letter-spacing: -0.025em;
    }

    .bs-print__meta {
        margin-left: auto;
        text-align: right;
        font-size: 11px;
        line-height: 1.65;
        color: #4b5563;
    }

    .bs-print__foot {
        margin-top: auto;
        display: flex;
        border-top: 1px solid #d4d7dc;
        padding-top: 9px;
        font-size: 9.5px;
        color: #9ca3af;
    }

    .bs-print__foot span:last-child { margin-left: auto; }

    a { color: #1b1f24 !important; text-decoration: none !important; }

    @page { margin: 14mm; }
}
/* ══ 23 · Round Recap — hero band, program-page article, moments + money sidebar ═══════════
   /events/{slug}/recap was the last event-scoped screen speaking the pre-overhaul vocabulary:
   an <h2 class="page-title">, a SheetSelect in a .filter-controls block, and a .recap-card of
   plain <p>s split on blank lines. This partial brings it onto the leaderboard's language.
   Source: handoffs/design_handoff_recap (direction 1c "program page", states 1d).

   Rules this block obeys, from src/GolfTracker.UI/CLAUDE.md:
   · --metal-* means STANDING (the section labels, a rare feat, the money card's eyebrow),
     --color-accent means LIVE OR MONEY, --under-par means UNDER PAR. Nothing else gets a hue.
   · Elevation, not boxes: the cards are .rt-card from 19-result-tabs.css, reused rather than
     redrawn — so are .rt-eyebrow, .rt-foot, .rt-controls and .pos-tile.
   · The hero is a DARK surface in both themes (--recap-hero-ground, which deliberately does not
     invert, same call --masthead-scrim makes), so the ink over it is absolute hex declared once
     as local custom properties on .rc-hero rather than scattered through the rules.

   Two prefixes: .rc-* for the screen, and .md-body for the generated markdown. Every markdown
   rule is scoped UNDER .md-body — the bare .md- prefix belongs to the League matchup detail in
   22-league.css, which concatenates before this file. */

/* ── The hero band ───────────────────────────────────────────────────────────────────────── */

/* Butts against the masthead's bottom edge: it breaks out of main's padding with negative
   margins, and everything below it takes the content column's normal gutters. The three
   margins mirror main's three paddings (base 1rem, ≤768px 0.5rem/1rem, ≥769px 20px/--space-5). */
.rc-hero {
    /* Ink over the hero. Absolute because the ground never flips — these are the dark-theme
       champagne/slate values, and they are the correct ones in light mode too. */
    --rc-metal: #c9ad6e;
    --rc-metal-bright: #f2e4bf;
    --rc-ink: #fff;
    --rc-ink-2: #eef1f4;
    --rc-caption: #aab2bc;
    --rc-label: #98a1ad;
    --rc-money: #7ee29a;
    --rc-under: #f78b92;
    --rc-divider: rgba(255, 255, 255, 0.12);

    margin: -1rem -1rem var(--space-4);
    padding: 26px var(--space-6) 22px;
    background: var(--recap-hero-ground);
    border-bottom: 1px solid var(--recap-hero-edge);
    color: var(--rc-ink);
}

@media (max-width: 768px) {
    .rc-hero { margin: -0.5rem -1rem var(--space-4); padding: 0 18px 20px; }
}

@media (min-width: 769px) {
    .rc-hero { margin: -20px calc(var(--space-5) * -1) var(--space-4); }
}

.rc-hero__top {
    display: flex;
    align-items: center;
    gap: 10px;
    min-height: 0;
}

.rc-eyebrow {
    font-size: 10.5px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--rc-metal);
    white-space: nowrap;
}

.rc-rule {
    width: 1px;
    height: 12px;
    background: rgba(201, 173, 110, 0.40);
    flex-shrink: 0;
}

.rc-sub {
    font-size: 12.5px;
    color: var(--rc-caption);
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.rc-actions {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

.rc-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 7px 11px;
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: 9px;
    background: rgba(255, 255, 255, 0.06);
    font: inherit;
    font-size: 12.5px;
    color: var(--rc-ink-2);
    white-space: nowrap;
    cursor: pointer;
    transition: background 0.14s ease;
}

.rc-btn:hover:not(:disabled) { background: rgba(255, 255, 255, 0.11); }
.rc-btn:disabled { opacity: 0.6; cursor: default; }
.rc-btn .material-symbols-outlined { font-size: 16px; color: var(--rc-caption); }

/* Regenerate. Metal rather than accent: rewriting the story is not a payout. */
.rc-btn--metal {
    border-color: rgba(201, 173, 110, 0.55);
    background: rgba(201, 173, 110, 0.22);
    font-weight: var(--font-weight-semibold);
    color: var(--rc-metal-bright);
}

.rc-btn--metal:hover:not(:disabled) { background: rgba(201, 173, 110, 0.32); }
.rc-btn--metal .material-symbols-outlined { color: inherit; }

/* Glyph-only Share, phone only — the wordy buttons live in the sticky action bar down there. */
.rc-btn--icon { padding: 7px; border-color: transparent; background: none; }
.rc-btn--icon .material-symbols-outlined { font-size: 22px; color: var(--rc-ink-2); }

.rc-headline {
    margin: 14px 0 0;
    font-size: 40px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.035em;
    line-height: 1.06;
    color: var(--rc-ink);
    max-width: 26ch;
    text-wrap: pretty;
}

/* ── The four-figure rail ────────────────────────────────────────────────────────────────── */

.rc-rail {
    margin-top: 20px;
    display: flex;
    align-items: stretch;
}

.rc-rail__cell {
    padding: 0 28px;
    border-left: 1px solid var(--rc-divider);
    min-width: 0;
}

.rc-rail__cell:first-child { padding-left: 0; border-left: none; }

.rc-rail__label {
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--rc-label);
}

/* Cell 1 frames the standing, so its label takes metal — the same call .rt-rail__cell--lead makes. */
.rc-rail__cell--lead .rc-rail__label { color: var(--rc-metal); }

.rc-rail__fig {
    margin-top: 6px;
    font-size: 24px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.03em;
    font-variant-numeric: tabular-nums;
    color: var(--rc-ink);
}

/* A name is not a figure: no tabular numerals, one weight lighter, tighter tracking. */
.rc-rail__fig--name {
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.025em;
    font-variant-numeric: normal;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.rc-rail__fig--money { color: var(--rc-money); }
.rc-rail__fig--under { color: var(--rc-under); }

.rc-rail__sub {
    margin-top: 3px;
    font-size: 12px;
    color: var(--rc-caption);
}

/* The to-par cell folds into the winner's caption at 390px, and the hero's sub line moves from
   the top row to under the headline. Both halves are in the DOM at both widths and each hides in
   its own media query — toggling one element's display would flatten the flex row it sits in. */
.rc-narrow,
.rc-sub--under { display: none; }

@media (max-width: 768px) {
    .rc-hero__top { height: 50px; }
    .rc-hero .rc-rule,
    .rc-hero__top .rc-sub { display: none; }
    .rc-headline { margin-top: 8px; font-size: 28px; line-height: 1.1; }
    .rc-hero .rc-sub--under { display: block; margin-top: 6px; }

    /* Three cells on a hairline ground rather than four with dividers: To par folds into the
       winner's caption, because a phone reader wants who / how much / how many skins. */
    .rc-rail {
        margin-top: 18px;
        display: grid;
        grid-auto-flow: column;
        grid-auto-columns: minmax(0, 1fr);
        gap: 1px;
        background: var(--rc-divider);
        border-radius: var(--radius-lg);
        overflow: hidden;
    }
    .rc-rail__cell {
        padding: 12px 14px;
        border-left: none;
        background: #171b21;
    }
    .rc-rail__cell:first-child { padding-left: 14px; }
    .rc-rail__cell--topar { display: none; }
    .rc-rail__label { font-size: 9.5px; }
    .rc-rail__fig { margin-top: 5px; font-size: 16px; }
    .rc-rail__sub { margin-top: 0; font-size: 11px; }
    .rc-narrow { display: inline; }
}

/* ── Control row ─────────────────────────────────────────────────────────────────────────── */

/* The round picker is RoundPills under .rt-controls — the segmented track from 19-result-tabs.css,
   no new CSS. This is only the provenance line that closes the row. */
.rc-prov {
    margin-left: auto;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 11.5px;
    color: var(--text-quiet);
}

.rc-prov .material-symbols-outlined { font-size: 15px; }

/* ── Body grid ───────────────────────────────────────────────────────────────────────────── */

.rc-body {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 312px;
    gap: var(--space-4);
    align-items: start;
}

/* Nothing for the sidebar (no moments, no wagering) — the article takes the whole column rather
   than leaving a 312px hole beside it. */
.rc-body--solo { grid-template-columns: minmax(0, 1fr); }

.rc-article {
    background: var(--surface-raised);
    border: 1px solid var(--hairline);
    border-radius: var(--radius-xl);
    box-shadow: var(--shadow-lg);
    padding: 34px 40px 38px;
    min-width: 0;
}

.rc-article .md-body { max-width: 46rem; margin: 0 auto; }

.rc-side {
    position: sticky;
    top: var(--space-4);
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    min-width: 0;
}

@media (max-width: 900px) {
    .rc-body { grid-template-columns: minmax(0, 1fr); }
    /* One column: the STORY comes first and the moments + money cards follow it. The moments card
       used to be ordered above the prose; the recap is the thing this page is for, and burying it
       under two cards of figures the leaderboard already carries read as a detour to reach it. */
    .rc-side { position: static; }
    .rc-article { padding: 20px 20px 24px; }
}

/* ── Moments card ────────────────────────────────────────────────────────────────────────── */

.rc-cardhead {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: 14px 16px 11px;
}

.rc-dot {
    width: 6px;
    height: 6px;
    border-radius: var(--radius-pill);
    background: var(--color-accent);
    flex-shrink: 0;
    animation: winprob-pulse 1.6s ease-in-out infinite;
}

.rc-link {
    margin-left: auto;
    display: inline-flex;
    align-items: center;
    gap: 3px;
    border: none;
    background: none;
    padding: 0;
    font: inherit;
    font-size: 11.5px;
    font-weight: var(--font-weight-semibold);
    color: var(--metal-strong);
    text-decoration: none;
    cursor: pointer;
}

.rc-link .material-symbols-outlined { font-size: 15px; }

.rc-moment {
    display: flex;
    align-items: center;
    gap: 11px;
    padding: 11px 16px;
    border-top: 1px solid var(--hairline-soft);
    transition: background 0.14s ease;
}

.rc-moment:hover { background: color-mix(in srgb, var(--text) 3%, transparent); }

/* A rare feat is the one moment that carries metal — the rule .moments-capsule__item.is-rare
   already follows. Everything else on this card is neutral or, when it took money, accent. */
.rc-moment--rare { background: var(--metal-wash-05); }
.rc-moment--rare .rc-moment__title { color: var(--metal-strong); }

.rc-moment__badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    border-radius: var(--radius-pill);
    background: var(--control-fill);
    flex-shrink: 0;
}

.rc-moment__badge .material-symbols-outlined { font-size: 17px; color: var(--text-quiet); }

.rc-moment__badge--rare { background: var(--metal-wash-18); }
.rc-moment__badge--rare .material-symbols-outlined { color: var(--metal-strong); }

.rc-moment__badge--money { background: color-mix(in srgb, var(--color-accent) 16%, transparent); }
.rc-moment__badge--money .material-symbols-outlined {
    color: color-mix(in srgb, var(--color-accent) 70%, var(--text));
}

.rc-moment__text {
    display: flex;
    flex-direction: column;
    line-height: 1.32;
    min-width: 0;
}

.rc-moment__title {
    font-size: 13.5px;
    font-weight: var(--font-weight-semibold);
    color: var(--text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.rc-moment__detail { font-size: 11.5px; color: var(--text-muted); }

/* ── Money card ──────────────────────────────────────────────────────────────────────────── */

.rc-money__row {
    display: grid;
    grid-template-columns: 26px minmax(0, 1fr) 62px;
    column-gap: 10px;
    align-items: center;
    padding: 9px 16px;
    border-top: 1px solid var(--hairline-soft);
}

/* background-IMAGE, not the shorthand: the shorthand would drop the row's own background-color
   in the same declaration — the reason 19-result-tabs.css's .rt-row.is-leader does the same. */
.rc-money__row--leader { background-image: var(--metal-row-wash); }

.rc-money__name {
    font-size: 14px;
    font-weight: var(--font-weight-semibold);
    color: var(--text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.rc-money__amt {
    text-align: right;
    font-size: 14px;
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
    color: var(--color-accent);
}

/* ── Empty / generating states ───────────────────────────────────────────────────────────── */

.rc-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    padding: 44px var(--space-6);
}

.rc-empty__badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 52px;
    height: 52px;
    border-radius: var(--radius-pill);
    background: var(--metal-wash-10);
    border: 1px solid var(--metal-edge);
}

.rc-empty__badge .material-symbols-outlined { font-size: 26px; color: var(--metal-strong); }

/* The spectator's version of the same card, neutral instead of metal: nothing here is a
   standing, and there is no action to invite. */
.rc-empty__badge--quiet { background: var(--control-fill); border-color: var(--hairline); }
.rc-empty__badge--quiet .material-symbols-outlined { color: var(--ink-disabled); }

.rc-empty__title {
    margin-top: var(--space-4);
    font-size: 19px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.02em;
    color: var(--text);
}

.rc-empty__body {
    margin-top: var(--space-2);
    max-width: 34rem;
    font-size: 14px;
    line-height: 1.6;
    color: var(--text-muted);
    text-wrap: pretty;
}

/* Green because generating is the live action on this screen. */
.rc-empty__cta {
    margin-top: 20px;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 12px 20px;
    border: none;
    border-radius: 11px;
    background: var(--color-accent);
    font: inherit;
    font-size: 14.5px;
    font-weight: var(--font-weight-semibold);
    color: var(--on-hue);
    cursor: pointer;
}

.rc-empty__cta:disabled { opacity: 0.65; cursor: default; }

.rc-empty__hint { margin-top: var(--space-3); font-size: 12px; color: var(--text-quiet); }

.rc-empty__links {
    margin-top: 20px;
    display: flex;
    gap: 10px;
    flex-wrap: wrap;
    justify-content: center;
}

.rc-empty__links a {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 10px 16px;
    border: 1px solid var(--control-fill-strong);
    border-radius: 10px;
    background: var(--control-fill);
    font-size: 13.5px;
    font-weight: var(--font-weight-medium);
    color: var(--text);
    text-decoration: none;
}

.rc-empty__links .material-symbols-outlined { font-size: 18px; color: var(--text-quiet); }

/* Skeleton body. Heading bars take the metal wash, text bars the hairline, so the shape of the
   article being written is legible before a word of it exists. */
.rc-skel {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    padding: 22px 32px 30px;
}

.rc-skel__bar {
    height: 11px;
    border-radius: 6px;
    background: var(--hairline-soft);
}

.rc-skel__bar--head {
    height: 13px;
    margin-top: 10px;
    background: var(--metal-wash-18);
}

.rc-skel__bar:first-child { margin-top: 0; }

/* ── Markdown source view ────────────────────────────────────────────────────────────────── */

.rc-src {
    margin: 0;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 13px;
    line-height: 1.75;
    color: color-mix(in srgb, var(--text) 88%, transparent);
    white-space: pre-wrap;
    word-break: break-word;
}

/* ── Phone action bar ────────────────────────────────────────────────────────────────────── */

.rc-actionbar { display: none; }

@media (max-width: 768px) {
    /* Sticks ABOVE .bottom-nav, not at bottom:0 — the design's phone frame has no tab bar and the
       app does (a floating 69px pane inset 14px from the edge, z-index 150). At bottom:0 this bar
       would come to rest underneath it and both buttons would be untappable. main already reserves
       the same distance, so the bar lands on that reserve rather than over content. */
    .rc-actionbar {
        position: sticky;
        bottom: calc(83px + env(safe-area-inset-bottom));
        /* Above .bottom-nav-scrim (149) — see .wager-stickybar for why. */
        z-index: 151;
        display: flex;
        gap: var(--space-2);
        margin: var(--space-3) -1rem 0;
        padding: 10px 16px 16px;
        border-top: 1px solid var(--hairline);
        background: color-mix(in srgb, var(--surface-raised) 92%, transparent);
        backdrop-filter: blur(8px);
    }

    /* 46px clears the 44px minimum target. */
    .rc-abtn {
        flex: 1;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        gap: 6px;
        height: 46px;
        border: 1px solid var(--control-fill-strong);
        border-radius: var(--radius-lg);
        background: var(--control-fill);
        font: inherit;
        font-size: 14px;
        font-weight: var(--font-weight-medium);
        color: var(--text);
        cursor: pointer;
    }

    .rc-abtn .material-symbols-outlined { font-size: 18px; color: var(--text-quiet); }

    .rc-abtn--metal {
        border-color: var(--metal-line);
        background: var(--metal-wash-16);
        font-weight: var(--font-weight-semibold);
        color: var(--metal-strong);
    }

    .rc-abtn--metal .material-symbols-outlined { color: inherit; }
    .rc-abtn:disabled { opacity: 0.6; cursor: default; }

    /* The hero's wordy buttons are the action bar's job at this width. */
    .rc-actions .rc-btn:not(.rc-btn--icon) { display: none; }
}

@media (min-width: 769px) {
    .rc-actions .rc-btn--icon { display: none; }
}

@media (prefers-reduced-motion: reduce) {
    .rc-dot { animation: none; }
}

/* ── The generated prose (.md-body) ──────────────────────────────────────────────────────────
   The one place this feature styles by TAG rather than by class, because the markup is produced
   at runtime by Markdig from the recap's markdown. Every rule is scoped under .md-body and must
   stay that way — loosened to bare tag selectors it would restyle every article in the app, and
   the bare .md- prefix is the League matchup detail's. */

.md-body {
    color: var(--text);
    font-size: 18px;
    line-height: 1.72;
}

.md-body > *:first-child { margin-top: 0; }
.md-body > *:last-child { margin-bottom: 0; }

.md-body p { margin: 0 0 1.05em; text-wrap: pretty; }

/* The one piece of pure decoration on the page, and what makes the screen read as a printed
   program rather than another data card. */
.md-body > p:first-of-type::first-letter {
    float: left;
    font-size: 62px;
    line-height: 0.8;
    padding: 6px 12px 0 0;
    font-weight: var(--font-weight-semibold);
    color: var(--metal-strong);
}

/* A section label is a STANDING, hence metal — the same treatment .rt-eyebrow gets. Deliberately
   not a big display heading: the hero already owns the one large title on this screen. */
.md-body h2 {
    margin: 2em 0 0.75em;
    font-size: 11px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.13em;
    text-transform: uppercase;
    color: var(--metal);
}

.md-body h3 {
    margin: 1.6em 0 0.5em;
    font-size: 18px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.01em;
    color: var(--text);
}

.md-body strong { font-weight: var(--font-weight-semibold); color: var(--text); }
.md-body em { font-style: italic; color: var(--text-muted); }

.md-body a {
    color: var(--metal-strong);
    border-bottom: 1px solid var(--metal-line);
    text-decoration: none;
}

.md-body a:hover { background: var(--metal-wash-10); }

.md-body ul {
    margin: 0 0 1.05em;
    padding: 0;
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: 0.42em;
}

.md-body ul li { position: relative; padding-left: 22px; }

.md-body ul li::before {
    content: "";
    position: absolute;
    left: 5px;
    top: 0.68em;
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background: var(--metal-line);
}

.md-body ol { margin: 0 0 1.05em; padding-left: 24px; }
.md-body ol li { margin-bottom: 0.42em; }

/* The pull-quote is the one element in the body that carries real visual weight — the line of
   the round. */
.md-body blockquote {
    margin: 1.6em 0;
    padding: 2px 0 2px 24px;
    border-left: 3px solid var(--metal);
    font-size: 23px;
    font-weight: var(--font-weight-medium);
    line-height: 1.45;
    letter-spacing: -0.015em;
    color: var(--text);
}

.md-body blockquote p { margin: 0; }

/* Every quote is attributed, and the attribution is a second paragraph inside the quote ("— **Name**").
   It's a byline, not part of the line, so it drops out of the pull-quote's weight — at 23px a name
   on its own line reads as a second sentence of the quote. */
.md-body blockquote p + p {
    margin-top: 0.55em;
    font-size: 14px;
    font-weight: var(--font-weight-medium);
    letter-spacing: 0;
    color: var(--text-muted);
}

.md-body table {
    width: 100%;
    border-collapse: collapse;
    margin: 1.5em 0;
    font-size: 14.5px;
    font-variant-numeric: tabular-nums;
}

.md-body th {
    text-align: left;
    padding: 0 12px 8px 0;
    border-bottom: 1px solid var(--hairline);
    font-size: 10.5px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

.md-body td { padding: 9px 12px 9px 0; border-bottom: 1px solid var(--hairline-soft); }
.md-body th:last-child,
.md-body td:last-child { text-align: right; padding-right: 0; }
.md-body tr:last-child td { border-bottom: none; }

.md-body hr { border: 0; border-top: 1px solid var(--hairline-soft); margin: 1.9em 0; }

.md-body code {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.88em;
    background: var(--control-fill);
    padding: 2px 5px;
    border-radius: var(--radius-sm);
}

/* A table is the one thing in the prose that can't reflow; it scrolls inside its own box rather
   than pushing the article wider than the column. */
.md-body .md-table-wrap { overflow-x: auto; }

@media (max-width: 768px) {
    .md-body { font-size: 16px; line-height: 1.68; }
    .md-body > p:first-of-type::first-letter { font-size: 48px; padding: 4px 9px 0 0; }
    .md-body blockquote { margin: 1.3em 0; padding-left: 18px; border-left-width: 2px; font-size: 18px; }
}
/* ══ 24 · Account surfaces — the panel, My events, the Account hub, My registrations ═══════
   The four destinations behind the masthead avatar. They were the last screens still drawing
   .settings-card (a flat --gray-150 slab), .data-table, .detail-row and a full-width navy
   .btn-primary; this partial brings them onto the language the leaderboard, the result tabs,
   the Round Hub and Event Settings already share.
   Source: handoffs/design_handoff_account_surfaces (turn 1a; 1b was not shipped).

   MOST OF THIS DESIGN WRITES NO LAYOUT. The Account hub is .settings-shell + .settings-nav +
   .set-card / .set-row wholesale; the registrations board is .rt-card / .rt-rail / .rt-row.
   What's here is only what those blocks don't have: an anchored panel, the two My events card
   shapes, and the registrations date gutter.

   Three rules the whole block obeys (src/GolfTracker.UI/CLAUDE.md):
   · --metal-* means STANDING, --color-accent means LIVE OR MONEY, --under-par means UNDER PAR.
     A finished, cancelled or ineligible state is neutral, never a fourth hue.
   · Semantic tokens only — no literal hex. Every one of these screens is reachable in dark mode.
   · Breakpoints are hardcoded 480 / 768 (769 for the panel flip, matching .event-shell) because
     a media query can't read a var().

   Prefix is .acc-*. Checked against every later partial — nothing else claims it. */

/* ══════════════════════════════════════════════════════════════════════════════════════════
   1 · The account panel
   ══════════════════════════════════════════════════════════════════════════════════════════
   ONE DOM, two presentations. Below 769px it is the bottom sheet it always was (.modal-panel
   supplies the geometry, the shadow and the ≤480px grabber); at 769px and up it detaches and
   hangs off the avatar that opened it. Two DOMs would mean two copies of the identity header
   and the You strip, and the phone one is behind a media query where nobody would see it rot.

   The .modal-backdrop stays the panel's immediate previous sibling at every width — that
   sibling order is what js/sheet-dismiss.js falls back to — but above 769px it goes invisible
   and only serves as the outside-click target. */

.acc-panel.modal-panel {
    /* .modal-panel's own 1.5rem padding would double every block's padding below. The blocks
       own their gutters here, because the identity header and the You strip are full-bleed
       bands rather than inset content. */
    padding: 0;
    padding-bottom: env(safe-area-inset-bottom);
    overflow: hidden;
    background: var(--surface-raised);
}

/* The grabber is drawn by .modal-panel::before with a -0.5rem top margin that assumed the
   sheet's own padding. With padding zeroed it needs its own room. */
@media (max-width: 480px) {
    .acc-panel.modal-panel::before { margin: 10px auto 2px; }
}

/* ── Identity header ── */
.acc-panel__id {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: 16px 18px 14px;
    /* Metal, because the strip immediately below it is standing and the two read as one block. */
    background: linear-gradient(180deg, var(--metal-wash-07), transparent);
}

.acc-panel__avatar {
    flex: none;
    width: 44px;
    height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-pill);
    /* --surface-inverse, not --navy: a solid dark chip must stay dark in both themes, and
       --on-solid is the one ink that never inverts. */
    background: var(--surface-inverse);
    color: var(--on-solid);
    font-size: 15px;
    font-weight: var(--font-weight-bold);
}

.acc-panel__idtext {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.acc-panel__name {
    font-size: 16px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.01em;
    color: var(--text);
}

.acc-panel__email {
    font-size: 12px;
    color: var(--text-quiet);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ── The "You" strip ──
   Rendered only inside an event, and only when the caller has a position on that board. Off an
   event it has nothing to say, so it is omitted rather than shown empty.

   Metal here is correct and load-bearing: this strip is STANDING. The money beside it is green
   because green means live-or-money. Neither is decoration; don't recolour either. */
.acc-you {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 11px 18px;
    border-top: 1px solid var(--metal-edge);
    border-bottom: 1px solid var(--hairline-soft);
    background: var(--metal-wash-05);
}

.acc-you__label {
    flex: none;
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--metal);
}

.acc-you__rule {
    flex: none;
    width: 1px;
    height: 12px;
    background: var(--metal-line);
}

.acc-you__line {
    min-width: 0;
    font-size: 12.5px;
    color: var(--text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.acc-you__score {
    color: var(--text);
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
}

.acc-you__money {
    flex: none;
    margin-left: auto;
    font-size: 12.5px;
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
    color: var(--color-accent);
}

/* ── Destination rows ──
   Four flat links collapsed to three: Account and Profile were always one destination wearing
   two labels. Each row carries a trailing pill OR a chevron, never both — the pill IS the
   reason to tap. */
.acc-dests {
    display: flex;
    flex-direction: column;
    padding: 6px 8px 8px;
}

.acc-dest {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    min-height: 52px;
    padding: 9px 10px;
    border: none;
    border-radius: 10px;
    background: none;
    font: inherit;
    text-align: left;
    text-decoration: none;
    color: var(--text);
    cursor: pointer;
    transition: background 0.14s ease;
}

.acc-dest:hover { background: var(--control-fill); }
.acc-dest:active { background: var(--control-fill-strong); }

.acc-dest > .material-symbols-outlined {
    flex: none;
    font-size: 22px;
    line-height: 1;
    color: var(--ink-disabled);
}

.acc-dest__label {
    flex: 1;
    min-width: 0;
    font-size: 16px;
    font-weight: var(--font-weight-semibold);
}

.acc-dest__chev {
    flex: none;
    font-size: 18px;
    line-height: 1;
    color: var(--ink-disabled);
}

/* A count — how many events, quiet because it is context rather than a prompt. */
.acc-pill {
    flex: none;
    display: inline-flex;
    align-items: center;
    padding: 2px 8px;
    border-radius: var(--radius-pill);
    background: var(--control-fill);
    font-size: 11px;
    font-weight: var(--font-weight-bold);
    font-variant-numeric: tabular-nums;
    color: var(--text-quiet);
}

/* Your next tee time. Metal because when you play is a standing fact about your season, not
   money and not a live state. */
.acc-pill--metal {
    background: var(--metal-wash-16);
    color: var(--metal-strong);
}

/* ── Appearance / alerts / Log out blocks ── */
.acc-block {
    padding: 12px 18px 14px;
    border-top: 1px solid var(--hairline-soft);
}

.acc-block__label {
    margin-bottom: var(--space-2);
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

/* MomentAlertsCard keeps its two hosts (see CLAUDE.md); it is a .set-card, which brings its own
   frame — inside a panel that is already a card, the frame is one border too many. */
.acc-block--alerts { padding: 10px 12px 12px; }
.acc-block--alerts .set-card {
    border: none;
    border-radius: 12px;
    box-shadow: none;
    background: var(--control-fill);
}
.acc-block--alerts .set-card__label { padding-top: 12px; }

/* Log out is deliberately QUIETER than the old #c0392b row. Logging out is not destructive —
   you sign back in — and spending the danger hue here is what makes it mean less on the actions
   that genuinely can't be undone. */
.acc-logout {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    width: 100%;
    min-height: 44px;
    padding: 9px 10px;
    border: none;
    border-radius: 10px;
    background: none;
    font-family: inherit;
    font-size: 14px;
    font-weight: var(--font-weight-semibold);
    text-align: left;
    color: var(--text-muted);
    cursor: pointer;
    transition: background 0.14s ease;
}

.acc-logout:hover { background: var(--control-fill); }
.acc-logout .material-symbols-outlined { font-size: 20px; color: var(--ink-disabled); }

/* On a phone the log-out block holds exactly one row, so it becomes a bordered card of its own
   — a lone borderless row at the foot of a sheet reads as a stray. */
@media (max-width: 768px) {
    .acc-block--logout { padding: 12px 12px 14px; }
    .acc-logout {
        min-height: 52px;
        padding: 9px 14px;
        border: 1px solid color-mix(in srgb, var(--danger) 30%, transparent);
        border-radius: 12px;
        font-size: 15px;
    }
}

/* ── The panel at ≥769px ──
   It hangs off the avatar rather than sliding up from the bottom. #app-root is a 1280px centred
   column, so the anchor is that column's right gutter, not the viewport's — at 1920px a plain
   `right: 24px` would leave it 300px clear of the avatar it belongs to.

   Two modifiers because the two chromes are different heights: the masthead's utility row is
   50px, the standalone .top-bar is 52px, and the design hangs the panel 8px into whichever one
   is above it. */
@media (min-width: 769px) {
    .acc-panel.modal-panel {
        position: fixed;
        left: auto;
        bottom: auto;
        width: 352px;
        max-width: calc(100vw - 2 * var(--space-5));
        max-height: calc(100vh - 80px);
        overflow-y: auto;
        border: 1px solid var(--hairline);
        border-radius: var(--radius-xl);
        box-shadow: 0 18px 48px rgba(20, 26, 34, 0.22);
        /* `.modal-panel` centres itself at ≥481px with `left: 50%; transform: translateX(-50%)`.
           Clearing `left` alone is not enough — the transform survives and drags the panel half
           its own width (176px) off the avatar it is supposed to hang from. That is why the
           keyframes below animate translateY only and land on `none`. */
        transform: none;
        animation: acc-panel-in 0.12s ease-out;
    }

    .acc-panel--masthead {
        top: calc(42px + env(safe-area-inset-top));
        right: calc(max(0px, (100vw - 1280px) / 2) + var(--space-5));
    }

    .acc-panel--topbar {
        top: calc(44px + env(safe-area-inset-top));
        right: calc(max(0px, (100vw - 1280px) / 2) + 1rem);
    }

    /* Still the click target that closes the panel, and still the .modal-panel's immediate
       previous sibling — it just stops dimming the page, because a dropdown anchored to its
       trigger doesn't take the screen over. */
    .acc-backdrop { background: transparent; }

    .acc-dest { min-height: 44px; }
    .acc-dest > .material-symbols-outlined { font-size: 20px; }
    .acc-dest__label { font-size: 14.5px; }
    .acc-panel__avatar { width: 42px; height: 42px; font-size: 14.5px; }
    .acc-panel__name { font-size: 15.5px; }
}

@keyframes acc-panel-in {
    from { opacity: 0; transform: translateY(4px); }
    to { opacity: 1; transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
    .acc-panel.modal-panel { animation: none; }
}

/* ══════════════════════════════════════════════════════════════════════════════════════════
   2 · My events
   ══════════════════════════════════════════════════════════════════════════════════════════
   The live event is pinned as a metal-edged card carrying the two facts that decide whether you
   open it; everything else is a .set-row inside one card per account. The pinned event STILL
   GETS ITS ROW below, marked "pinned above" — the settings rule that a list must not change
   length applies here too, or the count in the panel's pill stops matching what you can see. */

.acc-page {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

/* The head's right-hand CTA. Accent because creating an event is the screen's one primary action.
   It stays compact at EVERY width and never grows to full width — it sits beside the "My events"
   title in a row, and the title is what supplies the object the short label leaves out.

   It used to swap for a full-width pill at the FOOT of the list on a phone, which put the screen's
   one primary action below the fold from about five events on. The foot pill is gone; .acc-dock
   below is what takes over once this one scrolls away. */
.acc-cta {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 7px;
    padding: 9px 15px;
    border: none;
    border-radius: var(--radius-pill);
    background: var(--color-accent);
    font-family: inherit;
    font-size: 13.5px;
    font-weight: var(--font-weight-bold);
    color: var(--on-hue);
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
}

.acc-cta:hover { background: color-mix(in srgb, var(--color-accent) 88%, #000); }
.acc-cta .material-symbols-outlined { font-size: 18px; }

/* ── The docked pill ──
   The head pill's stand-in once it has scrolled off, and the reason the head pill can stay
   compact. Visibility is driven by an IntersectionObserver on .acc-cta--head itself
   (js/dock-observer.js toggles .is-visible) — never a scroll offset, which is right at one list
   length and wrong at every other.

   Phone only. At >=769px the head is never far from the eye and there is no bottom bar to dodge,
   so the head pill alone is the whole design. */
.acc-dock { display: none; }

@media (max-width: 768px) {
    .acc-dock {
        display: flex;
        justify-content: center;
        position: fixed;
        left: 0;
        right: 0;
        bottom: 0;
        /* Above the phone bar's pane (150) and its scrim (149). The two never overlap — the
           offset below lifts this clear of the bar — but a pill that could be painted over by
           a fade is not a primary action. */
        z-index: 151;
        padding: 12px 14px 18px;
        padding-bottom: calc(18px + env(safe-area-inset-bottom));
        /* A fade, not a bar: the last rows dissolve under the pill instead of colliding with it.
           --page-ground rather than the literal, so one declaration draws in both themes. */
        background: linear-gradient(180deg,
            color-mix(in srgb, var(--page-ground) 0%, transparent),
            color-mix(in srgb, var(--page-ground) 92%, transparent) 55%);
        /* The container spans the screen; only the pill takes a tap. */
        pointer-events: none;
        opacity: 0;
        visibility: hidden;
        transform: translateY(6px);
        /* visibility is delayed out and immediate in, so the hidden dock is unfocusable and
           out of the a11y tree without needing aria-hidden/tabindex on the markup. */
        transition: opacity 150ms ease-out, transform 150ms ease-out, visibility 0s linear 150ms;
    }

    /* My events is reachable with an event still current (the brand link), and NavMenu renders
       the phone bar whenever one is. The offset is the bar's own figure — 69px of floating pane
       plus its 14px inset — the same 83px main and .settings-ground reserve. */
    #app-root:has(.bottom-nav) .acc-dock {
        bottom: calc(83px + env(safe-area-inset-bottom));
        padding-bottom: 18px;
    }

    .acc-dock.is-visible {
        opacity: 1;
        visibility: visible;
        transform: none;
        transition: opacity 150ms ease-out, transform 150ms ease-out;
    }

    .acc-dock__pill {
        pointer-events: auto;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        gap: 7px;
        min-height: 48px;
        padding: 0 22px;
        border-radius: var(--radius-pill);
        background: var(--color-accent);
        font-family: inherit;
        font-size: 14.5px;
        font-weight: var(--font-weight-bold);
        color: var(--on-hue);
        text-decoration: none;
        white-space: nowrap;
        box-shadow: 0 10px 24px rgba(20, 26, 34, 0.24);
    }

    .acc-dock__pill:hover { background: color-mix(in srgb, var(--color-accent) 88%, #000); }
    .acc-dock__pill .material-symbols-outlined { font-size: 18px; }
}

@media (prefers-reduced-motion: reduce) {
    .acc-dock,
    .acc-dock.is-visible { transition: none; }
}

/* ── Card A: the live event ── */
.acc-live { border-color: var(--metal-edge); }

.acc-live__head {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    padding: 13px 20px 11px;
}

.acc-live__eyebrow {
    flex: none;
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--metal);
}

.acc-rule {
    flex: none;
    width: 1px;
    height: 12px;
    background: var(--metal-line);
}

.acc-live__meta {
    margin-left: auto;
    font-size: 12.5px;
    color: var(--text-muted);
}

/* A FLEX line, not the design's fixed four-column grid. Either stat cell is dropped whole when
   there's nothing behind it — no standing before the first score, no money before the first
   payout — and a fixed template leaves the dead column behind, pulling the button in off the
   right edge. Flex closes up instead. */
.acc-live__body {
    display: flex;
    align-items: center;
    gap: var(--space-5);
    padding: 4px 20px 18px;
}

.acc-live__head + .acc-live__body { padding-top: 0; }
.acc-live__body > .acc-live__title-cell { flex: 1; min-width: 0; }

.acc-live__title {
    margin: 0;
    font-size: 23px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.02em;
    line-height: 1.15;
    color: var(--text);
}

.acc-live__sub {
    margin: 5px 0 0;
    font-size: 12.5px;
    color: var(--text-muted);
}

/* A stat cell. The divider is a border rather than a gap so a cut cell (no standing yet, no
   money yet) closes up cleanly instead of leaving a rule with nothing beside it. */
/* The way in. --surface-inverse rather than the accent, because the accent on this card is
   already spoken for by the live pill and the money figure. */
.acc-live__go {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 7px;
    padding: 10px 16px;
    border: none;
    border-radius: 10px;
    background: var(--surface-inverse);
    font-family: inherit;
    font-size: 13.5px;
    font-weight: var(--font-weight-semibold);
    color: var(--on-solid);
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
}

.acc-live__go:hover { background: color-mix(in srgb, var(--surface-inverse) 88%, #000); }
.acc-live__go:disabled { opacity: 0.6; cursor: default; }
.acc-live__go .material-symbols-outlined { font-size: 17px; }

.acc-live__foot {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    padding: 12px 20px;
    border-top: 1px solid var(--metal-edge);
    background: var(--metal-wash-05);
    font-size: 12.5px;
    color: var(--text-muted);
}

.acc-live__foot > .material-symbols-outlined { flex: none; font-size: 16px; color: var(--metal); }
.acc-live__foot strong { color: var(--text); font-weight: var(--font-weight-semibold); }
.acc-live__foot-end { margin-left: auto; }

/* ── Cards B…: one per account ── */
.acc-acct__label {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: 14px 20px 8px;
    font-size: 11px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-quiet);
    text-decoration: none;
}

a.acc-acct__label:hover { color: var(--text-muted); }
.acc-acct__label .material-symbols-outlined { margin-left: auto; font-size: 18px; color: var(--ink-disabled); }

/* An event row. It is a .set-row — the left cell absorbs the slack and the caption wraps — with
   a leading glyph and a right-hand cluster instead of one control. */
.acc-evrow {
    width: 100%;
    border: none;
    background: none;
    font: inherit;
    text-align: left;
    text-decoration: none;
    color: var(--text);
    cursor: pointer;
}

/* The whole row is a <button> (or an <a>), which may only contain PHRASING content — so the
   name and caption are spans, not the divs every other .set-row uses, and spans are inline.
   Without this the two run together on one line. */
.acc-evrow .set-row__name,
.acc-evrow .set-row__caption { display: block; }

.acc-evrow:disabled { cursor: default; }

/* A finished season is quieter, not greyed out of legibility, and it is NOT amber: an event
   reaching its end is a legitimate state, not something anyone must fix. */
.acc-evrow--past { opacity: 0.72; }

.acc-evrow__glyph {
    flex: none;
    width: 24px;
    display: grid;
    place-items: center;
    color: var(--ink-disabled);
}

.acc-evrow__glyph .material-symbols-outlined { font-size: 24px; }

.acc-evrow__end {
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: 10px;
    white-space: nowrap;
}

.acc-evrow__chev { font-size: 20px; color: var(--ink-disabled); }

/* ── My events, phone ── */
@media (max-width: 768px) {
    .acc-live__body {
        flex-direction: column;
        align-items: stretch;
        gap: 14px;
        padding: 4px 16px 16px;
    }

    .acc-live__go {
        width: 100%;
        min-height: 48px;
    }

    .acc-live__title { font-size: 21px; }
    .acc-live__head { padding: 12px 16px 10px; }
    .acc-live__foot { padding: 11px 16px; }
    .acc-live__foot-end { margin-left: 0; flex-basis: 100%; }

    .acc-acct__label { padding: 13px 16px 6px; }

    /* .set-head stacks into a column on a phone, which is right for a settings page whose head
       carries a save chip and wrong here: the pill is the screen's primary action and it reads
       as one only while it sits BESIDE the title, which is also what lets the label be a single
       word. flex-start rather than centre, so a two-line purpose string doesn't push it down. */
    .acc-page .set-head {
        flex-direction: row;
        align-items: flex-start;
        gap: 12px;
    }
}

/* ══════════════════════════════════════════════════════════════════════════════════════════
   3 · The Account & profile hub
   ══════════════════════════════════════════════════════════════════════════════════════════
   Almost nothing. The shell, the rail, the detail column and every card and row come from
   07-settings.css unchanged — AccountNav is .settings-nav markup, so it inherits the compact
   rail at ≥768px for free, and below it the rail IS the hub's list. The rail's active row keeps
   the ACCENT wash it has there, deliberately: metal means standing, and there is no standing on
   these screens. (.settings-nav--metal is the leaderboard's opt-in; don't add it here.)

   What's left is the identity block the phone hub shows above its first card, and the two rows
   whose right-hand cell isn't one of the ten existing kinds. */

/* The hub's identity block and its Log out card are phone-only: at ≥769px the rail is one column
   of a master–detail and both would sit above it in a column 264px wide, where a 22px name and a
   full-width danger card read as a second page head competing with the detail pane's own. The
   panel that opened this screen already carries both on desktop. */
.settings-hub-id,
.settings-hub-logout { padding: 0 var(--space-1); }

@media (min-width: 768px) {
    .settings-hub-id,
    .settings-hub-logout,
    /* The rail navigates at this width and the panel that opened the hub is still one click
       away, so the bar's back chevron is redundant — the same call .settings-detail .app-bar
       makes for every pane. */
    .settings-hub-bar { display: none; }
}

/* The hub's own rail title would be the third thing naming this screen on a phone, under the
   app bar and the person's name. The rail keeps it at ≥768px, where it labels the column. */
@media (max-width: 767px) {
    .settings-shell--hub .settings-nav-title { display: none; }
}

.settings-hub-id { padding-bottom: var(--space-4); }
.settings-hub-logout { padding-top: var(--space-3); }

.acc-ident {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: 2px var(--space-1) 0;
}

.acc-ident__avatar {
    flex: none;
    width: 52px;
    height: 52px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-pill);
    background: var(--surface-inverse);
    color: var(--on-solid);
    font-size: 18px;
    font-weight: var(--font-weight-bold);
}

.acc-ident__body { flex: 1; min-width: 0; }

.acc-ident__name {
    margin: 0;
    font-size: 22px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.02em;
}

.acc-ident__email {
    margin: 3px 0 0;
    font-size: 13px;
    color: var(--text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* The Photo row's control: the avatar you have, beside the button that would replace it.
   Upload is disabled until there is somewhere to upload to — greyed with the reason in the
   row's caption, never a hidden control (the tier-4 rule, applied to a plain button). */
.acc-avatarcell {
    display: inline-flex;
    align-items: center;
    gap: 12px;
}

.acc-avatarcell__img {
    flex: none;
    width: 40px;
    height: 40px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-pill);
    background: var(--surface-inverse);
    color: var(--on-solid);
    font-size: 13.5px;
    font-weight: var(--font-weight-bold);
}

/* A figure stated on a row — the handicap index. NOT hue-coloured: an index is not a standing,
   not money and not under par (21-handicaps.css's rule, which holds wherever an index appears). */
.acc-figure {
    flex: none;
    display: inline-flex;
    align-items: baseline;
    gap: 8px;
}

.acc-figure__num {
    font-size: 24px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.02em;
    font-variant-numeric: tabular-nums;
    color: var(--text);
}

.acc-figure__as {
    font-size: 12px;
    color: var(--text-quiet);
    white-space: nowrap;
}

/* A value that drills in: the current value in quiet ink, then a chevron. Same shape
   SheetSelect's row variant draws, for a row whose destination is a page rather than a sheet. */
.acc-drill {
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: 4px;
    min-width: 0;
    padding: 0 4px 0 8px;
    border: none;
    background: none;
    font: inherit;
    font-size: 15px;
    color: var(--text-muted);
    text-decoration: none;
    cursor: pointer;
}

.acc-drill__value {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.acc-drill .material-symbols-outlined { flex: none; font-size: 20px; color: var(--ink-disabled); }

/* A missing optional field is quiet ink, the words, and a button that fixes it on the row —
   never a hue. Same call the players screen makes for a roster spot with no email. */
.acc-empty {
    font-size: 14px;
    color: var(--text-quiet);
}

/* The account name above the account half of the rail, and the hub list's own group heading. */
.acc-railname {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ══════════════════════════════════════════════════════════════════════════════════════════
   4 · My registrations
   ══════════════════════════════════════════════════════════════════════════════════════════
   A .rt-card board with a stat rail over it, replacing a <table class="data-table--cards">
   whose Status column printed the raw enum ("pending_payment") at the player.

   Both forms are in the DOM and each hides inside its own media query — the wide one is a CSS
   grid and the narrow one is a flex line, and toggling `display` on one of them would flatten
   it. Same call .wager-desktop / .wager-phone and the players roster both made. */

.acc-regboard { display: none; }
.acc-regagenda { display: none; }

@media (min-width: 769px) { .acc-regboard { display: block; } }
@media (max-width: 768px) { .acc-regagenda { display: block; } }

/* This board's column count is FIXED, so the template is declared here rather than published
   from C# as --rt-cols. That mechanism exists for a board whose columns are data-driven (the
   Money List's are the games the event pays) — using it for a static five would be ceremony. */
.acc-regboard .rt-head,
.acc-regboard .rt-row {
    --rt-cols: 64px minmax(0, 1fr) 132px 128px 168px;
}

/* The last row's divider is the card's own foot border. */
.acc-regboard .rt-row:last-child { border-bottom: none; }

/* ── The date cell ── stacked day-of-week over date, tabular so the column stays a column. */
.acc-regdate {
    display: flex;
    flex-direction: column;
    line-height: 1.15;
}

.acc-regdate__dow {
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

.acc-regdate__day {
    font-size: 19px;
    font-weight: var(--font-weight-bold);
    font-variant-numeric: tabular-nums;
    color: var(--text);
    white-space: nowrap;
}

/* The next round is the one standing fact on this screen — when you next play. */
.acc-regdate--next .acc-regdate__dow { color: var(--metal); }
.acc-regdate--next .acc-regdate__day { color: var(--metal-strong); }

.acc-regtee {
    font-size: 15px;
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
    color: var(--text);
}

.acc-regtee--none { font-weight: var(--font-weight-medium); color: var(--text-quiet); }

/* "Pick a slot" — metal, because choosing a tee time is fixing where you stand in the day, and
   green on this row would compete with the Pay action two columns over. */
.acc-slotbtn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    height: 34px;
    padding: 0 12px;
    border: 1px solid var(--metal-line);
    border-radius: 9px;
    background: var(--metal-wash-16);
    font-family: inherit;
    font-size: 12.5px;
    font-weight: var(--font-weight-semibold);
    color: var(--metal-strong);
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
}

.acc-slotbtn:hover { background: var(--metal-wash-18); }

.acc-regend {
    display: inline-flex;
    align-items: center;
    justify-content: flex-end;
    gap: var(--space-2);
    width: 100%;
}

/* A row's secondary action. Quiet by default; the one that takes money is accent. */
.acc-regact {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    height: 34px;
    padding: 0 12px;
    border: 1px solid color-mix(in srgb, var(--text) 14%, transparent);
    border-radius: 9px;
    background: var(--surface-raised);
    font-family: inherit;
    font-size: 12.5px;
    font-weight: var(--font-weight-semibold);
    color: var(--text);
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
}

.acc-regact:hover:not(:disabled) { background: color-mix(in srgb, var(--text) 4%, transparent); }
.acc-regact:disabled { color: var(--ink-disabled); cursor: not-allowed; }

.acc-regact--pay {
    border-color: transparent;
    background: var(--color-accent);
    color: var(--on-hue);
    font-weight: var(--font-weight-bold);
}

.acc-regact--pay:hover:not(:disabled) { background: color-mix(in srgb, var(--color-accent) 88%, #000); }

/* Entry state. Paid is money (accent), owing is a thing the player must act on (warning), and
   cancelled / refunded are NEUTRAL — an ended registration is not a fault. */
.acc-regstate--paid {
    background: color-mix(in srgb, var(--color-accent) 12%, transparent);
    border-color: color-mix(in srgb, var(--color-accent) 30%, transparent);
    color: color-mix(in srgb, var(--color-accent) 70%, var(--text));
}
.acc-regstate--paid .rt-state__dot { background: var(--color-accent); }

.acc-regstate--owes {
    background: color-mix(in srgb, var(--warning) 16%, transparent);
    border-color: color-mix(in srgb, var(--warning) 40%, transparent);
    /* Amber takes dark ink, not white — at #f39c12 white lands under 2:1 in light mode. */
    color: var(--acc-warn-ink);
}
.acc-regstate--owes .rt-state__dot { background: var(--warning); }

/* Page-local ink on the amber tint, the shape .cm-page / .set-page / .hc-page all use: darkened
   in light mode where the hue is too light on its own wash, reverted in dark where the hue has
   already been brightened for a dark ground. */
.acc-regpage { --acc-warn-ink: color-mix(in srgb, var(--warning) 42%, #000); }
:root[data-theme="dark"] .acc-regpage { --acc-warn-ink: var(--warning); }

/* The "Needs you" rail cell's Act pill — the same amber, at pill scale. */
.acc-act {
    display: inline-flex;
    align-items: center;
    padding: 2px 8px;
    border-radius: var(--radius-pill);
    background: color-mix(in srgb, var(--warning) 16%, transparent);
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: var(--acc-warn-ink);
}

.acc-rail__fig--warn { color: var(--warning); }

/* ── The phone form: a date gutter and a stacked body ──
   No horizontal scroll and no column tricks. The action lives INSIDE the row as a full-width
   44px button, because a 5-column grid at 390px puts it somewhere the thumb can't reach. */
.acc-regrow {
    display: flex;
    align-items: flex-start;
    gap: 14px;
    padding: 14px 16px;
    border-bottom: 1px solid var(--hairline-soft);
}

.acc-regrow:last-child { border-bottom: none; }
.acc-regrow--next { background-image: var(--metal-row-wash); }

/* The gutter. Fixed width so every row's body starts on the same line. */
.acc-reggutter {
    flex: none;
    width: 46px;
    display: flex;
    flex-direction: column;
    align-items: center;
    line-height: 1.1;
    padding-top: 2px;
}

.acc-reggutter__dow {
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

.acc-reggutter__num {
    font-size: 22px;
    font-weight: var(--font-weight-bold);
    font-variant-numeric: tabular-nums;
    color: var(--text);
}

.acc-reggutter__mon {
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

.acc-regrow--next .acc-reggutter__dow,
.acc-regrow--next .acc-reggutter__mon { color: var(--metal); }
.acc-regrow--next .acc-reggutter__num { color: var(--metal-strong); }

.acc-regbody {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 9px;
}

.acc-regbody__title {
    font-size: 15.5px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.01em;
    color: var(--text);
}

.acc-regbody__sub {
    margin-top: 2px;
    font-size: 12.5px;
    color: var(--text-muted);
    line-height: 1.4;
}

.acc-regbody__facts {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}

/* Full-width, 46px, inside the row — the whole point of the phone form. */
.acc-regbody .acc-regact,
.acc-regbody .acc-slotbtn {
    width: 100%;
    height: 46px;
    border-radius: 11px;
    font-size: 14px;
}

/* ── The registrations page, both widths ── */
.acc-regcontrols {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    flex-wrap: wrap;
}

/* `.segmented` is itself a flex container whose options are `flex: 1 1 0` — so it has no useful
   intrinsic width, and as an auto-sized item of this row it resolved to ~167px and wrapped every
   label, turning the active segment into a circle. It needs an explicit width, not just
   `flex: none`. The options stay equal-width, which is the control's contract. */
.acc-regcontrols .segmented { flex: none; width: min(360px, 100%); }

.acc-regcontrols__end {
    margin-left: auto;
    font-size: 12.5px;
    color: var(--text-muted);
}

@media (max-width: 768px) {
    .acc-regcontrols { display: block; }
    .acc-regcontrols__end { display: none; }
    .acc-regcontrols .segmented { width: 100%; }
}
/* ══ 25 · Course Stats — how the course played ═════════════════════════════════════════════
   /events/{slug}/stats. It was the last event-scoped read screen still on the pre-overhaul
   vocabulary: a .round-filter week trigger, a .course-info h4, and an eleven-column
   .data-table.course-stats-table with .summary-row / .out-row / .in-row / .total-row bands.
   Source: handoffs/design_handoff_course_stats (frames 1a desktop, 1b phone, 1c states).

   THIS PARTIAL IS DELIBERATELY SMALL. The card, the head, the foot, the stat rail, the grid
   board, the sort buttons, the live pill and the legend are all .rt-* from 19-result-tabs.css,
   reused unmodified — if you find yourself restyling an .rt- class here, you have diverged from
   the leaderboard and should stop. What's below is only what that block doesn't have: the column
   templates, the rank tile, the over/under ink, the five-segment distribution bar, and the
   phone's metal dot.

   Colour discipline (src/GolfTracker.UI/CLAUDE.md):
   · --metal-* is DIFFICULTY RANK and nothing else on this screen. Rank is a standing.
   · A hole's average versus par follows the scorecard: under par is --under-par, over par is
     quiet ink. The retired .course-under-par { color: green } had it exactly backwards, which
     is why it contradicted the leaderboard's .board-topar.under-par and .gp-side__ou.is-under.
   · Green appears twice: the eagle/birdie segments of the distribution bar with the MOST
     BIRDIES count beside them, and the LIVE pill on a round genuinely in progress.
   · Bogey and double+ take --under-par as a TINT, not the ink, so they read as "worse than par"
     without competing with the +/− figure in the column to their left.

   Placed last in the cascade: everything here is a new .cs-* selector, so it neither needs nor
   claims priority over 24-account.css's .acc-regboard narrowings of the same .rt-* block. */

/* ── The board ───────────────────────────────────────────────────────────────────────────── */

/* Hole · Par · Yds · Rank · Avg · +/− · Scoring · E · B · P · Bo · Dbl+.
   The phone template keeps five: everything dropped there is either derivable (Yds) or carried
   by the distribution bar (the five counts). Rank survives as .cs-dot beside the hole number. */
.cs-board {
    --rt-cols: 52px 44px 60px 54px 58px 66px minmax(130px, 1fr) 38px 38px 38px 38px 42px;
    --rt-cols-md: 52px 44px 60px 54px 58px 66px minmax(110px, 1fr) 34px 34px 34px 34px 38px;
    --rt-cols-sm: 36px 32px 48px 56px minmax(0, 1fr);
}

.cs-board .rt-row { padding: 12px 20px; }

/* .rt-head__sortable already has an .is-right; Par / Yds / Rank are the only centred heads in
   the whole .rt- vocabulary, so the modifier lives here rather than being pushed upstream. */
.cs-head-c { text-align: center; }

/* Ranks 1–3 carry the same fade-to-the-right wash the leader's row does on the board.
   background-IMAGE, never the shorthand — the shorthand resets background-image and would kill
   the wash on hover. Same trap .board-row and .rt-row both document. */
.cs-board .rt-row.is-hard { background-image: var(--metal-row-wash); }

.cs-hole {
    display: flex;
    align-items: center;
    gap: 5px;
    font-size: 15px;
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
    color: var(--text);
}

.cs-par {
    text-align: center;
    font-size: 13.5px;
    font-variant-numeric: tabular-nums;
    color: var(--text-muted);
}

.cs-yds {
    text-align: center;
    font-size: 13px;
    font-variant-numeric: tabular-nums;
    color: var(--text-quiet);
}

.cs-avg {
    text-align: right;
    font-size: 15px;
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
    color: var(--text);
}

/* The difficulty tile. .pos-tile--xs already sizes a 26px tile and .pos-tile--1/2/3 already
   define the metal taper, so this extends them rather than restating three washes — change the
   podium's weights once and this follows. */
.cs-rank {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-md);
    font-size: 12.5px;
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
    color: var(--text-muted);
}

.cs-rankcell { display: flex; justify-content: center; }

/* The 4px metal dot that replaces the rank column on a phone. The hardest holes are the reason
   the screen is open — they must stay findable once their column is gone. */
.cs-dot {
    display: none;
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background: var(--metal);
    flex-shrink: 0;
}

/* A hole's average versus par. Under par is the scorecard's red; even is near-full ink so "E"
   doesn't read as missing; over par stays quiet, because on a golf course most holes are. */
.cs-ou {
    text-align: right;
    font-size: 15px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.015em;
    font-variant-numeric: tabular-nums;
    color: var(--text-muted);
}

.cs-ou.is-under { color: var(--under-par); }
.cs-ou.is-even { color: color-mix(in srgb, var(--text) 88%, transparent); }

/* The scoring distribution — .ml-mix restated with five segments instead of three, because
   these ARE five different kinds of thing where the money bar's three were one. */
.cs-mix {
    display: flex;
    height: 9px;
    border-radius: 5px;
    overflow: hidden;
    background: var(--control-fill);
}

.cs-mix__seg { display: block; height: 100%; }
.cs-mix__seg--1 { background: color-mix(in srgb, var(--color-accent) 34%, transparent); }
.cs-mix__seg--2 { background: color-mix(in srgb, var(--color-accent) 18%, transparent); }
.cs-mix__seg--3 { background: var(--control-fill-strong); }
.cs-mix__seg--4 { background: color-mix(in srgb, var(--under-par) 16%, transparent); }
.cs-mix__seg--5 { background: color-mix(in srgb, var(--under-par) 34%, transparent); }

/* A zero is greyed, not hidden — "no eagles here" is information, and a blank cell in a column
   of numbers reads as a load failure. */
.cs-count {
    text-align: right;
    font-size: 13px;
    font-variant-numeric: tabular-nums;
    color: color-mix(in srgb, var(--text) 88%, transparent);
}

.cs-count.is-zero { color: var(--ink-disabled); }

/* ── OUT / IN / TOTAL ────────────────────────────────────────────────────────────────────── */

/* These stay .rt-row--foot so the figures land under their own columns; an .rt-foot flex row is
   flex and would collapse the grid — the note 19-result-tabs.css already carries. OUT and IN
   render only under the hole sort: under any other sort the nine-hole split describes rows that
   are no longer beside each other. TOTAL always renders. */
.cs-board .rt-row--foot.cs-in { border-top-color: var(--hairline-soft); }

.cs-total {
    background: var(--metal-wash-16);
    padding: 14px 20px;
}

.cs-board .rt-row--foot.cs-total:hover { background: var(--metal-wash-16); }

.cs-footlbl {
    font-size: 11px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--metal);
}

.cs-footlbl--total { color: var(--metal-strong); }

.cs-board .rt-row--foot .cs-par { font-size: 13.5px; font-weight: var(--font-weight-semibold); color: var(--text); }
.cs-board .rt-row--foot .cs-avg { font-weight: var(--font-weight-bold); }
.cs-board .rt-row--foot .cs-count { font-weight: var(--font-weight-semibold); color: var(--text); }
.cs-board .cs-total .cs-par { font-size: 14px; font-weight: var(--font-weight-bold); }
.cs-board .cs-total .cs-yds { color: var(--text-muted); }
.cs-board .cs-total .cs-avg { font-size: 17px; font-weight: var(--font-weight-bold); }
.cs-board .cs-total .cs-ou { font-size: 17px; font-weight: var(--font-weight-bold); }
.cs-board .cs-total .cs-count { font-size: 13.5px; font-weight: var(--font-weight-bold); }

/* ── Stat rail ───────────────────────────────────────────────────────────────────────────── */

/* The figure beside a rail cell's hole number. Quiet for over par (most holes), --under-par
   when the hole played under it, and accent for the birdie COUNT — that one is a tally of good
   scores rather than a differential, which is why it takes the good-news hue instead. */
.cs-rail__delta {
    font-size: 15px;
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
    color: var(--text-muted);
}

.cs-rail__delta.is-under { color: var(--under-par); }
.cs-rail__delta.is-good { color: color-mix(in srgb, var(--color-accent) 70%, var(--text)); }

.cs-rail__top {
    display: flex;
    align-items: baseline;
    gap: 9px;
    min-width: 0;
}

/* ── States ──────────────────────────────────────────────────────────────────────────────── */

/* A round genuinely in progress. The .p3-card.is-live treatment, reused verbatim: green here is
   legitimate because play is actually happening. A Scheduled or Finished round takes no accent. */
.cs-card.is-live { border-color: color-mix(in srgb, var(--color-accent) 32%, transparent); }
.cs-card.is-live .rt-cardhead { background: color-mix(in srgb, var(--color-accent) 5%, transparent); }

.cs-empty {
    padding: 34px 24px;
    text-align: center;
}

.cs-empty > .material-symbols-outlined {
    font-size: 30px;
    color: var(--ink-disabled);
}

.cs-empty__title {
    margin-top: 10px;
    font-size: 17px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.01em;
    color: var(--text);
}

.cs-empty__body {
    margin-top: 6px;
    font-size: 13px;
    color: var(--text-muted);
}

/* .board-manage is an <a> on the leaderboard and a <button> here — same affordance, so it takes
   the same chrome and only needs the two properties a button doesn't inherit. */
.cs-empty .board-manage {
    margin-top: 14px;
    font-family: inherit;
    cursor: pointer;
}

/* ── Responsive ──────────────────────────────────────────────────────────────────────────── */
/* Two breakpoints, matching the app. Everything 19-result-tabs.css's own media blocks do to
   .rt-* — the column-template swap, the rail going to two columns with its border flips, the
   row padding, .rt-controls__end losing its auto margin — applies here for free. */

@media (max-width: 1000px) {
    .cs-rail__delta { font-size: 14px; }
}

@media (max-width: 768px) {
    .cs-board .rt-row,
    .cs-board .cs-total { padding: 10px 14px; }

    /* Yds, Rank and the five counts go; the distribution bar carries what the counts said and
       .cs-dot carries what the rank column said. */
    .cs-hide-sm { display: none; }
    .cs-board .rt-row.is-hard .cs-dot { display: block; }

    .cs-hole { font-size: 14px; }
    .cs-par { font-size: 12.5px; }
    .cs-avg { font-size: 14px; }
    .cs-ou { font-size: 13.5px; }
    .cs-mix { height: 8px; border-radius: 4px; }

    .cs-board .cs-total .cs-avg,
    .cs-board .cs-total .cs-ou { font-size: 15px; }

    /* The rail's figures step down with the two-column layout the shared partial already sets. */
    .cs-rail__delta { font-size: 13px; }
    .cs-rail__top { gap: 7px; }
    .rt-rail--cs .rt-rail__cell { padding: 13px 14px 15px; gap: 5px; }
    .rt-rail--cs .rt-rail__label { font-size: 9.5px; }
    .rt-rail--cs .rt-rail__fig { font-size: 23px; }
    .rt-rail--cs .rt-rail__sub { font-size: 11px; }

    .cs-empty { padding: 28px 18px; }
    .cs-empty__title { font-size: 16px; }
}
/* ══ 26 · The bottom bar, the live-round dock, and the You tab ═════════════════════════════════
   Source: handoffs/design_handoff_bottom_nav (turn 1b + 2a/2b + turn 3).

   The phone bar was five items — Leaderboard · Recap · Odds · Course Stats · More — which mixed
   two kinds of thing: four LENSES ON RESULTS sitting at equal weight directly beneath the view
   pills, which are also lenses on results, and a drawer holding both the overflow views and the
   entire admin surface. Nothing in it was the thing you're actually doing on a Wednesday night.

   It is four stable tabs now — Board · Round · Season · You — on a floating, blurred pane, with the
   live round as a BANNER above it rather than as navigation.

   Four rules this block obeys, all from src/GolfTracker.UI/CLAUDE.md:

   · --metal-* means STANDING. The active tab's chip is metal because it is the same "this is where
     you stand" language as the week rail's selected numeral and the podium's position tiles.
     --color-accent means LIVE OR MONEY, which is why the Round tab's dot, the dock's status dot,
     the Pot tile and the return bar are all green and nothing else is.
   · THE DOCK IS A DARK SURFACE IN BOTH THEMES — the rule .lvs-header and --masthead-scrim follow.
     Its ink is absolute hex, declared once as local custom properties on .dock rather than
     scattered through the block, because light mode's --metal (#8a6d33) is invisible on #171b21.
     Everything else here is on semantic tokens and re-themes for free.
   · Spacing snaps to --space-* except sub-grid hairlines (the bar's 4px item gap, its 7px/8px pane
     padding) and device-chrome env() math, which is the standing exception.
   · Breakpoints are hardcoded 768/769 — a media query can't read a var(). 769 is where the account
     panel and the rail flip, matching .event-shell, and it is where the bar itself stops existing.

   Prefix is .bottom-nav-* for the bar and .dock-* for the dock. Checked against every partial —
   nothing claims .dock-, and .ls-* (League Schedule) and .lvs-* (live scoring) are deliberately
   avoided. See the note at the top of 12-live-scoring.css for what happens when you don't check. */

/* ══════════════════════════════════════════════════════════════════════════════════════════
   1 · The bar
   ══════════════════════════════════════════════════════════════════════════════════════════
   A floating pane, not an edge-to-edge strip: the board scrolls UNDER it, which is what the
   scrim above it exists to make legible. Phone only — at ≥769px the rail is the navigation and
   02-base-chrome.css's `display: none` default stands. */

@media (max-width: 768px) {
    /* A 96px non-interactive fade so board rows dissolve into the pane instead of colliding with
       it. pointer-events: none is load-bearing — this sits over the last rows of the board. */
    .bottom-nav-scrim {
        display: block;
        position: fixed;
        left: 0;
        right: 0;
        bottom: 0;
        height: 96px;
        z-index: 149;
        pointer-events: none;
        background: linear-gradient(180deg,
            color-mix(in srgb, var(--page-ground) 0%, transparent),
            color-mix(in srgb, var(--page-ground) 92%, transparent) 55%);
    }

    .bottom-nav {
        display: flex;
        position: fixed;
        /* env() adds to the inset rather than replacing it — the pane floats clear of the home
           indicator, it doesn't sit on it. */
        bottom: calc(14px + env(safe-area-inset-bottom));
        left: 12px;
        right: 12px;
        z-index: 150;
        gap: 4px;
        padding: 7px 8px;
        border-radius: 22px;
        /* The blur is the point. A solid fill here loses the "the board is underneath" reading
           that the floating pane exists for, so dark mode gets the same alpha on a raised
           surface rather than an opaque swap. */
        background: color-mix(in srgb, var(--surface-raised) 82%, transparent);
        backdrop-filter: blur(20px) saturate(160%);
        -webkit-backdrop-filter: blur(20px) saturate(160%);
        border: 1px solid var(--hairline);
        box-shadow: 0 10px 30px rgba(20, 26, 34, 0.16),
                    inset 0 1px 0 rgba(255, 255, 255, 0.7);
    }

    .bottom-nav-item {
        flex: 1;
        display: flex;
        flex-direction: column;
        align-items: center;
        gap: 5px;
        padding: 5px 0 3px;
        background: none;
        border: none;
        font-family: inherit;
        color: var(--text-muted);
        text-decoration: none;
        cursor: pointer;
        -webkit-tap-highlight-color: transparent;
    }

    /* 44 × 30 + the label + the item's own padding puts every tab a hair over 50px tall, which
       clears the 44px minimum with the label included rather than only the glyph. */
    .bottom-nav-icon {
        position: relative;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        width: 44px;
        height: 30px;
        border-radius: 10px;
        transition: background 0.14s ease;
    }

    .bottom-nav-item .material-symbols-outlined { font-size: 22px; }

    .bottom-nav-label {
        font-size: 10.5px;
        font-weight: var(--font-weight-semibold);
        line-height: 1;
    }

    /* The active tab takes a metal chip — standing, the same language as .mh-week.is-selected and
       the podium tiles. It replaced a navy-then-metal INK-only treatment; the chip is what makes
       the current tab findable without reading four labels. */
    .bottom-nav-item.active { color: var(--metal-strong); }
    .bottom-nav-item.active .bottom-nav-icon { background: var(--metal-wash-16); }
    .bottom-nav-item.active .bottom-nav-label { font-weight: var(--font-weight-bold); }

    /* A live round. Accent means live-or-money and this is live; the ring is what keeps it
       readable over both a lit glyph and the blurred board behind the pane. */
    .bottom-nav-dot {
        position: absolute;
        top: 1px;
        right: 8px;
        width: 7px;
        height: 7px;
        border-radius: var(--radius-pill);
        background: var(--color-accent);
        box-shadow: 0 0 0 2px color-mix(in srgb, var(--surface-raised) 90%, transparent);
        /* The leaderboard's own 1.6s beat, so every live dot in the app pulses at one rate.
           Already reduced-motion-gated where it is declared (10-scorecard.css). */
        animation: winprob-pulse 1.6s ease-in-out infinite;
    }

    /* The You tab's icon IS the caller's avatar, not a glyph — that is what makes the move out of
       the masthead read as a promotion. --surface-inverse stays dark in both themes and --on-solid
       is the one ink that never inverts, so this pair survives the flip. */
    .bottom-nav-avatar {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        width: 24px;
        height: 24px;
        border-radius: var(--radius-pill);
        background: var(--surface-inverse);
        color: var(--on-solid);
        font-size: 9.5px;
        font-weight: var(--font-weight-bold);
        letter-spacing: 0.02em;
    }
}

/* ══════════════════════════════════════════════════════════════════════════════════════════
   2 · The live-round dock
   ══════════════════════════════════════════════════════════════════════════════════════════
   Sits directly above the bar on the Board tab. A BANNER, not navigation: if it never renders,
   nothing becomes unreachable, because Round is still a tab.

   Its ink is absolute hex on purpose — see the header. Declared once here so a later rule can't
   invent a fifth grey. */

.dock {
    display: none;
}

@media (max-width: 768px) {
    .dock {
        --dock-ground: #171b21;
        --dock-ink: #f0f2f4;
        --dock-ink-2: #aab2bc;
        --dock-glyph: #98a2ad;
        --dock-ink-3: #6f7885;
        --dock-metal: #c9ad6e;
        --dock-metal-lit: #e8d6a8;
        --dock-metal-ink: #2b2413;
        --dock-live: #3ad160;

        display: flex;
        position: fixed;
        left: 12px;
        right: 12px;
        /* Directly above the bar: its 69px pane, its 14px inset, and 8px between the two. */
        bottom: calc(91px + env(safe-area-inset-bottom));
        z-index: 150;
        background: var(--dock-ground);
        border: 1px solid color-mix(in srgb, var(--dock-metal) 28%, transparent);
        box-shadow: 0 12px 30px rgba(20, 26, 34, 0.30);
        text-decoration: none;
    }

    /* A page carrying a dock has to reserve MORE than main's 83px, or the dock covers the last rows
       of whatever is under it. Reported off the Teams board, where the final team's row sat behind
       it with nothing left to scroll — the dock stays up until the round is Finished, so it isn't a
       moment you can wait out.

       147px = the dock's own 91px offset + its ~56px one-line pane. Only the two one-line shapes
       are reserved for: the expanded dock is a panel the reader opened and can collapse, and
       reserving its full height would leave a third of the screen blank whenever it's shut. Its
       bottom offset and the 83px in 02-base-chrome.css both feed this number — move one and move
       this. */
    main:has(.dock--collapsed),
    main:has(.dock--return) {
        padding-bottom: calc(147px + env(safe-area-inset-bottom) + 0.75rem);
    }

    /* ── Collapsed: one line, one verb ── */
    .dock--collapsed {
        align-items: center;
        gap: 11px;
        padding: 11px 12px;
        border-radius: 16px;
    }

    /* The LINE expands and the VERB opens the card — two targets, because "show me more" and
       "take me there" are different intentions and merging them costs one of them. */
    .dock__line {
        flex: 1;
        min-width: 0;
        display: flex;
        align-items: center;
        gap: 11px;
        padding: 0;
        background: none;
        border: none;
        font-family: inherit;
        text-align: left;
        cursor: pointer;
        -webkit-tap-highlight-color: transparent;
    }

    .dock__dot {
        flex: none;
        width: 8px;
        height: 8px;
        border-radius: var(--radius-pill);
        background: var(--dock-live);
        box-shadow: 0 0 0 3px color-mix(in srgb, var(--dock-live) 20%, transparent);
        animation: winprob-pulse 1.6s ease-in-out infinite;
    }

    .dock__lines {
        flex: 1;
        min-width: 0;
        display: flex;
        flex-direction: column;
        line-height: 1.3;
    }

    .dock__line1 {
        font-size: 13.5px;
        font-weight: var(--font-weight-semibold);
        color: var(--dock-ink);
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .dock__line2 {
        font-size: 11px;
        color: var(--dock-ink-2);
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    /* Metal fill: this is the standing thing to do next, and it is the only filled control on the
       collapsed dock. */
    .dock__verb {
        flex: none;
        display: inline-flex;
        align-items: center;
        gap: 5px;
        padding: 7px 13px;
        border-radius: var(--radius-pill);
        background: linear-gradient(180deg, var(--dock-metal-lit), var(--dock-metal));
        color: var(--dock-metal-ink);
        font-size: 12px;
        font-weight: var(--font-weight-bold);
        letter-spacing: 0.02em;
        white-space: nowrap;
        text-decoration: none;
    }

    .dock__verb .material-symbols-outlined { font-size: 15px; }

    /* ── Expanded: the round's mini-hub ── */
    .dock--expanded {
        flex-direction: column;
        padding: 14px 14px 12px;
        border-radius: 18px;
        box-shadow: 0 16px 40px rgba(20, 26, 34, 0.36);
    }

    .dock__head {
        display: flex;
        align-items: center;
        gap: 10px;
        margin-bottom: 12px;
    }

    .dock__eyebrow {
        font-size: 10px;
        font-weight: var(--font-weight-bold);
        letter-spacing: 0.12em;
        text-transform: uppercase;
        color: var(--dock-metal);
    }

    .dock__where {
        margin-left: auto;
        min-width: 0;
        font-size: 11.5px;
        color: var(--dock-ink-2);
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .dock__collapse {
        flex: none;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        width: 28px;
        height: 28px;
        margin: -4px -4px -4px 0;
        padding: 0;
        border: none;
        border-radius: 8px;
        background: none;
        color: var(--dock-glyph);
        cursor: pointer;
    }

    .dock__collapse .material-symbols-outlined { font-size: 20px; }

    .dock__tiles {
        display: flex;
        gap: var(--space-2);
        margin-bottom: 12px;
    }

    .dock__tile {
        flex: 1;
        display: flex;
        flex-direction: column;
        gap: 3px;
        padding: 11px 12px;
        border-radius: 12px;
        background: rgba(255, 255, 255, 0.06);
    }

    .dock__tile-label {
        font-size: 9.5px;
        font-weight: var(--font-weight-bold);
        letter-spacing: 0.1em;
        text-transform: uppercase;
        color: var(--dock-ink-3);
    }

    .dock__tile-fig {
        font-size: 19px;
        font-weight: var(--font-weight-bold);
        font-variant-numeric: tabular-nums;
        color: var(--dock-ink);
    }

    /* Green because green means money. It is the only hue in the tile row. */
    .dock__tile-fig--money { color: var(--dock-live); }

    /* THE one metal-filled row, and it is the scoring door. Nothing else in the dock competes
       with it: a person on hole 15 in the dark should be able to hit the right thing without
       reading. Scoring has exactly one door — "Your group" below goes to context, not entry. */
    .dock__primary {
        display: flex;
        align-items: center;
        gap: 11px;
        min-height: 52px;
        padding: 9px 12px;
        margin-bottom: 2px;
        border-radius: 12px;
        background: linear-gradient(180deg, var(--dock-metal-lit), var(--dock-metal));
        color: var(--dock-metal-ink);
        text-decoration: none;
    }

    .dock__primary > .material-symbols-outlined:first-child { flex: none; font-size: 21px; }
    .dock__primary > .material-symbols-outlined:last-child { flex: none; font-size: 18px; }

    .dock__primary-lines {
        flex: 1;
        min-width: 0;
        display: flex;
        flex-direction: column;
        line-height: 1.25;
    }

    .dock__primary-title { font-size: 15px; font-weight: var(--font-weight-bold); }

    .dock__primary-sub {
        font-size: 11px;
        font-weight: var(--font-weight-semibold);
        opacity: 0.75;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .dock__rows {
        display: flex;
        flex-direction: column;
        gap: 2px;
    }

    .dock__row {
        display: flex;
        align-items: center;
        gap: 11px;
        min-height: 46px;
        padding: 8px 10px;
        border-radius: 11px;
        color: var(--dock-ink);
        text-decoration: none;
    }

    .dock__row-glyph { flex: none; font-size: 20px; color: var(--dock-glyph); }

    .dock__row-label {
        flex: 1;
        min-width: 0;
        font-size: 14.5px;
        font-weight: var(--font-weight-semibold);
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .dock__row-end { flex: none; font-size: 11.5px; color: var(--dock-ink-2); }

    .dock__row-money {
        flex: none;
        font-size: 11.5px;
        font-weight: var(--font-weight-semibold);
        font-variant-numeric: tabular-nums;
        color: var(--dock-live);
    }

    .dock__row-chev { flex: none; font-size: 18px; color: var(--dock-ink-3); }

    /* ── The return bar (§8) ──
       Same geometry as the collapsed dock, GREEN rather than metal: this is a job in progress,
       not a standing. It replaces the dock while a claim is held, so the two never stack. */
    .dock--return {
        align-items: center;
        gap: 11px;
        padding: 11px 12px;
        border-radius: 16px;
        background: var(--color-accent);
        border-color: transparent;
        box-shadow: 0 12px 30px rgba(40, 167, 69, 0.30);
    }

    /* --on-hue, not --on-solid: the accent brightens in dark mode, and white on it lands at
       ~2.8:1. This is the pair that flips. */
    .dock--return .dock__glyph { flex: none; font-size: 21px; color: var(--on-hue); }
    .dock--return .dock__line1 { color: var(--on-hue); font-weight: var(--font-weight-bold); }
    .dock--return .dock__line2 { color: color-mix(in srgb, var(--on-hue) 82%, transparent); }
    .dock--return .dock__chev { flex: none; font-size: 20px; color: var(--on-hue); }

    /* Height and opacity, ~180ms. The sheet's own reduced-motion gate applies here too. */
    .dock--expanded { animation: dock-expand 0.18s cubic-bezier(0.4, 0, 0.2, 1); }
}

@keyframes dock-expand {
    from { opacity: 0; transform: translateY(6px); }
    to { opacity: 1; transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
    .dock--expanded,
    .dock__dot,
    .bottom-nav-dot { animation: none; }
}

/* ══════════════════════════════════════════════════════════════════════════════════════════
   2b · The masthead avatar leaves the header — below 769px only
   ══════════════════════════════════════════════════════════════════════════════════════════
   The trigger was at one end of the screen and the sheet it opened at the other, which is the
   whole reason the account moved into the bar. Below the breakpoint the You tab IS the avatar, so
   keeping this one would be two triggers for one destination on one screen.

   ABOVE 769px the avatar and its anchored panel are untouched — there is no bar up there, and the
   panel hangs off exactly this button. */

@media (max-width: 768px) {
    .mh-avatar { display: none; }
}

/* ══════════════════════════════════════════════════════════════════════════════════════════
   3 · The You tab
   ══════════════════════════════════════════════════════════════════════════════════════════
   The account panel's THIRD presentation. 24-account.css already runs "one DOM, two
   presentations" (a bottom sheet below 769px, an anchored panel above it); this is the same DOM
   as a full screen, reached as the bar's fourth tab. The sheet and the anchored panel are
   untouched — everything below is scoped to .acc-panel--page.

   What differs is only what a page has and a sheet doesn't: a larger identity block, because it is
   a page head rather than a sheet head, and the two admin-shaped rows. The brand row above it is
   the MASTHEAD's utility row — the You tab suppresses only the big header, so the brand and the
   wordmark are already on screen and a second one here would stack two. */

.acc-panel--page {
    display: flex;
    flex-direction: column;
    /* Break out of main's 1rem gutters — this screen is full-bleed bands, like the sheet. */
    margin: -0.5rem -1rem 0;
    background: var(--surface-raised);
    min-height: 100%;
}

/* The floating bar must never cover Log out. main already reserves the bar's height; the extra
   is the breathing room the design draws below the last row. */
.acc-panel--page .acc-block--logout { padding-bottom: var(--space-6); }

/* A page head, not a sheet head. */
.acc-panel--page .acc-panel__id { padding: 18px 18px 14px; }
.acc-panel--page .acc-panel__avatar { width: 52px; height: 52px; font-size: 18px; }
.acc-panel--page .acc-panel__name { font-size: 20px; }

/* "Switch event" carries a name rather than a count — a switcher that doesn't say what it would
   switch to is a switcher nobody taps. Quiet, because it is context and the chevron is the prompt. */
.acc-dest__hint {
    flex: none;
    font-size: 12.5px;
    color: var(--text-quiet);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 45%;
}

/* ── "Run this event" ──
   Where the More sheet's admin groups landed. A bordered card rather than three more borderless
   rows, because it is a different KIND of thing from the three destinations above it: those are
   about you, these are about the event you run. */
.acc-runcard {
    display: flex;
    flex-direction: column;
    background: var(--surface-raised);
    border: 1px solid var(--hairline);
    border-radius: 12px;
    overflow: hidden;
}

.acc-runrow {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    min-height: 48px;
    padding: 10px 14px;
    border-bottom: 1px solid var(--hairline-soft);
    color: var(--text);
    text-decoration: none;
}

.acc-runrow:last-child { border-bottom: none; }
.acc-runrow:active { background: var(--control-fill); }

.acc-runrow > .material-symbols-outlined { flex: none; font-size: 20px; color: var(--ink-disabled); }

.acc-runrow__label {
    flex: 1;
    min-width: 0;
    font-size: 15px;
    font-weight: var(--font-weight-semibold);
}

.acc-runrow__chev { flex: none; font-size: 18px; color: var(--ink-disabled); }

/* At ≥769px the bar doesn't exist, so nobody reaches this route by tapping — but it is a real
   route and a bookmark must still render something sane. Centre it like the settings detail
   column rather than stretching a phone screen across a desktop. */
@media (min-width: 769px) {
    .acc-panel--page {
        max-width: 700px;
        margin: 0 auto;
        border: 1px solid var(--hairline);
        border-radius: var(--radius-xl);
        overflow: hidden;
        min-height: 0;
    }
}

/* ══════════════════════════════════════════════════════════════════════════════════════════
   4 · The rail's live dot (≥769px)
   ══════════════════════════════════════════════════════════════════════════════════════════
   The desktop expression of the bar's Round-tab dot, on the "The round" group's hub row. */

.rail-live-dot {
    flex: none;
    margin-left: auto;
    width: 7px;
    height: 7px;
    border-radius: var(--radius-pill);
    background: var(--color-accent);
}
/* ============================================================================
   AUTH FRONT DOOR (.afd-)
   Source: handoffs/design_handoff_auth_front_door, direction 1a "broadcast dark".

   One screen behind /login, /register and /join, with three focus tabs. Replaces the three
   separate .auth-screen columns; 16-auth-pages.css stays, because ForgotPassword,
   ResetPassword, AcceptInvite and ClaimWelcome still render on that block.

   THE GROUND IS DARK IN BOTH THEMES — the rule --masthead-scrim, --recap-hero-ground and
   .lvs-header all follow. --auth-ground / --auth-edge are declared in 01-tokens.css's light
   block only and deliberately never re-declared under [data-theme="dark"]. The reason is
   specific to this screen: theme.js defaults the preference to `system`, so a first-time
   visitor lands on whatever their phone is set to, before the app has any preference of theirs
   to read. A ground that doesn't flip is one drawing to hold up rather than two.

   Consequently the ink is ABSOLUTE HEX, declared once as local custom properties on .afd-page
   rather than scattered through the rules below — the shape .lvs-header and .dock use. Light
   mode's --metal (#8a6d33) is effectively invisible on #12161b, which is why the champagne
   values are the drawn ones here in both themes.

   Colour discipline, unchanged: --afd-metal is STANDING (the eyebrows, the active tab, the
   resolved code, the section rules framing those), --afd-money is LIVE OR MONEY, --afd-under is
   UNDER PAR. Nothing else on this screen takes a hue.
   ============================================================================ */

.afd-page {
    /* Ink */
    --afd-ink: #ffffff;          /* headings */
    --afd-ink-2: #eef1f4;        /* row labels, input text */
    --afd-ink-3: #c8cfd8;        /* meta line, back chip */
    --afd-muted: #aab2bc;        /* sub-paragraphs, legal links */
    --afd-quiet: #98a1ad;        /* field labels, inactive tabs, icon buttons */
    --afd-faint: #6f7885;        /* helper text, legal, chevrons */
    --afd-sep: #4a5460;          /* the dots between legal links */

    /* Standing */
    --afd-metal: #c9ad6e;
    --afd-metal-ink: #e8d6a8;    /* the caret, the focused cell's character */
    --afd-metal-tab: #f2e4bf;    /* the active tab's label — brightest of the three */
    --afd-metal-line: rgba(201, 173, 110, 0.45);
    --afd-metal-edge: rgba(201, 173, 110, 0.30);
    --afd-metal-wash: rgba(201, 173, 110, 0.20);
    --afd-metal-wash-soft: rgba(201, 173, 110, 0.14);
    --afd-metal-focus: rgba(201, 173, 110, 0.60);
    --afd-metal-field: rgba(201, 173, 110, 0.55);

    /* Live or money */
    --afd-live: #3ad160;
    --afd-live-ink: #9df0b4;
    --afd-live-fill: rgba(58, 209, 96, 0.18);
    --afd-live-edge: rgba(58, 209, 96, 0.42);
    --afd-money: #7ee29a;
    --afd-meter: rgba(58, 209, 96, 0.85);

    /* Under par */
    --afd-under: #f78b92;

    /* Surfaces on the dark ground */
    --afd-fill: rgba(255, 255, 255, 0.06);
    --afd-fill-soft: rgba(255, 255, 255, 0.04);
    --afd-fill-cell: rgba(255, 255, 255, 0.07);
    --afd-fill-track: rgba(255, 255, 255, 0.05);
    --afd-line: rgba(255, 255, 255, 0.12);
    --afd-line-soft: rgba(255, 255, 255, 0.08);
    --afd-line-track: rgba(255, 255, 255, 0.07);
    --afd-rule: rgba(255, 255, 255, 0.09);
    --afd-meter-empty: rgba(255, 255, 255, 0.10);

    min-height: 100dvh;
    display: flex;
    flex-direction: column;
    background: var(--auth-ground);
    color: var(--afd-ink-2);
    font-family: var(--font-sans);
}

/* .minimal-layout caps its column at 480px and paints --surface behind it (12-live-scoring.css,
   where that cap is right for a scoring card). The front door is a full-bleed dark page with a
   two-column desktop layout, so it releases both — scoped with :has() so LiveScoring, Landing and
   every other MinimalLayout screen keep the cap they were written for. Same trick
   .app-bar:has(.overflow-menu__panel) and .set-card:has(…) use. */
#app-root.minimal-layout:has(.afd-page) {
    max-width: none;
    background: none;
}

/* ---- Shell -------------------------------------------------------------- */

.afd-shell {
    flex: 1;
    display: flex;
    flex-direction: column;
}

.afd-col {
    flex: 1;
    display: flex;
    flex-direction: column;
    padding: 0 var(--space-5);
}

/* The column's own flow. margin-top:auto on .afd-foot pins the footer to the bottom of the
   viewport on a short state (the code tab) and lets it follow the content on a tall one
   (create account), which is what the design's `margin-top: auto` note means. */
.afd-colinner {
    flex: 1;
    display: flex;
    flex-direction: column;
    width: 100%;
}

/* ---- Brand row ---------------------------------------------------------- */

.afd-brandrow {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    padding-top: var(--space-5);
}

.afd-brand {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    text-decoration: none;
}

.afd-brand img {
    width: 30px;
    height: 30px;
    border-radius: 9px;
    display: block;
}

.afd-brand__word {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--afd-quiet);
}

/* ---- Heading block ------------------------------------------------------ */

.afd-head {
    padding-top: var(--space-6);
}

.afd-title {
    margin: 0 0 10px;
    font-size: 31px;
    font-weight: 600;
    letter-spacing: -0.03em;
    line-height: 1.08;
    color: var(--afd-ink);
    text-wrap: balance;
}

.afd-sub {
    margin: 0;
    font-size: 14.5px;
    line-height: 1.55;
    color: var(--afd-muted);
    text-wrap: pretty;
}

/* ---- Focus tabs --------------------------------------------------------- */

.afd-tabs {
    display: flex;
    gap: 6px;
    margin-top: var(--space-5);
    padding: var(--space-1);
    border-radius: var(--radius-pill);
    background: var(--afd-fill-track);
    border: 1px solid var(--afd-line-track);
}

.afd-tab {
    flex: 1;
    padding: 9px 6px;
    border: none;
    border-radius: var(--radius-pill);
    background: none;
    color: var(--afd-quiet);
    font-family: inherit;
    font-size: 12.5px;
    font-weight: 500;
    cursor: pointer;
    /* The .view-pill transition — the vocabulary this tab row is borrowed from. */
    transition: background 0.14s ease, color 0.14s ease;
}

.afd-tab:hover { color: var(--afd-ink-2); }

.afd-tab.is-active {
    background: var(--afd-metal-wash);
    box-shadow: inset 0 0 0 1px var(--afd-metal-line);
    color: var(--afd-metal-tab);
    font-weight: 700;
}

/* ---- Shared field vocabulary -------------------------------------------- */

.afd-fields {
    display: flex;
    flex-direction: column;
    gap: 14px;
    padding-top: var(--space-6);
}

.afd-label {
    display: block;
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--afd-quiet);
    margin-bottom: var(--space-2);
}

/* The eyebrow above the code grid is a section label framing a standing, so it takes metal —
   the field labels above email/password do not. */
.afd-label--metal {
    color: var(--afd-metal);
    letter-spacing: 0.12em;
    margin-bottom: var(--space-3);
}

.afd-labelrow {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    margin-bottom: var(--space-2);
}

.afd-labelrow .afd-label { margin-bottom: 0; }

.afd-forgot {
    font-size: 12px;
    font-weight: 600;
    color: var(--afd-metal);
    text-decoration: none;
}

.afd-forgot:hover { color: var(--afd-metal-ink); text-decoration: underline; }

.afd-input {
    width: 100%;
    padding: 15px 14px;
    border: none;
    border-radius: var(--radius-lg);
    background: var(--afd-fill);
    box-shadow: inset 0 0 0 1px var(--afd-line);
    color: var(--afd-ink);
    font-family: inherit;
    font-size: 15.5px;
}

.afd-input::placeholder { color: var(--afd-faint); }

/* Every input takes a 1.5px champagne border on focus. This REPLACES the UA outline rather than
   removing it — the outline is suppressed only because something visible takes its place. */
.afd-input:focus {
    outline: none;
    box-shadow: inset 0 0 0 1.5px var(--afd-metal-field);
}

.afd-inputwrap { position: relative; }

.afd-inputwrap .afd-input { padding-right: 50px; }

.afd-eye {
    position: absolute;
    right: var(--space-2);
    top: 50%;
    transform: translateY(-50%);
    width: 36px;
    height: 36px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: none;
    border-radius: var(--radius-pill);
    background: none;
    color: var(--afd-quiet);
    cursor: pointer;
}

.afd-eye:hover { color: var(--afd-ink-2); }
.afd-eye .material-symbols-outlined { font-size: 20px; }

/* ---- Code entry --------------------------------------------------------- */

.afd-code {
    padding-top: var(--space-6);
}

/* ONE real input under six drawn cells, not six inputs.
   The handoff allows either and says to test iOS one-time-code autofill before committing to
   six — this is the shape that can't fail it. A password manager and an SMS autofill both fill
   a single field; across six they fill the first and drop five characters. Paste, backspace and
   text selection are then the browser's own behaviour rather than six focus handlers
   reimplementing them, which is where a split-cell input usually breaks. The cost is that
   tapping the fourth cell doesn't put the caret there — the flow is left-to-right typing, and
   the caret follows the character count. */
.afd-codebox {
    position: relative;
}

.afd-codeinput {
    position: absolute;
    inset: 0;
    width: 100%;
    z-index: 1;
    margin: 0;
    padding: 0;
    border: none;
    background: none;
    font-family: inherit;
    font-size: 25px;
    /* Invisible but real — the cells below draw the characters, and the active cell draws its
       own caret, so the native one is suppressed rather than left doubling it. */
    color: transparent;
    caret-color: transparent;
    text-align: center;
}

.afd-codeinput:focus { outline: none; }
.afd-codeinput::selection { background: transparent; }

.afd-cells {
    display: grid;
    grid-template-columns: repeat(6, 1fr);
    gap: 7px;
}

.afd-cell {
    height: 60px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-lg);
    background: var(--afd-fill-soft);
    box-shadow: inset 0 0 0 1px var(--afd-line-soft);
    color: var(--afd-ink);
    font-size: 25px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    transition: background 0.14s ease, box-shadow 0.14s ease;
}

.afd-cell.is-filled {
    background: var(--afd-fill-cell);
    box-shadow: inset 0 0 0 1px var(--afd-line);
}

.afd-cell.is-active {
    background: var(--afd-metal-wash-soft);
    box-shadow: inset 0 0 0 1.5px var(--afd-metal-focus);
    color: var(--afd-metal-ink);
}

.afd-caret {
    width: 2px;
    height: 26px;
    border-radius: 2px;
    background: var(--afd-metal-ink);
    animation: afd-caret-pulse 1.1s ease-in-out infinite;
}

/* Same shape as winprob-pulse, at the 1.1s the design gives the caret. */
@keyframes afd-caret-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.35; }
}

.afd-hint {
    margin-top: 11px;
    font-size: 12.5px;
    color: var(--afd-faint);
}

/* ---- Buttons ------------------------------------------------------------ */

/* The primary on a dark ground. --navy doesn't invert (it doubles as the solid chip ground), so
   a navy button here recedes into the page instead of leading it — hence the token pair. */
.afd-primary {
    width: 100%;
    padding: 16px;
    border: none;
    border-radius: 13px;
    background: var(--btn-primary-ground);
    color: var(--btn-primary-ink);
    font-family: inherit;
    font-size: 15.5px;
    font-weight: 700;
    letter-spacing: -0.01em;
    cursor: pointer;
    transition: background 0.14s ease, color 0.14s ease;
}

.afd-primary:disabled {
    opacity: 0.6;
    cursor: not-allowed;
}

/* The code tab has no field gap above its button — the cells and the helper line are one block,
   so the button needs its own separation. The other two tabs get it from .afd-fields' gap. */
.afd-primary--spaced { margin-top: var(--space-5); }

.afd-secondary {
    width: 100%;
    padding: 14px;
    border: none;
    border-radius: 13px;
    background: var(--afd-fill);
    box-shadow: inset 0 0 0 1px var(--afd-line);
    color: var(--afd-ink-2);
    font-family: inherit;
    font-size: 14.5px;
    font-weight: 600;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    text-decoration: none;
    transition: background 0.14s ease, color 0.14s ease;
}

.afd-secondary:hover { background: var(--afd-fill-cell); color: var(--afd-ink-2); }

.afd-divider {
    display: flex;
    align-items: center;
    gap: 11px;
    margin: var(--space-4) 0;
}

.afd-divider::before,
.afd-divider::after {
    content: "";
    flex: 1;
    height: 1px;
    background: var(--afd-rule);
}

.afd-divider span {
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--afd-faint);
}

/* Apple / Google. Drawn but not wired — the markup renders them only when SSO is switched on,
   so this block styles nothing today rather than shipping two dead buttons. */
.afd-sso {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
}

.afd-sso .afd-secondary { width: 100%; }

/* ---- Password strength -------------------------------------------------- */

.afd-meter {
    margin-top: 9px;
    display: flex;
    align-items: center;
    gap: 9px;
}

.afd-meter__seg {
    flex: 1;
    height: 4px;
    border-radius: var(--radius-pill);
    background: var(--afd-meter-empty);
    transition: background 0.14s ease;
}

.afd-meter__seg.is-on { background: var(--afd-meter); }

.afd-meter__word {
    flex: none;
    font-size: 11.5px;
    font-weight: 600;
    color: var(--afd-quiet);
}

/* ---- Password rules ----------------------------------------------------- */

/* The four things the server will actually check, drawn from the first frame rather than after a
   rejected submit. They wrap as chips rather than stacking as a list: four rows of text under the
   field pushes the primary off a 390px screen, and the strength meter already owns a full row
   directly above.

   A met rule takes the money/live green, which is the one place on this screen that hue is not
   about money — it is the app's own "this is satisfied" tick, the same call .set-saved makes.
   An unmet rule is deliberately NOT --afd-under: nothing is wrong yet, the box is simply empty. */
.afd-rules {
    margin: 10px 0 0;
    padding: 0;
    list-style: none;
    display: flex;
    flex-wrap: wrap;
    gap: 6px 12px;
}

.afd-rule {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: 12.5px;
    line-height: 1.3;
    color: var(--afd-faint);
    transition: color 0.14s ease;
}

.afd-rule__mark {
    font-size: 15px;
    /* Material Symbols' optical alignment sits a hair low against 12.5px text. */
    line-height: 1;
    color: var(--afd-line);
    transition: color 0.14s ease;
}

.afd-rule.is-met { color: var(--afd-ink-2); }

.afd-rule.is-met .afd-rule__mark { color: var(--afd-live); }

/* ---- Inline states ------------------------------------------------------ */

/* A failed sign-in is field-adjacent, so it stays inline above the primary rather than becoming
   a toast. --danger at ~14% on a --danger-at-40% border, ink at --on-hue's light value because
   this ground never flips. */
.afd-error {
    margin-top: var(--space-4);
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius-md);
    background: rgba(220, 53, 69, 0.14);
    border: 1px solid rgba(220, 53, 69, 0.40);
    color: #ffd7da;
    font-size: 0.875rem;
    line-height: 1.5;
}

/* Sign-up can fail three rules at once, and three sentences run together read as a paragraph
   nobody finishes. One line each, bulleted, so the count is visible before the words are. */
.afd-error__list {
    margin: 0;
    padding-left: 1.15em;
}

.afd-error__list li + li { margin-top: 3px; }

/* "Your session expired." — an explanation, not a failure. Amber on this ground, and the ink is
   the tint's own light value rather than --navy, which would be unreadable here. */
.afd-info {
    margin-top: var(--space-4);
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius-md);
    background: rgba(243, 156, 18, 0.14);
    border: 1px solid rgba(243, 156, 18, 0.40);
    color: #f6d9a6;
    font-size: 0.875rem;
    line-height: 1.5;
}

.afd-legalnote {
    margin-top: var(--space-5);
    padding-top: var(--space-4);
    border-top: 1px solid var(--afd-rule);
    font-size: 12px;
    line-height: 1.6;
    color: var(--afd-faint);
}

.afd-legalnote a { color: var(--afd-muted); text-decoration: underline; }

/* ---- Live pill ---------------------------------------------------------- */

.afd-live {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 3px 10px 3px var(--space-2);
    border-radius: var(--radius-pill);
    background: var(--afd-live-fill);
    border: 1px solid var(--afd-live-edge);
}

.afd-live__dot {
    width: 6px;
    height: 6px;
    border-radius: var(--radius-pill);
    background: var(--afd-live);
    /* Reuses winprob-pulse (10-scorecard.css) at its own 1.6s rather than declaring a fourth
       identical keyframe — the handoff names it as the match. */
    animation: winprob-pulse 1.6s ease-in-out infinite;
}

.afd-live__word {
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: var(--afd-live-ink);
}

/* ---- Resolved: header --------------------------------------------------- */

.afd-resolvedbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    padding-top: var(--space-5);
}

.afd-backchip {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 7px 12px 7px var(--space-2);
    border: none;
    border-radius: var(--radius-pill);
    background: var(--afd-fill);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.10);
    color: var(--afd-ink-3);
    font-family: inherit;
    font-size: 12.5px;
    font-weight: 600;
    cursor: pointer;
}

.afd-backchip .material-symbols-outlined { font-size: 17px; }

.afd-codeecho {
    font-family: ui-monospace, Menlo, Consolas, monospace;
    font-size: 13px;
    font-weight: 700;
    letter-spacing: 0.22em;
    color: var(--afd-metal);
    font-variant-numeric: tabular-nums;
}

.afd-eventhead { padding-top: var(--space-6); }

.afd-eyebrow {
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--afd-metal);
    margin-bottom: 10px;
}

.afd-eventname {
    margin: 0 0 14px;
    font-size: 30px;
    font-weight: 600;
    letter-spacing: -0.03em;
    line-height: 1.08;
    color: var(--afd-ink);
    text-wrap: balance;
}

/* The same vocabulary as .mh-meta on the leaderboard masthead. Every cell is optional — a
   missing course or field size drops its span and its hairline rather than printing an em dash. */
.afd-meta {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    font-size: 13px;
}

.afd-meta__course { color: var(--afd-ink-2); }
.afd-meta__field { color: var(--afd-ink-3); }

.afd-meta__rule {
    width: 1px;
    height: 14px;
    background: rgba(255, 255, 255, 0.18);
}

/* ---- Resolved: the three action rows ------------------------------------ */

.afd-rows {
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding-top: var(--space-6);
}

.afd-row {
    width: 100%;
    padding: 17px 18px;
    border: none;
    border-radius: 14px;
    background: var(--afd-fill);
    box-shadow: inset 0 0 0 1px var(--afd-line);
    color: var(--afd-ink-2);
    font-family: inherit;
    text-align: left;
    cursor: pointer;
    display: flex;
    align-items: center;
    gap: 13px;
    text-decoration: none;
    transition: background 0.14s ease;
}

.afd-row:hover { background: var(--afd-fill-cell); color: var(--afd-ink-2); }

.afd-row__icon { font-size: 22px; color: var(--afd-metal); flex: none; }

.afd-row__body {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.afd-row__name { font-size: 15.5px; font-weight: 600; }
.afd-row__sub { font-size: 12.5px; color: var(--afd-quiet); }

.afd-row__chev {
    margin-left: auto;
    font-size: 20px;
    color: var(--afd-faint);
    flex: none;
}

/* The one primary row. Solid, so its own ink inverts — including the chevron, which on this
   fill would otherwise be the near-invisible --afd-faint. */
.afd-row--primary {
    background: var(--btn-primary-ground);
    box-shadow: none;
    color: var(--btn-primary-ink);
}

.afd-row--primary:hover { background: #ffffff; color: var(--btn-primary-ink); }
.afd-row--primary .afd-row__icon { color: var(--btn-primary-ink); }
.afd-row--primary .afd-row__name { font-weight: 700; letter-spacing: -0.01em; }
.afd-row--primary .afd-row__sub { color: var(--afd-sep); font-weight: 500; }
.afd-row--primary .afd-row__chev { color: var(--afd-faint); }

/* The self-claim picker, once "Claim my spot" is tapped: the same rows, one per name. */
.afd-picks {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    padding-top: var(--space-5);
}

.afd-pick {
    width: 100%;
    padding: 15px 18px;
    border: none;
    border-radius: var(--radius-lg);
    background: var(--afd-fill);
    box-shadow: inset 0 0 0 1px var(--afd-line);
    color: var(--afd-ink-2);
    font-family: inherit;
    font-size: 15.5px;
    font-weight: 600;
    text-align: left;
    cursor: pointer;
    transition: background 0.14s ease;
}

.afd-pick:hover { background: var(--afd-fill-cell); }
.afd-pick:disabled { opacity: 0.6; cursor: not-allowed; }

.afd-linkrow {
    padding-top: var(--space-4);
    text-align: center;
    font-size: 13px;
    color: var(--afd-muted);
}

.afd-linkrow a,
.afd-linkrow button {
    border: none;
    background: none;
    padding: 0;
    font: inherit;
    color: var(--afd-metal-ink);
    font-weight: 600;
    text-decoration: underline;
    cursor: pointer;
}

/* The claim outcome's icon, mirroring .claim-welcome-icon's job on the old screen. */
.afd-outcome {
    width: 56px;
    height: 56px;
    margin: var(--space-6) 0 var(--space-4);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-pill);
    background: var(--afd-metal-wash-soft);
    box-shadow: inset 0 0 0 1px var(--afd-metal-line);
    color: var(--afd-metal-ink);
}

.afd-outcome .material-symbols-outlined { font-size: 28px; }

/* ---- Footer ------------------------------------------------------------- */

.afd-foot {
    margin-top: auto;
    padding: var(--space-6) 0 var(--space-5);
}

/* The pots card. Per the digest rule, a figure with nothing behind it is cut whole — the markup
   renders no card at all when the round has no in-play pots, rather than an empty $0. */
.afd-pots {
    padding: 15px 16px;
    border-radius: 14px;
    background: var(--afd-fill-soft);
    border: 1px solid var(--afd-metal-edge);
}

.afd-pots__label {
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--afd-metal);
    margin-bottom: 9px;
}

.afd-pots__body {
    display: flex;
    align-items: baseline;
    gap: 14px;
    flex-wrap: wrap;
}

.afd-pots__total {
    font-size: 20px;
    font-weight: 600;
    color: var(--afd-money);
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.02em;
}

.afd-pots__breakdown {
    font-size: 12.5px;
    color: var(--afd-quiet);
    font-variant-numeric: tabular-nums;
}

.afd-legal {
    margin-top: 14px;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 9px;
    font-size: 11.5px;
    color: var(--afd-faint);
}

.afd-legal a { color: var(--afd-muted); text-decoration: underline; }
.afd-legal span[aria-hidden] { color: var(--afd-sep); }

/* The rule above the footer, drawn only when the footer has a card above the legal line. */
.afd-foot--ruled { border-top: 1px solid var(--afd-metal-edge); padding-top: var(--space-4); }

/* ---- Signed-out page (/signed-out) -------------------------------------- */

/* Source: handoffs/design_handoff_signed_out_page. It is drawn on this block's own vocabulary —
   the page reuses .afd-page / .afd-shell / .afd-col / .afd-brandrow / .afd-brandpanel* / .afd-head
   / .afd-title / .afd-sub / .afd-outcome / .afd-primary / .afd-secondary / .afd-divider /
   .afd-rows / .afd-row* / .afd-eyebrow / .afd-foot / .afd-legal unchanged, and inherits the
   --afd-* ink from .afd-page for free. A separate partial would have to re-declare all of it.

   Only the product band is new. The design's stat rail and "Get the app" card are not built —
   see the comments in SignedOut.razor for why each was cut rather than approximated. */

/* .afd-head already carries the block's top padding, so the circle's own margin would double it.
   Its 16px below is the drawn 18 snapped to the --space-* scale. */
.afd-head--outcome .afd-outcome { margin-top: 0; }

/* .afd-primary is written for a <button>; here it is an <a> to /login and needs the block
   geometry a button gets for free. The white hover is .afd-row--primary's, which is the same
   near-white primary one row up. */
.afd-primary--link {
    display: block;
    box-sizing: border-box;
    text-align: center;
    text-decoration: none;
}

.afd-primary--link:hover { background: #ffffff; color: var(--btn-primary-ink); }

.afd-secondary__icon { font-size: 19px; color: var(--afd-metal); }

/* Both modifiers are written at .afd-rows.afd-rows--x, because the ≥769px block below sets
   .afd-rows' padding at equal specificity and later in source order — a single class here would
   lose to it and the two stacks would land on the same spacing at desktop. */
.afd-rows.afd-rows--cta { padding-top: var(--space-5); }
.afd-rows.afd-rows--tight { padding-top: var(--space-3); }

/* The product band — three things the sign-out took away. The glyphs and the rule above them are
   metal because they frame what the product does; nothing else in the band takes a hue. */
.afd-band {
    margin-top: var(--space-6);
    padding-top: var(--space-5);
    border-top: 1px solid var(--afd-metal-edge);
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

/* .afd-eyebrow carries its own margin for the resolved-code header; here the band's gap owns it. */
.afd-band .afd-eyebrow { margin-bottom: 0; }

.afd-band__points {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

.afd-band__point {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
}

.afd-band__icon {
    font-size: 20px;
    color: var(--afd-metal);
    flex: none;
    margin-top: 1px;
}

.afd-band__body {
    display: flex;
    flex-direction: column;
    gap: 3px;
    min-width: 0;
}

.afd-band__name {
    font-size: 14.5px;
    font-weight: 600;
    color: var(--afd-ink-2);
}

.afd-band__sub {
    font-size: 12.5px;
    line-height: 1.5;
    color: var(--afd-quiet);
}

/* ---- Desktop brand panel ------------------------------------------------ */

/* Hidden below the breakpoint rather than absent from the DOM: it is one block with no
   phone-side twin, so there is nothing here for the two-DOM rule to guard against. */
.afd-brandpanel { display: none; }

/* ============================================================================
   ≥769px — the two-column shell. Breakpoint matches the rest of the app.
   ============================================================================ */

@media (min-width: 769px) {
    .afd-shell {
        display: grid;
        grid-template-columns: 1.05fr 1fr;
        min-height: 820px;
    }

    .afd-brandpanel {
        display: flex;
        flex-direction: column;
        justify-content: space-between;
        padding: 42px 46px;
        /* Placeholder ground until a per-event image exists. EventMasthead.HeaderImageUrl is
           wired end-to-end but nothing sets it, so there is no asset to put under a scrim here
           either; when one lands, this becomes background-image + --masthead-scrim and the
           geometry is unchanged. */
        background-color: #10141a;
        background-image: repeating-linear-gradient(135deg, rgba(255, 255, 255, 0.045) 0 12px, transparent 12px 24px);
    }

    .afd-brandpanel .afd-brand img { width: 34px; height: 34px; border-radius: 10px; }
    .afd-brandpanel .afd-brand__word { font-size: 12px; color: var(--afd-muted); }

    .afd-brandpanel__body {
        display: flex;
        flex-direction: column;
        gap: 22px;
    }

    .afd-brandpanel__pill {
        display: inline-flex;
        align-self: flex-start;
        align-items: center;
        gap: 7px;
        padding: 5px 13px 5px 10px;
        border-radius: var(--radius-pill);
        background: rgba(201, 173, 110, 0.16);
        border: 1px solid var(--afd-metal-line);
        font-size: 10.5px;
        font-weight: 700;
        letter-spacing: 0.1em;
        text-transform: uppercase;
        color: var(--afd-metal-tab);
    }

    .afd-brandpanel__pill .material-symbols-outlined { font-size: 16px; color: var(--afd-metal-ink); }

    .afd-brandpanel__headline {
        margin: 0;
        font-size: 46px;
        font-weight: 600;
        letter-spacing: -0.035em;
        line-height: 1.05;
        color: var(--afd-ink);
        max-width: 20ch;
        text-wrap: balance;
    }

    .afd-brandpanel__blurb {
        margin: 0;
        max-width: 44ch;
        font-size: 16px;
        line-height: 1.6;
        color: var(--afd-ink-3);
        text-wrap: pretty;
    }

    .afd-brandpanel__caption {
        font-family: ui-monospace, Menlo, Consolas, monospace;
        font-size: 11px;
        letter-spacing: 0.04em;
        color: var(--afd-faint);
    }

    .afd-col {
        display: flex;
        align-items: center;
        justify-content: center;
        padding: 42px 56px;
        background: rgba(255, 255, 255, 0.02);
        border-left: 1px solid rgba(201, 173, 110, 0.22);
    }

    .afd-colinner {
        flex: none;
        max-width: 396px;
    }

    /* The brand row lives in the panel at this width — two marks on one screen is the same
       "two triggers for one thing" the masthead avatar drops below 769px. */
    .afd-brandrow { display: none; }

    .afd-tabs {
        margin-top: 0;
        margin-bottom: 30px;
    }

    .afd-tab { padding: 10px 6px; font-size: 13px; }

    /* Tabs lead the column on desktop; the heading follows them. */
    .afd-head { padding-top: 0; }
    .afd-title { font-size: 30px; }

    .afd-code,
    .afd-fields,
    .afd-rows { padding-top: var(--space-5); }

    .afd-foot { padding-bottom: 0; }
}

/* ---- Reduced motion ----------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
    .afd-live__dot { animation: none; }

    .afd-caret { animation: none; }

    .afd-tab,
    .afd-cell,
    .afd-primary,
    .afd-secondary,
    .afd-row,
    .afd-pick,
    .afd-rule,
    .afd-rule__mark,
    .afd-meter__seg { transition: none; }
}
/* ===================================================================================
   Tee-first round creation (design_handoff_tee_first_round_creation)
   ===================================================================================
   The front door (/events/create), the six-screen round wizard, and the hero card the
   rounds list promotes its Quick round row to.

   Almost nothing here is layout: every card is a `.set-card` and every row a `.set-row`
   from 07-settings.css, because the design's cards ARE that block. What this partial adds
   is the four things that block has no vocabulary for:

     .tee-hero  — the dark "We're on the tee" card, shared by the front door and the
                  rounds list so the gesture is learned once.
     .tee-ring  — the per-player tee dot on a roster row. Hollow means "playing the
                  round's tee", which is everyone, which is why the column has to read as
                  one quiet stripe rather than eight decisions.
     .tee-team  — the A/B pairing blocks and the `vs` rule between them.
     .tee-pick  — the single-select radio a format / pairing rule row carries. A radio is
                  not one of the ten row kinds, and a Segmented can't hold five options
                  with two-line captions.

   Prefix check (the .lvs- vs .ls- lesson): `.tee-` is claimed by nothing in 01–27, and
   this partial concatenates last, so it also wins any tie it happens to create. */

/* ── The hero ──────────────────────────────────────────────────────────────────────
   A dark surface in BOTH themes, the rule --masthead-scrim / --recap-hero-ground /
   --auth-ground follow. Its ink is absolute hex declared once here as local custom
   properties rather than scattered through the block, because on this ground light
   mode's --metal and --text are both invisible. */
.tee-hero {
    --tee-hero-ink: #fff;
    --tee-hero-body: #c8cfd8;
    --tee-hero-badge-ink: #9df0b4;
    --tee-hero-badge-dot: #3ad160;

    display: flex;
    flex-direction: column;
    gap: 14px;
    padding: 20px;
    border-radius: 18px;
    background: linear-gradient(180deg, #1c222a, #12161b);
    box-shadow: 0 12px 28px rgba(20, 26, 34, 0.22);
    text-decoration: none;
}

.tee-hero__badge {
    display: inline-flex;
    align-self: flex-start;
    align-items: center;
    gap: 6px;
    padding: 4px 11px 4px 8px;
    border-radius: var(--radius-pill);
    background: rgba(58, 209, 96, 0.18);
    border: 1px solid rgba(58, 209, 96, 0.42);
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: var(--tee-hero-badge-ink);
}
.tee-hero__badge .material-symbols-outlined { font-size: 14px; }
/* The dot is the "Fastest" variant's glyph slot — same 6px landmark either way, so the two
   copies of this card differ only in words. */
.tee-hero__dot {
    width: 6px;
    height: 6px;
    border-radius: var(--radius-pill);
    background: var(--tee-hero-badge-dot);
}

.tee-hero__title {
    font-size: 22px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.02em;
    line-height: 1.15;
    color: var(--tee-hero-ink);
}
.tee-hero__body {
    margin: 8px 0 0;
    font-size: 13.5px;
    line-height: 1.55;
    color: var(--tee-hero-body);
}

/* Near-white on the dark ground for the same reason --btn-primary-ground exists on the auth
   front door: --navy doubles as a solid chip ground and recedes into a dark card. */
.tee-hero__btn {
    width: 100%;
    padding: 15px;
    border: none;
    border-radius: 13px;
    background: #eef1f4;
    color: #14181d;
    font: inherit;
    font-size: 15px;
    font-weight: var(--font-weight-bold);
    text-align: center;
    text-decoration: none;
    cursor: pointer;
}
.tee-hero__btn:hover { background: #fff; }

/* ── The wizard page ───────────────────────────────────────────────────────────────
   Sits on .settings-ground inside .set-page, so every card and row below is the settings
   block unchanged. Only the column width and the inter-block rhythm are stated here.

   THE GROUND IS THE PARENT, NEVER THE SAME ELEMENT. .settings-ground breaks out of main's
   1rem gutters with `margin: -1rem -1rem 0`; this rule's `margin: 0 auto` is later in the
   cascade and cancels it, so stacking both classes on one div left the grey inset — and let
   the more specific `.app-bar + .set-page` margin-top through as a white gap under the bar.
   Every screen in the wizard is <div class="settings-ground"><div class="set-page tee-page">. */
.tee-page {
    max-width: 640px;
    margin: 0 auto;
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.tee-head { padding: 2px 4px 0; }
.tee-head__title {
    margin: 0;
    font-size: 30px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.025em;
    line-height: 1.1;
    color: var(--text);
    text-wrap: balance;
}
.tee-head__sub {
    margin: 7px 0 0;
    max-width: 52ch;
    font-size: 14px;
    line-height: 1.5;
    color: var(--text-muted);
}

/* The screen's one primary. Accent because this is the money-and-live hue and the tap it
   guards is "start the round". */
.tee-primary {
    width: 100%;
    padding: 16px;
    border: none;
    border-radius: 13px;
    background: var(--color-accent);
    color: var(--on-hue);
    font: inherit;
    font-size: 15.5px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.01em;
    text-align: center;
    text-decoration: none;
    cursor: pointer;
}
.tee-primary:hover:not(:disabled) { background: color-mix(in srgb, var(--color-accent) 88%, #000); }
/* Disabled here means "you haven't finished pairing yet", and the button says so — so it
   must not read as broken. Quiet fill, quiet ink, default cursor, never `opacity`. */
.tee-primary:disabled {
    background: var(--control-fill-strong);
    color: var(--ink-disabled);
    cursor: default;
}

.tee-caption {
    margin: 0;
    text-align: center;
    font-size: 12.5px;
    line-height: 1.55;
    color: var(--text-quiet);
}
.tee-caption strong { color: var(--text); font-weight: var(--font-weight-semibold); }
.tee-caption a,
.tee-link {
    color: var(--metal);
    font-weight: var(--font-weight-semibold);
    background: none;
    border: none;
    font-size: inherit;
    font-family: inherit;
    cursor: pointer;
    padding: 0;
}

/* Two rules with tracked caps between them — "Or plan something". */
.tee-divider {
    display: flex;
    align-items: center;
    gap: 11px;
}
.tee-divider::before,
.tee-divider::after {
    content: "";
    flex: 1;
    height: 1px;
    background: var(--hairline);
}
.tee-divider__label {
    font-size: 10.5px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

/* ── Course search ─────────────────────────────────────────────────────────────────
   A search box and its button, inside the card that holds the results. */
.tee-search {
    display: flex;
    gap: 8px;
    align-items: center;
    padding: 14px 16px;
}
.tee-search__field {
    flex: 1;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 9px;
    height: 46px;
    padding: 0 13px;
    border: 1px solid var(--hairline);
    border-radius: var(--radius-md);
    background: var(--surface-raised);
}
.tee-search__field .material-symbols-outlined { flex: none; font-size: 19px; color: var(--ink-disabled); }
.tee-search__field input {
    flex: 1;
    min-width: 0;
    border: none;
    background: none;
    font: inherit;
    font-size: 15.5px;
    color: var(--text);
    outline: none;
}
.tee-search__btn {
    flex: none;
    height: 46px;
    padding: 0 16px;
    border: none;
    border-radius: var(--radius-md);
    background: var(--navy);
    color: var(--on-solid);
    font: inherit;
    font-size: 14px;
    font-weight: var(--font-weight-semibold);
    cursor: pointer;
}
.tee-search__btn:disabled { background: var(--control-fill-strong); color: var(--ink-disabled); cursor: default; }

/* A result row. Whole-row button, so the name and the sub are spans (a button may only
   contain phrasing content) and both need `display:block` — the same override
   24-account.css writes for its full-row rows. */
.tee-result {
    display: flex;
    align-items: center;
    gap: 14px;
    width: 100%;
    padding: 13px 20px;
    min-height: 58px;
    border: none;
    border-top: 1px solid var(--hairline-soft);
    background: none;
    font: inherit;
    text-align: left;
    cursor: pointer;
}
.tee-result:hover { background: var(--control-fill); }
.tee-result__mark { flex: none; width: 21px; display: grid; place-items: center; }
.tee-result__mark .material-symbols-outlined { font-size: 21px; color: var(--color-accent); }
.tee-result__body { flex: 1; min-width: 0; }
.tee-result__name {
    display: block;
    font-size: 15px;
    font-weight: var(--font-weight-semibold);
    color: var(--text);
}
.tee-result__sub {
    display: block;
    margin-top: 3px;
    font-size: 12.5px;
    color: var(--text-muted);
}
.tee-result.is-selected {
    background: color-mix(in srgb, var(--color-accent) 7%, transparent);
}
.tee-result.is-selected .tee-result__name { font-weight: var(--font-weight-bold); }
/* The demoted search row at the foot of an event's own course list. */
.tee-result--muted .tee-result__name { font-size: 14.5px; color: var(--text-quiet); }
.tee-result--muted .tee-result__mark .material-symbols-outlined { font-size: 19px; color: var(--ink-disabled); }
.tee-result__chev { flex: none; font-size: 20px; color: var(--ink-disabled); }

/* ── Roster rows ───────────────────────────────────────────────────────────────────
   Denser than a .set-row (52px, not 62) because eight of them stack, and carrying four
   cells rather than the settings block's two. */
.tee-roster__head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    padding: 16px 20px 8px;
}
.tee-roster__eyebrow,
.tee-roster__count {
    font-size: 11px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
}
.tee-roster__eyebrow { color: var(--text-quiet); }
/* Metal, because "8 of 12 here" is a standing statement about tonight's field. */
.tee-roster__count { color: var(--metal); }
.tee-roster__all {
    border: none;
    background: none;
    font: inherit;
    font-size: 12.5px;
    font-weight: var(--font-weight-semibold);
    color: var(--metal);
    cursor: pointer;
}

.tee-player {
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
    padding: 9px 20px;
    min-height: 52px;
    border-top: 1px solid var(--hairline-soft);
}
.tee-player__avatar {
    flex: none;
    width: 28px;
    height: 28px;
    border-radius: var(--radius-pill);
    background: var(--control-fill-strong);
    color: var(--text-muted);
    display: grid;
    place-items: center;
    font-size: 11px;
    font-weight: var(--font-weight-bold);
}
.tee-player__avatar--self { background: var(--navy); color: var(--on-solid); }
.tee-player__body { flex: 1; min-width: 0; }
.tee-player__name {
    display: block;
    font-size: 15px;
    font-weight: var(--font-weight-semibold);
    color: var(--text);
}
.tee-player__name em { font-style: normal; font-weight: 400; color: var(--text-quiet); }
/* The only thing that appears under a name: "Gold tees", when this player is off the
   round's tee. Metal, because it's a fact about how they're playing, not a fault. */
.tee-player__over {
    display: block;
    margin-top: 2px;
    font-size: 12px;
    font-weight: var(--font-weight-semibold);
    color: var(--metal);
}

/* The index box. A dashed border and an em dash is the empty state, and it is deliberately
   not amber: a missing index never blocks, it just means that player scores gross. */
.tee-hcp {
    flex: none;
    width: 64px;
    height: 38px;
    padding: 0;
    border: 1px solid var(--hairline);
    border-radius: 9px;
    background: var(--surface-raised);
    font: inherit;
    font-size: 14.5px;
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
    color: var(--text);
    text-align: center;
    cursor: pointer;
}
.tee-hcp--empty {
    border-style: dashed;
    border-color: var(--control-fill-strong);
    background: var(--control-fill);
    color: var(--ink-disabled);
}
/* Flow B: the index is a league-owned value, so it reads as a figure, not a field. */
.tee-hcp--read {
    width: auto;
    min-width: 34px;
    border: none;
    background: none;
    text-align: right;
}

/* ── .tee-ring — the per-player tee dot ────────────────────────────────────────────
   Default is hollow and nothing else. The whole column has to read as one quiet stripe;
   filling every ring with the round's tee colour would draw eight decisions where none
   were made. Only an OVERRIDE gets colour, and it takes the metal wrapper wash too. */
.tee-ring {
    flex: none;
    width: 30px;
    height: 30px;
    padding: 0;
    display: grid;
    place-items: center;
    border: none;
    border-radius: var(--radius-pill);
    background: none;
    cursor: pointer;
}
.tee-ring__dot {
    width: 13px;
    height: 13px;
    border-radius: 50%;
    border: 1.5px solid var(--border-strong);
}
.tee-ring--over { background: var(--metal-wash-16); }
.tee-ring--over .tee-ring__dot { border: 1px solid rgba(0, 0, 0, 0.18); }
/* Someone who isn't playing has no tee to override, so the cell is held open and empty
   rather than the ring being removed and the row re-flowing. */
.tee-ring--none { visibility: hidden; }

/* Flow B check-in box. 22px square, accent when checked — the row wash says the same
   thing, and both together are what make a checked row scannable at arm's length. */
.tee-check {
    flex: none;
    width: 22px;
    height: 22px;
    padding: 0;
    display: grid;
    place-items: center;
    border: 1.5px solid var(--control-fill-strong);
    border-radius: 7px;
    background: none;
    cursor: pointer;
}
.tee-check.is-on {
    border-color: var(--color-accent);
    background: var(--color-accent);
}
.tee-check .material-symbols-outlined { font-size: 15px; color: var(--on-hue); }
.tee-player.is-in { background: color-mix(in srgb, var(--color-accent) 6%, transparent); }
/* A no-show stays in the league; it just misses this week. Muted, shorter, no tee ring. */
.tee-player.is-out { min-height: 50px; }
.tee-player.is-out .tee-player__name { font-weight: 400; color: var(--text-quiet); }
.tee-player.is-out .tee-hcp--read { color: var(--ink-disabled); font-weight: 400; }

/* The add-a-player line at the foot of the cold-start roster. */
.tee-add {
    display: flex;
    gap: 8px;
    align-items: center;
    padding: 12px 20px 14px;
    border-top: 1px solid var(--hairline-soft);
}
.tee-add__name,
.tee-add__hcp {
    height: 44px;
    padding: 0 13px;
    border: 1px solid var(--hairline);
    border-radius: var(--radius-md);
    background: var(--surface-raised);
    font: inherit;
    font-size: 15px;
    color: var(--text);
}
.tee-add__name { flex: 1; min-width: 0; }
.tee-add__hcp { flex: none; width: 64px; padding: 0; text-align: center; font-size: 14.5px; }
.tee-add__btn {
    flex: none;
    height: 44px;
    padding: 0 15px;
    border: none;
    border-radius: var(--radius-md);
    background: var(--navy);
    color: var(--on-solid);
    font: inherit;
    font-size: 13.5px;
    font-weight: var(--font-weight-semibold);
    cursor: pointer;
}
.tee-add__btn:disabled { background: var(--control-fill-strong); color: var(--ink-disabled); cursor: default; }

/* ── .tee-pick — a single-select row ───────────────────────────────────────────────
   The format list and the pairing rule. A 22px radio on the right rather than a check on
   the left, because the left of these rows is a name plus a full sentence of explanation. */
.tee-pick {
    display: flex;
    align-items: center;
    gap: 14px;
    width: 100%;
    padding: 12px 20px;
    min-height: 58px;
    border: none;
    border-top: 1px solid var(--hairline-soft);
    background: none;
    font: inherit;
    text-align: left;
    cursor: pointer;
}
.tee-pick:hover { background: var(--control-fill); }
.tee-pick__body { flex: 1; min-width: 0; }
.tee-pick__name {
    display: block;
    font-size: 15px;
    font-weight: var(--font-weight-semibold);
    color: var(--text);
}
.tee-pick__sub {
    display: block;
    margin-top: 3px;
    font-size: 12.5px;
    line-height: 1.4;
    color: var(--text-muted);
}
.tee-pick__radio {
    flex: none;
    width: 22px;
    height: 22px;
    display: grid;
    place-items: center;
    border-radius: var(--radius-pill);
    border: 1.5px solid var(--control-fill-strong);
}
.tee-pick.is-on { background: color-mix(in srgb, var(--color-accent) 7%, transparent); }
.tee-pick.is-on .tee-pick__name { font-weight: var(--font-weight-bold); }
.tee-pick.is-on .tee-pick__radio { border: none; background: var(--color-accent); }
.tee-pick__radio .material-symbols-outlined { font-size: 15px; color: var(--on-hue); }
/* An answer that belongs to the format above it — the Teams card's "who are you playing?"
   (design_handoff_teams_format §1). Indented to the same 44px the .set-row--sub knobs above it
   take, and washed, so the three of them read as one dependent block rather than as three more
   formats. */
.tee-pick--sub {
    padding-left: 44px;
    background: var(--metal-wash-05);
}
.tee-pick--sub:hover { background: var(--metal-wash-07); }
.tee-pick--sub.is-on { background: color-mix(in srgb, var(--color-accent) 7%, transparent); }

/* The drill-in to the rest of the catalog: same row, quieter, chevron instead of a radio. */
.tee-pick--more { min-height: 54px; }
.tee-pick--more .tee-pick__name { font-size: 14.5px; color: var(--text-quiet); }

/* The Scored row closes the format card and belongs to the whole card above it, so it takes
   a heavier rule than the hairline between two format choices. */
.tee-row--divide { border-top: 2px solid var(--control-fill-strong); }

/* ── The draw preview ──────────────────────────────────────────────────────────────── */
.tee-group__head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    padding: 16px 20px 8px;
}
.tee-group__head + .tee-group__head,
.set-card > .tee-group + .tee-group__head { border-top: 1px solid var(--hairline-soft); padding-top: 12px; }
.tee-group__label {
    font-size: 11px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-quiet);
}
.tee-group__label--armed { color: var(--metal); }
.tee-group__total {
    font-size: 11.5px;
    color: var(--text-quiet);
    font-variant-numeric: tabular-nums;
}
.tee-group {
    padding: 0 20px 14px;
    display: flex;
    flex-direction: column;
    gap: 7px;
}
.tee-group__row { display: flex; align-items: center; gap: 10px; }
.tee-group__name { flex: 1; font-size: 14.5px; font-weight: var(--font-weight-semibold); color: var(--text); }
.tee-group__idx { font-size: 13px; color: var(--text-quiet); font-variant-numeric: tabular-nums; }
/* "no index" in words, never an em dash — the whole point is that it is legible as a
   thing to fix rather than as missing data. */
.tee-group__idx--none { color: var(--ink-disabled); font-variant-numeric: normal; }

/* ── .tee-team — the pairing blocks ────────────────────────────────────────────────── */
.tee-team {
    padding: 0 20px 6px;
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.tee-team + .tee-vs + .tee-team { padding: 6px 20px 14px; }
.tee-team__row {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 9px 12px;
    border: none;
    border-radius: 11px;
    background: var(--control-fill);
    font: inherit;
    text-align: left;
    cursor: pointer;
}
.tee-team__badge {
    flex: none;
    width: 20px;
    height: 20px;
    border-radius: 6px;
    display: grid;
    place-items: center;
    font-size: 10.5px;
    font-weight: var(--font-weight-bold);
    color: var(--on-solid);
}
.tee-team__badge--a { background: var(--navy); }
/* B is metal rather than a second neutral: A and B are a seeding, which is a standing. */
.tee-team__badge--b { background: var(--metal); color: var(--on-solid); }
.tee-team__name { flex: 1; min-width: 0; font-size: 14.5px; font-weight: var(--font-weight-semibold); color: var(--text); }
.tee-team__idx { font-size: 12.5px; color: var(--text-quiet); font-variant-numeric: tabular-nums; }
.tee-team__idx--none { color: var(--ink-disabled); font-variant-numeric: normal; }

.tee-vs {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 5px 20px;
}
.tee-vs::before,
.tee-vs::after {
    content: "";
    flex: 1;
    height: 1px;
    background: var(--control-fill-strong);
}
.tee-vs span {
    font-size: 10.5px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--metal);
}

/* Manual pairing, armed. The halo is what makes "this one is waiting for a partner"
   survive a glance at a phone held at waist height. */
.tee-team__row--pick {
    background: var(--surface-raised);
    border: 1px solid var(--hairline);
    padding: 11px 13px;
    border-radius: 12px;
    gap: 11px;
}
.tee-team__row--pick:hover { background: var(--control-fill); }
.tee-team__row--armed {
    background: color-mix(in srgb, var(--color-accent) 10%, transparent);
    border: 2px solid var(--color-accent);
    box-shadow: 0 0 0 4px color-mix(in srgb, var(--color-accent) 10%, transparent);
}
.tee-team__row--armed .tee-team__name { font-weight: var(--font-weight-bold); }
.tee-team__row--armed .tee-player__avatar { background: var(--color-accent); color: var(--on-hue); }
.tee-team__row--armed .tee-team__idx { color: var(--color-accent); font-weight: var(--font-weight-semibold); }
.tee-team__check { flex: none; font-size: 19px; color: var(--color-accent); }
.tee-team__hint {
    margin: 0;
    padding: 6px 20px 12px;
    font-size: 12.5px;
    line-height: 1.5;
    color: var(--text-muted);
}

/* ── Money + live ──────────────────────────────────────────────────────────────────── */
/* The one place a figure is green on these screens: money in play. */
.tee-money { color: var(--ink-on-accent-tint, var(--color-accent)); font-variant-numeric: tabular-nums; font-weight: var(--font-weight-bold); }
.set-card__foot--money > .material-symbols-outlined { color: var(--color-accent); }
/* A wager scored against the round's grain. Brass, weight, and the words — the deviation
   has to be readable on the summary row or the per-game screen is the only place it exists. */
.tee-deviation { color: var(--metal); font-weight: var(--font-weight-semibold); }

/* Amber means one thing on these screens: somebody has no index and a net game is about to
   be computed at scratch for them. Ink on the tint is page-local and reverts in dark mode,
   the shape .cm-page / .set-page / .hc-page / .lg-page all use. */
.tee-page { --tee-warn-ink: #8a5a00; }
:root[data-theme="dark"] .tee-page { --tee-warn-ink: var(--warning); }
.set-card__foot--warn {
    background: color-mix(in srgb, var(--warning) 10%, transparent);
    color: var(--tee-warn-ink);
}
.set-card__foot--warn > .material-symbols-outlined { color: var(--tee-warn-ink); }
.set-card__foot--warn a,
.set-card__foot--warn .tee-link { color: inherit; font-weight: var(--font-weight-bold); text-decoration: underline; }

.tee-live__pill {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 3px 10px 3px 8px;
    border-radius: var(--radius-pill);
    background: color-mix(in srgb, var(--color-accent) 12%, transparent);
    border: 1px solid color-mix(in srgb, var(--color-accent) 38%, transparent);
    margin-bottom: 10px;
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: var(--ink-on-accent-tint, var(--color-accent));
}
.tee-live__pill .tee-hero__dot { background: var(--color-accent); }

/* A scheduled round is a STANDING fact — it isn't live and there is no money on it yet — so its
   pill and its date card take metal rather than the live screen's accent
   (design_handoff_teams_format §4). */
.tee-sched__pill {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 3px 10px 3px 8px;
    border-radius: var(--radius-pill);
    background: var(--metal-wash-16);
    border: 1px solid var(--metal-line);
    margin-bottom: 10px;
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: var(--metal-strong);
}
.tee-sched__pill .material-symbols-outlined { font-size: 14px; }

.tee-when { border: 1px solid var(--metal-edge); }

/* The join code is text to read aloud or type, not a button. */
.tee-code {
    display: inline-flex;
    align-items: center;
    height: 40px;
    padding: 0 14px;
    border-radius: var(--radius-md);
    border: 1px solid var(--metal-line);
    background: var(--metal-wash-10);
    color: var(--metal);
    font-family: ui-monospace, Menlo, Consolas, monospace;
    font-size: 17px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.14em;
}

.tee-share {
    display: flex;
    gap: 8px;
    align-items: center;
    padding: 6px 20px 16px;
}
.tee-share .link-input { flex: 1; min-width: 0; }
.tee-share__copy {
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    height: 40px;
    padding: 0 14px;
    border: none;
    border-radius: var(--radius-md);
    background: var(--color-accent);
    color: var(--on-hue);
    font: inherit;
    font-size: 13px;
    font-weight: var(--font-weight-semibold);
    cursor: pointer;
}
.tee-share__copy .material-symbols-outlined { font-size: 17px; }

/* The promote card. Metal edge rather than accent: it offers a standing (a season), not
   money and not something live. */
.tee-promote { border-color: var(--metal-edge); }
.tee-promote__actions { display: flex; gap: 9px; flex-wrap: wrap; margin-top: 2px; }

/* ── Phone ─────────────────────────────────────────────────────────────────────────
   The wizard's cards are already single-column; what has to give at 390px is the roster
   row, which carries four cells where a .set-row carries two. */
@media (max-width: 480px) {
    .tee-head__title { font-size: 27px; }
    .tee-player { gap: 10px; padding-left: 16px; padding-right: 16px; }
    .tee-roster__head,
    .tee-group__head,
    .tee-group,
    .tee-team { padding-left: 16px; padding-right: 16px; }
    .tee-hcp { width: 58px; }
    .tee-add { padding-left: 16px; padding-right: 16px; }
    .tee-add__hcp { width: 56px; }
}
/* ============================================================================
   TEAMS MODE ON THE LEADERBOARD  (design_handoff_teams_format §3)
   ============================================================================
   The board itself is .board-card / .board-head / .board-row from 18-leaderboard.css,
   unchanged — this partial adds three things that board has no vocabulary for:

     .tb-rail   — the pot rail that moved off the retired Groups tab. Three cells,
                  front / back / total, each with its amount, its winner and a
                  settled-or-in-play chip.
     .tb-card   — the hole-by-hole grid inside an expanded team row, and the two
                  marking treatments the counting-ball rule chooses between.
     .tb-foot   — the card's closing figures.

   The prefix is .tb- and NOT .team-: 15-league-responsive.css and 22-league.css both
   own team vocabulary further down the cascade. Check the later partials before
   picking a prefix — .ls- vs .lvs- is the scar this rule came from.

   Colour discipline, unchanged from everywhere else: --metal-* is STANDING (the
   position tile, the leading pot cell, the mark on a rare team ball's row label),
   --color-accent is LIVE OR MONEY (a pot figure, a settled amount), --under-par is
   UNDER PAR. The struck-out ball is neutral ink, because a dropped ball is not a
   fault, not money and not a standing — it is just the one that didn't count.
   ============================================================================ */

/* ── The pot rail ──────────────────────────────────────────────────────────── */
/* It CLOSES the card rather than heading it — the ranking is what the reader came for and the
   settlement follows from it, the same order .rt-foot puts a card's closing sentence in. So the
   divider is on top. */
.tb-rail {
    border-top: 1px solid var(--hairline);
}
/* The rail is the card's last child now, so the row above it is no longer :last-child and keeps
   the hairline .board-row gives every row — which would double up against the rail's own. The
   rail owns that line; whatever sits directly above it gives its own up. */
.tb-board .board-row:has(+ .tb-rail),
.tb-board .board-detail:has(+ .tb-rail) { border-bottom: none; }
.tb-rail__head {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    flex-wrap: wrap;
    padding: 14px var(--space-4) 10px;
}
.tb-rail__eyebrow {
    font-size: 11px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--metal);
}
.tb-rail__chip {
    display: inline-flex;
    align-items: center;
    padding: 3px 10px;
    border-radius: var(--radius-pill);
    background: var(--control-fill);
    font-size: 11px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-muted);
}
.tb-rail__end {
    margin-left: auto;
    font-size: 13px;
    color: var(--text-muted);
}

.tb-rail__cells {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
}
.tb-rail__cell {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 14px var(--space-4) 16px;
    border-left: 1px solid var(--hairline-soft);
}
.tb-rail__cell:first-child { border-left: none; }
/* Metal wash on a cell that has been settled — the standing it frames is decided. */
.tb-rail__cell--lead { background: var(--metal-wash-05); }
.tb-rail__top {
    display: flex;
    align-items: center;
    gap: var(--space-2);
}
.tb-rail__label {
    font-size: 11px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-quiet);
}
.tb-rail__fig {
    font-size: 26px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.02em;
    font-variant-numeric: tabular-nums;
    color: var(--text);
}
/* A figure that is money reads as money. */
.tb-rail__fig--money { color: var(--color-accent); }
.tb-rail__sub {
    font-size: 12.5px;
    line-height: 1.4;
    color: var(--text-muted);
}

/* ── The row's pot cell ────────────────────────────────────────────────────── */
.tb-pot {
    color: var(--color-accent);
    font-weight: var(--font-weight-bold);
    font-variant-numeric: tabular-nums;
}

/* ── The expanded team card ────────────────────────────────────────────────── */
/* A SIBLING of the row (see TeamsBoard.razor) rather than a child, so its clicks
   don't bubble back through the row toggle. Geometry is the player scorecard's:
   metal rule under the head, no inner panel, no second background. */
.tb-detail { padding-bottom: var(--space-4); }

/* The header is 18-leaderboard.css's own .psc-head block — .psc-eyebrow, .psc-rule,
   .psc-name, .psc-hcp, .psc-close — which is already written and already responsive
   (.psc-close goes order:1 / margin-left:auto below 768px, .psc-hcp drops to its own
   line). Only two things differ, and both are because a team name is four surnames:
   .psc-name is flex-shrink:0 + nowrap at source, which is right for one player and
   wrong for four, and there are no .psc-tabs here to push the close to the right. */
.tb-detail .psc-name {
    flex: 1 1 0;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
}
.tb-detail .psc-close {
    margin-left: auto;
    /* Pinned to the top edge, so it stays put when the name wraps to two lines. */
    align-self: flex-start;
}

/* ── The grid ──────────────────────────────────────────────────────────────── */
/* The players board already solved this: desktop draws all 18 on one template and a
   phone stacks two nines on ONE SHARED template, so hole 9 sits above hole 18 and
   Out sits above In. Both drawings are in the DOM and each hides in its own media
   query — the wide one is a 22-column grid and the stacked one is two 12-column
   grids, so a blanket display flip would flatten one of them. It used to be a single
   18-wide row with overflow-x:auto, which is the one thing the Players board's own
   card never asks anybody to do. */
.tb-card {
    margin-top: var(--space-3);
    font-variant-numeric: tabular-nums;
}
.tb-card--18 {
    --tb-cols: 76px repeat(9, 1fr) 44px repeat(9, 1fr) 44px 52px;
    border-top: 1px solid var(--metal-edge);
}
/* minmax(0, 1fr), NOT 1fr. A bare 1fr is minmax(auto, 1fr), which floors each hole
   column at its cell's min-content width — with cell padding that is ~24px, and
   9 × 24 + 60 + 32 + 36 overflows a 390px card, so the last column gets shaved off
   inside a border-radius/overflow-hidden board. Don't "fix" that by shrinking the
   label column back down; the label column is what change 3 of this work widened. */
.tb-card--9 {
    display: none;
    --tb-cols: 60px repeat(9, minmax(0, 1fr)) 32px 36px;
}
/* A round that plays a single nine has no wide drawing, so the stacked one shows at
   every width and takes the desktop label + summary widths above 768px. */
.tb-card--9.tb-card--only {
    display: block;
    --tb-cols: 76px repeat(9, 1fr) 44px 52px;
}
.tb-nine { border-top: 1px solid var(--metal-edge); }
.tb-nine--back { margin-top: 10px; }

.tb-card__row {
    display: grid;
    grid-template-columns: var(--tb-cols);
    align-items: stretch;
    text-align: center;
}
.tb-card__label,
.tb-card__cell {
    min-width: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 7px 2px;
    font-size: 13px;
    border-top: 1px solid var(--hairline-soft);
}
/* 76px, not the players card's 56: a surname has to fit where "R12" used to. */
.tb-card__label {
    justify-content: flex-start;
    padding-left: 2px;
    font-size: 12.5px;
    color: var(--text-muted);
    white-space: nowrap;
    overflow: hidden;
}
/* The inner chip is what carries a mark, so a strike is the width of the numeral and
   a ring is a circle round it rather than round the whole column. */
.tb-card__chip {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 20px;
    padding: 1px 4px;
    border-radius: var(--radius-sm);
}

/* Hole and Par carry no rule of their own — the card opens on the metal one above. */
.tb-card__row--head .tb-card__label,
.tb-card__row--head .tb-card__cell,
.tb-card__row--par .tb-card__label,
.tb-card__row--par .tb-card__cell {
    border-top: none;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

/* Out / In / Tot are separated by vertical metal hairlines, the way .psc-sum is. Out
   takes both edges on the 18-wide template, because there it sits between the nines. */
.tb-card__cell--sum { border-left: 1px solid var(--metal-edge); color: var(--metal); }
.tb-card__cell--sum-out { border-right: 1px solid var(--metal-edge); }
.tb-card__row--head .tb-card__cell--sum { color: var(--metal); }
.tb-card__row--par .tb-card__cell--sum {
    font-weight: var(--font-weight-bold);
    color: var(--metal);
}
.tb-card__row--player .tb-card__cell--sum {
    font-weight: var(--font-weight-semibold);
    color: var(--metal-strong);
}
/* A summary nothing has been posted into yet. Em dashes are the one thing --ink-disabled
   still means on this screen. */
.tb-card__chip--dash { color: var(--ink-disabled); }

.tb-card__row--team .tb-card__label {
    color: var(--metal);
    font-weight: var(--font-weight-bold);
}
.tb-card__row--team .tb-card__cell {
    font-weight: var(--font-weight-bold);
    border-top: 1px solid var(--metal-edge);
}

/* ── The two marks, and the rule that picks between them ───────────────────── */
/* At ONE counting ball the counter is shaded: one of two is a real 50/50 signal.
   At more than one the DROPPED ball is struck out instead — shading three of four
   would ink 75% of the card and turn the one fact worth seeing into a gap in the
   fill. One mark per hole either way, and it scales to four of five. */
.tb-card__chip--counted { background: var(--metal-wash-18); color: var(--text); }
/* Neutral ink — a dropped ball is not a fault, not money and not a standing — but
   --ink-disabled faded the numeral AND the rule to nothing at phone sizes, so the
   ink steps up to --text-muted and the STRIKE carries the signal instead. */
.tb-card__chip--dropped {
    color: var(--text-muted);
    text-decoration: line-through;
    text-decoration-color: color-mix(in srgb, var(--text) 62%, transparent);
    text-decoration-thickness: 1.5px;
}
/* The rare team ball: two or better under count × par (TeamsBoardView.TeamBallIsRare),
   drawn the way .psc-mark--birdie is. Sized locally because that one is 30px, which
   would blow a 1fr hole column here. */
.tb-card__chip--rare {
    width: 24px;
    height: 24px;
    min-width: 0;
    padding: 0;
    border-radius: 50%;
    box-shadow: inset 0 0 0 1.5px var(--under-par);
    color: var(--mark-under-ink);
    font-weight: var(--font-weight-bold);
}

.tb-legend {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex-wrap: wrap;
    margin: var(--space-3) 0 0;
    font-size: 12.5px;
    color: var(--text-muted);
}
.tb-legend__mark {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 22px;
    padding: 1px 5px;
    border-radius: var(--radius-sm);
    font-variant-numeric: tabular-nums;
}
.tb-legend__mark.is-counted { background: var(--metal-wash-18); color: var(--text); }
/* The swatch draws exactly what the card draws — same three decoration properties. */
.tb-legend__mark.is-dropped {
    color: var(--text-muted);
    text-decoration: line-through;
    text-decoration-color: color-mix(in srgb, var(--text) 62%, transparent);
    text-decoration-thickness: 1.5px;
}

/* ── The card's closing figures ────────────────────────────────────────────── */
.tb-foot {
    display: flex;
    justify-content: flex-end;
    gap: var(--space-5);
    flex-wrap: wrap;
    margin: var(--space-4) 0 0;
    padding-top: var(--space-3);
    border-top: 1px solid var(--hairline-soft);
    font-size: 15px;
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
}
.tb-foot__cell {
    display: inline-flex;
    align-items: baseline;
    gap: var(--space-2);
}
.tb-foot__label {
    font-size: 10.5px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

/* 768, not 767: this is the width at which the board itself switches to --board-cols-sm
   and the players scorecard swaps .psc-grid--18 for .psc-grid--9. A one-pixel offset
   left the rail on desktop columns inside a phone-column board. */
@media (max-width: 768px) {
    /* Front / back / total stack rather than squeezing three 26px figures into 390px. */
    .tb-rail__cells { grid-template-columns: 1fr; }
    .tb-rail__cell {
        border-left: none;
        border-top: 1px solid var(--hairline-soft);
        flex-direction: row;
        align-items: baseline;
        gap: var(--space-3);
        padding: 10px var(--space-3);
        flex-wrap: wrap;
    }
    .tb-rail__cell:first-child { border-top: none; }
    .tb-rail__fig { font-size: 20px; }
    .tb-rail__sub { flex-basis: 100%; }

    /* The team name wraps to two lines, and ONLY in Teams mode — scoped to .tb-board so
       the players board is untouched, where a single name has never needed two lines and
       wrapping it would only make rows uneven. At 390px the team column resolves to about
       154px and four surnames need roughly 250px, so nowrap+ellipsis cut mid-surname. */
    .tb-board .board-player__name {
        white-space: normal;
        overflow: visible;
        font-size: 14px;
        line-height: 1.25;
    }

    /* The name is allowed two lines in the card header too, for the same reason. */
    .tb-detail .psc-name {
        white-space: normal;
        overflow: visible;
        line-height: 1.2;
    }

    .tb-card--18 { display: none; }
    .tb-card--9 { display: block; }
    .tb-card--9.tb-card--only { --tb-cols: 60px repeat(9, minmax(0, 1fr)) 32px 36px; }

    .tb-card__label { font-size: 12px; }
    .tb-card__cell { font-size: 12.5px; }
    .tb-card__row--head .tb-card__label,
    .tb-card__row--head .tb-card__cell,
    .tb-card__row--par .tb-card__label,
    .tb-card__row--par .tb-card__cell { font-size: 12.5px; }
    /* min-width:0 is the other half of the minmax(0, 1fr) note above — a chip with a
       floor puts the min-content width straight back and shaves the Tot column. */
    .tb-card__chip { min-width: 0; padding: 1px 2px; }
    .tb-card__chip--rare { width: 22px; height: 22px; padding: 0; }
}

/* ============================================================================
   PAYOUT PLACES  (design_handoff_teams_format §2)
   ============================================================================
   The .pp-* block, hosted on .set-card / .set-row like every settings-shaped
   screen — the only things it adds are the split stripe, the percent field and
   the preset chips, none of which the row system has a vocabulary for.

   Metal is a PLACE (a standing), green is the money the place is worth. The
   stripe's three strengths are the podium's own taper, so first / second / third
   read the same here as they do on a board.
   ============================================================================ */

.pp-stripe {
    display: flex;
    gap: 2px;
    height: 10px;
    margin: var(--space-2) var(--space-4) var(--space-1);
    border-radius: var(--radius-pill);
    overflow: hidden;
}
.pp-stripe__seg { display: block; }
.pp-stripe__seg--1 { background: var(--metal); }
.pp-stripe__seg--2 { background: var(--metal-line); }
.pp-stripe__seg--3 { background: var(--metal-edge); }

/* The place row leads with the podium tile — the same one the board uses, so a
   place looks like a place wherever it is drawn. */
.pp-row { gap: var(--space-3); }
.pp-row .pos-tile { flex: none; }

.pp-figs {
    display: inline-flex;
    align-items: center;
    gap: var(--space-3);
}
.pp-pct {
    display: inline-flex;
    align-items: baseline;
    gap: 2px;
}
.pp-pct__input {
    width: 58px;
    text-align: right;
    font-variant-numeric: tabular-nums;
}
.pp-pct__sign { font-size: 13px; color: var(--text-muted); }
/* What the percent currently means, in the hue that means money. */
.pp-money {
    min-width: 64px;
    text-align: right;
    font-size: 15px;
    font-weight: var(--font-weight-bold);
    font-variant-numeric: tabular-nums;
    color: var(--color-accent);
}

.pp-presets {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-4) var(--space-1);
}
.pp-preset {
    display: inline-flex;
    align-items: center;
    height: 36px;
    padding: 0 14px;
    border: 1px solid var(--hairline);
    border-radius: var(--radius-pill);
    background: var(--surface-raised);
    font: inherit;
    font-size: 13.5px;
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
    color: var(--text);
    cursor: pointer;
}
.pp-preset:hover { background: var(--control-fill); }
.pp-preset.is-on {
    border-color: var(--metal-line);
    background: var(--metal-wash-16);
    color: var(--metal-strong);
}

@media (max-width: 480px) {
    .pp-figs { gap: var(--space-2); }
    .pp-money { min-width: 52px; font-size: 14px; }
    .pp-pct__input { width: 50px; }
}
/* ===================================================================================
   Brand-new-account welcome (design_handoff_round_hub_and_onboarding, Part 2)
   ===================================================================================
   The screen My events shows when there are no events, plus the five-step onboarding
   indicator it leads with. Prefixes: `.wel-` for the screen, `.onb-`/`.onb__` for the
   progress block, which is separate because it is the natural home for the post-create
   setup checklist and will get a second host.

   Almost nothing here is new vocabulary. The cards are `.set-card`, the kind rows are
   `.settings-row`, the hero is `.tee-hero`, the divider is `.tee-divider` and the six code
   cells are the auth front door's `.afd-cell` — this partial adds the page's column
   geometry, the progress block, and the three small pieces those blocks have no words for.

   Prefix check (the .lvs- vs .ls- lesson): `.wel-` and `.onb-` are claimed by nothing in
   01–29, and this partial concatenates last, so it also wins any tie it creates. */

/* ── The page ──
   Sits inside .settings-ground (which supplies the ground and the edge-to-edge breakout),
   so this only states the column and the rhythm between blocks. */
.wel-page {
    max-width: 1080px;
    margin: 0 auto;
    padding: 20px 0 24px;
    display: flex;
    flex-direction: column;
    gap: var(--space-5);
}

.wel-head { padding: 0 var(--space-1); }
.wel-eyebrow {
    font-size: 11px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--metal);
}
.wel-title {
    margin: 8px 0 0;
    font-size: 34px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.025em;
    line-height: 1.1;
    color: var(--text);
    text-wrap: balance;
}
.wel-sub {
    margin: 9px 0 0;
    max-width: 60ch;
    font-size: 15px;
    line-height: 1.55;
    color: var(--text-muted);
}

/* Left column is the doing, right column is the two things that aren't. One column below
   768px, in DOM order — the hero first, because that is the tap this screen is for. */
.wel-cols {
    display: grid;
    grid-template-columns: minmax(0, 1.6fr) minmax(300px, 1fr);
    gap: var(--space-5);
    align-items: start;
}
.wel-col {
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 16px;
}

/* ── The hero, horizontal ──
   .tee-hero__btn is `width: 100%` at source, which is right on a phone and wrong beside a
   paragraph — an inline pill needs the nowrap or "We're on the tee" breaks across two lines
   at the width the button ends up. Desktop only; the phone keeps the stock card. */
@media (min-width: 769px) {
    /* The card's three children are badge / text block / button. A grid re-lays them without
       touching TeeHero's DOM — the badge spans, and the text and the button share a row. */
    .wel-hero .tee-hero {
        display: grid;
        grid-template-columns: minmax(260px, 1fr) auto;
        align-items: end;
        column-gap: var(--space-5);
        row-gap: 14px;
        padding: var(--space-5);
    }
    /* justify-self, not the card's own align-self: in a grid the inline axis is the one that
       stretches, so the badge otherwise spans the card as a full-width green bar. */
    .wel-hero .tee-hero__badge { grid-column: 1 / -1; justify-self: start; }
    .wel-hero .tee-hero__title { font-size: 24px; }
    .wel-hero .tee-hero__body { max-width: 52ch; }
    .wel-hero .tee-hero__btn {
        width: auto;
        padding: 15px 28px;
        white-space: nowrap;
    }
}

/* The kind rows carry their hint on desktop and the label alone at 390px, where the hint
   turns a 56px row into a three-line block — and the sheet that opens says the same
   sentence as its purpose line, so nothing is lost. */
.wel-kind { min-height: 56px; }
@media (max-width: 768px) {
    .wel-kind__hint { display: none; }
}

/* ── The event-code card ──
   Metal-edged: holding a code is a standing, and this is the one block here that isn't about
   creating something. */
.wel-code {
    border-color: var(--metal-edge);
    /* The .afd-cell rules read a local ink set that is ABSOLUTE HEX, because the auth front
       door's ground is dark in both themes. This card is on the ordinary page ground, so the
       same rules are re-pointed at semantic tokens and light mode follows for free. Reusing
       the block rather than redrawing six cells is what keeps paste, backspace and iOS's
       one-time-code autofill behaving identically on both screens. */
    --afd-ink: var(--text);
    --afd-fill-soft: var(--control-fill);
    --afd-fill-cell: var(--control-fill-strong);
    --afd-line-soft: var(--hairline);
    --afd-line: var(--hairline);
    --afd-metal-ink: var(--metal-strong);
    --afd-metal-wash-soft: var(--metal-wash-10);
    --afd-metal-focus: var(--metal-line);
}
.wel-code__eyebrow { color: var(--metal); }
.wel-code__body { padding: 6px 20px 20px; }
.wel-code__title {
    font-size: 15px;
    font-weight: var(--font-weight-semibold);
    color: var(--text);
}
.wel-code__hint {
    margin: 6px 0 0;
    font-size: 12.5px;
    line-height: 1.5;
    color: var(--text-muted);
}
/* Smaller than the front door's 60px: this is a card in a side column, not the screen's
   subject. The 6px gap keeps six cells inside a 300px column. */
.wel-code .afd-codebox { margin-top: 14px; }
.wel-code .afd-cells { gap: 6px; }
.wel-code .afd-cell {
    height: 48px;
    border-radius: 10px;
    font-size: 19px;
}
.wel-code .afd-caret { height: 22px; }
.wel-code__error { margin-top: 10px; }

/* The card's own action. Not a green primary: creating is this screen's primary and joining
   somebody else's event is the other door, so it takes the quiet fill. */
.wel-btn {
    width: 100%;
    margin-top: 12px;
    padding: 13px;
    border: none;
    border-radius: 12px;
    background: var(--control-fill-strong);
    color: var(--text);
    font: inherit;
    font-size: 14px;
    font-weight: var(--font-weight-bold);
    cursor: pointer;
}
.wel-btn:hover:not(:disabled) { background: color-mix(in srgb, var(--text) 10%, transparent); }
.wel-btn:disabled { color: var(--ink-disabled); cursor: default; }

/* ── The showcase card ──
   A real board read through the spectator surface, so the placings take the metal taper the
   leaderboard's own podium uses and an under-par figure takes --under-par. Nothing here is a
   fourth hue. */
.wel-show__board {
    margin: 12px 20px 0;
    border: 1px solid var(--hairline);
    border-radius: 12px;
    overflow: hidden;
}
.wel-show__head {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 9px 12px;
    background: var(--control-fill);
    font-size: 10.5px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-quiet);
}
.wel-show__name {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.wel-show__row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    font-size: 13px;
}
.wel-show__row + .wel-show__row { border-top: 1px solid var(--hairline-soft); }
.wel-show__pos {
    flex: none;
    width: 18px;
    font-weight: var(--font-weight-bold);
    color: var(--text-quiet);
    font-variant-numeric: tabular-nums;
}
.wel-show__pos--1 { color: var(--metal-strong); }
.wel-show__pos--2 { color: var(--metal); }
.wel-show__pos--3 { color: var(--metal-dim); }
.wel-show__player {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.wel-show__score {
    flex: none;
    font-weight: var(--font-weight-semibold);
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}
.wel-show__score.is-under { color: var(--under-par); }
.wel-show__link {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 14px 20px 16px;
    font-size: 13.5px;
    font-weight: var(--font-weight-semibold);
    color: var(--color-accent);
    text-decoration: none;
}
.wel-show__link .material-symbols-outlined { font-size: 18px; }

/* The phone's whole showcase block. Both forms are in the DOM and each hides in its own
   media query — the same call the players roster and the wager pane make. */
.wel-showlink {
    display: none;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 12px;
    font-size: 13.5px;
    font-weight: var(--font-weight-semibold);
    color: var(--color-accent);
    text-decoration: none;
}
.wel-showlink .material-symbols-outlined { font-size: 18px; }

@media (max-width: 768px) {
    .wel-page { padding: 4px 0 var(--space-5); gap: 16px; }
    .wel-title { font-size: 27px; font-weight: var(--font-weight-bold); letter-spacing: -0.03em; }
    .wel-sub { margin-top: 8px; font-size: 14px; }
    .wel-cols { display: flex; flex-direction: column; gap: 16px; }
    .wel-col { gap: 16px; }
    .wel-show { display: none; }
    .wel-showlink { display: flex; }
}

/* ===================================================================================
   The onboarding progress block (.onb)
   ===================================================================================
   Five steps, the first two already complete, so a brand-new account reads 44% rather than
   zero. The bar's fill is a gradient from the accent to a lighter accent — expressed as a
   color-mix rather than the design's two literals, so light mode holds. */

.onb { padding: 20px var(--space-5) 22px; }

.onb__head {
    display: flex;
    align-items: baseline;
    gap: var(--space-3);
    flex-wrap: wrap;
}
.onb__eyebrow {
    font-size: 11px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-quiet);
}
.onb__count {
    margin-left: auto;
    font-size: 13px;
    color: var(--text-muted);
    white-space: nowrap;
}
.onb__num {
    color: var(--text);
    font-variant-numeric: tabular-nums;
}

.onb__track {
    height: 6px;
    border-radius: 3px;
    background: var(--hairline);
    margin-top: 12px;
    overflow: hidden;
}
.onb__fill {
    display: block;
    height: 100%;
    background: linear-gradient(
        90deg,
        var(--color-accent),
        color-mix(in srgb, var(--color-accent) 55%, #fff));
}

/* ── The labelled grid (desktop) ── */
.onb__steps {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: 8px;
    margin: 20px 0 0;
    padding: 0;
    list-style: none;
}
.onb__step {
    display: flex;
    flex-direction: column;
    gap: 10px;
}
.onb__markerrow {
    display: flex;
    align-items: center;
    gap: 8px;
}
/* The connector belongs to the step on its LEFT, so it takes that step's own state: the run
   from a complete step reads solid, and everything past the current one is the empty track. */
.onb__connector {
    flex: 1;
    height: 2px;
    border-radius: 2px;
    background: color-mix(in srgb, var(--text) 12%, transparent);
}
.onb__step--complete .onb__connector { background: var(--color-accent); }

.onb__marker {
    flex: none;
    width: 26px;
    height: 26px;
    border-radius: var(--radius-pill);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 12.5px;
    font-weight: var(--font-weight-bold);
    font-variant-numeric: tabular-nums;
}
.onb__marker .material-symbols-outlined { font-size: 17px; }
.onb__marker--sm {
    width: 22px;
    height: 22px;
    font-size: 11px;
}
.onb__marker--sm .material-symbols-outlined { font-size: 15px; }

/* Complete is a filled circle carrying --on-hue, the rule every accent ground follows.
   Current is a ring on a wash. Upcoming is a ring alone, in ink quiet enough to read as
   "not yet" and strong enough to still say what it is. */
.onb__step--complete .onb__marker {
    background: var(--color-accent);
    color: var(--on-hue);
}
.onb__step--current .onb__marker {
    background: color-mix(in srgb, var(--color-accent) 16%, transparent);
    box-shadow: inset 0 0 0 2px var(--color-accent);
    color: var(--color-accent);
}
.onb__step--upcoming .onb__marker {
    box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--text) 16%, transparent);
    color: var(--text-quiet);
}

.onb__label {
    font-size: 13.5px;
    font-weight: var(--font-weight-semibold);
    color: var(--text);
}
.onb__step--current .onb__label { color: var(--color-accent); }
.onb__step--upcoming .onb__label { color: var(--text-muted); }
.onb__sub {
    margin-top: 2px;
    font-size: 12px;
    color: var(--text-quiet);
}
.onb__step--current .onb__sub { color: var(--text-muted); }

/* ── The marker strip (phone) ──
   No labels: five two-line cells do not fit at 390px, and one line of words saying what is
   next is more use than five truncated ones. */
.onb__strip {
    display: none;
    align-items: center;
    gap: 6px;
    margin-top: 12px;
}
.onb__next {
    margin-left: 8px;
    font-size: 12.5px;
    line-height: 1.3;
    color: var(--text-muted);
}

@media (max-width: 768px) {
    .onb { padding: 16px; }
    .onb__eyebrow { font-size: 13px; letter-spacing: 0; text-transform: none; color: var(--text); }
    .onb__count { font-size: 12px; color: var(--text-quiet); }
    .onb__steps { display: none; }
    .onb__strip { display: flex; }
}
/* ══ 31 · Odds ═════════════════════════════════════════════════════════════════════════════
   /events/{slug}/odds — the last event-scoped screen still rendering the legacy .data-table:
   an <h2>, a paragraph, and three stacked tables with the head-to-head at the bottom. This
   partial carries `19-result-tabs.css`'s raised-card language onto it and reorders the page so
   the three questions a reader arrives with are answered top-down: who's the one to beat, how
   do I match up, where do I sit. Source: handoffs/design_handoff_odds_page.

   Everything shared is `.rt-*` and is NOT redrawn here — .rt-card, .rt-cardhead, .rt-eyebrow,
   .rt-rule, .rt-note, .rt-rail, .rt-head, .rt-row, .rt-foot, .rt-chip--metal and .pos-tile all
   come from 19- and 18-. `.od-*` is only what is unique to this screen.

   Two rules the whole block obeys:
   · NO GREEN ANYWHERE. --color-accent means live-or-money and none of these figures is money —
     the entire screen is hypothetical. Odds are standing (metal) or neutral. Nothing takes
     --under-par either.
   · The four form / venue badges are ALL NEUTRAL. Form is not a standing, not money and not
     under par, so it takes no hue — the arrow direction carries the sense.

   Both drawings of a responsive element are in the DOM, each hidden in its own media query
   (.od-hide-sm / .od-show-sm), the same call the players roster and the Wagers pane make — so a
   test has to say which one it means. */

/* ── Page head ─────────────────────────────────────────────────────────────────────────────
   One wrapping flex row on the baseline: title + disclaimer chip left, picker and the context
   chip pushed right. On a phone it wraps to two lines, picker leading the second. */

.od-head {
    display: flex;
    align-items: flex-end;
    gap: var(--space-3);
    flex-wrap: wrap;
    margin-bottom: var(--space-4);
}

.od-title {
    margin: 0;
    font-size: 27px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.025em;
    color: var(--text);
}

/* "Group Odds (Entertainment)" lost its parenthetical to this chip — the disclaimer is a
   standing property of the screen, not part of its name. */
.od-disclaim {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-bottom: 4px;
    padding: 4px 10px;
    border-radius: var(--radius-pill);
    background: var(--control-fill);
    font-size: 10.5px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: var(--text-quiet);
    white-space: nowrap;
}

.od-disclaim .material-symbols-outlined { font-size: 14px; }

/* The picker itself is untouched — the per-week chip sheet and the trip SheetSelect are what
   the codebase already decided. Only its placement on the head row is new. */
.od-picker {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

.od-picker .round-filter { margin: 0; }

.od-page .od-show-sm { display: none; }

/* ── Stat rail ─────────────────────────────────────────────────────────────────────────────
   Four cells that make the boards below optional reading. Cell 1 and cell 4 take the lead
   ground: the favourite IS the standing, and the storyline frames it. Metal is never used here
   to mean "a number" — cells 2 and 3 stay plain. */

.od-rail__cell--story { gap: var(--space-2); }

/* No figure — prose. .rt-rail__fig is nowrap + ellipsis, which is right for a name and wrong
   for two sentences, so the storyline is its own element rather than a modifier of it. */
.od-story {
    font-size: 13.5px;
    line-height: 1.45;
    color: var(--text);
    text-wrap: pretty;
}

.od-rail__long-name {
    font-size: 11.5px;
    color: var(--text-muted);
}

/* ── Head-to-head feature card ─────────────────────────────────────────────────────────────
   Promoted from the bottom of the page to second position: "how do I match up against him"
   answered in one card instead of two pickers and a 2×3 table nobody scrolled to. */

.od-h2h__pickers {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: var(--space-2);
    min-width: 0;
}

.od-vs {
    flex-shrink: 0;
    font-size: 11px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.1em;
    color: var(--text-quiet);
}

/* The card NEVER collapses — the head stays so the pickers don't move under the thumb. This is
   the slot the empty state, the spinner and the unsupported reason all land in. */
.od-h2h__slot {
    padding: 16px 20px 20px;
    border-top: 1px solid var(--hairline-soft);
    font-size: 13px;
    color: var(--text-muted);
    line-height: 1.5;
}

.od-h2h__slot .loading-spinner { margin: 0 auto; }

.od-combatants {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 78px minmax(0, 1fr);
    align-items: center;
    border-top: 1px solid var(--metal-edge);
}

.od-side {
    display: flex;
    flex-direction: column;
    gap: 7px;
    padding: 18px 20px 16px;
    min-width: 0;
}

.od-side--b {
    align-items: flex-end;
    text-align: right;
}

.od-side__name {
    font-size: 22px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.02em;
    color: var(--text);
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 100%;
}

.od-side__meta {
    font-size: 12.5px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

.od-side__badges {
    display: flex;
    gap: 6px;
    flex-wrap: wrap;
}

.od-side--b .od-side__badges { justify-content: flex-end; }

.od-vsmark {
    display: flex;
    align-items: center;
    justify-content: center;
    align-self: stretch;
}

.od-vsmark span {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 46px;
    height: 46px;
    border: 1px solid var(--metal-line);
    border-radius: 50%;
    background: var(--metal-wash-10);
    font-size: 13px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.06em;
    color: var(--metal-strong);
}

.od-meters {
    padding: 14px 20px 6px;
    border-top: 1px solid var(--hairline-soft);
}

.od-meter {
    display: grid;
    grid-template-columns: 92px minmax(0, 1fr) 92px;
    align-items: center;
    gap: 14px;
}

.od-meter + .od-meter { margin-top: 14px; }

/* The favoured side's price takes full ink and the underdog's goes quiet. That contrast is what
   makes the row readable at a glance — two figures at equal weight say nothing. */
.od-meter__odds {
    font-size: 24px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.02em;
    font-variant-numeric: tabular-nums;
    color: var(--text-muted);
}

.od-meter__odds.is-fav { color: var(--text); }
.od-meter__odds--b { text-align: right; }

.od-meter__bar {
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-width: 0;
}

.od-meter__labels {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-2);
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--text-quiet);
    font-variant-numeric: tabular-nums;
}

.od-meter__mode { color: var(--metal); }

.od-meter__track {
    display: flex;
    height: 8px;
    border-radius: var(--radius-sm);
    background: var(--control-fill-strong);
    overflow: hidden;
}

/* The one use of --metal-meter. The bar does not animate on load: nothing on this screen is
   live, and a meter that grows implies something moved. */
.od-meter__fill {
    display: block;
    height: 100%;
    background: var(--metal-meter);
}

.od-meter__fill--b { margin-left: auto; }

/* ── Boards ────────────────────────────────────────────────────────────────────────────────
   Column templates are declared here rather than published as --rt-cols from C#: that mechanism
   is for a board whose column COUNT is data-driven, and both of these are fixed. */

.od-players {
    --rt-cols: 54px minmax(150px, 1fr) 62px 92px 132px 132px;
    --rt-cols-sm: 34px minmax(0, 1fr) 84px;
}

.od-groups {
    --rt-cols: minmax(190px, 1fr) repeat(4, 122px);
    --rt-cols-sm: minmax(0, 1fr) 84px;
}

/* A price over its probability — the same treatment on both boards, so a group price and a
   player price read as the same kind of statement. */
.od-fig {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 1px;
    text-align: right;
    min-width: 0;
}

.od-fig__odds {
    font-size: 17px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.015em;
    font-variant-numeric: tabular-nums;
    color: var(--text);
}

.od-fig__pct {
    font-size: 11px;
    color: var(--text-quiet);
    font-variant-numeric: tabular-nums;
}

.od-grp {
    font-size: 13.5px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

.od-hcp {
    text-align: right;
    justify-self: end;
    font-size: 15px;
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
    color: var(--text);
}

.od-groupname {
    font-size: 15.5px;
    font-weight: var(--font-weight-semibold);
    color: var(--text);
}

/* ── Form / venue badges ───────────────────────────────────────────────────────────────────
   The emoji are gone (🔥 / ❄️ / ⛳ render at four different weights across platforms and can't
   be coloured); Material Symbols in, and ALL FOUR ARE NEUTRAL. `trending_down` is hot form —
   scoring lower is better, which reads correctly in golf and nowhere else. */

.od-badges {
    display: flex;
    gap: 5px;
    flex-wrap: wrap;
    margin-top: 5px;
}

.od-badge {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    height: 22px;
    padding: 0 8px;
    border: none;
    border-radius: var(--radius-pill);
    background: var(--control-fill);
    font-family: inherit;
    font-size: 11px;
    font-weight: var(--font-weight-semibold);
    color: var(--text-muted);
    white-space: nowrap;
}

.od-badge .material-symbols-outlined { font-size: 13px; }
button.od-badge { cursor: pointer; }
button.od-badge:hover { background: var(--control-fill-strong); color: var(--text); }

.od-badge--lg {
    height: 24px;
    padding: 0 9px;
    font-size: 11.5px;
}

.od-badge--lg .material-symbols-outlined { font-size: 14px; }

/* The tapped-badge sheet. Its pills are the same chrome as the row's, so the sheet and the row
   can't disagree about what a badge is. */
.od-detail__lines {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding-bottom: var(--space-3);
    border-bottom: 1px solid var(--hairline-soft);
    margin-bottom: var(--space-3);
}

.od-detail__line {
    display: flex;
    align-items: baseline;
    gap: var(--space-2);
    font-size: 13px;
    color: var(--text-muted);
}

.od-detail__line b {
    margin-left: auto;
    font-size: 15px;
    font-weight: var(--font-weight-bold);
    font-variant-numeric: tabular-nums;
    color: var(--text);
}

.od-detail__sub {
    margin: 0 0 var(--space-3);
    font-size: 12px;
    color: var(--text-quiet);
}

/* .badge-detail-row is a column flex in 10-scorecard.css and pins its pill left; that rule names
   .form-badge, which this screen no longer draws. */
.badge-detail-row .od-badge { align-self: flex-start; }

/* ══ Responsive ════════════════════════════════════════════════════════════════════════════
   One breakpoint that matters — the app's canonical 768px. The 1000px block only re-flows the
   rail, which 19- already turns 2-up there. */

@media (max-width: 1000px) {
    /* 19- makes the rail 2-up here and re-draws the hairlines by nth-child; cells 3 and 4 are
       full-width bands, so the even one has to shed the left border that rule gives it. */
    .od-rail .od-rail__cell--long,
    .od-rail .od-rail__cell--story {
        grid-column: 1 / -1;
        border-left: none;
    }

    /* Longest shot goes to one baseline: label left, figure and who it belongs to pushed right. */
    .od-rail .od-rail__cell--long {
        flex-direction: row;
        align-items: baseline;
        gap: 9px;
    }

    .od-rail .od-rail__cell--long .rt-rail__fig { margin-left: auto; }
}

@media (min-width: 769px) {
    /* Desktop density for the two head pickers — 34px, hairline, quiet caret. Below this width
       they keep SheetSelect's own 44px touch target. */
    .od-h2h__pickers .sheet-select-trigger {
        width: auto;
        min-width: 9.5rem;
        min-height: 34px;
        padding: 0 8px 0 12px;
        border-color: var(--hairline);
        border-radius: var(--radius-md);
        font-size: 13px;
        font-weight: var(--font-weight-medium);
    }

    .od-h2h__pickers .sheet-select-trigger__caret {
        font-size: 18px;
        color: var(--ink-disabled);
    }
}

@media (max-width: 768px) {
    /* Scoped to .od-page so these beat the display a class like .od-fig sets on the same node. */
    .od-page .od-hide-sm { display: none; }
    .od-page .od-show-sm { display: inline-flex; }

    .od-head { gap: var(--space-2); margin-bottom: var(--space-3); }
    .od-title { font-size: 23px; }
    .od-disclaim { margin-bottom: 0; padding: 3px 9px; font-size: 10px; letter-spacing: 0.08em; }

    /* The head wraps to two lines: title + disclaimer, then picker + context chip. A 12rem basis
       is what forces the wrap while still leaving the chip room beside the picker — at 100% the
       chip is pushed to a third line of its own. */
    .od-picker { flex: 1 1 12rem; min-width: 0; margin-left: 0; }
    .od-picker .sheet-select-trigger { width: 100%; min-width: 0; }

    .od-rail .rt-rail__cell { gap: 5px; padding: 13px 14px 15px; }
    .od-rail .rt-rail__label { font-size: 9.5px; letter-spacing: 0.11em; }
    .od-rail .rt-rail__fig { font-size: 19px; }
    .od-story { font-size: 12.5px; }

    /* A card head at 390px is the eyebrow and the one control that changes what's under it. */
    .od-page .rt-cardhead .rt-note { display: none; }

    .od-toggle { margin-left: auto; }
    .od-toggle .segmented { width: auto; }
    .od-toggle .segmented__opt { min-height: 44px; padding-left: 12px; padding-right: 12px; }

    /* The pickers stop being a right-hand cluster and take their own full-width row — the
       design's single "Change" affordance would need a combined two-player picker that doesn't
       exist, and one that opened only side A's sheet is half a control. */
    .od-h2h__pickers { flex: 1 0 100%; margin-left: 0; }
    .od-h2h__pickers .sheet-select-trigger { flex: 1; min-width: 0; }
    .od-h2h__slot { padding: 14px; }

    .od-combatants { grid-template-columns: minmax(0, 1fr) 44px minmax(0, 1fr); }
    .od-vsmark span { width: 36px; height: 36px; font-size: 11px; }
    .od-side { gap: 4px; padding: 13px 14px; }
    .od-side__name { font-size: 16px; }
    .od-side__meta { font-size: 11px; }
    .od-side__badges { display: none; }

    .od-meters { padding: 12px 14px 14px; }
    .od-meter { grid-template-columns: 66px minmax(0, 1fr) 66px; gap: 10px; }
    .od-meter + .od-meter { margin-top: 12px; }
    .od-meter__odds { font-size: 19px; }
    .od-meter__labels { font-size: 9.5px; letter-spacing: 0.1em; }
    .od-meter__track { height: 7px; }

    /* One market column, chosen by the toggle in the card head, so a row never squeezes two.
       Hide-only: exactly one of each pair survives, so nothing has to be re-shown. */
    .od-players.is-net .od-mkt--gross,
    .od-players.is-gross .od-mkt--net,
    .od-groups.is-front .od-mkt:not(.od-mkt--front),
    .od-groups.is-back .od-mkt:not(.od-mkt--back),
    .od-groups.is-total .od-mkt:not(.od-mkt--total),
    .od-groups.is-money .od-mkt:not(.od-mkt--money) { display: none; }

    .od-fig__odds { font-size: 16px; }
    .od-fig__pct { font-size: 10.5px; }
    .od-groupname { font-size: 14.5px; }

    /* Tapping the row is how a phone reaches a player's card without hitting an 11px pill. */
    .od-page .rt-row--click { min-height: 44px; }
}
/* ══ 32 · Player profile + public career page ═════════════════════════════════════════════
   /events/{slug}/players/{memberId}/profile (`1a`) and /p/{slug} (`2a`).
   Source: handoffs/design_handoff_player_profile.

   THIS PARTIAL IS DELIBERATELY SMALL, for the reason 25-course-stats.css states: nearly
   everything on both screens is .rt-* from 19-result-tabs.css and .psc-* from 18-leaderboard.css,
   reused unmodified. If you find yourself restyling an .rt- class here, you have diverged from
   the leaderboard and should stop. What genuinely belongs here:
     · the column templates for the Rounds, Scoring, Money, Differentials and Events boards;
     · the identity card's tile, name scale and scope switch;
     · the chart frames (trend, sparkline, consistency plot);
     · the `2a` hero, its absolute-hex ink block, and the conversion foot;
     · the record row (tile + label + context + figure).

   Prefix is .pf-. NOT .pp- (the payout-places control at the foot of 29-teams-board.css) and not
   .psc- (the player scorecard this design REUSES). Both later partials were checked, which is the
   rule .lvs- exists to remember.

   Colour discipline (src/GolfTracker.UI/CLAUDE.md):
   · --metal-* is STANDING — a finishing position, a counting differential, a career best, the
     eyebrows framing those, and the By-par meter fill. Nothing else.
   · --color-accent is LIVE OR MONEY — the Playing now pill, every dollar figure, the money bars,
     an index improvement. It therefore appears on `2a` only as the live-event pill, which is
     correct: there is no money on that page.
   · --under-par is UNDER PAR — the birdie/eagle rings and the two worse-than-par spread segments,
     as a TINT rather than ink so they don't compete with the figure beside them.
   · A tie, a zero or a "no data" is neutral, never a fourth hue. A zero is greyed
     (--ink-disabled), not hidden. */

/* ── Identity card ───────────────────────────────────────────────────────────────────────── */

.pf-id {
    display: flex;
    align-items: flex-start;
    gap: var(--space-5);
    padding: var(--space-5) var(--space-5) var(--space-4);
}

.pf-id__tile {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 64px;
    height: 64px;
    border-radius: 18px;
    background: var(--surface-inverse);
    color: var(--on-solid);
    font-size: 22px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.02em;
}

.pf-id__body {
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 7px;
}

.pf-id__name {
    margin: 0;
    font-size: 29px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.025em;
    color: var(--text);
    line-height: 1.1;
}

/* Hairline rules rather than middots — the .psc-course pattern. */
.pf-meta {
    display: flex;
    align-items: center;
    gap: 9px;
    flex-wrap: wrap;
    font-size: 12.5px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

.pf-meta__rule {
    width: 1px;
    height: 11px;
    background: var(--hairline);
}

.pf-meta strong { font-weight: var(--font-weight-semibold); color: var(--text); }

.pf-live {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 3px 10px 3px 8px;
    border-radius: 999px;
    background: color-mix(in srgb, var(--color-accent) 12%, transparent);
    border: 1px solid color-mix(in srgb, var(--color-accent) 30%, transparent);
    font-size: 10.5px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: color-mix(in srgb, var(--color-accent) 70%, var(--text));
    white-space: nowrap;
}

.pf-live__dot {
    width: 6px;
    height: 6px;
    border-radius: 999px;
    background: var(--color-accent);
    animation: winprob-pulse 1.6s ease-in-out infinite;
}

@media (prefers-reduced-motion: reduce) {
    .pf-live__dot { animation: none; }
}

/* The scope switch and the quiet note under it. */
.pf-scope {
    margin-left: auto;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: var(--space-2);
    flex: none;
}

.pf-scope__note {
    font-size: 11.5px;
    color: var(--text-quiet);
    font-variant-numeric: tabular-nums;
    text-align: right;
    max-width: 220px;
}

/* A career the player can't have is shown at 55% with the reason, never removed — the list must
   not change length between player types. */
.pf-scope.is-blocked .segmented { opacity: 0.55; }

/* Five form chips. The metal treatment is "good for them", not a fixed score. */
.pf-form {
    display: flex;
    gap: 5px;
    flex-wrap: wrap;
}

.pf-form__chip {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 32px;
    height: 28px;
    padding: 0 5px;
    border-radius: 8px;
    background: var(--control-fill);
    color: var(--text);
    font-size: 13px;
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
}

.pf-form__chip.is-strong {
    background: var(--metal-wash-16);
    color: var(--metal-strong);
    box-shadow: inset 0 0 0 1px var(--metal-line);
}

/* ── The ledger's one new row ────────────────────────────────────────────────────────────── */

/* The expanded player ledger on the leaderboard STAYS; it gained this row and this row is the
   primary door here. It lives inside .board-detail, so it takes that block's gutters rather than
   its own — .psc- because it belongs to the ledger, not to the screen it opens. */
.psc-fullprofile {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin-top: var(--space-3);
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius-lg);
    border: 1px solid var(--metal-edge);
    background: var(--metal-wash-05);
    text-decoration: none;
    color: var(--text);
    min-width: 0;
}

.psc-fullprofile:hover { background: var(--metal-wash-10); text-decoration: none; }
.psc-fullprofile > .material-symbols-outlined { font-size: 20px; color: var(--metal-strong); }

.psc-fullprofile__label {
    font-size: 14px;
    font-weight: var(--font-weight-semibold);
    color: var(--metal-strong);
    white-space: nowrap;
}

.psc-fullprofile__sub {
    font-size: 12.5px;
    color: var(--text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}

.psc-fullprofile__chev { margin-left: auto; font-size: 18px; color: var(--ink-disabled); }

@media (max-width: 600px) {
    .psc-fullprofile__sub { display: none; }
}

/* ── The claim-welcome screen's career-page note ─────────────────────────────────────────── */

/* Creating an account now creates a public page, so the screen that announces the account has to
   say so. It lives here rather than in 16-auth-pages.css because it is about this feature, and
   16- would have to be edited again the day the note changes. */
.claim-career {
    display: flex;
    flex-direction: column;
    gap: 5px;
    margin-top: var(--space-4);
    padding: var(--space-4);
    border-radius: var(--radius-lg);
    border: 1px solid var(--metal-edge);
    background: var(--metal-wash-05);
    text-align: left;
}

.claim-career__title {
    font-size: 13.5px;
    font-weight: var(--font-weight-semibold);
    color: var(--metal-strong);
}

.claim-career__url {
    font-size: 13px;
    color: var(--text);
    word-break: break-all;
}

.claim-career__note { font-size: 12.5px; color: var(--text-muted); }

/* ── Tabs ────────────────────────────────────────────────────────────────────────────────── */

/* .psc-tab verbatim; what this adds is the SCROLLER. Six tabs do not fit 390px and the last one
   must not be unreachable — the failure the week rail already had once. */
.pf-tabs {
    display: flex;
    align-items: flex-end;
    gap: 4px;
    border-bottom: 1px solid var(--hairline);
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
    min-width: 0;
}

.pf-tabs::-webkit-scrollbar { display: none; }
.pf-tabs .psc-tab { flex: none; }

.pf-tabs__note {
    margin-left: auto;
    padding-bottom: 9px;
    font-size: 11.5px;
    white-space: nowrap;
    color: var(--text-quiet);
}

@media (max-width: 768px) {
    .pf-tabs__note { display: none; }
}

/* ── Boards ──────────────────────────────────────────────────────────────────────────────── */

/* Day · Course · Tee · Gross · Net · To par · Pos · Won.
   Each narrow template declares exactly as many tracks as that width has VISIBLE cells — a
   *-hide-sm cell drops out of auto-placement entirely, and a list one track short pushes every
   later cell up a column. Count the hidden ones. */
.pf-rounds {
    --rt-cols: 64px minmax(150px, 1fr) 86px 62px 62px 66px 58px 88px;
    --rt-cols-md: 60px minmax(130px, 1fr) 58px 62px 56px 84px;
    --rt-cols-sm: 46px minmax(0, 1fr) 48px 54px 60px;
}

/* Hole type · Holes · Average · Spread · E · B · P · Bo · Dbl+ */
.pf-scoring {
    --rt-cols: 96px 74px 78px minmax(0, 1fr) 58px 58px 58px 58px 60px;
    --rt-cols-md: 92px 70px 74px minmax(0, 1fr);
    --rt-cols-sm: minmax(0, 1fr) 62px 62px;
}

/* Game · bar · wins · amount */
.pf-money {
    --rt-cols: 150px minmax(0, 1fr) 78px 96px;
    --rt-cols-md: 130px minmax(0, 1fr) 90px;
    --rt-cols-sm: 96px minmax(0, 1fr) 66px;
}

/* Date · Course · Score · Rating · Slope · Differential */
.pf-diffs {
    --rt-cols: 78px minmax(0, 1fr) 84px 74px 70px 96px;
    --rt-cols-md: 74px minmax(0, 1fr) 78px 92px;
    --rt-cols-sm: 56px minmax(0, 1fr) 44px 58px;
}

/* Year · Event · Rounds · Average · Best · Finished */
.pf-events {
    --rt-cols: 58px minmax(180px, 1fr) 78px 82px 74px 104px;
    --rt-cols-md: 54px minmax(140px, 1fr) 78px 100px;
    --rt-cols-sm: minmax(0, 1fr) 48px 50px 56px;
}

@media (max-width: 1000px) {
    .pf-rounds .rt-head, .pf-rounds .rt-row { grid-template-columns: var(--rt-cols-md); }
    .pf-scoring .rt-head, .pf-scoring .rt-row { grid-template-columns: var(--rt-cols-md); }
    .pf-money .rt-head, .pf-money .rt-row { grid-template-columns: var(--rt-cols-md); }
    .pf-diffs .rt-head, .pf-diffs .rt-row { grid-template-columns: var(--rt-cols-md); }
    .pf-events .rt-head, .pf-events .rt-row { grid-template-columns: var(--rt-cols-md); }
    .pf-hide-md { display: none; }
}

@media (max-width: 768px) {
    .pf-rounds .rt-head, .pf-rounds .rt-row { grid-template-columns: var(--rt-cols-sm); }
    .pf-scoring .rt-head, .pf-scoring .rt-row { grid-template-columns: var(--rt-cols-sm); }
    .pf-money .rt-head, .pf-money .rt-row { grid-template-columns: var(--rt-cols-sm); }
    .pf-diffs .rt-head, .pf-diffs .rt-row { grid-template-columns: var(--rt-cols-sm); }
    .pf-events .rt-head, .pf-events .rt-row { grid-template-columns: var(--rt-cols-sm); }
    .pf-hide-sm { display: none; }
}

/* A position tile. Podium takes metal; everything else is plain, and a tie is neither. */
.pf-pos {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 26px;
    height: 26px;
    padding: 0 8px;
    border-radius: 8px;
    font-size: 12.5px;
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
    color: var(--text-muted);
}

.pf-pos.is-podium { background: var(--metal-wash-16); color: var(--metal-strong); }

.pf-of {
    font-size: 11px;
    color: var(--text-quiet);
    white-space: nowrap;
}

.pf-money-fig { color: var(--color-accent); font-weight: var(--font-weight-semibold); }
.pf-money-fig.is-zero { color: var(--ink-disabled); font-weight: var(--font-weight-normal); }

/* The cross-link a card head carries — "Open handicap history". Metal because where a figure
   comes from is a standing, not an action. */
.pf-link {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: 12.5px;
    font-weight: var(--font-weight-semibold);
    color: var(--metal-strong);
    text-decoration: none;
    white-space: nowrap;
}

.pf-link:hover { text-decoration: underline; }
.pf-link .material-symbols-outlined { font-size: 16px; }

/* Two figures stacked in one right-aligned cell: the average with its delta beneath. */
.pf-stack {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    line-height: 1.2;
}

.pf-stack__fig {
    font-size: 17px;
    font-weight: var(--font-weight-bold);
    font-variant-numeric: tabular-nums;
    color: var(--text);
}

.pf-stack__sub {
    font-size: 11.5px;
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
    color: var(--text-muted);
}

/* The By-par meter. Metal because a par-type average against the field is a standing. */
.pf-meter {
    display: block;
    height: 9px;
    border-radius: 5px;
    background: var(--control-fill);
    overflow: hidden;
}

.pf-meter__fill {
    display: block;
    height: 100%;
    border-radius: 5px;
    background: var(--metal-meter);
}

.pf-meter__fill--money { background: color-mix(in srgb, var(--color-accent) 50%, transparent); }

/* The counting differential's row and figure — the one thing on the Handicap tab that resembles
   a standing, which is the whole reason it may take metal. */
.pf-diffs .rt-row.is-counting { background: var(--metal-wash-10); }
.pf-diffs .rt-row.is-counting .pf-diff { color: var(--metal-strong); font-weight: var(--font-weight-semibold); }

/* ── Charts ──────────────────────────────────────────────────────────────────────────────── */

.pf-chart {
    padding: var(--space-1) var(--space-5) var(--space-2);
}

.pf-chart svg { width: 100%; display: block; }
.pf-chart--trend svg { height: 186px; }
.pf-chart--spark svg { height: 74px; }

.pf-chart__grid { stroke: var(--hairline-soft); stroke-width: 1; }
.pf-chart__area { fill: var(--metal-wash-10); }
.pf-chart__line { fill: none; stroke: var(--metal); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.pf-chart__avg { stroke: var(--ink-disabled); stroke-width: 1; stroke-dasharray: 4 4; }
.pf-chart__dot { fill: var(--surface-raised); stroke: var(--metal); stroke-width: 2; }
.pf-chart__dot--low { fill: var(--metal); stroke: var(--surface-raised); }

.pf-chart__labels {
    display: flex;
    padding: 0 var(--space-5) var(--space-4);
    font-size: 10.5px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: 0.06em;
    color: var(--text-quiet);
    font-variant-numeric: tabular-nums;
}

.pf-chart__labels span { flex: 1; text-align: center; min-width: 0; }

.pf-legend {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: var(--space-4);
    font-size: 11.5px;
    color: var(--text-muted);
    flex-wrap: wrap;
}

.pf-legend__item { display: inline-flex; align-items: center; gap: 7px; }
.pf-legend__line { width: 14px; height: 2px; background: var(--metal); }
.pf-legend__dash { width: 14px; height: 0; border-top: 1px dashed var(--ink-disabled); }

/* The consistency plot: low / average / high with the middle-half box between them. Built from
   divs on a track rather than SVG text, so the figures stay real text at every zoom. */
.pf-range {
    position: relative;
    margin: var(--space-5) var(--space-5) var(--space-6);
    height: 44px;
}

.pf-range__track {
    position: absolute;
    left: 0;
    right: 0;
    top: 21px;
    height: 1px;
    background: var(--hairline);
}

.pf-range__box {
    position: absolute;
    top: 4px;
    height: 34px;
    border-radius: 7px;
    background: var(--metal-wash-16);
    border: 1px solid var(--metal-line);
}

.pf-range__mid {
    position: absolute;
    top: 0;
    width: 2px;
    height: 42px;
    background: var(--metal-strong);
    transform: translateX(-1px);
}

.pf-range__cap {
    position: absolute;
    top: 11px;
    width: 2px;
    height: 20px;
    background: var(--ink-disabled);
}

.pf-range__marks {
    display: flex;
    justify-content: space-between;
    padding: 0 var(--space-5) var(--space-5);
}

.pf-range__mark {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 3px;
}

.pf-range__mark span:first-child {
    font-size: 13px;
    font-weight: var(--font-weight-bold);
    font-variant-numeric: tabular-nums;
    color: var(--text);
}

.pf-range__mark--mid span:first-child { color: var(--metal-strong); }

.pf-range__mark span:last-child {
    font-size: 10.5px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

/* ── Spread + par-type bars (the same five segments Course Stats draws) ──────────────────── */

.pf-mix {
    display: flex;
    height: 10px;
    border-radius: 5px;
    overflow: hidden;
    background: var(--control-fill);
}

.pf-mix__seg { display: block; height: 100%; }
.pf-mix__seg--1 { background: color-mix(in srgb, var(--color-accent) 34%, transparent); }
.pf-mix__seg--2 { background: color-mix(in srgb, var(--color-accent) 18%, transparent); }
.pf-mix__seg--3 { background: var(--control-fill-strong); }
.pf-mix__seg--4 { background: color-mix(in srgb, var(--under-par) 16%, transparent); }
.pf-mix__seg--5 { background: color-mix(in srgb, var(--under-par) 34%, transparent); }

.pf-spread {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    padding: var(--space-4) var(--space-3) var(--space-5);
}

.pf-spread__cell {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 5px;
    padding: 0 var(--space-2);
    min-width: 0;
}

.pf-spread__cell + .pf-spread__cell { border-left: 1px solid var(--hairline-soft); }

.pf-spread__fig {
    font-size: 24px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.02em;
    font-variant-numeric: tabular-nums;
    color: var(--text);
}

.pf-spread__fig.is-zero { color: var(--ink-disabled); }

.pf-spread__label {
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-quiet);
    text-align: center;
}

/* ── Nines ───────────────────────────────────────────────────────────────────────────────── */

.pf-nines {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    padding: var(--space-2) var(--space-5) var(--space-5);
}

.pf-nines__cell {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 0 var(--space-4);
    min-width: 0;
}

.pf-nines__cell:first-child { padding-left: 0; }
.pf-nines__cell + .pf-nines__cell { border-left: 1px solid var(--hairline-soft); }

.pf-nines__label {
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

.pf-nines__fig {
    font-size: 24px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.02em;
    font-variant-numeric: tabular-nums;
    color: var(--text);
}

.pf-nines__sub { font-size: 11.5px; color: var(--text-muted); }

/* ── Handicap equation ───────────────────────────────────────────────────────────────────── */

.pf-eq {
    display: flex;
    align-items: center;
    gap: var(--space-6);
    padding: var(--space-2) var(--space-5) var(--space-5);
    flex-wrap: wrap;
}

.pf-eq__term { display: flex; flex-direction: column; gap: 3px; }

.pf-eq__label {
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

.pf-eq__fig {
    font-size: 32px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.03em;
    font-variant-numeric: tabular-nums;
    color: var(--text);
}

.pf-eq__op { font-size: 22px; color: var(--ink-disabled); }

.pf-eq__term--result {
    padding: 10px 18px;
    border-radius: 12px;
    background: var(--metal-wash-16);
    border: 1px solid var(--metal-line);
}

.pf-eq__term--result .pf-eq__label { color: var(--metal); }
.pf-eq__term--result .pf-eq__fig { color: var(--metal-strong); }

.pf-eq__end { margin-left: auto; text-align: right; }

/* ── Records ─────────────────────────────────────────────────────────────────────────────── */

.pf-records { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }

@media (max-width: 768px) {
    .pf-records { grid-template-columns: minmax(0, 1fr); }
}

.pf-rec {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    padding: var(--space-4) var(--space-5);
    border-top: 1px solid var(--hairline-soft);
    min-width: 0;
}

.pf-rec__tile {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    border-radius: 11px;
    background: var(--control-fill);
    color: var(--text-quiet);
}

.pf-rec__tile .material-symbols-outlined { font-size: 20px; }
.pf-rec.is-career .pf-rec__tile { background: var(--metal-wash-16); color: var(--metal-strong); }

.pf-rec__body { display: flex; flex-direction: column; gap: 2px; min-width: 0; }

.pf-rec__label {
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-quiet);
}

.pf-rec__where {
    font-size: 13px;
    color: var(--text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.pf-rec__fig {
    margin-left: auto;
    text-align: right;
    font-size: 23px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.025em;
    font-variant-numeric: tabular-nums;
    color: var(--text);
    white-space: nowrap;
}

.pf-rec.is-career .pf-rec__fig { color: var(--metal-strong); }

/* ── The public career page (`2a`) ───────────────────────────────────────────────────────── */

/* The hero ground is dark in BOTH themes, the call --masthead-scrim, --recap-hero-ground and
   --auth-ground all make — and it applies here more strongly than anywhere: theme.js resolves an
   unknown visitor against prefers-color-scheme, so a stranger arrives on whichever theme their
   phone is set to, and this is the one page whose whole job is to work for someone who has never
   seen the app. The ink over it is therefore ABSOLUTE HEX, declared once as local custom
   properties, exactly as .lvs-header and .dock do. */
.pf-pub {
    --pf-brand: #c9ad6e;
    --pf-emph: #e8d6a8;
    --pf-title: #fff;
    --pf-body: #eef1f4;
    --pf-muted: #aab2bc;
    --pf-quiet: #98a1ad;
    --pf-btn-ground: #eef1f4;
    --pf-btn-ink: #14181d;
    --pf-hairline: rgba(255, 255, 255, 0.12);

    min-height: 100vh;
    background: var(--page-ground);
}

.pf-hero {
    background: var(--auth-ground);
    border-bottom: 1px solid var(--auth-edge);
}

.pf-hero__inner {
    max-width: 1280px;
    margin: 0 auto;
    padding: var(--space-4) var(--space-5) 0;
}

.pf-hero__bar {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    flex-wrap: wrap;
}

.pf-hero__brand {
    display: inline-flex;
    align-items: center;
    gap: 9px;
    color: var(--pf-brand);
    font-size: 12px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.16em;
    text-transform: uppercase;
    text-decoration: none;
}

.pf-hero__brand svg { display: block; overflow: visible; }

.pf-hero__actions { margin-left: auto; display: flex; align-items: center; gap: var(--space-2); }

.pf-btn {
    display: inline-flex;
    align-items: center;
    padding: 8px 15px;
    border-radius: 10px;
    font-size: 13px;
    font-weight: var(--font-weight-semibold);
    text-decoration: none;
    white-space: nowrap;
}

.pf-btn--primary { background: var(--pf-btn-ground); color: var(--pf-btn-ink); }

.pf-btn--ghost {
    border: 1px solid rgba(255, 255, 255, 0.18);
    color: #c8cfd8;
    font-weight: var(--font-weight-normal);
}

.pf-hero__id {
    display: flex;
    align-items: flex-end;
    gap: var(--space-5);
    padding: var(--space-5) 0 var(--space-5);
    flex-wrap: wrap;
}

.pf-hero__tile {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 78px;
    height: 78px;
    border-radius: 22px;
    background: rgba(255, 255, 255, 0.08);
    border: 1px solid rgba(201, 173, 110, 0.32);
    color: var(--pf-emph);
    font-size: 26px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.02em;
}

.pf-hero__names { display: flex; flex-direction: column; gap: var(--space-2); min-width: 0; }

.pf-hero__eyebrow {
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--pf-brand);
}

.pf-hero__name {
    margin: 0;
    font-size: 38px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.03em;
    color: var(--pf-title);
    line-height: 1.05;
}

.pf-hero__since {
    font-size: 13px;
    color: var(--pf-muted);
    font-variant-numeric: tabular-nums;
}

.pf-hero__rail { margin-left: auto; display: flex; align-items: flex-end; }

.pf-hero__cell {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 0 var(--space-5);
}

.pf-hero__cell:last-child { padding-right: 0; }
.pf-hero__cell + .pf-hero__cell { border-left: 1px solid var(--pf-hairline); }

.pf-hero__label {
    font-size: 10px;
    font-weight: var(--font-weight-bold);
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--pf-quiet);
}

.pf-hero__cell--lead .pf-hero__label { color: var(--pf-brand); }

.pf-hero__fig {
    font-size: 30px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.03em;
    font-variant-numeric: tabular-nums;
    color: var(--pf-body);
    line-height: 1.2;
}

.pf-hero__cell--lead .pf-hero__fig { font-size: 46px; color: var(--pf-title); line-height: 1; }

.pf-hero__sub { font-size: 11.5px; color: var(--pf-muted); }

/* The tab strip sits on the hero's bottom edge, so its active bar meets the hero/body seam. */
.pf-hero__tabs {
    display: flex;
    align-items: flex-end;
    gap: 4px;
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
}

.pf-hero__tabs::-webkit-scrollbar { display: none; }

.pf-ptab {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    padding: 0;
    border: none;
    background: none;
    font: inherit;
    cursor: pointer;
    flex: none;
}

.pf-ptab__label {
    padding: 0 var(--space-4);
    font-size: 13.5px;
    font-weight: var(--font-weight-normal);
    color: var(--pf-quiet);
    white-space: nowrap;
}

.pf-ptab__bar { width: 100%; height: 2px; border-radius: 2px 2px 0 0; background: transparent; }
.pf-ptab.is-active .pf-ptab__label { color: var(--pf-emph); font-weight: var(--font-weight-semibold); }
.pf-ptab.is-active .pf-ptab__bar { background: var(--pf-brand); }

.pf-hero__updated {
    margin-left: auto;
    padding-bottom: 10px;
    font-size: 11.5px;
    white-space: nowrap;
    color: var(--pf-quiet);
}

/* Everything below the hero is the ordinary light ground and is fully tokenised. */
.pf-pub__body {
    max-width: 1280px;
    margin: 0 auto;
    padding: var(--space-5);
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

.pf-pub__grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: var(--space-4);
}

@media (max-width: 900px) {
    .pf-pub__grid { grid-template-columns: minmax(0, 1fr); }
    .pf-hero__rail { margin-left: 0; width: 100%; }
    .pf-hero__cell { padding-left: 0; padding-right: var(--space-4); }
    .pf-hero__cell + .pf-hero__cell { padding-left: var(--space-4); }
    .pf-hero__name { font-size: 28px; }
    .pf-hero__cell--lead .pf-hero__fig { font-size: 34px; }
    .pf-hero__tile { width: 54px; height: 54px; border-radius: 16px; font-size: 19px; }
}

/* A public page with no call to action wastes the only reason to have made it public. */
.pf-convert {
    display: flex;
    align-items: center;
    gap: var(--space-5);
    padding: var(--space-5) var(--space-5);
    border-radius: var(--radius-xl);
    background: var(--auth-ground);
    border: 1px solid var(--auth-edge);
    flex-wrap: wrap;
}

.pf-convert__body { display: flex; flex-direction: column; gap: 5px; min-width: 0; }

.pf-convert__title {
    font-size: 17px;
    font-weight: var(--font-weight-semibold);
    letter-spacing: -0.015em;
    color: #fff;
}

.pf-convert__sub { font-size: 13px; color: #aab2bc; }
.pf-convert .pf-btn { margin-left: auto; padding: 11px 20px; border-radius: 11px; font-size: 14px; }

/* The "not available" state is a real page on the same dark ground, never a 404 shell. */
.pf-gone {
    max-width: 520px;
    margin: 0 auto;
    padding: var(--space-8) var(--space-5);
    text-align: center;
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    align-items: center;
}

.pf-gone__title {
    font-size: 24px;
    font-weight: var(--font-weight-bold);
    letter-spacing: -0.02em;
    color: var(--pf-title);
}

.pf-gone__body { font-size: 14px; color: var(--pf-muted); }
.pf-gone .pf-btn { margin-top: var(--space-3); }

/* ── Phone ───────────────────────────────────────────────────────────────────────────────── */

@media (max-width: 768px) {
    .pf-id {
        flex-wrap: wrap;
        gap: var(--space-3);
        padding: var(--space-4) var(--space-4) var(--space-3);
    }

    .pf-id__tile { width: 50px; height: 50px; border-radius: 15px; font-size: 18px; }
    .pf-id__name { font-size: 22px; }

    /* The switch takes its own full-width line rather than being squeezed beside a name. */
    .pf-scope { margin-left: 0; width: 100%; align-items: stretch; }
    .pf-scope__note { text-align: left; max-width: none; }
    .pf-scope .segmented { width: 100%; }

    .pf-chart { padding: 0 var(--space-3) var(--space-2); }
    .pf-chart--trend svg { height: 120px; }
    .pf-chart__labels { display: none; }
    .pf-legend { display: none; }

    .pf-eq { gap: var(--space-4); padding: 0 var(--space-4) var(--space-4); }
    .pf-eq__fig { font-size: 26px; }
    .pf-eq__end { margin-left: 0; text-align: left; width: 100%; }

    .pf-spread { padding: var(--space-3) 0 var(--space-4); }
    .pf-spread__fig { font-size: 20px; }
    .pf-spread__label { font-size: 9px; letter-spacing: 0.09em; }

    .pf-nines { padding: 0 var(--space-4) var(--space-4); }
    .pf-nines__fig { font-size: 20px; }
    .pf-nines__cell { padding: 0 var(--space-3); }

    .pf-rec { padding: var(--space-3) var(--space-4); gap: var(--space-3); }
    .pf-rec__tile { width: 32px; height: 32px; border-radius: 10px; }
    .pf-rec__fig { font-size: 19px; }

    .pf-range { margin: var(--space-4) var(--space-4) var(--space-5); }
}
