/* =========================================================================
   TransitLive Web — Design Tokens ported from the iOS app
   Source of truth: TransitLive/Utilities/Colors.swift + the app-wide
   type/spacing/radius/shadow/motion scales recovered from the audit.

   PREFIX: --ds-*  (deliberately NOT --tl-*, which already exists in
   public/style.css:1599-1615 for the alert-card system; a compatibility
   alias layer at the bottom of this file maps the old names onto the new
   ones so the ~22k lines of existing JS keep resolving.)

   THEME MECHANISM: :root holds the DARK values (matching the site's
   current dark-first default), body.light-mode overrides to light, and
   body.high-contrast swaps the alert hues. This is exactly the existing
   contract, so no JS changes are required. Theme is written from
   localStorage['theme'] by mobile.js / go-mobile.js / desktop.js and
   broadcast across the iframe boundary by combined-mobile.js.

   UIKIT SEMANTIC COLORS RESOLVED. iOS light-mode values below are the
   real sRGB values of the UIKit semantics, not the symbol names:
     UIColor.systemBackground          -> #FFFFFF
     UIColor.systemGroupedBackground   -> #F2F2F7  (242,242,247)
     UIColor.secondarySystemBackground -> #F2F2F7  (242,242,247)
     UIColor.tertiarySystemBackground  -> #FFFFFF
     UIColor.label                     -> #000000
     UIColor.secondaryLabel            -> rgba(60,60,67,0.60)
     UIColor.tertiaryLabel             -> rgba(60,60,67,0.30)
     UIColor.quaternaryLabel           -> rgba(60,60,67,0.18)
     UIColor.separator                 -> rgba(60,60,67,0.29)
     UIColor.opaqueSeparator           -> #C6C6C8  (198,198,200)
   (Note: the audit reports secondaryBackground light as both #F2F2F7 and
   #FFFFFF in different places. #F2F2F7 is the correct resolution of
   secondarySystemBackground outside a grouped context; used here.)

   SHADOW CONVERSION. SwiftUI `radius` is a Gaussian sigma; CSS
   blur-radius ~= 2 x SwiftUI radius. All shadows below are already
   converted. e.g. SwiftUI (0.08, r8, y4) -> 0 4px 16px rgba(0,0,0,0.08).

   TYPE. 1pt = 1 CSS px at 1x. Sizes are expressed in rem against a
   16px root so they scale with the user's browser font-size preference,
   which is the web analogue of the app's 60 @ScaledMetric declarations.
   DO NOT use these for SVG map labels — those live in schema units and
   are written as inline styles by ttc-map-render.js:402-413.
   ========================================================================= */

:root {
  /* ---------------------------------------------------------------------
     1. FONT FAMILIES
     iOS uses SF Pro (.default), SF Pro Rounded (.rounded, 34 uses, always
     for numerals/badges) and SF Mono (.monospaced, 4 uses). The custom
     TransitPulse.otf is an ANIMATION/ICON font at U+E000-E007 and must
     NOT be shipped as a webfont for copy.
     --------------------------------------------------------------------- */
  --ds-font-sans: -apple-system, BlinkMacSystemFont, "SF Pro Text", "SF Pro Display", "Inter", system-ui, "Segoe UI", Roboto, sans-serif;
  --ds-font-rounded: ui-rounded, "SF Pro Rounded", -apple-system, BlinkMacSystemFont, "Inter", system-ui, sans-serif;
  --ds-font-mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;

  /* ---------------------------------------------------------------------
     2. COLOR — DARK (default)
     --------------------------------------------------------------------- */

  /* Backgrounds */
  --ds-bg-app: #0F1014;              /* systemBackground  rgb(0.059,0.063,0.078) */
  --ds-bg-grouped: #0B0C0F;          /* groupedBackground rgb(0.043,0.047,0.059) */
  --ds-bg-secondary: #1C1C1E;        /* secondaryBackground rgb(0.11,0.11,0.12) */
  --ds-bg-map: #0F1014;              /* mapBackground */
  --ds-surface-glass: rgba(26, 29, 35, 0.92);   /* surfaceGlass #1A1D23 @92% */

  /* Label ramp — DARK is pure white at 100/60/30/18% */
  --ds-label-primary: #FFFFFF;
  --ds-label-secondary: rgba(255, 255, 255, 0.60);
  --ds-label-tertiary: rgba(255, 255, 255, 0.30);
  --ds-label-quaternary: rgba(255, 255, 255, 0.18);

  /* Strokes / separators */
  --ds-hairline: rgba(255, 255, 255, 0.06);     /* THE border token, 39 uses */
  --ds-separator: rgba(255, 255, 255, 0.29);    /* declared, unused in app */
  --ds-separator-opaque: #383838;               /* white 0.22 — sheet grabber */

  /* Fixed-hue accents (identical in both schemes when used as FILLS) */
  --ds-alert-red: #EF4444;
  --ds-alert-orange: #FF9F1C;
  --ds-shuttle-blue: #3B82F6;
  --ds-system-blue: #0A84FF;         /* also the AccentColor asset */
  --ds-system-green: #30D158;
  --ds-system-yellow: #FFCD00;
  --ds-accessible-blue: #528CCB;
  --ds-go-brand-green: #009A3E;
  --ds-pro-gold: #FFCC33;
  --ds-brand-coral: #EC6964;         /* rgb(0.926,0.412,0.392) */

  /* Brand mark. The app ships two appearances and we follow them rather than
     inventing colours: AppIcon-Light is white-on-coral, AppIcon-Dark is a warm
     peach (#EAC4B5) on navy. With a transparent background the mark itself
     has to carry that, so it takes the coral on light and the peach on dark.
     The halo stays TTC yellow in both — it is the one element that has to
     separate from the body at 20px. */
  --ds-logo-body: #EAC4B5;           /* AppIcon-Dark's mark colour */
  --ds-logo-halo: #FFCD00;

  /* On-light-fill ink: the app's only such foreground. Used for text and
     glyphs on yellow (#FFCD00) and orange (#F58220) fills. */
  --ds-ink-on-light: #1A1300;

  /* Text-on-background variants — NEVER render a brand hue as text on
     white; these darken in light mode. */
  --ds-text-red: #EF4444;
  --ds-text-orange: #FF9F1C;
  --ds-text-blue: #3B82F6;
  --ds-text-green: #30D158;
  --ds-text-yellow: #FFCD00;

  /* Map-canvas specific */
  --ds-map-label: #FFFFFF;
  --ds-map-label-halo: #000000;
  --ds-map-marker-outline: #000000;
  --ds-map-dotgrid: rgba(255, 255, 255, 0.06);  /* labelPrimary @6% */
  --ds-map-union-glow-inner: rgba(255, 205, 0, 0.09);   /* #FFCD00 @9%  */
  --ds-map-union-glow-mid: rgba(255, 136, 0, 0.05);     /* #FF8800 @5%  */
  --ds-map-alert-separator: rgba(0, 0, 0, 0.55);        /* alertBorders opt-in */

  /* TTC brand line colours — badges, chips, alert-card accents ONLY.
     The DRAWN TRACK colours come from TTCMap.json and are written as
     inline styles by ttc-map-render.js:637-641; they intentionally
     differ (#fdc90b, #31a650, #b70174, #f8831d, #959597). */
  --ds-ttc-1: #FFCD00;
  --ds-ttc-2: #00A651;
  --ds-ttc-4: #8B288F;
  --ds-ttc-5: #F58220;
  --ds-ttc-6: #808285;

  /* GO line colours */
  --ds-go-lw: #98002E;
  --ds-go-le: #ED1B24;
  --ds-go-br: #005C8A;
  --ds-go-ki: #00853F;
  --ds-go-st: #7A5030;
  --ds-go-rh: #00A4E4;
  --ds-go-mi: #F58220;
  --ds-go-up: #40BFD9;

  /* tintOpacity(dark:light:) — the app's dark/light divergence mechanism,
     40 call sites. RULE: light mode uses roughly HALF the dark alpha.
     Exposed as scalars so gradients can be authored once. */
  --ds-tint-chip-inert: 0.06;
  --ds-tint-chip-neutral: 0.08;
  --ds-tint-chip-active: 0.12;
  --ds-tint-severity-fill: 0.19;     /* one of two light>dark inversions */
  --ds-tint-wash-strong: 0.55;
  --ds-tint-wash-mid: 0.42;
  --ds-tint-wash-soft: 0.22;
  --ds-tint-wash-faint: 0.14;
  --ds-tint-glow: 0.50;
  --ds-tint-shuttle-border: 0.25;    /* the other light>dark inversion */

  /* Composed surface fills. The tint scalars above are alphas over WHITE,
     which is correct on a dark ground and invisible on a light one — a white
     6% card on #F2F2F7 simply is not there. These resolve the whole fill so
     each scheme can pick its own ink, and every component uses them instead
     of writing rgba(255,255,255,...) directly. */
  --ds-fill-subtle: rgba(255, 255, 255, 0.06);
  --ds-fill-neutral: rgba(255, 255, 255, 0.08);
  --ds-fill-active: rgba(255, 255, 255, 0.12);

  /* De-emphasis constants */
  --ds-opacity-tab-unselected: 0.65;
  --ds-opacity-mode-unselected: 0.55;

  /* ---------------------------------------------------------------------
     3. TYPE SCALE  (pt -> rem @16px root)
     Canonical UI ramp 10-17; display 22/28/34.
     Frequency in the app: 13pt x35, 12pt x32, 11pt x20, 14pt x19, 16pt x18.
     --------------------------------------------------------------------- */
  --ds-fs-7:  0.4375rem;   /*  7pt — DualRoute warning glyph */
  --ds-fs-8:  0.5rem;      /*  8pt — inline GO badge */
  --ds-fs-9:  0.5625rem;   /*  9pt — chip leading glyph, peek eyebrow */
  --ds-fs-10: 0.625rem;    /* 10pt — caption2, section-head glyph */
  --ds-fs-11: 0.6875rem;   /* 11pt — micro caps labels, chip text */
  --ds-fs-12: 0.75rem;     /* 12pt — caption, line badge, badge label */
  --ds-fs-13: 0.8125rem;   /* 13pt — footnote, body prose, chip minutes */
  --ds-fs-14: 0.875rem;    /* 14pt — subheadline, row title */
  --ds-fs-15: 0.9375rem;   /* 15pt — body, severity headline, settings row */
  --ds-fs-16: 1rem;        /* 16pt — callout */
  --ds-fs-17: 1.0625rem;   /* 17pt — body large, station name in route */
  --ds-fs-18: 1.125rem;
  --ds-fs-20: 1.25rem;
  --ds-fs-22: 1.375rem;    /* 22pt — sheet title, empty-state title */
  --ds-fs-24: 1.5rem;
  --ds-fs-26: 1.625rem;
  --ds-fs-28: 1.75rem;     /* 28pt — onboarding title */
  --ds-fs-30: 1.875rem;
  --ds-fs-32: 2rem;
  --ds-fs-34: 2.125rem;    /* 34pt — largeTitle / screen title */

  /* Weights (iOS census: semibold 600 x87 > bold 700 x66 > heavy 800 x35) */
  --ds-fw-regular: 400;
  --ds-fw-medium: 500;
  --ds-fw-semibold: 600;
  --ds-fw-bold: 700;
  --ds-fw-heavy: 800;
  --ds-fw-black: 900;

  /* Tracking. SwiftUI .tracking() is in pt; converted to em by dividing
     by the font size at the site where it is used. */
  --ds-tracking-title: -0.018em;   /* -0.4pt @22pt — sheet/station titles  */
  --ds-tracking-section: -0.015em; /* -0.2pt @13pt — RECENTLY RESOLVED     */
  --ds-tracking-caps: 0.073em;     /* +0.8pt @11pt — ALL-CAPS micro labels */
  --ds-tracking-caps-tight: 0.055em; /* +0.6pt @11pt — settings headers    */
  --ds-tracking-peek: 0.056em;     /* +0.5pt @9pt  — peek status eyebrow   */

  /* Leading. SwiftUI lineSpacing is ADDITIONAL leading:
     line-height ~= (fontSize * 1.2 + 3) / fontSize */
  --ds-lh-tight: 1.2;
  --ds-lh-body: 1.43;      /* 13pt + 3pt lineSpacing */
  --ds-lh-relaxed: 1.39;   /* 16pt + 3pt lineSpacing */

  /* Numerals */
  --ds-numeric: tabular-nums;   /* use with font-variant-numeric */

  /* ---------------------------------------------------------------------
     4. SPACING  (stack gap census: 12 x48, 0 x44, 6 x30, 10 x21, 8 x19)
     --------------------------------------------------------------------- */
  --ds-space-0: 0px;
  --ds-space-1: 1px;
  --ds-space-2: 2px;
  --ds-space-3: 3px;
  --ds-space-4: 4px;    /* icon-to-label gap */
  --ds-space-5: 5px;    /* chip vertical padding */
  --ds-space-6: 6px;    /* tight in-row gap; glass-bar inner inset */
  --ds-space-8: 8px;
  --ds-space-10: 10px;  /* chip horizontal padding */
  --ds-space-12: 12px;  /* DEFAULT stack gap */
  --ds-space-14: 14px;
  --ds-space-16: 16px;  /* CANONICAL page/card gutter — 63 uses */
  --ds-space-18: 18px;
  --ds-space-20: 20px;  /* top-app-bar gutter */
  --ds-space-22: 22px;  /* clearance above the floating tab bar */
  --ds-space-24: 24px;
  --ds-space-28: 28px;
  --ds-space-32: 32px;  /* wide/centred gutter (onboarding, toasts) */
  --ds-space-40: 40px;  /* section break */
  --ds-space-60: 60px;

  /* Layout constants */
  --ds-gutter-page: var(--ds-space-16);
  --ds-gutter-header: var(--ds-space-20);
  --ds-content-max: 500px;        /* widest card clamp */
  --ds-tabbar-max: 300px;         /* floating tab bar clamp */
  --ds-modepicker-w: 160px;
  --ds-hit-min: 44px;             /* minimum touch target */
  --ds-safe-bottom: env(safe-area-inset-bottom, 0px);
  --ds-safe-top: env(safe-area-inset-top, 0px);

  /* ---------------------------------------------------------------------
     5. RADII
     iOS uses .continuous (squircle) on 62 of 70 rounded rects. CSS
     border-radius is a circular arc, so multiply by ~1.1 to read the
     same, or use the --sq variants below.
     --------------------------------------------------------------------- */
  --ds-radius-3: 3px;
  --ds-radius-5: 5px;
  --ds-radius-6: 6px;    /* GO route badge */
  --ds-radius-7: 7px;    /* bus badge */
  --ds-radius-8: 8px;    /* inner element / footer chip / icon tile */
  --ds-radius-10: 10px;  /* severity icon tile */
  --ds-radius-12: 12px;  /* sub-card, shuttle banner, callout */
  --ds-radius-14: 14px;  /* settings card / small card */
  --ds-radius-16: 16px;
  --ds-radius-18: 18px;  /* floating peek card */
  --ds-radius-20: 20px;  /* list card — THE alert card */
  --ds-radius-22: 22px;
  --ds-radius-26: 26px;  /* tutorial panel */
  --ds-radius-28: 28px;  /* CANONICAL bottom-sheet top corners */
  --ds-radius-44: 44px;  /* surface-map sheet */
  --ds-radius-pill: 999px;
  /* Squircle-compensated variants */
  --ds-radius-14-sq: 15.5px;
  --ds-radius-20-sq: 22px;
  --ds-radius-28-sq: 31px;

  /* ---------------------------------------------------------------------
     6. STROKE WIDTHS
     0.5 is THE border width, always paired with --ds-hairline (12 exact
     matches of strokeBorder(hairline, lineWidth: 0.5) in the app).
     --------------------------------------------------------------------- */
  --ds-stroke-hairline: 0.5px;
  --ds-stroke-thin: 1px;
  --ds-stroke-live: 1.5px;     /* systemGreen tracking ring */
  --ds-stroke-knockout: 2px;   /* secondaryBackground ring on overlapping dots */
  --ds-stroke-ring: 2.5px;

  /* ---------------------------------------------------------------------
     7. ELEVATION / SHADOWS  (already sigma->blur converted)
     --------------------------------------------------------------------- */
  --ds-shadow-glass: 0 4px 16px rgba(0, 0, 0, 0.08);       /* liquidGlass()  */
  --ds-shadow-pill: 0 1px 6px rgba(0, 0, 0, 0.08);         /* light mode only */
  --ds-shadow-tabbar: 0 10px 60px rgba(0, 0, 0, 0.40);
  --ds-shadow-peek: 0 10px 48px rgba(0, 0, 0, 0.40);       /* heaviest UI     */
  --ds-shadow-toast: 0 4px 20px rgba(0, 0, 0, 0.18);
  --ds-shadow-callout: 0 5px 20px rgba(0, 0, 0, 0.35);

  /* Coloured glows. Pattern: dot colour at 70-80% alpha, blur = 2 x radius,
     no offset. Severity glow carries a +2px y offset. */
  --ds-glow-severity-alpha: 0.50;   /* light mode 0.25 */
  --ds-glow-live: 0 0 6px rgba(48, 209, 88, 0.80);
  --ds-glow-alert-dot: 0 0 8px rgba(239, 68, 68, 0.80);
  --ds-glow-shuttle-dot: 0 0 10px rgba(59, 130, 246, 0.50);

  /* Map alert glow (SVG drop-shadow). iOS clamps the radius to
     min(nominal, 24/mapScale) so device-space blur never exceeds 24pt. */
  --ds-map-glow-pill: 12;
  --ds-map-glow-bar: 15;
  --ds-map-glow-alpha: 0.90;

  /* ---------------------------------------------------------------------
     8. GLASS / MATERIALS
     The browser cannot reproduce Liquid Glass refraction, so the
     pre-iOS-26 .ultraThinMaterial path is the port target: blur +
     saturate over a translucent fill, with a 0.5px hairline border.
     --------------------------------------------------------------------- */
  --ds-glass-blur: blur(20px) saturate(180%);
  --ds-glass-blur-heavy: blur(30px) saturate(180%);
  --ds-glass-fill: rgba(255, 255, 255, 0.06);
  --ds-glass-fill-material: rgba(30, 30, 30, 0.55);   /* ultraThinMaterial dark */
  --ds-glass-border: var(--ds-hairline);
  --ds-glass-shadow: var(--ds-shadow-glass);
  /* Floating tab bar fill. iOS 26 tints this black @35% and lets Liquid Glass
     refract and adapt behind it; a browser's backdrop-filter does neither, so
     the web needs a somewhat heavier fill to reach the same legibility over a
     scrolling list. See the battery-saver block for the no-blur case. */
  --ds-glass-tint-bar: rgba(28, 28, 30, 0.62);

  /* Network picker. The tab bar's 35%-black tint is nearly invisible sitting
     directly on the #0F1014 app bar (the tab bar gets away with it because it
     floats over the map). These give the picker a track that actually reads
     and a thumb with real separation from it — the app's pre-26 fallback uses
     white @14% on an ultraThin track for exactly the same reason. */
  --ds-picker-track: rgba(255, 255, 255, 0.10);
  --ds-picker-thumb: rgba(255, 255, 255, 0.22);
  --ds-glass-tint-selected: rgba(255, 255, 255, 0.18);/* Color.primary @12%, raised for the heavier bar fill */
  --ds-glass-pill-legacy: rgba(255, 255, 255, 0.14);  /* legacy selected pill  */
  --ds-glass-panel-opacity: 0.55;                     /* user-tunable 0.15-1.0 */

  /* ---------------------------------------------------------------------
     9. MOTION
     .smooth(duration:) is SwiftUI's critically-damped spring (bounce 0)
     and is THE selection/interaction curve — 8 call sites.
     --------------------------------------------------------------------- */
  --ds-ease-in-out: cubic-bezier(0.42, 0, 0.58, 1);
  --ds-ease-out: cubic-bezier(0, 0, 0.58, 1);
  --ds-ease-in: cubic-bezier(0.42, 0, 1, 1);
  --ds-ease-smooth: cubic-bezier(0.25, 0.1, 0.25, 1);      /* .smooth        */
  --ds-ease-spring-soft: cubic-bezier(0.32, 1.25, 0.60, 1);/* r0.28 d0.85    */
  --ds-ease-spring-bouncy: cubic-bezier(0.34, 1.56, 0.64, 1);/* r0.6 d0.7    */

  --ds-dur-micro: 0.15s;
  --ds-dur-fast: 0.20s;      /* toggle / opacity                      */
  --ds-dur-chip: 0.25s;      /* chip select                           */
  --ds-dur-select: 0.32s;    /* tab + mode-picker tap                 */
  --ds-dur-scrub: 0.26s;     /* tab drag-scrub                        */
  --ds-dur-list: 0.35s;      /* list reorder / toast                  */
  --ds-dur-scene: 0.45s;     /* screen transition                     */
  --ds-dur-settle: 0.50s;    /* sheet snap-back / camera reset        */
  --ds-dur-entrance: 0.70s;  /* onboarding entrance spring            */
  --ds-dur-camera: 0.60s;    /* fly-to (ease-out cubic, 60 frames)    */

  /* Ambient loops */
  --ds-dur-pulse-badge: 1.2s;   /* 'Previewing' eye 1.0 <-> 0.3       */
  --ds-dur-pulse-hint: 1.4s;
  --ds-dur-alert-flow: 2.4s;    /* marching pills, per track segment  */
  --ds-dur-alert-pulse: 3.0s;   /* bidirectional capsule breathing    */
  --ds-dur-go-shuttle: 2.0s;

  --ds-delay-stagger: 0.10s;
  --ds-delay-entrance: 0.08s;
}

/* =========================================================================
   LIGHT MODE
   Written by JS as body.light-mode (mobile.js:401-404, desktop.js:1520-1532,
   go-mobile.js:1485-1494). Light backgrounds defer to Apple system colours;
   the label ramp becomes Apple's label ramp; brand hues stay identical as
   FILLS but every text variant darkens substantially.
   ========================================================================= */
body.light-mode {
  /* Light: the coral the app icon uses as its own ground becomes the mark. */
  --ds-logo-body: #EC6964;

  --ds-bg-app: #FFFFFF;
  --ds-bg-grouped: #F2F2F7;
  --ds-bg-secondary: #F2F2F7;
  --ds-bg-map: #FFFFFF;
  --ds-surface-glass: rgba(255, 255, 255, 0.92);

  --ds-label-primary: #000000;
  --ds-label-secondary: rgba(60, 60, 67, 0.60);
  --ds-label-tertiary: rgba(60, 60, 67, 0.30);
  --ds-label-quaternary: rgba(60, 60, 67, 0.18);

  --ds-hairline: rgba(0, 0, 0, 0.06);
  --ds-separator: rgba(0, 0, 0, 0.29);
  --ds-separator-opaque: #C6C6C8;

  /* Text-on-white variants — the whole point of this ramp */
  --ds-text-red: #B91C1C;
  --ds-text-orange: #B45309;
  --ds-text-blue: #1D4ED8;
  --ds-text-green: #0F8B43;
  --ds-text-yellow: #7A5300;

  --ds-map-label: #1F2937;
  --ds-map-label-halo: #D4D4D8;
  --ds-map-marker-outline: #333338;
  --ds-map-dotgrid: rgba(0, 0, 0, 0.06);

  /* tintOpacity light halves — with the app's two deliberate inversions */
  --ds-tint-chip-inert: 0.06;
  --ds-tint-chip-neutral: 0.08;
  --ds-tint-chip-active: 0.10;
  --ds-tint-severity-fill: 0.24;     /* INVERSION: light > dark (0.19) */
  --ds-tint-wash-strong: 0.22;
  --ds-tint-wash-mid: 0.16;
  --ds-tint-wash-soft: 0.10;
  --ds-tint-wash-faint: 0.06;
  --ds-tint-glow: 0.25;
  --ds-tint-shuttle-border: 0.28;    /* INVERSION: light > dark (0.25) */

  --ds-glass-fill: rgba(255, 255, 255, 0.60);
  --ds-glass-fill-material: rgba(255, 255, 255, 0.55);
  --ds-glass-tint-selected: rgba(0, 0, 0, 0.12);
  --ds-glass-pill-legacy: #FFFFFF;

  /* The tab bar and mode picker tint. iOS 26 tints these with black @35% in
     both schemes and lets Liquid Glass re-read it against the backdrop; a
     browser cannot, so an unmodified 35% black renders as a heavy grey slab
     on a white page. Mirror the pre-26 .ultraThinMaterial appearance instead,
     which is what the rest of this sheet ports. */
  --ds-glass-tint-bar: rgba(252, 252, 254, 0.72);
  --ds-picker-track: rgba(0, 0, 0, 0.07);
  --ds-picker-thumb: #FFFFFF;

  /* Light surfaces are opaque white cards on a grey grouped ground — the
     iOS grouped-list look — not a translucent white wash. */
  --ds-fill-subtle: #FFFFFF;
  --ds-fill-neutral: rgba(0, 0, 0, 0.05);
  --ds-fill-active: rgba(0, 0, 0, 0.09);

  /* Light mode is where the selected pill gains a shadow and the tab bar
     shadow softens (the only shadow whose alpha, blur AND offset change). */
  --ds-shadow-tabbar: 0 6px 32px rgba(0, 0, 0, 0.12);
  --ds-shadow-pill: 0 1px 6px rgba(0, 0, 0, 0.08);
  --ds-glow-severity-alpha: 0.25;
}

/* Dark mode deliberately has NO selected-pill shadow. */
:root { --ds-shadow-pill-dark: none; }

/* =========================================================================
   HIGH VISIBILITY  (iOS: SettingsStore.highVisibilityEnabled)
   Swaps the alert hues AND, in the app, thickens strokes x1.2 and raises
   map glow radii 12/15 -> 18/22. Web currently only swaps colours; the
   stroke/glow scalars are included here so that can be fixed in CSS.
   ========================================================================= */
body.high-contrast {
  --ds-alert-red: #FF00FF;
  --ds-alert-orange: #00E5FF;
  --ds-text-red: #FF00FF;
  --ds-text-orange: #00E5FF;
  --ds-map-glow-pill: 18;
  --ds-map-glow-bar: 22;
  --ds-hv-stroke-scale: 1.2;
}

/* =========================================================================
   REDUCED MOTION / BATTERY SAVER
   iOS stops the gyro gradient entirely under Reduce Motion or Low Power
   and suppresses every map glow filter under Low Power. Mirror that.
   ========================================================================= */
@media (prefers-reduced-motion: reduce) {
  :root {
    --ds-dur-micro: 0.01ms; --ds-dur-fast: 0.01ms; --ds-dur-chip: 0.01ms;
    --ds-dur-select: 0.01ms; --ds-dur-scrub: 0.01ms; --ds-dur-list: 0.01ms;
    --ds-dur-scene: 0.01ms; --ds-dur-settle: 0.01ms; --ds-dur-entrance: 0.01ms;
  }
}
/* Battery saver drops backdrop-filter entirely — which means every glass
   surface loses the blur that was doing most of the work of separating it
   from the content behind it. A translucent fill that reads fine WITH blur
   becomes a window you can read straight through without it, so the fills go
   near-opaque here. This is the mode the floating tab bar disappears in
   otherwise. */
body.battery-saver {
  --ds-glass-blur: none;
  --ds-glass-blur-heavy: none;
  --ds-map-glow-alpha: 0;

  --ds-glass-tint-bar: rgba(24, 24, 26, 0.96);
  --ds-glass-fill-material: rgba(28, 28, 30, 0.96);
  --ds-picker-track: rgba(255, 255, 255, 0.14);
}

body.battery-saver.light-mode,
body.light-mode.battery-saver {
  --ds-glass-tint-bar: rgba(250, 250, 252, 0.97);
  --ds-glass-fill-material: rgba(252, 252, 254, 0.97);
  --ds-picker-track: rgba(0, 0, 0, 0.08);
}

/* =========================================================================
   COMPATIBILITY ALIAS LAYER — DO NOT DELETE
   Maps the site's existing custom-property names onto the new tokens so
   the ~22k lines of JS that emit `var(--l1-color)`, `var(--tl-red-text)`,
   `var(--alert-color)` etc. into inline style attributes keep resolving.
   Consumers: mobile.js:839/1166-1180/1966, go-mobile.js:1252/2350,
   desktop.js:913/1051, plus style.css / mobile.css / go-mobile.css /
   desktop.css. Retire only after every emitter is migrated.

   NOTE: --l3-color and --text-primary are referenced by existing JS but
   were never defined anywhere. They are defined here to fix two latent
   bugs (Line 3 badges and the GO preview button / station alert banner).
   ========================================================================= */
:root {
  --bg-color: var(--ds-bg-app);
  --surface-glass: var(--ds-surface-glass);
  --surface-glass-border: var(--ds-hairline);
  --text-main: var(--ds-label-primary);
  --text-muted: var(--ds-label-secondary);
  --text-primary: var(--ds-label-primary);   /* was undefined */
  --border-color: var(--ds-hairline);

  --l1-color: var(--ds-ttc-1);
  --l2-color: var(--ds-ttc-2);
  --l3-color: var(--ds-label-secondary);     /* was undefined */
  --l4-color: var(--ds-ttc-4);
  --l5-color: var(--ds-ttc-5);
  --l6-color: var(--ds-ttc-6);

  --alert-color: var(--ds-alert-red);
  --delay-color: var(--ds-alert-orange);
  --shuttle-color: var(--ds-shuttle-blue);

  --tl-card-bg: var(--ds-bg-secondary);
  --tl-hairline: var(--ds-hairline);
  --tl-label-secondary: var(--ds-label-secondary);
  --tl-label-tertiary: var(--ds-label-tertiary);
  --tl-red-text: var(--ds-text-red);
  --tl-orange-text: var(--ds-text-orange);

  --nav-height: 80px;
  --safe-area-bottom: env(safe-area-inset-bottom, 20px);
}

/* =========================================================================
   RECIPES — the three composites worth centralising up front.
   ========================================================================= */

/* Glass surface (the liquidGlass() port). Apply to FABs, tab bar, mode
   picker, popovers, sheets. Never stack glass on glass. */
.ds-glass {
  background: var(--ds-glass-fill-material);
  -webkit-backdrop-filter: var(--ds-glass-blur);
  backdrop-filter: var(--ds-glass-blur);
  border: var(--ds-stroke-hairline) solid var(--ds-glass-border);
  box-shadow: var(--ds-glass-shadow);
}

/* Standard content card. */
.ds-card {
  background: var(--ds-bg-secondary);
  border: var(--ds-stroke-hairline) solid var(--ds-hairline);
  border-radius: var(--ds-radius-20);
  max-width: var(--ds-content-max);
}

/* Numeric / badge voice — SF Pro Rounded heavy with tabular figures.
   This is the app's signature 'transit display' treatment (34 uses). */
.ds-numeric {
  font-family: var(--ds-font-rounded);
  font-weight: var(--ds-fw-heavy);
  font-variant-numeric: var(--ds-numeric);
}