/* ==========================================================================
   PACETOWIN DESIGN SYSTEM — single source of truth (Phase 2, Task 2.1)
   ==========================================================================
   Loaded FIRST by every page (homepage, league hubs, team pages), before any
   page-specific stylesheet. Spec: docs/pacetowin-brand-2026-report.md and
   docs/plans/p2-migration-spec.md (the migration guide for Tasks 2.2/2.4).

   Rules of the system:
   - Dark-first. `:root` is the dark Ink theme; `:root[data-theme="light"]`
     is the polished light secondary.
   - Orange = action. Cyan = live-data / focus / link. NEVER both in one
     gradient. Default gradients are retired.
   - Flat-with-depth elevation: 1px border + inner top highlight + soft
     ambient shadow. No blur-glass, no backdrop-filter.
   - Spacing on the 4px grid. Radius 8/12/16/24/pill.
   - NO `!important` in this file, ever. Components are single-class
     selectors (specificity 0,1,0) so page sheets can override cleanly.
   - `--btn-primary-*` and `.btn-primary` are FIXED brand orange with dark
     ink text (AA ~6:1). They are not redefined by the light theme or by
     team theming (`--team-*`), so the CTA is legible on every page.
   ========================================================================== */

/* --------------------------------------------------------------------------
   0. FONT FACES — self-hosted, no CDN (CSP/offline). Task 2.3.
      - Clash Display (Fontshare, OFL): wordmark / hero titles / big numerals.
        Static weights 600/700 (Fontshare doesn't offer a variable woff2).
      - Geist (Vercel, OFL): UI/body. Variable woff2, weight range 100-900.
      - Geist Mono (Vercel, OFL): tabular/numeric. Variable woff2, 100-900.
   -------------------------------------------------------------------------- */
@font-face {
    font-family: 'Clash Display';
    src: url('/fonts/clash-display-600.woff2') format('woff2');
    font-weight: 600;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: 'Clash Display';
    src: url('/fonts/clash-display-700.woff2') format('woff2');
    font-weight: 700;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: 'Geist';
    src: url('/fonts/geist-sans-variable.woff2') format('woff2');
    font-weight: 100 900;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: 'Geist Mono';
    src: url('/fonts/geist-mono-variable.woff2') format('woff2');
    font-weight: 100 900;
    font-style: normal;
    font-display: swap;
}

/* --------------------------------------------------------------------------
   1. PRIMITIVES — raw palette + fixed scales. Never themed, never used
      directly in components (semantic tokens below reference them).
   -------------------------------------------------------------------------- */
:root {
    /* Ink scale (dark surfaces) */
    --ink-950: #0A0E14;
    --ink-900: #0F141C;
    --ink-800: #161C26;
    --ink-700: #1F2733;
    --ink-600: #2A3340;
    --ink-500: #3A4553;

    /* Ink text ramp (on dark) */
    --ink-text-hi:  #F4F6F8;
    --ink-text-mid: #A6B0BE;
    --ink-text-low: #6B7686;

    /* Brand pace ramp */
    --pace-400: #FF8A4C;   /* orange as TEXT on dark (AA) */
    --pace-500: #FB7328;   /* orange fills / CTA */
    --pace-600: #E85D04;   /* fill hover / pressed */

    /* Cyan — live-data / focus / link ONLY */
    --cyan-400: #22D3EE;
    --cyan-700: #0E7490;   /* AA cyan for text/links on light backgrounds */

    /* Semantic hues (dark-tuned) */
    --green-400: #34D399;
    --rose-400:  #FB7185;
    --amber-400: #FBBF24;

    /* Violet — the Pythagorean "expected wins" (point-differential) secondary
       projection ONLY. Deliberately a third hue (not orange/cyan) so the
       pace-vs-expected distinction never relies on dash pattern alone. */
    --violet-400: #A78BFA;   /* AA on dark surfaces (~6.3:1) */
    --violet-600: #7C3AED;   /* AA on light/white surfaces (~5.7:1) */

    /* Fixed primary-CTA pair — identical in both themes, team-theme-proof */
    --btn-primary-bg: var(--pace-500);
    --btn-primary-hover-bg: var(--pace-600);
    --btn-primary-fg: var(--ink-950);
    /* Ink text used on ANY bright fill (pace bars, meters, badges) */
    --on-accent: var(--ink-950);

    /* Typography (Task 2.3 — self-hosted, no CDN) */
    --font-display: 'Clash Display', 'Arial Black', 'Helvetica Neue', Arial, sans-serif;
    --font-body: 'Geist', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    --font-mono: 'Geist Mono', 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace;
    --font-numeric: var(--font-mono);          /* numbers: always tabular */

    /* Type scale */
    --text-xs:  0.75rem;
    --text-sm:  0.875rem;   /* when uppercase, pair with +.06em tracking */
    --text-base: 1rem;
    --text-lg:  1.125rem;
    --text-xl:  1.25rem;
    --text-2xl: 1.5rem;
    --text-3xl: 2rem;
    --text-4xl: 2.5rem;
    --text-5xl: 3rem;
    --fs-display:  clamp(2rem, 5vw, 3rem);
    --fs-hero-num: clamp(3rem, 8vw, 5.5rem);

    /* Spacing — 4px grid: 4 8 12 16 24 32 48 64 96 */
    --space-1:  0.25rem;   /*  4px */
    --space-2:  0.5rem;    /*  8px */
    --space-3:  0.75rem;   /* 12px */
    --space-4:  1rem;      /* 16px */
    --space-6:  1.5rem;    /* 24px */
    --space-8:  2rem;      /* 32px */
    --space-12: 3rem;      /* 48px */
    --space-16: 4rem;      /* 64px */
    --space-24: 6rem;      /* 96px */

    /* Radius — 8 / 12 / 16 / 24 / pill */
    --radius-sm:   8px;
    --radius-md:   12px;
    --radius-lg:   16px;
    --radius-xl:   24px;
    --radius-pill: 9999px;

    /* Motion — 120 / 200 / 320ms, one easing */
    --motion-fast: 120ms;
    --motion-base: 200ms;
    --motion-slow: 320ms;
    --ease: cubic-bezier(0.2, 0.8, 0.2, 1);

    /* League identity colors (data, not theme) */
    --nfl-primary: #013369;  --nfl-accent: #d50a0a;
    --nba-primary: #17408b;  --nba-accent: #c9082a;
    --mlb-primary: #002d72;  --mlb-accent: #d50032;
    --nhl-primary: #111111;  --nhl-accent: #faaf19;
}

/* --------------------------------------------------------------------------
   2. SEMANTIC TOKENS — dark (default). This is the CANONICAL vocabulary;
      everything in components and page CSS uses these names.
   -------------------------------------------------------------------------- */
:root {
    color-scheme: dark;

    /* Surfaces */
    --bg-page:        var(--ink-950);  /* page background */
    --bg-sunken:      var(--ink-900);  /* wells, segmented track, hero wash */
    --surface:        var(--ink-800);  /* cards, panels, dropdowns */
    --surface-raised: var(--ink-700);  /* hover state, inputs, raised chips */
    --border:         var(--ink-600);
    --border-strong:  var(--ink-500);

    /* Text */
    --text-primary:   var(--ink-text-hi);
    --text-secondary: var(--ink-text-mid);
    --text-tertiary:  var(--ink-text-low);

    /* Accent roles */
    --accent:        var(--pace-500);  /* orange FILLS (bars, badges, CTA) */
    --accent-hover:  var(--pace-600);
    --accent-text:   var(--pace-400);  /* orange as TEXT — AA on this theme */
    --live:          var(--cyan-400);  /* live-data values, active nav */
    --link:          var(--cyan-400);
    --expected:      var(--violet-400); /* Pythagorean expected-wins projection ONLY */

    /* Status */
    --positive: var(--green-400);
    --negative: var(--rose-400);
    --warning:  var(--amber-400);
    --info:     var(--cyan-400);

    /* Focus (cyan, always) */
    --focus-ring-color: rgba(34, 211, 238, 0.55);
    --focus-ring: 0 0 0 3px var(--focus-ring-color);

    /* Elevation — flat-with-depth: inner top highlight + soft ambient.
       The 1px border comes from the component (`border: 1px solid var(--border)`). */
    --elev-highlight: rgba(255, 255, 255, 0.045);
    --elev-1: inset 0 1px 0 var(--elev-highlight), 0 1px 2px rgba(0, 0, 0, 0.35);
    --elev-2: inset 0 1px 0 var(--elev-highlight), 0 6px 16px rgba(0, 0, 0, 0.35);
    --elev-3: inset 0 1px 0 var(--elev-highlight), 0 16px 40px rgba(0, 0, 0, 0.45);
}

/* --------------------------------------------------------------------------
   3. SEMANTIC TOKENS — light secondary. Only re-points the themed roles;
      primitives and the fixed CTA pair are untouched.
   -------------------------------------------------------------------------- */
:root[data-theme="light"] {
    color-scheme: light;

    --bg-page:        #ffffff;
    --bg-sunken:      #f8fafc;
    --surface:        #ffffff;
    --surface-raised: #f1f5f9;
    --border:         #e2e8f0;
    --border-strong:  #cbd5e1;

    --text-primary:   #0f172a;
    --text-secondary: #475569;
    --text-tertiary:  #64748b;

    --accent:        var(--pace-500);  /* brand fill stays brand */
    --accent-hover:  var(--pace-600);
    --accent-text:   #c2410c;          /* AA orange text on white */
    --live:          #0891b2;          /* AA-leaning cyan on light */
    --link:          var(--cyan-700);
    --expected:      var(--violet-600); /* AA violet on light/white */

    --positive: #16a34a;
    --negative: #e11d48;
    --warning:  #d97706;
    --info:     #0284c7;

    --focus-ring-color: rgba(8, 145, 178, 0.5);

    --elev-highlight: rgba(255, 255, 255, 0.7);
    --elev-1: inset 0 1px 0 var(--elev-highlight), 0 1px 2px rgba(15, 23, 42, 0.08);
    --elev-2: inset 0 1px 0 var(--elev-highlight), 0 6px 16px rgba(15, 23, 42, 0.1);
    --elev-3: inset 0 1px 0 var(--elev-highlight), 0 16px 40px rgba(15, 23, 42, 0.14);
}

/* --------------------------------------------------------------------------
   5. LAYOUT PRIMITIVES
   -------------------------------------------------------------------------- */
.wrap {
    max-width: 1400px;
    margin-inline: auto;
    padding-inline: var(--space-8);
}

.wrap--narrow { max-width: 600px; }

/* Stat-tile row: as many 150px+ columns as fit */
.stat-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: var(--space-4);
}

/* Form field row; set --cols per instance (default 2) */
.form-grid {
    display: grid;
    grid-template-columns: repeat(var(--cols, 2), minmax(0, 1fr));
    gap: var(--space-4);
}

.u-center { text-align: center; }

@media (max-width: 640px) {
    .wrap { padding-inline: var(--space-4); }
    .form-grid { grid-template-columns: 1fr; }
}

/* --------------------------------------------------------------------------
   6. BUTTONS
      .btn = base; .btn-primary = THE action (fixed brand orange, dark ink
      text, AA, immune to theme + team overrides); .btn-ghost = secondary.
   -------------------------------------------------------------------------- */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    min-height: 44px;                 /* WCAG 2.5.5 target */
    padding: var(--space-3) var(--space-6);
    border: 1px solid transparent;
    border-radius: var(--radius-md);
    font-family: var(--font-body);
    font-size: var(--text-base);
    font-weight: 600;
    line-height: 1.2;
    text-decoration: none;
    cursor: pointer;
    user-select: none;
    transition: background-color var(--motion-base) var(--ease),
                border-color var(--motion-base) var(--ease),
                color var(--motion-base) var(--ease),
                box-shadow var(--motion-base) var(--ease),
                transform var(--motion-base) var(--ease);
}

.btn:focus-visible {
    outline: none;
    box-shadow: var(--focus-ring);
}

.btn:disabled {
    cursor: not-allowed;
    opacity: 0.55;
    transform: none;
}

.btn--block { width: 100%; }
.btn--sm { min-height: 38px; padding: var(--space-2) var(--space-4); font-size: var(--text-sm); }

/* Cookie-consent banner (Consent Mode v2). Google Analytics stays denied until
   the visitor accepts; the choice persists in localStorage ('ptw-consent'). */
.cookie-banner {
    position: fixed;
    left: 0; right: 0; bottom: 0;
    z-index: 2000;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: var(--space-4);
    padding: var(--space-4) var(--space-5);
    background: var(--surface-raised);
    border-top: 1px solid var(--border);
    box-shadow: var(--elev-3);
}
.cookie-banner[hidden] { display: none; }
.cookie-banner__text {
    margin: 0;
    color: var(--text-secondary);
    font-size: var(--text-sm);
    max-width: 62ch;
}
.cookie-banner__actions { display: flex; gap: var(--space-2); flex-shrink: 0; }
.btn--pill  { border-radius: var(--radius-pill); }

.btn-primary {
    background: var(--btn-primary-bg);
    color: var(--btn-primary-fg);
    font-weight: 700;
}

.btn-primary:hover:not(:disabled) {
    background: var(--btn-primary-hover-bg);
    transform: translateY(-2px);      /* restrained lift, per motion spec */
    box-shadow: var(--elev-2);
}

.btn-primary:active:not(:disabled) { transform: translateY(0); }

.btn-primary:focus-visible {
    /* ring + offset so cyan reads against the orange fill */
    box-shadow: 0 0 0 2px var(--bg-page), 0 0 0 5px var(--focus-ring-color);
}

.btn-ghost {
    background: var(--bg-sunken);
    border-color: var(--border);
    color: var(--text-primary);
}

.btn-ghost:hover:not(:disabled) {
    background: var(--surface-raised);
    border-color: var(--border-strong);
    transform: translateY(-2px);
    box-shadow: var(--elev-1);
}

/* --------------------------------------------------------------------------
   7. CARD / SURFACE
   -------------------------------------------------------------------------- */
.card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: var(--space-6);
    box-shadow: var(--elev-1);
}

.card--sunken {
    background: var(--bg-sunken);
    box-shadow: none;
}

/* Interactive cards (links, team cards) get the lift */
.card--interactive {
    display: block;
    color: inherit;
    text-decoration: none;
    cursor: pointer;
    transition: transform var(--motion-base) var(--ease),
                box-shadow var(--motion-base) var(--ease),
                border-color var(--motion-base) var(--ease),
                background-color var(--motion-base) var(--ease);
}

.card--interactive:hover {
    background: var(--surface-raised);
    border-color: var(--live);
    transform: translateY(-2px);
    box-shadow: var(--elev-2);
}

.card--interactive:focus-visible {
    outline: none;
    box-shadow: var(--focus-ring);
}

.card__title {
    color: var(--text-primary);
    font-size: var(--text-xl);
    font-weight: 600;
    margin-bottom: var(--space-4);
}

/* Team card (hub grids): logo + name + record row */
.team-card {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-4);
}

.team-card__logo {
    width: 60px;
    height: 60px;
    flex: none;
    object-fit: contain;
    background: #ffffff;              /* logos are drawn for light chips */
    border-radius: var(--radius-sm);
    padding: var(--space-2);
}

.team-card__info {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.team-card__name {
    color: var(--text-primary);
    font-weight: 600;
    font-size: var(--text-base);
    line-height: 1.2;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.team-card__meta {
    color: var(--live);
    font-size: var(--text-sm);
    font-weight: 500;
}

.team-card__meta::after { content: " \2192"; }

.team-card:hover .team-card__meta { text-decoration: underline; }

/* Hub team-card grid — wider tracks than the stat grid so names fit (no truncation). */
.team-grid {
    display: grid;
    gap: var(--space-4);
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    margin: var(--space-6) 0;
}

/* --------------------------------------------------------------------------
   8. STAT TILE — the number cards ("Current Record", "Projected Wins", …).
      Replaces the generator's inline-styled divs. Numbers are tabular.
      Color roles: default ink text; --live for live-data values;
      --accent-text for the headline pace number. Never rely on color alone
      to signal above/below .500 — pair with a +/-/arrow glyph in markup.
   -------------------------------------------------------------------------- */
.stat-tile {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: var(--space-6) var(--space-4);
    box-shadow: var(--elev-1);
    text-align: center;
}

.stat-tile__value {
    font-family: var(--font-numeric);
    font-feature-settings: "tnum" 1;
    font-variant-numeric: tabular-nums;
    /* Geist Mono's tabular decimal point sits in a full digit-width cell,
       which reads as an oversized gap ("64 . 7%") at display sizes. A
       slightly negative tracking closes it up without breaking alignment
       between digits (Task 2.3 mono-decimal fix). */
    letter-spacing: -0.07em;
    font-size: var(--text-3xl);
    font-weight: 700;
    line-height: 1.15;
    color: var(--text-primary);
}

.stat-tile--live  .stat-tile__value { color: var(--live); }        /* live data */
.stat-tile--accent .stat-tile__value { color: var(--accent-text); } /* pace headline */
.stat-tile--team  .stat-tile__value { color: var(--team-accent-safe, var(--text-primary)); }
.stat-tile--expected .stat-tile__value { color: var(--expected); } /* Pythagorean expected wins */

.stat-tile__label {
    margin-top: var(--space-1);
    color: var(--text-secondary);
    font-size: var(--text-sm);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

/* Secondary caption under the label — e.g. "Point differential" on the
   Expected Wins tile, clarifying it's a distinct metric from pace. Uses
   --text-secondary (not --text-tertiary): at --text-xs this is "small text"
   per WCAG (needs 4.5:1), and --text-tertiary only clears ~3.7:1 on
   --surface in the dark theme. */
.stat-tile__sublabel {
    margin-top: 2px;
    color: var(--text-secondary);
    font-size: var(--text-xs);
    font-weight: 500;
}

.stat-tile__delta {
    display: inline-block;
    margin-top: var(--space-1);
    font-family: var(--font-numeric);
    font-feature-settings: "tnum" 1;
    letter-spacing: -0.03em;
    font-size: var(--text-sm);
    font-weight: 600;
}

.stat-tile__delta.is-pos { color: var(--positive); }
.stat-tile__delta.is-neg { color: var(--negative); }

/* Hero-sized variant for the single headline number */
.stat-tile--hero .stat-tile__value { font-size: var(--fs-hero-num); }

/* --------------------------------------------------------------------------
   9. PACE BAR — win% progress with semantic performance bands.
      Bands (solid fills, gradients retired):
        .is-band-hot   >= 70%  positive green
        .is-band-on    50-70%  brand orange (on pace)
        .is-band-cold  30-50%  amber warning
        .is-band-off   < 30%   negative rose
      JS sets width + ONE band class. Color is never the only signal — the
      % label rides inside (lg) or beside (slim) the bar.
   -------------------------------------------------------------------------- */
.pace-bar {
    position: relative;
    height: 14px;
    background: var(--bg-sunken);
    border: 1px solid var(--border);
    border-radius: var(--radius-pill);
    overflow: hidden;
}

.pace-bar__fill {
    height: 100%;
    width: 0;
    background: var(--accent);
    border-radius: var(--radius-pill);
    transition: width var(--motion-slow) var(--ease),
                background-color var(--motion-base) var(--ease);
}

.pace-bar__fill.is-band-hot  { background: var(--positive); }
.pace-bar__fill.is-band-on   { background: var(--accent); }
.pace-bar__fill.is-band-cold { background: var(--warning); }
.pace-bar__fill.is-band-off  { background: var(--negative); }

/* Large homepage variant: 40px tall, % label inside the fill */
.pace-bar--lg { height: 40px; }

.pace-bar--lg .pace-bar__fill {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    padding-right: var(--space-3);
    min-width: 50px;
    color: var(--on-accent);          /* dark ink on every band fill — AA */
    font-family: var(--font-numeric);
    font-feature-settings: "tnum" 1;
    letter-spacing: -0.04em;
    font-weight: 700;
    font-size: var(--text-lg);
}

.pace-bar__caption {
    color: var(--text-secondary);
    font-size: var(--text-sm);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    margin-bottom: var(--space-2);
}

/* --------------------------------------------------------------------------
   10. METER — PlayoffMeter-style gauge: track + fill + threshold tick.
       Fill color: cyan by default (it is live DATA, not an action); a team
       page may recolor via `--meter-color`. Threshold position via `--at`.
   -------------------------------------------------------------------------- */
.meter {
    position: relative;
    height: 10px;
    background: var(--bg-sunken);
    border: 1px solid var(--border);
    border-radius: var(--radius-pill);
}

.meter__fill {
    height: 100%;
    width: 0;
    background: var(--meter-color, var(--live));
    border-radius: var(--radius-pill);
    transition: width var(--motion-slow) var(--ease);
}

.meter__threshold {
    position: absolute;
    top: -4px;
    bottom: -4px;
    left: var(--at, 50%);
    width: 2px;
    background: var(--border-strong);
    border-radius: 1px;
}

.meter__labels {
    display: flex;
    justify-content: space-between;
    margin-top: var(--space-2);
    color: var(--text-tertiary);
    font-family: var(--font-numeric);
    font-feature-settings: "tnum" 1;
    font-size: var(--text-xs);
}

/* --------------------------------------------------------------------------
   11. SEGMENTED CONTROL — league picker / mode toggle (radiogroup).
   -------------------------------------------------------------------------- */
.segmented {
    position: relative;
    display: inline-flex;
    align-items: center;
    min-height: 48px;
    padding: var(--space-1);
    background: var(--bg-sunken);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
}

.segmented__option {
    position: relative;
    z-index: 2;
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 40px;
    padding: var(--space-3) var(--space-6);
    border: none;
    background: none;
    border-radius: var(--radius-sm);
    font-family: inherit;
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--text-secondary);
    white-space: nowrap;
    cursor: pointer;
    user-select: none;
    transition: color var(--motion-base) var(--ease);
}

.segmented__option:hover { color: var(--text-primary); }

.segmented__option.active,
.segmented__option[aria-checked="true"],
.segmented__option[aria-selected="true"] {
    color: var(--text-primary);
    font-weight: 700;
}

.segmented__option:focus-visible {
    outline: none;
    box-shadow: var(--focus-ring);
}

.segmented__thumb {
    position: absolute;
    z-index: 1;
    top: var(--space-1);
    left: var(--space-1);
    height: calc(100% - 8px);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    box-shadow: var(--elev-1);
    transition: transform var(--motion-slow) var(--ease),
                width var(--motion-slow) var(--ease),
                left var(--motion-slow) var(--ease);
}

/* --------------------------------------------------------------------------
   12. FORMS — field wrapper, label, input, select.
       Focus is CYAN (cyan = focus, per the brand rule).
   -------------------------------------------------------------------------- */
.field { margin-bottom: var(--space-6); }

.field__label {
    display: block;
    margin-bottom: var(--space-2);
    color: var(--text-secondary);
    font-size: var(--text-sm);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

.input {
    box-sizing: border-box; /* width:100% must INCLUDE padding+border, else the
                               field overflows its container on narrow screens */
    width: 100%;
    min-height: 48px;
    padding: var(--space-3) var(--space-4);
    background: var(--surface-raised);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    color: var(--text-primary);
    font-family: var(--font-body);
    font-size: var(--text-base);
    font-weight: 500;
    transition: border-color var(--motion-base) var(--ease),
                background-color var(--motion-base) var(--ease),
                box-shadow var(--motion-base) var(--ease);
}

.input::placeholder { color: var(--text-tertiary); }

.input:focus {
    outline: none;
    border-color: var(--live);
    box-shadow: var(--focus-ring);
}

.field__error {
    display: none;
    margin-top: var(--space-1);
    color: var(--negative);
    font-size: var(--text-sm);
}

/* --------------------------------------------------------------------------
   13. NAV / APP SHELL — sticky solid header (no blur-glass).
   -------------------------------------------------------------------------- */
.site-header {
    position: sticky;
    top: 0;
    z-index: 1000;
    background: var(--bg-page);
    border-bottom: 1px solid var(--border);
}

.site-nav {
    display: flex;
    align-items: center;
    justify-content: space-between;
    max-width: 1400px;
    margin-inline: auto;
    padding: var(--space-4) var(--space-8);
}

.site-nav__brand {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    text-decoration: none;
    color: var(--text-primary);
    font-family: var(--font-display);
    font-weight: 700;
    letter-spacing: 0.01em;
}

.site-nav__brand:focus-visible {
    outline: none;
    box-shadow: var(--focus-ring);
    border-radius: var(--radius-sm);
}

.site-nav__links {
    display: flex;
    gap: var(--space-8);
    list-style: none;
    margin: 0;
    padding: 0;
}

.site-nav__link {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    color: var(--text-secondary);
    text-decoration: none;
    font-weight: 500;
    transition: color var(--motion-fast) var(--ease);
}

.site-nav__link:hover { color: var(--text-primary); }
.site-nav__link.active { color: var(--live); }

.site-nav__link:focus-visible {
    outline: none;
    box-shadow: var(--focus-ring);
    border-radius: var(--radius-sm);
}

@media (max-width: 640px) {
    .site-nav {
        flex-direction: column;
        gap: var(--space-3);
        padding: var(--space-4);
    }
    .site-nav__links {
        flex-wrap: wrap;
        justify-content: center;
        gap: var(--space-4) var(--space-6);
        width: 100%;
    }
}

/* --------------------------------------------------------------------------
   14. HERO — hub/landing headline block. Solid ink, no gradient.
   -------------------------------------------------------------------------- */
.hero {
    padding: var(--space-16) var(--space-8);
    background: var(--bg-sunken);
    border-bottom: 1px solid var(--border);
    text-align: center;
}

.hero__title {
    margin: 0 0 var(--space-4);
    color: var(--text-primary);
    font-family: var(--font-display);
    font-size: var(--fs-display);
    font-weight: 700;
    line-height: 1.1;
}

.hero__desc {
    margin: 0;
    color: var(--text-secondary);
    font-size: var(--text-lg);
}

/* --------------------------------------------------------------------------
   15. TEAM BANNER — the restrained team-color treatment (report spec):
       fixed dark banner + 4px team-color top border + low-opacity radial
       glow behind the logo. Text always sits on ink — retires the gradient
       banner and its scrim/text-shadow hacks. Team pages provide
       `--team-primary` / `--team-accent-safe` on :root (Task 2.5 wires it).
   -------------------------------------------------------------------------- */
.team-banner {
    position: relative;
    overflow: hidden;
    padding: var(--space-12) var(--space-8);
    background: var(--bg-sunken);
    border-top: 4px solid var(--team-primary, var(--accent));
    border-bottom: 1px solid var(--border);
    text-align: center;
}

.team-banner::before {
    content: '';
    position: absolute;
    inset: 0;
    background: radial-gradient(
        560px 280px at 50% 0%,
        color-mix(in srgb, var(--team-primary, var(--accent)) 20%, transparent),
        transparent 72%
    );
    pointer-events: none;
}

.team-banner > * { position: relative; z-index: 1; }

.team-banner__logo {
    width: 120px;
    height: 120px;
    object-fit: contain;
    background: #ffffff;
    border-radius: var(--radius-lg);
    padding: var(--space-3);
    margin-bottom: var(--space-4);
    box-shadow: var(--elev-2);
}

.team-banner__title {
    margin: 0 0 var(--space-2);
    color: var(--text-primary);
    font-family: var(--font-display);
    font-size: var(--fs-display);
    font-weight: 700;
    line-height: 1.1;
}

.team-banner__subtitle {
    margin: 0;
    color: var(--text-secondary);
    font-size: var(--text-lg);
}

/* --------------------------------------------------------------------------
   16. MISC SHARED PIECES
   -------------------------------------------------------------------------- */
/* Inline callout / notice strip (data freshness, errors) */
.callout {
    padding: var(--space-3) var(--space-4);
    border: 1px solid var(--border);
    border-left: 4px solid var(--info);
    border-radius: var(--radius-sm);
    background: var(--surface);
    color: var(--text-primary);
    font-size: var(--text-sm);
}

.callout--success { border-left-color: var(--positive); }
.callout--warning { border-left-color: var(--warning); }
.callout--error   { border-left-color: var(--negative); }

/* Body-copy links (cyan = link) */
.link {
    color: var(--link);
    text-decoration: none;
}

.link:hover { text-decoration: underline; }

.link:focus-visible {
    outline: none;
    box-shadow: var(--focus-ring);
    border-radius: var(--radius-sm);
}

/* Numeric text anywhere outside a stat tile */
.num {
    font-family: var(--font-numeric);
    font-feature-settings: "tnum" 1;
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.03em;
}

/* --------------------------------------------------------------------------
   17. REDUCED MOTION — settle instantly; the count-up JS checks this media
       query itself. (No !important: this file's own transitions all use
       the motion tokens, so zeroing durations here wins by source order for
       design-system components; legacy sheets keep their own guards until
       they are merged in Task 2.2.)
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
    :root {
        --motion-fast: 0.01ms;
        --motion-base: 0.01ms;
        --motion-slow: 0.01ms;
    }
}

/* --------------------------------------------------------------------------
   18. SEASON OUTLOOK VIZ — team-page data-visualization suite (Task 3.1).
       Pace Trajectory chart (hand-rolled SVG line chart), Playoff Pace meter
       (an honest wins/points-vs-threshold comparison — never phrased as a
       probability), and a Season Progress ring. All three are built by
       `renderViz()` in the team-page script (tools/build-pages.php) so they
       refresh on both the live ESPN fetch and the manual Calculate path.
       Draw-in transitions ride the shared --motion-slow token, so they
       collapse to ~instant automatically under prefers-reduced-motion
       (section 17) — no separate JS branch needed for the CSS-driven ones.
   -------------------------------------------------------------------------- */
.outlook-grid {
    display: grid;
    grid-template-columns: 2fr 1fr;
    gap: var(--space-6);
    align-items: start;
}

@media (max-width: 900px) {
    .outlook-grid { grid-template-columns: 1fr; }
}

.outlook-chart__caption,
.outlook-meter__caption {
    color: var(--text-secondary);
    font-size: var(--text-sm);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    margin-bottom: var(--space-2);
}

.pace-chart {
    display: block;
    width: 100%;
    /* Capped so the chart doesn't grow past ~1:1 scale on wide columns
       (e.g. the single-column tablet layout below); SVG text scales with
       the viewBox, so an uncapped width would blow the tick labels up.
       Font sizes below are tuned for the mobile floor (~277px rendered
       width at a 375px viewport) and stay comfortably readable up to
       this cap. */
    max-width: 640px;
    height: auto;
}

.pace-chart__axis { stroke: var(--border-strong); stroke-width: 1; }
.pace-chart__grid { stroke: var(--border); stroke-width: 1; }

.pace-chart__tick {
    fill: var(--text-secondary);
    font-family: var(--font-numeric);
    font-feature-settings: "tnum" 1;
    font-size: 16px;
}

.pace-chart__tick--playoff {
    fill: var(--warning);
    font-size: 14px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.pace-chart__line {
    fill: none;
    stroke-width: 2.5;
    stroke-linecap: round;
}

.pace-chart__line--actual    { stroke: var(--team-accent-safe, var(--live)); }
.pace-chart__line--projected { stroke: var(--accent); }
.pace-chart__line--avg       { stroke: var(--text-tertiary); stroke-width: 1.5; stroke-dasharray: 5 4; }
.pace-chart__line--playoff   { stroke: var(--warning); stroke-width: 1.5; stroke-dasharray: 2 3; }
/* Pythagorean "expected" endpoint — optional secondary projection, distinct
   hue (violet) AND a shorter dash than --projected's, so the two read apart
   even without color perception. Thinner stroke keeps pace as the primary
   read (spec: pace stays the headline, expected is the secondary "smarter"
   read). */
.pace-chart__line--expected  { stroke: var(--expected); stroke-width: 2; }

.pace-chart__dot {
    fill: var(--surface);
    stroke-width: 2.5;
}

.pace-chart__dot--actual    { stroke: var(--team-accent-safe, var(--live)); }
.pace-chart__dot--projected { stroke: var(--accent); }
.pace-chart__dot--expected  { stroke: var(--expected); stroke-width: 2; }

.pace-chart__endlabel {
    fill: var(--text-primary);
    font-family: var(--font-numeric);
    font-feature-settings: "tnum" 1;
    font-weight: 700;
    font-size: 18px;
}

.pace-chart__endlabel--expected {
    fill: var(--expected);
    font-size: 16px;
}

.chart-legend {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2) var(--space-4);
    margin: var(--space-3) 0 0;
    padding: 0;
    list-style: none;
}

.chart-legend__item {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    color: var(--text-secondary);
    font-size: var(--text-xs);
}

.chart-legend__swatch {
    display: inline-block;
    width: 18px;
    height: 0;
    border-top: 2px solid;
}

.chart-legend__swatch--actual    { border-color: var(--team-accent-safe, var(--live)); border-top-style: solid; }
.chart-legend__swatch--projected { border-color: var(--accent); border-top-style: dashed; }
.chart-legend__swatch--avg       { border-color: var(--text-tertiary); border-top-style: dashed; }
.chart-legend__swatch--playoff   { border-color: var(--warning); border-top-style: dotted; }
.chart-legend__swatch--expected  { border-color: var(--expected); border-top-style: dashed; border-top-width: 2px; }

/* Phase 4E: odds-movement badges ("+8% since the win", 7-day delta) + the
   season odds-trend sparkline. Injected after Season Outlook by app.js; the
   pill tints with its own semantic colour (positive/negative), the trend uses
   the cyan live-data accent. Theme-aware through the tokens. */
.odds-movement {
    display: flex;
    flex-direction: column;
    gap: var(--space-3, 0.5rem);
    margin-top: var(--space-5, 1rem);
}

.odds-movement__badges {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2, 0.375rem);
}

.odds-movement__delta {
    font-family: var(--font-mono, ui-monospace, monospace);
    font-size: var(--text-sm, 0.875rem);
    font-weight: 600;
    line-height: 1.35;
    padding: 0.4em 0.7em;
    border-radius: var(--radius-md, 12px);
    max-width: 100%;             /* never exceed the card */
    overflow-wrap: anywhere;     /* wrap long labels instead of overflowing */
    color: var(--text-secondary);
    background: color-mix(in srgb, currentColor 12%, transparent);
}

.odds-movement__delta--up   { color: var(--positive); }
.odds-movement__delta--down { color: var(--negative); }
.odds-movement__delta--flat { color: var(--text-tertiary); }

.odds-trend { width: 100%; }

.odds-trend__svg {
    display: block;
    width: 100%;
    height: 56px;
}

.odds-trend__area { fill: color-mix(in srgb, var(--live) 14%, transparent); stroke: none; }
.odds-trend__line { fill: none; stroke: var(--live); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.odds-trend__dot  { fill: var(--live); }

.odds-movement__note {
    margin: 0;
    color: var(--text-tertiary);
    font-size: var(--text-xs);
}

.outlook-side {
    display: flex;
    flex-direction: column;
    gap: var(--space-6);
}

/* Taller variant of the shared .meter component (section 10) for the
   Playoff Pace bar — same track/fill anatomy, more visual weight. */
.meter--lg { height: 20px; }

/* Phase 4C hierarchy pass (amendment #8): the outlook-meter card is now ONE
   "Pace" module — Win Pace (current rate) stacked above Playoff Pace (real
   borrowed odds when available, else the honest heuristic threshold) —
   instead of two separately-captioned bars living in different cards. */
.outlook-meter__subrow {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    margin-bottom: var(--space-2);
}

.outlook-meter__subrow--playoff { margin-top: var(--space-4); }

.outlook-meter__subrow-label {
    color: var(--text-secondary);
    font-size: var(--text-xs);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

.outlook-meter__subrow-value {
    font-family: var(--font-numeric);
    font-feature-settings: "tnum" 1;
    font-weight: 700;
    font-size: var(--text-sm);
    color: var(--text-primary);
}

.outlook-meter__sentence {
    margin: var(--space-2) 0 0;
    color: var(--text-primary);
    font-size: var(--text-sm);
    font-weight: 600;
}

/* Seed/title secondary read ("12% #1 seed · 4% title") — only shown when
   real odds are active and the source exposes that detail. */
.outlook-meter__sentence--secondary {
    margin: var(--space-1) 0 0;
    color: var(--text-secondary);
    font-weight: 600;
}

/* Source + as-of line ("via ESPN FPI · as of 7:42 PM"), incl. the MoneyPuck
   attribution the license requires when that source is active. Same
   AA-safe token as .outlook-meter__note (see the comment below). */
.outlook-meter__source {
    margin: var(--space-1) 0 0;
    color: var(--text-secondary);
    font-size: var(--text-xs);
}

/* --text-secondary, not --text-tertiary: at --text-xs (12px) this disclaimer
   is "small text" per WCAG, which needs 4.5:1 — --text-tertiary only clears
   ~3.7:1 against --surface/--bg-sunken. (On team pages this was accidentally
   masked by unified-styles.css's `.card p` rule outscoping it; the homepage
   card has no such rule, so it failed axe there — fixed at the token level
   so both surfaces render the same, AA-passing color.) */
.outlook-meter__note {
    margin: var(--space-1) 0 0;
    color: var(--text-secondary);
    font-size: var(--text-xs);
}

.outlook-ring {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-2);
    text-align: center;
}

.progress-ring {
    width: 120px;
    height: 120px;
}

.progress-ring__track { fill: none; stroke: var(--border); }

.progress-ring__fill {
    fill: none;
    stroke: var(--live);
    stroke-linecap: round;
    transition: stroke-dashoffset var(--motion-slow) var(--ease);
}

.progress-ring__num {
    fill: var(--text-primary);
    font-family: var(--font-numeric);
    font-feature-settings: "tnum" 1;
    font-weight: 700;
    font-size: 20px;
}

.progress-ring__label {
    color: var(--text-secondary);
    font-size: var(--text-sm);
    font-weight: 600;
}

/* Phase 4C hierarchy pass (amendment #8): one-line explainer sitting between
   the stat tiles and the Season Outlook card, disambiguating the three
   distinct "wins"-shaped reads (pace / expected / odds) the page now shows.
   Bare <p>, not inside a .card, so it needs its own color (unified-styles.css
   only styles `.card p`). --text-secondary (not --text-tertiary) for the
   same AA reason as .outlook-meter__note above. */
.hierarchy-explainer {
    margin: 0 0 var(--space-6);
    color: var(--text-secondary);
    font-size: var(--text-xs);
    text-align: center;
}
