/* ============================================================================
   CatchARidePDX — design tokens.

   Everything below this block resolves back to one of these. The sheet used to
   carry font sizes at 11 / 11.5 / 12.5 / 13.5px and padding at 9 / 13 / 15px,
   chosen one component at a time; nothing lined up and nothing was reusable.
   One type scale, one 4px spacing scale, one elevation model, one easing
   family — so the app reads as a single thing rather than fourteen.
   ========================================================================== */
:root{
  --font-sans:'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',system-ui,sans-serif;
  --font-mono:'JetBrains Mono','SF Mono','Fira Code',monospace;

  /* Type scale. Whole pixels only — half-pixel sizes hinted differently on
     every platform, which is why the old 11.5/13.5px labels never aligned with
     the 12/14px ones beside them. Ratio runs ~1.1 at the small end (where the
     UI is dense and steps must be subtle) opening to ~1.2 at the display end. */
  --fs-100:10px;   /* all-caps micro labels only */
  --fs-200:11px;   /* row metadata */
  --fs-300:12px;   /* secondary controls */
  --fs-400:13px;   /* default UI text */
  --fs-500:15px;   /* emphasis, controls that matter */
  --fs-600:17px;   /* card titles */
  --fs-700:20px;   /* the arrival countdown */
  --fs-800:24px;   /* stat numerals */
  --fs-900:clamp(56px,11vw,80px);   /* the countdown view's hero numeral */

  --lh-flat:1;     /* numerals whose box must not grow as digits change */
  --lh-tight:1.2;  /* titles */
  --lh-snug:1.35;  /* dense UI copy */
  --lh-body:1.5;   /* prose */

  /* Tracking is a function of size: small all-caps needs opening up, large
     display type needs closing in, mono numerals are wide and need closing in
     hardest. */
  --ls-caps:.07em;
  --ls-tight:-.01em;
  --ls-num:-.02em;
  --ls-display:-.03em;

  /* 4px spacing scale. The feed's rhythm is 4 / 8 / 12 / 16. */
  --sp-1:2px;  --sp-2:4px;  --sp-3:6px;  --sp-4:8px;  --sp-5:12px;
  --sp-6:16px; --sp-7:20px; --sp-8:24px; --sp-9:32px; --sp-10:40px;

  /* Radii step with the size of the thing: micro badges, chips, cards, sheets. */
  --radius-xs:5px; --radius-sm:8px; --radius-md:12px; --radius-lg:16px; --radius-full:9999px;

  /* Motion. Duration tracks distance travelled: state changes are near-instant,
     things that slide across the screen get time to be followed. One easing
     family, so nothing feels borrowed from somewhere else. */
  --dur-1:110ms; --dur-2:170ms; --dur-3:240ms; --dur-4:380ms;
  --ease-out:cubic-bezier(.16,1,.3,1);
  --ease-standard:cubic-bezier(.3,.6,.2,1);
  --ease-exit:cubic-bezier(.4,0,1,1);

  /* Elevation. Three real heights, each a tight contact shadow plus a wide
     ambient one; a single blurred blob reads as fog, not as height.
     --shadow-color is restated per theme so light themes do not get the
     black-on-white smudge the old fixed rgba(0,0,0,.4) produced. */
  --shadow-color:230 45% 5%;
  --shadow-1:0 1px 2px hsl(var(--shadow-color)/.14),0 2px 6px hsl(var(--shadow-color)/.10);
  --shadow-2:0 2px 4px hsl(var(--shadow-color)/.16),0 8px 20px hsl(var(--shadow-color)/.16);
  --shadow-3:0 6px 12px hsl(var(--shadow-color)/.22),0 22px 48px hsl(var(--shadow-color)/.26);
  --shadow-card:var(--shadow-1);
  --shadow-float:var(--shadow-3);

  --focus-w:2px;
  --focus-offset:2px;

  /* Neutral chip fills, derived from the card they sit on rather than from
     --bg-2. --bg-2 drifts a long way from --surface in some themes (Dracula's
     is a mid slate), which is how muted text on a "subtle" chip ended up at
     2.2:1. Mixed off --surface it can only ever be a shade of the card. */
  --tint:color-mix(in srgb,var(--text-0) 7%,var(--surface));
  --tint-2:color-mix(in srgb,var(--text-0) 13%,var(--surface));

  /* Status fills keep the hue but carry none of the contrast duty — the ink
     on top does that. */
  --fill-green:color-mix(in srgb,var(--green) 15%,var(--surface));
  --fill-yellow:color-mix(in srgb,var(--yellow) 15%,var(--surface));
  --fill-red:color-mix(in srgb,var(--red) 15%,var(--surface));
  --fill-blue:color-mix(in srgb,var(--blue) 15%,var(--surface));
  --fill-accent:color-mix(in srgb,var(--accent) 15%,var(--surface));

  /* Fallbacks for the derived inks below, in case relative colour is missing. */
  --paper-ink:#fff;
  --on-accent:#fff;
  --text-muted:var(--text-2);
  --ink-green:var(--green);
  --ink-yellow:var(--yellow);
  --ink-red:var(--red);
  --ink-blue:var(--blue);
  --ink-accent:var(--accent);
  /* Focus ring must not equal accent — accent-filled chrome would be 1:1 on the
   * inner edge. --ring follows text so it stays visible on any fill. */
  --ring:var(--text-0);
  --focus:var(--ring);
}

:root,[data-theme="light"]{--bg-0:#f8f9fc;--bg-1:#f0f1f6;--bg-2:#e8e9f0;--surface:#fff;--surface-hover:#f0f1f6;--text-0:#111128;--text-1:#3a3a58;--text-2:#676781;--accent:#6356e5;--accent-dim:rgba(99,86,229,.12);--green:#059669;--yellow:#b45309;--red:#dc2626;--blue:#2563eb;--glass:rgba(248,249,252,.82);--glass-border:rgba(0,0,0,.08);--border:rgba(0,0,0,.08);--map-filter:none}

/* Derived inks.
 *
 * A theme states a hue; whether that hue is *readable* depends on the surface
 * under it, and the fourteen themes below plus the ones in themes.css do not
 * agree on that. Rather than hand-tune every pairing (and get it wrong the next
 * time somebody adds a theme), derive:
 *
 *   --paper-ink  black or white, whichever the card can carry. The switch is a
 *                luminance test: multiply the distance from mid-grey by a large
 *                number and let rgb() clamp it to 0 or 255.
 *   --ink-*      the hue washed 45% toward paper-ink. 45% is the smallest wash
 *                that clears 4.5:1 for every hue in all 32 themes currently
 *                defined across both sheets, measured, not guessed.
 *   --on-accent  text placed on a solid fill of the accent.
 *
 * The 120/255 threshold was picked the same way: at 120 every accent in both
 * sheets clears 4.5:1 against the ink the switch chooses, with no hue shift.
 *
 * The wash costs saturation, so the fourteen themes below restate --ink-* and
 * --text-muted with values solved per theme — hue and saturation held, lightness
 * moved only as far as the measurement demanded. Those beat the generic wash.
 * A theme added later (themes.css and beyond) gets the derivation and is legible
 * without anyone having to remember this file exists.
 *
 * The light ramp is declared above rather than here because its selector is
 * `:root, [data-theme="light"]` — the :root half matches EVERY theme, so a
 * measured value put in it would leak into all of them. Light's own inks are in
 * a [data-theme="light"] block below, with the other thirteen.
 */
@supports (color:rgb(from white r g b)){
  :root{
    --paper-ink:rgb(from var(--surface)
      clamp(0,calc((.2126*r + .7152*g + .0722*b - 120)*-999),255)
      clamp(0,calc((.2126*r + .7152*g + .0722*b - 120)*-999),255)
      clamp(0,calc((.2126*r + .7152*g + .0722*b - 120)*-999),255));
    --on-accent:rgb(from var(--accent)
      clamp(0,calc((.2126*r + .7152*g + .0722*b - 120)*-999),255)
      clamp(0,calc((.2126*r + .7152*g + .0722*b - 120)*-999),255)
      clamp(0,calc((.2126*r + .7152*g + .0722*b - 120)*-999),255));
    --text-muted:color-mix(in srgb,var(--text-2) 72%,var(--paper-ink));
    --ink-green:color-mix(in srgb,var(--green) 55%,var(--paper-ink));
    --ink-yellow:color-mix(in srgb,var(--yellow) 55%,var(--paper-ink));
    --ink-red:color-mix(in srgb,var(--red) 55%,var(--paper-ink));
    --ink-blue:color-mix(in srgb,var(--blue) 55%,var(--paper-ink));
    --ink-accent:color-mix(in srgb,var(--accent) 55%,var(--paper-ink));
  }
}

/* ---- themes -------------------------------------------------------------
 * The base ramp is unchanged except for --text-2, which is raised to the
 * measured value rather than being shadowed by a new token: themes.css and
 * app.js both read --text-2 directly, and a muted colour that is only readable
 * if you remember to use the new name is not a fixed muted colour.
 * --text-muted stays as an alias so existing rules keep working.
 * Everything below was solved against that theme's own --surface,
 * --surface-hover, --bg-0 and --bg-1 for 4.5:1, not eyeballed.
 * themes.css is linked after this file and adds further themes; it sets only
 * the base ramp, so those themes fall through to the derivation above.
 * ------------------------------------------------------------------------ */
[data-theme="light"]{--shadow-color:230 40% 30%;--text-muted:var(--text-2);--ink-green:#047653;--ink-yellow:#a54c08;--ink-red:#c31f1f;--ink-blue:#1658ea;--ink-accent:#5c4ee4}
[data-theme="dark"]{--bg-0:#08080f;--bg-1:#0e0e18;--bg-2:#141422;--surface:#1e1e34;--surface-hover:#252544;--text-0:#f4f4fb;--text-1:#c4c4dc;--text-2:#9797b3;--accent:#7b6cf6;--accent-dim:rgba(123,108,246,.15);--green:#34d399;--yellow:#fbbf24;--red:#f87171;--blue:#60a5fa;--glass:rgba(14,14,24,.82);--glass-border:rgba(255,255,255,.06);--border:rgba(255,255,255,.06);--map-filter:invert(1) hue-rotate(180deg) brightness(.85) contrast(.9);
  --shadow-color:250 60% 2%;--text-muted:var(--text-2);--ink-green:#34d399;--ink-yellow:#fbbf24;--ink-red:#f87171;--ink-blue:#60a5fa;--ink-accent:#968af8}
[data-theme="high-contrast"]{--bg-0:#000;--bg-1:#0a0a0a;--bg-2:#141414;--surface:#1a1a1a;--surface-hover:#242424;--text-0:#fff;--text-1:#e0e0e0;--text-2:#b0b0b0;--accent:#ff0;--accent-dim:rgba(255,255,0,.15);--green:#0f0;--yellow:#ff0;--red:#f33;--blue:#3cf;--glass:rgba(0,0,0,.9);--glass-border:rgba(255,255,255,.25);--border:rgba(255,255,255,.25);--map-filter:invert(1) grayscale(1) contrast(1.3);
  --shadow-color:0 0% 0%;--text-muted:var(--text-2);--ink-green:#0f0;--ink-yellow:#ff0;--ink-red:#ff5151;--ink-blue:#3cf;--ink-accent:#ff0}
[data-theme="cyberpunk"]{--bg-0:#0a0014;--bg-1:#0f0020;--bg-2:#180030;--surface:#1d0a38;--surface-hover:#2a1050;--text-0:#e0f0ff;--text-1:#a0c0e0;--text-2:#6392b9;--accent:#0ff;--accent-dim:rgba(0,255,255,.14);--green:#3f9;--yellow:#fd0;--red:#f39;--blue:#4cf;--glass:rgba(10,0,20,.85);--glass-border:rgba(0,255,255,.16);--border:rgba(0,255,255,.14);--map-filter:invert(1) hue-rotate(200deg) saturate(1.4) brightness(.8);
  --shadow-color:275 100% 3%;--text-muted:var(--text-2);--ink-green:#3f9;--ink-yellow:#fd0;--ink-red:#ff3e9f;--ink-blue:#4cf;--ink-accent:#0ff}
[data-theme="synthwave"]{--bg-0:#1a0a2e;--bg-1:#1e0e36;--bg-2:#261442;--surface:#2d1850;--surface-hover:#3a2064;--text-0:#fce4ff;--text-1:#d4a0e0;--text-2:#b78dcc;--accent:#ff6ec7;--accent-dim:rgba(255,110,199,.16);--green:#5ee9b5;--yellow:#ffd866;--red:#ff5f87;--blue:#7ab8ff;--glass:rgba(26,10,46,.85);--glass-border:rgba(255,110,199,.16);--border:rgba(255,255,255,.08);--map-filter:invert(1) hue-rotate(250deg) saturate(1.3) brightness(.82);
  --shadow-color:280 70% 4%;--text-muted:var(--text-2);--ink-green:#5ee9b5;--ink-yellow:#ffd866;--ink-red:#ff6e92;--ink-blue:#7ab8ff;--ink-accent:#ff6ec7}
[data-theme="terminal"]{--bg-0:#0a0a0a;--bg-1:#0f0f0f;--bg-2:#161616;--surface:#121212;--surface-hover:#1c1c1c;--text-0:#00ff41;--text-1:#0c3;--text-2:#00a827;--accent:#00ff41;--accent-dim:rgba(0,255,65,.14);--green:#00ff41;--yellow:#dfd000;--red:#ff4141;--blue:#41d6ff;--glass:rgba(10,10,10,.9);--glass-border:rgba(0,255,65,.2);--border:rgba(0,255,65,.16);--map-filter:invert(1) grayscale(1) sepia(1) hue-rotate(75deg) saturate(2) brightness(.7);
  --shadow-color:0 0% 0%;--text-muted:var(--text-2);--ink-green:#00ff41;--ink-yellow:#dfd000;--ink-red:#ff4f4f;--ink-blue:#41d6ff;--ink-accent:#00ff41}
[data-theme="pacific"]{--bg-0:#0c1a14;--bg-1:#10221a;--bg-2:#162c22;--surface:#1a3328;--surface-hover:#224034;--text-0:#e0f4ec;--text-1:#a0c8b4;--text-2:#8db19f;--accent:#34d399;--accent-dim:rgba(52,211,153,.14);--green:#34d399;--yellow:#fbbf24;--red:#f87171;--blue:#60a5fa;--glass:rgba(12,26,20,.85);--glass-border:rgba(255,255,255,.07);--border:rgba(255,255,255,.07);--map-filter:invert(1) hue-rotate(140deg) brightness(.85) contrast(.9);
  --shadow-color:160 60% 3%;--text-muted:var(--text-2);--ink-green:#34d399;--ink-yellow:#fbbf24;--ink-red:#f98787;--ink-blue:#75b1fb;--ink-accent:#34d399}
[data-theme="solarized"]{--bg-0:#fdf6e3;--bg-1:#eee8d5;--bg-2:#e0dac4;--surface:#fffbf0;--surface-hover:#eee8d5;--text-0:#073642;--text-1:#2a5a66;--text-2:#556b72;--accent:#268bd2;--accent-dim:rgba(38,139,210,.12);--green:#859900;--yellow:#b58900;--red:#dc322f;--blue:#268bd2;--glass:rgba(253,246,227,.85);--glass-border:rgba(0,0,0,.08);--border:rgba(0,0,0,.09);--map-filter:sepia(.35) saturate(.8);
  --shadow-color:40 30% 28%;--text-muted:var(--text-2);--ink-green:#5f6d00;--ink-yellow:#826200;--ink-red:#bf2320;--ink-blue:#1d6ba2;--ink-accent:#1d6ba2}
[data-theme="dracula"]{--bg-0:#282a36;--bg-1:#44475a;--bg-2:#6272a4;--surface:#282a36;--surface-hover:#44475a;--text-0:#f8f8f2;--text-1:#e2e2dc;--text-2:#c9c9c3;--accent:#bd93f9;--accent-dim:rgba(189,147,249,.15);--green:#50fa7b;--yellow:#f1fa8c;--red:#ff5555;--blue:#8be9fd;--glass:rgba(40,42,54,.85);--glass-border:rgba(255,255,255,.1);--border:rgba(255,255,255,.1);--map-filter:invert(1) hue-rotate(180deg) brightness(.85) contrast(.9);
  --shadow-color:230 30% 6%;--text-muted:var(--text-2);--ink-green:#50fa7b;--ink-yellow:#f1fa8c;--ink-red:#ff9d9d;--ink-blue:#8be9fd;--ink-accent:#cba9fa}
[data-theme="monokai"]{--bg-0:#272822;--bg-1:#3e3d32;--bg-2:#49483e;--surface:#272822;--surface-hover:#3e3d32;--text-0:#f8f8f2;--text-1:#e6db74;--text-2:#bbb8aa;--accent:#a6e22e;--accent-dim:rgba(166,226,46,.15);--green:#a6e22e;--yellow:#e6db74;--red:#f92672;--blue:#66d9ef;--glass:rgba(39,40,34,.85);--glass-border:rgba(255,255,255,.1);--border:rgba(255,255,255,.1);--map-filter:invert(1) hue-rotate(180deg) brightness(.85) contrast(.9);
  --shadow-color:60 20% 4%;--text-muted:var(--text-2);--ink-green:#a6e22e;--ink-yellow:#e6db74;--ink-red:#fb80ad;--ink-blue:#66d9ef;--ink-accent:#a6e22e}
[data-theme="forest"]{--bg-0:#1c2621;--bg-1:#243029;--bg-2:#2e3b33;--surface:#1c2621;--surface-hover:#243029;--text-0:#e2eedb;--text-1:#a4bea3;--text-2:#90a98f;--accent:#65a153;--accent-dim:rgba(101,161,83,.15);--green:#65a153;--yellow:#bdae49;--red:#c65e5e;--blue:#559db2;--glass:rgba(28,38,33,.85);--glass-border:rgba(255,255,255,.08);--border:rgba(255,255,255,.08);--map-filter:invert(1) hue-rotate(120deg) brightness(.8) contrast(.9);
  --shadow-color:150 30% 4%;--text-muted:var(--text-2);--ink-green:#73ae61;--ink-yellow:#bdae49;--ink-red:#d38484;--ink-blue:#69a8bb;--ink-accent:#73ae61}
[data-theme="ocean"]{--bg-0:#0f1c2b;--bg-1:#17263b;--bg-2:#213550;--surface:#0f1c2b;--surface-hover:#17263b;--text-0:#e0f2fe;--text-1:#bae6fd;--text-2:#7dd3fc;--accent:#0ea5e9;--accent-dim:rgba(14,165,233,.15);--green:#10b981;--yellow:#f59e0b;--red:#ef4444;--blue:#3b82f6;--glass:rgba(15,28,43,.85);--glass-border:rgba(255,255,255,.08);--border:rgba(255,255,255,.08);--map-filter:invert(1) hue-rotate(190deg) brightness(.85) contrast(.9);
  --shadow-color:210 60% 3%;--text-muted:var(--text-2);--ink-green:#10b981;--ink-yellow:#f59e0b;--ink-red:#f15e5e;--ink-blue:#5693f7;--ink-accent:#0ea5e9}
[data-theme="rose-pine"]{--bg-0:#191724;--bg-1:#1f1d2e;--bg-2:#26233a;--surface:#191724;--surface-hover:#1f1d2e;--text-0:#e0def4;--text-1:#908caa;--text-2:#918ea5;--accent:#c4a7e7;--accent-dim:rgba(196,167,231,.15);--green:#31748f;--yellow:#f6c177;--red:#eb6f92;--blue:#9ccfd8;--glass:rgba(25,23,36,.85);--glass-border:rgba(255,255,255,.08);--border:rgba(255,255,255,.08);--map-filter:invert(1) hue-rotate(180deg) brightness(.85) contrast(.9);
  --shadow-color:265 40% 3%;--text-1:#b5b1c9;--text-muted:var(--text-2);--ink-green:#4097ba;--ink-yellow:#f6c177;--ink-red:#eb6f92;--ink-blue:#9ccfd8;--ink-accent:#c4a7e7}
[data-theme="nord"]{--bg-0:#2e3440;--bg-1:#3b4252;--bg-2:#434c5e;--surface:#2e3440;--surface-hover:#3b4252;--text-0:#eceff4;--text-1:#e5e9f0;--text-2:#c2cad8;--accent:#88c0d0;--accent-dim:rgba(136,192,208,.15);--green:#a3be8c;--yellow:#ebcb8b;--red:#bf616a;--blue:#81a1c1;--glass:rgba(46,52,64,.85);--glass-border:rgba(255,255,255,.1);--border:rgba(255,255,255,.1);--map-filter:invert(1) hue-rotate(180deg) brightness(.85) contrast(.9);
  --shadow-color:220 25% 8%;--text-muted:var(--text-2);--ink-green:#b3cc9d;--ink-yellow:#ebcb8b;--ink-red:#d9a2a7;--ink-blue:#9eb6cf;--ink-accent:#8bc2d1}

/* ---- base ---------------------------------------------------------------- */
*{box-sizing:border-box;margin:0;padding:0}
html,body{height:100%;max-width:100vw;overflow-x:hidden}
body{font-family:var(--font-sans);background:var(--bg-0);color:var(--text-0);min-height:100dvh;
  font-size:var(--fs-400);line-height:var(--lh-body);-webkit-font-smoothing:antialiased;
  display:flex;flex-direction:column;overflow-x:hidden;
  transition:background var(--dur-4) var(--ease-standard),color var(--dur-3) var(--ease-standard)}

/* Anything that ticks gets tabular figures. A proportional "1" is half the
   width of a "4", so a countdown ticking 4:11 -> 4:10 physically moved. */
.eta,.cd-big,.tile b,.det b,.modal-stat-val,.conn-time,.conn-wait,.sub-arr-time,.sub-arr-eta,
.sub-route-time-clock,.sub-route-time-eta,.stop-id-badge,.detail-stop-id,.arr-times,.map-stop-wait,
.analytics-stat-pill strong,.rtag,td.n,.live,.notif-volume-val{
  font-variant-numeric:tabular-nums;font-feature-settings:"tnum" 1}

.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0}

/* One focus ring for the whole app. Several controls used to drop the outline
   and re-tint their border instead, which is invisible on a dark theme and
   disappears entirely against a same-coloured neighbour. The outline is drawn
   outside the box with a gap, so it reads on any fill. */
:where(a,button,input,select,textarea,summary,[tabindex]):focus-visible,
.brand-live:focus-visible,.stop-fold:focus-visible,.arr:focus-visible,
.conn-row:focus-visible,.alert-item:focus-visible,.cd:focus-visible{
  outline:var(--focus-w) solid var(--focus);
  outline-offset:var(--focus-offset);
  border-radius:var(--radius-xs)}
:where(button,.chipbtn,.route-chip,.pill-nav button,.segmented button,.btn,.icon,
  .settings-trigger,.notif-trigger,.auth-icon,.quick-add):focus-visible{border-radius:inherit}

/* Honour the OS switch globally rather than per-animation. Transitions are
   flattened to 1ms rather than 0 so transitionend handlers still fire. */
@media(prefers-reduced-motion:reduce){
  *,*::before,*::after{
    animation-duration:1ms!important;animation-iteration-count:1!important;
    transition-duration:1ms!important;scroll-behavior:auto!important}
}

/* ---- hero ---------------------------------------------------------------- */
/* Shorter than it was: the legend strip came out to buy vertical space and a
   decorative photo should not quietly take it back. */
.hero{position:relative;height:clamp(84px,10vh,116px);flex:none;overflow:hidden;background:#1a1420}
.hero-art{width:100%;height:100%;display:block;object-fit:cover;object-position:center 58%}
/* Scrim so the photo lands into the topbar instead of butting against it. */
.hero::after{content:'';position:absolute;inset:auto 0 0;height:38%;pointer-events:none;
  background:linear-gradient(to bottom,transparent,color-mix(in srgb,var(--bg-0) 55%,transparent))}
.hero-overlay{position:absolute;inset:0;background:linear-gradient(90deg,rgba(0,0,0,.62) 0%,rgba(0,0,0,.24) 48%,transparent 100%)}
.hero-title{position:absolute;left:var(--sp-7);bottom:var(--sp-5);display:flex;align-items:center;gap:var(--sp-5)}
/* Text on a photograph cannot be measured against a token, so it gets its own
   scrim (.hero-overlay) plus a shadow rather than relying on either alone. */
.hero-title b{font-size:clamp(17px,2.4vw,23px);font-weight:700;color:#fff;letter-spacing:var(--ls-display);
  text-shadow:0 1px 2px rgba(0,0,0,.9),0 2px 12px rgba(0,0,0,.7)}
.badge-live{background:var(--ink-red);color:var(--surface);font-size:var(--fs-100);font-weight:800;
  letter-spacing:var(--ls-caps);padding:var(--sp-1) var(--sp-4);border-radius:var(--radius-xs)}

/* ---- topbar -------------------------------------------------------------- */
.topbar{background:var(--glass);backdrop-filter:blur(20px) saturate(1.6);-webkit-backdrop-filter:blur(20px) saturate(1.6);
  border-bottom:1px solid var(--glass-border);min-height:56px;display:flex;align-items:center;
  gap:var(--sp-5);padding:var(--sp-4) var(--sp-6);flex:none;flex-wrap:wrap;position:relative;z-index:100}
.brand{font-size:var(--fs-500);font-weight:700;letter-spacing:var(--ls-tight);white-space:nowrap}
.brand span{color:var(--ink-accent)}
.live{display:inline-flex;align-items:center;gap:var(--sp-3);font-size:var(--fs-200);color:var(--text-muted);font-family:var(--font-mono)}
@keyframes pulse{50%{opacity:.35}}

.brandwrap{display:flex;align-items:center;gap:var(--sp-4)}
.brandwrap .thumb{width:34px;height:34px;border-radius:var(--radius-sm);flex:none;display:grid;place-items:center;
  background:var(--accent);color:var(--on-accent)}
.brandwrap .thumb svg{width:20px;height:20px}
.brandwrap .sub{font-size:var(--fs-200);color:var(--text-muted);line-height:var(--lh-tight)}
.livechip{display:inline-flex;align-items:center;gap:var(--sp-3);background:var(--tint);border-radius:var(--radius-full);
  padding:var(--sp-2) var(--sp-5);font-size:var(--fs-100);font-weight:700;letter-spacing:var(--ls-caps);
  color:var(--text-1);text-transform:uppercase}

/* Everything on the right of the bar holds its size; the search field is the
   only thing allowed to give ground. Without this the settings trigger was the
   last item in the row and got squeezed off the edge of a 390px screen. */
.topright>*{flex:none}
.brand-live{display:inline-flex;align-items:center;gap:var(--sp-3);padding:var(--sp-2) var(--sp-4);
  border-radius:var(--radius-sm);cursor:pointer;user-select:none;
  transition:background var(--dur-1) var(--ease-standard)}
.brand-live:hover{background:var(--surface-hover)}
.brand-name{font-size:var(--fs-400);font-weight:700;letter-spacing:var(--ls-tight);color:var(--text-0);white-space:nowrap}
.brand-name span{color:var(--ink-accent)}
.live-text{display:none!important}

.topright{margin-left:auto;display:flex;align-items:center;gap:var(--sp-4);flex:1 1 auto;justify-content:flex-end;min-width:0}
.who{font-size:var(--fs-200);color:var(--text-muted);max-width:150px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* ---- tab bar ------------------------------------------------------------- */
.pill-nav{display:flex;background:var(--tint);border-radius:var(--radius-full);padding:3px;gap:2px}
.pill-nav button{font-family:inherit;font-size:var(--fs-400);font-weight:600;color:var(--text-muted);
  padding:var(--sp-3) var(--sp-6);border-radius:var(--radius-full);border:none;background:transparent;cursor:pointer;
  transition:color var(--dur-1) var(--ease-standard),background var(--dur-2) var(--ease-standard)}
.pill-nav button:hover{color:var(--text-0)}
.pill-nav button.on{color:var(--on-accent);background:var(--accent);box-shadow:var(--shadow-1)}

/* ---- buttons and inputs -------------------------------------------------- */
.btn{background:var(--accent);color:var(--on-accent);border:none;border-radius:var(--radius-full);
  padding:var(--sp-4) var(--sp-7);font-family:inherit;font-size:var(--fs-400);font-weight:600;cursor:pointer;
  transition:filter var(--dur-1) var(--ease-standard),transform var(--dur-1) var(--ease-standard),box-shadow var(--dur-2) var(--ease-standard)}
.btn:hover{filter:brightness(1.08);box-shadow:var(--shadow-2)}
.btn:active{transform:translateY(1px)}
.btn.sm{padding:var(--sp-3) var(--sp-5);font-size:var(--fs-300)}
.icon{background:var(--tint);border:1px solid var(--border);color:var(--text-1);border-radius:var(--radius-full);
  width:30px;height:30px;font-size:var(--fs-500);cursor:pointer;line-height:1;
  transition:background var(--dur-1) var(--ease-standard),color var(--dur-1) var(--ease-standard),border-color var(--dur-1) var(--ease-standard)}
.icon:hover{background:var(--tint-2);color:var(--text-0);border-color:var(--accent)}
/* #routeFilter keeps the old topbar cap. Theme lives in .settings-drop now —
   its width comes from .settings-select, not this leftover. */
#routeFilter{background:var(--tint);color:var(--text-1);border:1px solid var(--border);
  border-radius:var(--radius-full);padding:var(--sp-3) var(--sp-5);font-family:inherit;font-size:var(--fs-300);
  cursor:pointer;max-width:170px}
.settings-drop select.theme{max-width:none;width:100%}

/* Search: icon inside the field, so the affordance does not need a label. */
.topright>.search-wrap{position:relative;display:flex;align-items:center;flex:1 1 260px;min-width:120px;max-width:340px}
.search-wrap{position:relative;display:flex;align-items:center}
.search-ico{position:absolute;left:var(--sp-5);width:15px;height:15px;color:var(--text-muted);pointer-events:none;
  display:grid;place-items:center}
.search-ico svg{width:100%;height:100%}
.search-gps{position:absolute;right:var(--sp-3);display:grid;place-items:center;width:32px;height:32px;
  border:0;border-radius:var(--radius-full);background:transparent;color:var(--text-muted);cursor:pointer;padding:0}
.search-gps:hover,.search-gps:focus-visible{color:var(--ink-accent,var(--accent));outline:none;background:var(--accent-dim)}
.search{width:100%;background:var(--tint);border:1px solid var(--border);color:var(--text-0);
  border-radius:var(--radius-full);padding:var(--sp-4) var(--sp-9) var(--sp-4) var(--sp-9);
  font-family:inherit;font-size:var(--fs-400);
  transition:background var(--dur-2) var(--ease-standard),border-color var(--dur-2) var(--ease-standard),box-shadow var(--dur-2) var(--ease-standard)}
.search::placeholder{color:var(--text-muted)}
.search:focus{border-color:var(--accent);background:var(--surface);box-shadow:0 0 0 3px var(--accent-dim)}
.search-wrap:focus-within .search-ico{color:var(--ink-accent)}

/* "Add stop" is the one action on the bar that creates something, so it is the
   only outlined control up there. */
.quick-add{display:inline-flex;align-items:center;gap:var(--sp-3);flex:none;
  background:var(--fill-accent);border:1px solid color-mix(in srgb,var(--accent) 45%,transparent);
  color:var(--ink-accent);border-radius:var(--radius-full);padding:var(--sp-4) var(--sp-5);
  font-family:inherit;font-size:var(--fs-300);font-weight:600;cursor:pointer;white-space:nowrap;
  transition:background var(--dur-1) var(--ease-standard),border-color var(--dur-1) var(--ease-standard),transform var(--dur-1) var(--ease-standard)}
.quick-add svg{width:15px;height:15px;flex:none}
.quick-add:hover{background:var(--accent);border-color:var(--accent);color:var(--on-accent)}
.quick-add:active{transform:translateY(1px)}

/* ---- subbar -------------------------------------------------------------- */
.subbar{display:flex;gap:var(--sp-4);align-items:center;padding:var(--sp-4) var(--sp-6);
  border-bottom:1px solid var(--border);background:var(--bg-1);flex:none;flex-wrap:wrap;min-height:48px}
/* Own row under the route chips so Sort / Saved / Add span the width instead of
   huddling at the trailing edge. */
.subbar .right{margin-left:0;flex:1 1 100%;display:flex;gap:var(--sp-4);align-items:stretch}
.subbar .right > *{flex:1 1 0;min-width:0;justify-content:center}
.chipbtn{background:transparent;border:1px solid var(--border);color:var(--text-muted);border-radius:var(--radius-full);
  padding:var(--sp-4) var(--sp-6);font-family:inherit;font-size:var(--fs-400);font-weight:600;cursor:pointer;
  white-space:nowrap;display:inline-flex;align-items:center;gap:var(--sp-3);
  transition:color var(--dur-1) var(--ease-standard),border-color var(--dur-1) var(--ease-standard),background var(--dur-1) var(--ease-standard)}
.chipbtn:hover{color:var(--text-0);border-color:var(--accent)}
.chipbtn.on{color:var(--on-accent);background:var(--accent);border-color:var(--accent)}

.chips{display:flex;gap:var(--sp-3);align-items:center;overflow-x:auto;scrollbar-width:none;min-width:0}
.chips::-webkit-scrollbar{display:none}
.route-chip{background:var(--tint);border:1px solid transparent;color:var(--text-1);border-radius:var(--radius-full);
  padding:var(--sp-3) var(--sp-5);font-family:inherit;font-size:var(--fs-300);font-weight:600;cursor:pointer;
  white-space:nowrap;transition:background var(--dur-1) var(--ease-standard),color var(--dur-1) var(--ease-standard),border-color var(--dur-1) var(--ease-standard)}
.route-chip:hover{border-color:var(--accent)}
.route-chip.active{background:var(--accent);color:var(--on-accent);border-color:var(--accent)}

.sort-ico{width:16px;height:16px;color:currentColor;display:grid;place-items:center;flex:none}
.sort-ico svg{width:100%;height:100%}
.sort-cycle-label{font-size:var(--fs-300);font-weight:700;letter-spacing:var(--ls-caps);
  text-transform:uppercase}
.sort-menu{position:fixed;z-index:1200;background:var(--surface);border:1px solid var(--border);
  border-radius:var(--radius-md);box-shadow:var(--shadow-2);padding:var(--sp-2);display:flex;flex-direction:column;gap:2px}
.sort-menu[hidden]{display:none}
.sort-menu-opt{appearance:none;border:0;background:transparent;color:var(--text-0);text-align:left;
  font:inherit;font-size:var(--fs-300);font-weight:600;padding:var(--sp-4) var(--sp-5);border-radius:var(--radius-sm);cursor:pointer}
.sort-menu-opt:hover,.sort-menu-opt:focus-visible{background:var(--accent-dim);outline:none}
.sort-menu-opt.on{background:var(--accent);color:var(--on-accent)}
.collapse-all-ico{font-size:var(--fs-400);line-height:1}
.locate-ico{font-size:var(--fs-500);line-height:1;font-weight:700}
.th-sort{appearance:none;border:0;background:transparent;color:inherit;font:inherit;font-weight:700;
  cursor:pointer;padding:0;text-align:inherit}
.th-sort:hover{color:var(--ink-accent,var(--accent))}
th[aria-sort="ascending"] .th-sort::after{content:" \25B2";font-size:0.75em;opacity:.8}
th[aria-sort="descending"] .th-sort::after{content:" \25BC";font-size:0.75em;opacity:.8}

.alertcount{display:inline-flex;align-items:center;gap:var(--sp-3);background:var(--fill-yellow);
  color:var(--ink-yellow);border-radius:var(--radius-full);padding:var(--sp-2) var(--sp-5);
  font-size:var(--fs-300);font-weight:700}

/* ---- views --------------------------------------------------------------- */
main{flex:1;min-height:0;position:relative}
.view{position:absolute;inset:0;display:none;overflow:auto}
.view.on{display:block}
#map{position:absolute;inset:0;background:var(--bg-0)}
.leaflet-container{background:var(--bg-0);font-family:var(--font-sans)}
.leaflet-tile-pane{filter:var(--map-filter)}
.leaflet-popup-content-wrapper,.leaflet-popup-tip{background:var(--surface);color:var(--text-0);border:1px solid var(--border)}
.leaflet-popup-content-wrapper{border-radius:var(--radius-md)}
/* Bottom-center so the pill never covers Leaflet's top-left zoom control. */
.map-hint{position:absolute;top:auto;bottom:var(--sp-8);left:50%;transform:translateX(-50%);z-index:500;
  background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-full);
  padding:var(--sp-3) var(--sp-6);font-size:var(--fs-300);color:var(--text-1);box-shadow:var(--shadow-2);
  max-width:calc(100% - var(--sp-9));white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  pointer-events:none}
.map-hint[hidden]{display:none}
/* opacity cut the effective contrast of --text-0 on --bg-2 below 3:1 in light themes */
.heatmap-empty{color:var(--text-0)!important}

/* The feed is a single column of cards, so its width is a reading measure, not
   a container: ~600px keeps a route name and its countdown on one line at
   desktop without stranding them at opposite ends of a 1440px screen.
   The other two views are grids and get the room they need instead. */
.pad{padding:var(--sp-7) var(--sp-6);max-width:600px;margin:0 auto}
#v-countdown .pad{max-width:1180px}
/* 980px lands the eight stat tiles as 4x2 rather than 7-and-a-widow, and still
   gives the analytics charts their two columns. */
#v-history .pad{max-width:980px}

/* Past ~1180px a single 600px column leaves two thirds of the screen empty, so
   the feed becomes two columns of cards rather than one column of air. Below
   that it stays a single reading measure. */
@media(min-width:1180px){
  #v-stops .pad{max-width:1180px}
  #feed{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--sp-5);align-items:start}
  #feed>.stop,#feed>.skel{margin-bottom:0}
  #feed>.prompt{grid-column:1/-1}
}

/* ---- stop card ----------------------------------------------------------- */
.stop{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-lg);
  box-shadow:var(--shadow-1);margin-bottom:var(--sp-5);overflow:hidden;
  transition:box-shadow var(--dur-2) var(--ease-standard),border-color var(--dur-2) var(--ease-standard)}
.stop:hover{box-shadow:var(--shadow-2)}
.stop-head{display:flex;align-items:flex-start;gap:var(--sp-4);padding:var(--sp-5) var(--sp-6) var(--sp-5)}
/* Fold control is its own button so the save star is not nested-interactive. */
.stop-fold{display:flex;align-items:flex-start;gap:var(--sp-4);flex:1;min-width:0;
  background:transparent;border:none;color:inherit;font:inherit;text-align:left;cursor:pointer;
  padding:0;border-radius:var(--radius-xs)}
.stop-fold:hover{color:var(--text-0)}
.stop-fold:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.stop-fold .chev{margin-top:var(--sp-2);transform:rotate(90deg)}
.stop.collapsed .stop-fold .chev{transform:none}
.stop-fold-main{flex:1;min-width:0}
.stop-name{font-size:var(--fs-600);font-weight:700;color:var(--text-0);line-height:var(--lh-tight);letter-spacing:var(--ls-tight)}
.stop-sub{font-size:var(--fs-200);color:var(--text-muted);margin-top:var(--sp-1)}
.stop-meta{display:flex;align-items:center;gap:var(--sp-3);margin-top:var(--sp-3);flex-wrap:wrap}
.stop-id-badge{font-size:var(--fs-100);font-family:var(--font-mono);font-weight:700;color:var(--ink-accent);
  background:var(--fill-accent);padding:var(--sp-1) var(--sp-3);border-radius:var(--radius-xs);letter-spacing:0}
.stop-dir{display:inline-block;background:var(--fill-accent);color:var(--ink-accent);font-size:var(--fs-100);
  font-weight:800;letter-spacing:var(--ls-caps);text-transform:uppercase;padding:var(--sp-1) var(--sp-3);
  border-radius:var(--radius-xs)}
.walk{display:inline-flex;align-items:center;gap:var(--sp-2);font-size:var(--fs-200);color:var(--text-muted);
  margin-left:auto;white-space:nowrap;padding-top:var(--sp-1)}
.walk svg{width:12px;height:12px;flex:none}
.fav{margin-left:var(--sp-2);background:transparent;border:none;color:var(--text-muted);font-size:var(--fs-600);
  cursor:pointer;line-height:1;padding:0 var(--sp-1);border-radius:var(--radius-xs);flex:none;
  transition:color var(--dur-1) var(--ease-standard),transform var(--dur-2) var(--ease-out)}
.fav:hover{transform:scale(1.15)}
.fav.on{color:var(--ink-yellow)}

/* Column header. Its widths are the same tokens the rows use, so the labels sit
   over the columns they name instead of near them. */
.arrs-col-head{display:flex;align-items:center;gap:var(--sp-5);
  padding:var(--sp-3) calc(var(--sp-6) + 10px + var(--sp-5)) var(--sp-3) var(--sp-6);
  font-size:var(--fs-100);font-weight:700;text-transform:uppercase;letter-spacing:var(--ls-caps);
  color:var(--text-muted);background:var(--bg-1);border-top:1px solid var(--border);border-bottom:1px solid var(--border)}
.col-lbl-route{flex:1;min-width:0}
.col-lbl-status{width:76px;text-align:center;flex:none;margin:0}
.col-lbl-eta{width:86px;text-align:right;flex:none;margin:0}

/* ---- arrival row --------------------------------------------------------- */
/* Status reads three ways at once — the left border for peripheral scanning,
   the pill for the word, the countdown's colour for the glance. */
.arrs{list-style:none}
.arr{border-top:1px solid var(--border);border-left:3px solid transparent;padding:0;margin:0;
  list-style:none;transition:background var(--dur-1) var(--ease-standard)}
.arr:first-child{border-top:none}
.arr:hover,.arr:focus-within{background:var(--surface-hover)}
.arr.early{border-left-color:var(--blue)}
.arr.ontime{border-left-color:var(--green)}
.arr.slight{border-left-color:var(--yellow)}
.arr.late,.arr.verylate{border-left-color:var(--red)}
.arr.sched{border-left-color:var(--text-muted)}
.arr-expand{appearance:none;border:0;background:transparent;color:inherit;font:inherit;width:100%;
  display:flex;align-items:center;gap:var(--sp-5);min-height:60px;text-align:left;cursor:pointer;
  padding:var(--sp-5) var(--sp-6) var(--sp-5) calc(var(--sp-6) - 3px)}
.arr-expand:focus-visible{outline:var(--focus-w) solid var(--ring,var(--text-0));outline-offset:var(--focus-offset)}
.arr-mid{flex:1;min-width:0}
.arr-sign{font-size:var(--fs-500);font-weight:600;color:var(--text-0);line-height:var(--lh-tight);
  letter-spacing:var(--ls-tight);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* flex:0 1 auto + min-width keeps "h:mm AM" from losing to flex:none chips. */
.arr-times{font-size:var(--fs-200);color:var(--text-muted);margin-top:0;line-height:var(--lh-snug);
  flex:0 1 auto;min-width:5.75em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block}
.arr-meta{display:flex;align-items:center;gap:var(--sp-4);margin-top:var(--sp-2);min-width:0;flex-wrap:wrap}

/* Fixed-width status column. The pill's text ranges from "SCHED" to "+12 MIN";
   letting it size to content pushed the countdown left and right every refresh. */
.pill{flex:none;font-size:var(--fs-100);font-weight:700;padding:var(--sp-1) var(--sp-3);
  border-radius:var(--radius-full);text-transform:uppercase;letter-spacing:var(--ls-caps);
  line-height:1.6;text-align:center;white-space:nowrap}
.arr-expand>.pill,.arr>.pill{width:76px}
.pill.sched{background:var(--tint);color:var(--text-muted)}
.pill.early{background:var(--fill-blue);color:var(--ink-blue)}
.pill.ontime{background:var(--fill-green);color:var(--ink-green)}
.pill.slight{background:var(--fill-yellow);color:var(--ink-yellow)}
.pill.late{background:var(--fill-red);color:var(--ink-red)}
/* Only "very late" gets a solid fill — it is the one status worth shouting.
   Ink as the fill and --surface as the text guarantees the same ratio the ink
   was solved for, in every theme. */
.pill.verylate{background:var(--ink-red);color:var(--surface)}

/* The countdown is the reason the page exists: biggest thing in the row, mono,
   tabular, and the only element carrying status colour at size. */
.eta{flex:none;width:86px;text-align:right;font-family:var(--font-mono);font-size:var(--fs-700);
  font-weight:500;color:var(--text-0);letter-spacing:var(--ls-num);line-height:var(--lh-flat);
  font-variant-numeric:tabular-nums}
.eta.early{color:var(--ink-blue)}.eta.ontime{color:var(--ink-green)}.eta.slight{color:var(--ink-yellow)}
.eta.late,.eta.verylate{color:var(--ink-red)}.eta.sched{color:var(--text-1)}
.chev{color:var(--text-muted);font-size:var(--fs-500);flex:none;width:10px;text-align:center;
  transition:transform var(--dur-2) var(--ease-out)}
.arr.open .chev{transform:rotate(90deg)}

.crowd{display:inline-block;width:42px;height:5px;border-radius:var(--radius-full);background:var(--tint-2);overflow:hidden}
.crowd>span{display:block;height:100%;background:var(--accent)}
.stop-collapsed-chips{display:flex;align-items:center;gap:var(--sp-2);flex-wrap:wrap;margin-top:var(--sp-3);max-width:100%}
.stop-collapsed-chips .rchip{font-size:var(--fs-100,9.5px);min-width:0;padding:2px 6px;line-height:1.2}
.rchip-next .rchip-short{display:none}
.rchip-more{background:var(--tint);color:var(--text-1);border:1px solid var(--border)}
@media (max-width:360px){
  .rchip-next .rchip-full{display:none}
  .rchip-next .rchip-short{display:inline}
}
.rchip{flex:none;min-width:34px;text-align:center;color:#fff;font-family:var(--font-mono);font-size:var(--fs-200);
  font-weight:600;padding:var(--sp-1) var(--sp-3);border-radius:var(--radius-xs);
  text-shadow:0 1px 2px rgba(0,0,0,.85)}
.catch{font-size:var(--fs-100);font-weight:700;margin-top:var(--sp-1)}
.catch.go{color:var(--ink-green)}.catch.maybe{color:var(--ink-yellow)}.catch.no{color:var(--ink-red)}
.catch.missed{color:var(--text-muted);text-decoration:line-through}
.empty{font-size:var(--fs-400);color:var(--text-muted);padding:var(--sp-7) var(--sp-6);text-align:center}
.stop-dead,.stop-stale{opacity:.92;border-color:var(--warn, #c47a00)}
.stop-dead .stop-fold:disabled,.stop-stale .stop-fold:disabled{cursor:default;opacity:1}
.stop-dead-badge{display:inline-block;margin-left:var(--sp-3);padding:0.1em 0.45em;border-radius:999px;
  font-size:var(--fs-200);font-weight:600;letter-spacing:var(--ls-wide);text-transform:uppercase;
  color:var(--warn-ink, #5c3b00);background:var(--warn-bg, #f5e2b8)}
.stop-dead-msg{font-size:var(--fs-400);color:var(--text-muted);padding:var(--sp-6);
  border-top:1px solid var(--border)}

/* ---- arrival detail ------------------------------------------------------ */
.arr-detail{padding:0 var(--sp-6) var(--sp-5);border-top:1px solid var(--border);background:var(--bg-1)}
.det-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(108px,1fr));gap:var(--sp-5);padding-top:var(--sp-5)}
.det{min-width:0}
.det b{display:block;font-family:var(--font-mono);font-size:var(--fs-400);color:var(--text-0);line-height:var(--lh-tight)}
.det i{font-style:normal;font-size:var(--fs-100);color:var(--text-muted);text-transform:uppercase;
  letter-spacing:var(--ls-caps);font-weight:700}

/* ---- empty / loading states ---------------------------------------------- */
.prompt{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-lg);
  padding:var(--sp-10) var(--sp-8);text-align:center;box-shadow:var(--shadow-1)}
.prompt h2{font-size:var(--fs-600);color:var(--text-0);margin-bottom:var(--sp-4);letter-spacing:var(--ls-tight)}
.prompt p{font-size:var(--fs-400);color:var(--text-muted);margin-bottom:var(--sp-7)}
.skel{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-lg);
  padding:var(--sp-6);margin-bottom:var(--sp-5)}
/* The skeleton mirrors the real card's metrics, so nothing jumps when the data
   lands and replaces it. */
.skel-head{height:17px;width:58%;background:var(--tint-2);border-radius:var(--radius-xs);margin-bottom:var(--sp-5)}
.skel-bar{height:12px;background:var(--tint-2);border-radius:var(--radius-xs);margin-bottom:var(--sp-4)}
@media(prefers-reduced-motion:no-preference){
  .skel-head,.skel-bar{animation:shimmer 1.4s ease-in-out infinite}
  @keyframes shimmer{50%{opacity:.45}}}

/* ---- search panel -------------------------------------------------------- */
.panel{position:fixed;top:0;right:0;bottom:0;width:min(400px,100%);background:var(--bg-1);
  border-left:1px solid var(--border);box-shadow:var(--shadow-3);padding:var(--sp-6);z-index:200;
  transform:translateX(102%);transition:transform var(--dur-3) var(--ease-out);
  display:flex;flex-direction:column;gap:var(--sp-5)}
.panel.open{transform:none}
.panel-head{display:flex;align-items:center;gap:var(--sp-5)}
.panel-head strong{font-size:var(--fs-500);color:var(--text-0)}
.panel-head .icon{margin-left:auto}
#q{background:var(--tint);border:1px solid var(--border);color:var(--text-0);border-radius:var(--radius-full);
  padding:var(--sp-5) var(--sp-6);font-family:inherit;font-size:var(--fs-400);
  transition:border-color var(--dur-2) var(--ease-standard),box-shadow var(--dur-2) var(--ease-standard)}
#q::placeholder{color:var(--text-muted)}
#q:focus{border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-dim)}
.results{list-style:none;overflow:auto;flex:1}
.res{display:flex;align-items:center;gap:var(--sp-5);padding:var(--sp-5) var(--sp-1);border-bottom:1px solid var(--border)}
.res-name{font-size:var(--fs-400);color:var(--text-0);font-weight:500}
.res-sub{font-size:var(--fs-200);color:var(--text-muted);margin-top:var(--sp-1)}
.res-routes{display:flex;flex-wrap:wrap;gap:var(--sp-2);margin-top:var(--sp-3)}
.rtag{font-family:var(--font-mono);font-size:var(--fs-100);font-weight:500;padding:var(--sp-1) var(--sp-3);
  border-radius:var(--radius-xs);background:var(--tint);color:var(--text-1)}
.rtag.rail{background:var(--fill-accent);color:var(--ink-accent)}
.loc-banner{font-size:var(--fs-300);color:var(--text-1);background:var(--tint);border:1px solid var(--border);
  border-radius:var(--radius-md);padding:var(--sp-4) var(--sp-5)}
.loc-banner .linkish,.zip-form .btn{cursor:pointer}
.linkish{appearance:none;border:0;background:none;color:var(--ink-accent,var(--accent));font:inherit;font-weight:700;padding:0;text-decoration:underline}
.browse-chips{display:flex;flex-wrap:wrap;gap:var(--sp-2)}
.browse-chip{appearance:none;border:1px solid var(--border);background:var(--tint);color:var(--text-1);
  border-radius:var(--radius-full);padding:var(--sp-2) var(--sp-4);font:inherit;font-size:var(--fs-200);font-weight:600;cursor:pointer}
.browse-chip.on{background:var(--accent);color:var(--on-accent);border-color:var(--accent)}
.route-res{cursor:pointer}
.route-swatch{flex:none;width:12px;height:12px;border-radius:2px;align-self:center}
.freq-badge{display:inline-block;margin-left:var(--sp-2);font-size:var(--fs-100);font-weight:700;
  color:var(--ink-accent,var(--accent));background:var(--accent-dim);border-radius:var(--radius-xs);padding:1px 6px}
.res-actions{margin-left:auto;flex:none}
.res-banner{list-style:none;font-size:var(--fs-300);color:var(--text-2);padding:var(--sp-3) var(--sp-1)}
.zip-form{list-style:none;display:flex;flex-wrap:wrap;gap:var(--sp-3);align-items:center;padding:var(--sp-4) var(--sp-1)}
.zip-form input{flex:1 1 120px;min-width:0;background:var(--tint);border:1px solid var(--border);color:var(--text-0);
  border-radius:var(--radius-full);padding:var(--sp-4) var(--sp-5);font:inherit}

/* ---- history: stat tiles and tables -------------------------------------- */
.tiles{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:var(--sp-5);margin-bottom:var(--sp-7)}
.tile{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-md);
  padding:var(--sp-5) var(--sp-6);box-shadow:var(--shadow-1)}
.tile b{display:block;font-family:var(--font-mono);font-size:var(--fs-800);font-weight:500;
  line-height:var(--lh-tight);letter-spacing:var(--ls-num)}
.tile i{font-style:normal;font-size:var(--fs-100);color:var(--text-muted);text-transform:uppercase;
  letter-spacing:var(--ls-caps);font-weight:700}
.tile.ok b{color:var(--ink-green)}.tile.late b{color:var(--ink-red)}.tile.early b{color:var(--ink-blue)}
.tile.warn b{color:var(--ink-yellow)}.tile.accent b{color:var(--ink-accent)}
.card{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-md);
  overflow:hidden;box-shadow:var(--shadow-1)}
table{width:100%;border-collapse:collapse;font-size:var(--fs-400)}
th,td{text-align:left;padding:var(--sp-4) var(--sp-5);border-bottom:1px solid var(--border)}
tr:last-child td{border-bottom:none}
th{font-size:var(--fs-100);text-transform:uppercase;letter-spacing:var(--ls-caps);color:var(--text-muted);
  font-weight:700;position:sticky;top:0;background:var(--surface)}
td.n{text-align:right;font-family:var(--font-mono)}
.chip{display:inline-block;width:9px;height:9px;border-radius:2px;margin-right:var(--sp-3)}
.note{font-size:var(--fs-400);color:var(--text-1);background:var(--surface);border:1px solid var(--border);
  border-left:3px solid var(--accent);border-radius:var(--radius-sm);padding:var(--sp-5) var(--sp-6);margin-top:var(--sp-6)}
.segmented{display:inline-flex;background:var(--tint);border-radius:var(--radius-full);padding:3px;gap:2px;margin-bottom:var(--sp-6)}
.segmented button{border:none;background:transparent;color:var(--text-muted);font-family:inherit;
  font-size:var(--fs-400);font-weight:600;padding:var(--sp-3) var(--sp-6);border-radius:var(--radius-full);cursor:pointer;
  transition:color var(--dur-1) var(--ease-standard),background var(--dur-2) var(--ease-standard)}
.segmented button:hover{color:var(--text-0)}
.segmented button.on{background:var(--accent);color:var(--on-accent);box-shadow:var(--shadow-1)}

/* ---- countdown ----------------------------------------------------------- */
#cdContent{display:grid;gap:var(--sp-5);grid-template-columns:1fr}
@media(min-width:900px){
  /* One card per stop; at desktop width they tile rather than queueing down a
     600px column with the rest of the screen empty. */
  #cdContent{grid-template-columns:repeat(auto-fill,minmax(320px,1fr));align-items:start}
  #cdContent>.prompt{grid-column:1/-1}
}
.cd{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-lg);
  box-shadow:var(--shadow-1);padding:var(--sp-8) var(--sp-7);text-align:center;cursor:pointer;
  transition:border-color var(--dur-2) var(--ease-standard),box-shadow var(--dur-2) var(--ease-standard),transform var(--dur-2) var(--ease-standard)}
.cd:hover{border-color:var(--accent);box-shadow:var(--shadow-2);transform:translateY(-1px)}
.cd-stop{font-size:var(--fs-400);color:var(--text-muted);margin-bottom:var(--sp-2)}
.cd-route{font-size:var(--fs-600);font-weight:700;color:var(--text-0);margin-bottom:var(--sp-6);letter-spacing:var(--ls-tight)}
.cd-big{font-family:var(--font-mono);font-size:var(--fs-900);font-weight:500;line-height:var(--lh-flat);
  letter-spacing:var(--ls-display);font-variant-numeric:tabular-nums}
.cd-big.early{color:var(--ink-blue)}.cd-big.ontime{color:var(--ink-green)}.cd-big.slight{color:var(--ink-yellow)}
.cd-big.late,.cd-big.verylate{color:var(--ink-red)}.cd-big.sched{color:var(--text-1)}
.cd-meta{display:flex;gap:var(--sp-4);justify-content:center;align-items:center;flex-wrap:wrap;margin-top:var(--sp-6)}
.cd-crowd{height:6px;border-radius:var(--radius-full);background:var(--tint-2);overflow:hidden;
  margin:var(--sp-6) auto 0;max-width:240px}
.cd-crowd>span{display:block;height:100%;background:var(--accent);transition:width var(--dur-4) var(--ease-standard)}
.cd-next{font-size:var(--fs-300);color:var(--text-muted);margin-top:var(--sp-5)}
.cd .chev{display:inline-block;margin-top:var(--sp-4)}
.cd.open .chev{transform:rotate(90deg)}
.cd-detail{margin-top:var(--sp-6);text-align:left;border-top:1px solid var(--border);padding-top:var(--sp-5)}
.cd-header-row{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;
  gap:var(--sp-4);margin-bottom:var(--sp-6)}
.cd-seg{margin-bottom:0}
.cd-sort-wrap{display:inline-flex;align-items:center;gap:var(--sp-3);font-size:var(--fs-300)}
.cd-sort-select{background:var(--surface);color:var(--text-0);border:1px solid var(--border);
  border-radius:var(--radius-full);padding:var(--sp-3) var(--sp-5);font-size:var(--fs-300);font-weight:600;
  cursor:pointer;font-family:inherit}

/* ---- toasts -------------------------------------------------------------- */
.toasts{position:fixed;right:var(--sp-7);bottom:var(--sp-7);left:auto;z-index:300;display:flex;
  flex-direction:column;gap:var(--sp-4);max-width:340px;align-items:stretch}
.toast{display:flex;gap:var(--sp-5);text-align:left;background:var(--surface);border:1px solid var(--border);
  border-left:3px solid var(--accent);color:var(--text-0);border-radius:var(--radius-md);
  padding:var(--sp-5) var(--sp-5);box-shadow:var(--shadow-3);
  transition:opacity var(--dur-3) var(--ease-exit),transform var(--dur-3) var(--ease-exit)}
.toast .ico{flex:none;font-size:var(--fs-500);line-height:1.2}
.toast .tt{font-size:var(--fs-400);font-weight:600;color:var(--text-0);line-height:var(--lh-snug)}
.toast .ts{font-size:var(--fs-200);color:var(--text-muted);margin-top:var(--sp-1)}
.toast.warn{border-left-color:var(--yellow)}
.toast.go{border-left-color:var(--green)}
.toast.err{border-left-color:var(--red);color:var(--ink-red)}
.toast.out{opacity:0;transform:translateY(8px) scale(.98)}

/* ---- footer -------------------------------------------------------------- */
footer{padding:var(--sp-4) var(--sp-6);background:var(--glass);border-top:1px solid var(--glass-border);
  font-size:var(--fs-200);color:var(--text-muted);flex:none;text-align:center;line-height:var(--lh-snug)}
footer a{color:var(--text-1)}

/* ---- alerts strip -------------------------------------------------------- */
#alerts{flex:none}
#alerts.show{padding:var(--sp-4) var(--sp-6);background:var(--fill-yellow);border-bottom:1px solid var(--border)}
.alert{font-size:var(--fs-400);color:var(--text-1);margin-bottom:var(--sp-1)}

/* ---- settings dropdown --------------------------------------------------- */
.settings-wrap{position:relative;display:inline-flex}
.settings-trigger{width:34px;height:34px;border-radius:var(--radius-full);background:var(--tint);
  border:1px solid var(--border);color:var(--text-1);display:flex;align-items:center;justify-content:center;
  cursor:pointer;position:relative;flex:none;
  transition:background var(--dur-1) var(--ease-standard),color var(--dur-1) var(--ease-standard),border-color var(--dur-1) var(--ease-standard)}
.settings-trigger:hover,.settings-trigger[aria-expanded="true"]{background:var(--fill-accent);
  border-color:var(--accent);color:var(--ink-accent)}
.settings-drop{display:none;position:absolute;top:calc(100% + var(--sp-4));right:0;width:320px;
  background:var(--bg-1);border:1px solid var(--border);border-radius:var(--radius-md);
  box-shadow:var(--shadow-3);z-index:1500;padding:var(--sp-6);flex-direction:column;gap:var(--sp-6);
  box-sizing:border-box;transform-origin:top right;max-height:min(70vh,560px);overflow-y:auto}
.settings-drop.open{display:flex;animation:settingsDropIn var(--dur-2) var(--ease-out)}
@keyframes settingsDropIn{from{opacity:0;transform:scale(.97) translateY(-6px)}to{opacity:1;transform:none}}
.settings-section{display:flex;flex-direction:column;gap:var(--sp-4);padding-bottom:var(--sp-6);
  border-bottom:1px solid var(--border)}
.settings-section:last-child{padding-bottom:0;border-bottom:none}
.settings-label{font-size:var(--fs-100);font-weight:700;text-transform:uppercase;letter-spacing:var(--ls-caps);
  color:var(--text-muted);margin:0}
.settings-sublabel{font-size:var(--fs-200);font-weight:700;color:var(--text-1);margin:0}
.settings-hint{font-size:var(--fs-200);color:var(--text-muted);line-height:var(--lh-snug);margin:0}
.settings-header-row{display:flex;align-items:center;justify-content:space-between;gap:var(--sp-4)}
.settings-field{display:flex;flex-direction:column;gap:var(--sp-3)}
.settings-field-label{font-size:var(--fs-300);color:var(--text-1);font-weight:500}
.settings-identity{display:flex;align-items:center;gap:var(--sp-5)}
.settings-avatar{width:32px;height:32px;flex:none;display:grid;place-items:center;border-radius:var(--radius-full);
  background:var(--tint-2);color:var(--text-1)}
.settings-avatar svg{width:18px;height:18px}
.settings-identity-text{display:flex;flex-direction:column;min-width:0;flex:1}
.settings-identity-sub{font-size:var(--fs-200);color:var(--text-muted);line-height:var(--lh-snug)}
.settings-account{flex-direction:column;align-items:stretch}
.settings-user-info{display:flex;align-items:center;gap:var(--sp-4);font-size:var(--fs-400);font-weight:600;
  color:var(--text-0);overflow:hidden}
.settings-user-info .who,.settings-identity-text .who{display:inline-block;white-space:nowrap;overflow:hidden;
  text-overflow:ellipsis;max-width:170px;font-size:var(--fs-400);font-weight:600;color:var(--text-0)}
.settings-select{width:100%;background:var(--tint);border:1px solid var(--border);color:var(--text-0);
  border-radius:var(--radius-sm);padding:var(--sp-4) var(--sp-5);font-size:var(--fs-400);font-family:inherit;
  cursor:pointer;transition:border-color var(--dur-1) var(--ease-standard)}
.settings-select:hover{border-color:var(--accent)}
.auth-icon{display:inline-flex;align-items:center;justify-content:center;flex:none;border-radius:var(--radius-full);
  background:var(--tint);border:1px solid var(--border);color:var(--text-1);cursor:pointer;
  padding:var(--sp-3) var(--sp-5);font-size:var(--fs-300);font-weight:600;
  transition:background var(--dur-1) var(--ease-standard),color var(--dur-1) var(--ease-standard),border-color var(--dur-1) var(--ease-standard)}
.auth-icon:hover{background:var(--surface-hover);color:var(--text-0);border-color:var(--accent)}

/* ============================
   NOTIFICATION BELL (Req 1)
   ============================ */
.notif-wrap { position: relative; }
.notif-trigger {
  width: 32px;
  height: 32px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--bg-2);
  color: var(--text-muted);
  cursor: pointer;
  display: grid;
  place-items: center;
  font-size: var(--fs-500);
  transition: border-color var(--dur-2) var(--ease-standard),color var(--dur-2) var(--ease-standard),background var(--dur-2) var(--ease-standard);
  position: relative;
}
.notif-trigger:hover { border-color: var(--accent); color: var(--ink-accent); background: var(--accent-dim); }
.notif-trigger.has-unread { color: var(--ink-yellow); border-color: color-mix(in srgb, var(--yellow) 40%, transparent); }
.notif-badge {
  position: absolute;
  top: 3px;
  right: 3px;
  width: 8px;
  height: 8px;
  border-radius: var(--radius-full);
  background: var(--yellow);
  border: 2px solid var(--bg-1);
  display: none;
  animation: pulse 2s ease-in-out infinite;
}
.notif-trigger.has-unread .notif-badge { display: block; }

.notif-drop {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-float);
  width: 290px;
  display: none;
  z-index: 200;
}
.notif-drop.open { display: block; }

.notif-drop-head {
  padding: var(--sp-5) var(--sp-6) var(--sp-4);
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.notif-drop-head span {
  font-size: var(--fs-300);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-muted);
}
.notif-clear-btn {
  font-size: var(--fs-200);
  color: var(--text-muted);
  border: none;
  background: none;
  cursor: pointer;
  padding: var(--sp-1) var(--sp-3);
  border-radius: var(--radius-sm);
  transition: color 0.15s, background 0.15s;
  font-family: inherit;
}
.notif-clear-btn:hover { color: var(--text-0); background: var(--surface-hover); }

.notif-settings {
  padding: var(--sp-4) var(--sp-6);
  border-bottom: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}
.notif-toggle-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
}
.notif-toggle-label {
  font-size: var(--fs-300);
  color: var(--text-1);
  display: flex;
  align-items: center;
  gap: var(--sp-3);
}
.notif-switch {
  position: relative;
  width: 34px;
  height: 20px;
  flex-shrink: 0;
  display: inline-block;
}
.notif-switch input {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  margin: 0;
  cursor: pointer;
  z-index: 2;
}
.notif-switch-track {
  position: absolute;
  inset: 0;
  border-radius: var(--radius-full);
  background: var(--bg-2);
  border: 1px solid var(--border);
  transition: background 0.2s;
  pointer-events: none;
}
.notif-switch input:checked + .notif-switch-track { background: var(--accent); border-color: var(--accent); }
.notif-switch-track::after {
  content: '';
  position: absolute;
  top: 2px;
  left: 2px;
  width: 12px;
  height: 12px;
  border-radius: var(--radius-full);
  background: #fff;
  transition: transform 0.2s cubic-bezier(.16,1,.3,1);
}
.notif-switch input:checked + .notif-switch-track::after { transform: translateX(14px); }

.notif-volume-row {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  padding-left: var(--sp-1);
}
.notif-volume-label {
  font-size: var(--fs-200);
  color: var(--text-muted);
  white-space: nowrap;
}
.notif-volume {
  flex: 1;
  accent-color: var(--accent);
  height: 4px;
  cursor: pointer;
}

.notif-list {
  max-height: 200px;
  overflow-y: auto;
}
.notif-empty {
  padding: var(--sp-6) var(--sp-6);
  font-size: var(--fs-300);
  color: var(--text-muted);
  text-align: center;
  font-style: italic;
}
.notif-item {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-4);
  padding: var(--sp-4) var(--sp-6);
  border-top: 1px solid var(--border);
}
.notif-item:first-child { border-top: none; }
.notif-item-ico { font-size: var(--fs-400); flex-shrink: 0; margin-top: var(--sp-1); line-height: 1; }
.notif-item-body { flex: 1; min-width: 0; }
.notif-item-msg { font-size: var(--fs-300); color: var(--text-0); line-height: 1.4; }
.notif-item-time { font-size: var(--fs-100); color: var(--text-muted); margin-top: var(--sp-1); }

/* ============================
   SERVICE ALERTS (Req 3)
   ============================ */
.alert-toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-5);
  border: 1px solid var(--border);
  border-radius: var(--radius-full);
  background: var(--bg-2);
  color: var(--text-1);
  cursor: pointer;
  font-size: var(--fs-300);
  font-weight: 600;
  transition: border-color var(--dur-1) var(--ease-standard),color var(--dur-1) var(--ease-standard),background var(--dur-1) var(--ease-standard);
}
.alert-toggle:hover { border-color: var(--yellow); color: var(--ink-yellow); }
.alert-toggle.active { border-color: var(--yellow); color: var(--ink-yellow); background: var(--fill-yellow); }
.alert-toggle .alert-count {
  font-size: var(--fs-200);
  font-weight: 700;
  /* Ink as the fill and --surface as the text: contrast is symmetric, so this
     inherits the ratio the ink was already solved for. Solarized's raw --yellow
     under --bg-0 was 2.98:1. */
  background: var(--ink-yellow);
  color: var(--surface);
  border-radius: var(--radius-full);
  padding: var(--sp-1) var(--sp-3);
  min-width: 16px;
  text-align: center;
}

#alerts {
  flex: none;
  display: none;
  max-width: 900px;
  margin: 0 auto;
  padding: var(--sp-5) var(--sp-6) var(--sp-2);
  width: 100%;
}
#alerts.show { display: block; }
.alert-item {
  background: var(--fill-yellow);
  border: 1px solid color-mix(in srgb,var(--yellow) 42%,transparent);
  color: var(--text-0);
  padding: var(--sp-5) var(--sp-6);
  border-radius: var(--radius-md);
  margin-bottom: var(--sp-4);
  font-size: var(--fs-400);
  display: flex;
  align-items: flex-start;
  gap: var(--sp-4);
  cursor: pointer;
}
.alert-item .alert-icon { flex-shrink: 0; font-size: var(--fs-500); }
.alert-item .alert-body { flex: 1; min-width: 0; }
.alert-item .alert-header { font-weight: 600; margin-bottom: var(--sp-1); }
.alert-item .alert-routes { display: inline-flex; gap: var(--sp-2); margin-top: var(--sp-2); flex-wrap: wrap; }
.alert-item .alert-route-tag {
  background: var(--fill-yellow);
  color: var(--ink-yellow);
  font-size: var(--fs-200);
  font-weight: 600;
  padding: var(--sp-1) var(--sp-3);
  border-radius: var(--radius-full);
  border: 1px solid color-mix(in srgb,var(--yellow) 35%,transparent);
}
.alert-item .alert-desc {
  display: none;
  margin-top: var(--sp-3);
  font-size: var(--fs-300);
  color: var(--text-1);
  line-height: 1.4;
}
.alert-item.expanded .alert-desc { display: block; }
.alert-item .alert-dismiss {
  flex-shrink: 0;
  background: none;
  border: none;
  color: var(--text-muted);
  cursor: pointer;
  font-size: var(--fs-500);
  padding: 0 var(--sp-2);
  line-height: 1;
}
.alert-item .alert-dismiss:hover { color: var(--text-0); }
.alert-item a { color: var(--ink-accent); text-decoration: none; font-size: var(--fs-300); }
.alert-item a:hover { text-decoration: underline; }

/* ============================
   NESTED ARRIVALS (Req 2)
   ============================ */
.nested-arrs-head {
  font-size: var(--fs-200);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--text-muted);
  margin-top: var(--sp-5);
  padding-top: var(--sp-4);
  border-top: 1px dashed var(--border);
}
.nested-arrs {
  list-style: none;
  margin-top: var(--sp-3);
  border-radius: var(--radius-sm);
  overflow: hidden;
  border: 1px solid var(--border);
}
.nested-arrs .arr {
  background: var(--surface);
  font-size: var(--fs-300);
  padding: var(--sp-4) var(--sp-5);
}
.nested-arrs .arr:hover {
  background: var(--surface-hover);
}
.nested-arrs .arr-detail {
  background: var(--bg-2);
  padding: 0 var(--sp-5) var(--sp-5);
}

/* ============================
   COUNTDOWN REWORK (Req 4)
   ============================ */
.cd-map-toggle {
  margin-top: var(--sp-5);
  font-size: var(--fs-300);
  font-weight: 600;
  color: var(--ink-accent);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-5);
  border-radius: var(--radius-full);
  background: var(--bg-2);
  border: 1px solid var(--border);
  transition: border-color var(--dur-1) var(--ease-standard),color var(--dur-1) var(--ease-standard),background var(--dur-1) var(--ease-standard);
}
.cd-map-toggle:hover {
  background: var(--accent-dim);
  border-color: var(--accent);
  text-decoration: none;
}
.cd-map-wrapper {
  position: relative;
  margin-top: var(--sp-5);
  width: 100%;
}
/* Keep the slot's height while Leaflet is detached so a poll cannot collapse
 * the page and jump the reader. */
.cd-map-wrapper:not([hidden]) {
  min-height: 250px;
}
.cd-map-container {
  height: 250px;
  width: 100%;
  border-radius: var(--radius-md);
  overflow: hidden;
  border: 1px solid var(--border);
}
.cd-dist-badge {
  position: absolute;
  top: 10px;
  left: 10px;
  right: 10px;
  background: rgba(18, 18, 24, 0.88);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border: 1px solid rgba(255, 255, 255, 0.15);
  box-shadow: var(--shadow-2);
  border-radius: var(--radius-full);
  padding: var(--sp-3) var(--sp-6);
  font-size: var(--fs-300);
  font-weight: 600;
  color: #ffffff;
  display: flex;
  align-items: center;
  justify-content: space-between;
  z-index: 1000;
  pointer-events: none;
}
.cd-dist-badge .dist-highlight {
  color: #38bdf8;
  font-weight: 700;
}
.map-pin-stop {
  font-size: var(--fs-800);
  line-height: 1;
  text-align: center;
  filter: drop-shadow(0 2px 4px rgba(0,0,0,0.5));
}
.map-pin-veh {
  background: var(--bus-color, #3b82f6);
  border: 2px solid currentColor;
  border-radius: var(--radius-full);
  padding: var(--sp-2) var(--sp-4);
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  box-shadow: var(--shadow-2);
  color: #fff;
}
.map-pin-veh.is-rail { border-radius: 4px; }
.map-pin-veh .bus-ico {
  font-size: var(--fs-400);
  line-height: 1;
  display: grid;
  place-items: center;
  color: inherit;
}
.map-pin-veh .bus-ico .ico { width: 12px; height: 12px; display: block; }
.map-pin-veh .bus-lbl {
  font-size: var(--fs-200);
  font-weight: 700;
  color: inherit;
  line-height: 1;
}
.btn-gmap {
  display: inline-block;
  margin-top: var(--sp-5);
  font-size: var(--fs-300);
  font-weight: 600;
  color: var(--ink-accent);
  text-decoration: none;
}
.btn-gmap:hover { text-decoration: underline; }

/* ============================
   ANALYTICS & CHARTS (Req 5)
   ============================ */
.analytics-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--sp-6);
  margin-top: var(--sp-6);
}
@media(min-width: 800px) {
  .analytics-grid {
    grid-template-columns: repeat(2, 1fr);
  }
  .chart-card.full-width {
    grid-column: span 2;
  }
}
.chart-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: var(--sp-6);
  box-shadow: var(--shadow-1);
}
.chart-card h2 {
  font-size: var(--fs-400);
  font-weight: 700;
  color: var(--text-0);
  margin-bottom: var(--sp-5);
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.chart-card h2 small {
  font-size: var(--fs-200);
  font-weight: 400;
  /* text-muted/--text-2 fails 3:1 on several dark surfaces; text-1 clears it. */
  color: var(--text-1);
}
.chart-wrap {
  position: relative;
  width: 100%;
  min-height: 240px;
}
.chart-wrap.tall {
  min-height: 300px;
}
.chart-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 180px;
  text-align: center;
  font-size: var(--fs-300);
  color: var(--text-muted);
  padding: var(--sp-6);
  background: var(--bg-1);
  border-radius: var(--radius-sm);
}
.chart-empty.placeholder {
  border: 1px dashed var(--border);
}
.chart-empty strong {
  color: var(--text-1);
  margin-bottom: var(--sp-2);
}
.heatmap-grid {
  display: grid;
  grid-template-columns: 40px repeat(24, 1fr);
  gap: var(--sp-1);
  font-size: var(--fs-100);
  font-family: var(--font-mono);
  overflow-x: auto;
  padding-bottom: var(--sp-4);
}
.heatmap-cell {
  height: 20px;
  border-radius: 3px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--fs-100);
}
.reliability-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: var(--sp-5);
}
.rel-card {
  background: var(--bg-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: var(--sp-5);
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}
.rel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.rel-route {
  font-weight: 700;
  font-size: var(--fs-400);
  color: var(--text-0);
}
.rel-grade {
  font-size: var(--fs-400);
  font-weight: 800;
  border-radius: var(--radius-xs);
  padding: var(--sp-1) var(--sp-3);
}
.rel-grade.A { background: var(--fill-green); color: var(--ink-green); }
.rel-grade.B { background: var(--fill-blue); color: var(--ink-blue); }
.rel-grade.C { background: var(--fill-yellow); color: var(--ink-yellow); }
.rel-grade.D, .rel-grade.F { background: var(--fill-red); color: var(--ink-red); }
.rel-stat {
  font-size: var(--fs-200);
  color: var(--text-muted);
}
/* Analytics Filter Controls (Req: filter/search by stop/bus/date in analytics) */
.analytics-controls {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--sp-5);
  background: var(--bg-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: var(--sp-5) var(--sp-6);
  margin-bottom: var(--sp-6);
  width: 100%;
  box-sizing: border-box;
}

.filter-field {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  min-width: 110px;
  flex: 1 1 auto;
}

.filter-field.search-field {
  flex: 2 1 180px;
  min-width: 140px;
}

.filter-field label {
  font-size: var(--fs-200);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-muted);
}

.filter-input-wrap {
  position: relative;
  display: flex;
  align-items: center;
}

.filter-icon {
  position: absolute;
  left: 8px;
  pointer-events: none;
  font-size: var(--fs-200);
  opacity: 0.6;
}

.filter-input {
  width: 100%;
  box-sizing: border-box;
  background: var(--bg-2);
  border: 1px solid var(--border);
  color: var(--text-0);
  border-radius: var(--radius-sm);
  padding: var(--sp-3) var(--sp-5);
  font-size: var(--fs-300);
  font-family: inherit;
  transition: border-color .15s ease;
  min-height: 32px;
}

.filter-field.search-field .filter-input {
  padding-left: 26px;
}

.filter-input:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-dim);
}

.filter-select {
  cursor: pointer;
}

.btn-filter-reset {
  align-self: flex-end;
  padding: var(--sp-3) var(--sp-6);
  background: var(--bg-2);
  border: 1px solid var(--border);
  color: var(--text-1);
  border-radius: var(--radius-sm);
  font-size: var(--fs-300);
  font-weight: 600;
  cursor: pointer;
  height: 32px;
  transition: border-color var(--dur-1) var(--ease-standard),color var(--dur-1) var(--ease-standard),background var(--dur-1) var(--ease-standard);
  white-space: nowrap;
}

.btn-filter-reset:hover {
  background: var(--accent-dim);
  color: var(--ink-accent);
  border-color: var(--accent);
}

@media (max-width: 480px) {
  .analytics-controls {
    gap: var(--sp-4);
    padding: var(--sp-5);
  }
  .filter-field {
    min-width: calc(50% - 4px);
    flex: 1 1 calc(50% - 4px);
  }
  .filter-field.search-field {
    min-width: 100%;
    flex: 1 1 100%;
  }
  .btn-filter-reset {
    width: 100%;
  }
}

/* Downstream Stops & Sub-detail (parity with original Docker app) */
.arr-detail-section {
  margin-top: var(--sp-5);
  padding-top: var(--sp-4);
  border-top: 1px solid var(--border);
}
.arr-detail-head {
  font-size: var(--fs-200);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-muted);
  margin-bottom: var(--sp-3);
}
.arr-detail-conns {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}
.conn-row {
  display: flex;
  align-items: center;
  gap: var(--sp-3) var(--sp-5);
  padding: var(--sp-3) var(--sp-5);
  border-radius: var(--radius-sm);
  background: var(--surface);
  font-size: var(--fs-300);
  cursor: pointer;
  transition: background 0.15s;
  -webkit-tap-highlight-color: transparent;
}
.conn-row:hover { background: var(--surface-hover); }
.conn-row:active { background: var(--bg-2); }
.conn-dest { color: var(--text-0); flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-weight: 500; }
.conn-time { font-family: var(--font-mono); font-weight: 600; font-size: var(--fs-200); color: var(--text-muted); flex-shrink: 0; }
.conn-wait { font-weight: 700; color: var(--ink-accent); flex-shrink: 0; min-width: 28px; text-align: right; font-size: var(--fs-200); }
.sub-chevron {
  font-size: var(--fs-200);
  color: var(--text-muted);
  flex-shrink: 0;
  transition: transform 0.2s var(--ease-out);
  margin-left: var(--sp-1);
}
.conn-row.sub-expanded .sub-chevron { transform: rotate(90deg); }

.sub-detail {
  background: var(--bg-2);
  border-left: 3px solid var(--accent);
  margin-left: var(--sp-4);
  padding: var(--sp-3) var(--sp-4);
  border-radius: 0 0 var(--radius-sm) var(--radius-sm);
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}
.sub-arr {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  font-size: var(--fs-200);
  padding: var(--sp-2) 0;
  border-bottom: 1px solid var(--border);
}
.sub-arr:last-child { border-bottom: none; }
.sub-arr-route { color: var(--text-0); font-weight: 600; flex: 1; }
.sub-arr-time { font-family: var(--font-mono); font-size: var(--fs-100); color: var(--text-muted); }
.sub-arr-eta { font-weight: 700; color: var(--ink-accent); min-width: 28px; text-align: right; }

.transfer-badges {
  display: inline-flex;
  gap: var(--sp-2);
  flex-shrink: 0;
  flex-wrap: wrap;
}
.transfer-badge {
  font-size: var(--fs-100);
  font-weight: 700;
  padding: var(--sp-1) var(--sp-3);
  border-radius: var(--radius-full);
  background: var(--accent-dim);
  color: var(--ink-accent);
  white-space: nowrap;
  line-height: 1.4;
}
.sub-route-row {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  font-size: var(--fs-200);
  padding: var(--sp-2) var(--sp-3);
  cursor: pointer;
  border-bottom: 1px solid var(--border);
  transition: background 0.15s;
  border-radius: var(--radius-sm);
}
.sub-route-row:hover { background: var(--surface-hover); }
.sub-route-row:last-child { border-bottom: none; }
.sub-route-chevron {
  font-size: var(--fs-200);
  color: var(--text-muted);
  flex-shrink: 0;
  transition: transform 0.2s var(--ease-out);
  margin-left: auto;
}
.sub-route-row.sub-route-expanded .sub-route-chevron { transform: rotate(90deg); }
.sub-route-times {
  padding: var(--sp-1) var(--sp-4) var(--sp-2) var(--sp-5);
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
  border-bottom: 1px solid var(--border);
}
.sub-route-time-row {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  font-size: var(--fs-100);
  padding: var(--sp-1) 0;
}
.sub-route-time-row .sub-route-time-clock { font-family: var(--font-mono); color: var(--text-muted); }
.sub-route-time-row .sub-route-time-eta { font-weight: 600; color: var(--ink-accent); min-width: 28px; text-align: right; margin-left: auto; }

.show-more-stops {
  text-align: center;
  font-size: var(--fs-200);
  font-weight: 600;
  color: var(--ink-accent);
  padding: var(--sp-3) var(--sp-5);
  cursor: pointer;
  border-radius: var(--radius-sm);
  transition: background 0.15s;
  background: var(--surface);
  margin-top: var(--sp-2);
}
.show-more-stops:hover { background: var(--accent-dim); }

/* The legend strip that used to live above the feed is gone — the status is
 * already stated three ways in every row, so the strip was a caption for
 * something the eye had already read. Its rules went with it; the column
 * header and stop badges are defined once, with the card. */

.arr-detail-topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--sp-4) var(--sp-5);
  background: var(--bg-1);
  border-bottom: 1px solid var(--border);
  border-radius: var(--radius-sm) var(--radius-sm) 0 0;
  cursor: pointer;
  transition: background 0.15s;
  margin-bottom: var(--sp-4);
}
.arr-detail-topbar:hover { background: var(--surface-hover); }
.detail-stop-id {
  font-size: var(--fs-200);
  font-family: var(--font-mono);
  font-weight: 700;
  color: var(--ink-accent);
  background: var(--accent-dim);
  padding: var(--sp-1) var(--sp-4);
  border-radius: var(--radius-full);
  margin-right: var(--sp-3);
}
.detail-stop-name { font-size: var(--fs-300); font-weight: 600; color: var(--text-0); }
.arr-detail-collapse-btn {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--fs-200);
  font-weight: 600;
  color: var(--text-muted);
}
.arr-detail-topbar:hover .arr-detail-collapse-btn { color: var(--ink-accent); }
.det.highlight { border-left: 2px solid var(--accent); }

/* ---- Map Enhancements ---- */
.bus-marker-wrap { background: transparent; border: none; }
/* Fleet markers use .map-pin-veh (bus vs rail + inkOn); keep the wrap class for Leaflet. */
.bus-trail { opacity: 0.45; }
.bus-path-ahead { opacity: 0.75; }
.map-locate-btn {
  position: absolute;
  bottom: 24px;
  right: 14px;
  z-index: 500;
  display: inline-flex;
  align-items: center;
  gap: var(--sp-3);
  background: var(--surface);
  color: var(--text-0);
  border: 1px solid var(--border);
  border-radius: var(--radius-full);
  padding: var(--sp-4) var(--sp-6);
  font-size: var(--fs-300);
  font-weight: 600;
  cursor: pointer;
  box-shadow: var(--shadow-1);
  transition: border-color var(--dur-1) var(--ease-standard),color var(--dur-1) var(--ease-standard),background var(--dur-1) var(--ease-standard);
}
.map-locate-btn:hover {
  background: var(--surface-hover);
  border-color: var(--accent);
  color: var(--ink-accent);
}
.leaflet-popup-content-wrapper {
  background: var(--surface) !important;
  color: var(--text-0) !important;
  border-radius: var(--radius-md) !important;
  box-shadow: var(--shadow-3) !important;
  border: 1px solid var(--border);
  padding: 0 !important;
  overflow: hidden;
}
.leaflet-popup-content {
  margin: 0 !important;
  min-width: 240px;
  max-width: 300px;
  font-family: var(--font-sans) !important;
}
.leaflet-popup-tip {
  background: var(--surface) !important;
}
.map-card { padding: var(--sp-5); }
.map-card-head { display: flex; align-items: center; gap: var(--sp-4); margin-bottom: var(--sp-3); }
.map-card-sign { font-weight: 700; font-size: var(--fs-400); color: var(--text-0); line-height: 1.2; }
.map-card-meta { font-size: var(--fs-200); color: var(--text-muted); margin-top: var(--sp-1); }
.map-card-stops {
  margin-top: var(--sp-4);
  padding-top: var(--sp-4);
  border-top: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  max-height: 160px;
  overflow-y: auto;
}
.map-stop-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: var(--fs-200);
  padding: var(--sp-2) 0;
  border-bottom: 1px solid var(--border);
}
.map-stop-row:last-child { border-bottom: none; }
.map-stop-name { color: var(--text-0); font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 170px; }
.map-stop-wait { font-weight: 700; color: var(--ink-accent); font-family: var(--font-mono); }

/* ---- density: narrow screens ---------------------------------------------
 * Desktop buys comfort with padding; a phone buys it with fewer, tighter
 * columns. The arrival row keeps all three columns rather than stacking —
 * stacking doubles the row height and halves how many arrivals fit above the
 * fold, which is the whole point of the screen.
 * ------------------------------------------------------------------------ */
@media (max-width: 700px) {
  .hero { height: 72px; }
  .pad { padding: var(--sp-5) var(--sp-5); }
  .who { display: none; }
  .toasts { right: var(--sp-5); left: var(--sp-5); max-width: none; }

  .stop-head { padding: var(--sp-5) var(--sp-5) var(--sp-4); gap: var(--sp-4); }
  .stop-name { font-size: var(--fs-500); }
  .arr { padding: 0; }
  .arr-expand { gap: var(--sp-4); padding: var(--sp-4) var(--sp-5) var(--sp-4) calc(var(--sp-5) - 3px); min-height: 56px; }
  .arr-expand > .pill { width: 62px; }
  .eta { width: 74px; font-size: var(--fs-600); }
  .arrs-col-head { padding: var(--sp-3) calc(var(--sp-5) + 10px + var(--sp-4)) var(--sp-3) var(--sp-5); gap: var(--sp-4); }
  .col-lbl-status { width: 62px; }
  .col-lbl-eta { width: 74px; }
  .arr-detail { padding: 0 var(--sp-5) var(--sp-5); }
  .cd { padding: var(--sp-7) var(--sp-6); }
  /* auto-fit would drop the stat tiles to one per row at 390px, which turns
     eight numbers into a scroll. Two fixed columns instead. */
  .tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-4); }
  .det-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 640px) {
  .topbar { padding: var(--sp-4) var(--sp-5); gap: var(--sp-4); }
  .pill-nav { width: 100%; justify-content: space-between; order: 4; }
  .pill-nav button { padding: var(--sp-3) var(--sp-4); font-size: var(--fs-300); flex: 1; text-align: center; }
  .topright { width: 100%; justify-content: space-between; gap: var(--sp-4); order: 3; }
  .brand-live { padding: var(--sp-2) var(--sp-1); gap: var(--sp-2); }
  /* A step down rather than an ellipsis: "CatchARideP…" is worse than a
     slightly smaller wordmark, and the 12px it saves goes to the search field. */
  .brand-name { font-size: var(--fs-300); letter-spacing: 0; }
  .topright > .search-wrap { flex: 1 1 90px; min-width: 90px; max-width: none; }
  .search { padding: var(--sp-3) var(--sp-5) var(--sp-3) var(--sp-8); font-size: var(--fs-300); }
  .search-ico { left: var(--sp-4); width: 13px; height: 13px; }
  /* Label off, icon on: the pin already says "add a stop" and the bar has four
     controls competing for 390px. */
  .quick-add-txt { display: none; }
  .quick-add { padding: var(--sp-3); }
  .subbar { padding: var(--sp-4) var(--sp-5); gap: var(--sp-3); }
  .subbar .right { gap: var(--sp-3); }
  .chipbtn { padding: var(--sp-4) var(--sp-4); font-size: var(--fs-300); }
  .sort-cycle-label,
  .collapse-all-label,
  .locate-label,
  .fav-only-label { display: none; }
  .settings-drop,
  .notif-drop {
    position: fixed;
    top: var(--sp-10);
    left: var(--sp-5);
    right: var(--sp-5);
    width: auto;
    max-width: calc(100vw - var(--sp-5) * 2);
    z-index: 2200;
    box-shadow: var(--shadow-3);
    transform-origin: top center;
  }
}

/* Route Breakout Modal & Interactive Drill-down */
.modal {
  position: fixed;
  inset: 0;
  z-index: 2000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--sp-6);
  box-sizing: border-box;
}
.modal[hidden] {
  display: none !important;
}
.modal-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.65);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
}
.modal-card {
  position: relative;
  background: var(--bg-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-float);
  width: 100%;
  max-width: 500px;
  max-height: 85vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  box-sizing: border-box;
  animation: modalPop 0.2s var(--ease-out);
}
@keyframes modalPop {
  from { opacity: 0; transform: scale(0.96); }
  to { opacity: 1; transform: scale(1); }
}
.modal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--sp-6) var(--sp-7);
  border-bottom: 1px solid var(--border);
}
.modal-title-wrap {
  display: flex;
  align-items: center;
  gap: var(--sp-5);
}
/* There was no base .badge rule at all, so a badge inherited --text-0 and sat
 * on a raw TriMet route colour — in amber-crt and terminal the text came out
 * the same colour as its fill, 1.00:1. --on-accent is measured >=5.15:1 in all
 * 32 themes; JS overrides it inline when it paints a literal route colour. */
.badge {
  display: inline-block;
  padding: var(--sp-1) var(--sp-3);
  border-radius: var(--radius-sm);
  font-size: var(--fs-100);
  font-weight: 700;
  line-height: var(--lh-flat);
  background: var(--accent);
  color: var(--on-accent);
}
.badge.lg {
  font-size: var(--fs-500);
  font-weight: 800;
  padding: var(--sp-3) var(--sp-5);
  border-radius: var(--radius-sm);
  color: var(--on-accent);
}
#rmBadge { color: var(--on-accent); }
.settings-trigger.has-unread { color: var(--ink-yellow); border-color: color-mix(in srgb, var(--yellow) 40%, transparent); }
.settings-trigger.has-unread .notif-badge { display: block; }
/* Focus ring distinct from accent-filled tab chrome */
.pill-nav button:focus-visible,
.segmented button:focus-visible {
  outline: var(--focus-w) solid var(--ring, var(--text-0));
  outline-offset: var(--focus-offset);
}
#alerts.show { background: color-mix(in srgb, var(--yellow) 18%, var(--bg-1)); }
.modal { max-height: min(90vh, 720px); }
@media (max-width: 375px) {
  .modal { max-height: 92vh; width: calc(100vw - 16px); }
  .modal-body { overflow-y: auto; -webkit-overflow-scrolling: touch; }
}
.modal-head h2 {
  font-size: var(--fs-500);
  font-weight: 700;
  margin: 0;
  line-height: 1.2;
}
.modal-sub {
  font-size: var(--fs-200);
  color: var(--text-muted);
}
.modal-body {
  padding: var(--sp-6) var(--sp-7);
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: var(--sp-6);
}
.modal-stats-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--sp-4);
}
.modal-stat-tile {
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: var(--sp-4);
  text-align: center;
}
.modal-stat-val {
  font-size: var(--fs-600);
  font-weight: 800;
  font-family: var(--font-mono);
  color: var(--text-0);
}
.modal-stat-lbl {
  font-size: var(--fs-100);
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin-top: var(--sp-1);
}
.modal-bar-wrap {
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: var(--sp-5) var(--sp-5);
}
.modal-bar-label {
  font-size: var(--fs-200);
  font-weight: 600;
  color: var(--text-1);
  margin-bottom: var(--sp-3);
  display: flex;
  justify-content: space-between;
}
.modal-prog-bar {
  height: 8px;
  border-radius: var(--radius-xs);
  background: var(--border);
  overflow: hidden;
  display: flex;
}
.modal-prog-seg {
  height: 100%;
}
.modal-foot {
  display: flex;
  justify-content: flex-end;
  gap: var(--sp-4);
  padding: var(--sp-5) var(--sp-7);
  border-top: 1px solid var(--border);
  background: var(--bg-0);
}
.route-row {
  cursor: pointer;
  transition: background 0.15s ease;
}
.route-row:hover {
  background: var(--bg-2);
}
.rel-card[data-drill-route] {
  cursor: pointer;
  transition: transform 0.15s ease, border-color 0.15s ease;
}
.rel-card[data-drill-route]:hover {
  transform: translateY(-2px);
  border-color: var(--accent);
}
.analytics-summary-bar {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-4);
  background: var(--bg-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: var(--sp-5) var(--sp-6);
  margin-bottom: var(--sp-6);
  align-items: center;
  box-sizing: border-box;
}
.analytics-summary-title {
  width: 100%;
  font-size: var(--fs-400);
  font-weight: 700;
  color: var(--text-0);
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: var(--sp-2);
  gap: var(--sp-4);
  flex-wrap: wrap;
}
.day-partial-flag {
  font-size: var(--fs-200);
  font-weight: 700;
  color: var(--ink-yellow, var(--yellow));
  background: var(--fill-yellow, color-mix(in srgb, var(--yellow) 18%, transparent));
  border: 1px solid color-mix(in srgb, var(--yellow) 45%, transparent);
  border-radius: var(--radius-full);
  padding: var(--sp-2) var(--sp-4);
}
.analytics-stat-pill {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-3);
  background: var(--bg-2);
  border: 1px solid var(--border);
  padding: var(--sp-3) var(--sp-5);
  border-radius: var(--radius-sm);
  font-size: var(--fs-300);
}
.analytics-stat-pill strong {
  font-family: var(--font-mono);
  color: var(--text-0);
}

/* the icon buttons hold an SVG now, not a glyph */
.icon{display:inline-grid;place-items:center}
.icon svg{width:15px;height:15px}
