
    *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; -webkit-tap-highlight-color: transparent; }
    body { -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; }
    /* Selection stays on for anything the user might reasonably want to copy:
       all text inputs (route search, address bar, profile name) and the
       announcements modal body. */
    input, textarea, [contenteditable="true"], #alerts-modal-body, #alerts-modal-body * {
      -webkit-user-select: text; user-select: text; -webkit-touch-callout: default;
    }
    :root {
      --yellow: #FFD000;
      --accent-text: #FFD000;
      --dark:   #0a0a0a;
      --panel:  #141414;
      --border: #2a2a2a;
      --text:   #f0f0f0;
      --muted:  #555;
      --mono:   'DM Mono', monospace;
      --display:'Syne', sans-serif;
    }
    html, body { height: 100%; height: 100dvh; overflow: hidden; }
    body { background: var(--dark); color: var(--text); font-family: var(--mono); display: flex; flex-direction: column; }
    header { display: flex; align-items: center; padding: 9px 14px; padding-top: calc(9px + env(safe-area-inset-top)); border-bottom: 1px solid var(--border); background: var(--panel); flex-shrink: 0; gap: 8px; }
    .bus-badge { background: var(--yellow); color: var(--dark); font-family: var(--display); font-weight: 800; font-size: 0.75rem; padding: 4px 8px; letter-spacing: 0.05em; flex-shrink: 0; }
    h1 { font-family: var(--display); font-size: 0.9375rem; font-weight: 700; color: var(--text); white-space: nowrap; flex-shrink: 0; }
    .status-bar { display: flex; align-items: center; gap: 10px; margin-left: auto; flex-shrink: 0; }
    .stat { display: flex; flex-direction: column; align-items: flex-end; }
    .stat-value { font-size: 0.875rem; font-weight: 500; color: var(--accent-text); line-height: 1; }
    .stat-label { font-size: 0.5625rem; color: var(--muted); text-transform: uppercase; letter-spacing: 0.08em; margin-top: 1px; }
    .pulse-dot { width: 7px; height: 7px; border-radius: 50%; background: #00e676; animation: pulse 2s infinite; flex-shrink: 0; }
    .pulse-dot.loading { background: var(--yellow); }
    .pulse-dot.error   { background: #ff4444; animation: none; }
    @keyframes pulse { 0%,100%{opacity:1;transform:scale(1)}50%{opacity:.5;transform:scale(.8)} }
    .icon-btn { position: relative; background: transparent; border: 1px solid var(--border); color: var(--text); font-size: 0.875rem; width: 30px; height: 30px; cursor: pointer; display: flex; align-items: center; justify-content: center; transition: all .15s; flex-shrink: 0; }
    .icon-btn:hover { border-color: var(--yellow); color: var(--accent-text); }
    .main { display: flex; flex: 1; overflow: hidden; }
    #map { flex: 1; min-width: 0; outline: none; background: var(--tile-bg); }

    /* SIDEBAR */
    #sidebar { width: 280px; background: var(--panel); border-left: 1px solid var(--border); display: flex; flex-direction: column; flex-shrink: 0; overflow: hidden; transition: width 0.25s ease; }
    #sidebar.collapsed { width: 36px; }
    .sidebar-toggle { display: flex; align-items: center; justify-content: center; width: 36px; height: 36px; flex-shrink: 0; cursor: pointer; border-bottom: 1px solid var(--border); color: var(--muted); font-size: 0.8125rem; transition: color .15s; align-self: flex-end; }
    .sidebar-toggle:hover { color: var(--accent-text); }
    .sidebar-inner { display: flex; flex-direction: column; flex: 1; overflow: hidden; opacity: 1; transition: opacity 0.15s ease; }
    #sidebar.collapsed .sidebar-inner { opacity: 0; pointer-events: none; }
    .sidebar-header { padding: 10px 12px 8px; border-bottom: 1px solid var(--border); flex-shrink: 0; }
    .sidebar-title { font-family: var(--display); font-size: 0.625rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.1em; color: var(--muted); margin-bottom: 7px; }
    .search-wrap { position: relative; display: flex; align-items: center; }
    #route-search { width: 100%; background: #1e1e1e; border: 1px solid var(--border); color: var(--text); font-family: var(--mono); font-size: 0.75rem; padding: 6px 26px 6px 9px; outline: none; transition: border-color .15s; }
    #route-search:focus { border-color: var(--yellow); }
    #route-search::placeholder { color: var(--muted); }
    .search-clear { position: absolute; right: 7px; background: none; border: none; color: var(--muted); font-size: 0.8125rem; cursor: pointer; padding: 0; line-height: 1; display: none; }
    .search-clear.visible { display: block; }
    .filter-tabs { display: flex; border-bottom: 1px solid var(--border); flex-shrink: 0; }
    .filter-tab { flex: 1; padding: 6px 2px; text-align: center; font-family: var(--mono); font-size: 0.5625rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); cursor: pointer; border-bottom: 2px solid transparent; transition: all .15s; }
    .filter-tab.active { color: var(--accent-text); border-bottom-color: var(--yellow); }
    .sidebar-actions { display: flex; gap: 6px; padding: 7px 12px; border-bottom: 1px solid var(--border); flex-shrink: 0; }
    .action-btn { flex: 1; background: transparent; border: 1px solid var(--border); color: var(--muted); font-family: var(--mono); font-size: 0.5625rem; padding: 5px; cursor: pointer; text-transform: uppercase; letter-spacing: 0.06em; transition: all .15s; }
    .action-btn:hover { border-color: var(--yellow); color: var(--accent-text); }
    #route-list { flex: 1; overflow-y: auto; padding: 4px 0; -webkit-overflow-scrolling: touch; }
    #route-list::-webkit-scrollbar { width: 3px; }
    #route-list::-webkit-scrollbar-thumb { background: var(--border); }
    .route-item { display: flex; align-items: center; gap: 8px; padding: 6px 12px; cursor: pointer; user-select: none; transition: background .1s; }
    .route-item:hover { background: var(--card-header-bg, #1e1e1e); }
    .route-swatch { width: 9px; height: 9px; border-radius: 2px; flex-shrink: 0; }
    .route-check { width: 13px; height: 13px; border: 1.5px solid var(--border); border-radius: 2px; flex-shrink: 0; display: flex; align-items: center; justify-content: center; font-size: 0.5625rem; transition: all .15s; }
    .route-item.active .route-check { background: var(--yellow); border-color: var(--yellow); color: #000; }
    .route-info { flex: 1; min-width: 0; }
    .route-name { font-family: var(--display); font-size: 0.75rem; font-weight: 700; color: var(--text); }
    .route-long { font-size: 0.5625rem; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-top: 1px; }
    .route-count { font-size: 0.5625rem; color: var(--muted); flex-shrink: 0; }
    .route-dist  { font-size: 0.5625rem; color: var(--accent-text); flex-shrink: 0; font-family: var(--mono); }
    .fav-btn { background: none; border: none; cursor: pointer; font-size: 1rem; color: var(--muted); padding: 2px 4px; line-height: 1; flex-shrink: 0; transition: color .15s; }
    .fav-btn.active { color: var(--yellow); }
    .no-results { padding: 20px 12px; font-size: 0.6875rem; color: var(--muted); text-align: center; }
    .county-section { border-bottom: 1px solid var(--border); }
    .county-header { display: flex; align-items: center; gap: 8px; padding: 8px 12px; cursor: pointer; user-select: none; transition: background .1s; position: sticky; top: 0; z-index: 10; background: var(--panel); }
    .county-header:hover { background: var(--card-header-bg, #1a1a1a); }
    .county-name { font-family: var(--display); font-size: 0.75rem; font-weight: 700; color: var(--accent-text); flex: 1; }
    .county-meta { font-size: 0.5625rem; color: var(--muted); }
    .county-arrow { font-size: 0.5625rem; color: var(--muted); }
    .county-routes { border-top: 1px solid var(--border); }

    /* BUS MARKERS */
    .bus-marker { border: 2px solid rgba(0,0,0,0.7); border-radius: 3px; display: flex; flex-direction: column; align-items: center; justify-content: center; font-weight: 800; box-shadow: 0 2px 8px rgba(0,0,0,0.6); cursor: pointer; font-family: 'Syne', sans-serif; padding: 2px 4px; min-width: 26px; max-width: 64px; }
    .bus-marker.rail { border-style: dashed; border-color: #fff; }
    /* Box is deliberately larger than the shape (see RAIL_TAP_SIZE in app.js)
       to give these DOM markers a finger-sized tap target; the flex centring
       keeps the visible triangle/square exactly where it was. */
    .stop-rail { background: transparent; border: none; display: flex; align-items: center; justify-content: center; }
    .bus-arrow { font-size: 0.5625rem; line-height: 1; }
    .bus-label { font-size: 0.5625rem; line-height: 1.1; white-space: nowrap; }
    .bus-dest  { font-size: 0.4375rem; line-height: 1.1; white-space: nowrap; overflow: hidden; max-width: 60px; text-overflow: ellipsis; opacity: 0.8; font-family: 'DM Mono', monospace; font-weight: 400; }
    .gps-dot   { width: 14px; height: 14px; background: #2979ff; border: 3px solid white; border-radius: 50%; box-shadow: 0 0 0 3px rgba(41,121,255,0.3); }

    /* NEARBY-BUTTON DROP PIN
       The marker's icon box is 0x0 and sits on the latlng (see
       enterNearbyBtnPinPlacement), so the pin hangs off it bottom-centred:
       the glyph's tip — the viewBox's bottom edge — lands on the point. */
    .nearby-pin {
      --pin-size: 2.5rem;
      position: absolute; left: 0; bottom: 0;
      width: var(--pin-size); height: var(--pin-size);
      transform: translateX(-50%);
      transform-origin: 50% 100%;
      cursor: pointer;
    }
    .nearby-pin-glyph {
      position: absolute; inset: 0; width: 100%; height: 100%;
      fill: var(--yellow, #FFD000);
      filter: drop-shadow(0 1px 1px rgba(0,0,0,0.85)) drop-shadow(0 3px 6px rgba(0,0,0,0.5));
    }
    /* Placement-only target dot, centred on the tip and drawn behind the pin:
       the visible tell that this position isn't committed yet. */
    .nearby-pin-ring {
      display: none;
      position: absolute; left: 50%; bottom: 0;
      width: calc(var(--pin-size) * 0.32); height: calc(var(--pin-size) * 0.32);
      transform: translate(-50%, 50%);
      border-radius: 50%;
      background: var(--yellow, #FFD000);
      border: 2px solid rgba(0,0,0,0.65);
    }
    .nearby-pin.is-placing .nearby-pin-ring { display: block; }
    /* Once confirmed the pin is inert — no taps, no map-drag blocking — and
       bounces once as the acknowledgement. */
    .nearby-pin.is-placed {
      cursor: default; pointer-events: none;
      animation: nearby-pin-pop 0.42s cubic-bezier(.2,.8,.3,1);
    }
    @keyframes nearby-pin-pop {
      0%   { transform: translateX(-50%) scale(1); }
      40%  { transform: translateX(-50%) scale(1.3); }
      70%  { transform: translateX(-50%) scale(0.93); }
      100% { transform: translateX(-50%) scale(1); }
    }
    @media (prefers-reduced-motion: reduce) {
      .nearby-pin.is-placed { animation: none; }
    }
    /* Text-scale cap. Unlike the other overrides at the foot of this file this
       one isn't phone-gated: the map (and the accessibility scale) apply at
       every width. 2.5rem at the "larger" step (140%) is 56px, and that's
       where the pin stops growing — beyond it the pin starts covering the
       area it's meant to point at. */
    :is(html[data-text-size="largest"], html[data-text-size="huge"]) .nearby-pin {
      --pin-size: 56px;
    }
    .leaflet-popup-content-wrapper { background: var(--panel) !important; border: 1px solid var(--border) !important; border-radius: 0 !important; color: var(--text) !important; box-shadow: 0 4px 20px rgba(0,0,0,0.8) !important; font-family: var(--mono) !important; }
    .leaflet-popup-tip { background: var(--panel) !important; }
    .popup-route { font-family: var(--display); font-size: 1.25rem; font-weight: 800; line-height: 1; margin-bottom: 3px; display: flex; align-items: center; }
    .popup-provider-mark { display: inline-flex; align-items: center; justify-content: center; font-family: var(--mono); font-size: 0.5625rem; font-weight: 700; padding: 2px 4px; border-radius: 4px; margin-right: 7px; letter-spacing: 0.05em; }
    .popup-mark-img { height: 17px; width: auto; margin-right: 7px; }
    .popup-long  { font-size: 0.6875rem; color: var(--muted); margin-bottom: 6px; }
    .popup-dest  { font-size: 0.75rem; color: var(--text); margin-bottom: 7px; }
    .popup-row   { font-size: 0.6875rem; color: var(--muted); margin: 3px 0; text-transform: uppercase; letter-spacing: 0.06em; }
    .popup-row span { color: var(--text); }

    /* STOP POPUPS */
    .popup-stop-name { font-family: var(--display); font-size: 0.875rem; font-weight: 700; margin-bottom: 8px; }
    .popup-stop-routes { display: flex; flex-wrap: wrap; gap: 4px; }
    .stop-route-tag { font-family: var(--mono); font-size: 0.625rem; padding: 2px 6px; border-radius: 2px; border-width: 1px; border-style: solid; }
    .stop-route-tag.off { background: transparent; border-color: var(--border); color: var(--muted); }
    /* Timetable mode: one shared fill so the popup reads as a different mode
       at a glance, with each route's own colour kept as the border. Fixed
       colours rather than theme vars — it's a solid chip, legible on any
       popup background, and the point is that it looks unlike the route
       toggles in every theme. */
    .stop-route-tag.tt-pick {
      background: #bfe1ff; color: #0b2438; border-width: 2px; border-style: solid;
      font-weight: 700; cursor: pointer;
    }
    .popup-stop-hdr { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 8px; }
    .popup-stop-hdr .popup-stop-name { margin-bottom: 0; }
    .popup-tt-btn { font-family: var(--mono); font-size: 0.5625rem; text-transform: uppercase; letter-spacing: 0.06em; padding: 3px 7px; border-radius: 2px; background: transparent; border: 1px solid #333; color: #555; cursor: pointer; white-space: nowrap; }
    .popup-tt-btn:hover { border-color: var(--yellow); color: var(--accent-text); }
    .popup-tt-btn.active { background: var(--yellow); border-color: var(--yellow); color: #000; }
    /* Stop timetable modal rows */
    /* Wraps rather than overflows: at the larger accessibility font scales the
       day button alone can be wider than the row, so it drops to a second line
       instead of pushing out past the modal. */
    .tt-sub { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; font-size: 0.6875rem; color: var(--text); padding: 10px 2px; border: 1px solid var(--border); position: sticky; top: 0; z-index: 1; background: var(--panel); box-shadow: 0 5px 10px -5px rgba(0,0,0,0.35); }
    /* Stop name gives way first when the header is tight — the route tag and
       the day button both need their full width. */
    /* flex-basis rather than 0: flex decides line breaks from the basis, so
       once the tag and the day button leave less than this much room, the day
       button wraps to its own line and the name keeps a readable width instead
       of being shaved down to a couple of characters. Tuned to still fit on
       one line at the normal text size, where there's plenty of room. */
    .tt-stop { flex: 1 1 76px; min-width: 0; overflow: hidden; white-space: nowrap; }
    /* Day picker: the button and its list are one control. Open, the button
       drops its bottom edge and the list continues the same outline down from
       it, anchored to the button rather than dropped into the flow below. */
    /* Deliberately sized in px, not rem: the picker is already large enough to
       read, and letting it scale with the text-size setting made it eat the
       whole header row at the biggest scales, pushing the stop name out. */
    .tt-day-wrap { margin-left: auto; position: relative; flex-shrink: 0; max-width: 100%; }
    .tt-sub .tt-day {
      display: flex; align-items: center; gap: 7px;
      color: var(--chip-text, var(--text)); text-transform: uppercase;
      font-family: var(--display); font-size: 14px; font-weight: 700; letter-spacing: 0.06em;
      padding: 7px 11px; border-radius: 9px; cursor: pointer; white-space: nowrap;
      background: var(--map-btn-bg, #1e1e1e); border: 1px solid var(--map-btn-border, var(--border));
      transition: border-color .15s ease, color .15s ease;
    }
    .tt-sub .tt-day:hover { border-color: var(--yellow); color: var(--accent-text); }
    .tt-sub .tt-day.is-open {
      border-color: var(--yellow); color: var(--accent-text);
      border-bottom-color: transparent;      /* transparent, not none — keeps the height steady */
      border-radius: 9px 9px 0 0;
    }
    /* All seven names stacked in one grid cell, only the current one visible:
       the button reserves the width of the longest at whatever font scale is
       in use, so it never resizes between days and the list matches it. */
    .tt-day-name { display: grid; justify-items: center; }
    .tt-day-name > span { grid-area: 1 / 1; }
    .tt-day-name > span:not(.on) { visibility: hidden; }
    .tt-day-caret { font-size: 10px; line-height: 1; transition: transform .18s ease; }
    .tt-sub .tt-day.is-open .tt-day-caret { transform: rotate(180deg); }
    /* position:fixed, not absolute — the modal card is overflow:hidden and its
       body scrolls, so an absolutely positioned list gets clipped to whatever
       room the modal happens to have. That cut the day list off on stops with
       few or no departures. Fixed escapes both; positionTimetableDays() sets
       left/top/width/max-height from the button's rect, and flips it above the
       button when there isn't room below. */
    .tt-day-options {
      display: none; position: fixed; z-index: 510;
      flex-direction: column;
      background: var(--panel); border: 1px solid var(--yellow); border-top: none;
      border-radius: 0 0 9px 9px;
      overflow-y: auto; overflow-x: hidden;
      box-shadow: 0 10px 20px -8px rgba(0,0,0,0.45);
    }
    .tt-day-options.open { display: flex; }
    /* Flipped: the seam moves to the top of the list and the bottom of the button. */
    .tt-day-options.drop-up {
      border-top: 1px solid var(--yellow); border-bottom: none;
      border-radius: 9px 9px 0 0;
      box-shadow: 0 -10px 20px -8px rgba(0,0,0,0.45);
    }
    .tt-sub .tt-day.is-open.drop-up {
      border-bottom-color: var(--yellow); border-top-color: transparent;
      border-radius: 0 0 9px 9px;
    }
    .tt-day-option {
      display: flex; align-items: center; gap: 14px; width: 100%;
      padding: 10px 12px; background: transparent;
      border: none; border-top: 1px solid var(--border);
      color: var(--chip-text, var(--text));
      font-family: var(--display); font-size: 12px; font-weight: 700;
      cursor: pointer; text-align: left; white-space: nowrap;
      transition: background .15s ease;
    }
    /* The button above stays px-fixed on purpose (see the note at the top of
       this group) — 14px is already comfortable and scaling it ate the header
       row. The list is smaller than that though, so it does climb with the
       accessibility steps, arriving at the button's own 14px at the last one
       rather than running past it. positionTimetableDays() width-matches the
       list to the button, and 14px mixed-case still fits inside the button's
       14px uppercase + letter-spacing, so nothing clips. */
    :is(html[data-text-size="large"])   .tt-day-option { font-size: 12.5px; }
    :is(html[data-text-size="larger"])  .tt-day-option { font-size: 13px; }
    :is(html[data-text-size="largest"]) .tt-day-option { font-size: 13.5px; }
    :is(html[data-text-size="huge"])    .tt-day-option { font-size: 14px; }
    .tt-day-option:first-child { border-top: none; }
    .tt-day-option:hover  { background: var(--card-header-bg, #1a1a1a); }
    .tt-day-option.active { background: var(--card-header-bg, #1a1a1a); color: var(--accent-text); }
    .tt-day-check { margin-left: auto; color: var(--accent-text); font-size: 13px; visibility: hidden; }
    .tt-day-option.active .tt-day-check { visibility: visible; }
    .tt-row { display: flex; align-items: baseline; gap: 12px; padding: 6px 2px; border-bottom: 1px solid var(--border); font-size: 0.75rem; }
    .tt-time { font-family: var(--mono); font-weight: 700; min-width: 56px; color: var(--text); }
    .tt-nextday { font-size: 0.5rem; color: var(--muted); vertical-align: super; margin-left: 2px; }
    .tt-dest { color: var(--muted); font-size: 0.6875rem; flex: 1; }
    .tt-row.tt-next { border-left: 2px solid var(--yellow); padding-left: 8px; margin-left: -10px; }
    .tt-row.tt-next .tt-time { color: var(--accent-text); }
    .tt-status { padding: 14px 0; font-size: 0.6875rem; color: var(--muted); }

    footer { padding: 0 12px; border-top: 1px solid var(--border); background: var(--panel); font-size: 0.4375rem; color: var(--muted); text-transform: uppercase; letter-spacing: 0.08em; flex-shrink: 0; line-height: 16px; }
    .leaflet-control-attribution { font-size: 0.375rem !important; padding: 0 3px !important; line-height: 1.4 !important; }
    .county-header.is-stuck { box-shadow: 0 1px 0 0 var(--border); }
    .sticky-sentinel { height: 1px; margin-bottom: -1px; }
    .view { display: none; flex: 1; flex-direction: column; overflow: hidden; }
    .view.active { display: flex; }
    /* SETTINGS VIEW */
    #view-settings { background: var(--dark); }
    .settings-scroll { flex: 1; overflow-y: auto; padding: 16px 14px 32px; }
    .settings-heading { font-family: var(--display); font-size: 0.6875rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.15em; color: var(--accent-text); margin: 0 0 10px 4px; }
    /* Version footer — deliberately quiet; it's reference material for bug
       reports, not something to draw the eye. */
    .settings-version { margin-top: 18px; text-align: center; font-family: var(--mono); font-size: 0.6875rem; letter-spacing: 0.06em; color: var(--muted); }
    /* Card surfaces mirror the display board's .board-section: theme-tinted
       fill, hairline border, 16px radius, rows divided rather than glued.
       Fallback chain keeps desktop (≥900px, where the phone theme tokens
       aren't defined) on the legacy panel colours. */
    .settings-card {
      background: var(--card-bg, var(--panel));
      border: 1px solid var(--card-border, var(--border));
      border-radius: 16px;
      box-shadow: var(--card-shadow, none);
      overflow: hidden;
      margin-bottom: 20px;
    }
    /* flex-wrap + a min-content floor on the label column means a trailing
       control (segmented pill, switch) drops to its own line exactly when it
       would otherwise start clipping the label — no font-size step is
       assumed, so it self-corrects at any scale the user picks. */
    .settings-row {
      display: flex; align-items: center; flex-wrap: wrap; gap: 12px;
      padding: 12px 14px;
      cursor: pointer;
      border-bottom: 1px solid var(--card-border, var(--border));
      transition: background .15s ease;
    }
    /* Right-anchor the control whether it shares the label's line or wraps
       below it. Scoped to direct children so the same segmented-control
       class stays centred inside the Define Nearby modal. */
    .settings-row > .nearby-toggle-row,
    .settings-row > .fs-toggle-row,
    .settings-row > .profile-auto-toggle { margin-left: auto; }
    .settings-row:last-child { border-bottom: none; }
    .settings-row:hover  { background: var(--card-header-bg, #1a1a1a); }
    /* Touch devices never fire :hover, so the press state carries the
       feedback — a slightly stronger tint than hover in every theme. */
    .settings-row:active { background: var(--map-btn-bg, #1e1e1e); }
    /* Rows whose whole surface isn't a target (a toggle/segmented control
       does the work) shouldn't advertise one. */
    .settings-row.is-static { cursor: default; }
    .settings-row.is-static:hover, .settings-row.is-static:active { background: transparent; }
    /* Icon badge — same tile language as .board-map-btn / .m-sidebar-close.
       Sized in px on purpose: these are decorative glyphs sitting in a fixed
       box, so they hold their proportions across the text-size steps (the
       two largest steps bump the whole badge, see the overrides below). */
    .settings-row-icon {
      width: 32px; height: 32px; flex-shrink: 0;
      display: flex; align-items: center; justify-content: center;
      border-radius: 10px;
      background: var(--map-btn-bg, #1e1e1e);
      border: 1px solid var(--map-btn-border, var(--border));
      color: var(--map-btn-color, var(--muted));
      font-size: 16px; line-height: 1;
    }
    .settings-row-body { flex: 1; min-width: min-content; }
    .settings-row-label { font-family: var(--display); font-size: 0.75rem; font-weight: 700; color: var(--chip-text, var(--text)); }
    .settings-row-value { font-family: var(--mono); font-size: 0.6875rem; color: var(--chip-sub, var(--muted)); margin-top: 3px; }
    .settings-row-arrow {
      display: flex; align-items: center; flex-shrink: 0;
      color: var(--chip-sub, var(--muted));
      transition: color .15s ease, transform .15s ease;
    }
    .settings-row:hover .settings-row-arrow { color: var(--accent-text); transform: translateX(2px); }
    .settings-row.is-disabled { cursor: default; opacity: 0.5; }
    .settings-row.is-disabled:hover, .settings-row.is-disabled:active { background: transparent; }
    .settings-row.is-disabled:hover .settings-row-arrow { color: var(--chip-sub, var(--muted)); transform: none; }
    .settings-row.is-hidden { display: none; }

    /* MODAL CHROME — shared by every .nearby-modal in the app (Define
       Nearby, Quick Nearby Button, Themes, Announcements, stop Timetable,
       offline, iOS install). Deliberately common so all seven read as one
       component; only their bodies differ. */
    .nearby-modal-overlay {
      display: none; position: fixed; inset: 0;
      background: rgba(0,0,0,0.55);
      -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px);
      z-index: 500; justify-content: center; align-items: center; padding: 20px;
    }
    .nearby-modal-overlay.open { display: flex; animation: modal-overlay-in .18s ease; }
    .nearby-modal {
      background: var(--panel);
      border: 1px solid var(--card-border, var(--border));
      border-radius: 18px;
      box-shadow: 0 18px 48px rgba(0,0,0,0.45);
      width: 100%; max-width: 380px;
      display: flex; flex-direction: column; overflow: hidden;
      animation: modal-panel-in .2s cubic-bezier(.2,.8,.3,1);
    }
    @keyframes modal-overlay-in { from { opacity: 0; } to { opacity: 1; } }
    @keyframes modal-panel-in {
      from { opacity: 0; transform: translateY(10px) scale(0.97); }
      to   { opacity: 1; transform: none; }
    }
    @media (prefers-reduced-motion: reduce) {
      .nearby-modal-overlay.open, .nearby-modal { animation: none; }
    }
    /* Header follows .board-section-hdr: tinted strip + hairline rule,
       replacing the 2px full-bleed yellow rule this modal used to carry. */
    .nearby-modal-hdr {
      display: flex; align-items: center; gap: 10px;
      padding: 13px 14px;
      background: var(--card-header-bg, transparent);
      border-bottom: 1px solid var(--card-border, var(--border));
      position: relative; z-index: 2;
    }
    .nearby-modal-title { font-family: var(--display); font-size: 0.75rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.1em; color: var(--chip-text, var(--text)); flex: 1; min-width: 0; }
    .nearby-modal-close {
      background: var(--map-btn-bg, transparent);
      border: 1px solid var(--map-btn-border, var(--border));
      color: var(--chip-sub, var(--muted));
      width: 30px; height: 30px; border-radius: 9px;
      cursor: pointer; padding: 0; flex-shrink: 0;
      display: flex; align-items: center; justify-content: center;
      transition: background .15s ease, border-color .15s ease, color .15s ease;
    }
    .nearby-modal-close:hover  { border-color: var(--yellow); color: var(--accent-text); }
    .nearby-modal-close:active { background: var(--card-header-bg, transparent); }
    .nearby-modal-body { padding: 16px; display: flex; flex-direction: column; gap: 14px; }
    /* PA system: alert cards + unread badge */
    .alert-card { border: 1px solid var(--border); border-left: 3px solid var(--yellow); padding: 10px 12px; display: flex; flex-direction: column; gap: 4px; cursor: pointer; }
    .alert-card.collapsed .alert-card-body, .alert-card.collapsed .t-open { display: none; }
    .alert-card:not(.collapsed) .t-closed { display: none; }
    .alert-card.warning { border-left-color: #e67e22; }
    .alert-new { align-self: flex-start; background: #e67e22; color: #fff; font-size: 0.5625rem; font-weight: 700; letter-spacing: 0.05em; padding: 1px 6px; border-radius: 8px; }
    .alert-card-title { font-family: var(--display); font-size: 0.75rem; font-weight: 700; color: var(--text); }
    .alert-card-body { font-size: 0.6875rem; color: var(--muted); line-height: 1.5; }
    .alert-card-meta { font-size: 0.625rem; color: var(--muted); display: flex; justify-content: space-between; gap: 8px; letter-spacing: 0.05em; }
    .alert-card-meta a { color: var(--accent-text); text-decoration: none; }
    .alerts-empty { text-align: center; color: var(--muted); font-size: 0.75rem; padding: 18px 0; }
    .alerts-count { position: absolute; top: -5px; right: -5px; background: #e67e22; color: #fff; font-size: 0.5625rem; font-weight: 700; min-width: 15px; height: 15px; border-radius: 8px; display: none; align-items: center; justify-content: center; padding: 0 3px; }
    .alerts-count.on { display: flex; }
    .route-alert-ico { color: #e67e22; display: flex; align-items: center; flex-shrink: 0; cursor: pointer; }
    .route-alert-ico .ico { width: 13px; height: 13px; }
    .stop-go-btn { background: none; border: 1px solid var(--border); color: var(--accent-text); width: 24px; height: 24px; border-radius: 6px; display: flex; align-items: center; justify-content: center; cursor: pointer; padding: 0; flex-shrink: 0; }
    /* SEGMENTED CONTROLS — button alignment, text-size steps, nearby unit.
       A pill track with a single filled chip, in the spirit of the sliding
       .profile-auto-toggle rather than glued-together square buttons. The
       active chip borrows the FAB nav's active pair so it matches the
       TIME/MAP/SET pill in every theme (yellow on most, blue on powder). */
    .nearby-toggle-row, .fs-toggle-row {
      display: flex; align-items: center;
      align-self: center; width: max-content;
      gap: 2px; padding: 3px;
      background: var(--map-btn-bg, #1e1e1e);
      border: 1px solid var(--map-btn-border, var(--border));
      border-radius: 999px;
    }
    .nearby-toggle-btn, .fs-toggle-row .fs-btn {
      font-family: var(--mono);
      background: transparent; border: none; border-radius: 999px;
      color: var(--chip-sub, var(--muted));
      cursor: pointer; line-height: 1;
      display: inline-flex; align-items: center; justify-content: center; gap: 6px;
      touch-action: manipulation; -webkit-tap-highlight-color: transparent;
      transition: background .18s ease, color .18s ease;
    }
    .nearby-toggle-btn { font-size: 0.75rem; padding: 7px 16px; }
    .fs-toggle-row .fs-btn { padding: 6px 7px; min-width: 26px; }
    .nearby-toggle-btn.active, .fs-toggle-row .fs-btn.active {
      background: var(--nav-active-bg, var(--yellow));
      color: var(--nav-active-color, var(--dark));
      font-weight: 700;
      box-shadow: 0 1px 3px rgba(0,0,0,0.22);
    }
    .nearby-input-row { display: flex; align-items: center; gap: 10px; justify-content: center; }
    .nearby-input { width: 88px; text-align: center; background: var(--map-btn-bg, #1e1e1e); border: 1px solid var(--map-btn-border, var(--border)); border-radius: 10px; color: var(--chip-text, var(--text)); font-family: var(--mono); font-size: 1rem; font-weight: 500; padding: 9px 6px; outline: none; transition: border-color .15s ease; }
    .nearby-input:focus { border-color: var(--yellow); }
    .nearby-unit-label { font-family: var(--mono); font-size: 0.75rem; color: var(--chip-sub, var(--muted)); text-transform: uppercase; letter-spacing: 0.06em; min-width: 30px; }
    #nearby-map { width: 100%; height: 200px; border: 1px solid var(--card-border, var(--border)); border-radius: 12px; overflow: hidden; }
    /* Primary / secondary action buttons — shared by the nearby, iOS-install
       and offline modals so one press treatment covers all of them. */
    .nearby-save-btn, .offline-btn {
      padding: 12px; border-radius: 12px;
      font-family: var(--display); font-size: 0.75rem; font-weight: 700;
      text-transform: uppercase; letter-spacing: 0.1em;
      cursor: pointer;
      transition: filter .15s ease, border-color .15s ease, color .15s ease, transform .1s ease;
    }
    .nearby-save-btn, .offline-btn-primary {
      border: 1px solid var(--nav-active-bg, var(--yellow));
      background: var(--nav-active-bg, var(--yellow));
      color: var(--nav-active-color, var(--dark));
    }
    .nearby-save-btn { width: 100%; }
    .nearby-save-btn:hover, .offline-btn-primary:hover { filter: brightness(0.93); }
    .nearby-save-btn:active, .offline-btn:active { transform: scale(0.985); }
    .offline-btn-row { display: flex; gap: 10px; }
    .offline-btn { flex: 1; }
    .offline-btn-secondary { border: 1px solid var(--map-btn-border, var(--border)); background: var(--map-btn-bg, transparent); color: var(--chip-text, var(--text)); }
    .offline-btn-secondary:hover { border-color: var(--yellow); color: var(--accent-text); }

    /* BUG REPORT form — lives in the shared .nearby-modal chrome; only these
       field styles are new. Labels follow .profile-section-label, inputs
       follow .profile-input, and the category picker reuses the .theme-row
       look for its revealed options so the modal reads as one family. */
    .bug-field { display: flex; flex-direction: column; gap: 6px; }
    .bug-label {
      font-family: var(--display); font-size: 0.625rem; font-weight: 700;
      text-transform: uppercase; letter-spacing: 0.1em; color: var(--muted);
    }
    .bug-req { color: #e0483d; }
    .bug-input {
      width: 100%; box-sizing: border-box;
      background: var(--map-btn-bg, #1e1e1e);
      border: 1px solid var(--map-btn-border, var(--border));
      color: var(--chip-text, var(--text));
      font-family: var(--mono); font-size: 0.8125rem; line-height: 1.5;
      padding: 9px 10px; border-radius: 10px; outline: none;
      transition: border-color .15s ease;
    }
    .bug-input:focus { border-color: var(--yellow); }
    .bug-input::placeholder { color: var(--muted); opacity: 0.75; }
    .bug-textarea { resize: vertical; min-height: 96px; }
    /* Category: a button that reveals its options in place, rather than a
       native <select> (unstyleable across platforms) or a fixed pill row. */
    .bug-select {
      display: flex; align-items: center; gap: 10px; width: 100%;
      padding: 9px 10px; border-radius: 10px; cursor: pointer; text-align: left;
      background: var(--map-btn-bg, #1e1e1e);
      border: 1px solid var(--map-btn-border, var(--border));
      color: var(--chip-text, var(--text));
      font-family: var(--mono); font-size: 0.8125rem;
      transition: border-color .15s ease;
    }
    .bug-select:hover { border-color: var(--yellow); }
    .bug-select.is-open { border-color: var(--yellow); }
    .bug-select-value { flex: 1; min-width: 0; }
    .bug-select.is-empty .bug-select-value { color: var(--muted); }
    .bug-select-chev { width: 13px; height: 13px; flex-shrink: 0; color: var(--chip-sub, var(--muted)); transform: rotate(90deg); transition: transform .18s ease; }
    .bug-select.is-open .bug-select-chev { transform: rotate(-90deg); }
    .bug-options { display: none; flex-direction: column; gap: 6px; }
    .bug-options.open { display: flex; }
    .bug-option {
      display: flex; align-items: center; gap: 10px; width: 100%;
      padding: 9px 12px; border-radius: 10px;
      background: transparent;
      border: 1px solid var(--card-border, var(--border));
      color: var(--chip-text, var(--text));
      font-family: var(--display); font-size: 0.75rem; font-weight: 700;
      cursor: pointer; text-align: left;
      transition: background .15s ease, border-color .15s ease;
    }
    .bug-option:hover  { background: var(--card-header-bg, #1a1a1a); }
    .bug-option.active { border-color: var(--yellow); background: var(--card-header-bg, #1a1a1a); }
    .bug-option-check { margin-left: auto; color: var(--accent-text); font-size: 0.875rem; visibility: hidden; }
    .bug-option.active .bug-option-check { visibility: visible; }
    /* Live word count under the description. Turns amber below the minimum so
       a disabled Send button always has a visible reason next to it. */
    .bug-count { font-family: var(--mono); font-size: 0.625rem; color: var(--muted); text-align: right; }
    .bug-count.under { color: #e0a33d; }
    /* Honeypot — off-canvas rather than display:none, since a bot that skips
       hidden inputs is exactly the one worth catching. aria-hidden and
       tabindex="-1" on the markup keep it away from real users. */
    .bug-honeypot {
      position: absolute; left: -9999px; top: auto;
      width: 1px; height: 1px; overflow: hidden;
    }
    .bug-status { font-family: var(--mono); font-size: 0.6875rem; line-height: 1.5; color: var(--muted); display: none; }
    .bug-status.show { display: block; }
    .bug-status.error { color: #e0483d; }
    .bug-status.ok    { color: var(--accent-text); }
    /* Submit stays disabled until every required field is filled — the whole
       validation story, so it has to read as clearly unavailable. */
    .nearby-save-btn:disabled { opacity: 0.45; cursor: not-allowed; filter: none; }
    .nearby-save-btn:disabled:active { transform: none; }

    /* THEMES PICKER rows — kept outside the phone media query (unlike before)
       so the modal is styled at every width; the tokens fall back to the
       legacy vars on desktop. */
    .theme-row {
      display: flex; align-items: center; gap: 12px;
      padding: 11px 12px; width: 100%;
      background: transparent;
      border: 1px solid var(--card-border, var(--border));
      border-radius: 12px;
      cursor: pointer; text-align: left; font-family: inherit;
      transition: background .15s ease, border-color .15s ease;
    }
    .theme-row:hover  { background: var(--card-header-bg, #1a1a1a); }
    .theme-row:active { background: var(--map-btn-bg, #1e1e1e); }
    .theme-row.active { border-color: var(--yellow); background: var(--card-header-bg, #1a1a1a); }
    .theme-swatch { width: 42px; height: 26px; border-radius: 7px; flex-shrink: 0; display: flex; overflow: hidden; border: 1px solid var(--card-border, rgba(0,0,0,0.15)); }
    .theme-swatch span { flex: 1; display: block; }
    .theme-row-name { flex: 1; min-width: 0; font-family: var(--display); font-size: 0.75rem; font-weight: 700; color: var(--chip-text, var(--text)); }
    .theme-row-check { font-size: 0.875rem; color: var(--accent-text); width: 16px; text-align: right; flex-shrink: 0; }
    .theme-row:not(.active) .theme-row-check { visibility: hidden; }
    .bottom-nav { display: flex; background: var(--panel); border-top: 1px solid var(--border); flex-shrink: 0; padding-bottom: env(safe-area-inset-bottom); }
    @media (max-width: 380px) { .stat-label { display: none; } .stat-value { font-size: 0.75rem; } h1 { font-size: 0.8125rem; } }
    .nav-btn { flex: 1; background: none; border: none; color: var(--muted); font-size: 1.375rem; padding: 8px 4px 5px; cursor: pointer; display: flex; flex-direction: column; align-items: center; gap: 2px; transition: color .15s; }
    .nav-btn.active { color: var(--accent-text); }
    .nav-btn span { font-family: var(--mono); font-size: 0.5rem; text-transform: uppercase; letter-spacing: 0.06em; }
    /* SVG icon system — cross-platform consistent rendering */
    .ico { display: inline-block; width: 1em; height: 1em; vertical-align: -0.125em; fill: currentColor; }
    .nav-btn .ico { width: 22px; height: 22px; }
    .icon-btn .ico { width: 16px; height: 16px; }
    .board-gear .ico { width: 14px; height: 14px; }
    .board-map-btn .ico { width: 12px; height: 12px; }
    .settings-row-icon .ico { width: 16px; height: 16px; }

    /* TIMELINE BOARD */
    #view-timeline { background: #080808; position: relative; }
    .board-header { display: flex; align-items: center; padding: 10px 14px 8px; border-bottom: 1px solid #161616; flex-shrink: 0; gap: 8px; }
    .board-title { font-family: var(--display); font-size: 0.6875rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.15em; color: #FFB300; flex: 1; }
    .board-gear { background: transparent; border: 1px solid #222; color: #444; font-size: 0.875rem; width: 30px; height: 30px; cursor: pointer; display: flex; align-items: center; justify-content: center; transition: all .15s; }
    .board-gear:hover { border-color: #FFB300; color: #FFB300; }
    .board-wrap { flex: 1; overflow-y: auto; }
    .board-section { border-bottom: 1px solid #111; padding: 4px 0; }
    .board-section-hdr { display: flex; align-items: center; padding: 6px 14px 2px; gap: 6px; }
    /* min-width:0 is load-bearing: without it a flex item won't shrink below
       its longest word, so at the larger font scales a long stop name pushed
       the walk/map buttons clean off the screen. */
    .board-section-label { font-size: 0.5625rem; color: #3a3a3a; text-transform: uppercase; letter-spacing: 0.1em; flex: 1; min-width: 0; }
    .board-map-btn { background: none; border: 1px solid #222; color: #3a3a3a; font-size: 0.75rem; width: 24px; height: 20px; cursor: pointer; display: flex; align-items: center; justify-content: center; transition: all .15s; flex-shrink: 0; padding: 0; }
    .board-map-btn:hover { border-color: #FFB300; color: #FFB300; }
    .board-row { display: flex; align-items: center; padding: 7px 14px; }
    .board-row:hover { background: #0e0e0e; }
    .board-badge { font-family: var(--display); font-size: 1.0625rem; font-weight: 800; min-width: 52px; max-width: 72px; flex-shrink: 0; letter-spacing: -0.02em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding-right: 6px; }
    .board-badge-icon { display: flex; align-items: center; justify-content: center; padding: 0 6px 0 0; }
    .board-badge-icon img { height: 28px; width: auto; display: block; }
    .board-dest { flex: 1; min-width: 0; font-size: 0.75rem; color: #FFB300; letter-spacing: 0.04em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-family: var(--mono); }
    /* "Nothing running" row: sits in the .board-dest slot but reads as muted,
       and stays out of the marquee selector so it never scrolls. */
    .board-quiet-text { flex: 1; min-width: 0; font-size: 0.75rem; color: #6a6a6a; letter-spacing: 0.04em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-family: var(--mono); }
    .board-time { font-size: 0.8125rem; color: #FFB300; text-align: right; white-space: nowrap; min-width: 64px; flex-shrink: 0; letter-spacing: 0.02em; font-family: var(--mono); padding-left: 8px; }
    .board-time.urgent { color: #ff5533; }
    .board-time.board-now { color: #ff5533; }
    .board-empty { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px; background: none; border: none; color: inherit; cursor: pointer; padding: 20px; font: inherit; width: 100%; }
    .board-empty-icon { font-size: 2.5rem; color: #222; }
    .board-empty-text { font-size: 0.625rem; text-transform: uppercase; letter-spacing: 0.12em; color: #333; }
    .board-msg { font-size: 0.625rem; color: #FFB300; text-align: center; padding: 20px; opacity: 0.7; }
    /* BOARD SETTINGS OVERLAY */
    .board-settings-overlay { display: none; position: absolute; inset: 0; background: rgba(0,0,0,0.5); z-index: 200; flex-direction: column; justify-content: flex-end; }
    .board-settings-overlay.open { display: flex; }
    .board-settings-panel { background: var(--panel); border-top: 1px solid var(--border); max-height: 85%; display: flex; flex-direction: column; overflow: hidden; }
    .board-settings-hdr { display: flex; align-items: center; padding: 10px 12px; border-bottom: 1px solid var(--border); gap: 8px; flex-shrink: 0; }
    .board-settings-hdr-title { font-family: var(--display); font-size: 0.625rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.1em; color: var(--muted); flex: 1; }
    .board-settings-close { background: none; border: 1px solid var(--border); color: var(--muted); font-size: 0.75rem; width: 26px; height: 26px; cursor: pointer; display: flex; align-items: center; justify-content: center; }
    .board-settings-close:hover { border-color: var(--yellow); color: var(--accent-text); }
    .board-settings-search-wrap { padding: 8px 12px; border-bottom: 1px solid var(--border); flex-shrink: 0; }
    #board-search { width: 100%; background: var(--map-btn-bg, #1e1e1e); border: 1px solid var(--map-btn-border, var(--border)); color: var(--chip-text, var(--text)); font-family: var(--mono); font-size: 0.75rem; padding: 6px 9px; outline: none; }
    #board-search:focus { border-color: var(--yellow); }
    #board-search::placeholder { color: var(--muted); }
    .board-settings-list { flex: 1; overflow-y: auto; }
    .board-settings-item { display: flex; align-items: center; gap: 8px; padding: 7px 12px; cursor: pointer; transition: background .1s; }
    .board-settings-item:hover { background: #1e1e1e; }
    .board-settings-dot { width: 11px; height: 11px; border-radius: 3px; flex-shrink: 0; border: 1.5px solid #333; transition: all .15s; }
    .board-settings-item.pinned .board-settings-dot { border-color: transparent; }
    .board-settings-info { flex: 1; min-width: 0; }
    .board-settings-name { font-family: var(--display); font-size: 0.75rem; font-weight: 700; color: var(--text); }
    .board-settings-long { font-size: 0.5625rem; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-top: 1px; }

    /* ───────────────────────────────────────────────────────────
       PHONE REWORK (< 900px) — tokenised for theme switching.
       Defaults below match the original dark+yellow look.
       Theme overrides live in body.theme-X { ... } blocks further
       down. Desktop (≥ 900px) falls through unchanged.
       ─────────────────────────────────────────────────────────── */
    .m-chip, .m-search-btn, .m-alerts-btn, .m-zoom-stack, .m-fab, .phone-page-hdr { display: none; }
    @media (max-width: 899px) {
      /* ── Theme tokens (Default) ────────────────────────────── */
      body {
        --phone-bg:           #0d1014;
        --tile-bg:            #0a0a0a;
        --chip-bg:            rgba(0,0,0,0.7);
        --chip-border:        rgba(255,255,255,0.15);
        --chip-text:          #fff;
        --chip-sub:           #9098a0;
        --chip-live:          #2FB157;
        --card-bg:            rgba(255,255,255,0.04);
        --card-border:        rgba(255,255,255,0.07);
        --card-header-bg:     rgba(255,255,255,0.03);
        --map-btn-bg:         rgba(255,255,255,0.06);
        --map-btn-border:     rgba(255,255,255,0.07);
        --map-btn-color:      #f0f0f0;
        --gear-bg:            rgba(255,208,0,0.1);
        --gear-border:        rgba(255,208,0,0.35);
        --gear-color:         #FFD000;
        --fab-nav-bg:         rgba(20,24,30,0.82);
        --fab-nav-border:     rgba(255,255,255,0.08);
        --nav-active-bg:      #FFD000;
        --nav-active-color:   #111;
        --nav-inactive-color: #ccd0d5;
        --fab-border:         2px solid #111;
        --fab-shadow:         0 6px 16px rgba(255,208,0,0.4);
        --urgent-row-bg:      rgba(224,62,62,0.05);
        --sidebar-title:      #6a727b;
        --card-shadow:        0 2px 12px rgba(0,0,0,0.35);
      }
      body.theme-light {
        --phone-bg:           #f5f5f7;
        --tile-bg:            #e8e8eb;
        --chip-bg:            rgba(255,255,255,0.85);
        --chip-border:        rgba(0,0,0,0.08);
        --chip-text:          #111;
        --chip-sub:           #6e6e73;
        --chip-live:          #2FB157;
        --card-bg:            rgba(255,255,255,0.92);
        --card-border:        rgba(0,0,0,0.09);
        --card-header-bg:     rgba(0,0,0,0.02);
        --map-btn-bg:         rgba(0,0,0,0.04);
        --map-btn-border:     rgba(0,0,0,0.1);
        --map-btn-color:      #333;
        --gear-bg:            rgba(247,209,23,0.18);
        --gear-border:        rgba(247,209,23,0.45);
        --gear-color:         #7a6300;
        --fab-nav-bg:         rgba(255,255,255,0.9);
        --fab-nav-border:     rgba(0,0,0,0.08);
        --nav-active-bg:      #FFD000;
        --nav-active-color:   #111;
        --nav-inactive-color: #3a3a3c;
        --fab-border:         1.5px solid rgba(0,0,0,0.15);
        --fab-shadow:         0 4px 16px rgba(247,209,23,0.5);
        --urgent-row-bg:      rgba(224,62,62,0.05);
        --sidebar-title:      #6e6e73;
        --card-shadow:        0 1px 2px rgba(0,0,0,0.04), 0 6px 16px rgba(0,0,0,0.07);
      }
      body.theme-pearl {
        --phone-bg:           #eef2f8;
        --tile-bg:            #dde4ef;
        --chip-bg:            rgba(255,255,255,0.78);
        --chip-border:        rgba(160,190,220,0.35);
        --chip-text:          #2a3a4a;
        --chip-sub:           #5a6a7e;
        --chip-live:          #3aaa70;
        --card-bg:            rgba(255,255,255,0.8);
        --card-border:        rgba(160,190,220,0.35);
        --card-header-bg:     rgba(200,218,240,0.25);
        --map-btn-bg:         rgba(160,190,220,0.2);
        --map-btn-border:     rgba(160,190,220,0.4);
        --map-btn-color:      #4a6a90;
        --gear-bg:            rgba(247,209,23,0.14);
        --gear-border:        rgba(247,209,23,0.38);
        --gear-color:         #7a6800;
        --fab-nav-bg:         rgba(255,255,255,0.84);
        --fab-nav-border:     rgba(160,190,220,0.3);
        --nav-active-bg:      #FFD000;
        --nav-active-color:   #1a2a3a;
        --nav-inactive-color: #7a9ab8;
        --fab-border:         1.5px solid rgba(160,190,220,0.4);
        --fab-shadow:         0 6px 18px rgba(120,170,220,0.3);
        --urgent-row-bg:      rgba(224,62,62,0.05);
        --sidebar-title:      #7a9ab8;
        --card-shadow:        0 1px 2px rgba(120,170,220,0.10), 0 6px 16px rgba(120,170,220,0.16);
      }
      body.theme-powder {
        --phone-bg:           #dce8f5;
        --tile-bg:            #c9d8ec;
        --chip-bg:            rgba(200,222,245,0.72);
        --chip-border:        rgba(120,170,220,0.3);
        --chip-text:          #1e3050;
        --chip-sub:           #455566;
        --chip-live:          #2a9e60;
        --card-bg:            rgba(205,225,248,0.75);
        --card-border:        rgba(120,170,220,0.3);
        --card-header-bg:     rgba(120,170,220,0.12);
        --map-btn-bg:         rgba(80,130,200,0.14);
        --map-btn-border:     rgba(80,130,200,0.28);
        --map-btn-color:      #3060a0;
        --gear-bg:            rgba(247,209,23,0.18);
        --gear-border:        rgba(247,209,23,0.42);
        --gear-color:         #7a6200;
        --fab-nav-bg:         rgba(210,228,248,0.9);
        --fab-nav-border:     rgba(120,170,220,0.28);
        --nav-active-bg:      #5b9bd5;
        --nav-active-color:   #fff;
        --nav-inactive-color: #4a6a90;
        --fab-border:         1.5px solid rgba(80,130,200,0.25);
        --fab-shadow:         0 6px 18px rgba(100,160,230,0.38);
        --urgent-row-bg:      rgba(224,62,62,0.06);
        --sidebar-title:      #5a82aa;
        --card-shadow:        0 1px 2px rgba(60,110,180,0.10), 0 6px 16px rgba(60,110,180,0.16);
      }
      body.theme-pastel {
        --phone-bg:           #1a1428;
        --tile-bg:            #100a1c;
        --chip-bg:            rgba(180,160,240,0.22);
        --chip-border:        rgba(200,180,255,0.25);
        --chip-text:          #e8e0f8;
        --chip-sub:           #c8bcd8;
        --chip-live:          #7ee8b0;
        --card-bg:            rgba(180,160,240,0.1);
        --card-border:        rgba(200,180,255,0.18);
        --card-header-bg:     rgba(180,160,240,0.08);
        --map-btn-bg:         rgba(200,180,255,0.1);
        --map-btn-border:     rgba(200,180,255,0.22);
        --map-btn-color:      #c9a8ff;
        --gear-bg:            rgba(247,209,23,0.1);
        --gear-border:        rgba(247,209,23,0.3);
        --gear-color:         #FFD000;
        --fab-nav-bg:         rgba(48,34,80,0.9);
        --fab-nav-border:     rgba(200,180,255,0.2);
        --nav-active-bg:      #c9a8ff;
        --nav-active-color:   #1a1428;
        --nav-inactive-color: #b4a0d8;
        --fab-border:         2px solid rgba(255,255,255,0.2);
        --fab-shadow:         0 6px 18px rgba(160,120,255,0.35);
        --urgent-row-bg:      rgba(224,62,62,0.07);
        --sidebar-title:      #b4a0d8;
        --card-shadow:        0 2px 12px rgba(0,0,0,0.30);
      }
      body.theme-midnight {
        --phone-bg:           #060e1c;
        --tile-bg:            #04091a;
        --chip-bg:            rgba(20,44,80,0.82);
        --chip-border:        rgba(100,160,230,0.2);
        --chip-text:          #c8dff5;
        --chip-sub:           #a4b6ce;
        --chip-live:          #4cd9a0;
        --card-bg:            rgba(20,44,80,0.45);
        --card-border:        rgba(100,160,230,0.15);
        --card-header-bg:     rgba(20,44,80,0.3);
        --map-btn-bg:         rgba(100,160,230,0.1);
        --map-btn-border:     rgba(100,160,230,0.22);
        --map-btn-color:      #a8c4e8;
        --gear-bg:            rgba(247,209,23,0.1);
        --gear-border:        rgba(247,209,23,0.3);
        --gear-color:         #FFD000;
        --fab-nav-bg:         rgba(10,26,54,0.94);
        --fab-nav-border:     rgba(100,160,230,0.18);
        --nav-active-bg:      #FFD000;
        --nav-active-color:   #060e1c;
        --nav-inactive-color: #6a8cb0;
        --fab-border:         2px solid rgba(100,160,230,0.3);
        --fab-shadow:         0 6px 18px rgba(247,209,23,0.3);
        --urgent-row-bg:      rgba(224,62,62,0.07);
        --sidebar-title:      #6a8cb0;
        --card-shadow:        0 2px 12px rgba(0,0,0,0.35);
      }
      body.theme-warm-earth {
        --phone-bg:           #1a1008;
        --tile-bg:            #f0ece4;
        --chip-bg:            rgba(80,48,20,0.82);
        --chip-border:        rgba(220,160,80,0.22);
        --chip-text:          #e8d5b8;
        --chip-sub:           #c8b090;
        --chip-live:          #8fb04a;
        --card-bg:            rgba(80,48,20,0.38);
        --card-border:        rgba(220,160,80,0.18);
        --card-header-bg:     rgba(80,48,20,0.28);
        --map-btn-bg:         rgba(220,160,80,0.1);
        --map-btn-border:     rgba(220,160,80,0.22);
        --map-btn-color:      #e8d5b8;
        --gear-bg:            rgba(247,209,23,0.1);
        --gear-border:        rgba(247,209,23,0.3);
        --gear-color:         #FFD000;
        --fab-nav-bg:         rgba(48,28,8,0.94);
        --fab-nav-border:     rgba(220,160,80,0.2);
        --nav-active-bg:      #e07040;
        --nav-active-color:   #fff8f0;
        --nav-inactive-color: #a88050;
        --fab-border:         2px solid rgba(220,160,80,0.3);
        --fab-shadow:         0 6px 18px rgba(200,112,80,0.38);
        --urgent-row-bg:      rgba(224,62,62,0.07);
        --sidebar-title:      #a88050;
        --card-shadow:        0 2px 12px rgba(0,0,0,0.35);
      }
      /* Every theme flips the legacy dark vars so modals + leaflet popups
         take the theme's tint rather than the default charcoal. */
      body.theme-light {
        --panel:  #ffffff;
        --border: rgba(0,0,0,0.1);
        --text:   #111;
        --muted:  #6e6e73;
        --accent-text: #8a6d00;
      }
      /* Pearl + powder are blue-tinted, not plain white — give them their own
         legacy vars (derived from each theme's chip palette) so modals and
         leaflet popups match the theme instead of reading stark white. */
      body.theme-pearl      { --panel: #f4f8fc; --border: rgba(160,190,220,0.45); --text: #2a3a4a; --muted: #5a6a7e; --accent-text: #7d6100; }
      body.theme-powder     { --panel: #e7f0fb; --border: rgba(120,170,220,0.40); --text: #1e3050; --muted: #455566; --accent-text: #6a5200; }
      body.theme-pastel     { --panel: #241a3e; --border: rgba(201,168,255,0.18); --text: #efe8ff; --muted: #c8bcd8; }
      body.theme-midnight   { --panel: #0b1a30; --border: rgba(100,160,230,0.18); --text: #e8eef8; --muted: #a4b6ce; }
      body.theme-warm-earth { --panel: #241408; --border: rgba(220,160,80,0.2);   --text: #e8d5b8; --muted: #c8b090; }
      body.theme-forest     { --panel: #0f2418; --border: rgba(100,200,120,0.16); --text: #c8e8d0; --muted: #98b0a0; }
      body.theme-forest {
        --phone-bg:           #0a1410;
        --tile-bg:            #050d08;
        --chip-bg:            rgba(20,50,30,0.85);
        --chip-border:        rgba(100,200,120,0.2);
        --chip-text:          #c8e8d0;
        --chip-sub:           #98b0a0;
        --chip-live:          #6ade90;
        --card-bg:            rgba(20,50,30,0.48);
        --card-border:        rgba(100,200,120,0.15);
        --card-header-bg:     rgba(20,50,30,0.3);
        --map-btn-bg:         rgba(100,200,120,0.1);
        --map-btn-border:     rgba(100,200,120,0.22);
        --map-btn-color:      #c8e8d0;
        --gear-bg:            rgba(247,209,23,0.1);
        --gear-border:        rgba(247,209,23,0.3);
        --gear-color:         #FFD000;
        --fab-nav-bg:         rgba(12,36,20,0.94);
        --fab-nav-border:     rgba(100,200,120,0.18);
        --nav-active-bg:      #FFD000;
        --nav-active-color:   #0a1410;
        --nav-inactive-color: #6a9878;
        --fab-border:         2px solid rgba(100,200,120,0.3);
        --fab-shadow:         0 6px 18px rgba(80,200,100,0.32);
        --urgent-row-bg:      rgba(224,62,62,0.07);
        --sidebar-title:      #6a9878;
        --card-shadow:        0 2px 12px rgba(0,0,0,0.35);
      }

      /* Hide desktop chrome */
      body > header { display: none; }
      .bottom-nav { display: none; }
      .leaflet-control-zoom { display: none !important; }
      footer { display: none; }
      .board-gear { display: none; }
      .board-header { padding: 0; border-bottom: none; }
      .board-title { display: none; }

      /* Phone backgrounds + tile pane fallback */
      #view-timeline, #view-settings { background: var(--phone-bg); color: var(--chip-text); }
      .leaflet-container { background: var(--tile-bg); }

      /* ── Floating chip (top-left) ──────────────────────────── */
      .m-chip {
        position: fixed;
        top: calc(8px + env(safe-area-inset-top));
        left: 12px;
        z-index: 1100;
        display: flex; align-items: center; gap: 8px;
        pointer-events: none;
      }
      .m-chip .bus-badge { pointer-events: auto; }
      .m-chip-body {
        background: var(--chip-bg);
        -webkit-backdrop-filter: blur(8px);
        backdrop-filter: blur(8px);
        color: var(--chip-text);
        border: 1px solid var(--chip-border);
        padding: 6px 10px;
        border-radius: 8px;
        font-family: var(--mono);
        font-size: 0.6875rem;
        font-weight: 700;
        letter-spacing: 0.05em;
        display: flex; align-items: center; gap: 6px;
        pointer-events: auto;
      }
      .m-chip-label { color: var(--chip-sub); font-weight: 500; }
      .m-chip-sep   { color: var(--chip-sub); opacity: 0.5; }
      .m-chip-dot   {
        width: 7px; height: 7px; border-radius: 50%;
        background: var(--chip-live);
        box-shadow: 0 0 5px var(--chip-live);
        flex-shrink: 0;
      }

      /* ── Search button (top-right) ─────────────────────────── */
      .m-search-btn {
        position: fixed;
        top: calc(8px + env(safe-area-inset-top));
        right: calc(12px + env(safe-area-inset-right));
        z-index: 1100;
        width: 42px; height: 42px; border-radius: 21px;
        background: var(--chip-bg);
        -webkit-backdrop-filter: blur(8px);
        backdrop-filter: blur(8px);
        border: 1px solid var(--chip-border);
        color: var(--chip-text);
        display: flex; align-items: center; justify-content: center;
        cursor: pointer; padding: 0;
      }
      .m-search-btn .ico { width: 18px; height: 18px; }

      /* ── PA alerts button (top-left, under the AC chip) ────── */
      .m-alerts-btn {
        position: fixed;
        top: calc(52px + env(safe-area-inset-top));
        left: 12px;
        z-index: 1100;
        width: 42px; height: 42px; border-radius: 21px;
        background: var(--chip-bg);
        -webkit-backdrop-filter: blur(8px);
        backdrop-filter: blur(8px);
        border: 1px solid var(--chip-border);
        color: var(--chip-text);
        display: flex; align-items: center; justify-content: center;
        cursor: pointer; padding: 0;
      }
      .m-alerts-btn .ico { width: 18px; height: 18px; }
      .m-alerts-btn.active { color: #e67e22; border-color: #e67e22; }

      /* ── Right-edge zoom + locate stack ────────────────────── */
      .m-zoom-stack {
        position: fixed;
        top: 50%; transform: translateY(-50%);
        right: calc(10px + env(safe-area-inset-right));
        z-index: 1100;
        display: flex; flex-direction: column; gap: 6px;
      }
      .m-zoom-stack button {
        width: 36px; height: 36px; border-radius: 10px;
        background: var(--fab-nav-bg);
        -webkit-backdrop-filter: blur(10px);
        backdrop-filter: blur(10px);
        border: 1px solid var(--fab-nav-border);
        color: var(--chip-text);
        display: flex; align-items: center; justify-content: center;
        cursor: pointer; padding: 0;
      }
      .m-zoom-stack .ico { width: 16px; height: 16px; }

      /* Zoom/locate stack only over the map */
      body:not([data-view="map"]) .m-zoom-stack,
      body:not([data-view="map"]) .m-chip,
      body:not([data-view="map"]) .m-near-btn,
      body:not([data-view="map"]) .m-alerts-btn,
      body:not([data-view="map"]) .m-search-btn { display: none; }

      /* ── FAB (bottom-right, persistent) ────────────────────── */
      .m-fab {
        position: fixed;
        bottom: calc(20px + env(safe-area-inset-bottom));
        right: calc(16px + env(safe-area-inset-right));
        z-index: 1200;
        display: flex; flex-direction: column; align-items: center; gap: 8px;
        /* Container is 62 x ~254px because the closed .m-fab-stack still takes
           layout space above the yellow disc. Without this, that empty column
           swallows taps on any control that happens to sit under it (e.g. the
           right-most Text-size buttons in Settings). Only the disc itself and
           the open stack should intercept. */
        pointer-events: none;
      }
      .m-fab-main { pointer-events: auto; }
      .m-fab-stack {
        background: var(--fab-nav-bg);
        -webkit-backdrop-filter: blur(10px);
        backdrop-filter: blur(10px);
        border: 1px solid var(--fab-nav-border);
        border-radius: 22px;
        padding: 6px;
        display: flex; flex-direction: column; gap: 4px;
        opacity: 0; transform: translateY(8px) scale(0.96);
        transform-origin: bottom center;
        pointer-events: none;
        transition: opacity .15s ease, transform .15s ease;
      }
      .m-fab.open .m-fab-stack {
        opacity: 1; transform: translateY(0) scale(1);
        pointer-events: auto;
      }
      .m-fab-item {
        width: 50px; height: 54px; border-radius: 16px;
        background: transparent;
        border: none;
        color: var(--nav-inactive-color);
        display: flex; flex-direction: column; align-items: center;
        justify-content: center; gap: 3px;
        cursor: pointer; padding: 0;
        font-family: var(--mono);
      }
      .m-fab-item .ico { width: 20px; height: 20px; }
      .m-fab-item-label { font-size: 0.5rem; font-weight: 700; letter-spacing: 0.06em; }
      body[data-view="map"]      .m-fab-item[data-view="map"],
      body[data-view="timeline"] .m-fab-item[data-view="timeline"],
      body[data-view="settings"] .m-fab-item[data-view="settings"] {
        background: var(--nav-active-bg); color: var(--nav-active-color);
      }
      .m-fab-main {
        width: 62px; height: 62px; border-radius: 50%;
        background: var(--yellow); color: #111;
        display: flex; align-items: center; justify-content: center;
        border: var(--fab-border);
        box-shadow: var(--fab-shadow);
        cursor: pointer; padding: 0;
        transition: transform .15s ease;
      }
      .m-fab.open .m-fab-main { transform: rotate(90deg); }
      .m-fab-main .ico { width: 24px; height: 24px; }

      /* Quick Nearby Button — floats to the left of the main FAB. */
      .m-near-btn {
        position: fixed;
        bottom: calc(20px + env(safe-area-inset-bottom));
        right: calc(16px + 62px + 12px + env(safe-area-inset-right));
        z-index: 1200;
        height: 44px; padding: 0 18px; border-radius: 12px;
        background: rgba(140,140,140,0.85);
        color: #fff;
        border: var(--fab-border);
        box-shadow: var(--fab-shadow);
        display: flex; align-items: center; justify-content: center;
        cursor: pointer;
        font-family: var(--display); font-size: 0.75rem; font-weight: 700;
        letter-spacing: 0.12em; text-transform: uppercase;
        -webkit-tap-highlight-color: transparent;
        touch-action: manipulation;
        transition: background .15s ease, color .15s ease, border-color .15s ease, opacity .15s ease;
      }
      .m-near-btn.state-placement {
        background: transparent;
        color: var(--accent-text);
        border: 2px solid var(--yellow);
      }
      .m-near-btn.state-active {
        background: var(--yellow);
        color: #111;
      }
      .m-near-btn:disabled { opacity: 0.4; cursor: not-allowed; }

      /* Left-handed button alignment — mirrors map overlay anchors and
         reverses the board section header so map/gear sit on the left. */
      body.align-left .m-chip       { left: auto; right: calc(12px + env(safe-area-inset-right)); }
      body.align-left .m-search-btn { right: auto; left: calc(12px + env(safe-area-inset-left)); }
      body.align-left .m-alerts-btn { left: auto; right: calc(12px + env(safe-area-inset-right)); }
      /* Route-filter drawer mirrors to the left edge with the buttons.
         --drawer-dir flips the collapsed slide-out direction (see
         #sidebar.collapsed) without a specificity battle. */
      body.align-left { --drawer-dir: -1; }
      body.align-left #sidebar { right: auto; left: 0; border-left: none; border-right: 1px solid var(--fab-nav-border); border-radius: 0 0 16px 0; }
      body.align-left #sidebar .sidebar-header { padding-right: 14px; padding-left: 50px; }
      body.align-left .m-sidebar-close { right: auto; left: 14px; }
      body.align-left .m-zoom-stack { right: auto; left: calc(10px + env(safe-area-inset-left)); }
      body.align-left .m-fab        { right: auto; left: calc(16px + env(safe-area-inset-left)); }
      body.align-left .m-near-btn   { right: auto; left: calc(16px + 62px + 12px + env(safe-area-inset-left)); }
      body.align-left .board-section-hdr { flex-direction: row-reverse; }

      /* ── Sidebar reskin: slide-in glass panel ──────────────── */
      #view-map .main { display: block; position: relative; }
      #map { position: absolute; inset: 0; width: 100%; height: 100%; }
      #sidebar {
        position: fixed;
        top: 0; right: 0;
        width: min(86vw, 320px);
        height: 100dvh;
        padding-top: calc(env(safe-area-inset-top));
        padding-bottom: calc(env(safe-area-inset-bottom));
        background: var(--fab-nav-bg);
        -webkit-backdrop-filter: blur(20px);
        backdrop-filter: blur(20px);
        border-left: 1px solid var(--fab-nav-border);
        border-top: 1px solid var(--fab-nav-border);
        border-radius: 0 0 0 16px;
        transition: transform 0.22s ease;
        transform: translateX(0);
        z-index: 1300;
        flex-shrink: 0;
      }
      #sidebar.collapsed { width: min(86vw, 320px); transform: translateX(calc(100% * var(--drawer-dir, 1))); }
      #sidebar .sidebar-toggle { display: none; }
      #sidebar .sidebar-inner { opacity: 1 !important; pointer-events: auto !important; }
      #sidebar .sidebar-header { position: relative; padding: 14px 14px 10px; padding-right: 50px; border-bottom: none; }
      #sidebar .sidebar-title { font-size: 0.625rem; letter-spacing: 0.18em; color: var(--sidebar-title); margin-bottom: 10px; }
      #sidebar .search-wrap { background: var(--map-btn-bg); border: 1px solid var(--map-btn-border); border-radius: 10px; padding: 0; }
      #sidebar #route-search { background: transparent; border: none; padding: 7px 28px 7px 10px; font-size: 0.8125rem; color: var(--chip-text); }
      #sidebar #route-search:focus { border: none; }
      #sidebar #route-search::placeholder { color: var(--chip-sub); }
      #sidebar .filter-tabs { padding: 0 14px; border-bottom: 1px solid var(--card-border); }
      #sidebar .filter-tab { font-size: 0.6875rem; padding: 8px 2px; font-weight: 700; letter-spacing: 0.05em; color: var(--chip-sub); }
      #sidebar .filter-tab.active { color: var(--accent-text); border-bottom-color: var(--yellow); }
      #sidebar .sidebar-actions { border-bottom: 1px solid var(--card-border); padding: 8px 14px; }
      #sidebar .sidebar-actions .action-btn { border-color: var(--map-btn-border); border-radius: 8px; padding: 6px; color: var(--chip-text); }
      #sidebar #route-list { padding: 6px 0 20px; }
      #sidebar .route-name, #sidebar .county-name { color: var(--chip-text); }
      #sidebar .route-long, #sidebar .route-count, #sidebar .county-meta, #sidebar .county-arrow { color: var(--chip-sub); }
      #sidebar .county-header { background: var(--fab-nav-bg); border-bottom: 1px solid var(--card-border); }
      .m-sidebar-close {
        position: absolute; top: 14px; right: 14px;
        width: 30px; height: 30px; border-radius: 8px;
        background: var(--map-btn-bg);
        border: 1px solid var(--map-btn-border);
        color: var(--chip-text);
        display: flex; align-items: center; justify-content: center;
        cursor: pointer; padding: 0;
      }
      .m-sidebar-close .ico { width: 12px; height: 12px; }

      /* ── Inline phone header for board / settings ──────────── */
      .phone-page-hdr {
        display: flex; align-items: center; gap: 10px;
        padding: 10px 14px;
        padding-top: calc(10px + env(safe-area-inset-top));
        flex-shrink: 0;
      }
      .phone-page-hdr-text { flex: 1; min-width: 0; }
      .phone-page-hdr-title {
        font-family: var(--display);
        font-size: 0.6875rem; font-weight: 700;
        letter-spacing: 0.18em; color: var(--accent-text);
      }
      .phone-page-hdr-sub {
        font-family: var(--mono);
        font-size: 0.625rem; color: var(--chip-sub);
        letter-spacing: 0.12em; margin-top: 1px;
      }
      .phone-page-hdr .m-chip-body { background: var(--map-btn-bg); border-color: var(--map-btn-border); }

      /* ── Display board reskin ──────────────────────────────── */
      .board-wrap { padding: 4px 0 calc(110px + env(safe-area-inset-bottom)); }
      .board-section {
        background: var(--card-bg);
        border: 1px solid var(--card-border);
        border-radius: 16px;
        margin: 0 14px 12px;
        padding: 0;
        overflow: hidden;
      }
      .board-section-hdr {
        padding: 9px 12px;
        border-bottom: 1px solid var(--card-border);
        background: var(--card-header-bg);
        gap: 8px;
      }
      .board-section-label { font-size: 0.625rem; letter-spacing: 0.05em; color: var(--chip-text); flex: 1; text-transform: none; }
      .board-section-sep { display: none; }
      /* Single line + marquee rather than wrapping: wrapping made the header
         grow unpredictably at large font scales, and the name is what the
         user needs to read in full. */
      .board-section-name { display: block; font-family: var(--display); font-size: 0.8125rem; font-weight: 800; color: var(--chip-text); letter-spacing: 0.02em; text-transform: uppercase; white-space: nowrap; overflow: hidden; }
      .board-section-walk { display: block; font-size: 0.625rem; color: var(--chip-sub); margin-top: 2px; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; }
      .board-map-btn {
        width: 32px; height: 32px;
        border-radius: 8px;
        background: var(--map-btn-bg);
        border: 1px solid var(--map-btn-border);
        color: var(--map-btn-color);
        font-size: 0.875rem;
      }
      .board-map-btn .ico { width: 14px; height: 14px; }
      /* Inactive timetable button reads as a subtle outline — tint its
         hardcoded charcoal border/text off the theme like its siblings. */
      .popup-tt-btn { border-color: var(--border); color: var(--muted); }
      .board-gear-btn {
        width: 32px; height: 32px;
        border-radius: 8px;
        background: var(--gear-bg);
        border: 1px solid var(--gear-border);
        color: var(--gear-color);
        display: flex; align-items: center; justify-content: center;
        cursor: pointer; flex-shrink: 0; padding: 0;
        transition: background .15s;
      }
      .board-gear-btn .ico { width: 14px; height: 14px; }
      .board-row {
        padding: 10px 14px;
        border-bottom: 1px solid var(--card-border);
        gap: 12px;
      }
      .board-row:last-child { border-bottom: none; }
      .board-row.urgent { background: var(--urgent-row-bg); }
      .board-badge {
        font-family: var(--display);
        font-size: 0.875rem; font-weight: 900;
        min-width: 36px; max-width: 56px; height: 36px;
        border-radius: 8px;
        display: flex; align-items: center; justify-content: center;
        padding: 0 8px;
        background: var(--badge-bg, rgba(255,255,255,0.06));
        color: var(--badge-color, currentColor) !important;
        flex-shrink: 0;
      }
      .board-badge.board-badge-icon { background: transparent; padding: 0; }
      .board-badge.board-badge-icon img { height: 26px; }
      .board-dest { font-family: var(--mono); font-size: 0.8125rem; font-weight: 700; color: var(--chip-text); letter-spacing: 0.02em; }
      .board-quiet-text { font-family: var(--mono); font-size: 0.8125rem; font-weight: 700; color: var(--chip-sub); letter-spacing: 0.02em; }
      .board-time {
        display: flex; flex-direction: column; align-items: flex-end;
        line-height: 1; min-width: 48px; padding-left: 0;
        font-family: var(--display);
      }
      .board-time-num { font-size: 1.375rem; font-weight: 900; color: var(--chip-text); letter-spacing: -0.02em; }
      .board-time-unit { font-size: 0.5625rem; font-weight: 700; color: var(--chip-sub); margin-top: 3px; letter-spacing: 0.08em; }
      .board-time.urgent .board-time-num,
      .board-time.board-now .board-time-num { font-size: 0.75rem; color: #ff5533; letter-spacing: 0.04em; font-family: var(--mono); }
      .board-time.urgent .board-time-unit,
      .board-time.board-now .board-time-unit { display: none; }

      /* Board settings overlay → top-anchored centered glass card so the
         on-screen keyboard doesn't squeeze the route list. Same visual
         language as the map sidebar. */
      .board-settings-overlay {
        z-index: 1400;
        position: fixed; inset: 0;
        align-items: center;
        justify-content: flex-start;
        padding: calc(56px + env(safe-area-inset-top)) 12px calc(12px + env(safe-area-inset-bottom));
      }
      .board-settings-panel {
        background: var(--fab-nav-bg);
        -webkit-backdrop-filter: blur(20px);
        backdrop-filter: blur(20px);
        border: 1px solid var(--fab-nav-border);
        border-top: 1px solid var(--fab-nav-border);
        border-radius: 16px;
        width: 100%;
        max-width: 380px;
        max-height: 100%;
      }
      .board-settings-hdr { padding: 12px 14px 4px; border-bottom: none; }
      .board-settings-hdr-title { font-size: 0.625rem; letter-spacing: 0.18em; color: var(--sidebar-title); }
      .board-settings-close {
        background: var(--map-btn-bg);
        border: 1px solid var(--map-btn-border);
        color: var(--chip-text);
        border-radius: 8px; width: 30px; height: 30px;
      }
      .board-settings-overlay .filter-tabs { padding: 0 14px; border-bottom: 1px solid var(--card-border); }
      .board-settings-overlay .filter-tab { font-size: 0.6875rem; padding: 8px 2px; font-weight: 700; letter-spacing: 0.05em; color: var(--chip-sub); }
      .board-settings-overlay .filter-tab.active { color: var(--accent-text); border-bottom-color: var(--yellow); }
      .board-settings-search-wrap { padding: 10px 14px; border-bottom: none; }
      #board-search {
        background: var(--map-btn-bg);
        border: 1px solid var(--map-btn-border);
        border-radius: 10px;
        padding: 7px 10px;
        color: var(--chip-text);
        font-size: 0.8125rem;
      }
      #board-search:focus { border-color: var(--yellow); }
      #board-search::placeholder { color: var(--chip-sub); }
      .board-settings-list { padding: 2px 0 10px; }
      .board-settings-item { padding: 9px 14px; }
      .board-settings-item:hover { background: var(--card-header-bg); }
      .board-settings-name { color: var(--chip-text); }
      .board-settings-long { color: var(--chip-sub); }
      .board-settings-dot { border-color: var(--chip-sub); }
      .nearby-modal-overlay { z-index: 1500; }

      /* Settings view spacing — surfaces/colours now come from the base
         rules, which read the same tokens directly. */
      #view-settings .settings-scroll { padding-bottom: calc(110px + env(safe-area-inset-bottom)); }
      .board-row:hover { background: var(--card-header-bg); }
    }

    /* ── Profile bar (display board) ───────────────────────────── */
    .profile-bar {
      display: flex; align-items: center; gap: 8px;
      padding: 10px 12px; margin: 8px 14px 10px;
      background: var(--card-bg, var(--panel));
      border: 1px solid var(--card-border, var(--border));
      border-radius: 14px;
      flex-shrink: 0;
    }
    .profile-bar-name {
      flex: 1; min-width: 0;
      font-family: var(--display); font-size: 0.875rem; font-weight: 700;
      color: var(--chip-text, var(--text));
      letter-spacing: 0.02em;
      background: none; border: none; text-align: left; cursor: pointer;
      padding: 6px 4px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    }
    .profile-bar-gear {
      width: 36px; height: 36px; flex-shrink: 0; padding: 0;
      border-radius: 10px;
      background: var(--gear-bg, rgba(255,208,0,0.1));
      border: 1px solid var(--gear-border, rgba(255,208,0,0.35));
      color: var(--gear-color, #FFD000);
      display: flex; align-items: center; justify-content: center;
      cursor: pointer; transition: background .15s;
    }
    .profile-bar-gear .ico { width: 14px; height: 14px; }
    body.align-left .profile-bar { flex-direction: row-reverse; }
    body.align-left .profile-bar-name { text-align: right; }

    /* ── Profile dropdown overlay ──────────────────────────────── */
    .profile-dropdown-overlay {
      display: none; position: fixed; inset: 0; background: rgba(0,0,0,0.5);
      z-index: 1450; justify-content: center; align-items: flex-start;
      padding: 80px 14px 20px;
    }
    .profile-dropdown-overlay.open { display: flex; }
    .profile-dropdown {
      width: 100%; max-width: 380px;
      background: var(--panel); border: 1px solid var(--border);
      border-radius: 14px; overflow: hidden;
      max-height: 70vh; display: flex; flex-direction: column;
    }
    .profile-dropdown-list { overflow-y: auto; flex: 1; }
    .profile-dropdown-row {
      display: flex; align-items: center; gap: 8px;
      padding: 12px 14px; cursor: pointer;
      border-bottom: 1px solid var(--border);
      transition: background .1s;
    }
    .profile-dropdown-row:hover { background: rgba(255,255,255,0.04); }
    .profile-dropdown-row.active { background: rgba(255,208,0,0.08); }
    .profile-dropdown-name {
      flex: 1; min-width: 0;
      font-family: var(--display); font-size: 0.8125rem; font-weight: 700;
      color: var(--text); letter-spacing: 0.02em;
      overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    }
    .profile-dropdown-gear {
      width: 30px; height: 30px; flex-shrink: 0; padding: 0;
      border-radius: 8px;
      background: var(--gear-bg, rgba(255,208,0,0.1));
      border: 1px solid var(--gear-border, rgba(255,208,0,0.35));
      color: var(--gear-color, #FFD000);
      display: flex; align-items: center; justify-content: center;
      cursor: pointer;
    }
    .profile-dropdown-gear .ico { width: 12px; height: 12px; }
    .profile-dropdown-create {
      padding: 12px 14px; cursor: pointer;
      font-family: var(--display); font-size: 0.75rem; font-weight: 700;
      color: var(--accent-text); letter-spacing: 0.05em;
      text-align: center; background: rgba(255,208,0,0.06);
      border: none; width: 100%;
    }
    .profile-dropdown-create:hover { background: rgba(255,208,0,0.12); }

    /* ── Profile settings modal ────────────────────────────────── */
    .profile-modal-overlay {
      display: none; position: fixed; inset: 0; background: rgba(0,0,0,0.65);
      z-index: 1500; justify-content: center; align-items: center; padding: 20px;
    }
    .profile-modal-overlay.open { display: flex; }
    .profile-modal {
      background: var(--panel); border: 1px solid var(--border);
      width: 100%; max-width: 420px; max-height: 90vh;
      display: flex; flex-direction: column; overflow: hidden;
      border-radius: 12px;
    }
    .profile-modal-hdr {
      display: flex; align-items: center; padding: 12px 14px;
      border-bottom: 2px solid var(--yellow); flex-shrink: 0;
      position: relative; z-index: 2;
      box-shadow: 0 5px 12px -5px rgba(0,0,0,0.35);
    }
    .profile-modal-title {
      font-family: var(--display); font-size: 0.75rem; font-weight: 700;
      text-transform: uppercase; letter-spacing: 0.1em;
      color: var(--text); flex: 1;
    }
    .profile-modal-close {
      background: none; border: 1px solid var(--border); color: var(--muted);
      width: 28px; height: 28px; cursor: pointer;
      display: flex; align-items: center; justify-content: center;
    }
    .profile-modal-close:hover { border-color: var(--yellow); color: var(--accent-text); }
    .profile-modal-body { padding: 14px; overflow-y: auto; flex: 1; display: flex; flex-direction: column; gap: 14px; }
    .profile-section { display: flex; flex-direction: column; gap: 6px; }
    .profile-section-label {
      font-family: var(--display); font-size: 0.625rem; font-weight: 700;
      text-transform: uppercase; letter-spacing: 0.1em; color: var(--muted);
    }
    .profile-input {
      width: 100%;
      background: var(--map-btn-bg, #1e1e1e);
      border: 1px solid var(--map-btn-border, var(--border));
      color: var(--chip-text, var(--text));
      font-family: var(--mono); font-size: 0.8125rem;
      padding: 8px 10px; outline: none; border-radius: 6px;
      box-sizing: border-box;
    }
    .profile-input:focus { border-color: var(--yellow); }
    .profile-loc-row { display: flex; gap: 6px; }
    .profile-loc-btn {
      flex: 1; padding: 8px 10px; cursor: pointer;
      background: transparent; border: 1px solid var(--border);
      color: var(--muted); border-radius: 6px;
      font-family: var(--display); font-size: 0.6875rem; font-weight: 700;
      text-transform: uppercase; letter-spacing: 0.05em;
      transition: all .12s;
    }
    .profile-loc-btn.active {
      background: var(--yellow); color: #111; border-color: var(--yellow);
    }
    .profile-geocode-results {
      max-height: 160px; overflow-y: auto;
      border: 1px solid var(--map-btn-border, var(--border));
      border-radius: 6px;
      background: var(--map-btn-bg, #161616);
      margin-top: 4px;
    }
    .profile-geocode-results:empty { display: none; }
    .profile-geocode-row {
      padding: 8px 10px; cursor: pointer;
      font-size: 0.75rem; color: var(--chip-text, var(--text));
      border-bottom: 1px solid var(--map-btn-border, var(--border));
      font-family: var(--mono);
    }
    .profile-geocode-row:last-child { border-bottom: none; }
    .profile-geocode-row:hover { background: rgba(255,208,0,0.08); }
    .profile-loc-resolved {
      font-size: 0.6875rem; color: var(--muted); font-family: var(--mono);
      padding: 6px 0 0; word-break: break-word;
    }
    .profile-loc-current-btn {
      width: 100%; margin-top: 6px;
      padding: 8px 10px; cursor: pointer;
      background: transparent;
      border: 1px solid var(--map-btn-border, var(--border));
      color: var(--chip-text, var(--text));
      border-radius: 6px;
      font-family: var(--display); font-size: 0.6875rem; font-weight: 700;
      text-transform: uppercase; letter-spacing: 0.05em;
      transition: all .12s;
    }
    .profile-loc-current-btn:hover { border-color: var(--yellow); color: var(--accent-text); }
    .profile-loc-current-btn:disabled { opacity: 0.5; cursor: not-allowed; }
    .profile-routes-info {
      display: flex; align-items: center; gap: 10px;
      padding: 10px 12px; cursor: pointer;
      background: var(--map-btn-bg, #1e1e1e);
      border: 1px solid var(--map-btn-border, var(--border));
      border-radius: 6px;
    }
    .profile-routes-info:hover { border-color: var(--yellow); }
    .profile-routes-count {
      flex: 1; font-family: var(--mono); font-size: 0.75rem;
      color: var(--chip-text, var(--text));
    }
    .profile-routes-arrow { color: var(--muted); font-size: 1rem; }
    .profile-auto-row {
      display: flex; align-items: center; gap: 10px;
      padding: 10px 12px;
      background: var(--map-btn-bg, #161616);
      border: 1px solid var(--map-btn-border, var(--border));
      border-radius: 6px;
    }
    .profile-auto-row.disabled { opacity: 0.65; }
    .profile-auto-label { flex: 1; font-family: var(--display); font-size: 0.75rem; font-weight: 700; color: var(--chip-text, var(--text)); }
    .profile-auto-row.disabled .profile-auto-label { color: var(--muted); }
    .profile-auto-pill {
      font-size: 0.5625rem; padding: 3px 7px; border-radius: 4px;
      background: rgba(255,140,0,0.15); color: #ff9933;
      font-family: var(--display); font-weight: 700;
      text-transform: uppercase; letter-spacing: 0.06em;
    }
    /* iOS-style sliding toggle */
    .profile-auto-toggle {
      width: 44px; height: 24px; flex-shrink: 0; padding: 2px;
      background: var(--map-btn-bg, #2a2a2a); border: 1px solid var(--map-btn-border, var(--border));
      border-radius: 999px; cursor: pointer;
      display: flex; align-items: center;
      transition: background .18s, border-color .18s;
    }
    .profile-auto-toggle.on { background: var(--nav-active-bg, var(--yellow)); border-color: var(--nav-active-bg, var(--yellow)); }
    .profile-auto-toggle-knob {
      width: 18px; height: 18px; border-radius: 50%;
      background: var(--map-btn-color, #f0f0f0); transition: transform .18s;
      box-shadow: 0 1px 3px rgba(0,0,0,0.3);
    }
    .profile-auto-toggle.on .profile-auto-toggle-knob { transform: translateX(20px); background: var(--nav-active-color, #111); }
    /* Radius controls + map */
    .profile-auto-controls {
      display: flex; flex-direction: column; gap: 8px;
      margin-top: 8px;
    }
    .profile-radius-row {
      display: flex; align-items: center; gap: 10px;
      padding: 8px 12px;
      background: var(--map-btn-bg, #161616);
      border: 1px solid var(--map-btn-border, var(--border));
      border-radius: 6px;
    }
    .profile-radius-slider {
      flex: 1; height: 4px; appearance: none; -webkit-appearance: none;
      background: #2a2a2a; border-radius: 2px; outline: none; cursor: pointer;
    }
    .profile-radius-slider::-webkit-slider-thumb {
      -webkit-appearance: none; appearance: none;
      width: 16px; height: 16px; border-radius: 50%;
      background: var(--yellow); cursor: pointer; border: none;
    }
    .profile-radius-slider::-moz-range-thumb {
      width: 16px; height: 16px; border-radius: 50%;
      background: var(--yellow); cursor: pointer; border: none;
    }
    .profile-radius-value {
      font-family: var(--mono); font-size: 0.75rem; font-weight: 700;
      color: var(--chip-text, var(--text)); min-width: 56px; text-align: right;
    }
    #profile-geo-map {
      width: 100%; height: 180px;
      border: 1px solid var(--border); border-radius: 6px;
    }
    .profile-modal-footer {
      display: flex; gap: 8px; padding: 12px 14px;
      border-top: 1px solid var(--border); flex-shrink: 0;
    }
    .profile-btn {
      padding: 9px 14px; cursor: pointer; border-radius: 6px;
      font-family: var(--display); font-size: 0.6875rem; font-weight: 700;
      text-transform: uppercase; letter-spacing: 0.06em;
      border: 1px solid var(--border);
    }
    .profile-btn-delete {
      background: transparent; color: #ff5533; border-color: #ff5533;
      margin-right: auto;
    }
    .profile-btn-delete:hover { background: rgba(255,85,51,0.1); }
    .profile-btn-cancel { background: transparent; color: var(--muted); }
    .profile-btn-cancel:hover { border-color: var(--yellow); color: var(--accent-text); }
    .profile-btn-save { background: var(--yellow); color: #111; border-color: var(--yellow); }
    .profile-btn-save:hover { opacity: 0.85; }

    /* ── Profile switch toast ──────────────────────────────────── */
    .profile-toast {
      position: fixed; top: 0; left: 50%; transform: translateX(-50%) translateY(-100%);
      margin-top: calc(12px + env(safe-area-inset-top));
      background: rgba(20,24,30,0.92);
      color: #fff; font-family: var(--display); font-size: 0.75rem; font-weight: 700;
      letter-spacing: 0.05em;
      padding: 10px 18px; border-radius: 10px;
      border: 1px solid rgba(255,255,255,0.12);
      z-index: 2000; cursor: pointer; opacity: 0;
      transition: transform 0.25s ease, opacity 0.25s ease;
      backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
      pointer-events: none;
      box-shadow: 0 6px 20px rgba(0,0,0,0.4);
    }
    .profile-toast.show {
      transform: translateX(-50%) translateY(0);
      opacity: 1; pointer-events: auto;
    }

    /* ── Text-size accessibility overrides (largest & huge ONLY) ──
       html[data-text-size] is set by applyFontScale(). These rules must
       never affect normal/large/larger; smaller steps are already fine. */

    /* 1. Settings row icon badges — the badge is a fixed px box, so it grows
       modestly with the scale (like the floating map buttons below) instead
       of tracking the text. Both the glyph variants ("Aa", ↔, emoji) and the
       SVG variants are bumped together so the badges stay uniform. */
    :is(html[data-text-size="largest"]) .settings-row-icon {
      width: 36px; height: 36px; font-size: 18px;
    }
    :is(html[data-text-size="largest"]) .settings-row-icon .ico { width: 18px; height: 18px; }
    :is(html[data-text-size="huge"]) .settings-row-icon {
      width: 38px; height: 38px; font-size: 19px;
    }
    :is(html[data-text-size="huge"]) .settings-row-icon .ico { width: 19px; height: 19px; }
    /* The 5-step text-size control is the widest thing in Settings; at the
       two biggest scales its own "A" glyphs are large enough that the track
       needs tighter chips to stay on one line beside its label. */
    :is(html[data-text-size="largest"], html[data-text-size="huge"]) .fs-toggle-row .fs-btn {
      padding: 6px 4px; min-width: 22px;
    }
    :is(html[data-text-size="largest"], html[data-text-size="huge"]) .fs-toggle-row { gap: 1px; }

    /* 2. Filter tabs — sidebar container (86vw / 320px cap) is narrower
       than the board-settings panel (380px), so the same 4 tabs wrap
       there but not here. Keep on one line at these scales, drop the
       decorative SVG icons, and tighten spacing. */
    :is(html[data-text-size="largest"], html[data-text-size="huge"]) .filter-tab {
      white-space: nowrap;
      letter-spacing: 0.02em;
      padding-left: 0; padding-right: 0;
    }
    :is(html[data-text-size="largest"], html[data-text-size="huge"]) .filter-tab > svg.ico {
      display: none;
    }

    /* 3. Map header — cap the "AC" brand mark so the visible-count/timer
       chip has room before the fixed-size search button, and tighten the
       chip's own padding. */
    :is(html[data-text-size="largest"], html[data-text-size="huge"]) .bus-badge {
      font-size: 18px;
    }
    :is(html[data-text-size="largest"], html[data-text-size="huge"]) .m-chip-body {
      padding: 5px 7px; gap: 4px; letter-spacing: 0.02em;
    }
    /* Drop the "visible" word + separator on the map chip — the count
       and live-updated time still convey the meaning, and this reclaims
       the width the fixed-size search button needs. */
    :is(html[data-text-size="largest"], html[data-text-size="huge"]) .m-chip .m-chip-label,
    :is(html[data-text-size="largest"], html[data-text-size="huge"]) .m-chip .m-chip-sep {
      display: none;
    }

    /* 4. Announcements modal — near-fullscreen so bigger text has room
       to wrap into fewer, more scannable lines. */
    :is(html[data-text-size="largest"], html[data-text-size="huge"]) #alerts-modal-overlay {
      padding: 8px;
    }
    :is(html[data-text-size="largest"], html[data-text-size="huge"]) #alerts-modal-overlay .nearby-modal {
      max-width: none; width: 100%; height: 100%; max-height: 100%;
    }
    :is(html[data-text-size="largest"], html[data-text-size="huge"]) #alerts-modal-body {
      max-height: none !important; flex: 1;
    }

    /* 5. Vehicle markers — widen so scaled-up destination text isn't
       over-truncated. iconAnchor in app.js shifts to match so markers
       don't drift off their map position. */
    :is(html[data-text-size="largest"], html[data-text-size="huge"]) .bus-marker {
      max-width: 92px;
    }
    :is(html[data-text-size="largest"], html[data-text-size="huge"]) .bus-dest {
      max-width: 88px;
    }

    /* Floating map buttons — grow modestly with the accessibility scale so
       they aren't dwarfed by the surrounding UI, but stay clearly smaller
       than the FAB. Only bumped at the two largest steps (the smaller
       steps keep the 42px default). */
    :is(html[data-text-size="largest"]) :is(.m-search-btn, .m-alerts-btn) {
      width: 48px; height: 48px; border-radius: 24px;
    }
    :is(html[data-text-size="largest"]) :is(.m-search-btn, .m-alerts-btn) .ico {
      width: 20px; height: 20px;
    }
    :is(html[data-text-size="huge"]) :is(.m-search-btn, .m-alerts-btn) {
      width: 54px; height: 54px; border-radius: 27px;
    }
    :is(html[data-text-size="huge"]) :is(.m-search-btn, .m-alerts-btn) .ico {
      width: 22px; height: 22px;
    }
    /* Alerts button sits under the top-left AC chip; nudge it down at
       larger button sizes so it doesn't clip into the chip. */
    :is(html[data-text-size="largest"]) .m-alerts-btn {
      top: calc(58px + env(safe-area-inset-top));
    }
    :is(html[data-text-size="huge"]) .m-alerts-btn {
      top: calc(64px + env(safe-area-inset-top));
    }

    /* County-header route counts get jumbled at extreme scales — drop the
       " on" word and squeeze the "N · M" separator so "6 · 200 routes"
       reads on one line inside the drawer's narrow container. */
    :is(html[data-text-size="largest"], html[data-text-size="huge"]) .cm-on {
      display: none;
    }
    :is(html[data-text-size="largest"], html[data-text-size="huge"]) .cm-sep {
      padding: 0;
      letter-spacing: 0;
    }
    /* Regardless of text size, the default " · " has quite loose spacing
       relative to the numbers — this trims it visibly without touching
       the surrounding words. */
    .cm-sep { letter-spacing: -0.02em; }

    /* 6. Tighten letter-spacing on short uppercase/display labels.
       Base values in style.css run 0.05em–0.18em; 0.02em is the tightest
       any element uses today, so this only tightens crowded text, never
       loosens it. Paragraph text has no letter-spacing so is unaffected. */
    :is(html[data-text-size="largest"], html[data-text-size="huge"]) :is(
      .stat-label, .filter-tab, .action-btn, .bus-arrow, .bus-label,
      .popup-provider-mark, .popup-row, .popup-tt-btn, .stop-route-tag,
      .alert-new, .alert-card-title, .alert-card-meta,
      .alerts-count, footer, .settings-heading, .settings-row-label,
      .sidebar-title, .county-name, .county-arrow, .county-meta,
      .nav-btn span, .board-title, .board-section-label, .board-section-name,
      .board-section-walk, .board-badge, .board-time-num, .board-time-unit,
      .board-dest, .m-fab-item-label, .m-near-btn, .nearby-modal-title,
      .nearby-toggle-btn, .nearby-unit-label, .phone-page-hdr-title,
      .phone-page-hdr-sub, .theme-row-name, .profile-bar-name,
      .profile-section-label, .profile-loc-btn, .profile-loc-current-btn,
      .bug-label, .bug-option,
      .profile-auto-label, .profile-auto-pill, .profile-dropdown-name,
      .profile-dropdown-create, .profile-modal-title, .profile-btn,
      .profile-toast
    ) { letter-spacing: 0.02em; }

    /* Marquee for text that would otherwise be cut off — board destinations,
       board stop names, the timetable modal's stop name. Kicks in only where
       the text actually overflows (initMarquee adds .marquee and sets
       --marquee-shift on the container). Cycle: 4s show truncated → 6s slow
       scroll → 2s pause at the end → instant snap back. --marquee-shift is
       negative: how far the inner span is pulled left.
       The container itself needs white-space:nowrap + overflow:hidden. */
    .marquee-inner {
      display: inline-block;
      white-space: nowrap;
      will-change: transform;
    }
    /* Right-edge fade as a transparency mask on the text container, so the
       fade always resolves to whatever background it's painted on (card,
       urgent-tinted card, modal header) with no colour matching. */
    .marquee {
      position: relative;
      -webkit-mask-image: linear-gradient(to right, #000 0, #000 calc(100% - 18px), transparent 100%);
              mask-image: linear-gradient(to right, #000 0, #000 calc(100% - 18px), transparent 100%);
    }
    .marquee .marquee-inner {
      animation: marquee-scroll 12s infinite;
    }
    @keyframes marquee-scroll {
      0%,    33%   { transform: translateX(0); }
      83%,   99.5% { transform: translateX(var(--marquee-shift, 0)); }
      100%         { transform: translateX(0); }
    }
    @media (prefers-reduced-motion: reduce) {
      .marquee .marquee-inner { animation: none; }
    }

    /* ── ONBOARDING TOUR (tour.js) ─────────────────────────────────
       Spotlight walkthrough: four dim shades around a hole, a ring
       outlining the target, and a floating explainer card. Sits above
       every app surface (modals top out at 1500, toast at 2000 is
       fine to share the stage with). All colours come from the theme
       vars so the tour follows whatever theme is active. */
    #tour-root { display: none; position: fixed; inset: 0; z-index: 1600; pointer-events: none; --tour-dim: rgba(0,0,0,0.6); }
    #tour-root.tour-suspended > * { display: none !important; }
    /* The dim is a single element with an enormous ring-shadow, so the hole
       is a true cutout. Four abutting semi-transparent panels used to do this
       and left a hairline seam along their shared edges wherever the device
       pixel ratio was fractional. The panels remain, fully transparent, only
       to catch taps outside the hole. */
    .tour-mask {
      position: fixed; pointer-events: none;
      border-radius: 14px;
      box-shadow: 0 0 0 9999px var(--tour-dim);
      transition: left .22s ease, top .22s ease, width .22s ease, height .22s ease;
    }
    .tour-shade {
      position: fixed; background: transparent; pointer-events: auto;
    }
    .tour-blocker { position: fixed; pointer-events: auto; }
    /* Hands-on steps where the thing to touch sits outside the ring (search
       results, a stop popup's Timetable button, the route list): the dim
       stays as a highlight but must not eat the taps the step asks for. */
    #tour-root.tour-passthrough { --tour-dim: rgba(0,0,0,0.45); }
    #tour-root.tour-passthrough .tour-shade { pointer-events: none; }
    /* Compact: after the user has done the step's action, the card drops to
       the result line plus the buttons so the map behind it is visible. */
    #tour-root.tour-compact .tour-shade { pointer-events: none; }
    #tour-root.tour-compact .tour-step-count,
    #tour-root.tour-compact .tour-title,
    #tour-root.tour-compact .tour-text { display: none; }
    #tour-root.tour-compact .tour-hint { margin-top: 0; }
    #tour-root.tour-compact .tour-btns { margin-top: 10px; }
    .tour-ring {
      position: fixed; pointer-events: none;
      border: 2px solid var(--yellow); border-radius: 14px;
      box-shadow: 0 0 0 4px rgba(255,208,0,0.22);
      transition: left .22s ease, top .22s ease, width .22s ease, height .22s ease;
    }
    .tour-card {
      position: fixed; pointer-events: auto;
      background: var(--panel);
      border: 1px solid var(--card-border, var(--border));
      border-radius: 16px;
      box-shadow: 0 18px 48px rgba(0,0,0,0.5);
      width: min(330px, calc(100vw - 24px));
      padding: 14px 16px;
      font-family: var(--mono);
      transition: left .22s ease, top .22s ease;
    }
    .tour-arrow {
      position: fixed; pointer-events: none;
      width: 14px; height: 14px;
      background: var(--panel);
      border-left: 1px solid var(--card-border, var(--border));
      border-top: 1px solid var(--card-border, var(--border));
      transform: rotate(45deg);
      transition: left .22s ease, top .22s ease;
    }
    .tour-arrow.down { transform: rotate(225deg); }
    .tour-step-count {
      font-size: 0.5625rem; letter-spacing: 0.12em; text-transform: uppercase;
      color: var(--muted); margin-bottom: 6px;
    }
    .tour-title {
      font-family: var(--display); font-size: 1rem; font-weight: 800;
      color: var(--text); margin-bottom: 6px;
    }
    .tour-text { font-size: 0.75rem; line-height: 1.55; color: var(--text); }
    /* **bold** in step copy. Inherits its colour rather than taking the accent,
       so it stays legible on all eight themes and doesn't get confused with the
       yellow "try it" hint line. For a keyword highlight instead, this is the
       one place to change. */
    .tour-text strong, .tour-hint strong, .tour-title strong { font-weight: 700; }
    .tour-hint { font-size: 0.6875rem; margin-top: 8px; color: var(--accent-text, var(--yellow)); min-height: 0; }
    .tour-hint:empty { display: none; }
    .tour-hint.done { color: #43b97f; }
    .tour-btns { display: flex; align-items: center; gap: 8px; margin-top: 12px; }
    .tour-btn {
      font-family: var(--mono); cursor: pointer;
      border-radius: 9px; padding: 8px 13px;
      font-size: 0.6875rem; text-transform: uppercase; letter-spacing: 0.06em;
      border: 1px solid var(--border); background: transparent; color: var(--muted);
    }
    .tour-btn-exit { border-color: transparent; padding-left: 4px; margin-right: auto; }
    .tour-btn-next { background: var(--yellow); border-color: var(--yellow); color: #000; font-weight: 700; }
    .tour-btn-next.pulse { animation: tour-pulse 1.1s ease infinite; }
    @keyframes tour-pulse {
      0%, 100% { box-shadow: 0 0 0 0 rgba(255,208,0,0.55); }
      50%      { box-shadow: 0 0 0 8px rgba(255,208,0,0); }
    }
    @media (prefers-reduced-motion: reduce) {
      .tour-mask, .tour-ring, .tour-card, .tour-arrow { transition: none; }
      .tour-btn-next.pulse { animation: none; }
    }
    /* Welcome + accessibility modals (injected by tour.js, share the
       .nearby-modal chrome). */
    .tour-modal-text { font-family: var(--mono); font-size: 0.75rem; line-height: 1.6; color: var(--text); }
    .tour-modal-note { font-family: var(--mono); font-size: 0.625rem; color: var(--muted); text-align: center; }
    .tour-btn-secondary {
      background: transparent;
      border: 1px solid var(--card-border, var(--border));
      color: var(--text);
    }
    .tour-btn-skip {
      font-family: var(--mono); font-size: 0.6875rem; text-transform: uppercase;
      letter-spacing: 0.06em; background: none; border: none; cursor: pointer;
      color: var(--muted); padding: 6px; align-self: center;
    }
    /* Hidden developer reset, revealed inside the bug report form by a
       phrase only the developer would type (see tour.js). */
    .tour-reset-panel {
      display: none;
      flex-direction: column; gap: 8px;
      padding: 12px; border-radius: 12px;
      border: 1px solid #e03e3e;
      background: rgba(224,62,62,0.07);
    }
    .tour-reset-panel.open { display: flex; }
    .tour-reset-title {
      font-family: var(--display); font-size: 0.75rem; font-weight: 700;
      text-transform: uppercase; letter-spacing: 0.1em; color: #e03e3e;
    }
    .tour-reset-text { font-family: var(--mono); font-size: 0.6875rem; line-height: 1.5; color: var(--muted); }
    .tour-reset-btn { background: #e03e3e; border-color: #e03e3e; color: #fff; }
    .tour-reset-btn.is-armed { background: #b32020; border-color: #b32020; }

    .tour-a11y-label {
      font-family: var(--mono); font-size: 0.5625rem; text-transform: uppercase;
      letter-spacing: 0.1em; color: var(--muted); margin-bottom: -6px;
    }
