/* Fonts loaded via <link> in index.html for non-blocking rendering */

/* Shared brand palette (--color-primary / -light / -dark, the ink on it --color-on-primary and the logo mark
   --color-logo) is single-sourced from design-tokens/tokens.json via Style Dictionary (F-179 TASK_08, I-021 AD4).
   Generated by `cd mobile && npm run tokens`; drift-gated by scripts/check-token-drift.js.
   @import MUST precede all rule sets below. Do NOT re-declare these five vars here —
   the drift gate fails if they are redeclared or edited out of sync.
   The import is VERSIONED with the same ?v=N as app.css in index.html (bump both together;
   tests/scripts/css-import-versioned.test.js): nginx serves .css immutable for a year, so an unversioned import would
   keep a returning browser on its cached copy after a deploy. */
@import './_tokens.generated.css?v=48';

/* BRAND VALUES — I-021 AD3/AD4. The brand block only derives from the five imported vars and never redeclares them
   (scripts/css-token-parity.js). It must follow the @import directly. The rgb channels are pinned to the imported hex by
   tests/scripts/css-brand-rgb.test.js. The two per-theme rules are part of the brand block, not of the theme blocks,
   so they do not count for dark/light parity. "Orange only means mine" (REDESIGN_PROGRAM.md § 2). */
:root {
    /* rgb channels for rgba() composition: --X-rgb is the channel triplet of --X. */
    --color-primary-rgb: 237, 114, 0;
    --color-primary-light-rgb: 255, 153, 52;
    --color-primary-dark-rgb: 204, 100, 0;
    /* SnipePrice orange tonal scale. 500 = --color-primary, 400 = -light (dark-theme hover), 600 = -dark (light-theme
       hover). Brand logo orange (--color-logo) is reserved for the mark itself. */
    --color-primary-50: #fff5eb;
    --color-primary-100: #ffe6cc;
    --color-primary-200: #ffcb94;
    --color-primary-300: #ffb066;
    --color-primary-400: var(--color-primary-light);
    --color-primary-500: var(--color-primary);
    --color-primary-600: var(--color-primary-dark);
    --color-primary-700: #a34f00;
    --color-primary-800: #7a3b00;
    --color-primary-900: #4f2600;
    --color-brand-logo: var(--color-logo);
    /* Brand ink. Text on any primary-filled surface uses it: ink on #ed7200 is 5.9:1, on the hover
       #ff9934 8.3:1, on the active #cc6400 4.5:1 (WCAG AA). White on #ed7200 is only 3.0:1 — never use it. */
    --color-ink: var(--color-on-primary);
    --text-on-primary: var(--color-on-primary);

    /* F is flat (I-021 AD5): the name is kept for its callers, the value is the solid primary. */
    --gradient-primary: var(--color-primary);
}
:root, :root[data-theme="dark"] {
    /* Hover lightens in dark, darkens in light. */
    --color-primary-hover: var(--color-primary-light);
    /* Orange text ("mine") on the theme's surfaces. */
    --color-primary-text: #ff9d42;
    /* Brand line, glow (focus rings, primary shadows) and tinted surface ("mine" notices) — F dark --primary-line,
       --glow, --primary-bg. */
    --color-primary-line: rgba(var(--color-primary-rgb), 0.55);
    --color-primary-glow: rgba(var(--color-primary-rgb), 0.15);
    --color-primary-bg: rgba(var(--color-primary-rgb), 0.15);
}
:root[data-theme="light"] {
    --color-primary-hover: var(--color-primary-dark);
    --color-primary-text: #a34f00;
    --color-primary-line: rgba(var(--color-primary-rgb), 0.5);
    --color-primary-glow: rgba(var(--color-primary-rgb), 0.17);
    --color-primary-bg: rgba(var(--color-primary-rgb), 0.1);
}
/* END BRAND VALUES */

/* =====================================================================================================
   Dark theme block — I-021 AD1/AD3. Every theme-dependent colour, surface and shadow token, with prototype F's dark
   values (f.src.html, dark section; I-021 TASK_09) — opaque flat panels (AD5). The light block below declares exactly
   the same names (scripts/css-token-parity.js --require-blocks). Names are kept (AD1): each group names the F role it
   plays. Copy F, never invent; a name F has no role for (tier, accent, amber, tags, gold, chart categories) keeps the
   value the App shipped before.
   ===================================================================================================== */
:root, :root[data-theme="dark"] {
    /* Native controls and scrollbars follow the theme (I-023); js/theme-boot.js sets the same on <html> pre-paint */
    color-scheme: dark;
    /* Dark Theme — F --bg → --color-bg-dark; secondary / tertiary = F --panel-2 / --panel-3 */
    --color-bg-dark: #15171b;
    --color-bg-dark-secondary: #212429;
    --color-bg-dark-tertiary: #282c32;
    /* Elevated surface for floating menus / dropdown panels (Select, Dropdown menu, etc.) — F --panel, opaque */
    --color-bg-elevated: #1c1f24;
    /* Pinned (Fixed) table cells: opaque, or the columns that scroll under them show through (B-054). */
    --table-pinned-bg: var(--color-bg-elevated);
    /* New F roles (AD1): --panel-3, --panel-we, --we-band, --row-hover. */
    --color-panel-3: #282c32;
    --color-panel-we: #24272d;
    --color-we-band: #31353c;
    --color-row-hover: rgba(255, 255, 255, 0.04);

    /* Glass names, flat F values (AD5: opaque, no blur) — F --panel / --panel-2 → --glass-bg / --glass-bg-light (subtle:
       --panel-2, F's inset and header surface); F --line / --line-2 → --glass-border / --glass-border-light; shadow
       tint of F --shadow */
    --glass-bg-subtle: #212429;
    --glass-bg: #1c1f24;
    --glass-bg-light: #212429;
    --glass-border: #2d3238;
    --glass-border-light: #3c424b;
    --glass-shadow: rgba(0, 0, 0, 0.5);

    /* Text Colors — F --text / --text-2 / --muted */
    --text-primary: #eceef1;
    --text-secondary: #c3c8d0;
    --text-muted: #979eab;

    /* Gradients — F is flat: the page background is F --bg */
    --gradient-bg: var(--color-bg-dark);

    /* Semantic Status Colors — F --ok / --warn / --err / --info; -light and -hover take F's text tones
       (--opp-text, --above, --threat-text, --below); -rgb / -bg the hues of F's tints */
    --color-success: #5fd07f;
    --color-success-light: #6cd38a;
    --color-success-hover: #6cd38a;
    --color-success-rgb: 76, 200, 112;
    --color-success-bg: rgba(76, 200, 112, 0.13);
    --color-warning: #f0b44a;
    --color-warning-light: #f2bb55;
    --color-warning-rgb: 240, 170, 40;
    --color-warning-bg: rgba(240, 170, 40, 0.14);
    --color-error: #ff7b72;
    --color-error-light: #ff8f86;
    --color-error-rgb: 255, 99, 88;
    --color-error-bg: rgba(255, 99, 88, 0.2);
    --color-info: #82b4ff;
    --color-info-light: #8dbbff;
    --color-info-hover: #8dbbff;
    --color-info-rgb: 96, 150, 255;
    --color-info-bg: rgba(96, 150, 255, 0.14);
    --color-accent-purple: #722ed1;
    --color-accent-purple-light: #b37feb;
    --color-accent-purple-hover: #9254de;

    /* Subscription Tier Colors */
    --color-tier-starter: #60a5fa;
    --color-tier-pro: #a78bfa;
    --color-tier-starter-bg: rgba(96, 165, 250, 0.15);
    --color-tier-pro-bg: rgba(167, 139, 250, 0.15);

    /* Decorative Accents */
    --color-amber: #f5a623;

    /* Badges, events and the overlay mask — new F roles (AD1): --badge-bg / --badge-fg (neutral, never orange),
       --event, --mask */
    --color-badge-bg: #eceef1;
    --color-badge-fg: #15171b;
    --color-event: #f0b44a;
    /* Event label text (I-023 TASK_06); --color-event stays the dot / outline colour */
    --color-event-text: var(--color-event);
    --color-mask: rgba(0, 0, 0, 0.5);

    /* Shadow scale — replaces inline box-shadow values across the project.
       *-primary-* use the brand glow; non-primary use the neutral glass shadow. */
    --shadow-sm: 0 2px 4px var(--glass-shadow);
    --shadow-md: 0 4px 12px var(--glass-shadow);
    --shadow-lg: 0 8px 24px var(--glass-shadow);
    --shadow-xl: 0 16px 48px var(--glass-shadow);
    --shadow-primary-md: 0 4px 14px var(--color-primary-glow);
    --shadow-primary-lg: 0 8px 24px var(--color-primary-glow);
    --shadow-inset-subtle: inset 0 1px 0 rgba(255, 255, 255, 0.06);

    /* =================================================================================================
       SnipePrice Core — rate semantics, charts and tooltip (D1). Shared by the rate calendar, night drawer,
       dashboard and insights. Colour meaning (owner's point of view), never the brand orange for good/bad:
         competitor cheaper than me = threat  → error hue   (.rate-threat-1…3)
         competitor dearer than me  = room     → success hue (.rate-opportunity-1…3)
         my position vs comp median            → info (below) / neutral (at) / warning (above)
       Orange (--rate-mine) only ever means "my hotel / my price". F roles: --threat-*, --opp-*, --below*,
       --above*, --at-bg. The classes live in the "SnipePrice Core — rate semantics" section further down.
       ================================================================================================= */
    --rate-mine: var(--color-primary);
    /* "Mine" as text (F .rg .c-mine .v, .t-mine): the solid primary in dark; --rate-mine stays the graphic colour */
    --rate-mine-text: var(--rate-mine);
    --rate-mine-bg: rgba(var(--color-primary-rgb), 0.15);
    --rate-mine-border: rgba(var(--color-primary-rgb), 0.55);

    --rate-threat-bg-1: rgba(255, 99, 88, 0.11);
    --rate-threat-bg-2: rgba(255, 99, 88, 0.2);
    --rate-threat-bg-3: rgba(255, 99, 88, 0.32);
    --rate-threat-text: #ff8f86;
    /* F --threat: the solid threat mark (the dashboard board's undercut corner and legend swatch, I-028) */
    --rate-threat: #ff6b60;
    --rate-opportunity-bg-1: rgba(76, 200, 112, 0.09);
    --rate-opportunity-bg-2: rgba(76, 200, 112, 0.17);
    --rate-opportunity-bg-3: rgba(76, 200, 112, 0.28);
    --rate-opportunity-text: #6cd38a;

    --position-below-bg: rgba(96, 150, 255, 0.22);
    --position-below-border: rgba(96, 150, 255, 0.5);
    --position-below-text: #8dbbff;
    --position-above-bg: rgba(240, 170, 40, 0.22);
    --position-above-border: rgba(240, 170, 40, 0.5);
    --position-above-text: #f2bb55;
    --position-at-bg: rgba(255, 255, 255, 0.075);
    --position-at-border: var(--glass-border-light);

    --rate-sold-out-text: var(--text-muted);

    /* Month heat view — new F roles (AD1) --heat-a1…a3 (above median) / --heat-b1…b3 (below median) */
    --color-heat-a1: rgba(240, 170, 40, 0.12);
    --color-heat-a2: rgba(240, 170, 40, 0.23);
    --color-heat-a3: rgba(240, 170, 40, 0.36);
    --color-heat-b1: rgba(96, 150, 255, 0.13);
    --color-heat-b2: rgba(96, 150, 255, 0.23);
    --color-heat-b3: rgba(96, 150, 255, 0.36);

    /* Categorical series colours for competitor lines — none is orange, red or green on purpose. */
    --chart-cat-1: #7ea8ff;
    --chart-cat-2: #5fd4c7;
    --chart-cat-3: #b79cff;
    --chart-cat-4: #e9c46a;
    --chart-cat-5: #f28fb1;
    --chart-cat-6: #9fb4c7;
    --chart-band: rgba(150, 160, 176, 0.13);
    --chart-shade: rgba(255, 255, 255, 0.03);
    /* New F roles (AD1) --chart-comp / --chart-grid / --chart-median; --chart-band is F --band, --chart-shade F --none-bg */
    --color-chart-comp: rgba(150, 160, 176, 0.34);
    /* F --band-edge — the market-range outline (legend swatch, weekday median bar; I-029) */
    --color-chart-band-edge: rgba(150, 160, 176, 0.34);
    --color-chart-grid: rgba(255, 255, 255, 0.07);
    --color-chart-median: #d4d8e0;

    /* Shadows for floating Core surfaces (switcher panel, hovered month day, pinned grid edge). */
    --shadow-float: 0 14px 36px rgba(0, 0, 0, 0.5), 0 1px 3px rgba(0, 0, 0, 0.4);
    --shadow-lift: 0 6px 16px rgba(0, 0, 0, 0.35);
    --shadow-pinned-edge: 8px 0 16px -12px rgba(0, 0, 0, 0.6);
    /* New role tokens added by I-021 TASK_05 so app.css carries no colour literal outside the blocks. */
    --glass-border-subtle: #2d3238;
    --glass-bg-hover: #2b2f36;
    --glass-shine: rgba(255, 255, 255, 0.2);
    --color-error-solid: #ff7b72;
    --color-on-error-solid: #171820;
    --color-error-description: #ff8f86;
    /* I-032 (README D-l, D-o, D-s): F's color-mix() roles, measured — the selected card / tile ground (primary 5% over
       --panel), the danger section's border (--err 35% over --line), the "Link ready" box (--ok 35% / 6%) */
    --color-primary-faint: #262322;
    --color-error-line: #774c4c;
    --color-success-line: #3f6951;
    --color-success-faint: #202a29;
    --color-tier-starter-rgb: 96, 165, 250;
    --color-accent-purple-rgb: 114, 46, 209;
    --color-accent-cyan: #22d3ee;
    --color-accent-cyan-rgb: 34, 211, 238;
    --shadow-popup: 0 14px 36px rgba(0, 0, 0, 0.5), 0 1px 3px rgba(0, 0, 0, 0.4);
    --shadow-card-hover: 0 8px 32px rgba(0, 0, 0, 0.3);
    --shadow-tooltip: 0 14px 36px rgba(0, 0, 0, 0.5), 0 1px 3px rgba(0, 0, 0, 0.4);
    /* New role tokens added by I-021 TASK_06 so overrides.css carries no colour literal. */
    --glass-border-faint: rgba(255, 255, 255, 0.04);
    --glass-border-strong: rgba(255, 255, 255, 0.25);
    --text-disabled: rgba(255, 255, 255, 0.35);
    --color-scrim: rgba(0, 0, 0, 0.45);
    --color-on-solid: #ffffff;
    --color-tier-pro-rgb: 167, 139, 250;
    --color-amber-rgb: 245, 166, 35;
    /* AntD preset tag colours (cyan, pink/magenta, lime, volcano, geekblue): text tone + rgb for the tint */
    --color-tag-cyan: #36cfc9;
    --color-tag-cyan-rgb: 19, 194, 194;
    --color-tag-pink: #f759ab;
    --color-tag-pink-rgb: 235, 47, 150;
    --color-tag-lime: #bae637;
    --color-tag-lime-rgb: 160, 217, 17;
    --color-tag-volcano: #ff7a45;
    --color-tag-volcano-rgb: 250, 84, 28;
    --color-tag-geekblue: #597ef7;
    --color-tag-geekblue-rgb: 47, 84, 235;
    /* Gold subscription tier (tier-max): gradient, line and glow */
    --gradient-gold: linear-gradient(135deg, #d4af37 0%, #ffd700 50%, #b8860b 100%);
    --color-gold-line: rgba(255, 215, 0, 0.5);
    --shadow-gold: 0 0 12px rgba(212, 175, 55, 0.4);
    /* New role tokens added by I-023 TASK_04 (light audit). F --knob, --sk-1 / --sk-2; the rest name an App rule's
       per-theme value so dark computes as before: tooltip surface, sider selected item, focus ring, link text and the
       plan-max text glow and the light orange accent (--color-primary-300 in dark). */
    --color-knob: #eceef1;
    --color-skeleton-1: #24282e;
    --color-skeleton-2: #2d3239;
    --color-tooltip-bg: var(--color-bg-elevated);
    --color-tooltip-fg: var(--text-primary);
    --color-tooltip-border: var(--glass-border);
    --color-toast-bg: #23272d; /* F --sp-toast-bg: the Message toast ground (I-033 TASK_01) */
    --color-nav-selected-bg: rgba(var(--color-primary-rgb), 0.15);
    --color-nav-selected-text: var(--color-primary);
    --color-nav-selected-icon: var(--color-primary);
    --color-focus-ring: var(--color-primary-glow);
    /* Orange text and icons on the theme's surfaces (I-023 TASK_06): the solid primary here, as in I-021. Links rest
       on it and hover / press to --color-link-hover. */
    --color-primary-fg: var(--color-primary);
    --color-link-hover: var(--color-primary-text);
    --glow-text: 0 0 20px rgba(var(--color-primary-rgb), 0.4);
    --color-primary-accent: var(--color-primary-300);
}

/* =====================================================================================================
   Light theme block — I-021 AD3. Prototype F's light values (f.src.html, light section) for every name of the dark
   block. Live since I-023: js/theme-boot.js sets data-theme (System default, snipeprice.theme). Text tokens are F's
   (≥ 5.4:1 on their surfaces) — copy F, never invent. A name F has no light role for (tier, accent, amber, tag hues, chart
   categories) gets a light value of its own hue (I-023 TASK_04, README D-o): text ≥ 4.5:1 and graphics ≥ 3:1 on #ffffff,
   measured with scripts/fidelity/color.js (specs/I-023-RedesignLightTheme/VERIFICATION_REPORT.md).
   ===================================================================================================== */
:root[data-theme="light"] {
    color-scheme: light;
    /* Dark Theme names, light values — F --bg, --panel-2, --panel-3, --panel */
    --color-bg-dark: #f1f2f5;
    --color-bg-dark-secondary: #f7f8fa;
    --color-bg-dark-tertiary: #eceef2;
    --color-bg-elevated: #ffffff;
    --table-pinned-bg: var(--color-bg-elevated);
    --color-panel-3: #eceef2;
    --color-panel-we: #eff1f4;
    --color-we-band: #e2e5ea;
    --color-row-hover: rgba(20, 22, 27, 0.035);

    /* Glass names, flat F values — F --panel-2, --panel, --panel-2, --line, --line-2; shadow tint of F --shadow */
    --glass-bg-subtle: #f7f8fa;
    --glass-bg: #ffffff;
    --glass-bg-light: #f7f8fa;
    --glass-border: #dcdfe5;
    --glass-border-light: #c6cbd3;
    --glass-shadow: rgba(20, 22, 27, 0.13);

    /* Text Colors — F --text / --text-2 / --muted */
    --text-primary: #14161b;
    --text-secondary: #3a3f4a;
    --text-muted: #5a606d;

    /* Gradients — F is flat: the page background is F --bg */
    --gradient-bg: var(--color-bg-dark);

    /* Semantic Status Colors — F --ok / --warn / --err / --info; -light and -hover take F's text tones
       (--opp-text, --above, --threat-text, --below); -rgb / -bg the hues of F's tints */
    --color-success: #1f7a3a;
    --color-success-light: #1b7032;
    --color-success-hover: #1b7032;
    --color-success-rgb: 31, 140, 64;
    --color-success-bg: rgba(31, 140, 64, 0.1);
    --color-warning: #8a5300;
    --color-warning-light: #8a5300;
    --color-warning-rgb: 232, 150, 0;
    --color-warning-bg: rgba(232, 150, 0, 0.14);
    --color-error: #c0261b;
    --color-error-light: #b42318;
    --color-error-rgb: 217, 45, 32;
    --color-error-bg: rgba(217, 45, 32, 0.14);
    --color-info: #1453b8;
    --color-info-light: #1453b8;
    --color-info-hover: #1453b8;
    --color-info-rgb: 31, 102, 214;
    --color-info-bg: rgba(31, 102, 214, 0.1);
    --color-accent-purple: #722ed1;
    --color-accent-purple-light: #7a3fd0;
    --color-accent-purple-hover: #5b23ad;

    /* Subscription Tier Colors (no F role; I-023 D-o: same hue, text ≥ 4.5:1 on white and on its -bg) */
    --color-tier-starter: #2159d4;
    --color-tier-pro: #7c3aed;
    --color-tier-starter-bg: rgba(33, 89, 212, 0.1);
    --color-tier-pro-bg: rgba(124, 58, 237, 0.1);

    /* Decorative Accents (no F role; I-023 D-o: amber text 5.68:1 on white) */
    --color-amber: #8f5c00;

    /* Badges, events and the overlay mask — F --badge-bg / --badge-fg, --event, --mask */
    --color-badge-bg: #14161b;
    --color-badge-fg: #ffffff;
    --color-event: #d98c00;
    /* F --event is a graphic colour (2.41:1 as 10px text on white); event labels take F --warn (#8a5300) */
    --color-event-text: var(--color-warning);
    --color-mask: rgba(20, 22, 27, 0.36);

    /* Shadow scale — F --shadow's tint */
    --shadow-sm: 0 2px 4px var(--glass-shadow);
    --shadow-md: 0 4px 12px var(--glass-shadow);
    --shadow-lg: 0 8px 24px var(--glass-shadow);
    --shadow-xl: 0 16px 48px var(--glass-shadow);
    --shadow-primary-md: 0 4px 14px var(--color-primary-glow);
    --shadow-primary-lg: 0 8px 24px var(--color-primary-glow);
    --shadow-inset-subtle: inset 0 1px 0 rgba(20, 22, 27, 0.04);

    /* SnipePrice Core — rate semantics (see the dark block) — F --primary-bg / --primary-line, --threat-*, --opp-*,
       --below*, --above*, --at-bg, --panel-we, --row-hover */
    --rate-mine: var(--color-primary);
    /* F --primary-text (5.71:1 on white); --rate-mine (#ed7200, 2.996:1) is for marks, bars and lines only */
    --rate-mine-text: var(--color-primary-text);
    --rate-mine-bg: rgba(var(--color-primary-rgb), 0.1);
    --rate-mine-border: rgba(var(--color-primary-rgb), 0.5);

    --rate-threat-bg-1: rgba(217, 45, 32, 0.07);
    --rate-threat-bg-2: rgba(217, 45, 32, 0.14);
    --rate-threat-bg-3: rgba(217, 45, 32, 0.24);
    --rate-threat-text: #b42318;
    /* F --threat */
    --rate-threat: #d92d20;
    --rate-opportunity-bg-1: rgba(31, 140, 64, 0.07);
    --rate-opportunity-bg-2: rgba(31, 140, 64, 0.14);
    --rate-opportunity-bg-3: rgba(31, 140, 64, 0.24);
    --rate-opportunity-text: #1b7032;

    --position-below-bg: rgba(31, 102, 214, 0.14);
    --position-below-border: rgba(31, 102, 214, 0.5);
    --position-below-text: #1453b8;
    --position-above-bg: rgba(232, 150, 0, 0.22);
    --position-above-border: rgba(232, 150, 0, 0.5);
    --position-above-text: #8a5300;
    --position-at-bg: rgba(20, 22, 27, 0.06);
    --position-at-border: var(--glass-border-light);

    --rate-sold-out-text: var(--text-muted);

    /* Month heat view — F --heat-a1…a3 / --heat-b1…b3 */
    --color-heat-a1: rgba(232, 150, 0, 0.13);
    --color-heat-a2: rgba(232, 150, 0, 0.26);
    --color-heat-a3: rgba(232, 150, 0, 0.42);
    --color-heat-b1: rgba(31, 102, 214, 0.1);
    --color-heat-b2: rgba(31, 102, 214, 0.2);
    --color-heat-b3: rgba(31, 102, 214, 0.32);

    /* Charts — categorical colours have no F role (I-023 D-o: same hue, each ≥ 3:1 on white); median / grid / band /
       shade / comp are F's */
    --chart-cat-1: #3d6fd6;
    --chart-cat-2: #0f857a;
    --chart-cat-3: #7c52d9;
    --chart-cat-4: #8c6a00;
    --chart-cat-5: #c4336f;
    --chart-cat-6: #5c7085;
    --chart-band: rgba(90, 96, 109, 0.12);
    --chart-shade: rgba(20, 22, 27, 0.025);
    --color-chart-comp: rgba(90, 96, 109, 0.34);
    --color-chart-band-edge: rgba(90, 96, 109, 0.32);
    --color-chart-grid: rgba(20, 22, 27, 0.08);
    --color-chart-median: #3a3f4a;

    /* Shadows for floating Core surfaces — F --shadow */
    --shadow-float: 0 12px 32px rgba(20, 22, 27, 0.13), 0 1px 3px rgba(20, 22, 27, 0.08);
    --shadow-lift: 0 6px 16px rgba(20, 22, 27, 0.1);
    --shadow-pinned-edge: 8px 0 16px -12px rgba(20, 22, 27, 0.18);
    /* New role tokens added by I-021 TASK_05 — F --line, --panel-hover, --err, --threat-text, --shadow's tint; a name F
       has no role for keeps its dark value (shine, crash bar, on-error ink, accent-purple rgb); tier rgb and cyan follow
       their light text tone (I-023 D-o) */
    --glass-border-subtle: #dcdfe5;
    --glass-bg-hover: #e7eaef;
    --glass-shine: rgba(255, 255, 255, 0.2);
    --color-error-solid: #c0261b;
    --color-on-error-solid: #ffffff;
    --color-error-description: #b42318;
    /* I-032: F's color-mix() roles, measured (see the dark block) */
    --color-primary-faint: #fef8f2;
    --color-error-line: #d29e9e;
    --color-success-line: #9abca9;
    --color-success-faint: #f2f7f3;
    --color-tier-starter-rgb: 33, 89, 212;
    --color-accent-purple-rgb: 114, 46, 209;
    --color-accent-cyan: #0e7490;
    --color-accent-cyan-rgb: 14, 116, 144;
    --shadow-popup: 0 12px 32px rgba(20, 22, 27, 0.13), 0 1px 3px rgba(20, 22, 27, 0.08);
    --shadow-card-hover: 0 8px 32px rgba(20, 22, 27, 0.1);
    --shadow-tooltip: 0 12px 32px rgba(20, 22, 27, 0.13), 0 1px 3px rgba(20, 22, 27, 0.08);
    /* New role tokens added by I-021 TASK_06 — border / text / scrim take the ink tint of F's light block (no F role for
       faint, strong, disabled or scrim: derived from F --line / --text-2 / --mask); --text-disabled is opaque in light, 4.90:1 on
       white (I-023 TASK_04 Req 10); on-solid ink, the tag tint rgb and the gold tier keep their dark value; tier / amber rgb
       and the tag text tones take their light hue (I-023 D-o) */
    --glass-border-faint: rgba(20, 22, 27, 0.04);
    --glass-border-strong: #aab0ba;
    --text-disabled: #6b717d;
    --color-scrim: rgba(20, 22, 27, 0.2);
    --color-on-solid: #ffffff;
    --color-tier-pro-rgb: 124, 58, 237;
    --color-amber-rgb: 143, 92, 0;
    --color-tag-cyan: #0b7a75;
    --color-tag-cyan-rgb: 19, 194, 194;
    --color-tag-pink: #b8287a;
    --color-tag-pink-rgb: 235, 47, 150;
    --color-tag-lime: #4f6b00;
    --color-tag-lime-rgb: 160, 217, 17;
    --color-tag-volcano: #b33a0b;
    --color-tag-volcano-rgb: 250, 84, 28;
    --color-tag-geekblue: #2f4fd1;
    --color-tag-geekblue-rgb: 47, 84, 235;
    --gradient-gold: linear-gradient(135deg, #d4af37 0%, #ffd700 50%, #b8860b 100%);
    --color-gold-line: rgba(255, 215, 0, 0.5);
    --shadow-gold: 0 0 12px rgba(212, 175, 55, 0.4);
    /* New role tokens added by I-023 TASK_04 — F --knob, --sk-1 / --sk-2; tooltip = F --badge-bg / --badge-fg (F's
       [data-tip]); sider selected = F .nv[aria-current] (--panel-3, --text, --primary-text icon); focus ring = F
       :focus-visible's solid orange, -dark because --color-primary is 2.996:1 on white (#cc6400 3.90:1); link text = F
       --primary-text (5.71:1); no text glow in light */
    --color-knob: #ffffff;
    --color-skeleton-1: #eceef2;
    --color-skeleton-2: #f7f8fa;
    --color-tooltip-bg: var(--color-badge-bg);
    --color-tooltip-fg: var(--color-badge-fg);
    --color-tooltip-border: var(--color-badge-bg);
    --color-toast-bg: #ffffff; /* F --sp-toast-bg (I-033 TASK_01) */
    --color-nav-selected-bg: var(--color-panel-3);
    --color-nav-selected-text: var(--text-primary);
    --color-nav-selected-icon: var(--color-primary-text);
    --color-focus-ring: var(--color-primary-dark);
    /* Orange text and icons (I-023 TASK_06): F --primary-text, because the solid #ed7200 is 2.996:1 on white. Links
       rest on it, so their hover / press darkens one step (#7a3b00) instead of repeating it. */
    --color-primary-fg: var(--color-primary-text);
    --color-link-hover: var(--color-primary-800);
    --glow-text: none;
    /* The light orange accent (recommended rate, "mine" hovers and outlines): #ffb066 is 1.80:1 on white, -700
       (#a34f00) 5.71:1 */
    --color-primary-accent: var(--color-primary-700);
}

/* Theme-independent tokens — I-021 AD3 (D8): fonts, spacing, radius, transitions and third-party brand colours.
   Not part of dark/light parity. Page widths and form-drawer widths live in the "Page Width Variables" block below. */
:root {
    /* Legacy role names (I-021 #11439) — one alias per F role, declared once here, never per theme: the value lives
       only in the F-role token of each theme block, so each alias still resolves per theme. No token is renamed or
       removed (TASK_04 Req 5): --rate-weekend-bg is kept as the alias of F's weekend column (--color-panel-we). */
    --rate-row-hover-bg: var(--color-row-hover);
    --rate-weekend-bg: var(--color-panel-we);
    --chart-grid: var(--color-chart-grid);
    --chart-median: var(--color-chart-median);

    /* Social Brand Colors (third-party identities — the same in every theme) */
    --color-social-twitter: #1da1f2;
    --color-social-linkedin: #0a66c2;
    --color-social-facebook: #4267b2;
    --color-social-whatsapp: #25d366;

    /* Typography — I-021 AD7 (prototype F). Space Grotesk is the UI face, JetBrains Mono carries every number and label.
       Both are self-hosted (css/fonts.css); keep the system fallbacks after the first family. */
    --font-display: 'Space Grotesk', sans-serif;
    --font-body: 'Space Grotesk', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    --font-mono: 'JetBrains Mono', ui-monospace, 'SF Mono', monospace;

    /* Type scale — F. Body is 14px / 1.5; each tier below is a size with its weight (and tracking when it has one). */
    --type-body: 14px;
    --type-body-line: 1.5;
    --type-title: 26px;
    --type-title-weight: 600;
    --type-title-tracking: -0.015em;
    --type-panel-title: 15px;
    --type-panel-title-weight: 600;
    --type-step-title: 19px; /* F .wiz__title (I-032 D-n, #11504) */
    --type-step-title-weight: 600;
    --type-step-title-line: 1.25;
    --type-step-title-tracking: -0.01em;
    --type-section-title: 16px; /* F .sec__title — a settings section (I-032 D-o) */
    --type-block-title: 14px; /* F .hsec__t — a block of result cards (I-032 D-l) */
    --type-sub-title: 13.5px; /* F .subh — a sub-heading inside a panel (I-032 D-s) */
    --type-label: 10.5px;
    --type-label-weight: 500;
    --type-label-tracking: 0.06em;

    /* Control heights — F (inputs, selects, pickers, buttons; overrides.css "Control density" block) */
    --control-h-sm: 32px;
    --control-h: 34px;
    --control-h-lg: 36px;
    --control-h-block: 38px; /* full-width buttons — F .btn--block (auth forms) */

    /* Sidebar nav icon weight (I-037 D-g) — F draws 17px line icons at stroke 1.7; AntD's Outline glyphs are filled paths in
       a 1024-unit viewBox, so .shell-nav__item strokes them by this many glyph units (calibrated to F's ink at 1440).
       I-037 TASK_07: recalibrated at the real 17px glyph (overrides.css) — any stroke ≤ 1 unit renders a hairline, alpha
       ink 0.2188 vs F 0.2099 (+4 %); 32 units was compensating the 14px glyph AntD had imposed (≥ 0.285 at 17px) */
    --nav-icon-stroke: 1px;

    /* Spacing */
    --space-xs: 0.25rem;
    --space-sm: 0.5rem;
    --space-md: 1rem;
    --space-lg: 1.5rem;
    --space-xl: 2rem;
    --space-2xl: 3rem;

    /* Borders */
    /* F's scale (I-021 AD7): panels 14px, controls 8px, chips 6px; xs/xxs stay below the chip radius */
    --radius-xxs: 2px;
    --radius-xs: 4px;
    --radius-sm: 6px;
    --radius-md: 8px;
    --radius-lg: 14px;
    --radius-xl: 24px;

    /* Transitions */
    --transition-fast: 150ms ease;
    --transition-base: 250ms ease;
    --transition-slow: 400ms ease;
}

/* Global heading font — B-051 AD2. Uses the Typography tokens above (--font-display).
   AntD sets no heading font-family, so this rule can live here before ant-design-blazor.css. The type-scale title
   classes are listed too, so a non-heading element that should look like a title takes the display font from its class. */
h1, h2, h3, h4, h5, h6,
.page-title, .wizard-step__title, .section-title-sm, .dashboard-card-title, .form-section__title,
.detail-page-grid__side-title, .section-title-xs, .sec__title, .hsec__t, .pv__h, .team-panel__title, .subh {
    font-family: var(--font-display);
}

/* Type scale — B-051 AD3. One scale for every title class; pick the tier, never a new size.
   Tier             Size / weight     Classes
   page title       --type-title 26px / 600          .page-title (1.5rem at <=480px); count inside it: .page-title__count
   step title       --type-step-title 19px / 600     .wizard-step__title (F .wiz__title: 1.25 line, -0.01em — I-032 D-n)
   section title    --type-section-title 16px / 600  .sec__title (F settings section, I-032)
   panel title      --type-panel-title 15px / 600    .section-title-sm, .dashboard-card-title, .form-section__title,
                                                     .detail-page-grid__side-title, .core-card-title, .pv__h, .team-panel__title
   block title      --type-block-title 14px / 600    .hsec__t (F result-card block, I-032)
   sub-title        --type-sub-title 13.5px / 600    .subh (F panel sub-heading, I-032)
   label            --type-label 10.5px / 500 mono   .section-title-xs, .core-eyebrow, .kpi-strip__label (uppercase, tracked)
   Labels and numbers are set in --font-mono (JetBrains Mono): the label tier, .tabular-nums, .kpi-strip__value,
   .rate-pill, .page-title__count, .stat-value, .numeric-cell. Titles stay in the UI face.
   .section-title-xs is still in the heading list above, but it is a label now: its own rule (later, same specificity)
   sets --font-mono. */

html {
    height: 100%;
    background: var(--color-bg-dark);
    overflow: hidden;
}

body {
    font-family: var(--font-body);
    font-size: var(--type-body);
    line-height: var(--type-body-line);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    background: var(--gradient-bg);
    color: var(--text-primary);
    height: 100%;
    margin: 0;
    overflow: hidden;
}

/* Global Icon Color Default — TASK_04 systemic fix.
   AntDesign icons (.anticon), raw <svg>, and Material icons inherit currentColor
   so any element rendered outside an AntDesign component class chain still gets
   on-brand color (driven by body's --text-primary). Component-specific overrides
   in overrides.css (e.g., button-primary, message-success, menu-selected) remain
   authoritative — they win on specificity. */
.anticon,
.material-icons {
    color: currentColor;
}

svg:not(:root) {
    fill: currentColor;
}

/* Skip-to-Content Link (Accessibility) */
.skip-to-content {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
    z-index: 9999;
}

.skip-to-content:focus {
    position: fixed;
    top: 8px;
    left: 8px;
    width: auto;
    height: auto;
    padding: 8px 16px;
    background: var(--color-primary);
    color: var(--text-on-primary);
    font-size: 14px;
    font-weight: 600;
    border-radius: var(--radius-sm);
    text-decoration: none;
    z-index: 9999;
    outline: 2px solid var(--text-primary);
}

.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

#app {
    height: 100%;
    background: transparent;
    overflow: hidden;
}

/* Auth layout fix - ensure full height flex container */
.auth-page {
    display: flex;
    flex-direction: column;
    height: 100%;
}

h1:focus {
    outline: 2px solid transparent;
    outline-offset: 2px;
}

.content {
    padding-top: 1.1rem;
}

.valid.modified:not([type=checkbox]) {
    outline: 1px solid var(--color-success);
}

.invalid {
    outline: 1px solid var(--color-error);
}

.validation-message {
    color: var(--color-error-light);
}

/* I-023 TASK_04: the crash bar follows the theme — it inherits the root color-scheme and paints the elevated panel
   with the theme's text, so neither theme puts light text on a light bar. */
#blazor-error-ui {
    background: var(--color-bg-elevated);
    border-top: 1px solid var(--glass-border);
    color: var(--text-primary);
    bottom: 0;
    box-shadow: 0 -1px 2px var(--glass-shadow);
    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, var(--color-error-solid);
    padding: 1rem 1rem 1rem 3.7rem;
    color: var(--color-on-error-solid);
}

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

/* ========================================
   Theme logos (I-023)
   ======================================== */

/* Full wordmark per theme: logo.svg is white (dark ground), logo-light.svg is dark (light ground). Both <img>s are
   rendered; data-theme is set by theme-boot.js before first paint, so this CSS-only swap never flashes. It lives here
   because the selector depends on <html>, outside any component scope. A hidden image is display: none, so screen
   readers announce one. The collapsed logo-icon.svg (orange mark) reads on both grounds and is not swapped. */
.theme-logo--light {
    display: none;
}

:root[data-theme="light"] .theme-logo--dark {
    display: none;
}

:root[data-theme="light"] .theme-logo--light {
    display: revert;
}

/* ========================================
   App Loading Screen
   ======================================== */

.loading-screen {
    position: fixed;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    /* F is flat: the boot screen is the page ground (F --bg), tokens only. */
    background: var(--color-bg-dark);
    font-family: var(--font-body);
}

.loading-logo-container {
    position: relative;
    width: 120px;
    height: 120px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.loading-logo {
    width: 56px;
    height: 56px;
    animation: logoPulse 2s ease-in-out infinite;
    filter: drop-shadow(0 0 20px rgba(var(--color-primary-rgb), 0.5));
}

@keyframes logoPulse {
    0%, 100% {
        transform: scale(1);
        filter: drop-shadow(0 0 20px rgba(var(--color-primary-rgb), 0.5));
    }
    50% {
        transform: scale(1.05);
        filter: drop-shadow(0 0 30px rgba(var(--color-primary-rgb), 0.7));
    }
}

.loading-ring {
    position: absolute;
    width: 100%;
    height: 100%;
    transform: rotate(-90deg);
}

.loading-ring-track {
    fill: none;
    stroke: var(--glass-border-subtle);
    stroke-width: 3;
}

.loading-ring-progress {
    fill: none;
    stroke: var(--color-primary);
    stroke-width: 3;
    stroke-linecap: round;
    stroke-dasharray: calc(3.141 * 92 * var(--blazor-load-percentage, 0) / 100), 500;
    transition: stroke-dasharray 0.15s ease-out;
    filter: drop-shadow(0 0 6px rgba(var(--color-primary-rgb), 0.6));
    animation: ringGlow 2s ease-in-out infinite;
}

@keyframes ringGlow {
    0%, 100% {
        filter: drop-shadow(0 0 6px rgba(var(--color-primary-rgb), 0.6));
    }
    50% {
        filter: drop-shadow(0 0 12px rgba(var(--color-primary-rgb), 0.8));
    }
}

.loading-text {
    margin-top: 24px;
    color: var(--text-secondary);
    font-size: 14px;
    font-weight: 500;
    letter-spacing: 0.5px;
}

.loading-dots::after {
    content: '';
    animation: loadingDots 1.5s infinite;
}

@keyframes loadingDots {
    0%, 20% {
        content: '';
    }
    40% {
        content: '.';
    }
    60% {
        content: '..';
    }
    80%, 100% {
        content: '...';
    }
}

/* Inline code is reference text, not "mine" (I-021 AD6): the primary text colour (AntD sets its mono face) */
code {
    color: var(--text-primary);
}

.form-floating > .form-control-plaintext::placeholder, .form-floating > .form-control::placeholder {
    color: var(--bs-secondary-color);
    text-align: end;
}

.form-floating > .form-control-plaintext:focus::placeholder, .form-floating > .form-control:focus::placeholder {
    text-align: start;
}

/* ========================================
   AntDesign Global Theme Overrides
   For Auth Pages (Dark Theme)
   ======================================== */

/* Auth page specific - Language Picker Select */
.auth-page .ant-select {
    min-width: 130px;
}

.auth-page .ant-select-selector {
    background: var(--glass-bg-light) !important;
    border: 1px solid var(--glass-border) !important;
    border-radius: var(--radius-sm) !important;
    color: var(--text-secondary) !important;
    transition: all var(--transition-base) !important;
    height: 36px !important;
}

.auth-page .ant-select-arrow {
    color: var(--text-muted) !important;
}

.auth-page .ant-select:hover .ant-select-selector {
    border-color: var(--glass-border-light) !important;
}

.auth-page .ant-select-focused .ant-select-selector {
    border-color: var(--color-primary) !important;
    box-shadow: 0 0 0 2px var(--color-focus-ring) !important;
}

.auth-page .ant-select-selection-item {
    color: var(--text-secondary) !important;
    font-size: 0.875rem;
}

/* Dropdown menu styling */
.ant-select-dropdown {
    background: var(--color-bg-dark-secondary) !important;
    border: 1px solid var(--glass-border) !important;
    border-radius: var(--radius-md) !important;
    box-shadow: var(--shadow-popup) !important;
    padding: 0.25rem !important;
}

.ant-select-item {
    color: var(--text-secondary) !important;
    border-radius: var(--radius-sm) !important;
    transition: all var(--transition-fast) !important;
}

.ant-select-item-option-active:not(.ant-select-item-option-disabled) {
    background: var(--glass-bg-light) !important;
}

.ant-select-item-option-selected:not(.ant-select-item-option-disabled) {
    background: rgba(var(--color-primary-rgb), 0.15) !important;
    color: var(--color-primary-fg) !important;
    font-weight: 500;
}

.ant-select-item-option-selected:not(.ant-select-item-option-disabled) .ant-select-item-option-state {
    color: var(--color-primary-fg) !important;
}

/* ========================================
   Main Layout Global Overrides
   ======================================== */

/* Language Picker in Main Header */
.main-layout .main-header .ant-select-selector {
    background: var(--glass-bg-light) !important;
    border: 1px solid var(--glass-border) !important;
    border-radius: var(--radius-sm) !important;
    color: var(--text-secondary) !important;
    height: 36px !important;
}

.main-layout .main-header .ant-select-arrow {
    color: var(--text-muted) !important;
}

.main-layout .main-header .ant-select:hover .ant-select-selector {
    border-color: var(--glass-border-light) !important;
}

.main-layout .main-header .ant-select-focused .ant-select-selector {
    border-color: var(--color-primary) !important;
    box-shadow: 0 0 0 2px var(--color-focus-ring) !important;
}

.main-layout .main-header .ant-select-selection-item {
    color: var(--text-secondary) !important;
}

/* Select clear button - remove white background, show only X */
.ant-select-clear {
    background: transparent !important;
    background-color: transparent !important;
    color: var(--text-muted) !important;
}

.ant-select-clear:hover {
    color: var(--text-secondary) !important;
}

/* Hide clear icon when no value is selected */
.ant-select:not(:has(.ant-select-selection-item)) .ant-select-clear {
    display: none !important;
}

/* Hide arrow when a value is selected (selection-item exists) */
.ant-select:has(.ant-select-selection-item) .ant-select-arrow {
    display: none !important;
}

/* Search input group - seamless connection between input and button */
.ant-input-group-wrapper.ant-input-search {
    display: inline-table !important;
    width: auto !important;
}

.ant-input-search .ant-input-wrapper.ant-input-group {
    display: table !important;
    width: auto !important;
}

.ant-input-search .ant-input {
    display: table-cell !important;
    border-top-right-radius: 0 !important;
    border-bottom-right-radius: 0 !important;
    border-right: none !important;
}

.ant-input-search .ant-input-group-addon {
    display: table-cell !important;
    background: transparent !important;
    padding: 0 !important;
    border: none !important;
    width: 1px !important;
    vertical-align: middle !important;
}

.ant-input-search .ant-input-group-addon .ant-btn,
.ant-input-search .ant-input-search-button,
.ant-input-search .ant-btn.ant-btn-icon-only,
.ant-input-search .ant-input-group-addon .ant-btn.ant-btn-icon-only.ant-input-search-button {
    background: var(--glass-bg) !important;
    border: 1px solid var(--glass-border-light) !important;
    border-left: none !important;
    color: var(--text-primary) !important;
    border-radius: 0 var(--radius-md) var(--radius-md) 0 !important;
    margin-left: 0 !important;
    height: var(--control-h) !important;
}

.ant-input-search .ant-input-group-addon .ant-btn:hover,
.ant-input-search .ant-input-search-button:hover,
.ant-input-search .ant-btn.ant-btn-icon-only:hover {
    background: var(--glass-bg-light) !important;
    border-color: var(--color-primary) !important;
    border-left: none !important;
    color: var(--color-primary-fg) !important;
}

/* Spin/Loading in dark theme */
.main-layout .ant-spin-dot-item {
    background-color: var(--text-muted) !important;
}

/* Message/Notification overrides */
.ant-message-notice-content {
    background: var(--color-bg-dark-secondary) !important;
    border: 1px solid var(--glass-border) !important;
    border-radius: var(--radius-md) !important;
    box-shadow: var(--shadow-popup) !important;
}

.ant-message-success .anticon {
    color: var(--color-success) !important;
}

.ant-message-error .anticon {
    color: var(--color-error) !important;
}

.ant-message-info .anticon {
    color: var(--color-info) !important;
}

.ant-message-notice-content .ant-message-custom-content span:last-child {
    color: var(--text-primary) !important;
}

/* ========================================
   Global Button Styles - Rounded Action Buttons
   ======================================== */

/* Base button - rounded corners for all buttons */
.ant-btn {
    border-radius: var(--radius-md) !important;
    font-weight: 500;
    transition: all var(--transition-fast) !important;
}

/* Primary button - F .btn--primary (I-021 AD5): solid --color-primary, ink text, no gradient, no glow */
.ant-btn-primary {
    background: var(--color-primary) !important;
    border: none !important;
    box-shadow: none !important;
    color: var(--text-on-primary) !important;
}

/* B-028 (1330, 1349): the hover/focus/active guard excludes :disabled, [disabled] and .ant-btn-disabled inside
   :where() (zero specificity), so a class- or attribute-disabled primary (an <a>, a button in a disabled
   fieldset) never lights up and the disabled rule below owns its look. Hover = F --primary-hover, flat. */
.ant-btn-primary:hover:where(:not(:disabled):not([disabled]):not(.ant-btn-disabled)),
.ant-btn-primary:focus-visible:where(:not(:disabled):not([disabled]):not(.ant-btn-disabled)) {
    background: var(--color-primary-hover) !important;
    box-shadow: none !important;
}

.ant-btn-primary:active:where(:not(:disabled):not([disabled]):not(.ant-btn-disabled)) {
    background: var(--color-primary) !important;
    box-shadow: none !important;
}

/* B-051 AD4 (b): keyboard focus adds the brand focus ring (.impeccable.md). Same (0,2,0) as the hover/active rules,
   placed after both so a keyboard press keeps the ring. overrides.css repeats it for its own (0,3,0) primary copies,
   which decide the look. */
.ant-btn-primary:focus-visible:where(:not(:disabled):not([disabled]):not(.ant-btn-disabled)) {
    box-shadow: 0 0 0 2px var(--color-focus-ring) !important;
}

/* B-028 (1330): lists :disabled too and resets the lift */
.ant-btn-primary[disabled],
.ant-btn-primary:disabled,
.ant-btn-primary.ant-btn-disabled {
    background: rgba(var(--color-primary-rgb), 0.4) !important;
    box-shadow: none !important;
    color: var(--text-muted) !important;
    cursor: not-allowed;
    transform: none !important;
}

/* Default button - glass morphism style */
/* B-047 (fork B-001): a static-SSR page hand-writes <a class="ant-btn"> (no circuit, so no <Button> to emit
   ant-btn-default); a variant-less anchor gets the same glass recipe. Anchors carrying a variant class keep their
   own blocks (ant-btn-dashed stays excluded: it has its own look). The anchor test sits inside :where() so the
   BASE rule weigh exactly what .ant-btn-default weighs (0,1,0), so it wins or loses against other rules
   (overrides.css, contextual .x .ant-btn) the way the <button> does. The hover/focus-visible rules do NOT match:
   the anchor form is (0,2,0) (.ant-btn + pseudo-class; both :where() add nothing) against (0,3,0) for
   .ant-btn-default:hover:not(:disabled) - an anchor loses a tie-break that the <button> would win. */
.ant-btn-default,
.ant-btn:where(a:not(.ant-btn-primary):not(.ant-btn-dangerous):not(.ant-btn-text):not(.ant-btn-link):not(.ant-btn-dashed)) {
    background: var(--glass-bg) !important;
    border: 1px solid var(--glass-border-light) !important;
    color: var(--text-primary) !important;
}

/* B-008 (2608): :focus-visible, not :focus - a mouse click leaves no stuck highlight */
.ant-btn-default:hover:not(:disabled),
.ant-btn-default:focus-visible:not(:disabled),
.ant-btn:where(a:not(.ant-btn-primary):not(.ant-btn-dangerous):not(.ant-btn-text):not(.ant-btn-link):not(.ant-btn-dashed)):hover:where(:not(:disabled):not([disabled]):not(.ant-btn-disabled)),
.ant-btn:where(a:not(.ant-btn-primary):not(.ant-btn-dangerous):not(.ant-btn-text):not(.ant-btn-link):not(.ant-btn-dashed)):focus-visible:where(:not(:disabled):not([disabled]):not(.ant-btn-disabled)) {
    background: var(--glass-bg-hover) !important;
    border-color: var(--color-primary) !important;
    color: var(--color-primary-fg) !important;
}

.ant-btn-default[disabled],
.ant-btn-default.ant-btn-disabled,
.ant-btn:where(a:not(.ant-btn-primary):not(.ant-btn-dangerous):not(.ant-btn-text):not(.ant-btn-link):not(.ant-btn-dashed))[disabled],
.ant-btn:where(a:not(.ant-btn-primary):not(.ant-btn-dangerous):not(.ant-btn-text):not(.ant-btn-link):not(.ant-btn-dashed)).ant-btn-disabled {
    background: var(--glass-bg) !important;
    border-color: var(--glass-border-light) !important;
    color: var(--text-primary) !important;
    cursor: not-allowed;
    /* F .btn[disabled] (I-033 TASK_01): the rest look at half opacity — set here too, so a class-disabled anchor
       (no :disabled) dims like the button */
    opacity: 0.5;
}

/* Danger button - red styling */
.ant-btn-dangerous:not(.ant-btn-primary) {
    background: var(--glass-bg) !important;
    border: 1px solid color-mix(in srgb, var(--color-error) 50%, transparent) !important;
    color: var(--color-error) !important;
}

.ant-btn-dangerous:not(.ant-btn-primary):hover:not(:disabled),
.ant-btn-dangerous:not(.ant-btn-primary):focus-visible:not(:disabled) {
    background: rgba(var(--color-error-rgb), 0.25) !important;
    border-color: rgba(var(--color-error-rgb), 0.5) !important;
    color: var(--color-error-light) !important;
}

/* Primary danger button — F .btn--danger-solid, defined once in overrides.css "Danger Button Overrides" (I-030 D-k):
   its .ant-btn.ant-btn-primary rules load after this file, so a copy here would never win. */

/* Text button */
.ant-btn-text {
    background: transparent !important;
    border: none !important;
    color: var(--text-secondary) !important;
}

.ant-btn-text:hover:not(:disabled),
.ant-btn-text:focus-visible:not(:disabled) {
    background: var(--color-panel-3) !important;
    color: var(--text-primary) !important;
}

/* Link button */
.ant-btn-link {
    background: transparent !important;
    border: none !important;
    color: var(--color-primary-fg) !important;
    box-shadow: none !important;
}

.ant-btn-link:hover:not(:disabled),
.ant-btn-link:focus-visible:not(:disabled) {
    color: var(--color-link-hover) !important;
}

.ant-btn-link.ant-btn-dangerous {
    color: var(--color-error-light) !important;
}

.ant-btn-link.ant-btn-dangerous:hover:not(:disabled) {
    color: var(--color-error) !important;
}

/* B-051 AD4 (b): keyboard focus draws the brand focus ring (.impeccable.md) on every non-primary type, on top of the
   border/text highlight above. One rule decides the ring; each selector repeats its type's :focus-visible weight -
   Default (0,3,0), anchor form (0,2,0), Danger (0,4,0), Text and Link (0,3,0), Dashed (0,3,0, its highlight lives in
   overrides.css) - so it beats the rest rules' box-shadow (Link's `none`, (0,1,0)). Hover alone draws no ring. */
.ant-btn-default:focus-visible:not(:disabled),
.ant-btn:where(a:not(.ant-btn-primary):not(.ant-btn-dangerous):not(.ant-btn-text):not(.ant-btn-link):not(.ant-btn-dashed)):focus-visible:where(:not(:disabled):not([disabled]):not(.ant-btn-disabled)),
.ant-btn.ant-btn-dashed:focus-visible:where(:not(:disabled):not([disabled]):not(.ant-btn-disabled)),
.ant-btn-dangerous:not(.ant-btn-primary):focus-visible:not(:disabled),
.ant-btn-text:focus-visible:not(:disabled),
.ant-btn-link:focus-visible:not(:disabled) {
    box-shadow: 0 0 0 2px var(--color-focus-ring) !important;
}

/* Loading state */
.ant-btn-loading {
    opacity: 0.85;
}

/* Small button size */
.ant-btn-sm {
    border-radius: var(--radius-md) !important;
}

/* Large button size */
.ant-btn-lg {
    border-radius: var(--radius-md) !important;
}

/* Block button */
.ant-btn-block {
    border-radius: var(--radius-md) !important;
}

/* Button with icon spacing */
.ant-btn > .anticon + span,
.ant-btn > span + .anticon {
    margin-left: 6px;
}

/* Icon-only button */
.ant-btn-icon-only {
    border-radius: var(--radius-md) !important;
}

/* Button group */
.ant-btn-group .ant-btn:first-child:not(:last-child) {
    border-top-right-radius: 0 !important;
    border-bottom-right-radius: 0 !important;
}

.ant-btn-group .ant-btn:last-child:not(:first-child) {
    border-top-left-radius: 0 !important;
    border-bottom-left-radius: 0 !important;
}

.ant-btn-group .ant-btn:not(:first-child):not(:last-child) {
    border-radius: 0 !important;
}

/* ========================================
   Modal Button Overrides
   ======================================== */

.ant-modal-footer .ant-btn {
    border-radius: var(--radius-md) !important;
}

.ant-modal-confirm-btns .ant-btn {
    border-radius: var(--radius-md) !important;
}

/* ========================================
   Sidebar Menu Collapsed State
   ======================================== */

.ant-menu-inline-collapsed .ant-menu-item {
    padding: 0 !important;
    text-align: center !important;
}

.ant-menu-inline-collapsed .ant-menu-item .ant-menu-title-content {
    display: flex !important;
    justify-content: center !important;
    align-items: center !important;
    width: 100% !important;
    height: 100% !important;
}

.ant-menu-inline-collapsed .ant-menu-item .ant-menu-title-content a {
    display: flex !important;
    justify-content: center !important;
    align-items: center !important;
}

/* Hide text labels when sidebar is collapsed */
.ant-menu-inline-collapsed .ant-menu-item .ant-menu-title-content a span:not(.anticon) {
    display: none !important;
}

/* ========================================
   Search Input Button Override
   Override primary button styles for search inputs
   Make it a standalone rounded button like Create Ticket
   ======================================== */

.ant-input-search .ant-input-group-addon .ant-btn,
.ant-input-search .ant-input-search-button,
.ant-input-search .ant-btn-primary.ant-input-search-button,
.ant-input-group-addon .ant-btn.ant-input-search-button {
    background: var(--glass-bg) !important;
    border: 1px solid var(--glass-border-light) !important;
    box-shadow: none !important;
    color: var(--text-primary) !important;
    border-radius: var(--radius-md) !important;
    margin-left: 8px !important;
}

.ant-input-search .ant-input-group-addon .ant-btn:hover,
.ant-input-search .ant-input-search-button:hover,
.ant-input-search .ant-btn-primary.ant-input-search-button:hover,
.ant-input-group-addon .ant-btn.ant-input-search-button:hover {
    background: var(--glass-bg-hover) !important;
    border-color: var(--color-primary) !important;
    color: var(--color-primary-fg) !important;
    transform: none !important;
}

.ant-input-search .ant-input-group-addon {
    background: transparent !important;
    border: none !important;
    padding: 0 !important;
}

/* Make the search input have rounded corners on all sides */
.ant-input-search .ant-input {
    border-radius: var(--radius-md) !important;
}

/* ========================================
   TextArea Global Styling
   ======================================== */

.ant-input-textarea textarea,
textarea.ant-input {
    background: var(--glass-bg) !important;
    border: 1px solid var(--glass-border-light) !important;
    border-radius: var(--radius-md) !important;
    color: var(--text-primary) !important;
}

.ant-input-textarea textarea:focus,
.ant-input-textarea textarea:hover,
textarea.ant-input:focus,
textarea.ant-input:hover {
    border-color: var(--color-primary) !important;
    box-shadow: 0 0 0 2px var(--color-primary-glow) !important;
}

.ant-input-textarea textarea::placeholder {
    color: var(--text-muted) !important;
}

.ant-input-textarea-show-count {
    background: transparent !important;
}

.ant-input-data-count {
    color: var(--text-muted) !important;
}

/* Textareas on the theme's input surface - specific AntDesign selector. color-scheme is inherited from :root, so the
   native scrollbar and resize grip follow the theme (I-023 TASK_04). */
.ant-input-textarea .ant-input-affix-wrapper textarea.ant-input,
.ant-input-textarea textarea.ant-input,
.ant-input-textarea-show-count .ant-input-affix-wrapper textarea.ant-input,
.ant-input-textarea-in-form-item textarea.ant-input,
textarea.ant-input {
    background: var(--glass-bg) !important;
    background-color: var(--glass-bg) !important;
    border: 1px solid var(--glass-border-light) !important;
    border-radius: var(--radius-md) !important;
    color: var(--text-primary) !important;
}

.ant-input-textarea .ant-input-affix-wrapper,
.ant-input-textarea-show-count .ant-input-affix-wrapper {
    background: transparent !important;
    border: none !important;
}

/* Remove border from textarea wrapper when show-count is enabled */
.ant-input-textarea.ant-input-textarea-show-count,
.ant-input-textarea.ant-input-textarea-in-form-item,
div.ant-input-textarea.ant-input-textarea-show-count.ant-input-textarea-in-form-item {
    border: none !important;
    border-width: 0 !important;
    border-style: none !important;
}

.ant-input-textarea .ant-input-affix-wrapper textarea.ant-input:focus,
.ant-input-textarea textarea.ant-input:focus,
textarea.ant-input:focus {
    border-color: var(--color-primary) !important;
    box-shadow: 0 0 0 2px var(--color-focus-ring) !important;
    outline: none !important;
    background: var(--glass-bg) !important;
}

textarea.ant-input::placeholder {
    color: var(--text-muted) !important;
}

/* ========================================
   Global Form Input Styling
   Glass-morphism for all AntDesign inputs
   ======================================== */

/* Standard inputs */
.ant-input {
    background: var(--glass-bg) !important;
    border: 1px solid var(--glass-border-light) !important;
    border-radius: var(--radius-md) !important;
    color: var(--text-primary) !important;
    transition: all var(--transition-base) !important;
}

.ant-input::placeholder {
    color: var(--text-muted) !important;
}

.ant-input:hover {
    border-color: var(--text-muted) !important;
}

.ant-input:focus,
.ant-input-focused {
    border-color: var(--color-primary) !important;
    box-shadow: 0 0 0 2px var(--color-primary-glow) !important;
}

/* Input sizes — respect AntDesign defaults, no forced heights */

/* Input number */
.ant-input-number-lg {
    background: var(--glass-bg) !important;
    border: 1px solid var(--glass-border-light) !important;
    border-radius: var(--radius-md) !important;
    color: var(--text-primary) !important;
}

.ant-input-number-lg:hover {
    border-color: var(--glass-border-light) !important;
}

.ant-input-number-lg:focus,
.ant-input-number-lg-focused {
    border-color: var(--color-primary) !important;
    box-shadow: 0 0 0 2px var(--color-focus-ring) !important;
}

/* Password input — wrapper (.ant-input-affix-wrapper) */
.ant-input-affix-wrapper.ant-input-password {
    background: var(--glass-bg) !important;
    border: 1px solid var(--glass-border-light) !important;
    border-radius: var(--radius-md) !important;
}

.ant-input-affix-wrapper.ant-input-password:hover,
.ant-input-affix-wrapper.ant-input-password:focus-within {
    border-color: var(--color-primary) !important;
    box-shadow: 0 0 0 2px var(--color-focus-ring) !important;
}

.ant-input-affix-wrapper.ant-input-password .ant-input {
    background: transparent !important;
    border: none !important;
    color: var(--text-primary) !important;
}

.ant-input-affix-wrapper.ant-input-password .ant-input::placeholder {
    color: var(--text-muted) !important;
}

.ant-input-affix-wrapper.ant-input-password .ant-input-suffix .anticon {
    color: var(--text-muted) !important;
}

/* Password large size — respect AntDesign defaults */

/* Select */
.ant-select-selector {
    background: var(--glass-bg) !important;
    border: 1px solid var(--glass-border-light) !important;
    border-radius: var(--radius-md) !important;
    color: var(--text-primary) !important;
}

.ant-select-arrow {
    color: var(--text-muted) !important;
}

.ant-select:hover .ant-select-selector {
    border-color: var(--glass-border-light) !important;
}

.ant-select-focused .ant-select-selector {
    border-color: var(--color-primary) !important;
    box-shadow: 0 0 0 2px var(--color-focus-ring) !important;
}

.ant-select-selection-item {
    color: var(--text-primary) !important;
}

.ant-select-selection-placeholder {
    color: var(--text-muted) !important;
}

.ant-select-selection-search-input {
    color: var(--text-primary) !important;
}

/* Select large size — respect AntDesign defaults */

/* Date picker */
.ant-picker {
    background: var(--glass-bg) !important;
    border: 1px solid var(--glass-border-light) !important;
    border-radius: var(--radius-md) !important;
    color: var(--text-primary) !important;
    transition: all var(--transition-base) !important;
}

.ant-picker:hover {
    border-color: var(--glass-border-light) !important;
}

/* AntD Blazor drops .ant-picker-focused when focus moves to a RangePicker's end input, so :focus-within keeps the ring
   (I-023 TASK_04 keyboard walk). */
.ant-picker-focused,
.ant-picker:focus-within {
    border-color: var(--color-primary) !important;
    box-shadow: 0 0 0 2px var(--color-focus-ring) !important;
}

/* DatePicker large size — respect AntDesign defaults */

.ant-picker-input > input {
    color: var(--text-primary) !important;
}

.ant-picker-input > input::placeholder {
    color: var(--text-muted) !important;
}

.ant-picker-suffix {
    color: var(--text-muted) !important;
}

/* ========================================
   Native File Input Override — .upload-dropzone and .file-input only (B-009)
   The invisible full-size overlay is the click target of a positioned upload
   wrapper: .upload-dropzone, or the Support pages' .upload-area(-small). Their
   <InputFile class="file-input"> is a child component, so a page's scoped
   .file-input rule never reaches it — this global rule is the only one (the
   scoped copies in the Support pages were removed).
   ======================================== */

.upload-dropzone input[type="file"],
input[type="file"].file-input {
    position: absolute !important;
    inset: 0 !important;
    width: 100% !important;
    height: 100% !important;
    opacity: 0 !important;
    cursor: pointer !important;
    z-index: 100 !important;
    font-size: 0 !important;
}

/* Hide native button text completely */
.upload-dropzone input[type="file"]::-webkit-file-upload-button,
input[type="file"].file-input::-webkit-file-upload-button {
    visibility: hidden !important;
    width: 0 !important;
    height: 0 !important;
}

.upload-dropzone input[type="file"]::file-selector-button,
input[type="file"].file-input::file-selector-button {
    visibility: hidden !important;
    width: 0 !important;
    height: 0 !important;
}

/* ========================================
   Page Layout Utility Classes
   Standardized page widths and layouts
   ======================================== */

/* Page Width Variables */
:root {
    --page-width-narrow: 800px;
    --page-width-default: 1000px;
    --page-width-wide: 1200px;
    --page-width-portal: 960px;

    /* The shadow scale (--shadow-sm … --shadow-inset-subtle) is theme-dependent and lives in the dark and light
       blocks at the top of this file (I-021 AD3). */

    /* Form-drawer widths — consumed by EntityFormDrawer (TASK_06); 600px is F .nd (I-030 D-i, OverlaySizes.Drawer). */
    --form-drawer-width: 600px;
    --form-drawer-width-wide: 640px;
}

/* Page Wrapper - Base page styling */
.page-wrapper {
    min-height: calc(100vh - 64px - 56px); /* viewport - header - footer */
    padding: var(--space-xl);
    background: transparent;
    /* F-176: promoted from per-page scoped CSS. Every .page-wrapper now animates
       in once globally; design-lint Rule 4 is satisfied by this single declaration
       so individual .razor.css files no longer need to repeat it. */
    animation: pageSlideUp 0.4s ease-out;
}

/* Page Container - Default width */
.page-container {
    position: relative; /* For DevPathBadge positioning */
    max-width: var(--page-width-default);
    margin: 0 auto;
    width: 100%;
}

/* Page Container Variants */
.page-container--narrow {
    max-width: var(--page-width-narrow);
}

.page-container--wide {
    max-width: var(--page-width-wide);
}

.page-container--portal {
    max-width: var(--page-width-portal);
}

.page-container--full {
    max-width: 100%;
}

/* Vertical rhythm — uniform gap between top-level page-container children.
   The `:not(style):not(.dev-path-badge)` exclusions are critical: scoped-style
   components inject a <style> sibling that would otherwise trip the owl, and
   the absolutely-positioned DevPathBadge would distort the owl chain. */
.page-container > :not(style):not(.dev-path-badge) + :not(style):not(.dev-path-badge) {
    margin-top: var(--space-lg);
}

/* Page Header - F flat panel (I-021 AD2/AD5: class kept, opaque --glass-bg, 1px line, --radius-lg) */
.page-header {
    background: var(--glass-bg);
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-lg);
    padding: var(--space-xl);
    margin-bottom: var(--space-lg);
    animation: pageSlideUp 0.4s ease-out;
}

/* Page Header - Simple style (no card) */
.page-header--simple {
    background: transparent;
    border: none;
    border-radius: 0;
    padding: 0;
    margin-bottom: var(--space-xl);
    animation: pageFadeIn 0.5s ease-out;
}

/* Page Title */
.page-title {
    font-size: var(--type-title);
    font-weight: var(--type-title-weight);
    line-height: 1.15;
    color: var(--text-primary);
    letter-spacing: var(--type-title-tracking);
    margin: 0 0 var(--space-sm) 0;
    overflow-wrap: anywhere; /* B-009: one long word cannot force header overflow at 390-480px */
}

/* Count inside a page title (B-051 AD3) — muted body text, read as part of the heading:
   <h1 class="page-title" aria-label="Title">Title <span class="page-title__count">128</span></h1>
   (aria-label keeps the heading's accessible name the bare title) */
.page-title__count {
    font-family: var(--font-mono);
    font-size: 0.875rem;
    font-weight: 500;
    color: var(--text-muted);
    margin-left: var(--space-sm);
    font-variant-numeric: tabular-nums;
    vertical-align: middle;
}

/* F .ph__title under a 600px page container: 22px (f.html `@container page (max-width: 600px)`), which F's reviewed 520
   width already reaches — the App kept 24px (the <= 576px 1.5rem rule below) there and 26px from 577 to 600px (I-038
   TASK_07, pageTitle / phTitle at 390). Scoped to the F page frame (.page-wrapper--f declares the `page` container), so
   it outranks the later 1.5rem rule; a title outside the frame keeps 1.5rem. */
@container page (max-width: 600px) {
    .page-wrapper--f .page-title {
        font-size: 22px;
    }
}

/* Page Subtitle */
.page-subtitle {
    font-size: 0.9375rem;
    color: var(--text-secondary);
    margin: 0;
}

/* Subsection titles + body copy — sit inside a .glass-card (settings, detail,
   drawers, audit-log details). F-176: promoted from playground scoped CSS. */
.section-title-sm {
    font-size: var(--type-panel-title);
    font-weight: var(--type-panel-title-weight);
    color: var(--text-primary);
    margin: 0 0 var(--space-xs);
}

.section-title-xs {
    font-family: var(--font-mono);
    font-size: var(--type-label);
    font-weight: var(--type-label-weight);
    letter-spacing: var(--type-label-tracking);
    text-transform: uppercase;
    color: var(--text-secondary);
    margin: var(--space-md) 0 var(--space-xs);
}

.section-copy {
    color: var(--text-muted);
    font-size: 0.9375rem;
    margin: 0 0 var(--space-md);
}

.section-copy code {
    font-family: var(--font-mono);
    font-size: 0.8125rem;
    color: var(--text-primary);
}

/* Page Header with Actions (flex layout) */
.page-header--with-actions {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: var(--space-lg);
    flex-wrap: wrap; /* B-028 (1357): the actions drop under the title before the title is squeezed */
}

/* B-028 (1357) + B-008 (2641): the title column is content-sized, so a short title keeps its actions on
   its row; when title + actions do not fit, the actions wrap onto their own line instead of the title
   breaking mid-word (a flex item never shrinks below its basis while it shares a line). A fixed 16rem
   basis (or a 16rem min-width, which clamps the same hypothetical size) pushed the actions down even
   for a short title. */
.page-header--with-actions .page-header__content {
    flex: 1 1 auto;
}

/* B-008 (2641): the subtitle adds no intrinsic width, so the title alone decides whether the actions fit
   beside it and a long subtitle wraps inside the title column instead of pushing the actions down.
   Above 768px only — in the mobile column the content is sized to its text, which this would collapse. */
@media (min-width: 768.02px) {
    .page-header--with-actions .page-header__content > .page-subtitle {
        contain: inline-size;
    }
}

/* B-028 (1357): wrapped actions stay right-aligned under the title */
.page-header--with-actions .page-header__actions {
    margin-left: auto;
}

/* B-009: standalone so it applies with or without --with-actions; without it a flex
   child's default min-width:auto lets a long title push past its container at 391-480px */
.page-header__content {
    min-width: 0;
}

/* Page Title Row (for inline help icon) */
.page-header__title-row {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    flex-wrap: wrap; /* B-009: title + help icon wraps instead of overflowing at 391-480px */
}

/* Form Item with Help (for inline help popovers) */
.form-item-with-help {
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
}

/* Form row — 2-column split that stacks at narrow widths.
   F-176: promoted from FormPlayground.razor.css `.form-playground__row`. */
.form-row--split {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-md);
}

@media (max-width: 576px) {
    .form-row--split {
        grid-template-columns: 1fr;
    }
}

/* --- Layout utilities (B-008 / I-006) --- */

/* Form grid — multi-column fields / document header. Auto-fit by default; --2/--3/--4 fix the count,
   --3/--4 drop to 2 columns at <=992px and every variant stacks at <=576px. */
.form-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(14rem, 100%), 1fr));
    gap: var(--space-md) var(--space-lg);
}

.form-grid > * {
    min-width: 0;
}

.form-grid--2 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
}

.form-grid--3 {
    grid-template-columns: repeat(3, minmax(0, 1fr));
}

.form-grid--4 {
    grid-template-columns: repeat(4, minmax(0, 1fr));
}

.form-grid__full {
    grid-column: 1 / -1;
}

@media (max-width: 992px) {
    .form-grid--3,
    .form-grid--4 {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

@media (max-width: 576px) {
    .form-grid,
    .form-grid--2,
    .form-grid--3,
    .form-grid--4 {
        grid-template-columns: 1fr;
    }
}

/* Form stack — vertical field rhythm; the gap spaces the fields. Two classes on the AntD reset,
   because app.css loads before the AntD sheet. */
.form-stack {
    display: flex;
    flex-direction: column;
    gap: var(--space-md);
}

.form-stack--tight {
    gap: var(--space-sm);
}

.form-stack > .ant-form-item.ant-form-item {
    margin-bottom: 0;
}

/* AntD offsets each item's 24px bottom margin with a -24px "margin-offset" sibling so help text can hang
   below the item. The stack zeroes that margin, so the offset must go too or the help text overlaps the
   next field's label. */
.form-stack > .ant-form-item .ant-form-item-margin-offset.ant-form-item-margin-offset {
    margin-bottom: 0;
}

/* Form section — a group inside ONE .glass-card, separated by a divider. Not a surface (B-008):
   no background, blur, radius or shadow — never a card in a card. */
.form-section {
    padding-top: var(--space-lg);
    border-top: 1px solid var(--glass-border);
}

.form-section:first-child {
    padding-top: 0;
    border-top: none;
}

/* Any sibling before a section (another section, a .form-grid document header) is spaced off its divider. */
* + .form-section {
    margin-top: var(--space-lg);
}

.form-section__title {
    margin: 0 0 var(--space-md);
    font-size: var(--type-panel-title);
    font-weight: var(--type-panel-title-weight);
    color: var(--text-primary);
}

.form-section__description {
    margin: calc(-1 * var(--space-sm)) 0 var(--space-md);
    color: var(--text-muted);
}

/* Full-width InputNumber — AntD sizes it to 90px. Two classes, because app.css loads before the AntD sheet.
   B-006: replaces the inline `Style="width: 100%"` in the drawer seed. */
.ant-input-number.input-number--block {
    width: 100%;
}

/* Page Animations */
@keyframes pageSlideUp {
    from {
        opacity: 0;
        transform: translateY(20px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

@keyframes pageFadeIn {
    from {
        opacity: 0;
    }
    to {
        opacity: 1;
    }
}

/* ========================================
   Glass Card Utility
   F's flat .panel (I-021 AD2/AD5): opaque --glass-bg, 1px --glass-border line, --radius-lg (14px), no blur, no
   shadow, no gradient. The class name is kept (catalogue required_classes, lint inputs, E2E hooks).
   Apply .glass-card to any container element.
   ======================================== */

.glass-card {
    background: var(--glass-bg);
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-lg);
    color: var(--text-primary);
    padding: var(--space-lg, 1.5rem);
}

.glass-card-hover {
    transition: all var(--transition-fast);
}

/* A flat panel does not lift (F .panel): hover only strengthens the line. */
.glass-card-hover:hover {
    border-color: var(--glass-border-light);
}

/* Glow — I-021 AD5. The one opt-in decoration on a flat surface: a faint orange radial glow behind a single hero
   element (the dashboard board, I-028). Built from --color-primary-rgb; not applied anywhere yet. */
.glow {
    position: relative;
    isolation: isolate;
}

.glow::before {
    content: '';
    position: absolute;
    inset: -20% -10% auto;
    height: 120%;
    background: radial-gradient(ellipse at 50% 0%, rgba(var(--color-primary-rgb), 0.15) 0%, transparent 60%);
    pointer-events: none;
    z-index: -1;
}

/* ========================================
   Page Layout Templates
   Composable layout primitives used by the
   Detail, Form, and Settings page templates.
   See `/design-system#detail-page-template`,
   `/design-system#form-page-template`,
   `/design-system#settings-page-template`.
   ======================================== */

/* Detail page — two-column grid (main + side panel) */
.detail-page-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 320px;
    gap: var(--space-lg);
    align-items: start;
}

/* B-007: __main stacks its cards with the same gap as __side (.glass-card has no margin). */
.detail-page-grid__main {
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-md);
}

/* B-007: one-column detail page — __main only, no side column. */
.detail-page-grid--single {
    grid-template-columns: minmax(0, 1fr);
}

.detail-page-grid__side {
    display: flex;
    flex-direction: column;
    gap: var(--space-md);
    position: sticky;
    top: var(--space-lg);
    align-self: start;
}

/* Sub-block title inside .detail-page-grid__side panels.
   F-176: promoted from DetailPlayground.razor.css `.detail-playground__side-title`. */
.detail-page-grid__side-title {
    margin: 0 0 var(--space-md) 0;
    font-size: var(--type-panel-title);
    font-weight: var(--type-panel-title-weight);
    color: var(--text-primary);
}

@media (max-width: 768px) {
    /* B-007: minmax(0, 1fr), not 1fr — wide content (tables, code) must not overflow the track. */
    .detail-page-grid {
        grid-template-columns: minmax(0, 1fr);
    }

    .detail-page-grid__side {
        position: static;
    }
}

/* Form page — actions footer (becomes sticky-bottom on mobile) */
.form-actions-footer {
    display: flex;
    justify-content: flex-end;
    gap: var(--space-sm);
    margin-top: var(--space-lg);
    padding-top: var(--space-md);
    border-top: 1px solid var(--glass-border);
}

@media (max-width: 480px) {
    .form-actions-footer {
        position: sticky;
        bottom: 0;
        left: 0;
        right: 0;
        flex-direction: column-reverse;
        background: var(--glass-bg);
        border-top: 1px solid var(--glass-border);
        margin-top: var(--space-md);
        padding: var(--space-md);
        z-index: 5;
    }

    .form-actions-footer .ant-btn {
        width: 100%;
    }
}

/* Settings section — vertical stack of labelled fields inside a settings tab.
   F-176: promoted from SettingsPlayground.razor.css; the existing chained
   selector below (`.settings-tabs-layout .settings-section + .settings-section`)
   previously assumed this block existed but never defined the base. */
.settings-section {
    display: flex;
    flex-direction: column;
    gap: var(--space-md);
}

/* A Segmented (e.g. the Appearance theme control) sizes to its items, as F's `.seg` does (align-self: flex-start),
   instead of stretching across the section's flex column. I-023 */
.settings-section > .ant-segmented {
    align-self: flex-start;
}

.settings-section__actions {
    display: flex;
    justify-content: flex-end;
    margin-top: var(--space-sm);
    gap: var(--space-sm); /* B-009: buttons touched with no gap */
}

/* `.settings-section-actions` (hyphenated) is the catalog-required, production class name
   (Settings, Subscription, showcase) — `.settings-section__actions` above is the BEM name the Dev
   Playground uses. Defined only here; no margin-top, since pages manage their own spacing above the row. */
.settings-section-actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: var(--space-sm);
}

/* B-008 (2618, 2640): opt-in modifier - the action row stacks its buttons full-width at <=480px (Settings,
   Subscription, the showcase seeds). Global because the buttons are AntD child components, which a page's
   scoped CSS cannot reach without a (lint-banned) ::deep .ant-btn. A direct child that wraps a button (the
   Cancel trigger's focus-return span) stacks too, together with the button inside it. */
@media (max-width: 480px) {
    .settings-section-actions--stack-mobile > .ant-btn,
    .settings-section-actions--stack-mobile > :has(> .ant-btn),
    .settings-section-actions--stack-mobile > :has(> .ant-btn) > .ant-btn {
        width: 100%;
    }
}

/* B-008 (back-port pisarcheon I-006): intro row of a tab whose page owns the header. */
.tab-intro {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-md);
    flex-wrap: wrap;
    margin-bottom: var(--space-md);
}

.tab-intro__text {
    margin: 0;
    color: var(--text-muted);
}

/* B-008 (back-port pisarcheon B-027): a card title row (h3 + action) reuses .tab-intro; the row owns the bottom spacing. */
.tab-intro > .detail-page-grid__side-title {
    margin: 0;
}

/* Settings page — tabbed layout container */
.settings-tabs-layout {
    padding: var(--space-md) var(--space-lg);
}

.settings-tabs-layout .settings-section + .settings-section {
    margin-top: var(--space-lg);
}

/* ========================================
   Specialized Page Templates
   Dashboard, Pricing, Status Result,
   Notification Feed, Wizard. Heavy Data
   reuses .glass-card + filter-card.
   See `/design-system#dashboard-template`
   ... `/design-system#wizard-template`.
   ======================================== */

/* --- Dashboard --- */

/* Stat card — global so every dashboard / overview / summary page can use it.
   Promoted from DesignSystem.razor.css (F-174). Composition:
   .stat-card[.stat-card--clickable] > .stat-icon.stat-icon--<variant> + .stat-value + .stat-label
   (.stat-trend.stat-trend--up|--down optional). */
.stat-card {
    background: var(--glass-bg);
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-lg);
    padding: var(--space-lg);
    text-align: center;
    transition: all var(--transition-base);
}

/* B-009: only a clickable card lifts. A static card lifting 2px under the pointer read as a layout
   jump on dashboards. The clickable card is a native <button class="stat-card--clickable">, so that
   class is the only hook. */
.stat-card:hover {
    border-color: var(--glass-border-light);
}

.stat-card--clickable {
    cursor: pointer;
}

.stat-card--clickable:hover {
    border-color: var(--color-primary);
    transform: translateY(-2px);
    box-shadow: var(--shadow-primary-md);
}

.stat-card--clickable:focus-visible {
    border-color: var(--color-primary);
    outline: 2px solid var(--color-focus-ring);
    outline-offset: 2px;
}

/* B-009 (TASK_08): a clickable card is a native <button> (PR review 1345 — Space must not scroll the
   page). Reset only the UA button defaults that would otherwise fight `.stat-card`'s own look; background,
   border, padding and border-radius are NOT reset here so `.stat-card` above keeps winning. */
button.stat-card--clickable {
    font: inherit;
    color: inherit;
    width: 100%;
    display: block;
    margin: 0;
    -webkit-appearance: none;
    appearance: none;
}

/* B-028: both StatCard branches render <span> parts (one shared body), so every card stacks them;
   compact cards keep the inline label/value of the calculator seed (B-008 2588). */
.stat-card:not(.stat-card--compact) > .stat-value,
.stat-card:not(.stat-card--compact) > .stat-label {
    display: block;
}

.stat-card--compact {
    text-align: left;
}

.stat-card--compact .stat-value {
    font-size: 1.5rem;
    /* Amounts and date ranges wrap inside a narrow grid column instead of overflowing it. */
    overflow-wrap: anywhere;
}

.stat-card--compact + .stat-card--compact {
    margin-top: var(--space-sm);
}

/* B-008 (back-port evidens): in a stat grid the gap spaces the cards; the stacked-card margin would stagger the row. */
.dashboard-stat-grid > .stat-card--compact + .stat-card--compact {
    margin-top: 0;
}

.stat-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    border-radius: var(--radius-md);
    margin-bottom: var(--space-sm);
    font-size: 20px;
}

.stat-icon--blue {
    background: rgba(var(--color-tier-starter-rgb), 0.12);
    color: var(--color-tier-starter);
}

.stat-icon--cyan {
    background: rgba(var(--color-accent-cyan-rgb), 0.12);
    color: var(--color-accent-cyan);
}

.stat-icon--green {
    background: rgba(var(--color-success-rgb), 0.12);
    color: var(--color-success);
}

.stat-icon--warning {
    background: rgba(var(--color-warning-rgb), 0.12);
    color: var(--color-warning);
}

.stat-icon--purple {
    background: rgba(var(--color-accent-purple-rgb), 0.12);
    color: var(--color-accent-purple-light);
}

.stat-icon--danger {
    background: rgba(var(--color-error-rgb), 0.12);
    color: var(--color-error);
}

.stat-icon--primary,
.stat-icon--orange {
    background: rgba(var(--color-primary-rgb), 0.12);
    color: var(--color-primary-text);
}

.stat-value {
    font-family: var(--font-mono);
    font-size: 2.25rem;
    font-weight: 700;
    color: var(--text-primary);
    line-height: 1;
    margin-bottom: 6px;
}

.stat-label {
    font-size: 0.8125rem;
    font-weight: 500;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.stat-trend {
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
    margin-top: var(--space-sm);
    font-size: 0.8125rem;
    font-weight: 600;
}

.stat-trend--up {
    color: var(--color-success);
}

.stat-trend--down {
    color: var(--color-error);
}

.dashboard-stat-grid {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: var(--space-md);
}

/* B-009: exactly 5 or 6 cards fill their rows instead of orphaning the 5th/6th.
   Wrapped in a range media query because :has() specificity (0,3,0) would beat the
   992px / 480px collapse rules below. B-008 (2607, 2647): `min-width: 992.02px` is the complement of
   `max-width: 992px` without Media Queries L4 range syntax, which Safari/iOS 15.4-16.3 drop. */
@media (min-width: 992.02px) {
    .dashboard-stat-grid:has(> :nth-child(5):last-child) { grid-template-columns: repeat(3, minmax(0, 1fr)); }
    .dashboard-stat-grid:has(> :nth-child(6):last-child) { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

@media (min-width: 1200px) {
    .dashboard-stat-grid:has(> :nth-child(5):last-child) { grid-template-columns: repeat(5, minmax(0, 1fr)); }
}

@media (max-width: 992px) {
    .dashboard-stat-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

@media (max-width: 480px) {
    .dashboard-stat-grid {
        grid-template-columns: 1fr;
    }
}

/* Dashboard glass-card section heading (Recent activity, Quick actions, etc.) */
.dashboard-card-title {
    margin: 0 0 var(--space-md) 0;
    font-size: var(--type-panel-title);
    font-weight: var(--type-panel-title-weight);
    color: var(--text-primary);
}

/* Empty-state copy inside an activity feed / timeline card */
.activity-feed-empty {
    padding: var(--space-lg);
    text-align: center;
    color: var(--text-muted);
}

/* Grid wrapper for dashboard quick-action buttons */
.quick-actions {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
    gap: var(--space-md);
}

/* --- Pricing billing toggle --- */
.pricing-billing-toggle {
    display: flex;
    gap: 4px;
    padding: 4px;
    background: var(--glass-bg);
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-md);
    width: fit-content;
    margin: 0 auto var(--space-xl);
}

.pricing-billing-toggle button {
    padding: 8px 16px;
    border: none;
    background: transparent;
    color: var(--text-secondary);
    border-radius: var(--radius-sm);
    cursor: pointer;
    transition: all var(--transition-base);
    font-size: 0.875rem;
    display: flex;
    align-items: center;
    gap: var(--space-xs);
}

.pricing-billing-toggle button.active {
    background: var(--gradient-primary);
    color: var(--text-on-primary);
    box-shadow: var(--shadow-primary-md);
}

/* --- Pricing tier cards --- */
.pricing-tier-row {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--space-lg);
    align-items: stretch;
}

.pricing-tier-card {
    background: var(--glass-bg);
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-lg);
    padding: var(--space-xl);
    display: flex;
    flex-direction: column;
    gap: var(--space-md);
    position: relative;
    transition: all var(--transition-base);
}

.pricing-tier-card:hover {
    border-color: var(--glass-border-light);
    transform: translateY(-2px);
}

.pricing-tier-card--featured {
    border-color: var(--color-primary);
    box-shadow: 0 0 0 1px var(--color-primary), 0 8px 32px rgba(var(--color-primary-rgb), 0.15);
}

.pricing-tier-badge {
    position: absolute;
    top: -12px;
    left: 50%;
    transform: translateX(-50%);
    background: var(--color-primary);
    color: var(--text-on-primary);
    padding: 4px 12px;
    border-radius: 999px;
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.04em;
}

.pricing-tier-name {
    font-family: var(--font-display);
    font-size: 1.125rem;
    font-weight: 600;
    color: var(--text-primary);
    margin: 0;
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

.pricing-tier-price {
    display: flex;
    align-items: baseline;
    gap: var(--space-xs);
}

.pricing-tier-price__amount {
    font-family: var(--font-display);
    font-size: 2.25rem;
    font-weight: 700;
    color: var(--text-primary);
    line-height: 1;
}

/* "Custom" / "Contact us" enterprise-tier amount — smaller because it's a word.
   F-176: promoted from PricingPlayground.razor.css. */
.pricing-tier-price__amount--custom {
    font-size: 1.75rem;
}

.pricing-tier-price__period {
    font-size: 0.875rem;
    color: var(--text-secondary);
}

/* Pricing page header — centered variant.
   F-176: promoted from PricingPlayground.razor.css. */
.pricing-header--centered {
    text-align: center;
}

.pricing-tier-features {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-xs);
    color: var(--text-secondary);
    font-size: 0.875rem;
    flex: 1;
}

.pricing-tier-features li {
    padding-left: 1.25rem;
    position: relative;
}

.pricing-tier-features li::before {
    content: '✓';
    position: absolute;
    left: 0;
    color: var(--color-primary-fg);
    font-weight: 700;
}

@media (max-width: 768px) {
    .pricing-tier-row {
        grid-template-columns: 1fr;
    }

    .pricing-tier-card {
        padding: var(--space-lg);
    }
}

/* --- FAQ section (commonly paired with pricing / marketing pages) ---
   F-176: promoted from PricingPlayground.razor.css. */
.faq-section__title {
    font-family: var(--font-display);
    font-size: 1.25rem;
    font-weight: 600;
    color: var(--text-primary);
    margin: 0 0 var(--space-lg) 0;
}

/* --- Subscription "current plan" card ---
   F-176: promoted from SubscriptionPlayground.razor.css. Pairs with the
   already-global .subscription-tag family in overrides.css:1015. */
.subscription-current-plan {
    display: flex;
    flex-direction: column;
    gap: var(--space-md);
}

.subscription-current-plan__header {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: var(--space-lg);
    flex-wrap: wrap;
}

.subscription-current-plan__title {
    font-family: var(--font-display);
    font-size: 1.125rem;
    font-weight: 600;
    color: var(--text-primary);
    margin: 0 0 var(--space-xs) 0;
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

.subscription-current-plan__meta {
    display: flex;
    align-items: center;
    gap: var(--space-md);
    flex-wrap: wrap;
    margin: var(--space-xs) 0 0 0;
}

.subscription-current-plan__renewal {
    color: var(--text-secondary);
    font-size: 0.875rem;
}

.subscription-current-plan__actions {
    display: flex;
    gap: var(--space-sm);
    flex-wrap: wrap;
}

.subscription-current-plan__hint {
    color: var(--text-muted);
    font-size: 0.8125rem;
    margin: var(--space-sm) 0 0 0;
}

@media (max-width: 768px) {
    .subscription-current-plan__actions {
        width: 100%;
    }
}

/* --- Status Result --- */
.status-result {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    padding: var(--space-2xl) var(--space-lg);
}

.status-result__icon {
    width: 96px;
    height: 96px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 56px;
    margin-bottom: var(--space-lg);
    animation: resultIconPop 0.5s cubic-bezier(0.34, 1.56, 0.64, 1) both;
}

.status-result--success .status-result__icon {
    background: rgba(var(--color-success-rgb), 0.12);
    color: var(--color-success);
    box-shadow: 0 0 0 8px rgba(var(--color-success-rgb), 0.04), 0 8px 32px rgba(var(--color-success-rgb), 0.18);
}

.status-result--warning .status-result__icon {
    background: rgba(var(--color-warning-rgb), 0.12);
    color: var(--color-warning);
    box-shadow: 0 0 0 8px rgba(var(--color-warning-rgb), 0.04), 0 8px 32px rgba(var(--color-warning-rgb), 0.18);
}

.status-result--error .status-result__icon {
    background: rgba(var(--color-error-rgb), 0.12);
    color: var(--color-error);
    box-shadow: 0 0 0 8px rgba(var(--color-error-rgb), 0.04), 0 8px 32px rgba(var(--color-error-rgb), 0.18);
}

.status-result--info .status-result__icon {
    background: rgba(var(--color-info-rgb), 0.12);
    color: var(--color-info);
    box-shadow: 0 0 0 8px rgba(var(--color-info-rgb), 0.04), 0 8px 32px rgba(var(--color-info-rgb), 0.18);
}

.status-result__title {
    font-family: var(--font-display);
    font-size: 1.5rem; /* F .face--page h1: 600 24px (I-033 TASK_07 fidelity) */
    font-weight: 600;
    color: var(--text-primary);
    margin: 0 0 var(--space-sm) 0;
    letter-spacing: -0.02em;
    animation: slideUp 0.4s ease-out 0.2s both;
}

.status-result__description {
    color: var(--text-secondary);
    font-size: 0.9375rem;
    margin: 0 0 var(--space-lg) 0;
    max-width: 480px;
    animation: slideUp 0.4s ease-out 0.3s both;
}

.status-result__actions {
    display: flex;
    gap: var(--space-sm);
    flex-wrap: wrap;
    justify-content: center;
    animation: slideUp 0.4s ease-out 0.35s both;
}

@keyframes resultIconPop {
    from {
        opacity: 0;
        transform: scale(0.5);
    }
    to {
        opacity: 1;
        transform: scale(1);
    }
}

@media (max-width: 768px) {
    .status-result__actions {
        flex-direction: column;
        width: 100%;
    }

    .status-result__actions .ant-btn {
        width: 100%;
    }
}

@media (max-width: 480px) {
    .status-result {
        padding: var(--space-xl) var(--space-md);
    }

    .status-result__icon {
        width: 64px;
        height: 64px;
        font-size: 36px;
    }

    .status-result__title {
        font-size: 1.5rem;
    }
}

/* --- Audit-log primitives — referenced by `audit-log-playground` catalog pattern --- */
.audit-log-feed {
    display: flex;
    flex-direction: column;
    gap: var(--space-xs);
}

.audit-log-row {
    display: grid;
    grid-template-columns: auto 1fr auto;
    align-items: center;
    gap: var(--space-sm);
    padding: var(--space-sm) var(--space-md);
    border-radius: var(--radius-md);
    background: var(--glass-bg);
    border: 1px solid var(--glass-border);
    cursor: pointer;
    transition: background 120ms ease, border-color 120ms ease;
}

.audit-log-row:hover {
    background: var(--glass-bg-light);
    border-color: var(--glass-border-light);
}

.audit-log-row[data-selected="true"] {
    border-color: var(--color-primary);
    background: var(--glass-bg-light);
}

.audit-log-row[data-fresh="true"] {
    border-left: 3px solid var(--color-primary);
}

.audit-log-row__action {
    font-size: 0.8125rem;
    font-weight: 500;
    text-transform: capitalize;
}

.audit-log-row__target {
    color: var(--text-primary);
    font-weight: 500;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.audit-log-row__actor {
    color: var(--text-muted);
    font-size: 0.8125rem;
}

.audit-log-row__time {
    color: var(--text-muted);
    font-size: 0.8125rem;
    font-family: var(--font-mono);
    flex-shrink: 0;
}

/* Small muted timestamp under a timeline event message — activity feeds, change
   history, audit detail panels. F-176: promoted from DetailPlayground.razor.css. */
.timeline-event__time {
    margin-top: var(--space-xs);
    font-size: 0.8125rem;
    color: var(--text-muted);
}

/* --- File upload primitives — referenced by `file-upload-playground` catalog pattern --- */
.upload-dropzone {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-md) var(--space-lg);
    border: 1px dashed var(--glass-border-light);
    border-radius: var(--radius-md);
    background: var(--glass-bg);
    transition: border-color 150ms ease, background 150ms ease;
    gap: var(--space-sm);
}

.upload-dropzone:hover,
.upload-dropzone:focus {
    border-color: var(--color-primary);
    background: var(--glass-bg-light);
    outline: none;
}

/* Drag-active state — apply via .upload-dropzone--dragging when @ondragenter fires.
   F-176: promoted from FileUploadPlayground.razor.css. */
.upload-dropzone--dragging {
    border-color: var(--color-primary);
    background: var(--glass-bg-light);
}

/* Tall column-oriented dropzone (multi-file / clipboard-paste variants). */
.upload-dropzone--column {
    min-height: 140px;
    flex-direction: column;
}

/* "Choose file" label rendered as a button (sits inside a .upload-dropzone with
   a sibling visually-hidden <input type="file">).
   F-176: promoted from FileUploadPlayground.razor.css. */
.upload-choose-label {
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
    cursor: pointer;
    color: var(--text-secondary);
    font-size: 0.9375rem;
}

.upload-choose-label--block {
    flex-direction: column;
    text-align: center;
    color: var(--text-muted);
}

.upload-choose-label:hover {
    color: var(--color-primary-fg);
}

/* Avatar-upload row: 80×80 circular preview + adjacent picker affordance.
   F-176: promoted from FileUploadPlayground.razor.css. */
.upload-avatar-row {
    display: flex;
    align-items: center;
    gap: var(--space-lg);
}

.upload-avatar-preview {
    width: 80px;
    height: 80px;
    border-radius: 50%;
    background: var(--glass-bg);
    border: 1px solid var(--glass-border);
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    flex-shrink: 0;
}

.upload-avatar-preview img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* 96px preview (I-047 property photo in property settings): its initials in the avatar's 600 mono, sized to the circle */
.upload-avatar-preview--96 {
    width: 96px;
    height: 96px;
    font: 600 1.75rem var(--font-mono);
}

/* The picker label and the actions beside a preview (Upload / Replace + Remove); the hidden input's keyboard focus shows
   on its label, and a busy label is inert */
.upload-avatar-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-sm) var(--space-md);
}

.visually-hidden:focus-visible + .upload-choose-label {
    outline: 2px solid var(--color-focus-ring);
    outline-offset: 2px;
    border-radius: var(--radius-sm);
}

.upload-choose-label[aria-disabled="true"] {
    cursor: default;
    pointer-events: none;
    color: var(--text-muted);
}

/* The picker label is the field's main action: a 44px touch target on a phone, like the buttons beside it */
@media (max-width: 480px) {
    .upload-avatar-actions .upload-choose-label {
        min-height: 44px;
    }
}

.upload-file-row {
    display: flex;
    align-items: flex-start;
    gap: var(--space-md);
    padding: var(--space-sm) var(--space-md);
    border-radius: var(--radius-md);
    background: var(--glass-bg);
    border: 1px solid var(--glass-border);
    margin-top: var(--space-sm);
}

.upload-file-row[data-state="error"] {
    border-color: var(--color-error);
}

.upload-file-row[data-state="done"] {
    border-color: var(--color-success);
}

.upload-file-row__icon {
    width: 36px;
    height: 36px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--glass-bg-light);
    border-radius: var(--radius-sm);
    color: var(--text-muted);
    flex-shrink: 0;
}

.upload-file-row__body {
    flex: 1 1 auto;
    min-width: 0;
}

.upload-file-row__name {
    color: var(--text-primary);
    font-weight: 500;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.upload-file-row__meta {
    font-family: var(--font-mono);
    color: var(--text-muted);
    font-size: 0.8125rem;
    margin-bottom: var(--space-xs);
}

.upload-file-row__actions {
    display: flex;
    gap: var(--space-xs);
    flex-shrink: 0;
}

/* --- Modal-body form field — referenced by `modal-page` catalog pattern --- */
.ds-tpl-form-field {
    display: flex;
    flex-direction: column;
    gap: var(--space-xs);
    margin-bottom: var(--space-md);
}

.ds-tpl-form-field:last-child {
    margin-bottom: 0;
}

/* --- Empty State --- */
.empty-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    padding: var(--space-2xl) var(--space-xl);
    gap: var(--space-md);
}

/* F .face__ic (I-037 D-p): a 44px rounded square — the --panel-2 ground, a 1px --line edge, a 22px muted glyph — in both
   variants and at every width (F draws no larger empty face outside the result pages) */
.empty-state__icon {
    flex: none;
    width: 44px;
    height: 44px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--glass-bg-light);
    border: 1px solid var(--glass-border);
    border-radius: 12px;
    font-size: 22px;
    line-height: 1;
    color: var(--text-muted);
}

/* F .face__ic--wait — the waiting face (the calendar's "Collecting rates…"): orange text on the primary tint and line */
.empty-state__icon--primary {
    color: var(--color-primary-text);
    border-color: var(--color-primary-line);
    background: var(--color-primary-bg);
}

/* F .face__ic--err — a failed load: the error glyph with an error-tinted edge */
.empty-state__icon--error {
    color: var(--color-error);
    border-color: color-mix(in srgb, var(--color-error) 35%, var(--glass-border));
}

.empty-state__title {
    font-family: var(--font-display);
    font-size: 1.5rem;
    font-weight: 600; /* F .face h3 / .face--page h1 (I-033 TASK_01) */
    color: var(--text-primary);
    margin: 0;
}

.empty-state__description {
    color: var(--text-secondary); /* F .face p (I-033 TASK_01) */
    max-width: 480px;
    margin: 0;
}

.empty-state__cta {
    display: flex;
    gap: var(--space-sm);
    flex-wrap: wrap;
    justify-content: center;
    margin-top: var(--space-sm);
}

/* Section variant — an empty state inside a card or panel on a page that already has its heading. Compact by default
   (drawers, modals, small cards); F's 44px 20px .face padding belongs to the page's own state faces and is set where
   they sit (PR 814 #13209): the list / feed / rules panels ("Lists and feeds"), .calpanel, .bill-tabs (its .face--sm)
   and the state card below */
.empty-state--section {
    padding: var(--space-xl) var(--space-lg);
    gap: var(--space-sm);
}

/* A page state card: a glass card (or Team's padded body) holding only the face — the dashboard / insights / competitors
   / events / team load faces (I-038 TASK_02 E03 E08 E09, TASK_03 E11 E14 E15, E19) and the not-found / forbidden cards
   (E26 E27) — and the page's own panel faces under a head: the Dashboard decision queue (E02), the Dashboard's Latest
   alerts / Biggest market moves faces (F .panel > .face; B-075 TASK_09 E02: measured once the first-run queue drew its
   collecting row) and an empty comp set (E10). Never in a drawer or a modal: the night drawer's error card stays
   compact. */
#main-content .glass-card > .empty-state--section:only-child:not(.ant-drawer *):not(.ant-modal *),
#main-content .glass-card > .team-pad > .empty-state--section:only-child:not(.ant-drawer *):not(.ant-modal *),
#main-content .glass-card.dqueue > .empty-state--section:not(.ant-drawer *):not(.ant-modal *),
#main-content .dash-duo > .glass-card.dash-panel > .empty-state--section:not(.ant-drawer *):not(.ant-modal *),
#main-content .glass-card.cset > .empty-state--section:not(.ant-drawer *):not(.ant-modal *) {
    padding: 44px 20px;
}

.empty-state--section .empty-state__title {
    font-size: 1rem; /* F .face h3 16px (I-033 TASK_01) */
}

@media (max-width: 768px) {
    .empty-state__cta {
        flex-direction: column;
        width: 100%;
    }
}

@media (max-width: 480px) {
    .empty-state {
        padding: var(--space-xl) var(--space-md);
    }

    .empty-state__title {
        font-size: 1.25rem;
    }
}

/* --- Notification Feed --- */
.notification-feed {
    display: flex;
    flex-direction: column;
    gap: var(--space-sm);
}

.notification-card {
    display: flex;
    align-items: flex-start;
    gap: var(--space-md);
    background: var(--glass-bg);
    border: 1px solid var(--glass-border);
    border-left: 3px solid transparent;
    border-radius: var(--radius-md);
    padding: var(--space-md) var(--space-lg);
    transition: all var(--transition-fast);
}

.notification-card:hover {
    border-color: var(--glass-border-light);
}

/* Unread is information, not "mine": the neutral badge tone (F --badge-bg, I-021 AD6) */
.notification-card--unread {
    background: var(--glass-bg-light);
    border-left-color: var(--color-badge-bg);
}

.notification-card__icon {
    flex-shrink: 0;
    width: 40px;
    height: 40px;
    border-radius: var(--radius-md);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 18px;
}

.notification-card__icon--info {
    background: var(--color-info-bg);
    color: var(--color-info);
}

.notification-card__icon--success {
    background: rgba(var(--color-success-rgb), 0.12);
    color: var(--color-success);
}

.notification-card__icon--warning {
    background: rgba(var(--color-warning-rgb), 0.12);
    color: var(--color-warning);
}

.notification-card__icon--error {
    background: rgba(var(--color-error-rgb), 0.12);
    color: var(--color-error);
}

.notification-card__body {
    flex: 1;
    min-width: 0;
}

.notification-card__title {
    font-family: var(--font-display);
    font-size: 0.9375rem;
    font-weight: 600;
    color: var(--text-primary);
    margin: 0 0 4px 0;
}

.notification-card__text {
    color: var(--text-secondary);
    font-size: 0.875rem;
    margin: 0 0 4px 0;
}

.notification-card__time {
    font-size: 0.75rem;
    color: var(--text-muted);
}

@media (max-width: 480px) {
    .notification-card {
        padding: var(--space-md);
    }
}

/* --- Wizard Progress Rail --- */
.wizard-progress {
    display: flex;
    align-items: center;
    gap: 0;
    padding: var(--space-lg) 0;
    margin-bottom: var(--space-md);
}

.wizard-progress__step {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-xs);
    flex-shrink: 0;
}

.wizard-progress__bullet {
    width: 36px;
    height: 36px;
    border-radius: 50%;
    background: var(--glass-bg);
    border: 2px solid var(--glass-border);
    color: var(--text-secondary);
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 0.9375rem;
    transition: all var(--transition-base);
}

.wizard-progress__step--current .wizard-progress__bullet {
    border-color: var(--color-primary);
    color: var(--color-primary-fg);
    background: rgba(var(--color-primary-rgb), 0.12);
    box-shadow: 0 0 0 4px rgba(var(--color-primary-rgb), 0.12);
}

.wizard-progress__step--complete .wizard-progress__bullet {
    background: var(--color-primary);
    border-color: var(--color-primary);
    color: var(--text-on-primary);
}

.wizard-progress__label {
    font-size: 0.8125rem;
    color: var(--text-secondary);
    font-weight: 500;
    white-space: nowrap;
}

.wizard-progress__step--current .wizard-progress__label {
    color: var(--color-primary-fg);
    font-weight: 600;
}

.wizard-progress__rail {
    flex: 1;
    height: 2px;
    background: var(--glass-border);
    margin: 0 var(--space-sm);
    margin-bottom: 1.5rem; /* align with bullet center */
}

.wizard-progress__rail--complete {
    background: var(--color-primary);
}

.wizard-actions {
    display: flex;
    justify-content: space-between;
    margin-top: var(--space-lg);
}

@media (max-width: 480px) {
    .wizard-progress {
        padding: var(--space-md) 0;
    }

    .wizard-progress__label {
        display: none;
    }

    .wizard-actions .ant-btn {
        flex: 1;
    }
}

/* --- Wizard step body — title, hint, fields, review, edit-link.
   F-176: promoted from WizardPlayground.razor.css. Fills the obvious gap where
   .wizard-progress + .wizard-actions existed globally but step-body styles did not. */
.wizard-step__title {
    font-size: var(--type-step-title);
    font-weight: var(--type-step-title-weight);
    line-height: var(--type-step-title-line);
    letter-spacing: var(--type-step-title-tracking);
    color: var(--text-primary);
    margin: 0 0 var(--space-xs);
}

.wizard-step__hint {
    color: var(--text-muted);
    margin: 0 0 var(--space-lg);
}

.wizard-step__field {
    display: flex;
    flex-direction: column;
    gap: var(--space-xs);
    margin-bottom: var(--space-md);
}

.wizard-step__error {
    margin: 0;
    color: var(--color-error);
    font-size: 0.8125rem;
}

.wizard-step__review {
    display: flex;
    flex-direction: column;
    gap: var(--space-sm);
    margin: 0;
}

.wizard-step__review-row {
    display: grid;
    grid-template-columns: 160px 1fr auto;
    align-items: baseline;
    gap: var(--space-md);
}

.wizard-step__review-row dt {
    color: var(--text-muted);
    font-weight: 500;
}

.wizard-step__review-row dd {
    margin: 0;
    color: var(--text-primary);
}

.wizard-step__edit {
    background: transparent;
    border: none;
    color: var(--color-primary-fg);
    cursor: pointer;
    font: inherit;
    padding: 0;
}

.wizard-step__edit:hover {
    text-decoration: underline;
}

@media (max-width: 480px) {
    .wizard-step__review-row {
        grid-template-columns: 1fr auto;
    }

    .wizard-step__review-row dt {
        grid-column: 1 / -1;
    }
}

/* --- Portal Client Header Bar --- */
.client-header-bar {
    display: flex;
    align-items: center;
    gap: var(--space-md);
    padding: var(--space-sm) var(--space-lg);
    background: var(--glass-bg-light);
    border-bottom: 1px solid var(--glass-border);
    color: var(--text-secondary);
    font-size: 0.875rem;
}

.client-header-bar__label {
    font-weight: 500;
    color: var(--text-muted);
}

@media (max-width: 768px) {
    .client-header-bar {
        flex-wrap: wrap;
        padding: var(--space-sm) var(--space-md);
    }
}

/* --- Heavy Data Report --- */
.heavy-data-section {
    position: relative;
}

/* "{N} of {total} loaded" caption above streaming-data tables.
   F-176: promoted from HeavyDataPlayground.razor.css. */
.heavy-data-section__loaded-count {
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
    padding-top: 0.375rem;
}

.heavy-data-totals {
    position: sticky;
    bottom: 0;
    padding: var(--space-md) var(--space-lg);
    background: var(--color-bg-elevated);
    border-top: 1px solid var(--glass-border);
    z-index: 5;
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--space-md);
    font-size: 0.875rem;
    color: var(--text-secondary);
}

.heavy-data-totals strong {
    color: var(--text-primary);
}

.heavy-data-sentinel {
    height: 80px;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--text-muted);
}

.heavy-data-density--compact .ant-table-cell {
    padding: 4px 8px !important;
    font-size: 0.8125rem;
}

.heavy-data-density--comfortable .ant-table-cell {
    padding: 12px 16px !important;
}

.heavy-data-density--spacious .ant-table-cell {
    padding: 20px 24px !important;
}

/* ========================================
   Calendar Cell Annotations
   Global so every page rendering an annotated AntDesign <Calendar/>
   (vacation, billing, deadline, etc.) can reuse it.
   Composition:
     .calendar-cell[.calendar-cell--<variant>]
       > .calendar-cell__day + (.calendar-annotation)?
   Variants: --substitute, --override, --today, --past.
   See `/design-system#calendar-annotated-playground-template`.
   ======================================== */

.calendar-cell {
    position: relative;
    padding: 4px 6px;
    border-radius: var(--radius-sm);
    transition: background var(--transition-base);
}

.calendar-cell__day {
    font-weight: 600;
}

.calendar-annotation {
    display: inline-block;
    font-size: 0.6875rem;
    padding: 1px 4px;
    border-radius: var(--radius-xs);
    background: rgba(var(--color-primary-rgb), 0.15);
    color: var(--color-primary-fg);
    margin-left: 4px;
}

.calendar-cell--substitute {
    background: rgba(var(--color-tier-starter-rgb), 0.08);
}

.calendar-cell--override {
    background: rgba(var(--color-accent-purple-rgb), 0.08);
}

.calendar-cell--today {
    outline: 2px solid var(--color-primary);
}

.calendar-cell--past {
    opacity: 0.5;
}

/* ========================================
   Deadline-Dots (Density Grid)
   Global so reminder/alarm/scheduling UIs can reuse it.
   Composition:
     .deadline-row > .bureau-deadline-cell
       > .bureau-deadline-cell__date
       + .bureau-deadline-cell__dots
         > .deadline-dot.deadline-dot--<urgency> x N
         + .bureau-deadline-cell__overflow?
   Urgencies: --low, --med, --high, --critical.
   See `/design-system#deadline-dots-playground-template`.
   ======================================== */

.deadline-row {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 4px;
}

.bureau-deadline-cell {
    aspect-ratio: 1;
    padding: 6px;
    border-radius: var(--radius-sm);
    background: var(--glass-bg);
    border: 1px solid var(--glass-border);
    display: flex;
    flex-direction: column;
    justify-content: space-between;
}

.bureau-deadline-cell__date {
    font-family: var(--font-mono);
    font-weight: 600;
    color: var(--text-primary);
    font-size: 0.875rem;
}

.bureau-deadline-cell__dots {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 2px;
}

.deadline-dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    flex-shrink: 0;
}

.deadline-dot--low {
    background: var(--color-success);
}

/* Urgency runs through the semantic families (I-033): orange is only primary / "mine" / selection */
.deadline-dot--med {
    background: var(--color-info);
}

.deadline-dot--high {
    background: var(--color-warning);
}

.deadline-dot--critical {
    background: var(--color-error);
}

.bureau-deadline-cell__overflow {
    font-family: var(--font-mono);
    font-size: 0.6875rem;
    color: var(--text-muted);
    margin-left: 2px;
}

@media (max-width: 768px) {
    .deadline-row {
        grid-template-columns: repeat(5, 1fr);
    }
}

@media (max-width: 480px) {
    .deadline-row {
        grid-template-columns: repeat(3, 1fr);
    }
}

/* ========================================
   Playground Hub Grid (F-174 TASK_40)
   Used by /design-system/playgrounds (PlaygroundIndex.razor) — three card grids
   grouped by A/B/C playground category. Composition:
     .playground-section > .playground-card-grid > .playground-card.glass-card x N
   ======================================== */

.playground-section {
    margin-top: var(--space-2xl);
}

.playground-section:first-of-type {
    margin-top: var(--space-xl);
}

.playground-section__title {
    font-family: var(--font-display);
    font-size: 1.25rem;
    font-weight: 600;
    color: var(--text-primary);
    margin-bottom: var(--space-xs);
}

.playground-section__count {
    color: var(--text-muted);
    font-weight: 400;
    font-size: 0.875rem;
    margin-left: var(--space-xs);
}

.playground-section__hint {
    color: var(--text-secondary);
    font-size: 0.875rem;
    margin-bottom: var(--space-lg);
}

.playground-card-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: var(--space-md);
}

.playground-card {
    display: flex;
    flex-direction: column;
    min-width: 0;
    overflow-wrap: anywhere;
    gap: var(--space-xs);
    padding: var(--space-md) var(--space-lg);
    text-decoration: none;
    color: var(--text-primary);
    transition: border-color var(--transition-base);
}

/* A flat F panel does not lift or glow (I-033, as .glass-card-hover): hover only strengthens the line */
.playground-card:hover {
    border-color: var(--glass-border-light);
    text-decoration: none;
}

.playground-card__title {
    font-family: var(--font-display);
    font-size: 1rem;
    font-weight: 600;
    color: var(--text-primary);
}

.playground-card__description {
    font-size: 0.8125rem;
    color: var(--text-secondary);
    line-height: 1.4;
}

.playground-card__footer {
    margin-top: auto;
    padding-top: var(--space-sm);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-sm);
    border-top: 1px solid var(--glass-border);
}

.playground-card__route {
    font-family: var(--font-mono);
    font-size: 0.75rem;
    color: var(--text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.playground-card__cta {
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--color-primary-text);
    white-space: nowrap;
}

/* minmax(0, 1fr): a plain 1fr keeps the cards' min-content width (395px at 390), so the column outgrew the grid */
@media (max-width: 480px) {
    .playground-card-grid {
        grid-template-columns: minmax(0, 1fr);
    }
}

/* ========================================
   Reconciliation Grid
   Vertical stack of paired rows for matching workflows (transactions to bank statements,
   diff/sync UIs, etc.). Each row is a 3-column grid: left record | match badge | right record.
   Composition:
     .reconciliation-grid > .reconciliation-pair x N
       > .reconciliation-pair__side.reconciliation-pair__side--left
       + .reconciliation-match-badge[.reconciliation-match-badge--matched|--unmatched|--drop-target]
       + .reconciliation-pair__side.reconciliation-pair__side--right
   See `/design-system#reconciliation-playground-template`.
   ======================================== */

.reconciliation-grid {
    display: flex;
    flex-direction: column;
    gap: var(--space-sm);
}

.reconciliation-pair {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
    gap: var(--space-md);
    align-items: stretch;
    padding: var(--space-sm);
    border-radius: var(--radius-md);
    background: var(--glass-bg);
    border: 1px solid var(--glass-border);
    transition: border-color var(--transition-base);
}

.reconciliation-pair--matched {
    border-color: rgba(var(--color-success-rgb), 0.4);
    background: rgba(var(--color-success-rgb), 0.06);
}

.reconciliation-pair--drag-over {
    border-color: var(--color-primary);
    box-shadow: 0 0 0 2px var(--color-primary-glow);
}

.reconciliation-pair__side {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: var(--space-sm) var(--space-md);
    border-radius: var(--radius-sm);
    background: var(--glass-bg-light);
    min-height: 56px;
}

.reconciliation-pair__side--draggable {
    cursor: grab;
}

.reconciliation-pair__side--draggable:active {
    cursor: grabbing;
}

.reconciliation-pair__side--empty {
    background: transparent;
    border: 1px dashed var(--glass-border);
    color: var(--text-muted);
    align-items: center;
    justify-content: center;
    font-size: 0.8125rem;
}

.reconciliation-pair__reference {
    font-family: var(--font-mono);
    font-size: 0.8125rem;
    color: var(--text-secondary);
}

.reconciliation-pair__amount {
    font-family: var(--font-mono);
    font-size: 1rem;
    font-weight: 600;
    color: var(--text-primary);
}

.reconciliation-pair__date {
    font-family: var(--font-mono);
    font-size: 0.75rem;
    color: var(--text-muted);
}

.reconciliation-match-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    align-self: center;
    height: 32px;
    border-radius: 50%;
    background: var(--glass-bg-light);
    color: var(--text-muted);
    font-size: 1rem;
    border: 1px solid var(--glass-border);
}

.reconciliation-match-badge--matched {
    background: var(--color-success-bg);
    color: var(--color-success);
    border-color: rgba(var(--color-success-rgb), 0.4);
}

.reconciliation-match-badge--unmatched {
    color: var(--text-muted);
}

@media (max-width: 768px) {
    .reconciliation-pair {
        grid-template-columns: 1fr;
    }
    .reconciliation-match-badge {
        justify-self: center;
    }
}

/* ========================================
   Calculator Page Grid
   Two-pane input/output layout for calculator
   and financial tool pages. Composition:
   .calculator-page-grid > .calculator-pane[input] + .calculator-pane[output]
   See `/design-system#calculator-playground-template`.
   ======================================== */

.calculator-page-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: var(--space-lg);
}

/* Calculator pane — section heading inside an input/output pane on a calculator page.
   F-176: promoted from CalculatorPlayground.razor.css. */
.calculator-pane h3 {
    font-size: 1rem;
    font-weight: 600;
    color: var(--text-secondary);
    margin-bottom: var(--space-md);
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

@media (max-width: 768px) {
    .calculator-page-grid {
        grid-template-columns: 1fr;
    }
}

/* ========================================
   Shared Animations
   Common keyframes used across multiple pages.
   Pages can reference these without re-declaring.
   ======================================== */

@keyframes slideUp {
    from {
        opacity: 0;
        transform: translateY(20px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

@keyframes fadeIn {
    from {
        opacity: 0;
    }
    to {
        opacity: 1;
    }
}

/* ========================================
   Auth Form Shared Styles
   Used across Login, Register, LoginConfirm,
   RegisterConfirm pages.
   ======================================== */

.auth-form {
    width: 100%;
    position: relative;
    z-index: 1;
}

.auth-form-header {
    text-align: center;
    margin-bottom: var(--space-xl);
}

.auth-title {
    font-family: var(--font-display);
    font-size: 1.875rem;
    font-weight: 600;
    color: var(--text-primary);
    margin: 0 0 0.625rem 0;
    letter-spacing: -0.02em;
    line-height: 1.2;
}

.auth-subtitle {
    font-size: 0.9375rem;
    color: var(--text-secondary);
    margin: 0;
    font-weight: 400;
    line-height: 1.5;
}

.auth-code-expires {
    font-size: 0.875rem;
    color: var(--color-primary-fg);
    margin: 0.75rem 0 0 0;
    font-weight: 500;
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    padding: 0.375rem 0.75rem;
    background: rgba(var(--color-primary-rgb), 0.1);
    border-radius: var(--radius-sm);
}

.auth-footer-links {
    text-align: center;
    font-size: 0.9375rem;
    color: var(--text-secondary);
}

.auth-footer-links a {
    color: var(--color-primary-fg);
    text-decoration: none;
    margin-left: 0.375rem;
    font-weight: 500;
    transition: var(--transition-fast);
    position: relative;
}

.auth-footer-links a::after {
    content: '';
    position: absolute;
    bottom: -2px;
    left: 0;
    width: 0;
    height: 1px;
    background: var(--color-primary);
    transition: width var(--transition-base);
}

.auth-footer-links a:hover {
    color: var(--color-link-hover);
}

.auth-footer-links a:hover::after {
    width: 100%;
}

/* Auth-page button hover shine effect */
.auth-form .ant-btn-primary {
    position: relative;
    overflow: hidden;
}

.auth-form .ant-btn-primary::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: linear-gradient(
            135deg,
            var(--glass-shine) 0%,
            transparent 50%
    );
    opacity: 0;
    transition: opacity var(--transition-base);
}

.auth-form .ant-btn-primary:hover::before {
    opacity: 1;
}

@media (max-width: 480px) {
    .auth-title {
        font-size: 1.625rem;
    }

    .auth-subtitle {
        font-size: 0.875rem;
    }
}

/* ========================================
   Social Auth — provider sign-in button + labeled divider
   Global utilities used on auth pages (F-192). Full-width,
   glass/token surface — compose from globals, no scoped CSS.
   See `/design-system#social-auth-button` and
   `/design-system#auth-divider`.
   ======================================== */

/* Social auth button — full-width provider sign-in control */
.social-auth-button {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-sm);
    width: 100%;
    padding: var(--space-sm) var(--space-md);
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-md);
    background: var(--glass-bg);
    color: var(--text-primary);
    font-family: var(--font-body);
    font-size: 0.9375rem;
    font-weight: 500;
    line-height: 1.4;
    cursor: pointer;
    transition: background var(--transition-fast), border-color var(--transition-fast), transform var(--transition-fast);
}

.social-auth-button:hover {
    background: var(--glass-bg-light);
    border-color: var(--color-primary);
}

.social-auth-button:focus-visible {
    outline: none;
    box-shadow: 0 0 0 2px var(--color-focus-ring);
}

.social-auth-button:active {
    transform: translateY(1px);
}

.social-auth-button:disabled {
    opacity: 0.6;
    cursor: not-allowed;
}

/* Stacked social buttons keep a consistent vertical rhythm */
.social-auth-button + .social-auth-button {
    margin-top: var(--space-sm);
}

/* Leading provider-icon slot (inherits currentColor, 20px box) */
.social-auth-button__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 20px;
    height: 20px;
    font-size: 20px;
    line-height: 1;
}

.social-auth-button__icon svg {
    width: 100%;
    height: 100%;
}

/* Labeled divider — "or continue with" (line · label · line) */
.auth-divider {
    display: flex;
    align-items: center;
    gap: var(--space-md);
    margin: var(--space-lg) 0;
    color: var(--text-muted);
    font-size: 0.8125rem;
    font-weight: 500;
}

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

/* ========================================
   List Page Shared Components
   Filter cards, loading/retry states, tables,
   pagination, skeletons, and utilities used
   across list pages (TicketList, Notifications, etc.)
   ======================================== */

/* --- Loading Container --- */
.loading-container {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 300px;
    background: var(--glass-bg);
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-lg);
}

.loading-container .ant-spin-text {
    color: var(--text-secondary) !important;
}

/* --- Retry Container --- */
.retry-container {
    margin-top: var(--space-md);
    text-align: center;
}

/* Right-aligned inline retry row (for list/table pages with optimistic refetch).
   F-176: promoted from ListPlayground.razor.css `.list-playground__retry`. */
.retry-container--inline {
    text-align: initial;
    display: flex;
    justify-content: flex-end;
}

.retry-container .ant-btn {
    background: var(--glass-bg-light) !important;
    border: 1px solid var(--glass-border-light) !important;
    color: var(--text-secondary) !important;
}

.retry-container .ant-btn:hover {
    border-color: var(--color-primary) !important;
    color: var(--color-primary-fg) !important;
}

/* --- Filter Card --- */
.filter-card {
    background: var(--glass-bg);
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-lg);
    padding: var(--space-lg);
    margin-bottom: var(--space-lg);
    animation: pageSlideUp 0.4s ease-out;
}

.filter-row {
    display: flex;
    gap: var(--space-md);
    align-items: flex-end;
    flex-wrap: wrap;
}

.filter-item {
    flex: 1;
    min-width: 160px;
}

.filter-item--search {
    flex: 1.5;
    min-width: 200px;
}

.filter-label {
    display: block;
    font-size: 0.8125rem;
    color: var(--text-secondary);
    margin-bottom: var(--space-xs);
    font-weight: 500;
}

.filter-actions {
    display: flex;
    gap: var(--space-sm);
    align-items: flex-end;
    padding-bottom: 1px;
}

/* I-014 report-page: required-filter marker (the .form-field__label--required twin) and the
   disabled-run hint beside the Run button. */
.filter-label--required::after {
    content: " *";
    color: var(--color-error);
}

.filter-actions__hint {
    font-size: 0.8125rem;
    color: var(--text-secondary);
    align-self: center;
}

/* --- Tree toolbar + node title family ---
   F-176: promoted from TreePlayground.razor.css. "Search input + filter buttons +
   counter" toolbar above any tree/list; "icon + text" tree node title with
   filter/search states. Real org-chart, file-browser, role-tree pages want these. */
.tree-toolbar {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    margin-bottom: var(--space-md);
    flex-wrap: wrap;
}

.tree-toolbar > :first-child {
    flex: 1 1 320px;
}

.search-match-count {
    color: var(--text-muted);
    font-size: 0.8125rem;
}

.tree-node-title {
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
}

.tree-node-title__icon {
    color: var(--text-muted);
    flex-shrink: 0;
}

.tree-node-title--dimmed {
    opacity: 0.4;
}

.tree-node-title--match .tree-node-title__name {
    color: var(--color-primary-text);
    font-weight: 500;
}

.tree-node-title--match .tree-node-title__icon {
    color: var(--color-primary-fg);
}

/* --- Form Field utility (non-submit reactive inputs) --- */
.form-field {
    display: flex;
    flex-direction: column;
    gap: var(--space-xs);
    margin-bottom: var(--space-md);
}

/* B-009 (AD8): .settings-section already spaces its children with `gap`; the .form-field's
   own margin-bottom would double it. Every other .form-field user is in block flow and keeps
   the margin above. */
.settings-section > .form-field {
    margin-bottom: 0;
}

.form-field__label {
    font-size: 0.875rem;
    font-weight: 500;
    color: var(--text-secondary);
}

/* Required-field marker for a .form-field label (the AntD FormItem draws its own). */
.form-field__label--required::after {
    content: " *";
    color: var(--color-error);
}

/* A Switch with its label and description beside it (settings-page toggles). The label sits next to the
   control, not at the far edge of the card; the optional description wraps under the label. */
.switch-field {
    display: flex;
    align-items: flex-start;
    gap: var(--space-md);
}

.switch-field > .ant-switch {
    flex: none;
    margin-top: var(--space-xs);
}

.switch-field__text {
    display: flex;
    flex-direction: column;
    gap: var(--space-xs);
    min-width: 0;
}

.switch-field__text > .filter-label {
    margin-bottom: 0;
}

.switch-field__description {
    margin: 0;
    font-size: 0.8125rem;
    color: var(--text-muted);
}

/* Inline hint text beneath a .form-field (validation/help messaging).
   F-176: promoted from InputsPlayground.razor.css. */
.form-field__hint {
    font-size: 0.8125rem;
    color: var(--text-muted);
}

.form-field__hint--success {
    color: var(--color-success);
}

.form-field__hint--error {
    color: var(--color-error);
}

/* Password-strength meter — 4-state track + fill bar.
   F-176: promoted from InputsPlayground.razor.css. */
.password-strength {
    height: 4px;
    background: var(--glass-bg);
    border-radius: 999px;
    overflow: hidden;
    margin-top: var(--space-xs);
}

.password-strength__bar {
    height: 100%;
    transition: width 200ms ease, background-color 200ms ease;
}

.password-strength__bar--weak {
    background: var(--color-error);
}

.password-strength__bar--fair {
    background: var(--color-warning);
}

.password-strength__bar--strong {
    background: var(--color-amber);
}

.password-strength__bar--excellent {
    background: var(--color-success);
}

/* Suggestion chip row beneath an input — "Try these instead:" affordance.
   F-176: promoted from InputsPlayground.razor.css. */
.input-suggestions {
    margin-top: var(--space-xs);
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-xs);
    align-items: center;
    color: var(--text-muted);
    font-size: 0.8125rem;
}

.input-suggestions__item {
    background: var(--glass-bg);
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-sm);
    padding: 2px 8px;
    font-size: 0.8125rem;
    color: var(--text-primary);
    font-family: var(--font-mono);
    cursor: pointer;
    transition: border-color 150ms ease, background 150ms ease;
}

.input-suggestions__item:hover {
    border-color: var(--color-primary);
    background: var(--glass-bg-light);
}

/* Muted secondary meta-text shown beside an option's primary label (e.g. an
   email beside a user's display name in a `<Select>` or autocomplete row).
   F-176: promoted from InputsPlayground.razor.css. */
.option-meta {
    color: var(--text-muted);
    font-size: 0.875rem;
    margin-left: var(--space-xs);
}

/* Inline autocomplete results panel (rendered below the input).
   F-176: promoted from InputsPlayground.razor.css. */
.autocomplete-results-list {
    list-style: none;
    margin: var(--space-xs) 0 0;
    padding: 0;
    background: var(--glass-bg);
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-md);
    max-height: 280px;
    overflow-y: auto;
}

.autocomplete-results-list__item {
    padding: var(--space-sm) var(--space-md);
    cursor: pointer;
    color: var(--text-primary);
    font-size: 0.9375rem;
    border-bottom: 1px solid var(--glass-border);
    transition: background 150ms ease;
}

.autocomplete-results-list__item:last-child {
    border-bottom: none;
}

.autocomplete-results-list__item:hover {
    background: var(--glass-bg-light);
}

/* Filter card — search input */
.filter-card .ant-input-affix-wrapper {
    background: var(--glass-bg-light) !important;
    border: 1px solid var(--glass-border) !important;
    border-radius: var(--radius-md) !important;
}

.filter-card .ant-input-affix-wrapper:hover {
    border-color: var(--glass-border-light) !important;
}

.filter-card .ant-input-affix-wrapper:focus-within {
    border-color: var(--color-primary) !important;
    box-shadow: 0 0 0 2px var(--color-focus-ring) !important;
}

.filter-card .ant-input-affix-wrapper .ant-input {
    background: transparent !important;
    border: none !important;
    box-shadow: none !important;
    height: auto !important;
}

.filter-card .ant-input-search-button {
    border-radius: var(--radius-md) !important;
    margin-left: 5px !important;
}

/* Search input — fill filter-item container width */
.filter-card .ant-input-group-wrapper.ant-input-search {
    width: 100% !important;
}

.filter-card .ant-input-search .ant-input-wrapper.ant-input-group {
    width: 100% !important;
}

/* Multi-select tag styling inside filter cards */
.filter-card .ant-select-selection-overflow-item .ant-select-selection-item {
    background: rgba(var(--color-primary-rgb), 0.15) !important;
    border-color: rgba(var(--color-primary-rgb), 0.3) !important;
    color: var(--color-primary-fg) !important;
    border-radius: var(--radius-sm);
}

.filter-card .ant-select-selection-item-remove {
    color: var(--color-primary-fg) !important;
}

/* --- Page Header Actions --- */
.page-header__actions {
    display: flex;
    gap: var(--space-sm);
    align-items: center;
}

/* --- Table Container --- */
.table-container {
    background: var(--glass-bg);
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-lg);
    overflow: hidden;
    animation: pageSlideUp 0.5s ease-out;
}

/* B-005: a .table-container nested in a .glass-card is a plain inner wrapper —
   the card already draws the glass surface, so a second one is card-in-card chrome. */
.glass-card > .table-container,
.glass-card .table-container {
    background: transparent;
    border: 0;
    border-radius: 0;
    animation: none;
}

/* Allow horizontal scroll inside a glass-card-hosted table when the column set
   exceeds viewport width. F-176: promoted from TablesPlayground.razor.css. */
.table-card--scroll-x {
    overflow-x: auto;
}

/* I-012 (AD8): inside a scroll-x host the header cells wrap. With ScrollX the table is laid out
   `table-layout: fixed` at the sum of the column Widths, so a long title must break inside its
   column's Width rather than overflow it into the next header (or force the column wider).
   B-054 run 16: `break-word`, not `anywhere`. `anywhere` also lowers the cell's min-content size to one
   character, so in an auto-layout table a short header ("Status") shrinks to a sliver and splits mid-word
   whenever the table is squeezed. `break-word` keeps min-content at the longest word (columns stop there
   and the host scrolls) and still breaks a word that cannot fit its box, i.e. a long title inside a
   fixed-layout column's Width. */
.table-card--scroll-x .ant-table-thead > tr > th {
    white-space: normal;
    overflow-wrap: break-word;
}

/* I-012: a link button in an Ellipsis cell (a list's Subject/Title link) stays inside its column
   and ellipsizes its label. AntD's `.ant-btn` is an inline-block that sizes to its text and its
   `> span` is an inline-block too, so the cell's own text-overflow never reaches the label — the
   cell just clips the button mid-word. Only the label span ellipsizes: an Icon+label button also renders a
   `span.anticon`, which stays inline or the icon stacks above the label (B-054 run 14). */
.table-card--scroll-x .ant-table-cell-ellipsis > .ant-btn {
    max-width: 100%;
}

.table-card--scroll-x .ant-table-cell-ellipsis > .ant-btn > span:not(.anticon) {
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* --- Pinned (Fixed) table cells: opaque in every host (B-054 run 8) ---
   A frozen column must be opaque or the cells scrolling under it show through. overrides.css already paints
   the bare table, but it beats `.table-container .ant-table-tbody > tr > td { background: transparent !important }`
   and the th/hover twins only by source order (equal specificity). One class more in the host prefix wins on
   specificity alone: (0,3,2) at rest, (0,4,2) on row hover (the `.table-container` hover rule is (0,3,2)). */
.glass-card .ant-table-tbody > tr > td.ant-table-cell-fix-left,
.glass-card .ant-table-tbody > tr > td.ant-table-cell-fix-right,
.table-container .ant-table-tbody > tr > td.ant-table-cell-fix-left,
.table-container .ant-table-tbody > tr > td.ant-table-cell-fix-right,
.glass-card .ant-table-tbody > tr:hover > td.ant-table-cell-fix-left,
.glass-card .ant-table-tbody > tr:hover > td.ant-table-cell-fix-right,
.table-container .ant-table-tbody > tr:hover > td.ant-table-cell-fix-left,
.table-container .ant-table-tbody > tr:hover > td.ant-table-cell-fix-right {
    background-color: var(--table-pinned-bg) !important;
}

/* A pinned header cell paints the header's own opaque surface, so the header row reads as one band (I-023 TASK_04:
   --table-pinned-bg is the white panel in light, the header is --glass-bg-subtle). */
.glass-card .ant-table-thead > tr > th.ant-table-cell-fix-left,
.glass-card .ant-table-thead > tr > th.ant-table-cell-fix-right,
.table-container .ant-table-thead > tr > th.ant-table-cell-fix-left,
.table-container .ant-table-thead > tr > th.ant-table-cell-fix-right {
    background-color: var(--glass-bg-subtle) !important;
}

/* ========================================
   Table row affordances — expand, edit, sub-records.
   F-176: promoted from TablesPlayground.razor.css. Reusable across every
   feature table that needs expandable rows, ••• action menus, inline-edit
   cells, or sub-tables of child records (invoices line items, audit detail,
   sub-records, etc.).
   ======================================== */

/* Borderless chevron button used to expand a table row. */
.row-expand-toggle {
    background: none;
    border: none;
    color: var(--text-muted);
    cursor: pointer;
    padding: 4px;
    line-height: 1;
}

.row-expand-toggle:hover {
    color: var(--color-primary-fg);
}

/* Borderless ellipsis (•••) button that opens a per-row actions dropdown. */
.row-actions-toggle {
    background: none;
    border: none;
    color: var(--text-muted);
    cursor: pointer;
    font-size: 1.125rem;
    line-height: 1;
    padding: 4px 8px;
    border-radius: var(--radius-sm);
}

.row-actions-toggle:hover {
    color: var(--text-primary);
    background: var(--glass-bg-light);
}

/* Cell with a transparent dashed underline that becomes visible on hover —
   the "click to edit inline" affordance. */
.cell-editable {
    cursor: text;
    border-bottom: 1px dashed transparent;
    transition: border-color 150ms ease;
}

.cell-editable:hover {
    border-bottom-color: var(--glass-border-light);
}

/* Inline `<input>` that replaces a .cell-editable in edit mode. */
.cell-edit-input {
    background: var(--glass-bg-light);
    border: 1px solid var(--color-primary);
    border-radius: var(--radius-sm);
    color: var(--text-primary);
    font: inherit;
    padding: 2px 6px;
    width: 8rem;
    text-align: right;
}

/* Glass surface revealed below an expanded row. */
.row-expand-content {
    background: var(--glass-bg);
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-md);
    padding: var(--space-md) var(--space-lg);
    margin-top: var(--space-sm);
}

.row-expand-content__title {
    font-family: var(--font-display);
    font-size: 0.9375rem;
    font-weight: 600;
    color: var(--text-secondary);
    margin: 0 0 var(--space-sm);
}

/* Secondary `<table>` rendered inside .row-expand-content for child records
   (line items, sub-rows, audit detail). */
.row-expand-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.875rem;
    color: var(--text-primary);
}

.row-expand-table th {
    text-align: left;
    color: var(--text-muted);
    font-weight: 500;
    padding: 4px 8px;
    border-bottom: 1px solid var(--glass-border);
}

.row-expand-table td {
    padding: 6px 8px;
    border-bottom: 1px solid var(--glass-border);
}

.table-container .ant-table {
    background: transparent !important;
}

.table-container .ant-table-thead > tr > th {
    background: var(--glass-bg-subtle) !important;
    color: var(--text-secondary) !important;
    border-bottom: 1px solid var(--glass-border) !important;
    font-weight: 600;
    font-size: 0.8125rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

.table-container .ant-table-tbody > tr > td {
    background: transparent !important;
    border-bottom: 1px solid var(--glass-border) !important;
    color: var(--text-primary) !important;
}

.table-container .ant-table-tbody > tr:hover > td {
    background: var(--color-row-hover) !important;
}

.table-container .ant-table-tbody > tr:last-child > td {
    border-bottom: none !important;
}

/* --- Skeleton Rows --- */
.skeleton-row {
    background: var(--glass-bg);
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-lg);
    padding: var(--space-lg);
}

.skeleton-row .ant-skeleton-content .ant-skeleton-title {
    background: linear-gradient(90deg, var(--glass-bg-light) 25%, var(--glass-bg-hover) 50%, var(--glass-bg-light) 75%) !important;
    background-size: 400% 100% !important;
}

.skeleton-row .ant-skeleton-content .ant-skeleton-paragraph > li {
    background: linear-gradient(90deg, var(--glass-bg-light) 25%, var(--glass-bg-hover) 50%, var(--glass-bg-light) 75%) !important;
    background-size: 400% 100% !important;
}

.skeleton-row .ant-skeleton-avatar {
    background: var(--glass-bg-light) !important;
}

/* --- Pagination --- */
.pagination-container {
    display: flex;
    justify-content: center;
    padding: var(--space-lg);
}

.pagination-container .ant-pagination-item {
    background: transparent !important;
    border-color: transparent !important;
}

.pagination-container .ant-pagination-item a {
    color: var(--text-secondary) !important;
}

/* F .pgn button[aria-current] (I-033 TASK_01): the current page is --text 600 on --panel with a --text-2 edge — not orange */
.pagination-container .ant-pagination-item-active {
    background: var(--glass-bg) !important;
    border-color: var(--text-secondary) !important;
}

.pagination-container .ant-pagination-item-active a {
    color: var(--text-primary) !important;
    font-weight: 600;
}

.pagination-container .ant-pagination-prev .ant-pagination-item-link,
.pagination-container .ant-pagination-next .ant-pagination-item-link {
    background: transparent !important;
    border-color: transparent !important;
    color: var(--text-secondary) !important;
}

/* --- Empty State --- */
.ant-empty {
    padding: var(--space-2xl);
}

.ant-empty-description {
    color: var(--text-muted) !important;
}

/* --- Error Alert --- F .alert--err (I-033 TASK_01): the tone is the icon, edge and ground (overrides.css "Alert
   Overrides"); the message is --text and the description --text-2, as every alert */
.ant-alert-error {
    background: color-mix(in srgb, var(--color-error) 9%, var(--glass-bg)) !important;
    border: 1px solid color-mix(in srgb, var(--color-error) 45%, transparent) !important;
    border-radius: 10px;
}

.ant-alert-error .ant-alert-message {
    color: var(--text-primary) !important;
}

.ant-alert-error .ant-alert-description {
    color: var(--text-secondary) !important;
}

/* --- Utility Classes --- */
.datetime-cell {
    font-size: 0.875rem;
    color: var(--text-primary);
    font-family: var(--font-mono);
}

.text-muted {
    color: var(--text-muted);
}

/* CF-017: body copy one step below the text colour (F --text-2) — the Competitors page's weights help line */
.text-secondary {
    color: var(--text-secondary);
}

/* Brand-error color utility — destructive menu items, danger labels.
   F-176: promoted from TablesPlayground.razor.css. */
.text-danger {
    color: var(--color-error);
}

/* Right-aligned tabular-numeric cell — money/quantity/% columns in tables.
   F-176: promoted from TablesPlayground.razor.css. */
.numeric-cell {
    text-align: right;
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
}

.code-badge {
    background: var(--glass-bg);
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-sm);
    padding: 2px 8px;
    font-size: 0.8125rem;
    color: var(--text-primary);
    font-family: var(--font-mono);
}

/* Glass-surface preformatted text container — diffs, webhook payloads, stack
   traces, JSON previews, SQL viewers, API-key reveal blocks.
   F-176: promoted from AuditLogPlayground.razor.css. */
.code-block {
    background: var(--glass-bg);
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-sm);
    padding: var(--space-sm) var(--space-md);
    font-family: var(--font-mono);
    font-size: 0.8125rem;
    color: var(--text-primary);
    white-space: pre-wrap;
    margin: 0;
}

/* ========================================================================
   Playground-only utilities (F-176)

   These classes back demo-only chrome on `/design-system/playground/*` pages —
   variant comparison grids, "5-states-in-a-row" decorators, demo controls
   rows, in-frame caveats. They are NOT for production features. The `.pg-`
   prefix marks them as such.

   When a real feature legitimately needs a similar layout, promote the
   pattern out of this block into the main app.css utilities above. Do NOT
   reach into `.pg-*` from real feature pages.

   Source: specs/F-176-PlaygroundScopedCssCleanup/AUDIT_REPORT.md
   ======================================================================== */

/* Variant switcher control row — Empty, StatusResult */
.pg-variant-switcher {
    display: flex;
    justify-content: center;
    margin-bottom: var(--space-xl);
    animation: pageSlideUp 0.4s ease-out;
}

/* Section-heading inside a playground glass-card — Tags, Feedback, Skeleton,
   Inputs, FileUpload, Drawers */
.pg-section-title {
    font-family: var(--font-display);
    font-size: 1rem;
    font-weight: 600;
    color: var(--text-secondary);
    margin: 0 0 var(--space-md);
}

/* Companion body copy under .pg-section-title — FileUpload, Inputs, Drawers */
.pg-section-copy {
    font-size: 0.9375rem;
    color: var(--text-muted);
    margin: 0 0 var(--space-md);
}

.pg-section-copy code {
    color: var(--color-primary-text);
    font-family: var(--font-mono);
}

/* Compare-N-variants block (top-border separator) — Skeleton, Wizard,
   Subscription, Inputs */
.pg-variant {
    padding-top: var(--space-md);
    border-top: 1px solid var(--glass-border);
}

.pg-variant:first-of-type {
    padding-top: 0;
    border-top: none;
}

/* UPPERCASE letterspaced caption above each .pg-variant block */
.pg-variant-label {
    font-family: var(--font-display);
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    margin-bottom: var(--space-sm);
}

/* 2-column variant-comparison grid (stacks at 768) — Inputs */
.pg-variant-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-lg);
}

/* "label + control + hint" vertical stack inside .pg-variant-grid — Inputs */
.pg-field {
    display: flex;
    flex-direction: column;
    gap: var(--space-xs);
}

/* Inline-natural controls (Switch / Checkbox / Radio / Rate / Segmented) shouldn't
   stretch to fill the grid cell — they have intrinsic widths. Input / Select /
   DatePicker still stretch because they have their own width: 100%. */
.pg-field > .ant-switch,
.pg-field > .ant-radio-group,
.pg-field > .ant-checkbox-wrapper,
.pg-field > .ant-rate,
.pg-field > .ant-segmented {
    align-self: flex-start;
}

/* Generic vertical stack of demo items, gap-sm — Detail, Tags, Feedback */
.pg-stack-sm {
    display: flex;
    flex-direction: column;
    gap: var(--space-sm);
}

/* "Label on left, control on right" demo row — Settings */
.pg-split-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--space-md);
}

/* Centered single-state wrapper — Notifications */
.pg-center-row {
    display: flex;
    justify-content: center;
    padding: var(--space-md);
}

/* Flex-wrap row of demo trigger buttons — Modals, Drawers */
.pg-trigger-row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-sm);
}

/* Caveat / failure-mode notes list under a demo card — Modals */
.pg-notes-list {
    margin: 0;
    padding-left: var(--space-lg);
    color: var(--text-secondary);
    font-size: 0.875rem;
}

.pg-notes-list code {
    font-family: var(--font-mono);
    color: var(--color-primary-text);
}

/* Single `margin-bottom` spacer for a demo control row — Settings */
.pg-demo-spacer {
    margin-bottom: var(--space-md);
}

/* Secondary-color helper paragraph under a demo — Skeleton */
.pg-hint {
    color: var(--text-secondary);
    font-size: 0.875rem;
    margin: 0;
}

/* Flex-wrap row of demo controls (slider + button) above a demonstrator —
   Skeleton */
.pg-controls-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-md);
    margin-bottom: var(--space-md);
}

/* Inline-flex label wrapping a slider/switch in .pg-controls-row — Skeleton */
.pg-control-label {
    display: inline-flex;
    align-items: center;
    gap: var(--space-sm);
    color: var(--text-secondary);
    font-size: 0.875rem;
}

/* Bare reset + flex column container for a "loaded list" demo — Skeleton */
.pg-demo-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-xs);
}

/* 3-column "ref / label / amount" row used inside .pg-demo-list — Skeleton */
.pg-demo-list-item {
    display: grid;
    grid-template-columns: auto 1fr auto;
    align-items: baseline;
    gap: var(--space-md);
    padding: var(--space-sm) var(--space-md);
    background: var(--glass-bg-subtle);
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-sm);
}

.pg-demo-list-item__ref {
    font-family: var(--font-mono);
    color: var(--text-muted);
    font-size: 0.8125rem;
}

.pg-demo-list-item__label {
    color: var(--text-primary);
}

.pg-demo-list-item__amount {
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
    text-align: right;
    font-weight: 500;
    color: var(--text-primary);
}

/* Visually-hidden file input for playground file-picker demos — FileUpload */
.pg-visually-hidden-input {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* Viewport-fitting demo card to keep a long feed visible on-screen — AuditLog */
.pg-scroll-card-70vh {
    max-height: 70vh;
    overflow-y: auto;
}

/* A bounded stage for the shell demos (Shell, PropertyPicker, TopBar — I-024): the .shell inside it is the containing
   block of the off-canvas sider and its mask, so the narrow state stays inside the card */
.pg-shell-frame {
    height: 560px;
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-md);
    background: var(--color-bg-dark);
}

.pg-shell-frame > .shell {
    height: 100%;
}

/* Placeholder page body inside .pg-shell-frame */
.pg-shell-content {
    flex: 1;
    min-height: 0;
    overflow: auto;
    padding: var(--space-lg);
    color: var(--text-secondary);
}

/* A bounded stage for the first-login focus header (I-032 D-k) — WizardPlayground: the header and a short body, no sider */
.pg-focus-frame {
    height: 200px;
    overflow: hidden;
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-md);
    background: var(--color-bg-dark);
}

.pg-focus-frame > .shell {
    height: 100%;
}

/* Stage for a sidebar column, an open popover or an inline variant — PropertyPicker playground and the /design-system
   #app-shell / #property-picker demos (dev chrome, never product) */
.pg-shell-stage {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: var(--space-lg);
}

.pg-shell-stage__col {
    width: 256px;
    padding: 8px 6px;
    background: var(--glass-bg);
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-md);
}

.pg-shell-stage__col--rail {
    width: 64px;
    display: flex;
    justify-content: center;
}

/* The dashboard playground's F section (I-028) stands in for the F page frame's wrapper: it declares the same `page`
   inline-size container, so the dashboard block's container queries (duo, queue, KPI line, ticker rows) apply inside
   the template's page container without nesting a second .page-wrapper (B-028) — DashboardPlayground */
.pg-cq-page {
    container: page / inline-size;
    display: flex;
    flex-direction: column;
    gap: 16px; /* F .page's rhythm between the board, queue, KPI line and duo */
}

/* The heavy-data playground's F section (I-029) sits directly in the F frame (.page-container--f), whose wrapper is the
   `page` container, so it only needs F .page's 16px rhythm — no container of its own — HeavyDataPlayground */
.pg-f-section {
    display: flex;
    flex-direction: column;
    gap: 16px;
    min-width: 0;
}

.pg-f-section > .page-header {
    margin-bottom: 0;
}

/* --- Responsive: Tablet (768px) --- */
@media (max-width: 768px) {
    /* I-008 (D4): column stack; stretch, not the base flex-end, so a narrower item never drifts right */
    .filter-row {
        flex-direction: column;
        align-items: stretch;
    }

    /* I-008 (D4): 0,3,0 out-ranks a scoped `.filter-item--x[b-…]` (0,2,0) — the scoped flex-basis would
       otherwise become the item's HEIGHT in the column stack (audit: 240-280px items from a page's scoped
       `.filter-item--x` modifier). The doubled class gains that specificity without requiring a .filter-card
       ancestor, so filter rows inside a glass-card reset the global --actions/--date basis too */
    .filter-row > .filter-item.filter-item {
        flex: 0 0 auto;
        width: 100%;
        min-width: 0;
    }

    /* I-008 (D4): wrap, so a button pair never pushes past the card's left edge */
    .filter-actions {
        width: 100%;
        justify-content: flex-end;
        flex-wrap: wrap;
    }

    .page-header__actions {
        flex-direction: column;
        width: 100%;
        align-items: flex-start; /* B-028 (1329): Tags/Segmented keep their natural width; buttons are widened below */
    }

    /* B-009 (AD9) + B-028 (1343, 1360): equal-width, centred mobile header buttons — direct buttons and
       links, and a Popconfirm/Tooltip/Dropdown wrapper around a button together with its button.
       B-008 (2589, 2648): a Button.Group / Space.Compact / Dropdown.Button is one control, not split 50/50 */
    .page-header__actions > .ant-btn,
    .page-header__actions > a,
    .page-header__actions > :has(> .ant-btn):not(.ant-btn-group):not(.ant-space-compact):not(.ant-dropdown-button),
    .page-header__actions > :has(> .ant-btn):not(.ant-btn-group):not(.ant-space-compact):not(.ant-dropdown-button) > .ant-btn {
        width: 100%;
        justify-content: center;
        text-align: center;
    }

    /* B-008 (2620): a Space-wrapped action row stretches like direct buttons instead of shrinking to its
       intrinsic width under `align-items: flex-start` */
    .page-header__actions > .ant-space {
        width: 100%;
    }

    .page-header__actions > .ant-space > .ant-space-item {
        flex: 1 1 0;
    }

    .page-header__actions > .ant-space > .ant-space-item > .ant-btn {
        width: 100%;
    }

    /* I-008 (D10): the catalog's "tabs become horizontally scrollable" — native scroll + a thin visible scrollbar as
       the affordance; AntD's JS translate would fight the native scroll, its "more" button is redundant with it */
    .settings-tabs-layout > .ant-tabs > .ant-tabs-nav .ant-tabs-nav-wrap {
        overflow-x: auto;
        scrollbar-width: thin;
        scrollbar-color: var(--glass-border) transparent;
    }

    .settings-tabs-layout > .ant-tabs > .ant-tabs-nav .ant-tabs-nav-list {
        transform: none !important;
    }

    .settings-tabs-layout > .ant-tabs > .ant-tabs-nav .ant-tabs-nav-operations {
        display: none;
    }

    /* I-012: keep the overflow inside the wrap. A card that is a flex/grid item keeps min-width: auto = the strip's
       min-content, grows past its container and leaves the wrap nothing to scroll (wrap scrollWidth == clientWidth);
       min-width: 0 down the flex chain stops that. The list, not the wrap, carries the overflow (flex: none), and an
       individual `translate` on it — which `transform: none` does not reach — would push the first tab past the
       wrap's left edge, where scrollLeft cannot go. */
    .settings-tabs-layout {
        min-width: 0;
        max-width: 100%;
    }

    .settings-tabs-layout > .ant-tabs,
    .settings-tabs-layout > .ant-tabs > .ant-tabs-nav,
    .settings-tabs-layout > .ant-tabs > .ant-tabs-nav .ant-tabs-nav-wrap {
        min-width: 0;
    }

    .settings-tabs-layout > .ant-tabs > .ant-tabs-nav .ant-tabs-nav-wrap {
        flex: 1 1 auto;
    }

    .settings-tabs-layout > .ant-tabs > .ant-tabs-nav .ant-tabs-nav-list {
        flex: none;
        translate: none !important;
    }

    .page-wrapper {
        padding: var(--space-lg);
    }

    .page-header {
        padding: var(--space-lg);
    }

    .page-header--with-actions {
        flex-direction: column;
        gap: var(--space-md);
    }

    /* Playground utilities — mobile collapse */
    .pg-variant-grid {
        grid-template-columns: 1fr;
    }

    .pg-demo-list-item {
        grid-template-columns: 1fr;
    }

    .pg-demo-list-item__amount {
        text-align: left;
    }
}

/* --- I-012: 44px touch targets at <=480px (AntD default controls are 32px) ---
   specs/I-012-MobileTouchTargetsWideTables/PLAN.md AD3/AD7. Every interactive control outside a table cell is at least
   44px tall on a phone; desktop keeps AntD's default sizes (nothing here applies above 480px). Measured by the L2 probe
   (scripts/audit-page-design/mobile-probes.js) and the E2E probe (MobileLayoutProbe.cs) with the same selector list.
   Specificity: `ant-design-blazor.css` loads AFTER app.css (index.html), so an equal-specificity rule here loses to
   AntD's own `display` / `height` / `align-items`. AntD sets no `min-height` on these controls, so the lift itself
   needs no extra weight (exception: AntD's `textarea.ant-input { min-height: 32px }` outweighs `.ant-input` — every
   template TextArea has Rows >= 2, so none renders under 44px); the doubled class (0,2,0 — the `.filter-item.filter-item` idiom above) is used only where a
   property AntD does set must change. No `!important`: AntD uses none on these rules. A page's scoped rule
   (App.styles.css, loaded after app.css) of equal weight still wins, so `.sidebar-toggle-btn` / `.logout-btn` keep
   their own flex layout and only grow taller. */
@media (max-width: 480px) {
    /* Buttons, every size (`-sm` included). `min-height` beats AntD's fixed `height: 32px` / `24px`; inline-flex
       centres the label in the taller box (AntD's inline-block would leave it at the top). Icon-only buttons
       (incl. circle icon buttons) also get a 44px width so they stay square/round instead of a 32x44 sliver */
    .ant-btn.ant-btn {
        min-height: 44px;
        display: inline-flex;
        align-items: center;
        justify-content: center;
    }

    .ant-btn.ant-btn-icon-only {
        min-width: 44px;
    }

    /* Table cells keep AntD's compact row actions (AD3 exemption, as design-lint `button-size`). Written as a later,
       heavier reset instead of an ancestor `:not()`, so the lift above stays one plain selector: `:is()` takes its
       heaviest argument (0,1,0), giving 0,3,0 over the 0,2,0 lift. `unset` = `auto` — AntD sets no min-height or
       min-width here, so the 24/32px box returns; `inline-block` is AntD's own `.ant-btn` display */
    :is(td, th, .ant-table-cell) .ant-btn.ant-btn {
        min-height: unset;
        min-width: unset;
        display: inline-block;
    }

    /* Running text keeps its line (B-051 AD5): a Link/Text button (not icon-only) whose parent is a text container
       flows with the sentence instead of breaking it into a 44px box. Standalone Link/Text buttons (action rows,
       list items, card footers) keep the lift. The same parent list is `RUNNING_TEXT` in mobile-probes.js, which
       exempts these controls (`inRunningText`) — change the two together. Same idiom as the cell reset: `:is()` takes
       its heaviest argument, so parent (0,1,0) + type (0,1,0) + `:not()` (0,1,0) = 0,3,0 over the 0,2,0 lift.
       `min-height: unset` / `height: auto` / `padding: 0` / `inline-block` let the label set the box, as an inline
       link does. Never `li`, `.ant-list-item` or an action row: those are standalone targets */
    :is(p, dd, label, small, .ant-typography, .section-copy, .page-subtitle, .ant-alert-message, .ant-alert-description,
        .ant-form-item-extra, .ant-form-item-explain, .ant-empty-description) > :is(.ant-btn-link, .ant-btn-text):not(.ant-btn-icon-only) {
        min-height: unset;
        height: auto;
        padding: 0;
        display: inline-block;
    }

    /* Inputs, number inputs, pickers. The affix wrapper (prefix/suffix, password) is the 44px box; its inner input
       drops the lift and stretches to the wrapper's content height (AntD: `height: auto` in an inline-flex row).
       The number input's inner <input> is AntD's `height: 30px` (32 minus borders) — 42px keeps the text centred */
    .ant-input,
    .ant-input-affix-wrapper,
    .ant-input-number,
    .ant-picker {
        min-height: 44px;
    }

    .ant-input-affix-wrapper > input.ant-input {
        min-height: 0;
    }

    /* MoneyInput's currency wrapper (`.ant-input-number-affix-wrapper`, 1px border, no padding) is the visible box;
       its borderless inner InputNumber takes 42px so the whole field is 44px, not 44 + 2 */
    .ant-input-number-affix-wrapper > .ant-input-number {
        min-height: 42px;
    }

    .ant-input-number:not(:is(td, th, .ant-table-cell) *) .ant-input-number-input {
        height: 42px;
    }

    /* Selects. AntD fixes the single selector at `height: 32px` with a 30px line-height on the selected item and
       placeholder; the selector is already `display: flex`, so `align-items: center` keeps the text centred at any
       height (AntD sets no align-items on it). The absolutely placed search input (AntD `height: 30px`, 0,4,0) is
       stretched to the selector so a typed query sits on the same line as the selected item. Multiple selectors
       already centre their chips (`align-items: center`) */
    .ant-select-single .ant-select-selector,
    .ant-select-multiple .ant-select-selector {
        min-height: 44px;
    }

    .ant-select-single .ant-select-selector {
        align-items: center;
    }

    .ant-select-single:not(.ant-select-customize-input) .ant-select-selector .ant-select-selection-search .ant-select-selection-search-input {
        height: 100%;
    }

    /* Clickable tags and filter chips: tag links, checkable tags, button-role tags, radio buttons, segmented items.
       AntD's `display: inline-block` (0,1,0) needs the extra class/attribute/element to give way to inline-flex */
    a.ant-tag,
    .ant-tag.ant-tag-checkable,
    .ant-tag[role="button"],
    .ant-radio-button-wrapper.ant-radio-button-wrapper,
    .ant-segmented-item.ant-segmented-item {
        min-height: 44px;
        display: inline-flex;
        align-items: center;
        justify-content: center;
    }

    /* Checkbox and radio: the hit box is the wrapper <label>, not the 16px box. AntD aligns the row on its baseline,
       which in a 44px box pins box and label to the top; centring needs the box's `top: 0.2em` baseline nudge
       removed, or it sits ~3px below its label */
    .ant-checkbox-wrapper.ant-checkbox-wrapper,
    .ant-radio-wrapper.ant-radio-wrapper {
        display: inline-flex;
        align-items: center;
        min-height: 44px;
    }

    .ant-checkbox-wrapper .ant-checkbox,
    .ant-radio-wrapper .ant-radio {
        top: 0;
    }

    /* Pagers: page items, prev/next and the ••• jump items are AntD's fixed 32px boxes (`height`, so the doubled
       class). The table's own mini pager is pinned at 32px with `!important` in overrides.css, the one place this
       block must answer in kind */
    .ant-pagination-item.ant-pagination-item,
    .ant-pagination-prev.ant-pagination-prev,
    .ant-pagination-next.ant-pagination-next,
    .ant-pagination-jump-prev.ant-pagination-jump-prev,
    .ant-pagination-jump-next.ant-pagination-jump-next {
        min-width: 44px;
        height: 44px;
        line-height: 42px;
    }

    .ant-table-pagination.ant-pagination-mini .ant-pagination-item.ant-pagination-item,
    .ant-table-pagination.ant-pagination-mini .ant-pagination-prev.ant-pagination-prev,
    .ant-table-pagination.ant-pagination-mini .ant-pagination-next.ant-pagination-next,
    .ant-table-pagination.ant-pagination-mini .ant-pagination-jump-prev.ant-pagination-jump-prev,
    .ant-table-pagination.ant-pagination-mini .ant-pagination-jump-next.ant-pagination-jump-next,
    .ant-table-pagination.ant-pagination-mini .ant-pagination-prev .ant-pagination-item-link.ant-pagination-item-link,
    .ant-table-pagination.ant-pagination-mini .ant-pagination-next .ant-pagination-item-link.ant-pagination-item-link {
        min-width: 44px !important;
        height: 44px !important;
        line-height: 42px !important;
    }

    /* Switch: the 22px (small: 16px) track stays as drawn — a transparent top/bottom border grows the hit box to 44px
       and `background-clip` keeps the colour inside it. The handle is placed against the padding box, so it does not
       move. In a .switch-field the extra border is taken back from the top margin so the track stays on the label —
       one custom property carries the border, so each size (11px default, 14px small) takes back its own */
    .ant-switch.ant-switch {
        --touch-switch-border: 11px;
        height: 44px;
        border-block: var(--touch-switch-border) solid transparent;
        background-clip: padding-box;
    }

    .ant-switch.ant-switch-small {
        --touch-switch-border: 14px;
    }

    .switch-field > .ant-switch {
        margin-top: calc(var(--space-xs) - var(--touch-switch-border));
    }

    /* Table cells keep their dense rows (AD3, as the button reset above): every other listed control drops the lift.
       `:is()` adds 0,1,0 over each lift selector, and this block comes later */
    :is(td, th, .ant-table-cell) :is(.ant-input, .ant-input-affix-wrapper, .ant-input-number, .ant-picker),
    :is(td, th, .ant-table-cell) .ant-input-number-affix-wrapper > .ant-input-number,
    :is(td, th, .ant-table-cell) :is(.ant-select-single, .ant-select-multiple) .ant-select-selector,
    :is(td, th, .ant-table-cell) :is(a.ant-tag, .ant-tag.ant-tag-checkable, .ant-tag[role="button"]),
    :is(td, th, .ant-table-cell) .ant-radio-button-wrapper.ant-radio-button-wrapper,
    :is(td, th, .ant-table-cell) .ant-segmented-item.ant-segmented-item,
    :is(td, th, .ant-table-cell) .ant-checkbox-wrapper.ant-checkbox-wrapper,
    :is(td, th, .ant-table-cell) .ant-radio-wrapper.ant-radio-wrapper {
        min-height: unset;
    }

    /* A labelled checkbox/radio in a cell keeps AntD's own alignment (B-051 AD6): its wrapper is not 44px tall
       there, so the lift's centring and `top: 0` only take the box off its label's text line. Wrapper: 0,1,0 (`:is()`)
       + 0,1,0 = 0,2,0, equal to the 0,2,0 lift and later, so it wins. Box: `:is()` takes its heaviest argument
       (`.ant-checkbox-wrapper .ant-checkbox`, 0,2,0) + 0,1,0 = 0,3,0 over the 0,2,0 `top: 0`. Outside cells nothing
       changes */
    :is(td, th, .ant-table-cell) :is(.ant-checkbox-wrapper, .ant-radio-wrapper) {
        align-items: baseline;
    }

    :is(td, th, .ant-table-cell) :is(.ant-checkbox-wrapper .ant-checkbox, .ant-radio-wrapper .ant-radio) {
        top: 0.2em;
    }

    :is(td, th, .ant-table-cell) .ant-switch.ant-switch {
        --touch-switch-border: 0px;
        height: 22px;
        border-block-width: 0;
    }

    :is(td, th, .ant-table-cell) .ant-switch.ant-switch-small {
        height: 16px;
    }
}

/* --- Responsive: Small mobile (480px) — playground utilities --- */
@media (max-width: 480px) {
    .pg-controls-row {
        gap: var(--space-sm);
    }
}

/* Responsive - Mobile */
@media (max-width: 576px) {
    .page-wrapper {
        padding: var(--space-md);
    }

    .page-header {
        padding: var(--space-md);
    }

    .page-title {
        font-size: 1.5rem;
    }

    .page-subtitle {
        font-size: 0.875rem;
    }
}

/* =====================================================================================================
   SnipePrice Core — rate semantics, charts and tooltip (D1). Shared by the rate calendar, night drawer,
   dashboard and insights. Colour meaning (owner's point of view), never the brand orange for good/bad:
     competitor cheaper than me = threat  → error hue   (.rate-threat-1…3)
     competitor dearer than me  = room     → success hue (.rate-opportunity-1…3)
     my position vs comp median            → info (below) / neutral (at) / warning (above)
   Orange (--rate-mine) only ever means "my hotel / my price".
   The tokens (--rate-*, --position-*, --chart-*, --shadow-float/-lift/-pinned-edge and the status -rgb triplets) are
   theme-dependent and live in the dark and light blocks at the top of this file (I-021 AD3).
   ===================================================================================================== */

/* Competitor cell tints (grid, drawer, dashboard). Text keeps the threat/opportunity hue for contrast on tint. */
.rate-threat-1 { background: var(--rate-threat-bg-1); }
.rate-threat-2 { background: var(--rate-threat-bg-2); }
.rate-threat-3 { background: var(--rate-threat-bg-3); }
.rate-opportunity-1 { background: var(--rate-opportunity-bg-1); }
.rate-opportunity-2 { background: var(--rate-opportunity-bg-2); }
.rate-opportunity-3 { background: var(--rate-opportunity-bg-3); }
.rate-text--threat { color: var(--rate-threat-text); }
.rate-text--opportunity { color: var(--rate-opportunity-text); }
.rate-text--muted { color: var(--text-muted); }
.rate-text--mine { color: var(--rate-mine-text); }

/* Numbers that line up in columns. */
.tabular-nums {
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}

/* "Sold out" pill — neutral on purpose (sold out is information, not a threat). */
.rate-pill {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 1px 8px;
    border-radius: 999px;
    font-family: var(--font-mono);
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    line-height: 1.5;
    white-space: nowrap;
    color: var(--text-secondary);
    background: var(--glass-bg-light);
    border: 1px solid var(--glass-border);
}

.rate-pill--sold-out {
    color: var(--rate-sold-out-text);
    text-transform: uppercase;
}

/* A market event is information (F --event), not "mine" (I-021 AD6) */
.rate-pill--event {
    color: var(--color-event-text);
    background: transparent;
    border-color: var(--color-event);
}

/* My position vs comp median (month view, dashboard strip, legend swatches). */
.position-below { background: var(--position-below-bg); border-color: var(--position-below-border); }
.position-at { background: var(--position-at-bg); border-color: var(--position-at-border); }
.position-above { background: var(--position-above-bg); border-color: var(--position-above-border); }
.position-none { background: transparent; border-color: var(--glass-border); border-style: dashed; }
.position-text--below { color: var(--position-below-text); }
.position-text--above { color: var(--position-above-text); }

/* Chart series tones — LineChart lines/dots/swatches and any legend that names a series. */
.chart-tone--mine { --chart-color: var(--rate-mine); }
.chart-tone--median { --chart-color: var(--chart-median); }
.chart-tone--recommended { --chart-color: var(--color-primary-accent); }
.chart-tone--cat-1 { --chart-color: var(--chart-cat-1); }
.chart-tone--cat-2 { --chart-color: var(--chart-cat-2); }
.chart-tone--cat-3 { --chart-color: var(--chart-cat-3); }
.chart-tone--cat-4 { --chart-color: var(--chart-cat-4); }
.chart-tone--cat-5 { --chart-color: var(--chart-cat-5); }
.chart-tone--cat-6 { --chart-color: var(--chart-cat-6); }

/* Floating tooltip driven by js/snipe-tooltip.js (data-tip attributes). */
.snipe-tip {
    position: fixed;
    z-index: 2000;
    max-width: 280px;
    padding: 8px 10px;
    border-radius: var(--radius-sm);
    background: var(--color-bg-elevated);
    border: 1px solid var(--glass-border-light);
    box-shadow: var(--shadow-tooltip);
    color: var(--text-secondary);
    font-size: 0.75rem;
    line-height: 1.45;
    pointer-events: none;
    opacity: 0;
    transform: translateY(2px);
    transition: opacity 120ms ease, transform 120ms ease;
    font-variant-numeric: tabular-nums;
}

.snipe-tip--visible {
    opacity: 1;
    transform: translateY(0);
}

.snipe-tip__title {
    color: var(--text-primary);
    font-weight: 600;
    margin-bottom: 2px;
}

/* Plan badge classes. The top bar's WorkspacePlanBadge is now F's .tag / .tag--plan ("Shell (I-024)" below, which come
   later and win); these rules still style the plan chip on the Team & plan, Property settings and checkout pages until
   their own redesign items. */
.plan-badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    line-height: 1.5; /* the AntD header sets a 64px line-height */
}

.plan-badge__tier {
    padding: 2px 10px;
    border-radius: 999px;
    font-size: 0.75rem;
    font-weight: 600;
    border: 1px solid var(--glass-border-light);
    color: var(--text-secondary);
    background: var(--glass-bg-light);
}

.plan-badge__tier--starter {
    color: var(--color-tier-starter);
    background: var(--color-tier-starter-bg);
    border-color: transparent;
}

.plan-badge__tier--pro {
    color: var(--color-tier-pro);
    background: var(--color-tier-pro-bg);
    border-color: transparent;
}

.plan-badge__demo {
    padding: 2px 8px;
    border-radius: 999px;
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-on-primary);
    background: var(--color-primary-300);
}

@media (prefers-reduced-motion: reduce) {
    .snipe-tip { transition: none; }
}

/* Market range bar (RangeBar component + the rate grid's inline copy). */
.range-bar {
    position: relative;
    display: inline-block;
    width: 100%;
    min-width: 72px;
    height: 14px;
    vertical-align: middle;
}

.range-bar__track {
    position: absolute;
    left: 0;
    right: 0;
    top: 5px;
    height: 4px;
    border-radius: 999px;
    background: linear-gradient(90deg, var(--rate-threat-bg-3), var(--glass-border-light) 50%, var(--rate-opportunity-bg-3));
}

.range-bar__median {
    position: absolute;
    top: 2px;
    width: 2px;
    height: 10px;
    margin-left: -1px;
    border-radius: 999px;
    background: var(--chart-median);
}

.range-bar__mine {
    position: absolute;
    top: 2px;
    width: 10px;
    height: 10px;
    margin-left: -5px;
    border-radius: 50%;
    background: var(--rate-mine);
    box-shadow: 0 0 0 2px var(--color-bg-dark);
}

.range-bar__mine--outside {
    background: transparent;
    border: 2px solid var(--rate-mine);
}

.range-bar--empty .range-bar__track,
.range-bar--empty {
    opacity: 0.4;
}

/* Position strip: one cell per night coloured by my position vs the comp median (dashboard cards, insights). */
.position-strip {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: minmax(0, 1fr);
    gap: 3px;
}

.position-strip__cell {
    height: 22px;
    border-radius: var(--radius-xs);
    border: 1px solid transparent;
    padding: 0;
    cursor: default;
}

.position-strip__cell--clickable {
    cursor: pointer;
}

.position-strip__cell--clickable:hover,
.position-strip__cell--clickable:focus-visible {
    outline: 2px solid var(--glass-border-light);
    outline-offset: 1px;
}

/* Data freshness ("Updated 3 h ago") — FreshnessIndicator. */
/* F .fresh (I-033 TASK_01, f.src.html 819-821): 400 12px mono in --text-2 with a 7px gap; a plain 7px status dot (ok;
   amber when stale) with no halo */
.freshness {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    font: 400 12px var(--font-mono);
    color: var(--text-secondary);
    white-space: nowrap;
}

.freshness__dot {
    flex: none;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--color-success);
}

.freshness--stale {
    color: var(--color-warning-light);
}

.freshness--stale .freshness__dot {
    background: var(--color-warning);
}

.freshness--refreshing .freshness__dot {
    background: var(--color-info);
    box-shadow: 0 0 0 3px var(--color-info-bg);
    animation: freshnessPulse 1.2s ease-in-out infinite;
}

@keyframes freshnessPulse {
    0%, 100% { opacity: 1; transform: scale(1); }
    50% { opacity: 0.45; transform: scale(0.8); }
}

/* Plan limit / locked-feature hint — PlanLimitHint. */
/* Plan limit / locked-feature hint — PlanLimitHint. F .planhint (I-033 TASK_01, f.src.html 769, 937, 1068-1073): muted
   12.5px with a 6px gap; the card is a dashed --line-2 panel on --panel-2, 10px 12px, 10px radius, 13px --text-2. The
   "Contact us" link is F's neutral .planhint a (--text-2, 500): a lock is never orange (README D-i). */
.plan-hint {
    display: inline-flex;
    align-items: flex-start;
    gap: 6px;
    font-size: 12.5px;
    line-height: 1.5;
    color: var(--text-muted);
}

.plan-hint--card {
    display: flex;
    gap: 8px;
    padding: 10px 12px;
    border-radius: 10px;
    border: 1px dashed var(--glass-border-light);
    background: var(--glass-bg-subtle);
    color: var(--text-secondary);
    font-size: 13px;
}

.plan-hint__icon {
    flex: none;
    margin-top: 3px;
}

.plan-hint--card .plan-hint__icon {
    margin-top: 2px;
}

.plan-hint__link {
    color: var(--text-secondary);
    font-weight: 500;
}

/* (0,2,0): overrides.css's a:hover:where(…) (0,1,1) would turn the neutral link orange on hover — a lock is never orange */
.plan-hint__link:hover,
.plan-hint__link:active {
    color: var(--text-secondary);
}

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

/* =====================================================================================================
   SnipePrice Core — page vocabulary (D2). Shared by the dashboard, insights, competitors, alerts, events,
   property settings and team pages. Same colour rules as the block above: orange only means "mine".
   ===================================================================================================== */

/* Small uppercase label above a property page title ("RATE INSIGHTS"). */
.core-eyebrow {
    display: block;
    margin-bottom: 4px;
    font-family: var(--font-mono);
    font-size: var(--type-label);
    font-weight: var(--type-label-weight);
    letter-spacing: var(--type-label-tracking);
    text-transform: uppercase;
    /* F .lab: a label is muted, never orange (I-021 AD6) */
    color: var(--text-muted);
}

.core-subtitle {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 10px;
}

.core-sep {
    color: var(--text-muted);
}

/* KPI strip — one glass surface split into 4 (or 5) labelled figures with a plain-language hint. Promoted from
   CalendarKpiStrip so the dashboard and insights share it. */
.kpi-strip {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    padding: 0;
    overflow: hidden;
}

.kpi-strip--5 {
    grid-template-columns: repeat(5, minmax(0, 1fr));
}

.kpi-strip__item {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 16px 20px;
    border-left: 1px solid var(--glass-border);
    min-width: 0;
}

.kpi-strip__item:first-child {
    border-left: 0;
}

.kpi-strip__label {
    font-family: var(--font-mono);
    font-size: var(--type-label);
    font-weight: var(--type-label-weight);
    letter-spacing: var(--type-label-tracking);
    text-transform: uppercase;
    color: var(--text-muted);
}

.kpi-strip__value {
    font-family: var(--font-mono);
    font-size: 1.625rem;
    font-weight: 600;
    line-height: 1.15;
    color: var(--text-primary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.kpi-strip__value--text {
    font-size: 1.125rem;
    line-height: 1.6;
}

.kpi-strip__of {
    margin-left: 6px;
    font-family: var(--font-mono);
    font-size: 0.8125rem;
    font-weight: 500;
    color: var(--text-muted);
}

.kpi-strip__hint {
    font-size: 0.75rem;
    color: var(--text-secondary);
    line-height: 1.4;
}

@media (max-width: 1200px) {
    .kpi-strip--5 {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }

    .kpi-strip--5 .kpi-strip__item:nth-child(4) {
        border-left: 0;
    }

    .kpi-strip--5 .kpi-strip__item:nth-child(n + 4) {
        border-top: 1px solid var(--glass-border);
    }
}

@media (max-width: 992px) {
    .kpi-strip,
    .kpi-strip--5 {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .kpi-strip .kpi-strip__item:nth-child(odd) {
        border-left: 0;
    }

    .kpi-strip .kpi-strip__item:nth-child(even) {
        border-left: 1px solid var(--glass-border);
    }

    .kpi-strip .kpi-strip__item:nth-child(n + 3) {
        border-top: 1px solid var(--glass-border);
    }
}

@media (max-width: 480px) {
    .kpi-strip__item {
        padding: 12px 14px;
    }

    .kpi-strip__value {
        font-size: 1.25rem;
    }
}

/* Hotel photo thumbnail with an initial fallback (competitor rows, dashboard cards, insights table). */
.hotel-avatar {
    position: relative;
    display: inline-flex;
    flex-shrink: 0;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border-radius: 10px;
    overflow: hidden;
    /* F .av (I-033 TASK_01, f.src.html 195-199): --panel-3 with a --line edge, --text-2 initials in 600 mono; the
       component's sizes stay (28 / 40 / 56 — F's 26 / 30 / 32 / 38 scale is the opt-in .hotel-avatar--s* below) */
    background: var(--color-panel-3);
    border: 1px solid var(--glass-border);
    color: var(--text-secondary);
    font-family: var(--font-mono);
    font-weight: 600;
}

.hotel-avatar img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.hotel-avatar--sm {
    width: 28px;
    height: 28px;
    font-size: 0.75rem;
    border-radius: 7px;
}

.hotel-avatar--lg {
    width: 56px;
    height: 56px;
    font-size: 1.25rem;
}

.hotel-avatar--mine {
    border-color: var(--rate-mine-border);
    background: var(--rate-mine-bg);
    color: var(--color-primary-text); /* F .av--mine --primary-text in both themes (I-033 TASK_07 fidelity) */
}

/* Card title row: title + muted meta on the left, actions on the right. */
.core-card-head {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-sm) var(--space-md);
    margin-bottom: var(--space-md);
}

.core-card-title {
    margin: 0;
    font-family: var(--font-display);
    font-size: var(--type-panel-title);
    font-weight: var(--type-panel-title-weight);
    color: var(--text-primary);
}

.core-card-sub {
    margin: 2px 0 0;
    font-size: 0.8125rem;
    color: var(--text-muted);
}

.core-card-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-xs);
}

/* Position chip: my price vs the comp median (Below / At market / Above). F .chip (I-033 TASK_01, f.src.html 209-210):
   a borderless 20px chip, 6px sides, a 4px radius, 500 10.5px mono in --text-2 on the position ground (.position-*);
   below reads info blue, above amber, at market and no data neutral (the command palette's chip is the same look). */
.position-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    height: 20px;
    padding: 0 6px;
    border-radius: var(--radius-xs);
    border: 0;
    font: 500 10.5px var(--font-mono);
    white-space: nowrap;
    color: var(--text-secondary);
}

.position-chip.position-below { color: var(--position-below-text); }
.position-chip.position-above { color: var(--position-above-text); }
.position-chip.position-none { background: var(--chart-shade); }

/* Alert type tones on the notification-card icon (threat = a competitor got cheaper, opportunity = room to raise,
   market = the median moved). Orange stays reserved for "mine". */
.notification-card__icon.alert-tone--threat {
    background: rgba(var(--color-error-rgb), 0.12);
    color: var(--rate-threat-text);
}

.notification-card__icon.alert-tone--opportunity {
    background: rgba(var(--color-success-rgb), 0.12);
    color: var(--rate-opportunity-text);
}

.notification-card__icon.alert-tone--market {
    background: rgba(var(--color-info-rgb), 0.14);
    color: var(--color-info-light);
}

.notification-card__icon.alert-tone--demand {
    background: rgba(var(--color-warning-rgb), 0.14);
    color: var(--color-warning-light);
}

/* A plain callout row with a tone icon (Team settings' "you're alone" note; Insights uses F's ul.callouts, I-029). */
.core-callout {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 12px 14px;
    border-radius: var(--radius-md);
    border: 1px solid var(--glass-border);
    background: var(--glass-bg-subtle);
    font-size: 0.875rem;
    line-height: 1.5;
    color: var(--text-secondary);
}

.core-callout strong {
    color: var(--text-primary);
    font-weight: 600;
}

.core-callout__icon {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: var(--radius-sm);
    background: var(--glass-bg-light);
    color: var(--text-secondary);
}

.core-callout--info .core-callout__icon {
    background: rgba(var(--color-info-rgb), 0.14);
    color: var(--color-info-light);
}

/* Read-only definition rows (viewer faces, Booking.com listing). */
.core-facts {
    display: grid;
    grid-template-columns: minmax(120px, max-content) 1fr;
    gap: 8px var(--space-lg);
    margin: 0;
    font-size: 0.875rem;
}

.core-facts dt {
    color: var(--text-muted);
}

.core-facts dd {
    margin: 0;
    color: var(--text-primary);
    min-width: 0;
    overflow-wrap: anywhere;
}

/* Market event modal: the RangePicker's two-month popup is wider than the modal and renders inside it, so the modal
   content must not clip it (overrides.css gives .ant-modal-content overflow: hidden; its header/footer are transparent,
   so the rounded corners do not need the clip here). */
.event-form-modal .ant-modal-content {
    overflow: visible;
}

/* =====================================================================================================
   Shell (I-024) — prototype F's app shell (f.src.html CSS 93-235 + the 899px / 640px blocks), global so the
   playgrounds (/design-system/playground/shell, /property-picker, /top-bar; F-176: no scoped CSS) and the product
   components (MainLayout, NavMenu, PropertyPicker, the top bar) share ONE definition (I-024 D-j). AntD internals
   (Sider children, Menu items and group titles, Popover / Dropdown inner, Breadcrumb) live in overrides.css
   "Shell (I-024)". Tokens only — F roles: --panel = --glass-bg, --panel-2 = --glass-bg-light, --panel-3 =
   --color-panel-3, --line = --glass-border, --line-2 = --glass-border-light, --text-2 = --text-secondary,
   --muted = --text-muted, --r-sm = --radius-md, --r-xs = --radius-sm, --shadow = --shadow-popup, --mask = --color-mask.
   Orange only means "mine": the current property's avatar (.av--mine), the active nav icon, the plan tag.
   ===================================================================================================== */

/* Root of a shell: the sider + the main column. Positioned, so the < 900px off-canvas sider and its mask sit in it. */
.shell {
    position: relative;
    display: flex;
    min-height: 0;
    overflow: hidden;
}

.shell__main {
    flex: 1;
    min-width: 0;
    min-height: 0;
    display: flex;
    flex-direction: column;
}

/* --- Sidebar: 256px, F .sb ------------------------------------------------------------------------------------- */
.shell-sider {
    display: flex;
    flex-direction: column;
    min-height: 0;
    background: var(--glass-bg);
    border-right: 1px solid var(--glass-border);
    z-index: 20;
}

.shell-sider__top {
    height: 56px;
    flex: none;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 0 10px 0 18px;
    border-bottom: 1px solid var(--glass-border);
}

.shell-sider__logo {
    display: inline-flex;
    align-items: center;
    text-decoration: none;
}

/* Height only: display stays with the theme-logo--dark / --light swap */
.shell-sider__logo img {
    height: 24px;
}

/* Scoped under .shell-sider / .top-bar so they outrank .icon-btn's display */
.shell-sider__logo-icon,
.shell-sider .shell-sider__close {
    display: none;
}

.shell-sider__scroll {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    overflow-x: hidden;
    padding: 8px 6px 10px;
    display: flex;
    flex-direction: column;
    gap: 1px;
    scrollbar-width: thin;
}

/* Group label — F .sb__lab (.lab: 500 10.5px mono uppercase, muted). The AntD MenuItemGroup title gets the same look in
   overrides.css; this class is for a label outside a Menu. */
.shell-nav__group {
    padding: 14px 8px 5px;
    font: 500 10.5px/1.3 var(--font-mono);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.shell-nav__group:first-child {
    padding-top: 8px;
}

/* Nav item — F .nv: 34px, 500 13.5px, --text-2; hover / active --panel-3; active 600 + the icon in --primary-text.
   No ::before / ::after bar: the active state is the surface and the orange icon only. */
.shell-nav__item {
    position: relative;
    width: 100%;
    display: flex;
    align-items: center;
    gap: 10px;
    height: 34px;
    padding: 0 8px 0 10px;
    border-radius: var(--radius-md);
    background: none;
    color: var(--text-secondary);
    font: 500 13.5px var(--font-body);
    text-align: left;
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
}

.shell-nav__item:hover {
    background: var(--color-panel-3);
    color: var(--text-primary);
}

.shell-nav__item:focus-visible {
    outline: none;
    box-shadow: 0 0 0 2px var(--color-focus-ring);
}

.shell-nav__item .anticon {
    flex: none;
    font-size: 17px;
    color: var(--text-muted);
}

/* F .nv .ic weight (I-037 D-g): AntD's Outline glyphs are fill paths, so a stroke in the glyph's own colour thickens
   them evenly without changing the shape (paint-order keeps the fill on top). The rail and the narrow drawer reuse the
   item, so they inherit it. */
.shell-nav__item .anticon svg {
    stroke: currentColor;
    stroke-width: var(--nav-icon-stroke);
    paint-order: stroke;
}

.shell-nav__item[aria-current="page"] {
    background: var(--color-panel-3);
    color: var(--text-primary);
    font-weight: 600;
}

.shell-nav__item[aria-current="page"] .anticon {
    color: var(--color-primary-text);
}

.shell-nav__label {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Bottom collapse row — F .sb__bot (34px icon button at the right, ≥ 900px only). */
.shell-sider__bottom {
    flex: none;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    padding: 8px 10px;
    border-top: 1px solid var(--glass-border);
}

/* --- Icon rail: 64px, F .app.is-collapsed ----------------------------------------------------------------------- */
.shell-sider.is-rail .shell-sider__top {
    justify-content: center;
    padding: 0;
}

.shell-sider.is-rail .shell-sider__logo-full {
    display: none;
}

.shell-sider.is-rail .shell-sider__logo-icon {
    display: inline-flex;
}

.shell-sider.is-rail .shell-sider__scroll {
    padding: 8px 8px 10px;
}

/* Labels become 1px dividers; the first one (above the first group) goes */
.shell-sider.is-rail .shell-nav__group {
    font-size: 0;
    height: 1px;
    padding: 0;
    margin: 9px 6px;
    background: var(--glass-border);
}

.shell-sider.is-rail .shell-nav__group:first-child {
    display: none;
}

.shell-sider.is-rail .shell-nav__label,
.shell-sider.is-rail .shell-nav__item .badge-neutral,
.shell-sider.is-rail .property-picker__text,
.shell-sider.is-rail .property-picker__chevron,
.shell-sider.is-rail .property-picker__trigger .badge-neutral {
    display: none;
}

.shell-sider.is-rail .shell-nav__item {
    justify-content: center;
    padding: 0;
}

.shell-sider.is-rail .property-picker__trigger {
    justify-content: center;
    padding: 0;
    min-height: 44px;
    border-color: transparent;
    background: none;
}

/* The current property's avatar keeps an orange ring in the rail ("mine") */
.shell-sider.is-rail .property-picker__trigger .av,
.property-picker__trigger--rail .av {
    box-shadow: 0 0 0 2px var(--glass-bg), 0 0 0 3.5px var(--color-primary);
}

/* A hidden count becomes a 7px dot (F [data-dot]::after) */
.shell-sider.is-rail [data-dot] {
    position: relative;
}

.shell-sider.is-rail [data-dot]::after {
    content: '';
    position: absolute;
    top: 5px;
    right: 9px;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--color-badge-bg);
    box-shadow: 0 0 0 2px var(--glass-bg);
}

.shell-sider.is-rail .shell-sider__bottom {
    justify-content: center;
    padding: 8px 0;
}

/* --- Below 900px: the sider goes off-canvas, F @media (max-width: 899px) .sb ----------------------------------------
   ONE definition for both triggers (PR 736 #11692): the playground's "Narrow" toggle (.shell.is-narrow) and the real
   viewport (html.is-narrow-shell, set by js/device-service.js shellBreakpoint from the one media query that also drives
   IDeviceService.IsNarrowShell — PR 736 #11704; no CSS restates the break, tests/scripts/shell-breakpoint.test.js).
   Each rule's second selector keeps the old media-query specificity: :where() adds nothing. The rail is ignored here. */
.nav-mask {
    display: none;
    position: absolute;
    inset: 0;
    z-index: 61;
    background: var(--color-mask);
}

.top-bar .top-bar__burger {
    display: none;
}

.shell.is-narrow .shell-sider,
:where(.is-narrow-shell) .shell .shell-sider {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    z-index: 62;
    width: min(300px, 86vw);
    min-width: 0;
    max-width: none;
    flex: none;
    visibility: hidden;
    transform: translateX(-100%);
    transition: transform 0.18s ease-out, visibility 0s 0.18s;
    padding-bottom: env(safe-area-inset-bottom, 0px);
}

.shell.is-narrow.nav-open .shell-sider,
:where(.is-narrow-shell) .shell.nav-open .shell-sider {
    visibility: visible;
    transform: none;
    transition: transform 0.18s ease-out;
    box-shadow: var(--shadow-popup);
}

.shell.is-narrow.nav-open .nav-mask,
:where(.is-narrow-shell) .shell.nav-open .nav-mask {
    display: block;
}

.shell.is-narrow .shell-sider .shell-sider__close,
:where(.is-narrow-shell) .shell .shell-sider .shell-sider__close {
    display: inline-grid;
}

.shell.is-narrow .shell-sider__bottom,
:where(.is-narrow-shell) .shell .shell-sider__bottom {
    display: none;
}

.shell.is-narrow .top-bar,
:where(.is-narrow-shell) .top-bar {
    gap: 10px;
}

.shell.is-narrow .top-bar .top-bar__burger,
:where(.is-narrow-shell) .top-bar .top-bar__burger {
    display: inline-grid;
    margin-left: -6px;
}

.shell.is-narrow .command-field kbd,
:where(.is-narrow-shell) .command-field kbd {
    display: none;
}

/* --- Property picker: F .psw / .pswpop / .popt ---------------------------------------------------------------------- */
.property-picker {
    position: relative;
}

.property-picker__trigger {
    position: relative;
    width: 100%;
    display: flex;
    align-items: center;
    gap: 8px;
    min-height: 54px;
    padding: 7px 6px 7px 7px;
    margin-bottom: 4px;
    border: 1px solid var(--glass-border-light);
    border-radius: var(--radius-md);
    background: var(--glass-bg);
    color: var(--text-primary);
    font: inherit;
    text-align: left;
    cursor: pointer;
}

.property-picker__trigger:hover,
.property-picker__trigger[aria-expanded="true"] {
    border-color: var(--text-secondary);
}

.property-picker__trigger:focus-visible {
    outline: none;
    box-shadow: 0 0 0 2px var(--color-focus-ring);
}

/* Rail variant: the avatar alone, 44px, no border (the orange ring is in the rail block above) */
.property-picker__trigger--rail {
    justify-content: center;
    width: 44px;
    min-height: 44px;
    padding: 0;
    border-color: transparent;
    background: none;
}

.property-picker__trigger--rail .property-picker__text,
.property-picker__trigger--rail .property-picker__chevron,
.property-picker__trigger--rail .badge-neutral {
    display: none;
}

.property-picker__text {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    line-height: 1.3;
}

.property-picker__row {
    display: flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
}

.property-picker__name {
    min-width: 0;
    font-weight: 600;
    font-size: 13.5px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.property-picker__meta {
    font: 400 10.5px var(--font-mono);
    color: var(--text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.property-picker__chevron {
    flex: none;
    color: var(--text-muted);
}

/* The popover body: 320px, radius 12px, F --shadow. Rendered inside an AntD Popover overlay (portal), whose own
   chrome overrides.css removes (.property-picker-overlay), or inline below 900px (--inline). */
.property-picker__popover {
    width: 320px;
    max-width: calc(100vw - 24px);
    display: flex;
    flex-direction: column;
    background: var(--glass-bg);
    border: 1px solid var(--glass-border-light);
    border-radius: 12px;
    box-shadow: var(--shadow-popup);
    color: var(--text-primary);
}

.property-picker__popover--inline {
    width: auto;
    max-width: none;
    margin: 0 0 6px;
    box-shadow: none;
}

.property-picker__head {
    padding: 10px 12px 6px;
    font: 500 10.5px/1.3 var(--font-mono);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-muted);
}

.property-picker__search {
    position: relative;
    padding: 0 8px 8px;
}

.property-picker__search-icon {
    position: absolute;
    left: 19px;
    top: 10px;
    z-index: 1;
    color: var(--text-muted);
    pointer-events: none;
}

.property-picker__list {
    flex: 1;
    min-height: 0;
    max-height: 340px;
    overflow-y: auto;
    margin: 0;
    padding: 6px;
    list-style: none;
    border-top: 1px solid var(--glass-border);
}

.property-picker__option {
    width: 100%;
    display: flex;
    align-items: center;
    gap: 10px;
    min-height: 44px;
    padding: 5px 8px;
    border-radius: var(--radius-md);
    color: var(--text-primary);
    cursor: pointer;
}

.property-picker__option:hover {
    background: var(--glass-bg-light);
}

.property-picker__option.is-active {
    background: var(--color-panel-3);
}

.property-picker__option-text {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    line-height: 1.3;
}

.property-picker__option-name {
    font-weight: 600;
    font-size: 13.5px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.property-picker__option-meta {
    font: 400 11px var(--font-mono);
    color: var(--text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.property-picker__check {
    flex: none;
    width: 15px;
    display: inline-grid;
    color: var(--color-primary-text);
}

.property-picker__trigger .badge-neutral,
.property-picker__option .badge-neutral {
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    font-size: 10px;
}

.property-picker__add {
    width: 100%;
    display: flex;
    align-items: center;
    gap: 10px;
    min-height: 40px;
    padding: 0 14px;
    border: 0;
    border-top: 1px solid var(--glass-border);
    border-radius: 0 0 12px 12px;
    background: none;
    color: var(--text-secondary);
    font: 500 13.5px var(--font-body);
    text-align: left;
    cursor: pointer;
}

.property-picker__add .anticon {
    color: var(--text-muted);
}

.property-picker__add:hover {
    background: var(--glass-bg-light);
    color: var(--text-primary);
}

.property-picker__add.is-active {
    background: var(--color-panel-3);
    color: var(--text-primary);
}

.property-picker__limit {
    padding: 10px 14px;
    border-top: 1px solid var(--glass-border);
    font-size: 12.5px;
    line-height: 1.45;
    color: var(--text-muted);
}

.property-picker__none {
    padding: 16px 10px;
    text-align: center;
    color: var(--text-muted);
    font-size: 13px;
}

/* --- Top bar: F .hd -------------------------------------------------------------------------------------------- */
.top-bar {
    flex: none;
    position: relative;
    z-index: 30;
    height: 56px;
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 0 var(--space-lg);
    background: var(--glass-bg);
    border-bottom: 1px solid var(--glass-border);
}

/* Breadcrumb — F .crumb ol: 500 13px muted, "/" in --line-2, the current crumb 600 --text. Plain text, not links.
   The AntD Breadcrumb's own spans (separator, current crumb, below 900px only the last crumb) are in overrides.css. */
.top-bar__crumb {
    flex: 0 1 auto;
    min-width: 0;
    font: 500 13px var(--font-body);
    color: var(--text-muted);
    white-space: nowrap;
}

/* Search trigger — F .cmdk: flex 0 1 360px, 34px, --panel-2 + --line-2 */
.command-field {
    flex: 0 1 360px;
    min-width: 120px;
    margin-left: auto;
    height: 34px;
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 0 6px 0 11px;
    border: 1px solid var(--glass-border-light);
    border-radius: var(--radius-md);
    background: var(--glass-bg-light);
    color: var(--text-muted);
    font: 400 13.5px var(--font-body);
    text-align: left;
    cursor: pointer;
}

.command-field:hover {
    border-color: var(--text-secondary);
    color: var(--text-secondary);
}

.command-field:focus-visible {
    outline: none;
    box-shadow: 0 0 0 2px var(--color-focus-ring);
}

.command-field .anticon {
    flex: none;
}

.command-field__placeholder {
    flex: 1;
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.command-field kbd {
    font: 500 10.5px/1 var(--font-mono);
    padding: 3px 5px;
    border-radius: var(--radius-xs);
    border: 1px solid var(--glass-border-light);
    border-bottom-width: 2px;
    color: var(--text-secondary);
    background: var(--glass-bg);
}

.top-bar__actions {
    flex: none;
    display: flex;
    align-items: center;
    gap: 10px;
}

/* 34 × 34 icon button — F .iconbtn (the bell, the burger, the sider close / collapse buttons) */
.icon-btn {
    position: relative;
    flex: none;
    display: inline-grid;
    place-items: center;
    width: 34px;
    height: 34px;
    padding: 0;
    border: 1px solid transparent;
    border-radius: var(--radius-md);
    background: none;
    color: var(--text-secondary);
    font-size: 17px;
    cursor: pointer;
}

.icon-btn:hover {
    background: var(--color-panel-3);
    color: var(--text-primary);
}

.icon-btn:focus-visible {
    outline: none;
    box-shadow: 0 0 0 2px var(--color-focus-ring);
}

.icon-btn .badge-neutral {
    position: absolute;
    top: -3px;
    right: -5px;
}

/* Status: the dot only — the text is the .visually-hidden utility (read by screen readers, shown by the Tooltip and the
   avatar menu). */
.top-bar__status {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    height: 34px;
    padding: 0 8px;
    border-radius: var(--radius-md);
    text-decoration: none;
}

.top-bar__status:hover {
    background: var(--color-panel-3);
}

/* The status dot — the ONE definition of the five states (PR 736 #11705), used by the top-bar StatusIndicator, the
   avatar menu's status line and the playgrounds. Partial outage is bad news, so never brand orange — orange only means
   "mine" (REDESIGN_PROGRAM.md § 2) — and it is told apart from Major outage by SHAPE, not by a second red: a hollow ring
   (2px --color-error border, transparent fill) against Major outage's solid --color-error dot (I-021 PR 720 #11488,
   user decision A; kept by I-024 D-a). Operational adds F's 3px --ok ring. tests/scripts/status-indicator-dots.test.js
   pins the ring, the colour distances and that no other stylesheet re-declares a dot. */
.status-dot {
    flex: none;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    transition: background-color var(--transition-base);
}

.dot-operational {
    background-color: var(--color-success);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-success) 22%, transparent);
}

.dot-degraded {
    background-color: var(--color-warning);
}

.dot-partial-outage {
    box-sizing: border-box;
    background-color: transparent;
    border: 2px solid var(--color-error);
}

.dot-major-outage {
    background-color: var(--color-error);
}

.dot-unknown {
    background-color: var(--text-disabled);
}

/* The live indicator pulses while something is wrong (faster the worse); the avatar menu's line and the playgrounds'
   static dots do not */
.status-indicator .dot-degraded {
    animation: status-dot-pulse 2s ease-in-out infinite;
}

.status-indicator .dot-partial-outage {
    animation: status-dot-pulse 1.5s ease-in-out infinite;
}

.status-indicator .dot-major-outage {
    animation: status-dot-pulse 1s ease-in-out infinite;
}

@keyframes status-dot-pulse {
    0%, 100% {
        opacity: 1;
        transform: scale(1);
    }
    50% {
        opacity: 0.6;
        transform: scale(1.3);
    }
}

@media (prefers-reduced-motion: reduce) {
    .status-indicator .dot-degraded,
    .status-indicator .dot-partial-outage,
    .status-indicator .dot-major-outage {
        animation: none;
    }
}

/* Plan tags — F .plan: the plan (.tag--plan, orange = "mine") + a neutral Demo tag */
.plan-tags {
    display: inline-flex;
    gap: 4px;
}

.tag {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    height: 22px;
    padding: 0 7px;
    border-radius: var(--radius-sm);
    border: 1px solid var(--glass-border-light);
    background: var(--glass-bg-light);
    color: var(--text-secondary);
    font: 500 11.5px/1 var(--font-mono);
    white-space: nowrap;
}

.tag--plan {
    color: var(--color-primary-text);
    border-color: var(--color-primary-line);
    background: var(--color-primary-bg);
}

/* Avatar button — F .avbtn */
.user-avatar {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 4px 2px 2px;
    border: 1px solid transparent;
    border-radius: 10px;
    background: none;
    color: var(--text-muted);
    cursor: pointer;
}

.user-avatar:hover,
.user-avatar[aria-expanded="true"] {
    border-color: var(--glass-border-light);
}

.user-avatar:focus-visible {
    outline: none;
    box-shadow: 0 0 0 2px var(--color-focus-ring);
}

/* Avatar — F .av: 30px initials, radius 8, 600 11px mono; --mine = the current property (orange), --md 32, --lg 38 */
.av {
    flex: none;
    display: inline-grid;
    place-items: center;
    width: 30px;
    height: 30px;
    border-radius: var(--radius-md);
    border: 1px solid var(--glass-border);
    background: var(--color-panel-3);
    color: var(--text-secondary);
    font: 600 11px/1 var(--font-mono);
    letter-spacing: 0.02em;
}

.av--mine {
    background: var(--color-primary-bg);
    color: var(--color-primary-text);
    border-color: var(--color-primary-line);
}

.av--md {
    width: 32px;
    height: 32px;
    font-size: 11px;
}

.av--lg {
    width: 38px;
    height: 38px;
    border-radius: 10px;
    font-size: 12.5px;
}

/* Neutral count badge — F .badge (I-024 D-p): --color-badge-bg / --color-badge-fg, 18px, radius 9px, 600 10.5px mono.
   One style for the nav alerts count, the picker counts and the bell. Never orange. */
.badge-neutral {
    flex: none;
    display: inline-grid;
    place-items: center;
    min-width: 18px;
    height: 18px;
    padding: 0 5px;
    border-radius: 9px;
    background: var(--color-badge-bg);
    color: var(--color-badge-fg);
    font: 600 10.5px/1 var(--font-mono);
}

/* User menu — F .dpanel (300px, radius 12px, F --shadow) as the avatar Dropdown's overlay; also the bell's panel look */
.user-menu,
.shell-dpanel {
    width: 300px;
    max-width: calc(100vw - 32px);
    padding: 6px;
    background: var(--glass-bg);
    border: 1px solid var(--glass-border-light);
    border-radius: 12px;
    box-shadow: var(--shadow-popup);
    color: var(--text-primary);
}

.user-menu__who {
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
    padding: 8px 10px 10px;
}

.user-menu__who-text {
    min-width: 0;
}

.user-menu__name {
    display: block;
    font-weight: 600;
}

.user-menu__email {
    display: block;
    font: 400 12px var(--font-mono);
    color: var(--text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
}

.user-menu__ws {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    padding: 8px 10px;
    background: var(--glass-bg-light);
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-md);
    font-size: 13px;
}

.user-menu__ws-name {
    margin-right: auto;
    font-weight: 600;
}

.user-menu__status {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 9px 10px 4px;
    font: 400 12px var(--font-mono);
    color: var(--text-secondary);
}

.user-menu__sep {
    height: 1px;
    margin: 6px 4px;
    background: var(--glass-border);
}

.user-menu__item {
    width: 100%;
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 7px 10px;
    border: 0;
    border-radius: var(--radius-md);
    background: none;
    color: var(--text-primary);
    /* /1.5: F .mi inherits the body's 1.5 line height (7 + 20.25 + 7 = 34.25px); the shorthand alone resets it to normal */
    font: 400 13.5px/1.5 var(--font-body);
    text-align: left;
    text-decoration: none;
    cursor: pointer;
}

.user-menu__item:hover,
.user-menu__item:focus-visible {
    outline: none;
    background: var(--color-panel-3);
    color: var(--text-primary);
}

.user-menu__item .anticon {
    color: var(--text-muted);
}

/* The theme row holds the shared ThemeModeSegmented (I-023) instead of a link */
.user-menu__item--theme {
    cursor: default;
    justify-content: space-between;
}

.user-menu__item--theme:hover {
    background: none;
}

/* --- 640px: F @media (max-width: 640px) — plan tags leave the bar, the search is a 34px icon --------------------- */
@media (max-width: 640px) {
    .top-bar {
        padding: 0 var(--space-md);
    }

    .top-bar .plan-tags {
        display: none;
    }

    .command-field {
        flex: none;
        width: 34px;
        min-width: 0;
        padding: 0;
        justify-content: center;
        background: none;
        border-color: transparent;
    }

    .command-field__placeholder,
    .command-field kbd {
        display: none;
    }

    .top-bar__actions {
        gap: 4px;
    }
}

/* --- 480px: the I-012 touch-target lift for the shell's hand-built controls (the AntD lift above does not reach
   plain <button> / <a>). Desktop keeps F's 34px density; on a phone every standalone shell control is >= 44px. The
   menu <li> that wraps .shell-nav__item lets go of its fixed 34px in overrides.css. */
@media (max-width: 480px) {
    .icon-btn,
    .user-avatar,
    .top-bar__status {
        min-width: 44px;
        min-height: 44px;
    }

    .command-field {
        width: 44px;
        min-height: 44px;
    }

    /* .user-menu__item: the avatar menu's rows and the bell panel's "View all" */
    .shell-nav__item,
    .property-picker__add,
    .user-menu__item {
        min-height: 44px;
    }
}

@media (prefers-reduced-motion: reduce) {
    .shell .shell-sider,
    .shell.nav-open .shell-sider {
        transition: none;
    }
}

/* =====================================================================================================
   Command palette (I-025) — prototype F's .pal (f.src.html CSS 214-248, + .av--sm 197 and .chip 210), global so the
   playground (/design-system/playground/command-palette; F-176: no scoped CSS) and the product CommandPalette share
   ONE definition (I-025 D-k, I-024 D-j). The AntD Modal is the shell: WrapClassName="command-palette-wrap" places the
   dialog (top 64px, min(640px, 100% - 32px), max-height 100% - 96px) and overrides.css "Command palette (I-025)" resets
   its .ant-modal-content / .ant-modal-body, so .command-palette is the visible panel. Tokens only — F roles as in the
   Shell (I-024) header: --panel = --glass-bg, --panel-2 = --glass-bg-light, --panel-3 = --color-panel-3,
   --line = --glass-border, --line-2 = --glass-border-light, --muted = --text-muted, --r = --radius-lg (14px),
   --r-sm = --radius-md (8px), --shadow = --shadow-popup, --mask = --color-mask, --none-bg = --chart-shade.
   Orange only means "mine": the property avatars (.av--mine), my price on a night and the current-property check.
   ===================================================================================================== */

/* The dialog box inside the AntD wrap — F .pal's position and size (the Modal's Style / Width say the same) */
.command-palette-wrap .ant-modal {
    top: 64px;
    width: min(640px, calc(100% - 32px)) !important;
    max-width: calc(100% - 32px);
    max-height: calc(100% - 96px);
    margin: 0 auto;
    padding-bottom: 0;
}

/* F .pal — the visible panel */
.command-palette {
    display: flex;
    flex-direction: column;
    max-height: calc(100vh - 96px);
    background: var(--glass-bg);
    border: 1px solid var(--glass-border-light);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-popup);
    color: var(--text-primary);
    animation: pal-in 0.14s ease-out;
}

@keyframes pal-in {
    from {
        opacity: 0;
        transform: translateY(-6px);
    }

    to {
        opacity: 1;
        transform: none;
    }
}

/* F .pal__in — the 50px search row: icon, borderless input, Esc key */
.command-palette__input {
    flex: none;
    display: flex;
    align-items: center;
    gap: 10px;
    height: 50px;
    padding: 0 14px;
    border-bottom: 1px solid var(--glass-border);
    color: var(--text-muted);
}

.command-palette__input > .anticon {
    flex: none;
    font-size: 17px;
}

.command-palette__input input {
    flex: 1;
    min-width: 0;
    height: 100%;
    padding: 0;
    border: 0;
    background: transparent;
    box-shadow: none;
    outline: none;
    font: 400 15px var(--font-body);
    color: var(--text-primary);
}

.command-palette__input input::placeholder {
    color: var(--text-muted);
}

/* Key caps — the .command-field kbd look (top bar trigger), in the input row and the footer hints */
.command-palette kbd {
    font: 500 10.5px/1 var(--font-mono);
    padding: 3px 5px;
    border-radius: var(--radius-xs);
    border: 1px solid var(--glass-border-light);
    border-bottom-width: 2px;
    color: var(--text-secondary);
    background: var(--glass-bg);
}

/* F .pal__ls — the listbox */
.command-palette__list {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    padding: 4px 6px 8px;
    scrollbar-width: thin;
}

/* F .pal__g + .lab — group label (role=presentation), the .shell-nav__group look */
.command-palette__group {
    padding: 10px 8px 4px;
    font: 500 10.5px/1.3 var(--font-mono);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* F .pal__o — one 36px option (button[role=option]); hover = --panel-2, the active row = --panel-3 */
.command-palette__option {
    width: 100%;
    display: flex;
    align-items: center;
    gap: 10px;
    height: 36px;
    padding: 0 8px;
    border: 0;
    border-radius: var(--radius-md);
    background: none;
    cursor: pointer;
    text-align: left;
    color: var(--text-primary);
    font: inherit;
    font-size: 13.5px;
}

.command-palette__option > .anticon {
    flex: none;
    font-size: 16px;
    color: var(--text-muted);
}

.command-palette__option:hover {
    background: var(--glass-bg-light);
}

.command-palette__option.is-active {
    background: var(--color-panel-3);
}

.command-palette__option:focus-visible {
    outline: none;
    box-shadow: 0 0 0 2px var(--color-focus-ring);
}

.command-palette__option .lb {
    flex: none;
    white-space: nowrap;
    font-weight: 500;
}

.command-palette__option .lb.mono {
    font-family: var(--font-mono);
    font-size: 12.5px;
}

.command-palette__option .mt {
    flex: 1;
    min-width: 0;
    color: var(--text-muted);
    font: 400 11.5px var(--font-mono);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.command-palette__option .rt {
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font: 600 12.5px var(--font-mono);
}

/* "Mine": my price on a night and the current-property check */
.command-palette__option .rt .is-mine,
.command-palette__option .rt .anticon {
    color: var(--color-primary-text);
}

.command-palette__option .rt .is-muted {
    color: var(--text-muted);
}

/* F .chip — the compact position chip; the position-below|at|above|none classes (RateFormat.PositionClass) give its
   tint, as F's .pos-* do; no new position colour (D-k). :where() keeps the neutral --none-bg below them. */
:where(.command-palette__chip) {
    background: var(--chart-shade);
}

.command-palette__chip {
    display: inline-flex;
    align-items: center;
    height: 20px;
    padding: 0 6px;
    border: 0;
    border-radius: 4px;
    font: 500 10.5px var(--font-mono);
    color: var(--text-secondary);
    white-space: nowrap;
}

.command-palette__chip.position-none {
    background: var(--chart-shade);
}

.command-palette__chip.position-below {
    color: var(--position-below-text);
}

.command-palette__chip.position-above {
    color: var(--position-above-text);
}

/* F .pal__ft — the key hints; they wrap on a narrow panel */
.command-palette__footer {
    flex: none;
    display: flex;
    flex-wrap: wrap;
    gap: 6px 14px;
    padding: 8px 14px;
    border-top: 1px solid var(--glass-border);
    border-radius: 0 0 var(--radius-lg) var(--radius-lg);
    background: var(--glass-bg-light);
    font: 400 11.5px var(--font-mono);
    color: var(--text-muted);
}

.command-palette__footer kbd {
    margin-right: 3px;
}

/* F .pal__none — "Nothing matches" */
.command-palette__none {
    padding: 22px 10px;
    color: var(--text-muted);
    text-align: center;
}

/* Nights loading: two 36px skeleton rows under the group label */
.command-palette__skeleton {
    height: 36px;
    margin: 0 0 2px;
    border-radius: var(--radius-md);
    background: linear-gradient(90deg, var(--color-skeleton-1) 25%, var(--color-skeleton-2) 50%, var(--color-skeleton-1) 75%);
    background-size: 200% 100%;
    animation: skeletonShimmer 1.5s ease-in-out infinite;
}

/* F .av--sm — the 26px avatar of the Shell (I-024) .av family (palette property rows) */
.av--sm {
    width: 26px;
    height: 26px;
    border-radius: 7px;
    font-size: 10px;
}

@media (prefers-reduced-motion: reduce) {
    .command-palette,
    .command-palette__skeleton {
        animation: none;
    }
}

/* =====================================================================================================
   Wizard & settings (I-032) — prototype F's onboarding wizard, first-login focus header, settings page (section index,
   sections, save bar, live strategy preview) and Team & plan page (f.src.html CSS: .seg 285-292, settings 562-636,
   focus mode 638-640, hotel cards + wizard 724-787, plan meters / limits / members / invites / roles 925-954, locks
   1057-1079, the 720px settings container query 1176, the focus header's plan tag 1319; previews drawPreview 2551-2576).
   README D-k (focus header), D-l (wizard), D-m (horizon locks), D-n (step title tier, #11504), D-o (settings), D-p (save
   bar), D-s (Team & plan), D-t (account), D-y (design coverage). Global and opt-in: nothing restyles until a page uses
   the classes, so the wizard / settings playgrounds, the showcase and the Onboarding, Property settings, Team & plan and
   Account settings pages share ONE definition. The template's .wizard-progress / .settings-tabs-layout rules stay for
   the forks (D-y).
   Tokens only — F roles as in the earlier blocks: --panel = --glass-bg, --panel-2 = --glass-bg-subtle, --panel-3 =
   --color-panel-3, --line = --glass-border, --line-2 = --glass-border-light, --text = --text-primary, --text-2 =
   --text-secondary, --muted = --text-muted, --primary = --color-primary (ink --text-on-primary), --warn = --color-warning,
   --err = --color-error (badge ground --color-error-solid / --color-on-error-solid), --ok = --color-success, --shadow =
   --shadow-float, --chart-grid / --chart-median / --band / --band-edge = --chart-grid / --chart-median / --chart-band /
   --color-chart-band-edge, --row-hover = --color-row-hover; F's color-mix() roles are measured into --color-primary-faint,
   --color-error-line, --color-success-line and --color-success-faint (both theme blocks).
   Renamed on collision: F .steps → .ob-steps over AntD Steps; .anchor → .set-anchor (plain links + js/section-index.js); .hcard → the
   existing .hotel-card hooks (D-r); .scan → .onboarding__scan-row; .badge → .badge-neutral.badge--err; .lab →
   .core-eyebrow; .hd__brand → .shell-focus__brand; .panel → .glass-card; .prog__track / __bar → AntD Progress. Reused,
   never redefined: .tag / .tag--plan / .tag--warn, .badge-neutral, .plan-hint(--card), .plan-lock, .sw--line / --dash /
   --band, .page-wrapper--f / .page-container--f, .core-eyebrow, .av.
   Orange only means "mine": the current step's bullet, a selected card / tile, the suggestion line and its dots, the
   section index's active bar. Locks stay neutral (I-028 pill), the dirty dot is warning amber, error badges and
   .is-over are the error family.
   ===================================================================================================== */

/* --- Wizard: F .steps over AntD Steps (README D-l). overrides.css paints every .ant-steps item with !important, so the
   F rules carry it too (scoped under .ob-steps, which outranks them). --- */
.ob-steps.ant-steps {
    align-items: center;
    font-size: 0;
}

.ob-steps .ant-steps-item {
    overflow: hidden;
}

.ob-steps.ant-steps-horizontal .ant-steps-item:not(:first-child) {
    padding-left: 12px;
}

.ob-steps .ant-steps-item-container {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 4px 4px 4px 0;
    border-radius: var(--radius-md);
}

.ob-steps .ant-steps-item-container[role='button']:focus-visible {
    box-shadow: 0 0 0 2px var(--color-focus-ring);
}

/* F .step__b — a 26px circle, 600 12px mono; neutral until it is the current step */
.ob-steps .ant-steps-item-icon {
    flex: none;
    display: grid;
    place-items: center;
    width: 26px;
    height: 26px;
    margin: 0;
    border: 1px solid var(--glass-border-light) !important;
    border-radius: 50%;
    background: var(--glass-bg) !important;
    font: 600 12px/1 var(--font-mono);
}

.ob-steps .ant-steps-item-icon .ant-steps-icon {
    top: 0;
    color: var(--text-secondary) !important;
    font: inherit;
}

.ob-steps .ant-steps-item-icon .anticon {
    font-size: 12px;
}

/* F .step.is-done .step__b — --panel-3 ground, --text ink, a check; the neutral ring restated here because
   overrides.css's later .ant-steps-item-finish .ant-steps-item-icon (same specificity) paints it orange (TASK_03) */
.ob-steps .ant-steps-item-finish .ant-steps-item-icon {
    border-color: var(--glass-border-light) !important;
    background: var(--color-panel-3) !important;
}

.ob-steps .ant-steps-item-finish .ant-steps-item-icon .ant-steps-icon {
    color: var(--text-primary) !important;
}

/* F .step[aria-current="step"] .step__b — the only orange in the rail */
.ob-steps .ant-steps-item-process .ant-steps-item-icon {
    background: var(--color-primary) !important;
    border-color: var(--color-primary) !important;
}

.ob-steps .ant-steps-item-process .ant-steps-item-icon .ant-steps-icon {
    color: var(--text-on-primary) !important;
}

/* F .step / .step__l — 500 13.5px UI, muted; done --text-2; current 600 --text */
.ob-steps .ant-steps-item-content {
    min-width: 0;
}

.ob-steps .ant-steps-item-title {
    padding-right: 12px;
    color: var(--text-muted) !important;
    font: 500 13.5px/26px var(--font-body);
}

.ob-steps .ant-steps-item-finish .ant-steps-item-title {
    color: var(--text-secondary) !important;
}

.ob-steps .ant-steps-item-process .ant-steps-item-title {
    color: var(--text-primary) !important;
    font-weight: 600;
}

.ob-steps .ant-steps-item-container[role='button']:hover .ant-steps-item-title {
    color: var(--text-primary) !important;
}

/* F .steps__rail — 1px --line-2, --text-2 once the step is done (never orange) */
.ob-steps .ant-steps-item-title::after {
    top: 13px;
    height: 1px;
    background: var(--glass-border-light) !important;
}

.ob-steps .ant-steps-item-finish .ant-steps-item-title::after {
    background: var(--text-secondary) !important;
}

/* --- Wizard: F .page--narrow — the wizard sits on the F frame (the `page` container), 820px wide --- */
.page-container.page-container--f.page-container--narrow {
    max-width: 820px;
}

/* --- Wizard: F .wiz panel, title, hint, head, actions, counter, chips --- */
.glass-card.wiz {
    display: flex;
    flex-direction: column;
    gap: 18px;
    padding: 22px 24px 24px;
}

.wiz .wizard-step__title {
    margin: 0;
}

.wiz .wizard-step__hint {
    margin: 4px 0 0;
    color: var(--text-secondary);
}

.wiz__head {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
}

.wizard-actions.wact {
    align-items: center;
    gap: 8px;
    margin-top: 0;
}

.wact .ant-btn {
    height: 36px;
    padding: 0 16px;
}

.counter {
    padding-top: 4px;
    font: 400 12.5px var(--font-mono);
    color: var(--text-secondary);
    white-space: nowrap;
}

.counter b {
    color: var(--text-primary);
    font-weight: 600;
}

.chips {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

/* F .tag--btn — a removable chip on the .tag base */
.tag.tag--btn {
    height: 26px;
    padding: 0 6px 0 9px;
    font-family: var(--font-body);
    font-size: 12.5px;
    color: var(--text-primary);
    cursor: pointer;
}

.tag.tag--btn:hover {
    border-color: var(--text-secondary);
}

.tag--btn .anticon {
    color: var(--text-muted);
}

/* F .hsec — a titled block of result cards */
.hsec {
    display: flex;
    flex-direction: column;
    gap: 10px;
    min-width: 0;
}

.hsec__t {
    margin: 0;
    font-size: var(--type-block-title);
    font-weight: 600;
    line-height: 1.3;
    color: var(--text-primary);
}

/* F .searchrow — a search input that takes the row and its Search button (TASK_03: the onboarding searches) */
.searchrow {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
}

/* The input is the row's first child and takes the space; the button keeps its width */
.searchrow > :first-child {
    flex: 1;
    min-width: 0;
}

.searchrow > :last-child {
    flex: none;
}

/* The first scan's block inside the .wiz panel (onboarding-scan): the panel's own rhythm (TASK_03) */
.onboarding__scan {
    display: flex;
    flex-direction: column;
    gap: 18px;
    min-width: 0;
}

/* --- Wizard: result cards — F .hlist / .hgrid / .hcard on the existing .hotel-card hooks (README D-l, D-r) --- */
.hlist {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.hgrid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 8px;
}

.hotel-card {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    min-width: 0;
    min-height: 56px;
    padding: 8px 12px 8px 8px;
    border: 1px solid var(--glass-border-light);
    border-radius: 10px;
    background: var(--glass-bg);
    color: var(--text-primary);
    font: inherit;
    text-align: left;
    cursor: pointer;
}

.hotel-card:hover {
    border-color: var(--text-secondary);
}

.hotel-card:focus-visible {
    outline: none;
    box-shadow: 0 0 0 2px var(--color-focus-ring);
}

/* The user's choice is "mine": F .hcard[aria-checked="true"] */
.hotel-card.hotel-card--selected {
    border-color: var(--color-primary);
    box-shadow: inset 0 0 0 1px var(--color-primary);
    background: var(--color-primary-faint);
}

.hotel-card.hotel-card--disabled {
    background: var(--glass-bg-subtle);
    border-color: var(--glass-border);
    cursor: not-allowed;
}

/* F .av inside the card */
.hotel-card__photo {
    flex: none;
    display: inline-grid;
    place-items: center;
    width: 30px;
    height: 30px;
    overflow: hidden;
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-md);
    background: var(--color-panel-3);
    color: var(--text-secondary);
    font: 600 11px/1 var(--font-mono);
}

.hotel-card__body {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    line-height: 1.3;
}

.hotel-card__name {
    overflow: hidden;
    font-size: 13.5px;
    font-weight: 600;
    color: var(--text-primary);
    white-space: nowrap;
    text-overflow: ellipsis;
}

.hotel-card--disabled .hotel-card__name {
    color: var(--text-secondary);
}

.hotel-card__place,
.hotel-card__meta {
    overflow: hidden;
    font: 400 11px var(--font-mono);
    color: var(--text-muted);
    white-space: nowrap;
    text-overflow: ellipsis;
}

/* F .hcard__ck — an 18px ring (a box for multi-select), filled orange with the check when selected */
.hotel-card__check {
    flex: none;
    display: grid;
    place-items: center;
    width: 18px;
    height: 18px;
    border: 1.5px solid var(--glass-border-light);
    border-radius: 50%;
    color: var(--text-on-primary);
    font-size: 11px;
}

.hotel-card__check.hotel-card__check--box {
    border-radius: 4px;
}

.hotel-card--selected .hotel-card__check {
    border-color: var(--color-primary);
    background: var(--color-primary);
}

/* F .hcard__why */
.hotel-card__reason {
    flex: none;
    font: 500 11px var(--font-mono);
    color: var(--text-muted);
    white-space: nowrap;
}

/* --- Wizard: the first scan — F .prog (AntD Progress; overrides.css paints its bar with !important, so these do too) and
   .scan rows --- */
.prog {
    display: flex;
    align-items: center;
    gap: 12px;
}

.prog > .ant-progress {
    flex: 1;
    display: flex;
    align-items: center;
    gap: 12px;
    min-width: 0;
}

.prog .ant-progress-outer {
    flex: 1;
    min-width: 0;
    margin-right: 0;
    padding-right: 0;
}

.prog .ant-progress-inner {
    background: var(--color-panel-3) !important;
}

.prog .ant-progress-bg {
    height: 8px !important;
    background: var(--color-primary) !important;
}

.prog.is-done .ant-progress-bg {
    background: var(--color-success) !important;
}

.prog .ant-progress-text {
    flex: none;
    width: auto;
    margin-left: 0;
    min-width: 40px;
    font: 600 12.5px var(--font-mono);
    color: var(--text-primary);
    text-align: right;
}

.onboarding__scan-list {
    margin: 0;
    padding: 0;
    list-style: none;
    border: 1px solid var(--glass-border);
    border-radius: 10px;
}

.onboarding__scan-list > li {
    display: flex;
    align-items: center;
    gap: 10px;
    min-height: 42px;
    padding: 6px 14px;
    border-top: 1px solid var(--glass-border);
}

.onboarding__scan-list > li:first-child {
    border-top: 0;
}

.onboarding__scan-icon {
    flex: none;
    display: inline-grid;
    place-items: center;
    width: 18px;
    color: var(--text-muted);
}

.onboarding__scan-row--done .onboarding__scan-icon,
.onboarding__scan-row--done .onboarding__scan-state {
    color: var(--color-success);
}

.onboarding__scan-row--checking .onboarding__scan-icon,
.onboarding__scan-row--checking .onboarding__scan-state {
    color: var(--text-primary);
}

/* B-085 (F .scan__ic--waiting): a hotel the first scan got no rates for */
.onboarding__scan-row--waiting .onboarding__scan-icon {
    color: var(--color-warning);
}

.onboarding__scan-row--waiting .onboarding__scan-state {
    white-space: normal;
    text-align: right;
}

.onboarding__scan-name {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    font-weight: 500;
    white-space: nowrap;
    text-overflow: ellipsis;
}

.onboarding__scan-state {
    font: 400 12px var(--font-mono);
    color: var(--text-muted);
    white-space: nowrap;
}

/* --- Focused shell header (README D-k): first-login onboarding renders the top bar with the logo and the plan tag +
   avatar only — the layout does not render the sider, crumb, command field, status or bell (TASK_03) --- */
.top-bar.top-bar--focus {
    gap: 14px;
}

/* F .hd__brand — the full 22px logo at the left */
.shell-focus__brand {
    flex: none;
    display: inline-flex;
    align-items: center;
    text-decoration: none;
}

.shell-focus__brand img {
    height: 22px;
}

/* F .app.is-focus .hd__r { margin-left: auto } */
.top-bar--focus .top-bar__actions {
    margin-left: auto;
}

/* The content column without a sider takes the whole row */
.shell.is-focus > .content-layout {
    flex: 1;
    min-width: 0;
}

/* --- Settings: F .setgrid (index | form | preview), the narrow grid (no preview column) (README D-o, D-j) --- */
.setgrid {
    display: grid;
    grid-template-columns: 172px minmax(0, 1fr) 328px;
    gap: 24px;
    align-items: start;
}

.setgrid.setgrid--narrow {
    grid-template-columns: 184px minmax(0, 1fr);
    max-width: 1000px;
}

/* F .anchor — the section index: sticky, a left rule, 13.5px links, the current one a primary left bar + 600. Plain links
   (js/section-index.js follows the scroll): AntD Blazor's Anchor spies on window scroll only and sets the hash through
   window.eval, which the App's CSP blocks */
.set-anchor {
    position: sticky;
    top: 16px;
    display: flex;
    flex-direction: column;
    min-width: 0;
    border-left: 1px solid var(--glass-border-light);
}

/* F .anchor__lab.lab — "On this page" */
.set-anchor__lab {
    display: block;
    padding: 0 0 8px 14px;
}

.set-anchor__link {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin-left: -1px;
    padding: 6px 12px 6px 14px;
    border-left: 2px solid transparent;
    color: var(--text-secondary);
    font-size: 13.5px;
    text-decoration: none;
}

.set-anchor__link:hover {
    color: var(--text-primary);
}

.set-anchor__link:focus-visible {
    outline: none;
    box-shadow: inset 0 0 0 2px var(--color-focus-ring);
}

.set-anchor__link.is-active {
    border-left-color: var(--color-primary);
    color: var(--text-primary);
    font-weight: 600;
}

/* F .badge--err — a section's error count (the neutral badge on the error ground) */
.badge-neutral.badge--err {
    background: var(--color-error-solid);
    color: var(--color-on-error-solid);
}

/* F .setcol — the form column, the `form` container the tiles query */
.setcol {
    display: flex;
    flex-direction: column;
    gap: 16px;
    min-width: 0;
    container: form / inline-size;
}

/* F .sec — a flat panel per section */
.glass-card.sec {
    padding: 0;
    scroll-margin-top: 16px;
}

.sec__head {
    padding: 14px 20px 12px;
    border-bottom: 1px solid var(--glass-border);
}

.sec__title {
    margin: 0;
    font-size: var(--type-section-title);
    font-weight: 600;
    line-height: 1.3;
    color: var(--text-primary);
}

.sec__body {
    display: flex;
    flex-direction: column;
    gap: 20px;
    padding: 18px 20px 20px;
}

.glass-card.sec.sec--danger {
    border-color: var(--color-error-line);
}

/* F .fi — a field: label, control, help / warning */
.fi {
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-width: 0;
}

.fi__label {
    font: 500 12px var(--font-mono);
    letter-spacing: 0.01em;
    color: var(--text-secondary);
}

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

.fi__err {
    font-size: 12.5px;
    color: var(--color-error);
}

.fi__warn {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 12.5px;
    color: var(--color-warning);
}

/* F .seg { align-self: flex-start; flex-wrap: wrap } — a Segmented keeps its own width in a field and wraps on a phone */
.fi > .ant-segmented {
    align-self: flex-start;
    max-width: 100%;
}

.fi > .ant-segmented .ant-segmented-group {
    flex-wrap: wrap;
}

/* F .planhint a — a plan hint's "Contact us" is neutral (text-2, 500) in a wizard step or a settings section: a lock is
   never orange */
.wiz .plan-hint__link,
.sec .plan-hint__link {
    color: var(--text-secondary);
    font-weight: 500;
}

.row2 {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 20px;
}

.row2.row2--stack {
    grid-template-columns: minmax(0, 1fr);
}

/* F .ro-grid — read-only facts */
.ro-grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 12px 16px;
    margin: 0;
    padding: 12px 14px;
    border: 1px solid var(--glass-border);
    border-radius: 10px;
    background: var(--glass-bg-subtle);
}

.ro-grid.ro-grid--2 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
}

/* F accountPage's one-column ro-grid (inline grid-template-columns: minmax(0,1fr)) — Subscription's plan, Account's email */
.ro-grid.ro-grid--1 {
    grid-template-columns: minmax(0, 1fr);
}

.ro-grid > div {
    min-width: 0;
}

.ro-grid dt {
    margin-bottom: 3px;
    font: 500 10.5px var(--font-mono);
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.ro-grid dd {
    display: flex;
    align-items: center;
    gap: 6px;
    margin: 0;
    color: var(--text-primary);
    overflow-wrap: anywhere;
}

/* F .tiles / .tile — the strategy radio cards; the user's choice is "mine" (orange ring) */
.tiles {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 10px;
}

.tile {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 14px;
    border: 1px solid var(--glass-border-light);
    border-radius: 12px;
    background: var(--glass-bg);
    color: var(--text-primary);
    font: inherit;
    text-align: left;
    cursor: pointer;
}

.tile:hover {
    border-color: var(--text-secondary);
}

.tile:focus-visible {
    outline: none;
    box-shadow: 0 0 0 2px var(--color-focus-ring);
}

.tile.is-checked {
    border-color: var(--color-primary);
    box-shadow: inset 0 0 0 1px var(--color-primary);
    background: var(--color-primary-faint);
}

.tile__t {
    padding-right: 24px;
    font-weight: 600;
}

.tile__d {
    font-size: 12.5px;
    line-height: 1.45;
    color: var(--text-secondary);
}

/* F .valrow / .addon — the strategy value with its unit, the money bounds (MoneyInput draws the currency prefix) */
.valrow {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
}

.addon {
    display: inline-flex;
    align-items: stretch;
    width: 180px;
    max-width: 100%;
}

.addon > .ant-input-number,
.addon > .ant-input-number-affix-wrapper {
    flex: 1;
    width: auto;
    min-width: 0;
}

.addon > .ant-input-number:not(:last-child),
.addon > .ant-input-number-affix-wrapper:not(:last-child) {
    border-top-right-radius: 0;
    border-bottom-right-radius: 0;
}

.addon input {
    font-family: var(--font-mono);
}

.addon__suf {
    display: grid;
    place-items: center;
    min-width: 34px;
    padding: 0 9px;
    border: 1px solid var(--glass-border-light);
    border-left: 0;
    border-radius: 0 var(--radius-md) var(--radius-md) 0;
    background: var(--glass-bg-subtle);
    color: var(--text-muted);
    font: 500 12.5px var(--font-mono);
}

/* F .savebar — sticky at the column's foot: the dirty dot (warning amber), the error count, Discard, Save */
.savebar {
    position: sticky;
    bottom: 12px;
    z-index: 5;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
    padding: 10px 12px 10px 16px;
    border: 1px solid var(--glass-border-light);
    border-radius: var(--radius-lg);
    background: var(--glass-bg);
    box-shadow: var(--shadow-float);
}

.savebar__txt {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
    margin-right: auto;
    font-weight: 500;
}

.savebar__dirty {
    display: inline-flex;
    align-items: center;
}

.savebar__dot {
    display: inline-block;
    width: 7px;
    height: 7px;
    margin-right: 6px;
    border-radius: 50%;
    background: var(--color-warning);
}

/* --- Settings: the live strategy preview — F .pv-col / .pv (sticky aside) and the folded .pv--fold (AntD Collapse inside
   Rate suggestions at <= 1240px) (README D-j) --- */
.pv-col {
    position: sticky;
    top: 16px;
    min-width: 0;
}

.glass-card.pv {
    padding: 0;
}

.pv__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 12px 16px;
    border-bottom: 1px solid var(--glass-border);
}

/* F .tag--dash — the "Preview" tag */
.tag.tag--dash {
    border-style: dashed;
    background: none;
}

.pv__end {
    display: inline-flex;
    align-items: center;
    gap: 8px;
}

.pv__strategy {
    font: 500 11.5px var(--font-mono);
    color: var(--text-muted);
    text-align: right;
}

.pv__body {
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 14px 16px 16px;
}

.pv__h {
    margin: 0;
    font-size: var(--type-panel-title);
    font-weight: var(--type-panel-title-weight);
    line-height: 1.3;
    color: var(--text-primary);
}

.pv__desc {
    margin: 0;
    font-size: 13.5px;
    font-weight: 600;
}

.pv__chart {
    min-height: 190px;
}

.pv__legend {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 14px;
    font: 400 11.5px var(--font-mono);
    color: var(--text-muted);
}

.pv__legend > span {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    white-space: nowrap;
}

.pv__figs {
    display: grid;
    grid-template-columns: 1fr 1fr;
    margin: 0;
    border-top: 1px solid var(--glass-border);
}

.pv__figs > div {
    min-width: 0;
    padding: 8px 0 0;
}

.pv__figs > div + div {
    padding-left: 14px;
    border-left: 1px solid var(--glass-border);
}

.pv__figs dt {
    font: 500 10.5px var(--font-mono);
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.pv__figs dd {
    margin: 2px 0 0;
    font: 600 18px var(--font-mono);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* F .t-mine — the average suggestion is my figure */
.pv__figs dd.pv__mine {
    color: var(--color-primary-text);
}

.pv__figs dd span {
    font-size: 12px;
}

.pv__ex {
    margin: 0;
    font-size: 13px;
    color: var(--text-secondary);
}

.pv__note {
    margin: 0;
    padding-top: 8px;
    border-top: 1px dashed var(--glass-border-light);
    font-size: 12px;
    color: var(--text-muted);
}

/* F details.pv — the folded preview on the inset ground. overrides.css paints every .ant-collapse with !important, so the
   F rules carry it too (scoped under .pv--fold, which outranks them). */
.pv--fold.ant-collapse {
    border: 1px solid var(--glass-border-light) !important;
    border-radius: 10px !important;
    background: var(--glass-bg-subtle) !important;
}

.pv--fold > .ant-collapse-item {
    border-bottom: 0;
}

.pv--fold.ant-collapse > .ant-collapse-item.ant-collapse-no-arrow > .ant-collapse-header {
    align-items: center;
    padding: 12px 16px;
    color: var(--text-primary) !important;
}

.pv--fold .ant-collapse-header-text {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    min-width: 0;
}

.pv--fold .pv__chev {
    color: var(--text-muted);
    transition: transform var(--transition-fast);
}

.pv--fold > .ant-collapse-item-active .pv__chev {
    transform: rotate(180deg);
}

.pv--fold > .ant-collapse-item-active > .ant-collapse-header {
    border-bottom: 1px solid var(--glass-border);
}

.pv--fold .ant-collapse-content {
    border-top: 0 !important;
    background: none !important;
    color: var(--text-primary) !important;
}

.pv--fold .ant-collapse-content > .ant-collapse-content-box {
    padding: 0 !important;
}

/* --- StrategyPreviewChart (F drawPreview, H 196: 10px top, a 46px value gutter, a 24px date row) --- */
.spc {
    display: grid;
    grid-template-columns: 46px minmax(0, 1fr);
    grid-template-rows: 162px 24px;
    padding-top: 10px;
    min-width: 0;
}

.spc__yaxis {
    position: relative;
    grid-column: 1;
    grid-row: 1;
}

.spc__ytick {
    position: absolute;
    right: 8px;
    transform: translateY(-50%);
    font: 400 11px var(--font-mono);
    color: var(--text-muted);
    white-space: nowrap;
}

.spc__plot {
    position: relative;
    grid-column: 2;
    grid-row: 1;
    margin-right: 6px;
}

.spc__svg {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    overflow: visible;
}

.spc__we {
    fill: var(--color-row-hover);
}

.spc__grid {
    stroke: var(--chart-grid);
    stroke-width: 1;
    vector-effect: non-scaling-stroke;
}

.spc__band {
    fill: var(--chart-band);
}

.spc__bound {
    stroke: var(--text-secondary);
    stroke-width: 1.5;
    stroke-dasharray: 1 3;
    vector-effect: non-scaling-stroke;
}

.spc__median {
    fill: none;
    stroke: var(--chart-median);
    stroke-width: 1.6;
    stroke-dasharray: 5 4;
    vector-effect: non-scaling-stroke;
}

/* The suggestion is "mine": the primary line and its dots */
.spc__line {
    fill: none;
    stroke: var(--color-primary);
    stroke-width: 2.4;
    stroke-linejoin: round;
    vector-effect: non-scaling-stroke;
}

.spc__dot {
    position: absolute;
    width: 5.2px;
    height: 5.2px;
    border-radius: 50%;
    background: var(--color-primary);
    transform: translate(-50%, -50%);
}

/* F .chart .halo — the floor / ceiling label over the plot */
.spc__bound-label {
    position: absolute;
    right: 0;
    transform: translateY(calc(-100% - 4px));
    font: 400 11px var(--font-mono);
    color: var(--text-secondary);
    white-space: nowrap;
    text-shadow: 0 0 3px var(--glass-bg), 0 0 3px var(--glass-bg);
}

.spc__bound-label.spc__bound-label--start {
    right: auto;
    left: 4px;
}

.spc__xaxis {
    position: relative;
    grid-column: 2;
    grid-row: 2;
    margin-right: 6px;
}

.spc__xtick {
    position: absolute;
    bottom: 6px;
    transform: translateX(-50%);
    font: 400 11px var(--font-mono);
    color: var(--text-muted);
    white-space: nowrap;
}

/* --- Team & plan (README D-s): F .duo, plan meters (AntD Progress), limits, member / invite rows, roles --- */
.duo {
    display: grid;
    grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
    gap: 16px;
    align-items: start;
}

.duo__col {
    display: flex;
    flex-direction: column;
    gap: 16px;
    min-width: 0;
}

/* F .panel__head / .panel__sub inside a team panel */
.team-panel__head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 10px 16px;
    padding: 12px 16px;
    border-bottom: 1px solid var(--glass-border);
}

.team-panel__titlerow {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

.team-panel__title {
    margin: 0;
    font-size: var(--type-panel-title);
    font-weight: var(--type-panel-title-weight);
    line-height: 1.3;
    color: var(--text-primary);
}

.team-panel__sub {
    margin: 2px 0 0;
    font-size: 12.5px;
    color: var(--text-muted);
}

.glass-card.team-panel {
    padding: 0;
}

.meters {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 18px 28px;
    padding: 16px 16px 18px;
}

.meter {
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-width: 0;
}

.meter__head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
    font-size: 13px;
    color: var(--text-secondary);
}

.meter__val {
    font: 600 12.5px var(--font-mono);
    font-variant-numeric: tabular-nums;
    color: var(--text-primary);
    white-space: nowrap;
}

.meter .ant-progress {
    line-height: 1;
}

/* F .prog__track / .prog__bar radius 4px (AntD rounds both to 100px — TASK_08 fidelity, teamMeterTrack) */
.meter .ant-progress-inner {
    background: var(--color-panel-3) !important;
    border-radius: 4px !important;
}

/* F .meter .prog__bar: my workspace's usage is "mine" (primary); full = warning amber, over = error */
.meter .ant-progress-bg {
    height: 6px !important;
    border-radius: 4px !important;
    background: var(--color-primary) !important;
}

.meter.is-full .ant-progress-bg {
    background: var(--color-warning) !important;
}

.meter.is-over .ant-progress-bg {
    background: var(--color-error) !important;
}

.meter__note {
    font-size: 12px;
    line-height: 1.4;
    color: var(--text-muted);
}

.limits {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 22px;
    margin: 0;
    padding: 12px 16px 14px;
    list-style: none;
    border-top: 1px solid var(--glass-border);
    font-size: 13px;
    color: var(--text-secondary);
}

.limits > li {
    display: inline-flex;
    align-items: center;
    gap: 7px;
}

.limits .anticon {
    flex: none;
    color: var(--text-muted);
}

.limits > li.is-off {
    color: var(--text-muted);
}

/* The page lists member / invite rows as ul > li (the E2E page objects select the li); the playground uses divs */
ul.crow-list {
    margin: 0;
    padding: 0;
    list-style: none;
}

/* An invite link with less than a day left keeps the warning tint the old Team page gave its expiry */
.crow__p .is-soon {
    color: var(--color-warning-light);
}

/* F .crow — a member / invite row */
.crow {
    display: grid;
    align-items: center;
    gap: 14px;
    padding: 9px 12px 9px 16px;
    border-top: 1px solid var(--glass-border);
}

.crow:first-child {
    border-top: 0;
}

.crow.crow--mem {
    grid-template-columns: 32px minmax(0, 1fr) auto auto;
}

.crow.crow--inv {
    grid-template-columns: auto minmax(0, 1fr) auto;
}

.crow.crow--inv > .tag {
    justify-self: start;
}

.crow__t {
    display: flex;
    flex-direction: column;
    min-width: 0;
    line-height: 1.3;
}

.crow__n {
    overflow: hidden;
    font-size: 13.5px;
    font-weight: 600;
    white-space: nowrap;
    text-overflow: ellipsis;
}

.crow__n .tag {
    height: 19px;
    margin-left: 6px;
    font-size: 10.5px;
    vertical-align: 1px;
}

.crow__p {
    overflow: hidden;
    font: 400 11px var(--font-mono);
    color: var(--text-muted);
    white-space: nowrap;
    text-overflow: ellipsis;
}

/* F .pad — a padded block inside a team panel */
.team-pad {
    display: flex;
    flex-direction: column;
    gap: 14px;
    padding: 14px 16px 16px;
}

.team-pad + .team-pad {
    border-top: 1px solid var(--glass-border);
}

/* F .invc — role + "Create invite link" */
.invc {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 10px 12px;
}

/* F .invd — the created link, in the success family ("Link ready") */
.invd {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 12px 14px;
    border: 1px solid var(--color-success-line);
    border-radius: 10px;
    background: var(--color-success-faint);
}

.invd__lab {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    font-size: 13.5px;
    font-weight: 500;
}

.invd__lab > .anticon {
    color: var(--color-success);
}

.invd__row {
    display: flex;
    align-items: center;
    gap: 8px;
}

.invd__row input {
    font-family: var(--font-mono);
}

.subh {
    margin: 0;
    font-size: var(--type-sub-title);
    font-weight: 600;
    line-height: 1.3;
    color: var(--text-primary);
}

.muted-line {
    margin: 0;
    font-size: 13px;
    color: var(--text-muted);
}

/* F .roles — the roles legend */
.roles {
    display: flex;
    flex-direction: column;
    margin: 0;
}

.roles > div {
    display: grid;
    grid-template-columns: 84px minmax(0, 1fr);
    gap: 12px;
    padding: 10px 16px;
    border-top: 1px solid var(--glass-border);
}

.roles > div:first-child {
    border-top: 0;
}

.roles dt {
    padding-top: 1px;
}

.roles dd {
    margin: 0;
    font-size: 13px;
    color: var(--text-secondary);
}

/* --- Container queries: the page follows its content width (F 1159, 1176, 1202, 1262, 1298, 1304) --- */
@container page (max-width: 1000px) {
    .duo {
        grid-template-columns: minmax(0, 1fr);
    }
}

@container page (max-width: 900px) {
    .row2,
    .ro-grid,
    .ro-grid.ro-grid--2 {
        grid-template-columns: minmax(0, 1fr);
    }

    .meters {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

/* F 1176: one column; the section index becomes a static, horizontal tab row with a bottom rule and no label */
@container page (max-width: 720px) {
    .setgrid,
    .setgrid.setgrid--narrow {
        grid-template-columns: minmax(0, 1fr);
        gap: 16px;
    }

    .set-anchor {
        position: static;
        flex-direction: row;
        flex-wrap: wrap;
        border-left: 0;
        border-bottom: 1px solid var(--glass-border-light);
    }

    .set-anchor__lab {
        display: none;
    }

    .set-anchor__link {
        margin: 0 0 -1px;
        padding: 8px 12px;
        border-left: 0;
        border-bottom: 2px solid transparent;
    }

    .set-anchor__link.is-active {
        border-bottom-color: var(--color-primary);
    }
}

@container page (max-width: 600px) {
    .hgrid {
        grid-template-columns: minmax(0, 1fr);
    }

    .glass-card.wiz {
        padding: 18px 16px 20px;
    }

    .ob-steps .ant-steps-item:not(.ant-steps-item-process) .ant-steps-item-title {
        font-size: 0;
        padding-right: 8px;
    }

    .meters {
        grid-template-columns: minmax(0, 1fr);
    }

    /* F .crow under a 600px page (reviewed at 520): 10px gap, 9px 8px 9px 12px (I-038 TASK_04, P09 / P11 at 390) */
    .crow {
        gap: 10px;
        padding: 9px 8px 9px 12px;
    }

    .crow.crow--mem {
        grid-template-columns: 32px minmax(0, 1fr) auto;
    }

    .crow.crow--inv {
        grid-template-columns: minmax(0, 1fr) auto;
    }

    .crow.crow--inv > .crow__t {
        grid-column: 1 / -1;
        grid-row: 2;
    }

    .roles > div {
        grid-template-columns: minmax(0, 1fr);
        gap: 4px;
    }
}

/* F 1202: the strategy tiles stack in a narrow form column */
@container form (max-width: 560px) {
    .tiles {
        grid-template-columns: minmax(0, 1fr);
    }

    .tile__t {
        padding-right: 28px;
    }
}

/* The section index's horizontal row is a row of touch targets on a phone: >= 44px tall at <= 480px, as every standalone
   control (I-012 AD3; the row itself follows the page container above) */
@media (max-width: 480px) {
    .set-anchor__link {
        min-height: 44px;
    }
}

/* F 1319: the focus header keeps its plan tag below 640px (the shell hides .plan-tags there) — the shell follows the
   viewport, so this one rule is a media query */
@media (max-width: 640px) {
    .top-bar.top-bar--focus .plan-tags {
        display: inline-flex;
    }
}

/* =====================================================================================================
   Data grid (I-027) — prototype F's dense grid .rg / .cc / .rbar / .mb (f.src.html CSS 426-480), legend swatches .sw
   (305-310, .sw--we 885; F's .pos-* (366) are the App's .position-* family) and markup grid() (2340-2375). Global and opt-in (README D-e): nothing
   restyles until a <table class="dgrid"> opts in, so the tables playground (/design-system/playground/tables; F-176: no
   scoped CSS) and the Rate calendar grid share ONE definition. The AntD list-table variant .table--f (D-i) lives in
   overrides.css. Tokens only — F roles as in the Shell (I-024) header: --panel = --glass-bg, --panel-2 =
   --glass-bg-light, --panel-3 = --color-panel-3, --panel-we = --color-panel-we, --panel-hover = --glass-bg-hover,
   --line = --glass-border, --line-2 = --glass-border-light, --text = --text-primary, --text-2 = --text-secondary,
   --muted = --text-muted, --threat-N / --opp-N = --rate-threat-bg-N / --rate-opportunity-bg-N, --threat-text /
   --opp-text = --rate-threat-text / --rate-opportunity-text, --warn / --warn-bg = --color-warning / --color-warning-bg,
   --info = --color-info, --chart-median = --color-chart-median, --below-bg / --at-bg / --above-bg = --position-*-bg,
   --none-bg = --chart-shade. No new token.
   Every cell paints var(--cell, var(--glass-bg)): a row only sets --cell (weekend, selected, hover — all opaque panel
   tokens, so the sticky cells never let the scrolled columns show through) and a tint layers its translucent colour
   over it, so one rule per tint covers every row state (F's layering).
   Orange only means "mine" (D-c): the Mine figure (.dgrid__sticky-2 .dgrid__v) and the range bar's mine dot. The
   selected row's bar is --text-primary, rank 1 and the raise arrow are opportunity green, the lower arrow is info blue.
   ===================================================================================================== */

/* F .grid-frame — the scrolling host. It declares the inline-size container the < 600px rule below queries. */
.dgrid-frame {
    overflow: auto;
    max-height: 420px;
    container: dgrid / inline-size;
}

/* F .rg — the <table> */
.dgrid {
    --dgrid-sticky-1-w: 206px;
    --dgrid-sticky-2-w: 92px;
    border-collapse: separate;
    border-spacing: 0;
    width: max-content;
    min-width: 100%;
    font: 400 12.5px var(--font-mono);
    font-variant-numeric: tabular-nums;
    color: var(--text-primary);
}

.dgrid th,
.dgrid td {
    box-sizing: border-box;
    height: 34px;
    padding: 0 10px;
    border-bottom: 1px solid var(--glass-border);
    white-space: nowrap;
    text-align: right;
    background: var(--cell, var(--glass-bg));
    font-weight: 400;
}

/* Row states only change --cell. Hover (0,3,2) wins over weekend and selected, as in F. */
.dgrid tbody tr.is-we {
    --cell: var(--color-panel-we);
}

.dgrid tbody tr:not(.mb) {
    cursor: pointer;
}

.dgrid tbody tr:not(.mb):hover {
    --cell: var(--glass-bg-hover);
}

.dgrid tbody tr.is-sel {
    --cell: var(--color-panel-3);
}

.dgrid tbody tr.is-sel .dgrid__sticky-1 {
    box-shadow: inset 3px 0 0 var(--text-primary);
}

.dgrid tbody tr:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: -2px;
}

/* The row's outline is painted under the opaque sticky cells (they stack above it), so the sticky cells draw the same
   2px ring themselves: top + bottom on both, plus the left edge on the first. It follows .is-sel, so focus wins while
   the row has it and the selected bar returns on blur. */
.dgrid tbody tr:focus-visible > .dgrid__sticky-1 {
    box-shadow: inset 2px 0 0 var(--color-primary), inset 0 2px 0 var(--color-primary), inset 0 -2px 0 var(--color-primary);
}

.dgrid tbody tr:focus-visible > .dgrid__sticky-2 {
    box-shadow: inset 0 2px 0 var(--color-primary), inset 0 -2px 0 var(--color-primary);
}

/* Sticky 46px header */
.dgrid thead th {
    position: sticky;
    top: 0;
    z-index: 3;
    height: 46px;
    padding-bottom: 6px;
    vertical-align: bottom;
    background: var(--glass-bg-light);
    border-bottom: 1px solid var(--glass-border-light);
    font: 500 10.5px/1.25 var(--font-mono);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-muted);
}

/* F .h-name — a hotel name in the header: UI face, two lines at most */
.dgrid__h-name {
    display: -webkit-box;
    max-width: 104px;
    margin-left: auto;
    overflow: hidden;
    white-space: normal;
    font: 500 11.5px/1.2 var(--font-body);
    text-transform: none;
    letter-spacing: 0;
    color: var(--text-primary);
    text-align: right;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
}

/* F .c-night / .c-mine — the two sticky columns; their widths are custom properties so a page can map its own */
.dgrid .dgrid__sticky-1 {
    position: sticky;
    left: 0;
    z-index: 2;
    width: var(--dgrid-sticky-1-w);
    min-width: var(--dgrid-sticky-1-w);
    max-width: var(--dgrid-sticky-1-w);
    padding-left: 16px;
    overflow: hidden; /* a safety net: the night's one line never slides under the sticky Mine column */
    text-align: left;
}

.dgrid .dgrid__sticky-2 {
    position: sticky;
    left: var(--dgrid-sticky-1-w);
    z-index: 2;
    min-width: var(--dgrid-sticky-2-w);
    border-right: 1px solid var(--glass-border-light);
}

.dgrid thead .dgrid__sticky-1,
.dgrid thead .dgrid__sticky-2 {
    z-index: 4;
}

/* F .nl / .lead — the night label (weekday bold on weekend rows) and its lead time */
.dgrid__nl {
    font-weight: 500;
    color: var(--text-primary);
}

.dgrid__wd {
    font-weight: 700;
}

.dgrid__lead {
    margin-left: 8px;
    font-size: 11px;
    color: var(--text-muted);
}

/* F .ev — an event on the night, warning hue (never orange). In the Night cell it gives way to the label and the
   high-demand dot, then an ellipsis (the tip names it). This base budget serves a Night cell without the .dgrid__night
   row (the playgrounds and the showcase): border-box (its own 12px padding counts), the column less the cell's 16 + 10px
   padding, the ~76px label and the pill's 8px margin = 96px at the 206px column. The rate grid sizes it from the
   remaining width instead (.dgrid__night below, #11928). */
.dgrid__ev {
    box-sizing: border-box;
    display: inline-block;
    max-width: calc(var(--dgrid-sticky-1-w) - 110px);
    margin-left: 8px;
    padding: 1px 6px;
    overflow: hidden;
    text-overflow: ellipsis;
    vertical-align: middle;
    border-radius: var(--radius-xs);
    font: 500 10.5px var(--font-mono);
    color: var(--color-warning);
    background: var(--color-warning-bg);
}

/* A high-demand dot after the pill takes its 13px (7px + 6px margin) out of the pill, so the overflow never clips it */
.dgrid__ev:has(+ .hd-dot) {
    max-width: calc(var(--dgrid-sticky-1-w) - 123px);
}

/* A low-impact event is muted (the pre-I-027 rg-event--low look); medium and high keep F's warning pill. */
.dgrid__ev--low {
    color: var(--text-secondary);
    background: var(--glass-bg-light);
}

/* CF-015 — a holiday on the night (no event): the muted low look with a dashed outline, so it never reads as an event */
.dgrid__ev--holiday {
    color: var(--text-secondary);
    background: var(--glass-bg-light);
    outline: 1px dashed var(--glass-border);
    outline-offset: -1px;
}

/* #11928 (B-065, I-038 D-o) — the Night cell's one row: the label, the event pill (or the lead label) and the high-demand
   dot in a flex wrapper inside the cell (the <th> stays a table cell — Firefox drops position: sticky on a flex <th>).
   The label and the dot keep their width; the pill takes what is left, up to F's .ev (max-width 96px under F's global
   box-sizing: border-box = 84px content + its 12px padding, measured at 1440 and 834), and ellipsizes inside it. */
.dgrid__night {
    display: flex;
    align-items: center;
    min-width: 0;
}

.dgrid__night > * {
    flex: none;
}

.dgrid__night > .dgrid__ev,
.dgrid__night > .dgrid__ev:has(+ .hd-dot) {
    flex: 0 1 auto;
    min-width: 0;
    max-width: 96px;
}

/* F .hd-dot — high demand (half or more of the market sold out) */
.hd-dot {
    display: inline-block;
    width: 7px;
    height: 7px;
    margin-left: 6px;
    vertical-align: 1px;
    border-radius: 2px;
    background: var(--color-warning);
}

/* CF-018 — F v14 .ud-mark: unusual demand (the market level well above the season's normal) — an info-blue rising arrow
   on a 15px tile after the night label / the High demand dot; it must never read as the amber dot */
.ud-mark {
    display: inline-grid;
    place-items: center;
    width: 15px;
    height: 15px;
    margin-left: 6px;
    vertical-align: -3px;
    border-radius: var(--radius-xs);
    font-size: 11px;
    color: var(--color-info);
    background: var(--color-info-bg);
}

/* In the legend the key leads its label: no left margin */
.cal-legend .ud-mark,
.cal-legend .hd-dot {
    margin-left: 0;
}

/* F .c-mine .v — my price, the grid's only orange figure */
.dgrid .dgrid__sticky-2 .dgrid__v {
    font-weight: 600;
    color: var(--color-primary-text);
}

/* F .chg — the price moved since the previous scan */
.dgrid__chg--up,
.dgrid__chg--down {
    margin-left: 3px;
    font-size: 10px;
}

.dgrid__chg--up {
    color: var(--rate-opportunity-text);
}

.dgrid__chg--down {
    color: var(--rate-threat-text);
}

/* F .dl — the delta against my price; coloured from tint level 2 */
.dgrid__dl {
    display: inline-block;
    min-width: 34px;
    margin-left: 6px;
    font-size: 11px;
    color: var(--text-muted);
}

/* F .cc / .c-market — competitor and market column widths */
.dgrid__cc {
    min-width: 116px;
}

.dgrid__market {
    min-width: 132px;
}

/* F .cc.threat-N / .cc.opportunity-N — the tint layered over the row's --cell */
.dgrid .tint-threat-1 {
    background: linear-gradient(var(--rate-threat-bg-1), var(--rate-threat-bg-1)) var(--cell, var(--glass-bg));
}

.dgrid .tint-threat-2 {
    background: linear-gradient(var(--rate-threat-bg-2), var(--rate-threat-bg-2)) var(--cell, var(--glass-bg));
}

.dgrid .tint-threat-3 {
    background: linear-gradient(var(--rate-threat-bg-3), var(--rate-threat-bg-3)) var(--cell, var(--glass-bg));
}

.dgrid .tint-opp-1 {
    background: linear-gradient(var(--rate-opportunity-bg-1), var(--rate-opportunity-bg-1)) var(--cell, var(--glass-bg));
}

.dgrid .tint-opp-2 {
    background: linear-gradient(var(--rate-opportunity-bg-2), var(--rate-opportunity-bg-2)) var(--cell, var(--glass-bg));
}

.dgrid .tint-opp-3 {
    background: linear-gradient(var(--rate-opportunity-bg-3), var(--rate-opportunity-bg-3)) var(--cell, var(--glass-bg));
}

.dgrid .tint-threat-2 .dgrid__dl,
.dgrid .tint-threat-3 .dgrid__dl {
    color: var(--rate-threat-text);
}

.dgrid .tint-opp-2 .dgrid__dl,
.dgrid .tint-opp-3 .dgrid__dl {
    color: var(--rate-opportunity-text);
}

/* F .sold / .los — sold out is neutral information; a minimum stay reads "N+" */
.chip-sold {
    display: inline-block;
    padding: 1px 6px;
    border: 1px dashed var(--glass-border-light);
    border-radius: var(--radius-xs);
    font-size: 10.5px;
    line-height: 1.3;
    color: var(--text-muted);
}

.chip-los {
    margin-left: 5px;
    padding: 0 3px;
    border: 1px solid var(--glass-border-light);
    border-radius: 3px;
    font-size: 10px;
    color: var(--text-muted);
}

/* CF-016 — F v12 .nst: the night states beside .chip-sold. Closed (out of season) is hatched from the line token, not on
   sale (rates not loaded yet) a dashed --text-secondary outline; both neutral information, legible in both themes */
.chip-closed,
.chip-nos {
    display: inline-block;
    padding: 1px 6px;
    border-radius: var(--radius-xs);
    font-size: 10.5px;
    line-height: 1.3;
    color: var(--text-muted);
    white-space: nowrap;
}

.chip-closed {
    border: 1px solid var(--glass-border-light);
    background: repeating-linear-gradient(135deg, var(--glass-border) 0 2px, transparent 2px 6px);
}

.chip-nos {
    border: 1px dashed var(--text-secondary);
}

/* F .los--mkt — the market column's min-stay marker: some priced competitor needs a minimum stay */
.chip-los.chip-los--mkt {
    margin-left: 4px;
    vertical-align: middle;
}

/* F .cc--closed / .cc--nos — a closed cell hatches over the row's --cell; a not-on-sale cell is never tinted */
.dgrid .rg-cell--closed {
    background: repeating-linear-gradient(135deg, var(--color-panel-3) 0 3px, transparent 3px 8px) var(--cell, var(--glass-bg));
}

.dgrid .rg-cell--nos {
    background: var(--cell, var(--glass-bg));
}

/* F .gaprow — one divider row for a closed season: its one th spans every column on the panel-3 ground; not a night,
   so no pointer and no hover */
.dgrid tbody tr.rg-gaprow,
.dgrid tbody tr.rg-gaprow:not(.mb):hover {
    --cell: var(--color-panel-3);
    cursor: default;
}

.dgrid tr.rg-gaprow th {
    text-align: left;
    font: 500 12px var(--font-body);
    color: var(--text-secondary);
}

.dgrid tr.rg-gaprow .chip-closed {
    margin-right: 8px;
}

/* F .rec-up / .rec-down — the suggestion's direction: raise = opportunity green, lower = info blue */
.dgrid__rec--up,
.dgrid__rec--down {
    margin-left: 3px;
    font-size: 10px;
}

.dgrid__rec--up {
    color: var(--rate-opportunity-text);
}

.dgrid__rec--down {
    color: var(--color-info);
}

/* CF-017 F v13 .rec-low / .rec-dot — a Low-confidence Suggested cell is muted; a suggestion that changed today ends in a
   small info-blue dot */
.rg-rec.rec-low {
    color: var(--text-muted);
}

.rec-dot {
    display: inline-block;
    width: 6px;
    height: 6px;
    margin-left: 5px;
    border-radius: 50%;
    background: var(--color-info);
    vertical-align: 2px;
}

/* F .rbar — the market range (54 x 4) with the median tick and my position as an orange dot */
.rbar {
    position: relative;
    display: inline-block;
    width: 54px;
    height: 4px;
    margin-left: 8px;
    vertical-align: middle;
    border-radius: 2px;
    background: var(--glass-border-light);
}

.rbar__med {
    position: absolute;
    top: -3px;
    width: 2px;
    height: 10px;
    margin-left: -1px;
    background: var(--color-chart-median);
}

.rbar__mine {
    position: absolute;
    top: -3px;
    box-sizing: border-box;
    width: 10px;
    height: 10px;
    margin-left: -5px;
    border: 2px solid var(--cell, var(--glass-bg));
    border-radius: 50%;
    background: var(--color-primary);
}

/* My price is outside the comp-set range: the dot sits at the edge as a hollow orange ring (the pre-I-027
   range-bar__mine--outside look; F has no outside state), so it never reads as a price at the min or the max. */
.rbar__mine--out {
    border-color: var(--color-primary);
    background: var(--cell, var(--glass-bg));
}

/* F .rank1 — I am the cheapest: opportunity green, never orange */
.rank-1 {
    font-weight: 600;
    color: var(--rate-opportunity-text);
}

/* F tr.mb — the month break */
.dgrid tr.mb th,
.dgrid tr.mb td {
    height: 26px;
    background: var(--color-panel-3);
    font: 600 10.5px var(--font-mono);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-secondary);
    text-align: left;
}

/* F .legend / .sw — the colour key beside a grid */
.dgrid-legend {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 14px;
    font: 400 11.5px var(--font-mono);
    color: var(--text-muted);
}

.dgrid-legend > span {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    white-space: nowrap;
}

/* Borderless: the global .position-* classes bring a border colour / style (.position-none a dashed one), never a width (#11918) */
.sw {
    display: inline-block;
    flex: none;
    width: 10px;
    height: 10px;
    border: 0;
    border-radius: 3px;
}

.sw--threat {
    background: var(--rate-threat-bg-2);
}

.sw--opp {
    background: var(--rate-opportunity-bg-2);
}

/* The weekend swatch is the weekend rows' own ground (--color-panel-we), outlined so it reads on the panel */
.sw--we {
    background: var(--color-panel-we);
    box-shadow: inset 0 0 0 1px var(--glass-border-light);
}

/* Position swatches use the one position family (.position-below / -at / -above / -none, RateFormat.PositionClass).
   .position-none is a dashed outline elsewhere; a borderless swatch needs F's faint --none-bg fill instead. */
.sw.position-none {
    background: var(--chart-shade);
}

/* A narrow frame (< 600px): the Night column gives up 56px — a container query on .dgrid-frame (the calendar's .rate-grid-host declares the same container) */
@container dgrid (max-width: 599.98px) {
    .dgrid {
        --dgrid-sticky-1-w: 150px;
    }

    /* the lead label ("in 3 d") does not fit beside the night at 150px; the event pill narrows itself */
    .dgrid__lead {
        display: none;
    }
}

/* #11941 (B-065, I-031 README D-t) — a phone-width page (<= 600px `page` container): the event pill drops to its own
   line under the night label, at the Night column less the cell's 16 + 10px padding, so a name keeps >= 10 characters;
   the high-demand dot stays beside it (its 7px + 6px margin come out of the pill). Only a night that has an event
   takes the second line (in the .dgrid__night row it wraps, the label taking the whole first line). */
@container page (max-width: 600px) {
    .dgrid .dgrid__sticky-1 .dgrid__nl:has(+ .dgrid__ev) {
        display: block;
        flex-basis: 100%;
    }

    .dgrid .dgrid__sticky-1 .dgrid__night:has(> .dgrid__ev) {
        flex-wrap: wrap;
    }

    .dgrid .dgrid__sticky-1 .dgrid__ev {
        max-width: calc(var(--dgrid-sticky-1-w) - 26px);
        margin: 2px 0 0;
    }

    .dgrid .dgrid__sticky-1 .dgrid__ev:has(+ .hd-dot) {
        max-width: calc(var(--dgrid-sticky-1-w) - 39px);
    }
}

/* =====================================================================================================
   Rate calendar (I-031) — prototype F's Rate calendar (f.src.html CSS: .page 252, .ph__sub.mono 259, tags .tag--warn /
   --info / --opp 204-206, .content--fill .page / .calpanel / .kstrip / .ks / .toolbar / .tb 427-439, .foot-note 481,
   month heat .mwrap / .months / .month__h / .mgrid / .mc / .heat-* / .ev-dot 483-510, night drawer content .figs / .fig /
   .rec / .norec / .tbl / .chart-body 513-557, .lockp / .btn.is-locked / .planhint--card / .toolbar__hints 1057-1075,
   container queries 1166-1243; markup calendarPage / calHints / monthView / nightDrawer 2303-2450, exportBtn 3174-3179).
   README D-g, D-i, D-j, D-k, D-l, D-m, D-n, D-o,
   D-p, D-q, D-s, D-t. Global and opt-in: nothing restyles until a page adds the class, so the heavy-data playground's
   calendar section, the calendar-annotated playground's heat section (F-176: no scoped CSS), the showcase and the Rate
   calendar share ONE definition. Tokens only — F roles as in the Data grid (I-027) header: --panel = --glass-bg,
   --panel-2 = --glass-bg-subtle, --line = --glass-border, --line-2 = --glass-border-light, --text = --text-primary,
   --text-2 = --text-secondary, --muted = --text-muted, --threat = --rate-threat, --event = --color-event (the event dot;
   the grid's event pill stays --color-warning), --heat-b1..3 / --heat-a1..3 = --color-heat-b1..3 / --color-heat-a1..3,
   --none-bg = --chart-shade, --at-bg = --position-at-bg, --chart-median = --color-chart-median, --primary-bg =
   --color-primary-bg, --primary-text = --color-primary-text, --r-xs = --radius-sm, --r-sm = --radius-md. No new
   token: F's --none-bg and --at-bg already are --chart-shade and --position-at-bg in both theme blocks.
   Reused, never redefined: the F frame (.page-wrapper--f / .page-container--f), .core-eyebrow (F .lab), the I-029
   toolbar item / label (.ins-toolbar__item / __label), the locked Segmented option (.ant-segmented-item.is-locked +
   .ins-hz-lock), .plan-lock, .plan-hint(--card), the I-027 grid (.dgrid-frame / table.dgrid) and swatch base .sw,
   the I-028 .sw--uc, the I-029 .sw--line / .sw--dash and table.tbl-f.
   Renamed on collision: F .toolbar → .cal-toolbar, .toolbar .legend → .cal-legend, .figs → .nd-figs, .chart-body →
   .nd-chart, .btn.is-locked → .ant-btn.is-locked, .face → the EmptyState face inside .calpanel.
   Orange only means "mine": my figure (.fig__val--mine), my row in the hotels table (table.tbl-f tr.is-mine), the
   panel-head .sw--line and the focus ring. Heat is the info-blue / amber families, the event dot the event amber, the
   undercut corner threat red; the toolbar Segmented, the locked Export button and the plan lock are neutral.
   ===================================================================================================== */

/* F .content--fill .page (427): the calendar frame fills #main-content's height (at least 560px) — the layout's content
   wrapper hands the height down — the panel flexes and the grid frame scrolls inside it (README D-g) */
.content-wrapper:has(> .page-wrapper--fill) {
    height: 100%;
}

.page-wrapper.page-wrapper--f.page-wrapper--fill {
    height: 100%;
}

.page-wrapper.page-wrapper--f.page-wrapper--fill > .page-container.page-container--f {
    height: 100%;
    min-height: 560px;
}

/* F .ph__sub.mono (259) — the calendar header's mono sub-line: freshness · guests · currency (README D-i) */
.page-header .page-subtitle.cal-sub,
.page-container.page-container--f > .page-header .page-subtitle.cal-sub {
    font: 400 12.5px var(--font-mono);
    color: var(--text-muted);
}

/* F .calpanel — one panel: KPI strip, toolbar, body (grid, month view or a face) (README D-j) */
.glass-card.calpanel {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    min-height: 0;
    padding: 0;
    overflow: hidden;
}

.calpanel .dgrid-frame {
    flex: 1 1 auto;
    min-height: 260px;
    max-height: none;
}

/* F .face inside the panel: the EmptyState faces (error, collecting, no competitors, no match) at F's 44px 20px */
.calpanel .empty-state {
    padding: 44px 20px;
}

/* The panel body under the toolbar (the grid or the month view): fills the panel and dims while a filter change reloads
   (the page's former .rate-calendar__surface--busy, I-031 TASK_04) */
.cal-body {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    min-height: 0;
    overflow: auto;
    transition: opacity var(--transition-base);
}

.cal-body.is-busy {
    opacity: 0.6;
}

/* The Rate calendar's own grid frame (RateCalendarGrid's .rate-grid, I-027) fills the panel body as .dgrid-frame does:
   one scroller, under the sticky header, inside the panel — no frame of its own inside the panel (README D-g) */
.calpanel .cal-body > .rate-grid-host {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    min-height: 0;
}

.calpanel .cal-body .rate-grid {
    flex: 1 1 auto;
    min-height: 260px;
    max-height: none;
    border: 0;
    border-radius: 0;
}

/* F loading: the body's skeleton rows at the panel's 16px inset */
.cal-skeleton {
    padding: 16px;
}

/* A failed horizon / filter reload (B-075 B3): the error alert and its Retry between the toolbar and the kept grid, at
   the panel's 16px inset; Retry wraps under the alert on a narrow panel */
.cal-reload-error {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 12px;
    padding: 12px 16px;
}

.cal-reload-error > .ant-alert {
    flex: 1 1 240px;
    min-width: 0;
}

/* The collecting face's scan progress: "n of N hotels checked" under a bar (I-031 TASK_04) */
.cal-progress {
    display: flex;
    flex-direction: column;
    gap: 6px;
    width: min(320px, 100%);
    font-size: 0.8125rem;
    color: var(--text-secondary);
    text-align: center;
}

/* F .kstrip / .ks — the KPI strip (README D-k) */
.kstrip {
    display: flex;
    flex-wrap: wrap;
    border-bottom: 1px solid var(--glass-border);
}

.ks {
    display: flex;
    flex: 1 1 auto;
    align-items: baseline;
    gap: 8px;
    min-width: 0;
    padding: 9px 16px;
    border-right: 1px solid var(--glass-border);
}

.ks:last-child {
    border-right: 0;
}

.ks > .core-eyebrow {
    white-space: nowrap;
}

.ks__val {
    white-space: nowrap;
    font: 600 15px var(--font-mono);
    font-variant-numeric: tabular-nums;
    color: var(--text-primary);
}

.ks__val small {
    font-size: 11.5px;
    font-weight: 400;
    color: var(--text-muted);
}

.ks__hint {
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    font-size: 12px;
    color: var(--text-muted);
}

/* F .toolbar[role=toolbar] inside the panel: the --panel-2 ground, a bottom rule (README D-j) */
.cal-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 14px;
    min-width: 0;
    padding: 8px 12px 8px 16px;
    border-bottom: 1px solid var(--glass-border);
    background: var(--glass-bg-subtle);
}

/* F .toolbar .seg — mono 12.5px options with F's 8px padding, the selected option on the panel ground with a --line-2
   ring, never orange (the AntD Segmented's selected item and thumb are primary-filled globally in overrides.css) */
.cal-toolbar .ant-segmented-item-label {
    padding: 0 8px;
    font: 500 12.5px var(--font-mono);
}

.cal-toolbar .ant-segmented-item-selected,
.cal-toolbar .ant-segmented-thumb {
    background: var(--glass-bg) !important;
    color: var(--text-primary) !important;
    box-shadow: 0 0 0 1px var(--glass-border-light) !important;
}

.cal-toolbar .ant-segmented-item-selected .ant-segmented-item-label {
    font-weight: 600;
}

/* F .toolbar .legend — the grid / heat colour key at the toolbar's right end (README D-l) */
.cal-legend {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 12px;
    margin-left: auto;
    font: 400 11px var(--font-mono);
    color: var(--text-muted);
}

.cal-legend > span {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    white-space: nowrap;
}

/* The grid legend's range-bar key (.rbar, Data grid) shows my dot mid-range (the page's former scoped rule, TASK_04) */
.cal-legend .rbar__mine {
    left: 50%;
}

/* CF-016 — F v12 stLegend: the min-stay key's "3+" sits flush (F's inline margin-left: 0) */
.cal-legend .chip-los {
    margin-left: 0;
}

/* CF-016 — F v12 nightDrawer: the All hotels Min stay column's "N+" sits flush too (F's inline margin-left: 0) */
.tbl-f .chip-los {
    margin-left: 0;
}

/* CF-016 — F v12 .sw--closed: the month legend's closed-day key, hatched like .mc--closed with a line-token edge */
.sw--closed {
    background: repeating-linear-gradient(135deg, var(--glass-border-light) 0 2px, transparent 2px 5px);
    box-shadow: inset 0 0 0 1px var(--glass-border-light);
}

/* F .heatkey — the three intensities of a side as one swatch group */
.heatkey {
    display: inline-flex;
    gap: 2px;
}

.heatkey .sw {
    border-radius: 2px;
}

/* F .toolbar__hints — the plan hints take their own row (README D-m) */
.toolbar__hints {
    display: flex;
    flex-basis: 100%;
    flex-wrap: wrap;
    gap: 4px 18px;
}

/* F .planhint a (937) — a plan hint's "Contact us" is neutral text-2 / 500 in the toolbar hints and the drawer's lock
   card: locks are never orange (the base .plan-hint__link rule is the pre-redesign primary link) */
.toolbar__hints .plan-hint__link,
.norec .plan-hint__link {
    color: var(--text-secondary);
    font-weight: 500;
}

/* F .foot-note — under the panel */
.foot-note {
    margin: 0;
    font: 400 11.5px var(--font-mono);
    color: var(--text-muted);
}

/* CF-016 — F v12 .ks-note: under the KPI strip, what the KPIs leave out (closed / not-on-sale competitor nights) */
.cal-kpi-note {
    display: flex;
    align-items: center;
    gap: 6px;
    margin: 0;
    padding: 8px 16px;
    border-bottom: 1px solid var(--glass-border);
    font: 400 11.5px var(--font-mono);
    color: var(--text-muted);
}

/* F v12 .season-banner — the info Alert above the panel while the property is closed; its text line in --text-secondary */
.season-banner {
    margin-bottom: 14px;
}

.season-banner .ant-alert-description {
    color: var(--text-secondary);
}

/* F .btn.is-locked (1061-1063) — a plan-locked button (Export CSV, README D-n): muted text, a dashed border, not-allowed,
   still focusable and clickable (aria-disabled), and NEVER dimmed (no opacity). It carries a .plan-lock. The selectors
   outrank the !important .ant-btn-default rest, hover and keyboard-focus looks (the focus one is (0,3,0) and would turn
   the text and border orange); the global focus ring (box-shadow) still draws on keyboard focus. */
.ant-btn.is-locked,
.ant-btn.is-locked:hover:not(:disabled),
.ant-btn.is-locked:focus-visible:not(:disabled),
.ant-btn.is-locked:active:not(:disabled) {
    cursor: not-allowed;
    border-style: dashed !important;
    border-color: var(--glass-border-light) !important;
    background: var(--glass-bg) !important; /* F .btn's --panel (I-033 TASK_01) */
    color: var(--text-muted) !important;
}

.ant-btn.is-locked .plan-lock {
    margin-left: 0;
}

/* F .mwrap / .months — the month heat view scrolls inside the panel (README D-o) */
.mwrap {
    flex: 1 1 auto;
    min-height: 0;
    padding: 16px;
    overflow: auto;
}

.months {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(440px, 100%), 1fr));
    align-content: start;
    gap: 22px 28px;
}

.month__h {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 8px;
}

/* the heading face comes from the global h1-h6 rule; F's 600 15px is the panel-title step */
.month__h h3 {
    margin: 0;
    font-size: var(--type-panel-title);
    font-weight: var(--type-panel-title-weight);
    color: var(--text-primary);
}

.month__h span {
    font: 400 11.5px var(--font-mono);
    color: var(--text-muted);
}

.mgrid {
    display: grid;
    grid-template-columns: repeat(7, minmax(0, 1fr));
    gap: 3px;
}

.mgrid__dow {
    padding: 0 6px 3px;
}

/* F .mc — one night: day + event dot, price, delta + sold-out count; no weekend tint */
.mc {
    position: relative;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    gap: 2px;
    min-width: 0;
    min-height: 70px;
    margin: 0;
    padding: 6px 7px;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    background: var(--chart-shade);
    color: var(--text-primary);
    text-align: left;
    font: inherit;
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
}

button.mc {
    cursor: pointer;
}

button.mc:hover {
    border-color: var(--text-secondary);
}

button.mc:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: 1px;
}

/* F's intensities (heat(n)): <= 10 %, <= 25 %, > 25 % each side of the median; at market; no data */
.heat-none {
    background: var(--chart-shade);
}

.heat-at {
    background: var(--position-at-bg);
}

.heat-b1 {
    background: var(--color-heat-b1);
}

.heat-b2 {
    background: var(--color-heat-b2);
}

.heat-b3 {
    background: var(--color-heat-b3);
}

.heat-a1 {
    background: var(--color-heat-a1);
}

.heat-a2 {
    background: var(--color-heat-a2);
}

.heat-a3 {
    background: var(--color-heat-a3);
}

.sw.heat-none {
    box-shadow: inset 0 0 0 1px var(--glass-border-light);
}

/* A blank lead-in cell and an untracked day (the day number only) */
.mc--blank {
    background: none;
}

.mc--off {
    border: 1px dashed var(--glass-border);
    background: none;
}

.mc--off .mc__day {
    color: var(--text-muted);
}

.mc.is-sel {
    box-shadow: 0 0 0 2px var(--text-primary);
}

.mc__top {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 4px;
}

.mc__day {
    font-size: 11.5px;
    font-weight: 600;
    color: var(--text-secondary);
}

.mc__ev {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--color-event);
    box-shadow: 0 0 0 1.5px var(--glass-bg);
}

/* CF-015 — a holiday night without an event: the same dot, outlined instead of filled */
.mc__ev--holiday {
    box-sizing: border-box;
    background: transparent;
    border: 1.5px solid var(--text-secondary);
}

.mc.is-under .mc__ev {
    margin-right: 9px;
}

/* CF-018 — F v14 .mc__marks: the day's top-line marks (unusual demand, then the event dot); .mc__ud the 13px info tile */
.mc__marks {
    display: inline-flex;
    align-items: center;
    gap: 3px;
}

.mc__ud {
    display: inline-grid;
    place-items: center;
    width: 13px;
    height: 13px;
    border-radius: 3px;
    font-size: 9px;
    font-style: normal;
    color: var(--color-info);
    background: var(--color-info-bg);
}

.mc__price {
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    font-size: 14.5px;
    font-weight: 600;
    line-height: 1.1;
}

.mc__price--sold {
    align-self: flex-start;
    padding: 1px 5px;
    border: 1px dashed var(--glass-border-light);
    border-radius: var(--radius-xs);
    font-size: 10.5px;
    font-weight: 500;
    color: var(--text-muted);
}

/* CF-016 — F v12 .mc--closed: a closed day of a seasonal property, hatched from the line token with a solid edge, and
   its "Closed" state line */
.mc.mc--closed {
    border-style: solid;
    background: repeating-linear-gradient(135deg, var(--glass-border) 0 2px, transparent 2px 7px);
}

.mc__st {
    font-size: 10px;
    color: var(--text-muted);
}

/* F .month-gap — the slim note that stands in for the closed months, across the whole .months grid */
.month-gap {
    grid-column: 1 / -1;
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    border: 1px dashed var(--glass-border-light);
    border-radius: var(--radius-xs);
    font: 500 12px var(--font-body);
    color: var(--text-secondary);
}

.mc__foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 4px;
    font-size: 10.5px;
    color: var(--text-secondary);
}

.mc__so {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    color: var(--text-muted);
}

/* F .mc.is-under::after — the 9px undercut corner (a competitor is cheaper than me), threat red */
.mc.is-under::after {
    content: '';
    position: absolute;
    top: 0;
    right: 0;
    border-top: 9px solid var(--rate-threat);
    border-left: 9px solid transparent;
    border-top-right-radius: 5px;
}

/* F .ev-dot — the legend's event key */
.ev-dot {
    display: inline-block;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--color-event);
}

/* The legend's holiday key (CF-015): the outlined month-view dot */
.ev-dot--holiday {
    box-sizing: border-box;
    background: transparent;
    border: 1.5px solid var(--text-secondary);
}

/* Night drawer content (README D-p, D-q, D-s). The body is the `nd` container F's 500px rule reads; F .nd__body stacks
   its panels 16px apart, the loading skeleton panels the same */
.night-drawer__body {
    container: nd / inline-size;
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.night-drawer__loading {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

/* F .tbl has no minimum width: in the drawer the hotels table takes its content width and scrolls inside its panel */
.night-drawer__body table.tbl-f {
    min-width: 0;
}

/* F .figs / .fig — the four figures (You, Median, Rank, Sold out) */
.nd-figs {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
}

.fig {
    display: flex;
    flex-direction: column;
    gap: 3px;
    min-width: 0;
    padding: 12px 14px;
    border-left: 1px solid var(--glass-border);
}

.fig:first-child {
    border-left: 0;
}

.fig__val {
    white-space: nowrap;
    font: 600 21px/1.15 var(--font-mono);
    font-variant-numeric: tabular-nums;
    color: var(--text-primary);
}

.fig__val small {
    font-size: 13px;
    font-weight: 400;
    color: var(--text-muted);
}

.fig__val--mine {
    color: var(--color-primary-text);
}

.fig__sub {
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    font: 400 11.5px var(--font-mono);
    color: var(--text-muted);
}

/* F .rec — the suggestion: price + delta beside the direction tags and the reason */
.rec {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    align-items: start;
    gap: 18px;
    padding: 14px 16px 16px;
}

.rec__price {
    display: block;
    margin-top: 4px;
    font: 600 30px/1.05 var(--font-mono);
    font-variant-numeric: tabular-nums;
    color: var(--text-primary);
}

.rec__delta {
    font: 400 12px var(--font-mono);
    color: var(--text-muted);
}

.rec__tags {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

.rec__reason {
    margin: 8px 0 0;
    font-size: 13.5px;
    color: var(--text-secondary);
}

/* F .norec — no suggestion for the night, or the plan-lock card in its place */
.norec {
    margin: 0;
    padding: 14px 16px 16px;
    color: var(--text-secondary);
}

.norec .plan-hint--card {
    margin: 0;
}

/* F .chart-body — the price-history chart's panel body */
.nd-chart {
    min-height: 240px;
    padding: 12px 12px 8px;
}

/* F .tag--opp / --info / --warn (204-206) on the Shell's .tag: the suggestion's Raise / Lower tags and the night's event /
   High-demand tags. F's color-mix() borders read the nearest token (--rate-opportunity-bg-3, --position-below-border,
   --position-above-border). Hold is the plain .tag. */
.tag--opp {
    border-color: var(--rate-opportunity-bg-3);
    background: var(--rate-opportunity-bg-1);
    color: var(--rate-opportunity-text);
}

.tag--info {
    border-color: var(--position-below-border);
    background: var(--color-info-bg);
    color: var(--color-info);
}

.tag--warn {
    border-color: var(--position-above-border);
    background: var(--color-warning-bg);
    color: var(--color-warning);
}

/* CF-016 — F v12 .tag--los: the drawer header's "min N nights" — a neutral tag with a dashed edge */
.tag.tag--los {
    border-style: dashed;
}

/* F v12 .note.note--los — the min-stay disclosure above All hotels: an info-blue icon and a --text-secondary line */
.note--los {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    margin: 0 16px 10px;
    font-size: 13.5px;
    color: var(--text-secondary);
}

.note--los > .anticon {
    flex: none;
    margin-top: 3px;
    color: var(--color-info);
}

/* The panel-head legend's competitors key (F .sw with --chart-comp) */
.sw--comp {
    background: var(--color-chart-comp);
}

/* F .tbl tr.is-mine — my row in the hotels table (orange = mine) */
table.tbl-f tr.is-mine > * {
    background: var(--color-primary-bg);
}

table.tbl-f tr.is-mine > :nth-child(2) {
    font-weight: 600;
    color: var(--color-primary-text);
}

/* F's page container queries (1166-1199) on the frame's `page` container — after the I-028 dashboard ones */
@container page (max-width: 820px) {
    .kstrip {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .ks {
        border-right: 0;
    }

    .ks:nth-child(odd) {
        border-right: 1px solid var(--glass-border);
    }

    .ks:nth-child(n + 3) {
        border-top: 1px solid var(--glass-border);
    }

    .cal-legend {
        margin-left: 0;
    }
}

@container page (max-width: 600px) {
    .page-wrapper.page-wrapper--f.page-wrapper--fill > .page-container.page-container--f {
        height: auto;
        min-height: 0;
    }

    .glass-card.calpanel {
        flex: none;
    }

    /* A half-width KPI cell on a phone: the value and the hint wrap under the label instead of running into the next
       cell (TASK_04 390 walk) */
    .ks {
        flex-wrap: wrap;
        row-gap: 2px;
    }

    .calpanel .dgrid-frame,
    .calpanel .cal-body .rate-grid {
        flex: none;
        max-height: 70vh;
    }

    .cal-body,
    .calpanel .cal-body > .rate-grid-host {
        flex: none;
    }

    .mwrap {
        flex: none;
        max-height: 75vh;
        padding: 12px;
    }

    .mc {
        min-height: 58px;
        padding: 4px 5px;
    }

    .mc__price {
        font-size: 12.5px;
    }

    /* A 45px phone cell holds 33px of content (TASK_07 390 walk): "Sold out" breaks onto two lines and the foot puts the
       sold-out count under the delta, instead of running past the cell edge (F's 600px rules leave both overflowing) */
    .mc__price--sold {
        max-width: 100%;
        padding: 1px 2px;
        white-space: normal;
        font-size: 10.5px;
        line-height: 1.15;
    }

    .mc__foot {
        flex-wrap: wrap;
        gap: 0 4px;
    }

    /* F .seg wraps: the label sits above the options and the options wrap inside the panel */
    .cal-toolbar .ins-toolbar__item {
        flex-wrap: wrap;
        max-width: 100%;
    }

    .cal-toolbar .ant-segmented {
        max-width: 100%;
    }

    .cal-toolbar .ant-segmented-group {
        flex-wrap: wrap;
    }
}

/* F @container nd (max-width: 500px) (1206-1210): the figures 2 x 2, the suggestion in one column */
@container nd (max-width: 500px) {
    .nd-figs {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .fig:nth-child(3) {
        border-left: 0;
    }

    .fig:nth-child(n + 3) {
        border-top: 1px solid var(--glass-border);
    }

    .rec {
        grid-template-columns: minmax(0, 1fr);
    }
}

/* =====================================================================================================
   Dashboard (I-028) — prototype F's dashboard (f.src.html CSS: page frame .content / .page 251-252, board .bt / .rh /
   .cell / .collect / .addbtn 329-373, queue .qgroup / .qi 375-398 + .qi__ic--info 652, .kline / .duo / .tk 400-422,
   .lockp 1057, .sw--uc 305, container queries 1158-1194; markup board / bandRow / buildQueue / queuePanel / kline /
   alertsPanel / movesPanel 2120-2296). README D-e, D-k, D-m, D-n, D-u. Global and opt-in: nothing restyles until a page
   adds the class, so the dashboard playground (/design-system/playground/dashboard; F-176: no scoped CSS) and the
   Dashboard share ONE definition. Tokens only — F roles as in the Data grid (I-027) header: --panel = --glass-bg,
   --panel-2 = --glass-bg-light, --panel-3 = --color-panel-3, --panel-we = --color-panel-we, --we-band = --color-we-band,
   --line = --glass-border, --line-2 = --glass-border-light, --row-hover = --color-row-hover, --text = --text-primary,
   --text-2 = --text-secondary, --muted = --text-muted, --threat = --rate-threat, --threat-1 / --threat-text =
   --rate-threat-bg-1 / --rate-threat-text, --opp-1 / --opp-text = --rate-opportunity-bg-1 / --rate-opportunity-text,
   --info / --info-bg = --color-info / --color-info-bg, --below-bg / --at-bg / --above-bg = the .position-* classes,
   --none-bg = --chart-shade, --r / --r-sm / --r-xs = --radius-lg / --radius-md / --radius-sm. F's color-mix() icon
   borders read the nearest token (--rate-threat-bg-3, --rate-opportunity-bg-3, --position-below-border).
   Orange only means "mine" (D-e): the mine avatar, my price in the row head (.dboard__rh__tn b), the mine-tone queue
   icon (.qi__ic--mine) and the focus ring. Unread badges (.badge-neutral), the weekend band, the collecting icon, the
   Segmented filter and the plan lock are neutral; .glow stays as I-021 AD5 defined it.
   The page container is the F frame's wrapper (.page-wrapper--f, no padding — F's .content box), so the container
   queries below measure the same width F's do; the padded .page-container--f would shift every breakpoint by 48px.
   ===================================================================================================== */

/* F .content / .page — the page frame (D-u): 1440px, 22 / 24 / 40px, a 16px column gap */
.page-wrapper.page-wrapper--f {
    padding: 0;
    container: page / inline-size;
}

.page-container.page-container--f {
    box-sizing: border-box;
    max-width: 1440px;
    margin: 0 auto;
    padding: 22px max(24px, env(safe-area-inset-right, 0px)) 40px max(24px, env(safe-area-inset-left, 0px));
    display: flex;
    flex-direction: column;
    gap: 16px;
}

/* The column gap spaces the children: drop the page container's owl margin and the header's own bottom margin */
.page-container.page-container--f > :not(style):not(.dev-path-badge) + :not(style):not(.dev-path-badge) {
    margin-top: 0;
}

.page-container.page-container--f > .page-header {
    margin-bottom: 0;
}

/* F .ph__sub (the body size, no own size) and .ph .btn (0 12px) — I-028 TASK_09 fidelity (pageSub 15 vs 14px,
   btn padding 15 vs 12px); the shared .page-subtitle / AntD button keep their size on every other page */
.page-container.page-container--f > .page-header .page-subtitle {
    font-size: var(--type-body);
}

.page-container.page-container--f > .page-header .ant-btn:not(.ant-btn-icon-only) {
    padding-inline: 12px;
}

/* F's 16px gutters at <= 640px follow the viewport (F's --gut-l / --gut-r) */
@media (max-width: 640px) {
    .page-container.page-container--f {
        padding-right: max(16px, env(safe-area-inset-right, 0px));
        padding-left: max(16px, env(safe-area-inset-left, 0px));
    }
}

/* F .panel with its own head / foot — the board, the queue and the duo panels draw their rows edge to edge */
.dboard,
.dqueue,
.dash-panel {
    min-width: 0;
    padding: 0;
}

.dash-panel__head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 10px 16px;
    padding: 12px 16px;
    border-bottom: 1px solid var(--glass-border);
}

/* The panel-title tier (F .panel__title 600 15px); the heading face comes from the global h1-h6 rule */
.dash-panel__title {
    margin: 0;
    font-size: var(--type-panel-title);
    font-weight: var(--type-panel-title-weight);
    line-height: 1.3;
    color: var(--text-primary);
}

.dash-panel__sub {
    margin: 2px 0 0;
    font-size: 12.5px;
    color: var(--text-muted);
}

.dash-panel__foot {
    border-top: 1px solid var(--glass-border);
}

/* F .board — the 14-night board */
.dboard .dash-panel__head {
    padding-bottom: 6px;
    border-bottom: 0;
}

.dboard__meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 16px;
}

/* F .sw--uc — the undercut swatch: the at-market ground with the threat corner */
.sw--uc {
    position: relative;
    background: var(--position-at-bg);
}

.sw--uc::after {
    content: '';
    position: absolute;
    top: 0;
    right: 0;
    border-left: 6px solid transparent;
    border-top: 6px solid var(--rate-threat);
}

.dboard__scroll {
    overflow-x: auto;
}

/* F .bt — a native <table> (I-027 D-a); every cell paints var(--cell, var(--glass-bg)) like .dgrid */
.dboard__table {
    width: 100%;
    min-width: 1130px;
    table-layout: fixed;
    border-collapse: separate;
    border-spacing: 0;
}

.dboard__table col.dboard__c-prop {
    width: 246px;
}

.dboard__table col.dboard__c-s {
    width: 72px;
}

.dboard__table th,
.dboard__table td {
    background: var(--cell, var(--glass-bg));
}

.dboard__table thead th {
    padding: 8px 2px;
    border-bottom: 1px solid var(--glass-border);
    vertical-align: bottom;
    text-align: center;
    font: 500 10.5px/1.3 var(--font-mono);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-muted);
}

.dboard__table thead .dboard__prop {
    padding-left: 16px;
    text-align: left;
}

.dboard__wd {
    display: block;
}

.dboard__dt {
    display: block;
    white-space: nowrap;
    font-size: 10.5px;
    text-transform: none;
    letter-spacing: -0.02em;
    color: var(--text-secondary);
}

/* The today column (the first night): its date is bold */
.dboard__table thead .is-today .dboard__dt {
    font-weight: 600;
    color: var(--text-primary);
}

.dboard__table thead .is-we .dboard__wd {
    font-weight: 600;
    color: var(--text-primary);
}

.dboard__table thead .dboard__stat {
    padding-right: 12px;
    text-align: right;
}

.dboard__table tbody th,
.dboard__table tbody td {
    height: 74px;
    padding: 5px 2px;
    border-bottom: 1px solid var(--glass-border);
    vertical-align: middle;
}

.dboard__table tbody tr:last-child th,
.dboard__table tbody tr:last-child td {
    border-bottom: 0;
}

/* F .c-prop — the sticky first column (246px through its col), opaque so the scrolled nights never show through */
.dboard__table .dboard__prop {
    position: sticky;
    left: 0;
    z-index: 2;
    padding: 8px 10px 8px 16px;
    border-right: 1px solid var(--glass-border);
    background: var(--glass-bg);
    text-align: left;
    font-weight: 400;
}

/* F .is-we / .we-start / .we-end — weekend columns: the stronger ground, framed by --line-2 rules */
.dboard__table .is-we {
    --cell: var(--color-panel-we);
}

.dboard__table .we-start {
    box-shadow: inset 1px 0 0 var(--glass-border-light);
}

.dboard__table .we-end {
    box-shadow: inset -1px 0 0 var(--glass-border-light);
}

.dboard__table .we-start.we-end {
    box-shadow: inset 1px 0 0 var(--glass-border-light), inset -1px 0 0 var(--glass-border-light);
}

/* F tr.bt-band — the "WEEKEND" band row above the night header */
.dboard__table thead tr.dboard__band th,
.dboard__table thead tr.dboard__band td {
    height: auto;
    padding: 8px 0 0;
    border-bottom: 0;
    vertical-align: bottom;
}

.dboard__band-label {
    display: block;
    margin: 0 1px;
    padding: 3px 0;
    border-radius: 6px 6px 0 0;
    background: var(--color-we-band);
    color: var(--text-primary);
    font: 600 9.5px/1.2 var(--font-mono);
    letter-spacing: 0.1em;
    text-transform: uppercase;
}

.dboard__table thead tr.dboard__band + tr th {
    padding-top: 6px;
}

/* F .c-s — the four trailing stat cells */
.dboard__table .dboard__stat {
    padding-right: 12px;
    text-align: right;
    font: 500 13px var(--font-mono);
    font-variant-numeric: tabular-nums;
}

.dboard__table .dboard__stat--first {
    border-left: 1px solid var(--glass-border);
}

.dboard__stat a {
    color: var(--text-primary);
    text-decoration-color: var(--glass-border-light);
    text-underline-offset: 3px;
}

/* F .rh — the row head: avatar, name (to the calendar), unread badge, tonight and median lines */
.dboard__rh {
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
}

.dboard__rh__txt {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.dboard__rh__top {
    display: flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
}

.dboard__rh__name {
    display: -webkit-box;
    overflow: hidden;
    font-size: 14px;
    font-weight: 600;
    line-height: 1.25;
    color: var(--text-primary);
    text-decoration: none;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
}

.dboard__rh__name:hover {
    color: var(--text-primary);
    text-decoration: underline;
}

.dboard__rh__tn {
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    font: 400 11.5px/1.35 var(--font-mono);
    color: var(--text-muted);
}

/* My price — "mine" */
.dboard__rh__tn b {
    font-size: 13px;
    font-weight: 600;
    color: var(--color-primary-text);
}

/* F .av.av--mine.av--lg — the 38px mine avatar (HotelAvatar's .hotel-avatar--mine, on the F mine ground) */
.dboard__av.hotel-avatar {
    width: 38px;
    height: 38px;
    border-radius: 10px;
    font: 600 12.5px/1 var(--font-mono);
}

.dboard__av.hotel-avatar--mine {
    background: var(--color-primary-bg);
    border-color: var(--color-primary-line);
    color: var(--color-primary-text);
}

/* F .cell — the night button, painted by the .position-below / -at / -above / -none family. Its border is set here
   so .position-*'s border colour and .position-none's dashed style never reach the cell (I-027 #11918). */
.dboard__cell {
    position: relative;
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 3px;
    width: 100%;
    height: 62px;
    padding: 0;
    border: 1px solid transparent;
    border-radius: var(--radius-md);
    color: var(--text-primary);
    cursor: pointer;
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
}

.dboard__cell.position-none {
    background: var(--chart-shade);
}

.dboard__cell:hover {
    border-color: var(--text-secondary);
}

.dboard__p {
    font-size: 12.5px;
    font-weight: 600;
    line-height: 1;
}

.dboard__d {
    font-size: 10.5px;
    line-height: 1;
    color: var(--text-secondary);
}

.dboard__so {
    font-size: 9.5px;
    line-height: 1.2;
    color: var(--text-muted);
    text-align: center;
}

/* CF-016 — F v12 .cell__so--closed (dashboard.data.light.offseason): a closed night, hatched like .chip-closed. The hatch
   only, as F: no padding or border, so "Closed" fits the ~39px night column at 1440 (a padded chip overflowed it) */
.dboard__so.dboard__so--closed {
    background: repeating-linear-gradient(135deg, var(--glass-border) 0 2px, transparent 2px 6px);
}

/* F .cell.is-uc::after — the undercut corner, a 7px threat triangle */
.dboard__cell.is-uc::after {
    content: '';
    position: absolute;
    top: 4px;
    right: 4px;
    border-left: 7px solid transparent;
    border-top: 7px solid var(--rate-threat);
    border-radius: 0 2px 0 0;
}

/* F .collect — a property still collecting its first rates (the row spans the nights and stats) */
.dboard__collect {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 6px 16px;
}

/* F queuePanel(em) — the first-run decision queue's collecting row sits under the panel head (B-075 AD12) */
.dqueue > .dboard__collect {
    padding: 14px 16px;
}

/* F .collect .face__ic.face__ic--wait — a waiting face, so the primary tone (I-037 D-p: Primary = F's wait tone, used by
   the waiting faces); I-038 TASK_02 (E02): it was the neutral face tone. The glyph is F's rendered colour, not the wait
   tone: F's `.collect span { color: var(--text-2) }` (0,1,1) beats `.face__ic--wait`'s colour, so F draws a text-2 glyph
   on the wait box (I-038 TASK_10, E02 measured: 195 200 208 dark / 58 63 74 light) */
.dboard__collect-ic {
    display: grid;
    flex: none;
    place-items: center;
    width: 38px;
    height: 38px;
    border: 1px solid var(--color-primary-line);
    border-radius: 12px;
    background: var(--color-primary-bg);
    color: var(--text-secondary);
    font-size: 13px;
}

.dboard__collect b {
    display: block;
    font-weight: 600;
}

/* The text's spans only: the icon is a span too and sets its own colour (I-038 TASK_08) */
.dboard__collect span:not(.dboard__collect-ic) {
    font-size: 13px;
    color: var(--text-secondary);
}

/* F .addbtn — the footer "Add property · N of M slots"; .is-locked at the plan limit (with a .plan-lock) */
.dboard__add {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 11px 16px;
    border: 0;
    border-radius: 0 0 var(--radius-lg) var(--radius-lg);
    background: none;
    color: var(--text-secondary);
    cursor: pointer;
    font: 500 14px var(--font-body);
    text-align: left;
}

.dboard__add:hover {
    background: var(--color-row-hover);
    color: var(--text-primary);
}

.dboard__add-slots {
    font: 400 11.5px var(--font-mono);
    color: var(--text-muted);
}

/* .dboard__add.is-locked — the plan-lock pattern's locked row, shared with the property picker's: the I-033 Elements block */

/* F .queue — Today's decisions: a Segmented filter, group headers, item rows, "Show all N" */
.dqueue__tools {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
}

/* F .seg: the selected option is the panel ground with a --line-2 ring, never orange (D-e). The AntD Segmented's
   selected item and thumb are primary-filled globally (overrides.css); inside the queue they read F's neutral look. */
.dqueue__seg .ant-segmented-item-selected,
.dqueue__seg .ant-segmented-thumb {
    background: var(--glass-bg) !important;
    color: var(--text-primary) !important;
    box-shadow: 0 0 0 1px var(--glass-border-light) !important;
}

.dqueue__seg .ant-segmented-item-selected {
    font-weight: 600;
}

.dqueue__seg .ant-segmented-item-label {
    font: inherit;
    font-family: var(--font-mono);
    font-size: 12.5px;
}

.dqueue__count {
    margin-left: 6px;
    font-weight: 400;
    color: var(--text-muted);
}

.dqueue__group {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 7px 16px;
    border-top: 1px solid var(--glass-border);
    border-bottom: 1px solid var(--glass-border);
    background: var(--glass-bg-light);
    font: 500 10.5px/1.3 var(--font-mono);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.dqueue__group:first-child {
    border-top: 0;
}

.dqueue__group .dqueue__count {
    margin-left: 0;
    color: var(--text-secondary);
}

/* F .qi — one decision: icon, title + description + night, property, figure, chevron */
.qi {
    display: grid;
    grid-template-columns: 32px minmax(0, 1fr) 176px 168px 16px;
    align-items: center;
    gap: 14px;
    width: 100%;
    padding: 10px 16px;
    border: 0;
    border-top: 1px solid var(--glass-border);
    background: none;
    color: var(--text-primary);
    cursor: pointer;
    font: inherit;
    text-align: left;
}

.dqueue__group + .qi {
    border-top: 0;
}

.qi:hover {
    background: var(--color-row-hover);
}

.qi__ic {
    display: grid;
    place-items: center;
    width: 32px;
    height: 32px;
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-md);
    background: var(--color-panel-3);
    color: var(--text-secondary);
}

/* A rate change on my price — "mine" */
.qi__ic--mine {
    background: var(--color-primary-bg);
    border-color: var(--color-primary-line);
    color: var(--color-primary-text);
}

.qi__ic--threat {
    background: var(--rate-threat-bg-1);
    border-color: var(--rate-threat-bg-3);
    color: var(--rate-threat-text);
}

.qi__ic--opportunity {
    background: var(--rate-opportunity-bg-1);
    border-color: var(--rate-opportunity-bg-3);
    color: var(--rate-opportunity-text);
}

.qi__ic--info {
    background: var(--color-info-bg);
    border-color: var(--position-below-border);
    color: var(--color-info);
}

.qi__main {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.qi__title {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    font-size: 14px;
    font-weight: 600;
}

.qi__desc {
    display: -webkit-box;
    overflow: hidden;
    font-size: 13px;
    line-height: 1.4;
    color: var(--text-secondary);
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
}

.qi__meta {
    font: 400 11.5px var(--font-mono);
    color: var(--text-muted);
}

/* The property inside the meta line — shown only once the property column is gone (<= 900px) */
.qi__meta-prop {
    display: none;
}

.qi__prop {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
    font-size: 13px;
    color: var(--text-secondary);
}

.qi__prop > span:last-child {
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

.qi__fig {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 2px;
    text-align: right;
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
}

.qi__fig .num {
    white-space: nowrap;
    font-size: 13px;
}

.qi__fig .sub {
    font-size: 11.5px;
    color: var(--text-muted);
}

.qi__go {
    color: var(--text-muted);
}

.dqueue__more {
    display: flex;
    justify-content: center;
    padding: 10px;
    border-top: 1px solid var(--glass-border);
    border-radius: 0 0 var(--radius-lg) var(--radius-lg);
    background: var(--glass-bg-light);
}

/* F .kline — the KPI line: four cells on one panel */
.kline {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-lg);
    background: var(--glass-bg);
}

.kline__cell {
    display: flex;
    flex-direction: column;
    gap: 3px;
    min-width: 0;
    padding: 10px 16px 11px;
    border-left: 1px solid var(--glass-border);
}

.kline__cell:first-child {
    border-left: 0;
}

.kline__row {
    display: flex;
    align-items: baseline;
    gap: 10px;
    min-width: 0;
}

.kline__val {
    white-space: nowrap;
    font: 600 19px/1.2 var(--font-mono);
    font-variant-numeric: tabular-nums;
    color: var(--text-primary);
}

.kline__val small {
    font-size: 12px;
    font-weight: 400;
    color: var(--text-muted);
}

.kline__hint {
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    font-size: 12.5px;
    color: var(--text-muted);
}

/* F .duo — latest alerts (7fr) beside biggest moves (5fr) */
.dash-duo {
    display: grid;
    grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
    align-items: start;
    gap: 16px;
}

/* F .tk-list / .tk — the ticker rows of both duo panels */
.tk-list {
    margin: 0;
    padding: 0;
    list-style: none;
}

.tk {
    display: grid;
    grid-template-columns: 6px 82px 108px minmax(0, 1fr) auto 46px;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 7px 16px;
    border: 0;
    border-top: 1px solid var(--glass-border);
    background: none;
    color: var(--text-primary);
    cursor: pointer;
    font: inherit;
    text-align: left;
}

.tk-list > li:first-child .tk {
    border-top: 0;
}

.tk:hover {
    background: var(--color-row-hover);
    /* The market-move rows are links: (0,2,0) keeps overrides.css a:hover's link colour off the row text */
    color: var(--text-primary);
}

.tk--move {
    grid-template-columns: 82px minmax(0, 1fr) auto 46px;
}

/* The unread dot (neutral information, never orange) */
.tk__dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--color-info);
}

.tk__night {
    white-space: nowrap;
    font: 500 12px var(--font-mono);
    color: var(--text-secondary);
}

.tk__type {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    white-space: nowrap;
    font: 500 10.5px var(--font-mono);
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

.tk__type--threat {
    color: var(--rate-threat-text);
}

.tk__type--opportunity {
    color: var(--rate-opportunity-text);
}

.tk__type--neutral {
    color: var(--text-muted);
}

.tk__main {
    display: flex;
    flex-direction: column;
    min-width: 0;
    line-height: 1.35;
}

.tk__head {
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    font-size: 13.5px;
    font-weight: 500;
}

.tk__meta {
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    font-size: 12px;
    color: var(--text-muted);
}

.tk__px {
    white-space: nowrap;
    text-align: right;
    font: 400 12.5px var(--font-mono);
    color: var(--text-secondary);
}

.tk__pct {
    white-space: nowrap;
    text-align: right;
    font: 600 12.5px var(--font-mono);
}

/* F .lockp — the plan lock: a neutral dashed pill with a lock and the plan that includes the option (D-k) */
.plan-lock {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    height: 16px;
    margin-left: 5px;
    padding: 0 4px;
    border: 1px dashed var(--glass-border-light);
    border-radius: var(--radius-xs);
    white-space: nowrap;
    vertical-align: 1px;
    font: 500 10px/1 var(--font-mono);
    letter-spacing: 0;
    text-transform: none;
    color: var(--text-muted);
}

.plan-lock__icon {
    flex: none;
    font-size: 10px;
}

/* The focus ring (orange, D-e) on every dashboard button, inset so the panel never clips it */
.dboard__cell:focus-visible,
.dboard__add:focus-visible,
.qi:focus-visible,
.tk:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: -2px;
}

/* F's page container queries (1158-1194): page internals follow the content width */
@container page (max-width: 1000px) {
    .dash-duo {
        grid-template-columns: minmax(0, 1fr);
    }
}

@container page (max-width: 900px) {
    .qi {
        grid-template-columns: 32px minmax(0, 1fr) 150px 16px;
    }

    .qi__prop {
        display: none;
    }

    .qi__meta-prop {
        display: inline;
    }
}

@container page (max-width: 820px) {
    .kline {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .kline__cell:nth-child(3) {
        border-left: 0;
    }

    .kline__cell:nth-child(n + 3) {
        border-top: 1px solid var(--glass-border);
    }
}

@container page (max-width: 600px) {
    .page-container.page-container--f {
        padding-top: 16px;
    }

    .kline {
        grid-template-columns: minmax(0, 1fr);
    }

    .kline__cell.kline__cell {
        border-left: 0;
    }

    .kline__cell + .kline__cell {
        border-top: 1px solid var(--glass-border);
    }

    .tk {
        grid-template-columns: 6px 74px minmax(0, 1fr) 42px;
        gap: 8px;
        padding: 9px 12px;
    }

    .tk--move {
        grid-template-columns: 74px minmax(0, 1fr) 42px;
    }

    .tk__type,
    .tk .tk__px {
        display: none;
    }

    .qi {
        grid-template-columns: 30px minmax(0, 1fr);
        gap: 12px;
        padding: 10px 12px;
    }

    .qi__fig {
        grid-column: 2;
        flex-direction: row;
        align-items: flex-start;
        gap: 10px;
        text-align: left;
    }

    .qi__go {
        display: none;
    }

    .dqueue__group {
        padding: 7px 12px;
    }
}

/* =====================================================================================================
   Insights (I-029) — prototype F's Insights page (f.src.html CSS: .lab 84, .seg 285-290, .legend / .sw 303-310,
   .toolbar / .tb 436-439, .tbl / .hc / .tscroll 542-551 + 849-852, Insights 863-900, .lockp / .is-locked 1057-1064,
   .toolbar__hints 1074, page container queries 1247-1282; markup insightsPage 3051-3107, hzButtons 3163-3172).
   README D-b, D-h, D-j, D-k, D-l, D-m, D-o. Global and opt-in: nothing restyles until a page adds the class, so the
   heavy-data playground's F section (/design-system/playground/heavy-data; F-176: no scoped CSS) and Rate insights share
   ONE definition. Tokens only — F roles as in the I-028 dashboard block header, plus --chart-comp = --color-chart-comp,
   --band = --chart-band, --band-edge = --color-chart-band-edge (new, both theme blocks), --heat-a2 = --color-heat-a2,
   --threat-3 / --opp-3 = --rate-threat-bg-3 / --rate-opportunity-bg-3, --font-ui = --font-body.
   Reused, never redefined: the F frame (.page-wrapper--f / .page-container--f), .kline / .kline__*, .qi__ic--*,
   .plan-lock, .dash-panel / __head / __title / __sub (F .panel), and .sw (the I-027 data-grid swatch base).
   Renamed on collision: F .toolbar → .ins-toolbar, .legend → .ins-legend (.dgrid-legend is the grid's), .trend →
   .ins-trend, .tbl → table.tbl-f (the native form of I-027's AntD .table--f), .tscroll → .tbl-f__scroll, .sw--we →
   .sw--ins-we (.sw--we is the grid's weekend-row swatch on --color-panel-we; the trend's weekend is --color-row-hover).
   Text tones reuse .rate-text--threat / --opportunity / --muted and .position-text--below / --above (no .t-* classes).
   Locked Segmented item (D-h): AntD's SegmentedItem takes a Class but no attributes, so the hook is
   <SegmentedItem Class="is-locked" Disabled> (AntD then never selects it) whose content is a focusable
   span.ins-hz-lock[tabindex=0][role=button][aria-disabled=true][data-tip][aria-label="{n} · {tip}"] holding the number
   and a .plan-lock. AntD's disabled item has no opacity; .is-locked replaces its colour, not F's native .seg.
   Orange only means "mine" (D-l): .sw--line, .sw--bar, .wkb__bar--mine, .wkb__v and the focus ring. The suggested
   swatch (.sw--sugg) reads the chart's own --chart-color, so it is paired with .chart-tone--recommended; the toolbar
   Segmented, the callout icons (.qi__ic--threat / --opportunity / --info, never --mine) and the plan lock are neutral.
   ===================================================================================================== */

/* F .ph__sub — the data-freshness sub-line under the page title. F's insightsPage head() draws a plain .ph__sub (body
   size, --text-2), not the dashboard's .ph__sub.mono (I-029 TASK_07 fidelity: pageSub 12.5 vs 14px, muted vs --text-2) */
.page-header .page-subtitle.ins-sub,
.page-container.page-container--f > .page-header .page-subtitle.ins-sub {
    font-size: var(--type-body);
    color: var(--text-secondary);
}

/* F .panel > .toolbar[role=toolbar] — one panel on the toolbar ground (F: border-bottom 0, radius --r) */
.glass-card.ins-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 14px;
    min-width: 0;
    padding: 8px 12px 8px 16px;
    background: var(--glass-bg-light);
}

/* F .tb — a label and its control */
.ins-toolbar__item {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    min-width: 0;
}

/* F .lab */
.ins-toolbar__label {
    white-space: nowrap;
    font: 500 10.5px/1.3 var(--font-mono);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.ins-toolbar__item .ant-select {
    width: 220px;
    max-width: 100%;
}

/* F .toolbar__hints — the inline plan hint takes its own row */
.ins-toolbar__hints {
    display: flex;
    flex-basis: 100%;
    flex-wrap: wrap;
    gap: 4px 18px;
}

/* F .seg inside the toolbar: mono 12.5px options, 8px padding, the selected option on the panel ground with a --line-2
   ring — never orange (D-l). The AntD Segmented's selected item and thumb are primary-filled globally (overrides.css). */
.ins-toolbar .ant-segmented-item-label {
    padding: 0 8px;
    font: 500 12.5px var(--font-mono);
}

.ins-toolbar .ant-segmented-item-selected,
.ins-toolbar .ant-segmented-thumb {
    background: var(--glass-bg) !important;
    color: var(--text-primary) !important;
    box-shadow: 0 0 0 1px var(--glass-border-light) !important;
}

.ins-toolbar .ant-segmented-item-selected .ant-segmented-item-label {
    font-weight: 600;
}

/* F .seg button.is-locked — a plan-locked option: muted, not-allowed, regular weight, and NOT dimmed (no opacity) */
.ant-segmented-item.is-locked,
.ant-segmented-item.is-locked:hover {
    cursor: not-allowed;
    font-weight: 400;
    color: var(--text-muted) !important;
}

.ant-segmented-item.is-locked .ant-segmented-item-label {
    font-weight: 400;
}

/* AntD keeps a disabled item's hidden radio focusable: the locked option is ONE tab stop (its .ins-hz-lock), as F's button
   (I-029 TASK_04 fix). The radio is never checked — the item is Disabled — so nothing reads it. */
.ant-segmented-item.is-locked .ant-segmented-item-input {
    display: none;
}

/* The focusable content of a locked item (aria-disabled, the tip in data-tip): the number + the I-028 .plan-lock, which
   already is F's .lockp (16px, dashed --glass-border-light, 500 10px mono, margin-left 5px) — not redefined here */
.ins-hz-lock {
    display: inline-flex;
    align-items: center;
    cursor: not-allowed;
}

.ins-hz-lock:focus-visible {
    outline: none;
}

/* F .kline--5 — the Insights KPI line: five cells, the value above its hint, the hint wraps */
.kline--5 {
    grid-template-columns: repeat(5, minmax(0, 1fr));
}

.kline--5 .kline__row {
    flex-direction: column;
    align-items: stretch;
    gap: 1px;
}

.kline--5 .kline__hint {
    display: block;
    white-space: normal;
    line-height: 1.35;
}

/* F .kl__val--text — a name as the value (the toughest competitor): the UI face, one line, ellipsis */
.kline__val--text {
    overflow: hidden;
    max-width: 100%;
    white-space: nowrap;
    text-overflow: ellipsis;
    font: 600 15px/1.35 var(--font-body);
}

/* F .legend in a panel head */
.ins-legend {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 14px;
    font: 400 11.5px var(--font-mono);
    color: var(--text-muted);
}

.ins-legend > span {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    white-space: nowrap;
}

/* F .sw--line / --dash / --band / --we / --ev / --bar / --medbar on the .sw base; .sw--sugg is the suggested series */
.sw--line {
    width: 14px;
    height: 0;
    border-radius: 0;
    border-top: 2.5px solid var(--color-primary);
}

.sw--dash {
    width: 14px;
    height: 0;
    border-radius: 0;
    border-top: 2px dashed var(--chart-median);
}

.sw--sugg {
    width: 14px;
    height: 0;
    border-radius: 0;
    border-top: 2px dotted var(--chart-color);
}

.sw--band {
    width: 14px;
    background: var(--chart-band);
    box-shadow: inset 0 0 0 1px var(--color-chart-band-edge);
}

.sw--ins-we {
    background: var(--color-row-hover);
    box-shadow: inset 0 0 0 1px var(--glass-border-light);
}

.sw--ev {
    background: var(--color-heat-a2);
}

.sw--bar {
    background: var(--color-primary);
}

.sw--medbar {
    background: var(--color-chart-comp);
    box-shadow: inset 0 0 0 1px var(--color-chart-band-edge);
}

/* F .trend — the trend chart's box inside its panel */
.ins-trend {
    min-height: 300px;
    padding: 12px 12px 8px;
}

/* F trendChart: a weekend column fills var(--row-hover), as its .sw--ins-we swatch does (D-k). LineChart's own weekend
   shade (--chart-shade) stays on the night drawer (D-c); events keep --color-heat-a2 (I-029 TASK_07 walk fix) */
.ins-trend .line-chart__shade:not(.line-chart__shade--event) {
    fill: var(--color-row-hover);
}

/* The states and panels under the toolbar stack at the F frame's 16px rhythm (they sit inside the aria-live wrapper, so the
   frame's own column gap does not reach them; I-029 TASK_05 fix) */
.ins-stack {
    display: flex;
    flex-direction: column;
    gap: 16px;
    min-width: 0;
}

/* F .ins-grid — weekday pattern (7fr) beside what stands out (5fr) */
.ins-grid {
    display: grid;
    grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
    align-items: start;
    gap: 16px;
}

/* F .wkb — weekday bars: my average (orange, "mine") beside the market median, Fri / Sat named in bold */
.wkb {
    display: grid;
    grid-template-columns: repeat(7, minmax(0, 1fr));
    gap: 6px;
    padding: 30px 16px 6px;
}

.wkb__day {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 5px;
    min-width: 0;
}

.wkb__plot {
    display: flex;
    align-items: flex-end;
    justify-content: center;
    gap: 3px;
    width: 100%;
    height: 150px;
    border-bottom: 1px solid var(--glass-border-light);
}

.wkb__bar {
    position: relative;
    width: min(22px, 40%);
    border-radius: 4px 4px 0 0;
}

.wkb__bar--mine {
    background: var(--color-primary);
}

.wkb__bar--med {
    background: var(--color-chart-comp);
    box-shadow: inset 0 0 0 1px var(--color-chart-band-edge);
}

.wkb__v {
    position: absolute;
    bottom: calc(100% + 3px);
    left: 50%;
    transform: translateX(-50%);
    white-space: nowrap;
    font: 600 10.5px var(--font-mono);
    color: var(--color-primary-text);
}

.wkb__name {
    font: 500 11px var(--font-mono);
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.wkb__name.is-we {
    font-weight: 600;
    color: var(--text-primary);
}

.wkb__d {
    font: 500 11px var(--font-mono);
}

/* :where() — the gap's .position-text--below / --above colour wins over the neutral default */
:where(.wkb__d) {
    color: var(--text-secondary);
}

.wkb__legend {
    padding: 4px 16px 14px;
}

/* F .callouts — what stands out: one row per callout with a 30px tone icon (.qi__ic--threat / --opportunity / --info) */
ul.callouts {
    margin: 0;
    padding: 0;
    list-style: none;
}

.callouts li {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 12px 16px;
    border-top: 1px solid var(--glass-border);
    font-size: 13.5px;
    color: var(--text-secondary);
}

.callouts li:first-child {
    border-top: 0;
}

.callouts b {
    font-weight: 600;
    color: var(--text-primary);
}

.callouts .qi__ic {
    flex: none;
    width: 30px;
    height: 30px;
}

/* F .tscroll > table.tbl — the native list table (README D-m; I-027's .table--f values): it scrolls inside its panel */
.tbl-f__scroll {
    overflow-x: auto;
    border-radius: 0 0 var(--radius-lg) var(--radius-lg);
}

table.tbl-f {
    width: 100%;
    min-width: 760px;
    border-collapse: collapse;
    font: 400 12.5px var(--font-mono);
    font-variant-numeric: tabular-nums;
}

table.tbl-f thead th {
    padding: 8px 12px;
    text-align: right;
    white-space: nowrap;
    border-bottom: 1px solid var(--glass-border);
    background: var(--glass-bg-light);
    font: 500 10.5px var(--font-mono);
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--text-muted);
}

table.tbl-f tbody td,
table.tbl-f tbody th[scope="row"] {
    padding: 7px 12px;
    text-align: right;
    white-space: nowrap;
    border-bottom: 1px solid var(--glass-border);
    font: 400 12.5px var(--font-mono);
    font-variant-numeric: tabular-nums;
    color: var(--text-primary);
}

table.tbl-f tbody tr:last-child > * {
    border-bottom: 0;
}

table.tbl-f tr > :first-child,
table.tbl-f .l {
    text-align: left;
}

table.tbl-f tbody tr:hover > * {
    background: var(--color-row-hover);
}

/* F .sorth — a sortable header: the header's own font, the sorted one (is-on, aria-sort on its th) in the text colour */
.sorth {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 0;
    border: 0;
    background: none;
    white-space: nowrap;
    font: inherit;
    letter-spacing: inherit;
    text-transform: inherit;
    color: inherit;
    cursor: pointer;
}

.sorth:hover,
.sorth.is-on {
    color: var(--text-primary);
}

/* F .hc — the hotel cell: avatar + name (ellipsis) */
.hc {
    display: flex;
    align-items: center;
    gap: 8px;
    max-width: 230px;
    font: 500 13px var(--font-body);
}

.hc > span:not(.hotel-avatar) {
    overflow: hidden;
    text-overflow: ellipsis;
}

/* F .ixbar — price index around the 100 axis: below in the threat family, above in the opportunity family */
.ixbar {
    position: relative;
    display: inline-block;
    width: 90px;
    height: 8px;
    margin-right: 10px;
    border-radius: 2px;
    vertical-align: middle;
    background: var(--color-panel-3);
}

.ixbar__axis {
    position: absolute;
    top: -3px;
    bottom: -3px;
    left: 50%;
    width: 1px;
    background: var(--chart-median);
}

.ixbar__fill {
    position: absolute;
    top: 0;
    bottom: 0;
    border-radius: 2px;
}

.ixbar__fill--below {
    background: var(--rate-threat-bg-3);
}

.ixbar__fill--above {
    background: var(--rate-opportunity-bg-3);
}

.ixlab {
    display: inline-block;
    min-width: 40px;
}

/* F .share — undercut share: a 56px track with a threat fill, then the % */
.share {
    display: inline-flex;
    align-items: center;
    gap: 8px;
}

.share__t {
    overflow: hidden;
    width: 56px;
    height: 6px;
    border-radius: 3px;
    background: var(--color-panel-3);
}

.share__f {
    display: block;
    height: 100%;
    background: var(--rate-threat);
}

/* The focus ring (orange, D-l) on the locked option and the sort buttons */
.ant-segmented-item.is-locked:has(.ins-hz-lock:focus-visible),
.sorth:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: -2px;
}

/* F's page-type container queries (1247-1282) on the frame's `page` container — after the I-028 dashboard ones */
@container page (max-width: 1000px) {
    .ins-grid {
        grid-template-columns: minmax(0, 1fr);
    }

    .kline--5 {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }

    .kline--5 .kline__cell:nth-child(4) {
        border-left: 0;
    }

    .kline--5 .kline__cell:nth-child(n + 4) {
        border-top: 1px solid var(--glass-border);
    }
}

@container page (max-width: 820px) {
    .kline--5 {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .kline--5 .kline__cell:nth-child(4) {
        border-left: 1px solid var(--glass-border);
    }

    .kline--5 .kline__cell:nth-child(5) {
        border-left: 0;
    }
}

@container page (max-width: 600px) {
    .kline--5 {
        grid-template-columns: minmax(0, 1fr);
    }

    .kline--5 .kline__cell.kline__cell {
        border-left: 0;
    }

    .wkb {
        gap: 3px;
        padding: 16px 10px 6px;
    }

    .wkb__v {
        font-size: 9.5px;
    }

    /* F .seg wraps: on a narrow page the label sits above the options and the options wrap inside the panel */
    .ins-toolbar__item {
        flex-wrap: wrap;
        max-width: 100%;
    }

    .ins-toolbar .ant-segmented {
        max-width: 100%;
    }

    .ins-toolbar .ant-segmented-group {
        flex-wrap: wrap;
    }
}

/* A phone-width page (merge gate #12131): seven weekday columns are ~44px wide, too narrow for a value such as
   "RSD 12,400" — the labels would overlap. Hide them as the pre-I-029 WeekdayBars did below 480px; each day keeps its
   numbers in the aria-label and the data-tip. */
@container page (max-width: 480px) {
    .wkb__v {
        display: none;
    }
}

/* =====================================================================================================
   Overlays (I-030) — prototype F's modal, drawer and Popconfirm (f.src.html CSS: .iconbtn / --line 182-185, .mask 228,
   .btn--danger-solid 279, .nd / __head / __bar / .pager / .nd__body 513-529, .pop 604-607, .popc 679-680, .hcard / .hsec
   726-739, .planhint 769-770, .nd--form / __title / __sub / __foot + .modal / __head / __title / __body / __foot 828-840,
   phone 1230-1284; markup popBtn / renderPop 2645-2665, cmpDrawer 2922, setModal 2942). README D-g, D-h, D-i, D-j, D-k,
   D-n, D-x. Global and opt-in: the AntD-level surface (mask, panel, head, footer, confirm dialogs) lives in overrides.css
   "Modal/Drawer Overrides"; this block holds the F anatomy a component opts into — .modal-f (Modal WrapClassName),
   .drawer-head / .drawer-body / .drawer-section / .drawer-card / .drawer-foot (EntityFormDrawer and the rollouts),
   .danger-popconfirm (DangerPopconfirm's OverlayClassName) — plus the ported rules of the overlay components' scoped
   sheets (D-x), under their own class names and prefixed with the component's root class so they stay scoped.
   Tokens only — F roles as in the I-028 dashboard block header: --panel = --glass-bg, --panel-2 = --glass-bg-light,
   --panel-3 = --color-panel-3, --line = --glass-border, --line-2 = --glass-border-light, --text = --text-primary,
   --text-2 = --text-secondary, --muted = --text-muted, --r = --radius-lg, --r-sm = --radius-md, --shadow =
   --shadow-popup, --warn = --color-warning, --err / --on-err = --color-error-solid / --color-on-error-solid,
   --font-ui = --font-body.
   Orange only means "mine": the checked .drawer-card (the user's own selection) and the primary buttons. Danger is red
   (the Popconfirm's solid OK — overrides.css "Danger Button Overrides", the one .btn--danger-solid), the Popconfirm's icon amber; the close, pager, eyebrow and notices are neutral.
   Renamed on collision: none (.modal-help, .modal-f, .drawer-*, .danger-popconfirm were free in app.css and
   overrides.css). The command palette (.command-palette-wrap, I-025) and the property-picker / help popovers never
   match a rule here.
   ===================================================================================================== */

/* --- Modal (F .modal, D-h): opt-in through the Modal's WrapClassName="modal-f" --------------------------------------- */

/* F .modal: top 72px; the 540px width is the Modal's Width (OverlaySizes.Modal) */
.modal-f .ant-modal {
    top: 72px;
    padding-bottom: 24px;
}

/* F .modal__body: a column with an 18px gap (paddings are overrides.css's, every modal) */
.modal-f .ant-modal-body {
    display: flex;
    flex-direction: column;
    gap: 18px;
}

/* F .modal__body > p — the one help paragraph that opens the body */
.ant-modal-body .modal-help,
.modal-help {
    margin: 0;
    font-size: 13.5px;
    line-height: 1.5;
    color: var(--text-secondary);
}

/* F .fi — label (required: " *" from .form-field__label--required), the field, its error (role="alert") and help */
.modal-f .form-field {
    gap: 6px;
    margin-bottom: 0;
}

/* F .fi__label: 500 12px mono, --text-2 (I-030 TASK_08 fidelity: was 13px / --text) */
.modal-f .form-field__label {
    font-family: var(--font-mono);
    font-size: 12px;
    font-weight: 500;
    letter-spacing: 0.01em;
    color: var(--text-secondary);
}

.modal-f .form-field__hint {
    font-size: 12.5px;
    color: var(--text-muted);
}

.modal-f .form-field__hint--error {
    color: var(--color-error);
}

/* F .fi — the AntD FormItem a modal still uses (ChangeEmailModal, DeleteAccountModal): the .fi__label face, no item
   margin (the body's 18px gap spaces the blocks) */
.modal-f .ant-form-item {
    margin-bottom: 0;
}

.modal-f .ant-form-item-label > label {
    font-family: var(--font-mono);
    font-size: 12px;
    font-weight: 500;
    letter-spacing: 0.01em;
    color: var(--text-secondary);
}

/* F .input: a --line-2 edge (the global input draws --line); overrides.css's focus / disabled / read-only rules, later
   in the cascade, still win at equal specificity */
.modal-f .ant-input {
    border-color: var(--glass-border-light) !important;
}

.modal-f .ant-input:hover:not(:disabled):not(:focus):not([readonly]) {
    border-color: var(--glass-border-strong) !important;
}

/* F .modal__foot sits on --panel-2 with the content's bottom radius */
.modal-f .ant-modal-footer {
    border-radius: 0 0 var(--radius-lg) var(--radius-lg);
}

/* F ≤ 640px: top-aligned with a 16px inset */
@media (max-width: 640px) {
    .modal-f .ant-modal {
        top: 16px;
        max-width: calc(100vw - 32px);
        margin: 0 auto;
        padding-bottom: 16px;
    }
}

/* --- Drawer (F .nd, D-j): the head goes through the AntD title slot, the foot is the body's sticky last child ------- */

/* F .nd__head: a bar (eyebrow · pager · close) above the title */
.drawer-head {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    gap: 10px;
    width: 100%;
    min-width: 0;
}

/* F .nd__bar */
.drawer-head__bar {
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
}

/* The bar's first item (eyebrow, or the title when there is none) takes the free width */
.drawer-head__bar > :first-child {
    flex: 1 1 auto;
    min-width: 0;
}

/* F .nd__bar .lab — mono uppercase label, one line */
.drawer-head__eyebrow {
    display: block;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    font: 500 10.5px/1.3 var(--font-mono);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-muted);
}

/* F .nd__title */
.drawer-head .drawer-head__title {
    margin: 0;
    font-size: 19px;
    font-weight: 600;
    line-height: 1.25;
    letter-spacing: -0.01em;
    color: var(--text-primary);
    overflow-wrap: anywhere;
}

/* F .ntitle h2: the night drawer's title is the larger detail title (600 26px / 1.1; 22px ≤ 767px) */
.night-drawer .drawer-head .drawer-head__title {
    font-size: 26px;
    line-height: 1.1;
    letter-spacing: -0.015em;
}

/* F .nd__body on the night drawer: AntD's 24px body padding off, F's 16px 20px 28px on the content column (its gap and
   content rules are in the I-031 calendar block) */
.night-drawer .ant-drawer-body {
    padding: 0;
}

.night-drawer .ant-drawer-body > .night-drawer__body {
    padding: 16px 20px 28px;
}

/* F .nd__sub (aria-live="polite" on the element) */
.drawer-head__sub {
    font: 400 12.5px/1.4 var(--font-mono);
    color: var(--text-secondary);
}

.drawer-head__sub b {
    font-weight: 600;
    color: var(--text-primary);
}

/* F .iconbtn.iconbtn--line — the outlined 34px close. Doubled with .ant-drawer-close (its selector hook), whose AntD
   base rule loads after this file. */
.drawer-close,
.drawer-head .drawer-close.ant-drawer-close {
    position: static;
    flex: none;
    display: inline-grid;
    place-items: center;
    width: 34px;
    height: 34px;
    margin: 0;
    padding: 0;
    border: 1px solid var(--glass-border-light);
    border-radius: var(--radius-md);
    background: var(--glass-bg);
    color: var(--text-secondary);
    font-size: 14px;
    line-height: 1;
    cursor: pointer;
}

.drawer-close:hover,
.drawer-head .drawer-close.ant-drawer-close:hover {
    background: var(--color-panel-3);
    color: var(--text-primary);
}

.drawer-close:focus-visible,
.drawer-head .drawer-close.ant-drawer-close:focus-visible {
    outline: 2px solid var(--color-focus-ring);
    outline-offset: 2px;
}

/* F .pager — previous / next with the neighbour's label */
.drawer-pager {
    flex: none;
    display: inline-flex;
    border: 1px solid var(--glass-border-light);
    border-radius: var(--radius-md);
    overflow: hidden;
    background: var(--glass-bg);
}

.drawer-pager button {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    height: 32px;
    padding: 0 10px;
    border: 0;
    background: none;
    color: var(--text-primary);
    font: 500 12px var(--font-mono);
    white-space: nowrap;
    cursor: pointer;
}

.drawer-pager button + button {
    border-left: 1px solid var(--glass-border-light);
}

.drawer-pager button:hover:not([disabled]) {
    background: var(--color-panel-3);
}

.drawer-pager button[disabled] {
    color: var(--text-muted);
    opacity: 0.55;
    cursor: not-allowed;
}

.drawer-pager button:focus-visible {
    outline: 2px solid var(--color-focus-ring);
    outline-offset: -2px;
}

/* F .nd__body */
.drawer-body {
    display: flex;
    flex-direction: column;
    gap: 16px;
    padding: 16px 20px 28px;
}

/* F .hsec */
.drawer-section {
    display: flex;
    flex-direction: column;
    gap: 10px;
    min-width: 0;
}

.drawer-section__title {
    margin: 0;
    font-size: 14px;
    font-weight: 600;
    line-height: 1.3;
    color: var(--text-primary);
}

/* F .hcard — a checkbox card (role="checkbox" + aria-checked on the element) */
.drawer-card {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    min-width: 0;
    min-height: 56px;
    padding: 8px 12px 8px 8px;
    border: 1px solid var(--glass-border-light);
    border-radius: 10px;
    background: var(--glass-bg);
    color: var(--text-primary);
    font: inherit;
    text-align: left;
    cursor: pointer;
}

.drawer-card:hover {
    border-color: var(--text-secondary);
}

.drawer-card:focus-visible {
    outline: 2px solid var(--color-focus-ring);
    outline-offset: 2px;
}

/* Checked = the user's own selection, "mine": the primary border, an inset ring and a 5% primary tint */
.drawer-card[aria-checked="true"] {
    border-color: var(--color-primary);
    box-shadow: inset 0 0 0 1px var(--color-primary);
    background: color-mix(in srgb, var(--color-primary) 5%, var(--glass-bg));
}

.drawer-card[aria-disabled="true"] {
    border-color: var(--glass-border);
    background: var(--glass-bg-light);
    cursor: not-allowed;
}

/* Inside a card (I-030 TASK_05, the competitor picker): name over place on the left, the reason or the check on the right */
.drawer-card__body {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.drawer-card__name {
    font-size: 13.5px;
    font-weight: 600;
    line-height: 1.3;
    color: var(--text-primary);
    overflow-wrap: anywhere;
}

.drawer-card__place {
    font-size: 12.5px;
    line-height: 1.35;
    color: var(--text-secondary);
}

.drawer-card__reason {
    flex: none;
    font: 500 11.5px/1.3 var(--font-mono);
    color: var(--text-muted);
}

.drawer-card__check {
    flex: none;
}

/* F .nd__foot — sticky at the bottom of the drawer, Cancel then the primary */
.drawer-foot {
    position: sticky;
    bottom: 0;
    z-index: 2;
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    align-items: center;
    gap: 8px;
    padding: 12px 20px;
    border-top: 1px solid var(--glass-border);
    background: var(--glass-bg-light);
}

/* EntityFormDrawer (ported from EntityFormDrawer.razor.css): the body scrolls, the foot stays. The foot is also
   .form-actions-footer (catalogue required_classes), whose page margin and ≤ 480px stacking it does not take. */
.entity-drawer .entity-drawer-body {
    flex: 1 1 auto;
    overflow-y: auto;
}

.entity-drawer .entity-drawer-footer.drawer-foot {
    flex-direction: row;
    margin-top: 0;
}

/* "Save and add another" on the left. AntD's Checkbox puts its Class on the inner .ant-checkbox, so the wrapper — the
   flex item — is the one pushed (the scoped rule on the class never moved it) */
.entity-drawer .entity-drawer-footer > .ant-checkbox-wrapper:has(.entity-drawer-footer__save-and-add) {
    margin-right: auto;
}

/* F .nd / v9's wide drawer: width min(<size>, 100%) — a drawer never outgrows the viewport. The 1100px "Add
   competitors" drawer at a tablet width (768–1100px) otherwise ran off the left edge (PR 808 fidelity, O01 834) */
.ant-drawer-right .ant-drawer-content-wrapper {
    max-width: 100%;
}

/* F ≤ 767px: every right drawer is full width with no left edge, 16px sides (replaces the night drawer's and the
   entity drawer's own phone rules) */
@media (max-width: 767.98px) {
    .ant-drawer-right .ant-drawer-content-wrapper {
        width: 100% !important;
        max-width: 100% !important;
    }

    .ant-drawer-right .ant-drawer-content {
        border-left: 0 !important;
    }

    .ant-drawer-right .ant-drawer-header,
    .ant-drawer-right .drawer-body,
    .ant-drawer-right .drawer-foot {
        padding-left: 16px;
        padding-right: 16px;
    }

    .entity-drawer .entity-drawer-footer.drawer-foot .ant-btn {
        width: auto;
    }

    .night-drawer .ant-drawer-body > .night-drawer__body {
        padding-left: 16px;
        padding-right: 16px;
    }

    .night-drawer .drawer-head .drawer-head__title {
        font-size: 22px;
    }
}

/* F ≤ 640px: the pager keeps its arrows, the neighbour labels go. The arrow is AntD's <Icon>, itself a span.anticon, so
   only the label spans hide (I-030 TASK_02: a bare `span` hid the arrows too). */
@media (max-width: 640px) {
    .drawer-pager button span:not(.anticon) {
        display: none;
    }
}

/* --- Popconfirm (F .pop.popc, D-g): DangerPopconfirm's OverlayClassName -------------------------------------------- */

/* overrides.css's generic popover rules are !important; these outrank them by specificity, never the picker's */
.danger-popconfirm .ant-popover-inner {
    max-width: min(320px, calc(100vw - 32px));
    padding: 12px 14px !important;
    border: 1px solid var(--glass-border-light) !important;
    border-radius: 10px !important;
    background: var(--glass-bg) !important;
    box-shadow: var(--shadow-popup) !important;
}

.danger-popconfirm .ant-popover-inner-content {
    padding: 0 !important;
    color: var(--text-primary) !important;
}

/* F .pop b — the warning icon beside the question */
.danger-popconfirm .ant-popover-message {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    padding: 0 0 10px;
    font-size: 13px;
}

.danger-popconfirm .ant-popover-message > .anticon,
.danger-popconfirm .danger-popconfirm__icon {
    position: static;
    flex: none;
    margin-top: 2px;
    font-size: 15px;
    color: var(--color-warning) !important;
}

.danger-popconfirm .ant-popover-message-title {
    min-width: 0;
    padding-left: 0;
}

.danger-popconfirm__content {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

/* F .pop b: the browser's bold (700) — I-030 TASK_08 fidelity, was 600 */
.danger-popconfirm__title {
    font-weight: 700;
    font-size: 13.5px;
    line-height: 1.4;
    color: var(--text-primary);
}

/* F .popc p */
.danger-popconfirm .danger-popconfirm__desc {
    margin: 0;
    font-size: 13px;
    line-height: 1.45;
    color: var(--text-secondary);
}

/* F .pop__acts — Cancel (small default) then the solid danger OK */
.danger-popconfirm .ant-popover-buttons {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
    margin: 0;
}

/* F .btn--sm: both actions are small (28px, 0 10px, 13px) — I-030 TASK_08 fidelity, was the 32px control height */
.danger-popconfirm .ant-popover-buttons .ant-btn {
    height: 28px;
    margin-left: 0;
    padding: 0 10px;
    font-size: 13px;
}

/* The OK is Primary + Danger: F .btn--danger-solid comes from overrides.css "Danger Button Overrides", once */

/* F draws no arrow */
.danger-popconfirm .ant-popover-arrow {
    display: none !important;
}

/* --- Ported scoped sheets (D-x): same class names, ::deep dropped, prefixed with the component's root class ------ */
/* The rollouts (TASK_04-07) delete each .razor.css; until then its attribute-scoped copy wins the ties. */

/* CompetitorPickerDrawer (<Drawer Class="competitor-picker">) */
.competitor-picker .competitor-picker__search {
    display: flex;
    gap: 8px;
}

.competitor-picker .competitor-picker__results {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

/* EventFormModal (<Modal WrapClassName="event-form-modal">) */
.event-form-modal .event-form {
    display: flex;
    flex-direction: column;
}

.event-form-modal .event-form__optional {
    font-weight: 400;
    color: var(--text-muted);
}

/* ApiKeyCreatedModal (<Modal Class="api-key-created-modal">) — the key is shown once, on a neutral inset */
.api-key-created-modal .key-display {
    padding: 14px 16px;
    border: 1px solid var(--glass-border-light);
    border-radius: var(--radius-md);
    background: var(--glass-bg-light);
}

/* F .lab */
.api-key-created-modal .key-label {
    margin-bottom: var(--space-sm);
    font: 500 10.5px/1.3 var(--font-mono);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.api-key-created-modal .key-value {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--space-md);
}

.api-key-created-modal .key-value code {
    flex: 1;
    overflow-x: auto;
    word-break: break-all;
    padding: var(--space-sm) var(--space-md);
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-sm);
    background: var(--color-bg-dark);
    font-family: var(--font-mono);
    font-size: 13px;
    color: var(--text-primary);
}

.api-key-created-modal .copy-btn {
    flex-shrink: 0;
}

/* ChangeEmailModal (<Modal WrapClassName="change-email-modal modal-f">) — the scoped sheet's rules plus overrides.css's former
   "Change Email Modal - Input Styling" block (folded here; !important kept where it outranked the global inputs) */
.change-email-modal .ant-input {
    border: 1px solid var(--glass-border-light) !important;
    border-radius: var(--radius-md) !important;
    background: var(--glass-bg-light) !important;
    color: var(--text-primary) !important;
}

.change-email-modal .ant-input:hover {
    border-color: var(--glass-border-strong) !important;
}

.change-email-modal .ant-input:focus,
.change-email-modal .ant-input-focused {
    border-color: var(--color-primary) !important;
    box-shadow: 0 0 0 2px var(--color-focus-ring) !important;
}

.change-email-modal .ant-input::placeholder {
    color: var(--text-disabled) !important;
}

/* The OTP input — as LoginConfirm / RegisterConfirm */
.change-email-modal #change-email-otp {
    text-align: center;
    letter-spacing: 0.5em;
    font-family: var(--font-display);
    font-weight: 600;
}

/* Code expiry notice — a neutral inset (an expiry is not "mine") */
.change-email-modal .code-expiry {
    margin-bottom: 0 !important;
    padding: 8px 16px !important;
    border: 1px solid var(--glass-border-light) !important;
    border-radius: var(--radius-sm) !important;
    background: var(--glass-bg-light) !important;
    font-size: 13px !important;
    text-align: center !important;
    color: var(--text-secondary) !important;
}

.change-email-modal .resend-link {
    margin-top: 0 !important;
    padding-top: var(--space-md) !important;
    border-top: 1px solid var(--glass-border) !important;
    text-align: center !important;
}

.change-email-modal .resend-link .ant-btn-link {
    font-size: 13px !important;
    color: var(--text-muted) !important;
}

.change-email-modal .resend-link .ant-btn-link:hover {
    color: var(--text-primary) !important;
}

/* DeleteAccountModal (<Modal WrapClassName="delete-account-modal modal-f">) */
/* The notices sit in the F body's 18px column gap — no margin of their own */
.delete-account-modal .delete-notice {
    margin-bottom: 0;
}

/* "Manage subscription instead", directly under the subscription warning */
.delete-account-modal .manage-subscription-link {
    margin: -10px 0 0 0;
    text-align: right;
}

/* The terminal success badge composes .status-result__icon; the body is a column, so its wrapper centres it */
.delete-account-modal .status-result--success {
    display: flex;
    justify-content: center;
}

/* =====================================================================================================
   Elements (I-033) — prototype F's Elements screen (f.src.html elementsPage 3793, elb() 3635, NEW.el 1736-1752; the
   gallery rules 1013-1053 and their 899px / 640px fallbacks 1223-1225, 1244; the plan locks 1057-1075). README D-a, D-c,
   D-f, D-i, D-p, D-aa. Tokens only: every colour is a theme token (I-023), so light needs no second block; opt-in classes
   only — nothing here styles an AntD class or a bare element. What it holds:
   - the showcase's F anatomy for TASK_02: .elgrid of .elb blocks (.elb--t / --r / --wide), the .elb__h head (an h3 and
     a .tag.tag--dash naming the AntD component), .elb__row / __col / __cap, the token swatch list (.swlist / .swt) and
     the type-scale rows (.tscale), the faces grid (.fgrid);
   - F elements the App had no rule for: the threat tag (.tag--threat; .tag--opp / --info / --warn are I-031's), the
     avatar size scale 26 / 30 / 32 / 38 (.hotel-avatar--s26 … --s38);
   - the plan-lock pattern's locked row (README D-i): the dashboard's "Add property" (.dboard__add.is-locked, moved here
     from the I-028 dashboard block) and the property picker's (.property-picker__add.is-locked, TASK_06) — muted, not-allowed,
     never dimmed, never orange; the keyboard row stays visible. The pill (.plan-lock, I-028), the locked button
     (.ant-btn.is-locked, I-031), the locked Segmented option (.ant-segmented-item.is-locked / .ins-hz-lock, I-029) and
     the hint (.plan-hint, Core D1) keep their rules where their blocks pin them.
   ===================================================================================================== */

/* F .elsec / .elgrid / .elb — a group panel holds a two-column grid of blocks; a wide block spans the row */
.elsec {
    scroll-margin-top: 16px;
}

.elgrid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
}

.elb {
    min-width: 0;
    padding: 16px;
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.elb--t {
    border-top: 1px solid var(--glass-border);
}

.elb--r {
    border-left: 1px solid var(--glass-border);
}

.elb--wide {
    grid-column: 1 / -1;
}

/* F .elb__h — the block title (the sub-title tier) and the dashed tag naming the AntD component, which wraps */
.elb__h {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 6px 10px;
}

.elb__h h3 {
    margin: 0;
    font-size: var(--type-sub-title);
    font-weight: 600;
    color: var(--text-primary);
}

.elb__h .tag {
    height: auto;
    min-height: 22px;
    padding: 3px 7px;
    line-height: 1.35;
    white-space: normal;
}

.elb__row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px 12px;
    min-width: 0;
}

.elb__col {
    display: flex;
    flex-direction: column;
    gap: 10px;
    min-width: 0;
}

.elb__cap {
    font: 400 11px var(--font-mono);
    color: var(--text-muted);
}

/* F .swlist / .swt — a token row: its name, then the value on the light and on the dark panel (inline grounds) */
.swlist {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(260px, 100%), 1fr));
    gap: 6px 16px;
}

.swt {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 64px 64px;
    gap: 8px;
    align-items: center;
    padding: 4px 8px;
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-md);
    font: 400 11.5px var(--font-mono);
    color: var(--text-secondary);
}

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

.swt__f {
    display: grid;
    place-items: center;
    height: 28px;
    border-radius: var(--radius-sm);
    box-shadow: inset 0 0 0 1px var(--glass-border);
}

.swt__c {
    width: 34px;
    height: 18px;
    border-radius: var(--radius-xs);
    box-shadow: 0 0 0 1px var(--glass-border-light);
}

/* F .tscale — one row per type tier: the sample, then its spec in muted mono */
.tscale {
    list-style: none;
    margin: 0;
    padding: 0;
}

.tscale li {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 4px 16px;
    align-items: baseline;
    padding: 9px 0;
    border-top: 1px solid var(--glass-border);
}

.tscale li:first-child {
    border-top: 0;
    padding-top: 0;
}

.tscale__spec {
    font: 400 11px var(--font-mono);
    color: var(--text-muted);
    white-space: nowrap;
}

/* F .fgrid — the Empty / Result faces side by side, each in a 10px --line frame */
.fgrid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(200px, 100%), 1fr));
    gap: 8px;
}

.fgrid > * {
    border: 1px solid var(--glass-border);
    border-radius: 10px;
    padding: 18px 12px;
}

/* F .tag--threat — a cheaper competitor (the red family; F's edge is the tone at 40%) */
.tag--threat {
    border-color: color-mix(in srgb, var(--rate-threat-text) 40%, transparent);
    background: var(--rate-threat-bg-1);
    color: var(--rate-threat-text);
}

/* F .av--sm / .av / .av--md / .av--lg — the avatar size scale on HotelAvatar's Class (26 / 30 / 32 / 38) */
.hotel-avatar.hotel-avatar--s26 {
    width: 26px;
    height: 26px;
    border-radius: 7px;
    font-size: 10px;
}

.hotel-avatar.hotel-avatar--s30 {
    width: 30px;
    height: 30px;
    border-radius: var(--radius-md);
    font-size: 11px;
}

.hotel-avatar.hotel-avatar--s32 {
    width: 32px;
    height: 32px;
    border-radius: var(--radius-md);
    font-size: 11px;
}

.hotel-avatar.hotel-avatar--s38 {
    width: 38px;
    height: 38px;
    border-radius: 10px;
    font-size: 12.5px;
}

/* README D-i — the locked row (F .addbtn.is-locked): muted, not-allowed, no hover ground; still focusable / reachable, never
   dimmed (no opacity) and never orange. The picker's keyboard row (.is-active) keeps its --panel-3 ground so the position
   stays visible. */
.dboard__add.is-locked,
.property-picker__add.is-locked {
    color: var(--text-muted);
    cursor: not-allowed;
}

.dboard__add.is-locked:hover,
.property-picker__add.is-locked:hover {
    background: none;
    color: var(--text-muted);
}

.property-picker__add.is-locked.is-active {
    background: var(--color-panel-3);
    color: var(--text-muted);
}

.property-picker__add.is-locked {
    flex-wrap: wrap;
    row-gap: 2px;
    padding-top: 8px;
    padding-bottom: 8px;
}

/* The limit sentence under the locked row (the picker's existing Shell.Picker.Limit.* text), aligned with the label. It
   keeps .property-picker__limit (its test id's hook), so that footer's own padding and rule are reset here (TASK_06). */
.property-picker__add-sub {
    flex-basis: 100%;
    padding: 0 0 0 24px;
    border-top: 0;
    font-size: 12.5px;
    font-weight: 400;
    line-height: 1.45;
    color: var(--text-muted);
}

/* A focusable plan lock (PlanLockLabel with a Tip) shows the brand focus ring on keyboard focus (README D-i) */
.plan-lock[tabindex]:focus-visible {
    outline: none;
    box-shadow: 0 0 0 2px var(--color-focus-ring);
}

/* F's 899px fallback is the shell's narrow break: html.is-narrow-shell (js/device-service.js) and the shell playground's
   .shell.is-narrow toggle, one selector list (shell-breakpoint.test.js) — never a restated media query */
.shell.is-narrow .elgrid,
:where(.is-narrow-shell) .elgrid {
    grid-template-columns: minmax(0, 1fr);
}

.shell.is-narrow .elb--r,
:where(.is-narrow-shell) .elb--r {
    border-left: 0;
}

.shell.is-narrow .elgrid > .elb + .elb,
:where(.is-narrow-shell) .elgrid > .elb + .elb {
    border-top: 1px solid var(--glass-border);
}

@media (max-width: 640px) {
    .swt {
        grid-template-columns: minmax(0, 1fr) 56px 56px;
    }
}

/* =====================================================================================================
   Lists and feeds (I-034) — prototype F's list and feed models (f.src.html CSS: frame / panel / face 251-322, .tb 437,
   .sold 472, .tbl 542-551, .fi__label 576, .addon__suf 601-603, tabs / feed / filters / rules 663-721, comp sets / .crow
   808-825, events table 849-861, invite rows 940-951, .cellsub 995, .pgn 1007-1011, locks 1057-1067, container queries
   1183-1275). README D-f, D-g, D-i, D-k, D-l, D-n, D-p, D-q, D-r, D-t, D-w, D-y. Tokens only — F roles as in the I-027 data-grid
   and I-028 dashboard headers: --panel = --glass-bg, --panel-2 = --glass-bg-light, --panel-3 =
   --color-panel-3, --line = --glass-border, --line-2 = --glass-border-light, --row-hover = --color-row-hover, --text =
   --text-primary, --text-2 = --text-secondary, --muted = --text-muted, --threat-1 / --threat-text = --rate-threat-bg-1 /
   --rate-threat-text, --opp-1 / --opp-text = --rate-opportunity-bg-1 / --rate-opportunity-text, --info / --info-bg =
   --color-info / --color-info-bg, --warn / --warn-bg = --color-warning / --color-warning-bg, --ok = --color-success,
   --above = --position-above-text, --heat-aN = --color-heat-aN, --r / --r-sm / --r-xs = --radius-lg / --radius-md /
   --radius-sm, --font-ui = --font-body. Every colour is a theme token (I-023), so light needs no second block.
   Opt-in and scoped: every rule sits under a page / panel class — .list-panel, .feed-panel, .rules-pane, .alerts-tabs,
   .cset, .comp-usage, .events-panel, .events-timeline, .crow--comp, .crow--key, .notification-card--compact,
   .frl-votes — so the earlier generic rules (.filter-card, .notification-card, .glass-card, .crow) never decide here and
   no other page changes. What it holds:
   - the list model (D-f): section.glass-card.list-panel (F .panel) = the in-panel filter strip
     .filter-card.list-filters (F .filters; the .filter-card / .filter-row / .filter-item hooks stay for the I-012 <= 768px
     stack, the list lint rules and the page objects), the table--f table (I-027, overrides.css — reused, not redefined)
     in its scroll host, the foot .list-panel__foot (F .feed__foot: the count line + the App's Pagination in F .pgn
     sizes, D-g);
   - the feed model (D-n, D-q): section.glass-card.feed-panel = the same strip, the F .banner, .notification-feed of
     .notification-card as F article.al (icon box, title + the --color-info unread dot (D-p), text, meta, side) — the
     AlertItem (.alert-item__*) hooks share every rule — and the foot; the compact card for the bell list (D-r);
   - the Alerts rules pane (.rules-pane: .tab-intro, .rule-row as F .rule) and the Alerts Tabs underline (.alerts-tabs —
     the 2px orange bar is the current selection);
   - the comp-set panel (D-j, D-k, D-w): .cset head, title row, sub line, .cset__acts whose small buttons are F .btn--sm
     (28px, 13px, 10px — the <= 480px touch lift still wins), the .comp-usage line, .crow.crow--comp rows (no price
     column, D-k) with the .fresh freshness;
   - Events (D-l): the .events-panel head and F's table cells (.evname / .evdate / .evnote / .c-notes / .row-acts), the
     impact tags .tag--imp-low|medium|high (the amber family — never orange) and the timeline panel .events-timeline in
     F's language (mono labels, --line rules, impact-family bars, a neutral --text "Today" rule);
   - API-key rows .crow.crow--key (D-t, F .crow--inv model); the F faces in the panels;
   - AntD Tag tones inside the panels (D-h): .ant-tag.tag--info|warn|opp|threat beats the neutral .ant-tag !important base.
   Orange only means "mine" (Constraint 6): the feature-request "my vote" (.frl-votes.is-mine) and the current tab bar.
   Unread dots, locks, impact tags and freshness are never orange.
   ===================================================================================================== */

/* F .panel — one flat panel per list: the strip, the rows and the foot run edge to edge */
.glass-card.list-panel,
.glass-card.feed-panel,
.glass-card.rules-pane,
.glass-card.cset,
.glass-card.events-panel,
.glass-card.events-timeline {
    padding: 0;
    min-width: 0;
}

/* F .filters — the in-panel strip: no card of its own (no border, shadow, animation or margin), the --panel-2 ground,
   a --line bottom rule and the panel's top radius */
.glass-card.list-panel > .filter-card.list-filters,
.glass-card.feed-panel > .filter-card.list-filters {
    margin: 0;
    padding: 10px 16px;
    border: 0;
    border-bottom: 1px solid var(--glass-border);
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
    background: var(--glass-bg-light);
    box-shadow: none;
    animation: none;
}

.list-panel > .list-filters > .filter-row,
.feed-panel > .list-filters > .filter-row {
    gap: 8px 16px;
}

/* F .tb — above 768px the label sits before its control (gap 7, the desktop query below); at <= 768px the I-012 stack
   keeps the label above a control that fills the item (the L2 filter probe) */
.list-panel > .list-filters .filter-item,
.feed-panel > .list-filters .filter-item {
    min-width: 0;
}

.list-panel > .list-filters .filter-item > :not(.filter-label),
.feed-panel > .list-filters .filter-item > :not(.filter-label) {
    flex: 1 1 auto;
    min-width: 0;
}

/* F .filters .input — a text field with an affix (the search icon) is F's --panel box with the --line-2 edge, like the
   AntD Search; the I-012 `.filter-card` rule paints it on the strip's own ground with the faint border (I-034 TASK_08
   fidelity: V11 listSearch border --line vs F --line-2). Focus keeps the earlier rule's orange ring. */
.list-panel > .list-filters .ant-input-affix-wrapper,
.feed-panel > .list-filters .ant-input-affix-wrapper {
    background: var(--glass-bg) !important;
}

.list-panel > .list-filters .ant-input-affix-wrapper:not(:focus-within),
.feed-panel > .list-filters .ant-input-affix-wrapper:not(:focus-within) {
    border-color: var(--glass-border-light) !important;
}

/* F .lab — 10.5px mono uppercase muted */
.list-panel > .list-filters .filter-label,
.feed-panel > .list-filters .filter-label {
    font: 500 10.5px/1.3 var(--font-mono);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-muted);
    white-space: nowrap;
}

/* Desktop only: the strip is one wrapping row of F-sized items. At <= 768px the I-012 column stack (.filter-row,
   .filter-row > .filter-item.filter-item) decides — a flex-basis here would become the item's height in the column. */
@media (min-width: 768.02px) {
    .list-panel > .list-filters > .filter-row,
    .feed-panel > .list-filters > .filter-row {
        align-items: center;
    }

    .list-panel > .list-filters .filter-item,
    .feed-panel > .list-filters .filter-item {
        display: flex;
        align-items: center;
        gap: 7px;
        flex: 0 1 240px;
    }

    .list-panel > .list-filters .filter-label,
    .feed-panel > .list-filters .filter-label {
        margin: 0;
    }

    .list-panel > .list-filters .filter-item.filter-item--search,
    .feed-panel > .list-filters .filter-item.filter-item--search {
        flex: 0 1 320px;
    }
}

/* The strip's controls keep the App's --control-h (34px, I-021 control density) rather than F's 30px .select: the density is
   pinned at 1440 on the list seed (MobileLayoutSweepTests ListPlayground_Desktop1440_DefaultControlHeightUnchanged, "never
   lowered"), so the block sizes no control here. */

/* The F Segmented in the strip (Alerts "Show"): the global .ant-segmented is F .seg already; it keeps its own width */
.feed-panel > .list-filters .filter-item > .ant-segmented {
    flex: 0 0 auto;
}

/* The panel's own states: the skeleton and the error alert keep F's 16px inset (the faces carry their own padding) */
.list-panel > .list-panel__state,
.feed-panel > .list-panel__state,
.rules-pane > .list-panel__state,
.list-panel > .list-panel__live > .list-panel__state,
.feed-panel > .list-panel__live > .list-panel__state {
    padding: 14px 16px;
}

/* F .tbl cells the table--f variant does not carry: the subject / title link (F .evname) and the sub line (.cellsub) */
.list-panel .evname,
.events-panel .evname {
    display: inline-flex;
    max-width: 100%;
    height: auto;
    padding: 0;
    border: 0;
    background: none;
    color: var(--text-primary);
    font: 600 13.5px var(--font-body);
    text-align: left;
    cursor: pointer;
    text-decoration: underline;
    text-decoration-color: var(--glass-border-light);
    text-underline-offset: 3px;
}

.list-panel .evname:hover,
.events-panel .evname:hover {
    text-decoration-color: currentColor;
}

/* The Support / Feature-request lists keep the AntD link Button (row hooks: button.ant-btn-link, the ellipsis cell) as the
   .evname link; the global .ant-btn-link colour is !important (brand orange) and orange only means "mine", so the subject /
   title keeps F's ink here, hover included */
.list-panel .ant-btn.ant-btn-link.evname,
.list-panel .ant-btn.ant-btn-link.evname:hover:not(:disabled),
.list-panel .ant-btn.ant-btn-link.evname:focus-visible:not(:disabled) {
    color: var(--text-primary) !important;
}

.list-panel .cellsub {
    display: block;
    margin-top: 2px;
    font: 400 11px var(--font-mono);
    color: var(--text-muted);
}

/* F .feed__foot — the count line and the pager under the rows */
.list-panel__foot,
.feed-panel__foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    flex-wrap: wrap;
    padding: 10px 16px;
    border-top: 1px solid var(--glass-border);
    border-radius: 0 0 var(--radius-lg) var(--radius-lg);
    background: var(--glass-bg-light);
    font: 400 11.5px var(--font-mono);
    color: var(--text-muted);
}

.list-panel__foot .pagination-container,
.feed-panel__foot .pagination-container {
    margin-left: auto;
    padding: 0;
    justify-content: flex-end;
}

/* F .pgn — 30px mono page buttons above 480px (the <= 480px touch block keeps them 44px) */
.list-panel__foot .ant-pagination-item,
.list-panel__foot .ant-pagination-prev,
.list-panel__foot .ant-pagination-next,
.list-panel__foot .ant-pagination-jump-prev,
.list-panel__foot .ant-pagination-jump-next {
    font: 500 12.5px var(--font-mono);
}

@media (min-width: 480.02px) {
    .list-panel__foot .ant-pagination-item,
    .list-panel__foot .ant-pagination-prev,
    .list-panel__foot .ant-pagination-next,
    .list-panel__foot .ant-pagination-jump-prev,
    .list-panel__foot .ant-pagination-jump-next {
        min-width: 30px !important;
        height: 30px !important;
        line-height: 28px !important;
    }

    .list-panel__foot .ant-pagination-prev .ant-pagination-item-link,
    .list-panel__foot .ant-pagination-next .ant-pagination-item-link {
        width: 30px !important;
        height: 30px !important;
    }
}

/* F .face in a panel (44px 20px, gap 8, a 16px title, 48ch text). EmptyState keeps its circle icon (I-001 pins it).
   The list / feed / rules panels' faces; the page state cards outside these panels take the same F .face padding from
   the state-card rule beside .empty-state--section (PR 814 #13209). */
.list-panel .empty-state,
.feed-panel .empty-state,
.rules-pane .empty-state {
    padding: 44px 20px;
    gap: 8px;
}

/* Size and weight only: the headings keep --font-display from the global heading rule */
.list-panel .empty-state__title,
.feed-panel .empty-state__title,
.rules-pane .empty-state__title {
    margin: 4px 0 0;
    font-size: 16px;
    font-weight: 600;
    color: var(--text-primary);
}

.list-panel .empty-state__description,
.feed-panel .empty-state__description,
.rules-pane .empty-state__description {
    max-width: 48ch;
}

/* F .banner — the "All alert rules are off" alert inside the feed panel */
.feed-panel__banner {
    margin: 12px 16px 0;
}

/* F ul.feed — the rows of the panel */
.feed-panel .notification-feed {
    display: block;
    margin: 0;
    padding: 0;
    list-style: none;
}

/* F article.al — icon, main, side; a --line top rule between rows, none above the first */
.feed-panel .notification-card,
.notification-card.notification-card--compact {
    display: grid;
    grid-template-columns: 32px minmax(0, 1fr) auto;
    gap: 14px;
    align-items: start;
    padding: 12px 16px;
    border: 0;
    border-top: 1px solid var(--glass-border);
    border-radius: 0;
    background: none;
    animation: none;
}

.feed-panel .notification-feed > .notification-card:first-child,
.feed-panel .notification-feed > :first-child > .notification-card {
    border-top: 0;
}

.feed-panel .notification-card:hover,
.notification-card.notification-card--compact:hover {
    border-color: var(--glass-border);
    background: var(--color-row-hover);
}

/* Unread is the dot (D-p), not a ground or a left border */
.feed-panel .notification-card.notification-card--unread,
.notification-card.notification-card--compact.notification-card--unread {
    border-left: 0;
    background: none;
}

.feed-panel .notification-card.notification-card--unread:hover,
.notification-card.notification-card--compact.notification-card--unread:hover {
    background: var(--color-row-hover);
}

/* F .qi__ic — the 32px icon box: neutral --panel-3; the alert tones from the existing threat / opportunity tokens */
.feed-panel .notification-card__icon,
.notification-card--compact .notification-card__icon {
    display: grid;
    place-items: center;
    width: 32px;
    height: 32px;
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-md);
    background: var(--color-panel-3);
    color: var(--text-secondary);
    font-size: 17px;
}

.feed-panel .notification-card__icon.alert-tone--threat,
.notification-card--compact .notification-card__icon.alert-tone--threat {
    border-color: color-mix(in srgb, var(--rate-threat-text) 30%, transparent);
    background: var(--rate-threat-bg-1);
    color: var(--rate-threat-text);
}

.feed-panel .notification-card__icon.alert-tone--opportunity,
.notification-card--compact .notification-card__icon.alert-tone--opportunity {
    border-color: color-mix(in srgb, var(--rate-opportunity-text) 30%, transparent);
    background: var(--rate-opportunity-bg-1);
    color: var(--rate-opportunity-text);
}

/* Sold out and market moves are neutral in F (D-n); the playground's notification types are neutral too */
.feed-panel .notification-card__icon.alert-tone--market,
.feed-panel .notification-card__icon.alert-tone--demand,
.feed-panel .notification-card__icon[class*='notification-card__icon--'],
.notification-card--compact .notification-card__icon.alert-tone--market,
.notification-card--compact .notification-card__icon[class*='notification-card__icon--'] {
    border-color: var(--glass-border);
    background: var(--color-panel-3);
    color: var(--text-secondary);
}

/* F .al__main — a button or a block holding title, text and meta */
.feed-panel .notification-card__main,
.feed-panel .notification-card__body,
.feed-panel .alert-item__main,
.notification-card--compact .notification-card__main {
    display: flex;
    flex-direction: column;
    gap: 3px;
    min-width: 0;
    padding: 0;
    border: 0;
    background: none;
    color: var(--text-primary);
    font: inherit;
    text-align: left;
}

.feed-panel button.notification-card__main,
.feed-panel .alert-item__main,
.notification-card--compact button.notification-card__main {
    cursor: pointer;
}

.feed-panel .notification-card__main:focus-visible,
.feed-panel .alert-item__main:focus-visible {
    outline-offset: 3px;
    border-radius: 4px;
}

/* F .al__title — 600 14px, 500 once read */
.feed-panel .notification-card__title,
.notification-card--compact .notification-card__title {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    margin: 0;
    font: 600 14px/1.35 var(--font-body);
    color: var(--text-primary);
}

/* F .al__title — an alert's title is centred and wraps, so its neutral type tag (F `.al__title .tag`) sits after the
   headline (I-034 TASK_08 fidelity: tag missing in the App) */
.feed-panel .alert-item__title {
    align-items: center;
    flex-wrap: wrap;
}

.feed-panel .notification-card:not(.notification-card--unread) .notification-card__title,
.notification-card--compact:not(.notification-card--unread) .notification-card__title {
    font-weight: 500;
}

/* F .unread — the 7px unread dot is information blue (D-p), never orange */
.feed-panel .notification-card__dot,
.feed-panel .alert-item__unread-dot,
.notification-card--compact .notification-card__dot {
    display: inline-block;
    flex: none;
    width: 7px;
    height: 7px;
    /* centred on the title's first line: a long title wraps beside the dot (the row is flex, not flex-wrap), it never strands it */
    margin-top: calc((1.35em - 7px) / 2);
    border-radius: 50%;
    background: var(--color-info);
}

/* F .al__text — 13px --text-2 */
.feed-panel .notification-card__text,
.notification-card--compact .notification-card__text {
    margin: 0;
    font-size: 13px;
    line-height: 1.45;
    color: var(--text-secondary);
}

/* F .al__meta — 11.5px mono muted */
.feed-panel .notification-card__meta,
.feed-panel .alert-item__meta,
.notification-card--compact .notification-card__meta {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
    font: 400 11.5px var(--font-mono);
    color: var(--text-muted);
}

.feed-panel .notification-card__time,
.notification-card--compact .notification-card__time {
    font: 400 11.5px var(--font-mono);
    color: var(--text-muted);
}

/* F .al__side — mono, right-aligned: the percentage, the prices, the row actions */
.feed-panel .notification-card__side,
.feed-panel .alert-item__side,
.notification-card--compact .notification-card__side {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 4px;
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
    text-align: right;
}

.feed-panel .notification-card__pct,
.feed-panel .alert-item__pct {
    font-size: 13px;
    font-weight: 600;
}

.feed-panel .notification-card__px,
.feed-panel .alert-item__prices,
.notification-card--compact .notification-card__px {
    font-size: 12.5px;
    color: var(--text-secondary);
    white-space: nowrap;
}

.feed-panel .notification-card__acts,
.notification-card--compact .notification-card__acts {
    display: flex;
    align-items: center;
    gap: 2px;
}

/* The side is mono for the figures; its actions keep the UI font (F .linkbtn / .iconbtn) */
.feed-panel .notification-card__acts .ant-btn,
.notification-card--compact .notification-card__acts .ant-btn {
    font-family: var(--font-body);
}

/* F .linkbtn — "Mark read" as a small underlined text action */
.feed-panel .alert-item__mark {
    padding: 0;
    border: 0;
    background: none;
    color: var(--text-secondary);
    font: 500 12.5px var(--font-body);
    text-decoration: underline;
    text-underline-offset: 3px;
    cursor: pointer;
}

.feed-panel .alert-item__mark:hover {
    color: var(--text-primary);
}

/* The bell list (D-r): the same card, tighter — 10px 12px rows, a 28px icon box, 13px title */
.notification-card.notification-card--compact {
    grid-template-columns: 28px minmax(0, 1fr) auto;
    gap: 10px;
    padding: 10px 12px;
}

.notification-card--compact:first-child {
    border-top: 0;
}

.notification-card--compact .notification-card__icon {
    width: 28px;
    height: 28px;
    font-size: 15px;
}

.notification-card--compact .notification-card__title {
    font-size: 13px;
}

.notification-card--compact .notification-card__text {
    font-size: 12.5px;
}

/* A notification row is a role="button": the whole row opens its target (the bell's compact row too) */
.feed-panel .notification-card[role='button'],
.notification-card.notification-card--compact[role='button'] {
    cursor: pointer;
}

/* F's open affordance (t-muted, the right / link icon at 16px) at the end of the row's actions */
.feed-panel .notification-arrow {
    display: inline-grid;
    place-items: center;
    font-size: 16px;
    color: var(--text-muted);
}

/* The foot of a feed with no count line (Notifications): Load more sits where F's does, at the right */
.feed-panel__foot > .ant-btn:only-child {
    margin-left: auto;
}

/* F .btn--sm — "Load more" in the foot: 28px, 13px, 10px side padding. Keyed on the foot, not AntD's Size="Small" (design-lint
   button-size keeps .ant-btn-sm in table cells — I-034 TASK_05, as .cset__acts); the <= 480px touch block still lifts it. */
.feed-panel__foot .ant-btn {
    height: 28px;
    padding-inline: 10px;
    font-size: 13px;
}

/* F .tabs on the Alerts page: 40px tabs, 500 14px, the selected one 600 over the 2px orange bar (the current selection) */
.alerts-tabs .ant-tabs-nav {
    margin-bottom: 16px;
}

.alerts-tabs .ant-tabs-tab {
    height: 40px;
    padding: 0 12px;
    font: 500 14px var(--font-body);
}

.alerts-tabs .ant-tabs-tab + .ant-tabs-tab {
    margin-left: 2px;
}

.alerts-tabs .ant-tabs-tab-active .ant-tabs-tab-btn {
    font-weight: 600;
}

.alerts-tabs .ant-tabs-ink-bar {
    height: 2px;
    border-radius: 2px;
    background: var(--color-primary);
}

/* F .tab-intro — the rules pane's head line */
.rules-pane .tab-intro {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
    margin: 0;
    padding: 12px 16px;
    border-bottom: 1px solid var(--glass-border);
}

.rules-pane .tab-intro p {
    margin: 0;
    font-size: 13.5px;
    color: var(--text-secondary);
}

/* F .rule — switch, then the head, the sentence and the fields */
.rules-pane .rule-row {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    gap: 14px;
    padding: 14px 16px 16px;
    border-top: 1px solid var(--glass-border);
}

.rules-pane .rule-row:first-child {
    border-top: 0;
}

.rules-pane .rule-row__toggle {
    margin-top: 6px;
}

.rules-pane .rule-row__head {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}

.rules-pane .rule-row__icon {
    display: grid;
    place-items: center;
    width: 30px;
    height: 30px;
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-md);
    background: var(--color-panel-3);
    color: var(--text-secondary);
    font-size: 15px;
}

.rules-pane .rule-row__icon.alert-tone--threat {
    border-color: color-mix(in srgb, var(--rate-threat-text) 30%, transparent);
    background: var(--rate-threat-bg-1);
    color: var(--rate-threat-text);
}

.rules-pane .rule-row__icon.alert-tone--opportunity {
    border-color: color-mix(in srgb, var(--rate-opportunity-text) 30%, transparent);
    background: var(--rate-opportunity-bg-1);
    color: var(--rate-opportunity-text);
}

.rules-pane .rule-row__name {
    font-size: 14px;
    font-weight: 600;
    color: var(--text-primary);
    cursor: pointer;
}

.rules-pane .rule-row__sentence {
    margin: 6px 0 12px;
    font-size: 13.5px;
    color: var(--text-secondary);
}

.rules-pane .rule-row--off .rule-row__name,
.rules-pane .rule-row--off .rule-row__sentence {
    color: var(--text-muted);
}

.rules-pane .rule-row__fields {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 12px 22px;
}

.rules-pane .rule-row__field {
    display: flex;
    flex-direction: column;
    gap: 5px;
}

.rules-pane .rule-row__field--end {
    margin-left: auto;
}

/* F .fi__label — 500 12px mono --text-2 */
.rules-pane .rule-row__field .filter-label {
    margin: 0;
    font: 500 12px var(--font-mono);
    letter-spacing: 0.01em;
    color: var(--text-secondary);
}

/* F .addon — the threshold input with its % suffix, 112px wide */
.rules-pane .rule-row__inline {
    display: flex;
    align-items: stretch;
    width: 112px;
}

.rules-pane .rule-row__inline > :first-child {
    flex: 1 1 auto;
    min-width: 0;
}

.rules-pane .rule-row__unit {
    display: grid;
    place-items: center;
    min-width: 34px;
    padding: 0 9px;
    border: 1px solid var(--glass-border-light);
    border-left: 0;
    border-radius: 0 var(--radius-md) var(--radius-md) 0;
    background: var(--glass-bg-light);
    color: var(--text-muted);
    font: 500 12.5px var(--font-mono);
}

/* F .panel__head — the comp-set, events and timeline panel heads */
.cset > .cset__head,
.events-panel > .events-panel__head,
.events-timeline > .events-timeline__head,
.events-timeline > .core-card-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px 16px;
    flex-wrap: wrap;
    margin: 0;
    padding: 12px 16px;
    border-bottom: 1px solid var(--glass-border);
}

/* F .panel__title / .panel__sub — size, weight and line-height only: the h2 keeps --font-display from the heading rule */
.cset .cset__title,
.events-timeline .core-card-title {
    margin: 0;
    font-size: 15px;
    font-weight: 600;
    line-height: 1.3;
    color: var(--text-primary);
}

.events-timeline .core-card-sub {
    margin: 2px 0 0;
    font-size: 12.5px;
    color: var(--text-muted);
}

/* F .cset__titlerow / .cset__sub / .cset__acts */
.cset .cset__titlerow {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

.cset .cset__sub {
    margin: 3px 0 0;
    font: 400 12px var(--font-mono);
    color: var(--text-muted);
}

/* F .cset__sub a — the calendar link in the UI face and --text, never the orange link colour (orange only means
   "mine", Constraint 6 — I-034 TASK_08 fidelity: csetLink colour #ed7200 vs F --text) */
.cset .cset__sub a {
    font-family: var(--font-body);
    color: var(--text-primary);
}

/* "n / max competitors" at the limit reads threat (F .t-threat) — information, not "mine" */
.cset .cset__count--full {
    color: var(--rate-threat-text);
}

.cset .cset__acts {
    display: flex;
    align-items: center;
    gap: 4px;
    flex-wrap: wrap;
}

/* README D-w — F .btn--sm in the comp-set head and on a row's Remove: 28px, 13px, 10px side padding. Keyed on the
   container, not AntD's Size="Small" (design-lint button-size keeps .ant-btn-sm in table cells — I-034 TASK_03); the
   global small button stays 32px, and the <= 480px touch block lifts these with min-height, which still wins. */
.cset .cset__acts .ant-btn,
.crow--comp .row-acts .ant-btn {
    height: 28px;
    padding-inline: 10px;
    font-size: 13px;
}

.cset .cset__acts .ant-btn.ant-btn-icon-only {
    width: 28px;
    padding-inline: 0;
}

/* The API-key row's Revoke is the same F .btn--sm (I-034 TASK_07) */
.crow--key .row-acts .ant-btn {
    height: 28px;
    padding-inline: 10px;
    font-size: 13px;
}

/* The event row's Edit / Delete are the same F .btn--sm (I-034 TASK_08 fidelity: evRowActs 32 vs F 28px) */
.events-panel .row-acts .ant-btn {
    height: 28px;
    padding-inline: 10px;
    font-size: 13px;
}

/* F .usage — "2 of 5 comp sets · up to 15 competitors per set on Pro" */
.comp-usage {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 10px;
    margin: 0;
    font: 400 12.5px var(--font-mono);
    color: var(--text-secondary);
}

.comp-usage b {
    color: var(--text-primary);
}

/* The comp-set panels sit in the page's aria-live region under the usage line, out of reach of the F frame's column gap:
   the same 16px between them (F .page gap) — the deleted page sheet's .comp-set margin (I-034 TASK_03) */
.comp-usage ~ .glass-card.cset {
    margin-top: 16px;
}

/* F .crow in a comp set: avatar, name + place, freshness, Remove (F's 150px price column dropped — D-k) */
.crow.crow--comp {
    grid-template-columns: 32px minmax(0, 1fr) 180px auto;
}

.crow--comp .crow__n {
    font-size: 13.5px;
    font-weight: 600;
}

.crow--comp .crow__p {
    font: 400 11px var(--font-mono);
    color: var(--text-muted);
}

/* F .fresh — "Checked 5 h ago" with a success dot; waiting for the first prices with a warning dot */
.crow--comp .fresh {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    font: 400 12px var(--font-mono);
    color: var(--text-secondary);
    white-space: nowrap;
}

.crow--comp .fresh__dot {
    flex: none;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--color-success);
}

.crow--comp .fresh--wait .fresh__dot {
    background: var(--color-warning);
}

.crow--comp .row-acts,
.crow--key .row-acts,
.events-panel .row-acts {
    display: inline-flex;
    justify-content: flex-end;
    gap: 2px;
}

/* F .tbl cells of the events table: the dates with their "N nights · when" line, the notes, the row actions */
.events-panel .evdate {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.events-panel .evdate small {
    font-size: 11px;
    color: var(--text-muted);
}

/* F .top — every events cell sits at the top of its row (the dates and the name carry a second line) */
.events-panel .ant-table-tbody > tr.ant-table-row > td {
    vertical-align: top;
}

/* F td.wrap — the notes in the UI face and --text-2; !important beats the global cell ink (overrides.css
   `.ant-table-tbody > tr > td`, I-034 TASK_08 fidelity: evNotes colour --text vs F --text-2) */
.events-panel .ant-table-tbody > tr.ant-table-row > td.c-notes {
    min-width: 220px;
    max-width: 420px;
    white-space: normal;
    font: 400 13px/1.45 var(--font-body);
    color: var(--text-secondary) !important;
}

.events-panel .evnote {
    display: none;
    max-width: 260px;
    margin-top: 4px;
    white-space: normal;
    font: 400 12.5px/1.4 var(--font-body);
    color: var(--text-secondary);
}

/* F .tag--imp-* — the amber family (the --above text role over the heat grounds); never orange. On an AntD Tag the
   tone must beat the neutral .ant-tag !important base. */
.events-panel .tag--imp-low,
.events-timeline .tag--imp-low {
    border-color: color-mix(in srgb, var(--position-above-text) 35%, transparent) !important;
    background: var(--color-heat-a1) !important;
    color: var(--position-above-text) !important;
}

.events-panel .tag--imp-medium,
.events-timeline .tag--imp-medium {
    border-color: color-mix(in srgb, var(--position-above-text) 50%, transparent) !important;
    background: var(--color-heat-a2) !important;
    color: var(--position-above-text) !important;
}

.events-panel .tag--imp-high,
.events-timeline .tag--imp-high {
    border-color: color-mix(in srgb, var(--position-above-text) 70%, transparent) !important;
    background: var(--color-heat-a3) !important;
    color: var(--text-primary) !important;
}

/* The "Next 90 days" timeline panel (D-l, an accepted difference) in F's language */
.events-timeline .events-timeline__legend {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font: 400 11.5px var(--font-mono);
    color: var(--text-muted);
}

.events-timeline > .events-timeline__track {
    position: relative;
    margin: 0 16px;
    padding-top: 26px;
    overflow: hidden;
}

.events-timeline .events-timeline__months {
    position: absolute;
    inset: 0 0 auto 0;
    height: 100%;
    pointer-events: none;
}

.events-timeline .events-timeline__month {
    position: absolute;
    top: 6px;
    bottom: 0;
    padding-left: 6px;
    border-left: 1px solid var(--glass-border);
    font: 500 10.5px var(--font-mono);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.events-timeline .events-timeline__lanes {
    position: relative;
    height: calc(var(--lanes, 1) * 34px + 6px);
    min-height: 40px;
}

/* "Today" is a neutral --text rule, never orange (D-l) */
.events-timeline .events-timeline__today {
    position: absolute;
    left: 0;
    top: -20px;
    bottom: -4px;
    width: 2px;
    border-radius: var(--radius-xxs);
    background: var(--text-primary);
}

.events-timeline .events-timeline__axis {
    display: flex;
    justify-content: space-between;
    margin-top: 6px;
    padding: 8px 0 12px;
    border-top: 1px solid var(--glass-border);
    font: 400 11px var(--font-mono);
    color: var(--text-muted);
}

.events-timeline .events-timeline__axis-today {
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-primary);
}

.events-timeline .events-timeline__bar {
    position: absolute;
    display: flex;
    align-items: center;
    gap: 8px;
    height: 28px;
    margin-top: 3px;
    color: var(--text-primary);
    font: 600 12px var(--font-body);
    text-decoration: none;
    white-space: nowrap;
}

/* Bars in the impact family: low / medium / high read the heat grounds and the --above edge of the impact tags */
.events-timeline .events-timeline__bar-fill {
    flex: 0 0 100%;
    min-width: 8px;
    height: 100%;
    border: 1px solid color-mix(in srgb, var(--position-above-text) 35%, transparent);
    border-radius: var(--radius-sm);
    background: var(--color-heat-a1);
}

.events-timeline .events-timeline__bar--medium .events-timeline__bar-fill {
    border-color: color-mix(in srgb, var(--position-above-text) 50%, transparent);
    background: var(--color-heat-a2);
}

.events-timeline .events-timeline__bar--high .events-timeline__bar-fill {
    border-color: color-mix(in srgb, var(--position-above-text) 70%, transparent);
    background: var(--color-heat-a3);
}

.events-timeline .events-timeline__bar:hover .events-timeline__bar-fill,
.events-timeline .events-timeline__bar:focus-visible .events-timeline__bar-fill {
    border-color: var(--text-secondary);
}

.events-timeline .events-timeline__bar-label {
    flex: 0 0 auto;
    max-width: 220px;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* F .crow--inv as the API-key row: name + prefix, status tag, created, last used, Revoke */
.crow.crow--key {
    grid-template-columns: minmax(0, 1fr) auto auto auto auto;
}

.crow--key .crow__n {
    font-size: 13.5px;
    font-weight: 600;
}

.crow--key .crow__key {
    font: 400 12px var(--font-mono);
    color: var(--text-secondary);
}

.crow--key .crow__date {
    font: 400 11.5px var(--font-mono);
    color: var(--text-muted);
    white-space: nowrap;
}

/* AntD Tag tones inside the panels (D-h) and the I-035 detail rail (.kv, D-j): the global .tag--* tones on an AntD Tag must
   beat its neutral !important base (SupportTagTones; Urgent is the threat family, never orange) */
.list-panel .ant-tag.tag--info,
.feed-panel .ant-tag.tag--info,
.crow--key .ant-tag.tag--info,
.kv .ant-tag.tag--info {
    border-color: var(--position-below-border) !important;
    background: var(--color-info-bg) !important;
    color: var(--color-info) !important;
}

.list-panel .ant-tag.tag--warn,
.feed-panel .ant-tag.tag--warn,
.crow--key .ant-tag.tag--warn,
.kv .ant-tag.tag--warn {
    border-color: var(--position-above-border) !important;
    background: var(--color-warning-bg) !important;
    color: var(--color-warning) !important;
}

.list-panel .ant-tag.tag--opp,
.feed-panel .ant-tag.tag--opp,
.crow--key .ant-tag.tag--opp,
.kv .ant-tag.tag--opp {
    border-color: var(--rate-opportunity-bg-3) !important;
    background: var(--rate-opportunity-bg-1) !important;
    color: var(--rate-opportunity-text) !important;
}

.list-panel .ant-tag.tag--threat,
.feed-panel .ant-tag.tag--threat,
.crow--key .ant-tag.tag--threat,
.kv .ant-tag.tag--threat {
    border-color: color-mix(in srgb, var(--rate-threat-text) 40%, transparent) !important;
    background: var(--rate-threat-bg-1) !important;
    color: var(--rate-threat-text) !important;
}

/* F .t-mine — the feature request I voted for is "mine" (Constraint 6); every other vote count is muted */
.frl-votes {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    color: var(--text-muted);
}

.frl-votes.is-mine {
    color: var(--color-primary-text);
    font-weight: 400; /* F .t-mine inherits the cell's 400 (I-037 D-ac); orange alone marks "mine" */
}

/* F's container rules on the page container (.page-wrapper--f is the `page` container, as in the I-028 block) */
@container page (max-width: 980px) {
    .events-panel .ant-table-thead > tr > th.c-notes,
    .events-panel .ant-table-tbody > tr.ant-table-row > td.c-notes {
        display: none;
    }

    /* The fixed-layout table keeps a hidden column's <col> (the 4th, Notes) in its width: drop it, or a dead 220px strip
       makes the table scroll where F's fits */
    .events-panel .ant-table colgroup > col:nth-child(4) {
        display: none;
    }

    .events-panel .evnote {
        display: block;
    }
}

/* A phone: the "Next 90 days" track scrolls inside its panel — the late bars' name labels run past the 90-day edge and would
   otherwise be clipped (README D-ab). Wider containers keep the clip: no scrollbar for a label's last few pixels. */
@container page (max-width: 600px) {
    .events-timeline > .events-timeline__track {
        overflow-x: auto;
        overflow-y: hidden;
    }

    /* The 90 days keep a 720px track, so the bars and their names spread out and the track scrolls; squeezed into a
       phone's width the names ran into each other (I-034 TASK_08 390 check). The month rules span it too. */
    .events-timeline .events-timeline__months,
    .events-timeline .events-timeline__lanes,
    .events-timeline .events-timeline__axis {
        width: 720px;
    }
}

@container page (max-width: 820px) {
    .crow.crow--comp {
        grid-template-columns: 32px minmax(0, 1fr) auto;
        row-gap: 2px;
    }

    /* F hides the freshness here (its price column stays); the App's row has no price (D-k), so the freshness wraps
       under the name instead and stays readable on a phone, as the page showed it before (I-034 TASK_03) */
    .crow--comp > .hotel-avatar {
        grid-row: 1 / span 2;
    }

    .crow--comp .fresh {
        grid-column: 2;
        grid-row: 2;
    }

    .crow--comp > .row-acts {
        grid-column: 3;
        grid-row: 1 / span 2;
    }

    /* F hides the price column here; the App's key row has no price, so its two dates stack under the name instead
       (I-034 TASK_07) and Revoke keeps the top-right cell */
    .crow.crow--key {
        grid-template-columns: minmax(0, 1fr) auto auto;
        row-gap: 2px;
    }

    .crow--key > .crow__date {
        grid-column: 1;
    }

    .crow--key > .row-acts {
        grid-column: 3;
        grid-row: 1;
    }
}

@container page (max-width: 600px) {
    .glass-card.list-panel > .filter-card.list-filters,
    .glass-card.feed-panel > .filter-card.list-filters {
        padding: 10px 12px;
    }

    .feed-panel .notification-card,
    .notification-card.notification-card--compact {
        grid-template-columns: 30px minmax(0, 1fr);
        gap: 12px;
        padding: 12px;
    }

    .feed-panel .notification-card__side,
    .feed-panel .alert-item__side {
        grid-column: 2;
        flex-direction: row;
        flex-wrap: wrap;
        align-items: center;
        justify-content: flex-start;
        gap: 6px 12px;
        text-align: left;
    }

    /* F .tab-intro { padding: 12px } under a 600px page (I-038 TASK_03, V35 at 390: 16px → 12px) */
    .rules-pane .tab-intro {
        padding: 12px;
    }

    .rules-pane .rule-row {
        gap: 12px;
        padding: 14px 12px;
    }

    .crow.crow--comp {
        gap: 10px;
        padding: 9px 8px 9px 12px;
    }

    .crow.crow--key {
        gap: 2px 10px;
    }
}

/* =====================================================================================================
   Details and forms (I-035) — prototype F's detail and form models (f.src.html CSS: .lab 84, .av 195-198, .ph / .panel /
   .panel__head / .panel__title 253-263, .btn--text 271-272, .seg 285-292, .sec__body 573, .fi / .fi__label / .req 574-578,
   .row2 581, details.clp 627-633, .linkbtn 653-654, .cnt-hint 660, .pad 943, .dgrid (App .detail-grid) / .kv / .thread / .msg / .drop /
   .formcol / .wact--end / .backlink 969-993, .clp__head / .clp__body / .or 1002-1005, container queries 1161, 1182-1200;
   screens tkDetail 3524, tkNew 3543, frDetail 3586, frNew 3608). README D-f, D-g, D-h, D-i, D-j, D-k, D-l, D-m, D-o, D-y.
   Tokens only — F roles as in the I-027 data-grid and I-028 dashboard headers: --panel = --glass-bg, --panel-2 =
   --glass-bg-light, --panel-3 = --color-panel-3, --line = --glass-border, --line-2 = --glass-border-light, --text =
   --text-primary, --text-2 = --text-secondary, --muted = --text-muted, --info / --info-bg = --color-info /
   --color-info-bg, --ok = --color-success, --err = --color-error, --threat-1 / --threat-text = --rate-threat-bg-1 /
   --rate-threat-text, --primary (focus) = --color-focus-ring, --r / --r-sm / --r-xs = --radius-lg / --radius-md /
   --radius-sm, --font-ui = --font-body. Every colour is a theme token (I-023), so light needs no second block.
   Opt-in and scoped: every rule sits under the block's own classes — .ph, .backlink, .detail-grid, .thread, .msg, .file-chip,
   .reply-panel, .linkbtn, .kv, .formcol, .row2, .drop, .clp, .wact — compounded with the App hooks it restyles
   (.page-header.ph, .detail-page-grid.detail-grid, .form-actions-footer.wact.wact--end, .upload-area.drop,
   .upload-dropzone.drop), so the earlier generic rules (.detail-page-grid*, .form-actions-footer, .upload-dropzone)
   keep deciding for EntityFormDrawer, AuditLogPlayground and every other user (Constraint 3). What it holds:
   - the detail head (D-g): .page-header.ph with the eyebrow .lab (F .lab), the title row and the actions (gap 8);
   - the back link (D-f): a.backlink (detail) as F .btn--text; button.backlink (the forms' AntD Text button) is that
     already — both sit at the start of the F frame's column;
   - the detail grid (D-g): .detail-page-grid.detail-grid = F .dgrid (minmax(0, 1fr) 280px, gap 16, one column at a page
     container <= 900px, the rail not sticky); renamed from F's .dgrid because that names the I-027 data-grid table
     (F .rg) in the App (PR 797 #12827); panels flush (.panel__head + h2.panel__title, .pad bodies);
   - the thread (D-h): ol.thread > li.msg (grid 32px / 1fr), .msg--team on --panel-2 with the info avatar .av--info —
     never orange; .msg__head / __who / __time / __body / __edited; file chips (D-i) .file-chip in a .file-chips row;
   - the reply panel (D-k): .reply-panel's form as F .pad, the AntD count as F .cnt-hint, "Add attachments" as F
     .linkbtn over the InputFile overlay, the per-file list (.file-upload-list / .file-upload-item, classes unchanged)
     as F rows with status tones (uploading info, completed success, failed threat);
   - the rail (D-j): dl.kv (dt = F .lab, dd, .kv__big, .mono) and the SupportTagTones tones on its AntD Tags;
   - the form column (D-l): form.formcol (780px), its panel body (F .sec__body padding), the AntD labels as F .fi__label
     with the required * in --color-error, the .row2 two-up row (the global I-032 .row2, two up until a 600px page
     container) and the Priority RadioGroup button style as F .seg (the global Segmented's measurements, I-033);
   - the drop zone (D-m): .upload-area.drop / .upload-dropzone.drop as F .drop (the native file-input overlay rules and
     .upload-dropzone--dragging stay); the Reference Collapse .clp.ant-collapse as F details.clp and its .or divider;
   - the actions row (D-o): .form-actions-footer.wact.wact--end as F .wact--end (no card, no rule, right-aligned, gap 8;
     the <= 480px sticky column of the base rule still applies; the 36px buttons come from the I-032 .wact rule).
   Orange only means "mine" (Constraint 6): the primary buttons (AntD, unchanged), my vote (.vote-button.voted and its
   badge) and the focus ring (--color-focus-ring). Team rows, file chips, status icons and the drop zone are never orange.
   ===================================================================================================== */

/* F .ph — the head: title column and actions on one wrapping row, aligned to the bottom, gap 16 */
.page-header.ph {
    align-items: flex-end;
    gap: 16px;
}

/* The <= 768px head is a column (the base .page-header--with-actions rule): F's bottom alignment would push the title
   column to the right edge there, so the column stretches and the eyebrow + title start at the frame's edge (I-035
   TASK_07, 390 check) */
@media (max-width: 768px) {
    .page-header--with-actions.ph {
        align-items: stretch;
    }
}

/* F .ph__titlerow — the eyebrow row (number + an optional tag), gap 12 */
.ph .ph__titlerow {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
}

/* F .lab — the eyebrow: 500 10.5px mono uppercase, muted (I-021 AD6: a label is never orange) */
.ph .lab {
    font: 500 10.5px/1.3 var(--font-mono);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-muted);
}

/* F .ph__title — 4px above and below the title */
.page-header.ph .page-title {
    margin: 4px 0;
}

/* F .ph__actions — gap 8 */
.page-header.ph .page-header__actions {
    gap: 8px;
}

/* F .vote — the vote button's count badge: F's neutral .badge at rest (--badge-bg / --badge-fg, I-024 D-p — I-035
   TASK_07 fidelity, P30 voteBadge); on my vote (the primary, "mine") F .vote[aria-pressed] .badge — the on-primary
   ground with the brand ink */
.ph .vote-button {
    gap: 8px;
}

.ph .vote-button .frd-vote-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 20px;
    height: 18px;
    padding: 0 5px;
    border-radius: 9px;
    background: var(--color-badge-bg);
    color: var(--color-badge-fg);
    font: 600 10.5px/1 var(--font-mono);
    font-variant-numeric: tabular-nums;
}

.ph .vote-button.voted .frd-vote-badge {
    background: var(--text-on-primary);
    color: var(--color-primary-text);
}

/* F .btn--text.backlink — the one-line back link above the head (D-f): F's text button, aligned to the start of the
   frame's column. button.backlink is the AntD Text button (already F .btn--text); a.backlink draws the same look. */
.backlink {
    align-self: flex-start;
}

a.backlink {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    height: 32px;
    padding: 0 12px;
    border-radius: var(--radius-md);
    background: none;
    color: var(--text-secondary);
    font: 500 13.5px var(--font-body);
    text-decoration: none;
    white-space: nowrap;
}

a.backlink:hover,
a.backlink:active {
    background: var(--color-panel-3);
    color: var(--text-primary);
}

a.backlink:focus-visible {
    outline: 2px solid var(--color-focus-ring);
    outline-offset: 1px;
}

/* A standalone control: the 44px touch target at <= 480px, as the global rule gives the AntD button.backlink */
@media (max-width: 480px) {
    a.backlink {
        min-height: 44px;
    }
}

/* F .dgrid — main 1fr + the 280px rail, gap 16. The App class is .detail-grid, not .dgrid: .dgrid names the I-027
   data-grid table (F .rg), whose table / th / td / row rules must never reach a detail page (PR 797 #12827). */
.detail-page-grid.detail-grid {
    grid-template-columns: minmax(0, 1fr) 280px;
    gap: 16px;
}

.detail-page-grid.detail-grid.detail-page-grid--single {
    grid-template-columns: minmax(0, 1fr);
}

/* F .dgrid__col (App .detail-grid) — each column a flex column, gap 16; the rail is not sticky in F */
.detail-page-grid.detail-grid > .detail-page-grid__main,
.detail-page-grid.detail-grid > .detail-page-grid__side {
    min-width: 0;
    gap: 16px;
}

.detail-page-grid.detail-grid > .detail-page-grid__side {
    position: static;
}

/* F .panel — flush: the head, the rows, the rail lists and .pad bodies carry their own padding */
.detail-page-grid.detail-grid .glass-card {
    padding: 0;
    min-width: 0;
}

/* F .panel__head / .panel__title (262-263) */
.detail-grid .panel__head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 10px 16px;
    padding: 12px 16px;
    border-bottom: 1px solid var(--glass-border);
}

.detail-grid .panel__title {
    margin: 0;
    font-size: 15px;
    font-weight: 600;
    line-height: 1.3;
    color: var(--text-primary);
}

/* F .pad — a panel body: 14px 16px 16px, a flex column, gap 14 */
.detail-grid .pad {
    display: flex;
    flex-direction: column;
    gap: 14px;
    padding: 14px 16px 16px;
    min-width: 0;
}

.detail-grid .pad + .pad {
    border-top: 1px solid var(--glass-border);
}

/* F .thread / .msg (980-988) */
.thread {
    margin: 0;
    padding: 0;
    list-style: none;
}

.thread > .msg {
    display: grid;
    grid-template-columns: 32px minmax(0, 1fr);
    gap: 12px;
    padding: 14px 16px;
    border-top: 1px solid var(--glass-border);
}

.thread > .msg:first-child {
    border-top: 0;
}

/* F .msg--team — a support / admin row on the --panel-2 ground (info, never orange — D-h) */
.thread > .msg.msg--team {
    background: var(--glass-bg-light);
}

.thread > .msg.msg--team:last-child {
    border-radius: 0 0 var(--radius-lg) var(--radius-lg);
}

/* F .av--md — the global AntD avatar is F .av at 32px already (overrides.css I-033); the team avatar is F .av--info */
.msg .ant-avatar {
    width: 32px;
    height: 32px;
    line-height: 30px;
    font-size: 16px;
}

.msg .ant-avatar.av--info {
    background: var(--color-info-bg);
    border-color: color-mix(in srgb, var(--color-info) 30%, transparent);
    color: var(--color-info);
}

.msg .msg__main {
    min-width: 0;
}

.msg .msg__head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: 4px 10px;
}

.msg .msg__who {
    font-size: 13.5px;
    font-weight: 600;
    color: var(--text-primary);
}

.msg .msg__time {
    font: 400 11.5px var(--font-mono);
    color: var(--text-muted);
}

.msg .msg__edited {
    font-size: 11.5px;
    color: var(--text-muted);
}

.msg .msg__body {
    margin: 4px 0 0;
    font-size: 13.5px;
    color: var(--text-secondary);
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

.msg .msg__acts {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    margin-top: 6px;
}

/* F attachment chip (D-i) — paper-clip, name, mono size; the hover edge is the text role, never orange */
.file-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 8px;
}

.file-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    max-width: 100%;
    min-width: 0;
    padding: 4px 8px;
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-sm);
    background: var(--glass-bg);
    color: var(--text-secondary);
    font-size: 12.5px;
    line-height: 1.3;
    text-decoration: none;
}

.file-chip:hover,
.file-chip:active {
    border-color: var(--text-secondary);
    color: var(--text-primary);
}

.file-chip:focus-visible {
    outline: 2px solid var(--color-focus-ring);
    outline-offset: 1px;
}

.file-chip .anticon {
    flex: none;
    color: var(--text-muted);
}

.file-chip .file-chip__name {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.file-chip small {
    flex: none;
    font: 400 11.5px var(--font-mono);
    color: var(--text-muted);
}

/* F #reply-section form.pad — the reply / comment body: 14px 16px 16px, gap 12; AntD items spaced by the gap. The pages'
   AntD Form wears the global .pad itself (AntD wraps the <form>, so no child selector here reaches it). */
.reply-panel > .reply-panel__body {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 14px 16px 16px;
}

.reply-panel .ant-form-item {
    margin-bottom: 0;
}

/* F .cnt-hint — the TextArea count: 400 11px mono muted */
.reply-panel .ant-input-textarea-show-count::after,
.reply-panel .ant-input-data-count,
.formcol .ant-input-textarea-show-count::after,
.formcol .ant-input-data-count {
    font: 400 11px var(--font-mono);
    font-variant-numeric: tabular-nums;
    color: var(--text-muted);
}

/* F .linkbtn — "+ Add attachments": an underlined text action; the InputFile overlay (global .file-input) covers it */
.reply-panel .linkbtn,
.formcol .linkbtn {
    position: relative;
    display: inline-flex;
    align-self: flex-start;
    align-items: center;
    gap: 4px;
    padding: 2px 0;
    color: var(--text-secondary);
    font: 500 12.5px var(--font-body);
    text-decoration: underline;
    text-decoration-color: var(--glass-border-light);
    text-underline-offset: 3px;
    white-space: nowrap;
    cursor: pointer;
}

.reply-panel .linkbtn label,
.formcol .linkbtn label {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    color: inherit;
    cursor: pointer;
}

.reply-panel .linkbtn:hover,
.formcol .linkbtn:hover {
    color: var(--text-primary);
    text-decoration-color: currentColor;
}

.reply-panel .linkbtn:focus-within,
.formcol .linkbtn:focus-within {
    outline: 2px solid var(--color-focus-ring);
    outline-offset: 2px;
    border-radius: var(--radius-sm);
}

/* The per-file list as F rows: name, mono size, status icon tones — the classes the pages render stay */
.reply-panel .file-upload-list,
.formcol .file-upload-list {
    display: flex;
    flex-direction: column;
    margin: 8px 0 0;
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-md);
    background: var(--glass-bg);
    overflow: hidden;
}

.reply-panel .file-upload-item,
.formcol .file-upload-item {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 8px;
    min-height: 36px;
    padding: 4px 4px 4px 12px;
    border: 0;
    border-radius: 0;
    background: none;
    font-size: 13px;
    color: var(--text-secondary);
}

.reply-panel .file-upload-item + .file-upload-item,
.formcol .file-upload-item + .file-upload-item {
    border-top: 1px solid var(--glass-border);
}

.reply-panel .file-upload-item > .anticon:first-child,
.formcol .file-upload-item > .anticon:first-child {
    flex: none;
    color: var(--text-muted);
}

.reply-panel .file-upload-item.uploading > .anticon:first-child,
.formcol .file-upload-item.uploading > .anticon:first-child {
    color: var(--color-info);
}

.reply-panel .file-upload-item.completed > .anticon:first-child,
.formcol .file-upload-item.completed > .anticon:first-child {
    color: var(--color-success);
}

.reply-panel .file-upload-item.failed,
.formcol .file-upload-item.failed {
    background: var(--rate-threat-bg-1);
}

.reply-panel .file-upload-item.failed > .anticon:first-child,
.formcol .file-upload-item.failed > .anticon:first-child {
    color: var(--rate-threat-text);
}

.reply-panel .file-upload-item .file-name,
.formcol .file-upload-item .file-name {
    flex: 1 1 160px;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--text-primary);
    font-size: 13px;
}

.reply-panel .file-upload-item .file-size,
.formcol .file-upload-item .file-size {
    font: 400 11.5px var(--font-mono);
    color: var(--text-muted);
}

.reply-panel .file-upload-item .file-error,
.formcol .file-upload-item .file-error {
    font-size: 12px;
    color: var(--rate-threat-text);
}

/* F .kv (969-973) — the rail's key / value list; dt is F .lab */
.kv {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin: 0;
    padding: 14px 16px 16px;
}

.kv > dt {
    font: 500 10.5px/1.3 var(--font-mono);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.kv > dd {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    margin: 0 0 8px;
    color: var(--text-primary);
    overflow-wrap: anywhere;
}

.kv > dd:last-child {
    margin-bottom: 0;
}

.kv .kv__big {
    font: 600 21px var(--font-mono);
    font-variant-numeric: tabular-nums;
}

.kv .mono {
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
}

/* F .formcol — the form column: 780px, a flex column, gap 16 */
.formcol {
    display: flex;
    flex-direction: column;
    gap: 16px;
    width: 100%;
    max-width: 780px;
}

/* F .sec__body (573) — the panel body's padding; fields keep their own spacing (.form-field, AntD items) */
.formcol > .glass-card {
    padding: 18px 20px 20px;
}

/* F .fi__label — 500 12px mono, --text-2; the required * in the error colour (F .req) */
.formcol .ant-form-item-label > label,
.formcol .form-field__label {
    font-family: var(--font-mono);
    font-size: 12px;
    font-weight: 500;
    letter-spacing: 0.01em;
    color: var(--text-secondary);
}

.formcol .ant-form-item-required::before,
.formcol .req {
    color: var(--color-error) !important;
}

.formcol .req {
    margin-left: 2px;
}

/* F .row2 — the global I-032 .row2 (two up, gap 20); in a form it stays two up until a 600px page container */
.formcol .row2 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
}

/* F .seg — the Priority RadioGroup in button style, the global Segmented's measurements (I-033): a --panel-2 track,
   26px mono items, the picked one on the panel ground with a --line-2 ring — never orange. Only a button-style group:
   a plain RadioGroup in a .row2 keeps its radios */
.formcol .row2 .ant-radio-group:has(> .ant-radio-button-wrapper) {
    display: inline-flex;
    flex-wrap: wrap;
    align-self: flex-start;
    gap: 2px;
    padding: 2px;
    border: 1px solid var(--glass-border-light);
    border-radius: var(--radius-md);
    background: var(--glass-bg-light);
}

.formcol .row2 .ant-radio-group .ant-radio-button-wrapper {
    display: inline-flex;
    align-items: center;
    height: 26px;
    padding: 0 10px;
    border: 0 !important;
    border-radius: var(--radius-sm) !important;
    background: none !important;
    box-shadow: none !important;
    color: var(--text-secondary) !important;
    font: 500 12.5px var(--font-mono);
}

.formcol .row2 .ant-radio-group .ant-radio-button-wrapper::before {
    display: none;
}

.formcol .row2 .ant-radio-group .ant-radio-button-wrapper:hover {
    color: var(--text-primary) !important;
}

.formcol .row2 .ant-radio-group .ant-radio-button-wrapper.ant-radio-button-wrapper-checked {
    background: var(--glass-bg) !important;
    box-shadow: 0 0 0 1px var(--glass-border-light) !important;
    color: var(--text-primary) !important;
    font-weight: 600;
}

.formcol .row2 .ant-radio-group .ant-radio-button-wrapper:has(:focus-visible) {
    outline: 2px solid var(--color-focus-ring);
    outline-offset: 1px;
}

/* F .drop (989-994) — the dashed drop zone on the --panel-2 ground; the native file input still covers it (the global
   .file-input / .upload-dropzone input overlay), and .upload-dropzone--dragging keeps its own state colours */
.upload-area.drop,
.upload-dropzone.drop {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 4px;
    padding: 18px 16px;
    border-radius: 10px;
    color: var(--text-secondary);
    font-size: 13.5px;
    text-align: center;
    cursor: pointer;
}

.upload-area.drop,
.upload-dropzone.drop:not(.upload-dropzone--dragging) {
    border: 1px dashed var(--glass-border-light);
    background: var(--glass-bg-light);
}

.upload-area.drop:hover,
.upload-dropzone.drop:not(.upload-dropzone--dragging):hover {
    border-color: var(--text-secondary);
    color: var(--text-primary);
}

.upload-area.drop:focus-within,
.upload-dropzone.drop:focus-within {
    outline: 2px solid var(--color-focus-ring);
    outline-offset: 2px;
}

/* The App's label inside the zone is F's content column (icon, text, small) — no box of its own */
.upload-area.drop .upload-label,
.upload-dropzone.drop .upload-choose-label {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    min-height: 0;
    padding: 0;
    border: 0;
    background: none;
    color: inherit;
    font-size: 13.5px;
}

.upload-dropzone.drop .upload-choose-label:hover {
    color: var(--text-primary);
}

.drop .anticon {
    font-size: 20px;
    color: var(--text-muted);
}

.drop small,
.drop .upload-hint {
    margin: 0;
    font: 400 11.5px var(--font-mono);
    color: var(--text-muted);
}

/* F details.clp — the Reference collapsible: an inset on the --panel-2 ground with a --line-2 edge, a 500 13.5px head,
   the muted chevron. overrides.css paints every .ant-collapse with !important, so these carry it too. */
.clp.ant-collapse {
    border: 1px solid var(--glass-border-light) !important;
    border-radius: 10px !important;
    background: var(--glass-bg-light) !important;
}

.clp.ant-collapse > .ant-collapse-item {
    border-bottom: 0 !important;
}

.clp.ant-collapse > .ant-collapse-item > .ant-collapse-header {
    align-items: center;
    padding: 10px 14px;
    color: var(--text-primary) !important;
    font: 500 13.5px var(--font-body);
}

.clp.ant-collapse .ant-collapse-arrow {
    color: var(--text-muted);
}

.clp.ant-collapse > .ant-collapse-item-active > .ant-collapse-header {
    border-bottom: 1px solid var(--glass-border);
}

.clp.ant-collapse .ant-collapse-content {
    border-top: 0 !important;
    background: none !important;
    color: var(--text-primary) !important;
}

.clp.ant-collapse .ant-collapse-content > .ant-collapse-content-box {
    display: flex;
    flex-direction: column;
    gap: 14px;
    padding: 14px !important;
}

/* F .or — the "or" divider: 500 10.5px mono, tracked, muted, between two --line rules */
.clp .or {
    display: flex;
    align-items: center;
    gap: 10px;
    font: 500 10.5px var(--font-mono);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.clp .or::before,
.clp .or::after {
    content: '';
    flex: 1;
    height: 1px;
    background: var(--glass-border);
}

.clp .ant-divider-inner-text {
    font: 500 10.5px var(--font-mono);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-muted);
}

/* F .wact.wact--end — the form's actions: no card, right-aligned, gap 8 (the 36px buttons: the I-032 .wact rule) */
.form-actions-footer.wact.wact--end {
    justify-content: flex-end;
    align-items: center;
    gap: 8px;
    margin-top: 0;
}

/* Above 480px no rule and no padding; at <= 480px the base rule's sticky column (its ground, rule and padding) applies */
@media (min-width: 480.02px) {
    .form-actions-footer.wact.wact--end {
        padding: 0;
        border-top: 0;
    }
}

/* F 1161: the rail stacks under the main column at a page container <= 900px */
@container page (max-width: 900px) {
    .detail-page-grid.detail-grid {
        grid-template-columns: minmax(0, 1fr);
    }
}

/* F 1182-1200: at a page container <= 600px the two-up row stacks and the thread rows tighten */
@container page (max-width: 600px) {
    .formcol .row2 {
        grid-template-columns: minmax(0, 1fr);
    }

    .thread > .msg {
        gap: 10px;
        padding: 12px;
    }

    .formcol > .glass-card {
        padding: 16px;
    }
}

/* =====================================================================================================
   Remaining pages (I-036) — prototype F's auth split shell, plans / subscription / FAQ, result face and the Referrals
   dashboard model (f.src.html CSS: .tag / .tag--dash 202-208, frame / .ph / .panel / .panel__sub / .panel__foot 251-268,
   .face / .face__ic 314-317, .cell / .pos-* 360-366, .tbl 542-546, details.clp 627-633, .tabs 663-667, auth 791-805,
   .result-col / .face--page / face tones / .meters 908-925, .tier__feats 963-965, .ctbl / .pcards / .pcard / .faq /
   .feats2 / .auth--split / .lp / .lpb 1087-1150, .auth__card 1281, container queries 1309-1350; screens authShell 3416,
   productPanel 3425, loginPage 2755, deletionPage 3460, billingPage 3373, pcard 3337, compareTable 3326, nextUpPanel 3366,
   resultPage 3437). README Constraint 4, 7, D-n, D-o, D-p, D-s, D-t, D-v, D-w, D-ab, D-ac.
   Tokens only — F roles as in the I-027 … I-035 headers: --panel = --glass-bg, --panel-2 = --glass-bg-light, --line =
   --glass-border, --line-2 = --glass-border-light, --text = --text-primary, --text-2 = --text-secondary, --muted =
   --text-muted, --ok = --color-success, --warn / --warn-bg = --color-warning / --color-warning-bg, --err = --color-error,
   --info / --info-bg = --color-info / --color-info-bg, --threat = --rate-threat, --threat-1 / --threat-text =
   --rate-threat-bg-1 / --rate-threat-text, --below-bg / --at-bg / --above-bg = --position-below-bg / --position-at-bg /
   --position-above-bg, --none-bg = --chart-shade, --primary-bg / --primary-line / --primary-text / --glow =
   --color-primary-bg / --color-primary-line / --color-primary-text / --color-primary-glow, --r / --r-sm = --radius-lg /
   --radius-md, --font-ui = --font-body. Every colour is a theme token (I-023), so light needs no second block.
   Opt-in and scoped: every rule sits under the block's own classes — .auth--split, .auth__card, .lp, .lpb, .pcards,
   .pcard, .pfoot, .ctbl, .bill-head, .bill-panel, .bill-stack, .bill-tabs, .feats2, .faq, .result-col, .pricing-checkout, .referral-share,
   .referral-reward, .history-section, .kline--3, .subscription-current-plan__header — so Index.razor's info face,
   DeleteAccountModal, the Settings page, EntityFormDrawer and the base .status-result* / .auth-* / .pricing-* rules keep
   deciding everywhere else (Constraint 4). What it holds:
   - the auth split shell (D-s): .auth-page.auth--split is the `auth` container (F's breakpoints query #content; the
     App's query the layout's own width) — grid hd / main / ft beside lp, the 64px header, the card column
     (.auth-left > .auth-main > .auth-container.auth__card, min(420px, 100%)), F's card look (title 30px, sub 15px, mono
     expiry, field labels, separator, links, the .otp-code-field input), the mono footer; one column at <= 900px with the
     panel as a strip above the card; no entrance animation (I-021 AD5);
   - the product panel (D-t): aside.lp with the one faint glow behind it, the copy (.lp__eyebrow / __title / __sub) and
     the static 7-night sample board .lpb (head with .av--mine, 7 day columns, 58px .cell on the position grounds, the
     threat corner, tonight ringed in the text role, the .dgrid-legend foot) — nothing in it is interactive; the cells reuse
     the .position-* family (#11903), never F's .pos-*;
   - the billing views (D-n, D-o, D-p): .bill-panel (F .panel with .panel__head / __title / __sub / __foot), .pcards /
     .pcard (Recommended .is-rec in the --text-2 role, the current plan .is-current on the primary line), .tier__feats,
     .pfoot, the Compare plans table table.tbl-f.ctbl (current column .c-cur), .feats2, .bill-tabs (Plan / Invoices) with
     .tab-intro, and the FAQ .faq of .clp Collapses on the panel ground; .meters / .meter are the I-032 Team rules (reused);
   - the switch-on checkout branch (D-h): .pricing-checkout carries Upgrade.razor.css's toggle labels, the savings badge
     (neutral) and .plan-action; the featured-amount gradient and the card entrance animation are dropped;
   - the result face (D-v): .result-col (600px) and the .status-result* hooks restyled only under .result-col and
     .auth__card as F .face--page (56px tone icon, 24px title, 54ch text, wrapped actions, .face__meta);
   - the Referrals model (D-w): .referral-share (link box, neutral share links, code row), .kline.kline--3,
     .referral-reward (a neutral .meter), .history-section with its status tags in F tones.
   Orange only means "mine" (Constraint 7): the current plan (.is-current, .c-cur), the .lp glow and its eyebrow
   (F --primary-text), the primary buttons (AntD, unchanged), .av--mine (global) and the focus ring. Recommended is
   neutral ink, positions use the position family, the undercut corner is threat.
   ===================================================================================================== */

/* F .auth.auth--split — the shell: card column left, product panel right; the layout is the `auth` container. An element
   cannot query its own container, so the <= 900px stack is done by the children (below): the empty second row on the left
   is where the panel strip lands, which keeps F's "auto auto 1fr auto" stacked rows */
/* #app, body and html clip (overflow: hidden) and the global .auth-page is 100% tall, so the shell scrolls its own overflow —
   a tall card (Register) or a short window (a phone on its side) stays reachable (I-036 TASK_04) */
.auth-page.auth--split {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.08fr);
    grid-template-rows: auto auto 1fr auto;
    grid-template-areas: "hd lp" ". lp" "main lp" "ft lp";
    min-height: 100%;
    overflow-y: auto;
    container: auth / inline-size;
}

/* F .auth__hd — 64px, logo left, language right, no ground and no rule */
.auth--split > .auth-header {
    grid-area: hd;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    height: 64px;
    padding: 0 24px;
    background: none;
    border-bottom: 0;
}

.auth--split .auth-logo a {
    display: inline-flex;
}

.auth--split .auth-logo-img {
    height: 24px;
    width: auto;
}

/* F .auth__left — the card column, centred vertically */
.auth--split > .auth-left {
    grid-area: main;
    display: flex;
    flex-direction: column;
    justify-content: center;
    min-width: 0;
}

/* F .auth__main in the split: 16px above, 40px below, the card centred */
.auth--split .auth-main {
    flex: none;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 16px 24px 40px;
}

/* F .auth__wrap + .auth__card — min(420px, 100%), 28px 28px 22px, gap 16; no entrance animation (I-021 AD5) */
.auth--split .auth-container.auth__card {
    width: min(420px, 100%);
    max-width: none;
    display: flex;
    flex-direction: column;
    gap: 16px;
    padding: 28px 28px 22px;
    animation: none;
}

/* The page's form is the card's column: F stacks the head, the form, the separator and the links 16px apart */
.auth__card .auth-form {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.auth__card .auth-form-header {
    margin: 0;
    text-align: left;
}

/* F .auth--split .auth__card h1 — 600 30px/1.15, -.02em */
.auth--split .auth__card .auth-title {
    margin: 0;
    font: 600 30px/1.15 var(--font-body);
    letter-spacing: -0.02em;
    color: var(--text-primary);
}

/* F .auth__sub — 15px in the split, --text-2 */
.auth--split .auth__card .auth-subtitle {
    margin: 6px 0 0;
    font-size: 15px;
    color: var(--text-secondary);
}

/* F .auth__exp — 12px mono, muted (the template's orange pill goes) */
.auth__card .auth-code-expires {
    display: block;
    margin: 6px 0 0;
    padding: 0;
    background: none;
    font: 400 12px var(--font-mono);
    color: var(--text-muted);
}

/* F .auth__form — the fields 14px apart */
.auth__card .ant-form {
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.auth__card .ant-form .ant-form-item {
    margin-bottom: 0;
}

/* AntD holds 24px under every field for its message — the explain box's min-height and a 0 x 24px spacer beside it
   (inline style) — and takes it back with a -24px offset inside an item whose own margin pays for it. With the item's
   margin at 0 the offset would shrink the item and a two-line message would sit behind the next control, and the
   reserve would double F's 14px field rhythm. The message keeps its own height and an empty one takes none. */
.auth__card .ant-form-item-margin-offset {
    display: none;
}

.auth__card .ant-form-item-explain {
    min-height: 0;
}

.auth__card .ant-form-item-explain + div {
    height: 0 !important;
}

/* F .fi__label — 500 12px mono, --text-2 */
.auth__card .filter-label,
.auth__card .ant-form-item-label > label {
    font: 500 12px var(--font-mono);
    letter-spacing: 0.01em;
    color: var(--text-secondary);
}

/* F .otp — the code input: mono 16px, .4em letter-spacing */
.auth__card .otp-code-field input {
    font: 400 16px var(--font-mono);
    letter-spacing: 0.4em;
}

/* F .cnt-hint — the code field's "0 / 6" count: 11px mono, muted (AntD's ShowCount suffix; I-036 TASK_10 fidelity) */
.auth__card .otp-code-field .ant-input-show-count-suffix {
    font: 400 11px var(--font-mono);
    color: var(--text-muted);
}

/* F .auth__sep — a 1px --line rule, 2px above and below (a plain element: overrides.css pins .ant-divider's margin) */
.auth__card .auth__sep {
    height: 1px;
    margin: 2px 0;
    background: var(--glass-border);
}

/* F .auth__links — 13.5px --text-2, centred; links 600 in the text colour (never orange) */
.auth__card .auth-footer-links {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-wrap: wrap;
    gap: 6px;
    margin: 0;
    font-size: 13.5px;
    color: var(--text-secondary);
}

.auth__card .auth-footer-links a {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    margin-left: 0;
    font-weight: 600;
    color: var(--text-primary);
    text-decoration: underline;
    text-decoration-color: var(--glass-border-light);
    text-underline-offset: 3px;
}

.auth__card .auth-footer-links a:hover {
    color: var(--text-primary);
    text-decoration-color: currentColor;
}

.auth__card .auth-footer-links a::after {
    display: none;
}

/* F .alert b + p — 13.5px throughout, a 2px gap and a 16px icon on the first line (AntD's description Alert is 16px /
   14px / 18px); the warning, info and error notices on the deletion pages */
.auth__card .ant-alert-with-description .ant-alert-message,
.auth__card .ant-alert-description {
    font-size: 13.5px;
    line-height: 1.45;
}

.auth__card .ant-alert-with-description .ant-alert-description {
    margin-top: 2px;
}

.auth__card .ant-alert-with-description .ant-alert-icon {
    margin-top: 2px;
    font-size: 16px;
}

/* The referral banner (Register) and the deletion acknowledgement — an F info line / a plain row in the card */
.auth__card .referral-banner {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    border: 1px solid var(--position-below-border);
    border-radius: var(--radius-md);
    background: var(--color-info-bg);
    color: var(--text-primary);
    font-size: 13.5px;
}

.auth__card .referral-banner-icon {
    color: var(--color-info);
}

.auth__card .referral-banner-subtitle {
    color: var(--text-secondary);
}

.auth__card .subscription-acknowledgement {
    margin: 0;
}

/* The confirm pages' #otp-error (the OTP input's aria-describedby target) stays in the DOM; empty, it must not
   add a flex gap of its own between the code field and the buttons */
.auth__card #otp-error:empty {
    display: none;
}

/* F .auth__ft — 11.5px mono muted, left, no top rule in the split */
.auth--split > .auth-footer {
    grid-area: ft;
    margin: 0;
    padding: 14px 24px 18px;
    background: none;
    border-top: 0;
    text-align: left;
}

.auth--split > .auth-footer .footer-content {
    font: 400 11.5px var(--font-mono);
    letter-spacing: 0;
    color: var(--text-muted);
}

/* F .lp — the product panel: the panel ground, a left rule, the one faint glow behind it. clip, not hidden: a scroll
   container's grid row may shrink below its content, which crushed the <= 900px strip under the card (I-036 TASK_04) */
.lp {
    grid-area: lp;
    position: relative;
    isolation: isolate;
    overflow: clip;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 28px;
    padding: 48px max(48px, env(safe-area-inset-right, 0px)) 48px 56px;
    background: var(--glass-bg);
    border-left: 1px solid var(--glass-border);
}

.lp::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    background: radial-gradient(70% 60% at 62% 62%, var(--color-primary-glow), transparent 72%);
}

.lp .lp__copy {
    display: flex;
    flex-direction: column;
    gap: 12px;
    max-width: 34em;
}

/* F .lab.lp__eyebrow — the eyebrow in the --primary-text role (the panel speaks for my product) */
.lp .lp__eyebrow {
    font: 500 10.5px/1.3 var(--font-mono);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--color-primary-text);
}

.lp .lp__title {
    margin: 0;
    max-width: 13em;
    font: 600 44px/1.06 var(--font-body);
    letter-spacing: -0.025em;
    color: var(--text-primary);
}

.lp .lp__sub {
    margin: 0;
    max-width: 36em;
    font-size: 16px;
    line-height: 1.55;
    color: var(--text-secondary);
}

/* F .lpb — the sample board, a panel of at most 600px; nothing in it takes the pointer */
.lpb {
    max-width: 600px;
    padding: 0;
    background: var(--glass-bg);
}

.lpb .lpb__head {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 12px 16px;
    border-bottom: 1px solid var(--glass-border);
}

.lpb .lpb__t {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    line-height: 1.3;
}

.lpb .lpb__t b {
    font-size: 14px;
    font-weight: 600;
    color: var(--text-primary);
}

.lpb .lpb__t span {
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    font: 400 11px var(--font-mono);
    color: var(--text-muted);
}

.lpb .lpb__row {
    display: grid;
    grid-template-columns: repeat(7, minmax(0, 1fr));
    gap: 5px;
    margin: 0;
    padding: 12px 14px 6px;
    list-style: none;
}

.lpb .lpb__row > li {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 5px;
    min-width: 0;
}

/* F .lpb__d — 500 10.5px mono uppercase, muted; the date under it in --text-2 */
.lpb .lpb__d {
    font: 500 10.5px/1.2 var(--font-mono);
    letter-spacing: 0.04em;
    text-transform: uppercase;
    text-align: center;
    white-space: nowrap;
    color: var(--text-muted);
}

.lpb .lpb__d b {
    display: block;
    font-weight: 500;
    letter-spacing: -0.02em;
    text-transform: none;
    color: var(--text-secondary);
}

.lpb .lpb__row > li.is-we .lpb__d {
    font-weight: 600;
    color: var(--text-primary);
}

.lpb .lpb__row > li.is-tn .lpb__d,
.lpb .lpb__row > li.is-tn .lpb__d b {
    font-weight: 700;
    color: var(--text-primary);
}

/* F .lpb .cell — the 58px night on its position ground; not a button */
.lpb .cell {
    position: relative;
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 3px;
    width: 100%;
    height: 58px;
    border: 1px solid transparent;
    border-radius: var(--radius-md);
    color: var(--text-primary);
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
    cursor: default;
}

/* F .pos-* is the App's one position family, .position-below / -at / -above / -none (#11903, reused): the cell's own border
   above keeps their border colour and .position-none's dashed style off it; no position takes F's faint --none-bg */
.lpb .cell.position-none {
    background: var(--chart-shade);
}

.lpb .cell__p {
    font-size: 12.5px;
    font-weight: 600;
    line-height: 1;
}

.lpb .cell__d {
    font-size: 10.5px;
    line-height: 1;
    color: var(--text-secondary);
}

/* F .cell.is-uc::after — the 7px threat corner */
.lpb .cell.is-uc::after {
    content: '';
    position: absolute;
    top: 4px;
    right: 4px;
    border-left: 7px solid transparent;
    border-top: 7px solid var(--rate-threat);
    border-radius: 0 2px 0 0;
}

/* F .lpb li.is-tn .cell — tonight ringed in the text role */
.lpb .lpb__row > li.is-tn .cell {
    box-shadow: 0 0 0 2px var(--text-primary);
}

.lpb .lpb__foot {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 8px 14px;
    padding: 8px 16px 12px;
}

/* The F frame's 16px gutters on a phone (F's --gut-l / --gut-r) */
@media (max-width: 640px) {
    .auth--split > .auth-header,
    .auth--split .auth-main,
    .auth--split > .auth-footer {
        padding-right: 16px;
        padding-left: 16px;
    }
}

@container auth (max-width: 1100px) {
    .lp {
        padding-right: max(32px, env(safe-area-inset-right, 0px));
        padding-left: 40px;
    }

    .lp .lp__title {
        font-size: 36px;
    }
}

/* F <= 900px: one column (hd, lp, main, ft) — the panel is a strip above the card, the footer centred with a rule. Each
   child spans both columns on its own row (rows auto / auto / 1fr / auto: the card column takes the height) */
@container auth (max-width: 900px) {
    .auth--split > .auth-header,
    .auth--split > .lp,
    .auth--split > .auth-left,
    .auth--split > .auth-footer {
        grid-column: 1 / -1;
    }

    .auth--split > .auth-header {
        grid-row: 1;
    }

    .auth--split > .lp {
        grid-row: 2;
    }

    .auth--split > .auth-left {
        grid-row: 3;
        justify-content: flex-start;
    }

    .auth--split > .auth-footer {
        grid-row: 4;
    }

    .auth--split .auth-main {
        padding-top: 24px;
    }

    .auth--split > .auth-footer {
        text-align: center;
        border-top: 1px solid var(--glass-border);
    }

    .lp {
        gap: 12px;
        padding: 16px 24px 18px;
        border-left: 0;
        border-top: 1px solid var(--glass-border);
        border-bottom: 1px solid var(--glass-border);
    }

    .lp .lp__eyebrow,
    .lp .lp__sub,
    .lpb .lpb__foot {
        display: none;
    }

    .lp .lp__copy {
        max-width: none;
        gap: 0;
    }

    .lp .lp__title {
        max-width: none;
        font-size: 24px;
    }

    .lpb {
        max-width: 640px;
    }

    .lpb .lpb__head {
        padding: 8px 12px;
    }

    .lpb .lpb__row {
        padding: 10px 10px 12px;
    }
}

/* F <= 640px: the card's 22px 18px 18px */
@container auth (max-width: 640px) {
    .auth--split .auth-container.auth__card {
        padding: 22px 18px 18px;
    }

    .lp {
        padding-right: 16px;
        padding-left: 16px;
    }
}

@container auth (max-width: 600px) {
    .lp .lp__title {
        font-size: 20px;
    }

    .lpb .lpb__row {
        gap: 3px;
        padding: 8px 8px 10px;
    }

    .lpb .cell {
        height: 46px;
    }

    .lpb .cell__p {
        font-size: 11px;
    }

    .lpb .cell__d,
    .lpb .lpb__d {
        font-size: 9.5px;
        letter-spacing: 0;
    }
}

/* F .panel with a head — the billing panels draw their rows edge to edge */
.glass-card.bill-panel {
    padding: 0;
}

.bill-panel .panel__head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 10px 16px;
    padding: 12px 16px;
    border-bottom: 1px solid var(--glass-border);
}

/* F .cset__titlerow — the title and its plan tags */
.bill-panel .panel__titlerow {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

.bill-panel .panel__title {
    margin: 0;
    font-size: 15px;
    font-weight: 600;
    line-height: 1.3;
    color: var(--text-primary);
}

.bill-panel .panel__sub {
    margin: 2px 0 0;
    font-size: 12.5px;
    color: var(--text-muted);
}

.bill-panel .panel__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.bill-panel .panel__foot {
    padding: 12px 16px 14px;
    border-top: 1px solid var(--glass-border);
}

/* Subscription's panels and states stack at the F frame's 16px rhythm: they sit inside the page's aria-live wrapper, so
   the frame's own column gap does not reach them (as .ins-stack, I-029; I-036 TASK_07) */
.bill-stack {
    display: flex;
    flex-direction: column;
    gap: 16px;
    min-width: 0;
}

/* F .pcards — three plan cards, gap 16 (one column at a 760px page container) */
.pcards {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    align-items: stretch;
    gap: 16px;
}

/* F .pcard — a flex column, gap 14, 20px 20px 18px */
.glass-card.pcard {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 14px;
    padding: 20px 20px 18px;
}

/* F .pcard.is-rec — Recommended: the --text-2 line and inset ring, never orange */
.glass-card.pcard.is-rec {
    border-color: var(--text-secondary);
    box-shadow: inset 0 0 0 1px var(--text-secondary);
}

/* F .pcard.is-current — the current plan is mine: the primary line */
.glass-card.pcard.is-current {
    border-color: var(--color-primary-line);
    box-shadow: inset 0 0 0 1px var(--color-primary-line);
}

.pcard .pcard__top {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    min-height: 26px;
}

.pcard .pcard__name {
    margin: 0 auto 0 0;
    font: 600 19px/1.2 var(--font-body);
    color: var(--text-primary);
}

/* F .tag--rec — ink on the panel ground */
.pcard .tag.tag--rec {
    border-color: var(--text-secondary);
    background: var(--glass-bg);
    color: var(--text-primary);
}

.pcard .pcard__price {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 4px;
}

.pcard .pcard__price b {
    font: 600 34px/1 var(--font-mono);
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.02em;
    color: var(--text-primary);
}

.pcard .pcard__price span {
    font: 400 13px var(--font-mono);
    color: var(--text-muted);
}

/* The dashed launch / no-card tag keeps its own width in the column */
.pcard > .tag {
    align-self: flex-start;
}

.pcard .pcard__desc {
    min-height: 2.9em;
    margin: 0;
    color: var(--text-secondary);
}

/* F .tier__feats — a top rule, 14px above, 9px apart, 13.5px; the ok checks; items in --text inside a card */
.pcard .tier__feats {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 9px;
    margin: 0;
    padding: 14px 0 0;
    list-style: none;
    border-top: 1px solid var(--glass-border);
    font-size: 13.5px;
}

.pcard .tier__feats > li {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    color: var(--text-primary);
}

.pcard .tier__feats .anticon {
    flex: none;
    margin-top: 2px;
    color: var(--color-success);
}

.pcard .pcard__cta {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

/* F .pfoot — the footnote: 12.5px muted with its info icon */
.pfoot {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    max-width: 90ch;
    margin: 0;
    font-size: 12.5px;
    color: var(--text-muted);
}

.pfoot .anticon {
    flex: none;
    margin-top: 2px;
}

/* F .ctbl — the Compare plans table on the native list table (table.tbl-f in its .tbl-f__scroll host) */
.ctbl thead th {
    vertical-align: bottom;
}

/* F .c-cur — the current plan's column on the --primary-bg ground (mine) */
.ctbl th.c-cur,
.ctbl td.c-cur {
    background: var(--color-primary-bg);
}

.ctbl th .th-plan {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 4px;
    font: 600 13px var(--font-body);
    letter-spacing: 0;
    text-transform: none;
    color: var(--text-primary);
}

.ctbl th .th-plan small {
    font: 400 11px var(--font-mono);
    color: var(--text-muted);
}

.ctbl tbody tr > :first-child {
    white-space: normal;
    font: 500 13px var(--font-body);
    color: var(--text-primary);
}

.ctbl td .anticon {
    vertical-align: -3px;
}

.ctbl .yes {
    color: var(--color-success);
}

.ctbl .no {
    color: var(--text-muted);
}

.ctbl .arrow {
    margin: 0 6px;
    color: var(--text-muted);
}

.ctbl .gain {
    font-weight: 600;
    color: var(--text-primary);
}

/* F .feats2 — the current plan's features in three columns, 14px 16px, a bottom rule */
.feats2 {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 8px 22px;
    margin: 0;
    padding: 14px 16px;
    list-style: none;
    border-bottom: 1px solid var(--glass-border);
    font-size: 13.5px;
    color: var(--text-primary);
}

.feats2 > li {
    display: flex;
    align-items: flex-start;
    gap: 8px;
}

.feats2 .anticon {
    flex: none;
    margin-top: 2px;
    color: var(--color-success);
}

/* The Plan / Invoices tabs panel: the AntD tabs along its top edge, the panes padded as F .tab-intro */
.bill-tabs .ant-tabs-nav {
    margin: 0;
    padding: 0 16px;
}

.bill-tabs .ant-tabs-tabpane {
    padding: 14px 16px 16px;
}

.bill-panel .tab-intro {
    margin: 0;
}

/* F .face--sm — the Invoices tab's "No transactions yet" face, 28px 20px (I-036 TASK_10 fidelity) */
.bill-tabs .empty-state {
    padding: 28px 20px;
}

/* F .faq — the questions 8px apart, 14px 16px 16px; each a details.clp on the panel ground, 600 14px heads */
.faq {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 14px 16px 16px;
}

.faq .clp.ant-collapse {
    background: var(--glass-bg) !important;
}

.faq .clp.ant-collapse > .ant-collapse-item > .ant-collapse-header {
    padding: 12px 14px;
    font: 600 14px var(--font-body);
}

.faq .clp .ant-collapse-content-box p {
    max-width: 75ch;
    margin: 0;
    color: var(--text-secondary);
}

@container page (max-width: 900px) {
    .feats2 {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

@container page (max-width: 760px) {
    .pcards {
        grid-template-columns: minmax(0, 1fr);
    }

    .pcard .pcard__desc {
        min-height: 0;
    }
}

@container page (max-width: 600px) {
    .feats2 {
        grid-template-columns: minmax(0, 1fr);
    }

    /* F .tab-intro { padding: 12px } under a 600px page — the Plan / Invoices panes and the FAQ foot
       (I-038 TASK_06, P19 / V38 at 390: padding-left 16px → 12px) */
    .bill-tabs .ant-tabs-tabpane,
    .bill-panel .panel__foot.tab-intro {
        padding: 12px;
    }
}

/* The billing head's Segmented (D-n) is wider than a phone's head (three segments, ~400px): at a narrow page container
   it wraps inside the head, as the calendar toolbar's does, instead of running past the viewport (I-036 TASK_06) */
@container page (max-width: 600px) {
    .bill-head .ant-segmented {
        max-width: 100%;
    }

    .bill-head .ant-segmented-group {
        flex-wrap: wrap;
    }
}

/* The switch-on checkout branch (D-h) — carried from Upgrade.razor.css: the toggle row and its label emphasis, the
   savings badge (neutral, Constraint 7) and the card CTA at the foot; the featured-amount gradient and the entrance
   animation are dropped (I-021 AD5) */
.pricing-checkout .pricing-billing-toggle {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-md);
    margin: var(--space-sm) auto var(--space-xl);
}

.pricing-checkout .pricing-billing-toggle span {
    font-weight: 500;
    color: var(--text-muted);
}

.pricing-checkout .pricing-billing-toggle span.toggle-active {
    font-weight: 600;
    color: var(--text-primary);
}

.pricing-checkout .savings-badge {
    display: inline-block;
    margin-left: var(--space-xs);
    padding: 2px 8px;
    border: 1px solid var(--glass-border-light);
    border-radius: var(--radius-md);
    background: var(--glass-bg-light);
    font: 600 12px var(--font-mono);
    color: var(--text-secondary);
}

.pricing-checkout .plan-action {
    margin-top: auto;
}

@media (max-width: 480px) {
    .pricing-checkout .pricing-billing-toggle {
        gap: var(--space-sm);
    }

    .pricing-checkout .savings-badge {
        display: block;
        margin: var(--space-xs) 0 0;
    }
}

/* F .result-col — one 600px column, centred, gap 16 */
.result-col {
    display: flex;
    flex-direction: column;
    gap: 16px;
    width: min(600px, 100%);
    margin: 0 auto;
}

.result-col > .glass-card {
    padding: 0;
}

/* F .face.face--page — the result face, only inside .result-col and the auth card (Index.razor, DeleteAccountModal and
   the base .status-result keep theirs) */
.result-col .status-result,
.auth__card .status-result {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    padding: 44px 28px 36px;
    text-align: center;
}

/* F .face__ic in .face--page — 56 x 56, radius 16, the neutral line and panel-2 ground; no circle, no pop, no glow */
.result-col .status-result__icon,
.auth__card .status-result__icon {
    display: grid;
    place-items: center;
    width: 56px;
    height: 56px;
    margin: 0;
    border: 1px solid var(--glass-border);
    border-radius: 16px;
    background: var(--glass-bg-light);
    box-shadow: none;
    color: var(--text-muted);
    font-size: 26px;
    animation: none;
}

/* F .face__ic--ok */
.result-col .status-result--success .status-result__icon,
.auth__card .status-result--success .status-result__icon {
    border-color: color-mix(in srgb, var(--color-success) 35%, var(--glass-border));
    background: color-mix(in srgb, var(--color-success) 8%, var(--glass-bg));
    color: var(--color-success);
}

/* F .face__ic--warn — on --warn-bg */
.result-col .status-result--warning .status-result__icon,
.auth__card .status-result--warning .status-result__icon {
    border-color: color-mix(in srgb, var(--color-warning) 40%, var(--glass-border));
    background: var(--color-warning-bg);
    color: var(--color-warning);
}

/* F .face__ic--err */
.result-col .status-result--error .status-result__icon,
.auth__card .status-result--error .status-result__icon {
    border-color: color-mix(in srgb, var(--color-error) 35%, var(--glass-border));
    color: var(--color-error);
}

/* F .face__ic--info — on --info-bg */
.result-col .status-result--info .status-result__icon,
.auth__card .status-result--info .status-result__icon {
    border-color: color-mix(in srgb, var(--color-info) 35%, var(--glass-border));
    background: var(--color-info-bg);
    color: var(--color-info);
}

/* F .face--page h1 — 600 24px/1.2, -.015em */
.result-col .status-result__title,
.auth__card .status-result__title {
    margin: 6px 0 0;
    font: 600 24px/1.2 var(--font-body);
    letter-spacing: -0.015em;
    color: var(--text-primary);
    animation: none;
}

/* F .face--page p — --text-2, 54ch */
.result-col .status-result__description,
.auth__card .status-result__description {
    max-width: 54ch;
    margin: 0;
    font-size: var(--type-body);
    color: var(--text-secondary);
    animation: none;
}

.result-col .status-result__description strong,
.auth__card .status-result__description strong {
    font-weight: 600;
    color: var(--text-primary);
}

/* F .face--page .face__acts — wrapped and centred, 12px above (no full-width column on a phone) */
.result-col .status-result__actions,
.auth__card .status-result__actions {
    flex-direction: row;
    flex-wrap: wrap;
    justify-content: center;
    gap: 8px;
    width: auto;
    margin-top: 12px;
    animation: none;
}

.result-col .status-result__actions .ant-btn,
.auth__card .status-result__actions .ant-btn {
    width: auto;
}

/* F .face__meta — 12px mono (CheckoutSuccess's plan line, Join's expiry). F declares it muted, but its `.face p` rule
   (--text-2) outranks `.face__meta`, so F renders the line in --text-2 — the App matches what F renders (I-036 TASK_10) */
.result-col .face__meta,
.auth__card .face__meta {
    margin: 0;
    font: 400 12px var(--font-mono);
    color: var(--text-secondary);
}

@container page (max-width: 600px) {
    .result-col .status-result {
        padding: 32px 16px 28px;
    }

    .result-col .status-result__title {
        font-size: 21px;
    }
}

/* F .face--page inside .auth__card (the deleted state) — the card already pads, so the face keeps 8px 0 4px at every
   width, and the card's h1 (30px / 1.15, -.02em) outranks .face--page h1 */
.auth__card .status-result {
    padding: 8px 0 4px;
}

.auth__card .status-result__title {
    font-size: 30px;
    line-height: 1.15;
    letter-spacing: -0.02em;
}

/* Referrals on the dashboard model (D-w): the share panel — a plain F panel, no glow, no gradient */
.glass-card.referral-share {
    display: flex;
    flex-direction: column;
    gap: 14px;
    padding: 16px;
}

.referral-share .share-link-box {
    display: flex;
    align-items: center;
    gap: 8px;
    max-width: 600px;
    padding: 4px 4px 4px 12px;
    border: 1px solid var(--glass-border-light);
    border-radius: var(--radius-md);
    background: var(--glass-bg-light);
}

.referral-share .share-link-text {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    font: 400 12.5px var(--font-mono);
    color: var(--text-secondary);
}

.referral-share .share-buttons {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

/* The share links are F .btn — neutral, no brand tints and no lift */
.referral-share .share-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    height: 32px;
    padding: 0 12px;
    border: 1px solid var(--glass-border-light);
    border-radius: var(--radius-md);
    background: var(--glass-bg);
    font: 500 13.5px var(--font-body);
    color: var(--text-primary);
    text-decoration: none;
}

.referral-share .share-btn:hover {
    border-color: var(--text-secondary);
    color: var(--text-primary);
}

.referral-share .code-section {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

/* The code label is F .lab */
.referral-share .code-label {
    font: 500 10.5px/1.3 var(--font-mono);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.referral-share .code-display {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

.referral-share .code-value {
    font: 600 21px var(--font-mono);
    letter-spacing: 0.04em;
    color: var(--text-primary);
}

/* Customize is a link Button (hook .customize-btn) and the global .ant-btn-link colour is !important brand orange; orange
   only means "mine" (the primary Copy Link, the focus ring), so it keeps F's neutral text-button ink, as the lists' .evname */
.referral-share .ant-btn.ant-btn-link.customize-btn {
    color: var(--text-secondary) !important;
}

.referral-share .ant-btn.ant-btn-link.customize-btn:hover:not(:disabled),
.referral-share .ant-btn.ant-btn-link.customize-btn:focus-visible:not(:disabled) {
    color: var(--text-primary) !important;
}

/* The KPI line with three cells (Total referrals, Conversions, Reward days earned) */
.kline.kline--3 {
    grid-template-columns: repeat(3, minmax(0, 1fr));
}

/* The reward days meter is not my workspace's usage: a neutral bar (the Team .meter, I-032) */
.referral-reward .meter .ant-progress-bg {
    background: var(--text-secondary) !important;
}

.referral-reward .meter.is-full .ant-progress-bg {
    background: var(--color-warning) !important;
}

/* The history panel: the AntD table edge to edge under its head; status tags in F tones (pending neutral) */
.glass-card.history-section {
    padding: 0;
}

.history-section .panel__head {
    padding: 12px 16px;
    border-bottom: 1px solid var(--glass-border);
}

/* Referrals' own pieces (I-036 TASK_09). The page's panels sit inside its aria-live wrapper, so the frame's column gap does
   not reach them: the wrapper (and the commission KPI lines, one per currency) wear .bill-stack, the F-rhythm column above */
/* F .panel__title / .panel__sub — the share panel's title and sub and the history panels' heads (size, weight and
   line-height only: the h2 keeps --font-display from the heading rule) */
.referral-share .hero-title,
.history-section .panel__title {
    margin: 0;
    font-size: 15px;
    font-weight: 600;
    line-height: 1.3;
    color: var(--text-primary);
}

.referral-share .hero-subtitle {
    margin: 2px 0 0;
    font-size: 12.5px;
    color: var(--text-muted);
}

/* The payout panel's body is padded as F .tab-intro; the table panels draw their rows edge to edge */
.history-section .panel__body {
    padding: 14px 16px 16px;
}

.history-section .panel__body .tab-intro {
    margin-bottom: 0;
}

.history-section .panel__body .tab-intro + .settings-section-actions {
    margin-top: 12px;
}

.history-section .pagination-container {
    padding: 12px 16px;
}

/* One reward meter: the panel is flush and the meter takes the whole row (the Team .meters grid is three columns) */
.glass-card.referral-reward {
    padding: 0;
}

.referral-reward .meters {
    grid-template-columns: minmax(0, 1fr);
}

/* Status tags in F tones — the referral history and the Subscription billing status (D-w, D-ai) */
.history-section .ant-tag.tag--ok,
.subscription-current-plan__header .ant-tag.tag--ok {
    border-color: color-mix(in srgb, var(--color-success) 40%, transparent) !important;
    background: var(--color-success-bg) !important;
    color: var(--color-success) !important;
}

.history-section .ant-tag.tag--info,
.subscription-current-plan__header .ant-tag.tag--info {
    border-color: var(--position-below-border) !important;
    background: var(--color-info-bg) !important;
    color: var(--color-info) !important;
}

.history-section .ant-tag.tag--warn,
.subscription-current-plan__header .ant-tag.tag--warn {
    border-color: var(--position-above-border) !important;
    background: var(--color-warning-bg) !important;
    color: var(--color-warning) !important;
}

.history-section .ant-tag.tag--threat,
.subscription-current-plan__header .ant-tag.tag--threat {
    border-color: color-mix(in srgb, var(--rate-threat-text) 40%, transparent) !important;
    background: var(--rate-threat-bg-1) !important;
    color: var(--rate-threat-text) !important;
}

@container page (max-width: 820px) {
    .kline.kline--3 .kline__cell:nth-child(3) {
        border-left: 1px solid var(--glass-border);
    }

    .kline.kline--3 .kline__cell:nth-child(n + 3) {
        border-top: 0;
    }
}

@container page (max-width: 600px) {
    .kline.kline--3 {
        grid-template-columns: minmax(0, 1fr);
    }

    .kline.kline--3 .kline__cell + .kline__cell {
        border-top: 1px solid var(--glass-border);
        border-left: 0;
    }

    .referral-share .share-link-box {
        flex-wrap: wrap;
    }
}

/* =====================================================================================================
   Competitor finder (I-039) — prototype F v9's competitor finder (onboarding step 3 and the "Add competitors" drawer:
   the CSS block "Competitor finder (I-039)", cfSide / cfMain / cfCard / cfSelected). Showcase: /design-system
   #competitor-finder, #filter-facets, #hotel-card, #selected-list, the wide wizard step (#wizard-template) and the wide
   drawer (#drawer-playground-template). F names → App names: cfSide = .cf__side, cfMain = .cf__main, cfCard =
   .hotel-card.hotel-card--rich (the existing hotel-card hooks), cfSelected = .sel, the facet groups = .ff.
   Tokens only — F roles as in the I-027 … I-036 headers: --panel = --glass-bg, --panel-2 = --glass-bg-light, --line =
   --glass-border, --line-2 = --glass-border-light, --text = --text-primary, --text-2 = --text-secondary, --muted =
   --text-muted, --mask = --color-mask, --shadow = --shadow-float. Every colour is a theme token, so light needs no
   second block. Orange only means "mine": a selected card (.hotel-card--selected, I-032) and the primary button; facet
   checks are neutral (the --text fill), never the primary.
   Opt-in: every rule sits under the block's own classes (.cf, .ff, .sel, .hotel-card--rich, .page-container--wide on the
   F frame), so the I-032 wizard cards and every other page keep deciding everywhere else.
   ===================================================================================================== */

/* --- Wide wizard step: one step of the F wizard on 1200px (the F frame's own max-width is 1440) --- */
.page-container.page-container--f.page-container--wide {
    max-width: var(--page-width-wide);
}

/* --- The finder: a 252px sticky sidebar beside the results column --- */
.cf {
    display: grid;
    grid-template-columns: 252px minmax(0, 1fr);
    align-items: start;
    gap: 16px;
    min-width: 0;
}

.cf__side {
    position: sticky;
    top: 12px;
    display: flex;
    flex-direction: column;
    max-height: calc(100vh - 24px);
    min-width: 0;
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-lg);
    background: var(--glass-bg);
    overflow: hidden;
}

.cf__side-head {
    flex: none;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 12px 14px;
    border-bottom: 1px solid var(--glass-border);
}

.cf__side-title {
    margin: 0;
    font-size: var(--type-panel-title);
    font-weight: var(--type-panel-title-weight);
    color: var(--text-primary);
}

.cf__side-actions {
    display: inline-flex;
    align-items: center;
    gap: 8px;
}

/* The scrollable facet groups between the head and the apply bar */
.cf__groups {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
}

/* The apply bar: "Changes not applied yet" over a full-width primary "Show results" (disabled until something changed) */
.cf__apply {
    flex: none;
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 12px 14px;
    border-top: 1px solid var(--glass-border);
    background: var(--glass-bg-light);
}

.cf__apply .ant-btn {
    width: 100%;
    height: var(--control-h-block);
}

.cf__pending {
    display: flex;
    align-items: center;
    gap: 6px;
    font: 500 11.5px var(--font-mono);
    color: var(--text-secondary);
}

/* The amber dirty dot of the I-032 save bar */
.cf__pending::before {
    content: "";
    flex: none;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--color-warning);
}

/* A text button in the finder's chrome: Clear, Clear all, Show all n */
.cf__link {
    padding: 0;
    border: 0;
    background: none;
    color: var(--text-secondary);
    font: 500 12.5px var(--font-body);
    cursor: pointer;
    white-space: nowrap;
}

.cf__link:hover {
    color: var(--text-primary);
    text-decoration: underline;
}

.cf__link:focus-visible {
    outline: none;
    border-radius: var(--radius-sm);
    box-shadow: 0 0 0 2px var(--color-focus-ring);
}

.cf__link:disabled {
    color: var(--text-muted);
    text-decoration: none;
    cursor: default;
}

/* --- The results column: toolbar, applied chips, the date note, the card grid, "Show 20 more" --- */
.cf__main {
    display: flex;
    flex-direction: column;
    gap: 12px;
    min-width: 0;
}

.cf__toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 16px;
    min-width: 0;
}

.cf__count {
    margin-right: auto;
    font: 400 12.5px var(--font-mono);
    color: var(--text-secondary);
    white-space: nowrap;
}

.cf__count b {
    color: var(--text-primary);
    font-weight: 600;
}

.cf__ctl {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    min-width: 0;
}

.cf__ctl-label {
    font: var(--type-label-weight) var(--type-label) var(--font-mono);
    letter-spacing: var(--type-label-tracking);
    text-transform: uppercase;
    color: var(--text-muted);
    white-space: nowrap;
}

/* AntD writes width: 100% on the Select; the flex basis decides its width in the row */
.cf__ctl > .ant-select {
    flex: 0 0 196px;
}

.cf__ctl > .ant-picker {
    flex: 0 0 148px;
}

.cf__chips {
    align-items: center;
}

/* F v9 .cf__note: mono 12px, muted */
.cf__note {
    margin: 0;
    font: 400 12px var(--font-mono);
    color: var(--text-muted);
}

/* overrides.css greys every drawer paragraph (.ant-drawer-body p, !important); the note keeps F's muted tone there too */
.ant-drawer-body p.cf__note {
    color: var(--text-muted) !important;
}

.cf__note b {
    font-family: var(--font-mono);
    font-weight: 600;
    color: var(--text-primary);
}

.cf__grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(290px, 100%), 1fr));
    gap: 8px;
}

.cf__more {
    display: flex;
    justify-content: center;
    padding-top: 4px;
}

/* Loading: one skeleton per card slot (the command palette's shimmer) */
.cf__skel {
    height: 132px;
    border-radius: 10px;
    background: linear-gradient(90deg, var(--color-skeleton-1) 25%, var(--color-skeleton-2) 50%, var(--color-skeleton-1) 75%);
    background-size: 200% 100%;
    animation: skeletonShimmer 1.5s ease-in-out infinite;
}

/* The phone-only "Filters (n)" button, the sheet's close and its mask (doubled class: AntD's .ant-btn sets display) */
.cf__toolbar .cf__filters-btn,
.cf__sheet-close,
.cf__mask {
    display: none;
}

/* ≤ 767px: the sidebar leaves the row; "Filters (n)" opens it as a bottom sheet from 10vh over the mask */
@media (max-width: 767.98px) {
    .cf {
        grid-template-columns: minmax(0, 1fr);
    }

    .cf__toolbar .cf__filters-btn {
        display: inline-flex;
    }

    .cf.is-sheet-open .cf__sheet-close {
        display: inline-grid;
    }

    .cf__side {
        display: none;
    }

    .cf.is-sheet-open .cf__side {
        position: fixed;
        z-index: 1010;
        inset: 10vh 0 0;
        display: flex;
        max-height: none;
        border-bottom: 0;
        border-radius: var(--radius-lg) var(--radius-lg) 0 0;
        box-shadow: var(--shadow-float);
    }

    .cf.is-sheet-open .cf__mask {
        position: fixed;
        z-index: 1009;
        inset: 0;
        display: block;
        background: var(--color-mask);
    }

    .cf__ctl > .ant-select,
    .cf__ctl > .ant-picker {
        flex: 1 1 0;
        min-width: 0;
    }

    .cf__ctl {
        flex: 1 1 100%;
    }
}

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

/* ≤ 480px: the I-012 44px touch target for the finder's hand-built controls (the AntD lift does not reach them) */
@media (max-width: 480px) {
    .ff__row,
    .cf__chips .tag.tag--btn,
    .cf__link {
        min-height: 44px;
    }

    .cf__sheet-close.icon-btn,
    .sel__row .icon-btn {
        width: 44px;
        height: 44px;
    }
}

/* --- Filter facets: a titled group of checkbox / radio rows (F .fgroup) --- */
.ff {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 12px 14px;
    border-bottom: 1px solid var(--glass-border);
}

.ff:last-child {
    border-bottom: 0;
}

.ff__title {
    margin: 0;
    font-size: 13px;
    font-weight: 600;
    line-height: 1.3;
    color: var(--text-primary);
}

.ff__sub {
    margin: -4px 0 0;
    font: 400 11px var(--font-mono);
    color: var(--text-muted);
}

.ff__list {
    display: flex;
    flex-direction: column;
    gap: 1px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.ff__row {
    position: relative;
    display: flex;
    align-items: center;
    gap: 8px;
    min-height: 28px;
    color: var(--text-primary);
    font-size: 13px;
    line-height: 1.3;
    cursor: pointer;
}

.ff__row--sub {
    padding-left: 24px;
}

.ff__row.is-disabled {
    color: var(--text-muted);
    cursor: not-allowed;
}

/* The native input stays in the row for the keyboard and screen readers; the box draws it */
.ff__input {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: 0;
    opacity: 0;
    pointer-events: none;
}

.ff__box {
    flex: none;
    position: relative;
    width: 16px;
    height: 16px;
    border: 1.5px solid var(--glass-border-light);
    border-radius: 4px;
    background: var(--glass-bg);
}

.ff__row--radio .ff__box {
    border-radius: 50%;
}

.ff__row:hover .ff__box {
    border-color: var(--text-secondary);
}

/* Checked: the neutral --text fill (orange stays "mine") with a tick / dot in the panel ground */
.ff__input:checked + .ff__box {
    border-color: var(--text-primary);
    background: var(--text-primary);
}

.ff__input:checked + .ff__box::after {
    content: "";
    position: absolute;
    left: 4px;
    top: 1px;
    width: 5px;
    height: 9px;
    border: solid var(--glass-bg);
    border-width: 0 2px 2px 0;
    transform: rotate(45deg);
}

.ff__row--radio .ff__input:checked + .ff__box::after {
    left: 3.5px;
    top: 3.5px;
    width: 6px;
    height: 6px;
    border: 0;
    border-radius: 50%;
    background: var(--glass-bg);
    transform: none;
}

.ff__input:focus-visible + .ff__box {
    box-shadow: 0 0 0 2px var(--color-focus-ring);
}

.ff__input:disabled + .ff__box {
    background: var(--glass-bg-subtle);
    border-color: var(--glass-border);
}

.ff__label {
    flex: 1;
    min-width: 0;
}

.ff__more {
    align-self: flex-start;
    margin-top: 2px;
}

.ff__help {
    margin: 0;
    font-size: 12px;
    line-height: 1.4;
    color: var(--text-muted);
}

/* --- Rich hotel card: the I-032 .hotel-card with a 44px initials avatar, two-line name and the stars / score / price / tags lines --- */
.hotel-card.hotel-card--rich {
    align-items: flex-start;
    gap: 12px;
    padding: 10px 12px 10px 10px;
}

.hotel-card--rich .hotel-card__photo {
    width: 44px;
    height: 44px;
    border-radius: var(--radius-md);
    font-size: 13px;
}

.hotel-card--rich .hotel-card__body {
    gap: 3px;
}

.hotel-card--rich .hotel-card__name {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    font-size: 14px;
    white-space: normal;
}

.hotel-card--rich .hotel-card__check {
    margin-top: 2px;
}

.hotel-card__line {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 2px 6px;
    font-size: 12px;
    color: var(--text-secondary);
}

.hotel-card__stars {
    letter-spacing: 0.04em;
    color: var(--text-secondary);
}

/* The review score: a neutral mono badge (not Booking's blue, not orange) */
.hotel-card__score {
    display: inline-grid;
    place-items: center;
    min-width: 28px;
    height: 20px;
    padding: 0 5px;
    border-radius: var(--radius-sm);
    background: var(--text-primary);
    color: var(--glass-bg);
    font: 600 11.5px/1 var(--font-mono);
}

/* F v9 .hcard__line--price: the amount 600 14px mono in the text colour, "1 night · <date>" 11px muted */
.hotel-card__price {
    font: 400 11px var(--font-mono);
    color: var(--text-muted);
}

.hotel-card__price b {
    font-size: 14px;
    font-weight: 600;
    color: var(--text-primary);
}

.hotel-card__tags {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    margin-top: 3px;
}

.hotel-card__tags .tag {
    height: 20px;
    padding: 0 6px;
    font-size: 11px;
}

/* The reason wraps in a narrow column so the body keeps its width */
.hotel-card--rich .hotel-card__reason {
    align-self: flex-start;
    max-width: 64px;
    margin-top: 2px;
    text-align: right;
    white-space: normal;
}

/* --- Selected list: "Selected (n)" and a grid of removable rows (F v9 cfSelected .selc: a --panel-2 box with a
   ruled head) --- */
.sel {
    display: flex;
    flex-direction: column;
    min-width: 0;
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-lg);
    background: var(--glass-bg-light);
}

.sel__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 9px 14px;
    border-bottom: 1px solid var(--glass-border);
}

.sel__title {
    margin: 0;
    font-size: var(--type-block-title);
    font-weight: 600;
    line-height: 1.3;
    color: var(--text-primary);
}

.sel__title .sel__n {
    font-family: var(--font-mono);
    font-weight: 500;
    color: var(--text-secondary);
}

.sel__grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(250px, 100%), 1fr));
    gap: 2px 8px;
    margin: 0;
    padding: 6px;
    list-style: none;
}

.sel__row {
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
    min-height: 42px;
    padding: 4px 4px 4px 6px;
    border: 1px solid var(--glass-border);
    border-radius: 10px;
    background: var(--glass-bg);
}

.sel__body {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    line-height: 1.3;
}

.sel__name {
    overflow: hidden;
    font-size: 13px;
    font-weight: 600;
    color: var(--text-primary);
    white-space: nowrap;
    text-overflow: ellipsis;
}

.sel__meta {
    overflow: hidden;
    font: 400 11px var(--font-mono);
    color: var(--text-muted);
    white-space: nowrap;
    text-overflow: ellipsis;
}

.sel__row .icon-btn {
    width: 28px;
    height: 28px;
    font-size: 13px;
}

.sel__empty {
    margin: 0;
    padding: 12px 14px;
    font-size: 13px;
    color: var(--text-muted);
}

/* -----------------------------------------------------------------------------------------------------
   Season picker (CF-016) — prototype F v12 "Season & guests (settings) and onboarding season question" (f.html
   seasonField / mdPicker / guestBlock): the open-from / open-until range of day + month Selects and the guest-country
   rows. AntD components only; tokens only. A sub-block of the last block, not a new banner block (the block-order
   contracts in tests/scripts/app-css-*.test.js pin the banners). Showcase: /design-system#season-picker.
   ----------------------------------------------------------------------------------------------------- */
.season-range {
    display: flex;
    flex-wrap: wrap;
    gap: 12px 20px;
    margin-top: 10px;
}

/* F .mdpick — a repeating day + month: day 72px, month 96px. The widths sit on wrapper spans (F .selwrap): an AntD
   Select writes an inline width: 100% on its root, so it fills its wrapper */
.mdpick {
    display: inline-flex;
    gap: 6px;
}

.mdpick__d {
    width: 72px;
}

.mdpick__m {
    width: 96px;
}

/* F .chips--inherit / .tag--inherit — the market's guest countries, shown greyed until the owner overrides them */
.chips--inherit {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

.chips--inherit .tag--inherit {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin: 0;
    opacity: 0.85;
}

.tag--inherit b {
    font-weight: 600;
}

/* F .guest-rows / .guest-row — the override: country, optional months, remove */
.guest-rows {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.guest-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 12px;
}

.guest-row__cc {
    width: 220px;
    max-width: 100%;
}

.guest-row__m {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    min-width: 0;
    max-width: 100%;
}

/* The month pair shrinks with a phone-width row instead of spilling past it */
.guest-row__mo {
    width: 128px;
    max-width: calc(50% - 14px);
}

.guest-acts {
    display: flex;
    align-items: center;
    gap: 14px;
    margin-top: 8px;
}

/* =====================================================================================================
   Rate suggestions v2 (CF-017) — prototype F v13 (f.html "v13 — Rate suggestions v2", L939-1001) on the App tokens:
   the confidence chip (.conf on the Shell's .tag), the Low suggestion (.rec--low, .note--low), the drawer's "Why this
   price" (.why__*, table.tbl-f.tbl-f--why), the competitor weight (.wbar, .crow--w / .crow__w, the Popover
   OverlayClassName .wopts-pop with .wopts / .wopt), the learned position (.tiles--2, .learned__sum,
   table.tbl-f.tbl-f--learned) and the hostel type warning (.crow__warn, .hcard__warn) with the info hint
   .fi__help--hint. Renames: F .tbl--why → .tbl-f--why, .tbl--learned → .tbl-f--learned, .popc--w → .wopts-pop, F .lab →
   .core-eyebrow, F .ic → .anticon. F tokens: --ok = --color-success, --warn / --warn-bg = --color-warning /
   --color-warning-bg, --info = --color-info, --text-2 = --text-secondary, --muted = --text-muted, --line / --line-2 =
   --glass-border / --glass-border-light, --panel / --panel-2 = --glass-bg / --glass-bg-light, --r-sm = --radius-md.
   Orange only for the owner's own choice (the selected .wopt, a weight "Set by you", the suggested total) and the bar.
   The calendar's .rec-low / .rec-dot sit beside .dgrid__rec--up / --down in the Data grid block.
   ===================================================================================================== */

/* F .conf — a .tag with a leading dot: High success, Medium neutral, Low warning */
.conf__dot {
    flex: none;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: currentColor;
}

.conf--high {
    border-color: color-mix(in srgb, var(--color-success) 40%, transparent);
    background: color-mix(in srgb, var(--color-success) 10%, var(--glass-bg));
    color: var(--color-success);
}

.conf--medium {
    color: var(--text-secondary);
}

.conf--low {
    border-color: color-mix(in srgb, var(--color-warning) 45%, transparent);
    background: var(--color-warning-bg);
    color: var(--color-warning);
}

/* F .rec--low — a Low suggestion's price is muted */
.rec--low .rec__price {
    color: var(--text-muted);
}

/* F .note--low — the Low-confidence warning line under the suggestion */
.note--low {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    margin: 0 16px 6px;
    padding: 10px 12px;
    border-radius: var(--radius-md);
    background: var(--color-warning-bg);
    font-size: 13px;
    color: var(--text-primary);
}

/* overrides.css greys every drawer paragraph (.ant-drawer-body p, !important); the note keeps F's primary text there */
.ant-drawer-body p.note--low {
    color: var(--text-primary) !important;
}

.note--low > .anticon {
    flex: none;
    margin-top: 3px;
    color: var(--color-warning);
}

/* F .why__bar / .why__body / .why__h — the "Why this price" toggle and the explanation under it */
.why__bar {
    display: flex;
    padding: 0 10px 10px;
}

.why__body {
    padding: 4px 16px 16px;
    border-top: 1px solid var(--glass-border);
}

.why__h {
    margin: 14px 0 8px;
    font: 600 11px var(--font-mono);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-muted);
}

/* F ol.why — the steps: label + detail, the % and the value right-aligned in fixed columns */
.why {
    margin: 0;
    padding: 0;
    list-style: none;
}

.why__row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 56px 76px;
    align-items: baseline;
    gap: 10px;
    padding: 8px 0;
    border-top: 1px dashed var(--glass-border);
}

.why__row:first-child {
    border-top: 0;
}

.why__t {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.why__t b {
    font-size: 13px;
    font-weight: 600;
    color: var(--text-primary);
}

.why__t span {
    font-size: 12px;
    color: var(--text-secondary);
}

.why__pct {
    font: 500 12px var(--font-mono);
    text-align: right;
}

.why__pct--up {
    color: var(--rate-opportunity-text);
}

.why__pct--down {
    color: var(--color-info);
}

.why__v {
    font: 600 13px var(--font-mono);
    font-variant-numeric: tabular-nums;
    text-align: right;
    color: var(--text-primary);
}

.why__row--total {
    border-top: 1px solid var(--glass-border-light);
}

.why__row--total .why__v {
    font-size: 15px;
    color: var(--color-primary-text);
}

.why__more {
    margin: 6px 0 0;
    font-size: 12.5px;
}

/* F .tbl--why — the competitors in this suggestion: compact rows, the left-out ones muted */
table.tbl-f.tbl-f--why {
    min-width: 0;
}

table.tbl-f.tbl-f--why tbody td,
table.tbl-f.tbl-f--why thead th {
    padding-top: 6px;
    padding-bottom: 6px;
}

table.tbl-f.tbl-f--why tr.is-out td {
    color: var(--text-muted);
}

/* F .why__conf / .why__log / .why__notes — reasons (check / warning), today's changes, notes (info) */
.why__conf,
.why__log,
.why__notes {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin: 0;
    padding: 0;
    list-style: none;
    font-size: 12.5px;
    color: var(--text-secondary);
}

.why__conf li,
.why__notes li {
    display: flex;
    align-items: flex-start;
    gap: 8px;
}

.why__conf .anticon,
.why__notes .anticon {
    flex: none;
    margin-top: 3px;
}

.why__conf .is-ok .anticon {
    color: var(--color-success);
}

.why__conf .is-bad .anticon {
    color: var(--color-warning);
}

.why__notes .anticon {
    color: var(--color-info);
}

.why__log li {
    display: grid;
    grid-template-columns: 46px 110px minmax(0, 1fr);
    gap: 8px;
}

.why__log li > time,
.why__log li > :nth-child(2) {
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
}

/* F .wbar — the weight: a 56px track filled to the effective weight, the word, Auto or "Set by you" */
.wbar {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    white-space: nowrap;
}

.wbar__track {
    width: 56px;
    height: 6px;
    overflow: hidden;
    border-radius: 3px;
    background: var(--glass-border);
}

.wbar__track i {
    display: block;
    height: 100%;
    border-radius: 3px;
    background: var(--color-primary);
}

.wbar__w {
    min-width: 46px;
    font: 500 12px var(--font-mono);
    color: var(--text-primary);
}

.wbar__src {
    font: 400 11px var(--font-mono);
    color: var(--text-muted);
}

.wbar__src.is-man {
    color: var(--color-primary-text);
}

/* F .crow.crow--w — a comp-set row with the weight cell: avatar, name, weight, freshness, Remove (no price column, D-k).
   F's 270px weight column gives way before the name drops under 140px; the bar's source then wraps under the bar. */
.crow.crow--comp.crow--w {
    grid-template-columns: 32px minmax(140px, 1fr) minmax(0, 270px) 180px auto;
}

.crow__w {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    min-width: 0;
}

.crow__wt {
    display: flex;
    flex-direction: column;
    gap: 3px;
    min-width: 0;
}

.crow__wt .core-eyebrow {
    margin: 0;
    font-size: 9.5px;
}

.crow__wt .wbar {
    flex-wrap: wrap;
    row-gap: 2px;
}

/* The "Change" text button is F's .btn--sm, as the row's Remove */
.crow__w .ant-btn {
    height: 28px;
    padding-inline: 10px;
    font-size: 13px;
}

/* F .crow.is-off — a Price only competitor stays listed, muted */
.crow.is-off .crow__n,
.crow.is-off .wbar__w {
    color: var(--text-muted);
}

/* F .popc--w — the weight popover (AntD Popover OverlayClassName="wopts-pop") and its radio list */
.wopts-pop {
    width: min(340px, calc(100vw - 32px));
    max-width: none;
}

.wopts {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.wopt {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    width: 100%;
    padding: 8px;
    border: 1px solid transparent;
    border-radius: var(--radius-md);
    background: none;
    color: var(--text-primary);
    font: inherit;
    text-align: left;
    cursor: pointer;
}

.wopt:hover {
    background: var(--glass-bg-light);
}

.wopt:focus-visible {
    outline: none;
    box-shadow: 0 0 0 2px var(--color-focus-ring);
}

.wopt.is-on {
    border-color: var(--color-primary-line);
    background: var(--color-primary-bg);
}

.wopt__r {
    flex: none;
    width: 14px;
    height: 14px;
    margin-top: 2px;
    border: 1.5px solid var(--glass-border-light);
    border-radius: 50%;
}

.wopt.is-on .wopt__r {
    border: 4px solid var(--color-primary);
}

.wopt__t {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.wopt__t b {
    font-size: 13px;
    font-weight: 600;
}

.wopt__t span {
    font-size: 12px;
    color: var(--text-secondary);
}

/* F .pop__acts — Cancel under the list */
.wopts__acts {
    display: flex;
    justify-content: flex-end;
    margin-top: 8px;
}

/* F .crow__warn / .hcard__warn — the hostel ↔ non-hostel line under a name, wrapping, in the warning colour */
.crow__warn,
.hcard__warn {
    display: inline-flex;
    align-items: flex-start;
    gap: 5px;
    margin-top: 3px;
    font-size: 11.5px;
    line-height: 1.35;
    white-space: normal;
    color: var(--color-warning);
}

.crow__warn > .anticon,
.hcard__warn > .anticon {
    flex: none;
    margin-top: 1px;
}

/* F .tiles--2 — the two "How we suggest" tiles */
.tiles.tiles--2 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
}

.tile__t > .tag {
    margin-left: 6px;
    vertical-align: 1px;
}

/* F .learned__sum / .tbl--learned — where the owner usually sits: lead × weekdays / weekends, a thin cell faded */
.learned__sum {
    margin: 0;
    font-size: 13px;
    color: var(--text-secondary);
}

table.tbl-f.tbl-f--learned {
    min-width: 0;
}

table.tbl-f.tbl-f--learned td {
    text-align: right;
}

/* F th.l: the Booked ahead label reads left — the generic tbody th[scope=row] rule outranks table.tbl-f .l */
table.tbl-f.tbl-f--learned tbody th[scope="row"] {
    text-align: left;
}

table.tbl-f.tbl-f--learned td b {
    font: 600 13px var(--font-mono);
}

table.tbl-f.tbl-f--learned td b.is-down {
    color: var(--color-info);
}

table.tbl-f.tbl-f--learned td b.is-up {
    color: var(--rate-opportunity-text);
}

table.tbl-f.tbl-f--learned td small {
    display: block;
    font: 400 11px var(--font-mono);
    color: var(--text-muted);
}

table.tbl-f.tbl-f--learned td.is-thin b {
    opacity: 0.6;
}

/* F .fi__help--hint — an info line with its icon (learned position, the hostel Guests hint) */
.fi__help.fi__help--hint {
    display: flex;
    align-items: center;
    gap: 6px;
    margin: 4px 0 0;
    color: var(--color-info);
}

.fi__help--hint > .anticon {
    flex: none;
}

/* CF-018 — F v14 "Suggestion engine layer 2" (f.html "v14 — Suggestion engine layer 2"): the left-out competitor row, the
   competitor behaviour line and its Reprices often chip, the unusual-demand drawer tag and the two layer-2 notes. The
   Market pressure / Far-out prior steps are plain .why__row. F tokens as above; --info-bg = --color-info-bg; F's
   color-mix() tag edges = the .tag--warn / .tag--info borders (--position-above-border / --position-below-border).
   The calendar markers (.ud-mark, .mc__marks, .mc__ud) sit beside .hd-dot and .mc__ev. */

/* F .tbl--why tr.is-out s — a left-out competitor's price, struck through */
table.tbl-f.tbl-f--why tr.is-out td s {
    text-decoration-thickness: 1px;
}

/* F .why-out — why a competitor was left out (anomaly D80 / product switch D78): warning icon + wrapping line */
.why-out {
    display: flex;
    align-items: center;
    gap: 4px;
    margin-top: 2px;
    font-size: 11.5px;
    line-height: 1.35;
    white-space: normal;
    color: var(--color-warning);
}

.why-out .anticon {
    flex: none;
}

table.tbl-f.tbl-f--why tr.is-out td .why-out {
    color: var(--color-warning);
}

/* F .comp-beh — how often a competitor reprices · how fast it follows the market, under its name; italic when unknown */
.comp-beh {
    display: block;
    margin-top: 2px;
    font-size: 11.5px;
    font-weight: 400;
    line-height: 1.35;
    white-space: normal;
    color: var(--text-muted);
}

.comp-beh--none {
    font-style: italic;
}

table.tbl-f.tbl-f--why .comp-beh {
    max-width: 36ch;
}

/* F .tag--fast — "Reprices often": the amber chip that replaces the line for a competitor repricing several times a day */
.tag--fast {
    border-color: var(--position-above-border);
    background: var(--color-warning-bg);
    color: var(--color-warning);
}

.comp-beh .tag--fast {
    height: 20px;
    margin-top: 2px;
    font-size: 11px;
}

/* F .tag--ud — the drawer header's "Unusual demand" tag: the info family, never the amber High demand tag */
.tag--ud {
    border-color: var(--position-below-border);
    background: var(--color-info-bg);
    color: var(--color-info);
}

/* F .why__notes .is-ud / .is-early — the unusual-demand note (info rising arrow) and the early sell-out note (success check) */
.why__notes .is-ud .anticon {
    color: var(--color-info);
}

.why__notes .is-early .anticon {
    color: var(--color-success);
}

/* F 1202: the two tiles stack in a narrow form column, as the strategy tiles */
@container form (max-width: 560px) {
    .tiles.tiles--2 {
        grid-template-columns: minmax(0, 1fr);
    }
}

/* F 1460-1476 (page <= 600, App 820 where the comp row drops its columns): the weight cell wraps under the name */
@container page (max-width: 820px) {
    .crow.crow--comp.crow--w {
        grid-template-columns: 32px minmax(0, 1fr) auto;
    }

    .crow--comp.crow--w > .hotel-avatar {
        grid-row: 1 / span 3;
    }

    .crow--comp.crow--w > .crow__w {
        grid-column: 2;
        grid-row: 3;
        flex-wrap: wrap;
        justify-content: flex-start;
    }

    .crow--comp.crow--w > .row-acts {
        grid-row: 1 / span 3;
    }
}

/* Below 520px (a phone, the drawer full width): the steps keep three narrower columns, a change's cause wraps under it */
@media (max-width: 520px) {
    .why__row {
        grid-template-columns: minmax(0, 1fr) 44px 64px;
        gap: 6px;
    }

    .why__log li {
        grid-template-columns: 40px minmax(0, 1fr);
    }

    .why__log li > :last-child {
        grid-column: 1 / -1;
    }
}
