/* ============================================================================
   Rail Buddy — the palette, the app shell, and the map surface.

   Bootstrap 5.3 (vendored) styles the pages; this file holds what it has no
   opinion about: the railway signal palette mapped onto Bootstrap's --bs-*
   variables (so the chrome follows data-bs-theme), the one-row app shell, and
   everything drawn inside a Leaflet map — the rail, the pins, the name plates,
   the km-post ticks, the train. The map renderers read the --rb-* tokens
   through RB.readTheme(), which is how the rail follows the theme.
   ========================================================================== */

/* ---- Light palette — brushed aluminium in daylight ---------------------- */
:root,
[data-bs-theme="light"] {
    --rb-signal-amber: #e8821e;
    --rb-signal-amber-strong: #c96a10;
    --rb-signal-red: #c43d2e;
    --rb-signal-green: #2f8f4e;
    --rb-terra: var(--rb-signal-amber);
    --rb-terra-strong: var(--rb-signal-amber-strong);

    --rb-rail-dim: #b3bdc4;
    --rb-geo-bg: #c6ced3;          /* map fallback when tiles are offline */
    --rb-rail-on-map: #2a3338;     /* rail drawn over light tiles */
    --rb-panel: #eef2f4;
    --rb-field: #e2e8ec;
    --rb-card-shadow: 0 1px 0 rgba(255, 255, 255, .6) inset, 0 1px 2px rgba(20, 28, 33, .12), 0 3px 8px rgba(20, 28, 33, .10);
    --rb-metal: linear-gradient(180deg, #f3f6f8 0%, #e7edf0 48%, #dfe6ea 100%);

    --bs-body-bg: #dde3e7;
    --bs-body-color: #232a2e;
    --bs-emphasis-color: #11181c;
    --bs-emphasis-color-rgb: 17, 24, 28;
    --bs-secondary-color: #5c686f;
    --bs-secondary-bg: #d2d9dd;
    --bs-tertiary-color: #828f97;
    --bs-tertiary-bg: #e6ebee;
    --bs-border-color: #c1cacf;
    --bs-border-color-translucent: rgba(17, 24, 28, .14);
    --bs-heading-color: #11181c;

    --bs-link-color: #b8610f;
    --bs-link-color-rgb: 184, 97, 15;
    --bs-link-hover-color: #8f4a09;
    --bs-link-hover-color-rgb: 143, 74, 9;

    --bs-primary: #e8821e;
    --bs-primary-rgb: 232, 130, 30;
    --bs-primary-text-emphasis: #8f4a09;
    --bs-primary-bg-subtle: #f7e4cd;
    --bs-primary-border-subtle: #e6c39a;
}

/* ---- Dark palette — gunmetal and brushed steel -------------------------- */
[data-bs-theme="dark"] {
    --rb-signal-amber: #ef8e2a;
    --rb-signal-amber-strong: #ffa03d;
    --rb-signal-red: #e0593f;
    --rb-signal-green: #4fae6e;
    --rb-terra: var(--rb-signal-amber);
    --rb-terra-strong: var(--rb-signal-amber-strong);

    --rb-rail-dim: #3a444b;
    --rb-geo-bg: #0c1113;
    --rb-rail-on-map: #d2dade;
    --rb-panel: #1e262b;
    --rb-field: #161c20;
    --rb-card-shadow: 0 1px 0 rgba(255, 255, 255, .04) inset, 0 2px 4px rgba(0, 0, 0, .45), 0 6px 16px rgba(0, 0, 0, .5);
    --rb-metal: linear-gradient(180deg, #283238 0%, #1f282d 50%, #192115 100%);

    --bs-body-bg: #0e1214;
    --bs-body-color: #cdd5da;
    --bs-emphasis-color: #eef3f5;
    --bs-emphasis-color-rgb: 238, 243, 245;
    --bs-secondary-color: #8b99a1;
    --bs-secondary-bg: #080b0d;
    --bs-tertiary-color: #65727a;
    --bs-tertiary-bg: #1a2227;
    --bs-border-color: #2b353b;
    --bs-border-color-translucent: rgba(231, 239, 243, .12);
    --bs-heading-color: #eef3f5;

    --bs-link-color: #f0a14a;
    --bs-link-color-rgb: 240, 161, 74;
    --bs-link-hover-color: #f6b76f;
    --bs-link-hover-color-rgb: 246, 183, 111;

    --bs-primary: #ef8e2a;
    --bs-primary-rgb: 239, 142, 42;
    --bs-primary-text-emphasis: #f6b76f;
    --bs-primary-bg-subtle: #2a1d0d;
    --bs-primary-border-subtle: #5c3f1a;
}

body { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }

/* Bootstrap compiles its component colours at build time, so the components that hard-code the
   stock blue are re-pointed at the palette here. Re-run `grep '#0d6efd' bootstrap.min.css` after
   a Bootstrap upgrade: a new component with a compiled-in colour would need a line below. */
.btn-primary {
    --bs-btn-bg: var(--rb-terra); --bs-btn-border-color: var(--rb-terra);
    --bs-btn-hover-bg: var(--rb-terra-strong); --bs-btn-hover-border-color: var(--rb-terra-strong);
    --bs-btn-active-bg: var(--rb-terra-strong); --bs-btn-active-border-color: var(--rb-terra-strong);
    --bs-btn-disabled-bg: var(--rb-terra); --bs-btn-disabled-border-color: var(--rb-terra);
    --bs-btn-color: #fff; --bs-btn-hover-color: #fff; --bs-btn-active-color: #fff; --bs-btn-disabled-color: #fff;
}
.btn-secondary {
    --bs-btn-bg: #5c676d; --bs-btn-border-color: #5c676d;
    --bs-btn-hover-bg: #4c565b; --bs-btn-hover-border-color: #4c565b;
    --bs-btn-active-bg: #4c565b; --bs-btn-active-border-color: #4c565b;
    --bs-btn-disabled-bg: #5c676d; --bs-btn-disabled-border-color: #5c676d;
    --bs-btn-color: #fff; --bs-btn-hover-color: #fff; --bs-btn-active-color: #fff;
}
[data-bs-theme="dark"] .btn-secondary {
    --bs-btn-bg: #39444a; --bs-btn-border-color: #39444a;
    --bs-btn-hover-bg: #46525a; --bs-btn-hover-border-color: #46525a;
    --bs-btn-active-bg: #46525a; --bs-btn-active-border-color: #46525a;
}
.btn-outline-secondary {
    --bs-btn-color: var(--bs-secondary-color); --bs-btn-border-color: var(--bs-border-color);
    --bs-btn-hover-bg: var(--rb-field); --bs-btn-hover-border-color: var(--bs-secondary-color);
    --bs-btn-hover-color: var(--bs-emphasis-color);
    --bs-btn-active-bg: var(--rb-field); --bs-btn-active-border-color: var(--bs-secondary-color);
    --bs-btn-active-color: var(--bs-emphasis-color);
}
.btn-outline-primary {
    --bs-btn-color: var(--bs-primary); --bs-btn-border-color: var(--bs-primary);
    --bs-btn-hover-bg: var(--bs-primary); --bs-btn-hover-border-color: var(--bs-primary);
    --bs-btn-active-bg: var(--bs-primary); --bs-btn-active-border-color: var(--bs-primary);
    --bs-btn-disabled-color: var(--bs-primary); --bs-btn-disabled-border-color: var(--bs-primary);
}
.card { --bs-card-bg: var(--rb-panel); }
.dropdown-menu { --bs-dropdown-link-active-bg: var(--bs-primary); }
.nav-pills { --bs-nav-pills-link-active-bg: var(--bs-primary); }
.list-group {
    --bs-list-group-bg: transparent;
    --bs-list-group-border-color: var(--bs-border-color);
    --bs-list-group-color: var(--bs-body-color);
    --bs-list-group-action-color: var(--bs-body-color);
    --bs-list-group-action-hover-bg: var(--rb-field);
    --bs-list-group-action-hover-color: var(--bs-emphasis-color);
    --bs-list-group-action-active-bg: var(--rb-field);
    --bs-list-group-active-bg: var(--bs-primary);
    --bs-list-group-active-border-color: var(--bs-primary);
}
.form-control, .form-select { background-color: var(--rb-field); border-color: var(--bs-border-color); }
.form-control:focus, .form-select:focus { border-color: var(--rb-terra); box-shadow: 0 0 0 .2rem rgba(var(--bs-primary-rgb), .2); }
.form-control::placeholder { color: var(--bs-tertiary-color); }
.form-control-color { background-color: var(--rb-field); }
.form-check-input:checked, .form-check-input[type=checkbox]:indeterminate { background-color: var(--bs-primary); border-color: var(--bs-primary); }
/* A checkbox sharing a `.row.align-items-end` with text inputs: give it a control's height so its
   caption lines up with the neighbours' labels (the users page). */
.form-check-inrow { min-height: calc(1.5em + .75rem + 2px); display: flex; align-items: center; gap: .4rem; padding-left: 0; }
.form-check-inrow .form-check-input { margin: 0; float: none; flex: none; }

/* ---- Page widths and running text ---------------------------------------- */
.rb-prose { max-width: 68ch; }
.rb-narrow-sm { max-width: 380px; width: 100%; }
.rb-narrow { max-width: 720px; }
.rb-narrow-lg { max-width: 900px; }
.rb-cardcol { flex: 1 1 16rem; min-width: 0; }
.rb-user-actions .btn { min-height: 40px; display: inline-flex; align-items: center; justify-content: center; }
.rb-404 { text-align: center; }
.rb-404 svg { width: min(340px, 80vw); height: auto; margin-bottom: .5rem; }
.rb-404 .rail { stroke: currentColor; opacity: .28; }
.rb-404 .stop { fill: var(--bs-primary); }
.rb-404 .sleeper { stroke: currentColor; opacity: .16; }
.rb-404 .num { font-size: clamp(3rem, 12vw, 5.5rem); font-weight: 800; line-height: 1; letter-spacing: -.03em; color: var(--bs-primary); margin: 0; }

/* ============================================================================
   THE APP SHELL — one bar (fragments/appshell.html): the three tools, the Rail
   app's three views nested inside it, the clock, the theme and the account.
   It narrows by dropping words, never destinations.
   ========================================================================== */
/* Locked to the device width: no double-tap zoom (touch-action), no rubber-band or pull-to-refresh
   (overscroll-behavior), no text selection over a driving screen. Leaflet keeps its own touch-action
   inside the maps, which is where pinch-zoom still belongs. */
.rb-shell {
    display: flex; flex-direction: column; overflow: hidden; background: var(--bs-body-bg);
    height: 100vh; height: 100dvh;   /* the dynamic unit follows a browser toolbar in and out; the plain one is the fallback */
    touch-action: manipulation; overscroll-behavior: none; -webkit-text-size-adjust: 100%;
    user-select: none; -webkit-user-select: none;
    /* The one inset the app keeps at its edge: a curved screen or a case lip hides the outermost
       character or two of anything set flush, so text stops this far short of the glass. */
    --rb-edge: 6px;
}
@supports (-webkit-touch-callout: none) { .rb-shell { min-height: -webkit-fill-available; } }   /* older iOS: the visible height, toolbar excluded */
.rb-shell input, .rb-shell textarea, .rb-shell select, .rb-shell [contenteditable], .rb-shell .rb-prose { user-select: text; -webkit-user-select: text; }
/* The tool scrolls by default; a tool that owns its layout (the maps) says so with --fixed, so a
   page that forgets gets a scrollbar rather than clipped content. */
.rb-shell-main { flex: 1 1 auto; min-height: 0; position: relative; overflow: auto; }
.rb-shell-main--fixed { overflow: hidden; }

.rb-appbar {
    flex: none; align-items: center; gap: .25rem; background: var(--rb-panel); border-bottom: 1px solid var(--bs-border-color);
    /* Bootstrap gives the navbar .5rem top and bottom; the top one used to be REPLACED by the safe-area
       inset, so the row sat high on every phone without a notch. Now the inset is added on every side. */
    padding: .25rem calc(var(--rb-edge) + env(safe-area-inset-right, 0px)) .25rem calc(var(--rb-edge) + env(safe-area-inset-left, 0px));
    padding-top: calc(.25rem + env(safe-area-inset-top, 0px));
}
/* The menu button and the three view tabs are the row: every one a 44 px target, the tabs equal thirds
   of what the button leaves (nav-fill), icon over label on a phone and beside it from sm up (the flex
   is Bootstrap utilities in appshell.html). The current view is filled in the signal colour. */
.rb-menu { min-width: 44px; min-height: 44px; padding: 0; font-size: 1.6rem; line-height: 1; color: var(--bs-emphasis-color); border: 1px solid var(--bs-border-color); border-radius: .5rem; background: var(--rb-panel); background-image: var(--rb-metal); }
.rb-menu:hover, .rb-menu:focus-visible, .rb-menu[aria-expanded="true"] { color: var(--bs-emphasis-color); background: var(--rb-field); border-color: var(--bs-secondary-color); }
.rb-menu-list { min-width: 15rem; }
.rb-menu-list .dropdown-item { min-height: 44px; display: flex; align-items: center; }
.rb-menu-list .dropdown-item.active { color: #fff; }
.rb-views .nav-link { min-height: 44px; padding: .15rem .25rem; line-height: 1; color: var(--bs-secondary-color); border-radius: .5rem; }
.rb-views .nav-link .bi { font-size: 1.3rem; line-height: 1; }
.rb-view-label { font-size: .7rem; font-weight: 600; letter-spacing: .02em; white-space: nowrap; }
.rb-views .nav-link:hover, .rb-views .nav-link:focus-visible { color: var(--bs-emphasis-color); background: var(--bs-tertiary-bg); }
.rb-views .nav-link.active { color: #fff; font-weight: 600; }
@media (min-width: 576px) {
    .rb-views .nav-link { padding: .3rem .6rem; }
    .rb-views .nav-link .bi { font-size: 1.15rem; }
    .rb-view-label { font-size: .9rem; }
}

/* A tool's own toolbar (the Planner's Map/List + search) and its controls panel. */
.rb-toolbar { flex: none; background: var(--bs-tertiary-bg); }
.rb-find { min-width: 0; max-width: 26rem; }
@media (min-width: 768px) { .rb-controls-panel { width: 320px; flex: 0 0 320px; overflow-y: auto; } }
.rb-find-results {
    position: absolute; top: calc(100% + 4px); left: 0; right: 0; z-index: 1200;
    max-height: 50vh; overflow-y: auto; background: var(--rb-panel);
    border: 1px solid var(--bs-border-color); border-radius: 9px; padding: 4px; box-shadow: 0 6px 20px rgba(0, 0, 0, .3);
}
.rb-find-results[hidden] { display: none; }

/* RB.toast: bottom-centre, clear of the driver's docked panel. */
.rb-toasts { position: fixed; left: 50%; bottom: calc(var(--rb-bar-h, 0px) + 16px); transform: translateX(-50%); width: max-content; max-width: min(92vw, 28rem); }
.rb-toasts .toast { width: auto; }

/* ============================================================================
   THE RAIL APP — route head, the three views, the floating controls.
   ========================================================================== */
/* No page padding below the bar beyond the edge inset and the phone's own safe areas. */
.rb-routehead { flex: none; padding: 0 calc(var(--rb-edge) + env(safe-area-inset-right, 0px)) 0 calc(var(--rb-edge) + env(safe-area-inset-left, 0px)); }
.rb-routehead-main { min-width: 0; }
.rb-route-name { font-size: 1.12rem; letter-spacing: -.015em; line-height: 1.15; color: var(--bs-emphasis-color); }
.rb-route-region { font-size: .64rem; letter-spacing: .05em; }
.rb-km-now { font-size: 1.34rem; color: var(--bs-emphasis-color); }
.rb-km-total { font-size: .72rem; }
.rb-route-progress { --bs-progress-height: 3px; --bs-progress-bg: var(--bs-border-color); --bs-progress-bar-bg: var(--rb-terra); --bs-progress-bar-transition: width .24s linear; margin-top: .2rem; }
.rb-nextup { display: flex; align-items: baseline; gap: .5rem; margin-top: .1rem; min-width: 0; font-family: var(--bs-font-monospace); }
.rb-nextup[hidden] { display: none; }
.rb-nextup-k { flex: none; font-size: .56rem; letter-spacing: .14em; text-transform: uppercase; color: var(--bs-secondary-color); }
.rb-nextup-name { min-width: 0; font-size: .92rem; font-weight: 600; color: var(--bs-emphasis-color); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rb-nextup-dist { margin-left: auto; flex: none; font-size: .84rem; font-weight: 700; color: var(--rb-terra); }

/* The three full-bleed views; only one shows at a time. --rb-bar-h is the docked panel's measured
   height (driver.js), which the map and strip leave room for. */
.rb-view { flex: 1; min-height: 0; position: relative; border-top: 1px solid var(--bs-border-color); --rb-bar-h: 66px; }
#strip-wrap, #map-wrap, #dynamics-wrap { position: absolute; inset: 0; background: var(--bs-body-bg); }
#strip-wrap[hidden], #map-wrap[hidden], #dynamics-wrap[hidden] { display: none; }
#strip-wrap, #map-wrap { bottom: var(--rb-bar-h, 66px); }
#map { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: var(--rb-geo-bg); }
#dynamics-wrap { overflow-y: auto; }
.rb-view-eyebrow { position: absolute; left: calc(var(--rb-edge) + env(safe-area-inset-left, 0px)); top: 6px; z-index: 500; font-family: var(--bs-font-monospace); font-size: .56rem; letter-spacing: .14em; color: var(--bs-secondary-color); text-transform: uppercase; pointer-events: none; }
.rb-strip-map { position: absolute; inset: 0; background: var(--rb-geo-bg); }
.rb-strip-empty { position: absolute; inset: 0; z-index: 5; display: flex; align-items: center; justify-content: center; padding: 0 2rem; text-align: center; pointer-events: none; font-size: .82rem; color: var(--bs-secondary-color); background: var(--bs-body-bg); }
.rb-strip-empty[hidden] { display: none; }

/* The right-edge control cluster: search, zoom, alerts, recentre, the capture "+". */
.rb-controls { right: calc(var(--rb-edge) + env(safe-area-inset-right, 0px)); bottom: calc(var(--rb-bar-h, 66px) + 8px); z-index: 700; }
.rb-ctl-btn {
    width: 44px; height: 40px; padding: 0; border-radius: 9px; border: 2px solid var(--bs-border-color);
    background: var(--rb-panel); background-image: var(--rb-metal); color: var(--bs-emphasis-color);
    font-size: 22px; line-height: 1; box-shadow: var(--rb-card-shadow);
}
.rb-ctl-btn:active { transform: scale(.94); }
.rb-recenter { display: inline-flex; align-items: center; justify-content: center; color: var(--rb-signal-amber); }
.rb-recenter svg { display: block; }
.rb-recenter[hidden] { display: none; }
.rb-alerts { font-size: 17px; }
.rb-alerts[aria-pressed="true"] { border-color: var(--rb-signal-amber); }
.rb-alerts[aria-pressed="false"] { opacity: .55; }
.rb-fab { width: 56px; height: 56px; border: none; border-radius: 50%; background: var(--rb-terra); color: #fff; font-size: 30px; line-height: 1; box-shadow: 0 4px 14px rgba(42, 34, 27, .35); transition: transform .12s ease, background .15s ease; }
.rb-fab:hover { background: var(--rb-terra-strong); color: #fff; }
.rb-fab:active { transform: scale(.94); }
.rb-fab-stop { background: #c62828; font-size: 22px; }
.rb-fab-stop:hover { background: #b71c1c; color: #fff; }
.rb-fab-stop[hidden] { display: none; }

/* On-map scale bars: horizontal on the map, vertical on the strip (distance runs up the page). Both sit
   inside their view's wrap, whose bottom already stops at the docked bar, so their offset is from THAT edge:
   bottom-left, directly above the GPS accuracy badge (which hangs off the bar instead); the chips stack above. */
.rb-scale {
    position: absolute; left: calc(var(--rb-edge) + env(safe-area-inset-left, 0px)); z-index: 640; pointer-events: none; display: flex; gap: 3px;
    background: #fff; color: #000; border: 1px solid #000;
    border-radius: 2px; padding: 3px 6px; font-family: var(--bs-font-monospace); font-size: .72rem; font-weight: 800; letter-spacing: .02em;
    box-shadow: var(--rb-card-shadow);
}
.rb-scale-bar { display: block; box-sizing: border-box; }
.rb-scale-h { bottom: 42px; flex-direction: column; align-items: flex-start; }
.rb-scale-h .rb-scale-bar { height: 5px; min-width: 14px; border: 2px solid #000; border-top: 0; }
.rb-scale-v { bottom: 42px; flex-direction: row; align-items: center; }
.rb-scale-v .rb-scale-bar { width: 5px; min-height: 14px; border: 2px solid #000; border-left: 0; }
.rb-scale-v .rb-scale-lbl { writing-mode: vertical-rl; }

/* Recording banner, GPS-offset badge, the sync / update / reject chips and the location prompt. */
.rb-rec-banner {
    position: absolute; top: 52px; left: 50%; transform: translateX(-50%); z-index: 650;
    display: flex; align-items: center; gap: .45rem; padding: .3rem .85rem;
    background: var(--rb-terra); color: #fff; border-radius: 999px; font-family: var(--bs-font-monospace); font-size: .76rem; box-shadow: var(--rb-card-shadow);
}
.rb-rec-banner[hidden] { display: none; }
.rb-rec-dot { width: 8px; height: 8px; border-radius: 50%; background: #fff; animation: rb-pulse 1s ease-in-out infinite; }
@keyframes rb-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .25; } }
.rb-offset {
    position: absolute; left: calc(var(--rb-edge) + env(safe-area-inset-left, 0px)); bottom: calc(var(--rb-bar-h, 66px) + 8px); z-index: 600;
    display: inline-flex; align-items: center; gap: .35rem; padding: .22rem .5rem; border-radius: 7px;
    background: color-mix(in oklab, var(--rb-panel) 90%, transparent); border: 1px solid var(--bs-border-color);
    font-family: var(--bs-font-monospace); font-size: .62rem; letter-spacing: .02em; color: var(--bs-body-color);
    box-shadow: var(--rb-card-shadow); pointer-events: none;
}
.rb-offset[hidden] { display: none; }
.rb-offset .k { font-size: .52rem; letter-spacing: .1em; color: var(--bs-secondary-color); }
.rb-offset.wide { color: var(--rb-terra); font-weight: 600; }
.rb-sync-chip {
    position: absolute; left: calc(var(--rb-edge) + env(safe-area-inset-left, 0px)); bottom: calc(var(--rb-bar-h, 66px) + 78px); z-index: 600;
    display: inline-flex; align-items: center; gap: .4rem; padding: .22rem .55rem; border-radius: 7px;
    background: color-mix(in oklab, var(--rb-panel) 90%, transparent); border: 1px solid var(--rb-signal-amber);
    font-family: var(--bs-font-monospace); font-size: .62rem; letter-spacing: .02em; color: var(--bs-body-color);
    box-shadow: var(--rb-card-shadow); pointer-events: none; max-width: min(70vw, 340px);
}
.rb-sync-chip[hidden] { display: none; }
.rb-sync-dot { flex: 0 0 auto; width: 8px; height: 8px; border-radius: 50%; background: var(--rb-signal-amber); animation: rb-pulse 1.2s ease-in-out infinite; }
/* The update offer (green: something good is available) and a refused change (red: something was
   lost) sit a row higher and, unlike the sync chip, take taps. */
.rb-update-chip { bottom: calc(var(--rb-bar-h, 66px) + 110px); border-color: var(--rb-signal-green); pointer-events: auto; }
.rb-update-chip .rb-sync-dot { background: var(--rb-signal-green); }
.rb-reject-chip { bottom: calc(var(--rb-bar-h, 66px) + 110px); border-color: var(--rb-signal-red); pointer-events: auto; }
.rb-reject-chip .rb-sync-dot { background: var(--rb-signal-red); animation: none; }
.rb-reject-chip .rb-update-reload { border-color: var(--rb-signal-red); }
.rb-reject-chip .rb-update-reload:hover, .rb-reject-chip .rb-update-reload:focus-visible { background: color-mix(in oklab, var(--rb-signal-red) 22%, transparent); }
.rb-update-reload { margin-left: .15rem; padding: .1rem .45rem; border: 1px solid var(--rb-signal-green); border-radius: 5px; background: transparent; color: inherit; font: inherit; letter-spacing: inherit; cursor: pointer; }
.rb-update-reload:hover, .rb-update-reload:focus-visible { background: color-mix(in oklab, var(--rb-signal-green) 22%, transparent); }
.rb-locprompt {
    position: absolute; z-index: 700; left: 50%; transform: translateX(-50%); top: 14px; width: min(92vw, 380px);
    padding: .7rem .8rem; border-radius: 10px; background: color-mix(in oklab, var(--rb-panel) 96%, transparent);
    border: 1px solid var(--rb-signal-amber); box-shadow: var(--rb-card-shadow); color: var(--bs-body-color);
}
.rb-locprompt[hidden] { display: none; }
.rb-locprompt-head { display: flex; align-items: flex-start; gap: .45rem; font-size: .82rem; line-height: 1.35; margin-bottom: .55rem; }
.rb-locprompt-head .bi { color: var(--rb-signal-amber); flex: 0 0 auto; margin-top: .1rem; }
.rb-locprompt-help { margin: 0 0 .6rem; padding-left: 1.1rem; font-size: .72rem; line-height: 1.45; color: var(--bs-secondary-color); }
.rb-locprompt-help[hidden] { display: none; }
.rb-locprompt-help li + li { margin-top: .2rem; }
.rb-loc-dot { display: inline-block; flex: 0 0 auto; width: 10px; height: 10px; border-radius: 50%; background: var(--bs-secondary-color); }
.rb-loc-dot--ok { background: var(--bs-success); }
.rb-loc-dot--warn { background: var(--rb-signal-amber); }
.rb-loc-dot--bad { background: var(--bs-danger); }

/* Pin search: a docked panel under the route head. */
.rb-search-panel {
    position: absolute; left: 10px; right: 10px; top: 8px; z-index: 720; display: flex; flex-direction: column;
    max-height: min(60vh, 420px); background: var(--rb-panel); border: 1px solid var(--bs-border-color);
    border-radius: 12px; box-shadow: var(--rb-card-shadow); overflow: hidden;
}
.rb-search-panel[hidden] { display: none; }
.rb-search-head { display: flex; gap: 6px; padding: 8px; border-bottom: 1px solid var(--bs-border-color); }
.rb-search-head .form-control { flex: 1; min-width: 0; }
.rb-search-head .btn { flex: 0 0 auto; border: 1px solid var(--bs-border-color); background: var(--rb-panel); color: var(--bs-body-color); }
.rb-search-results { overflow-y: auto; -webkit-overflow-scrolling: touch; }
.rb-search-row { display: flex; align-items: center; gap: 10px; width: 100%; padding: 10px 12px; border: 0; border-bottom: 1px solid var(--bs-border-color); background: transparent; color: var(--bs-body-color); text-align: left; font-size: .95rem; }
.rb-search-row:last-child { border-bottom: 0; }
.rb-search-row:hover, .rb-search-row:focus-visible { background: var(--rb-field); }
.rb-search-dot { flex: 0 0 auto; width: 12px; height: 12px; border-radius: 50%; border: 2px solid #fff; box-shadow: 0 0 0 1px rgba(0, 0, 0, .25); }
.rb-search-name { flex: 1; min-width: 0; overflow: hidden; line-height: 1.25; }
.rb-search-dist { flex: 0 0 auto; font-family: var(--bs-font-monospace); font-size: .72rem; color: var(--bs-secondary-color); }
.rb-search-empty { padding: 14px 12px; color: var(--bs-secondary-color); font-size: .9rem; }
.rb-search-halo { animation: rb-halo 1.2s ease-in-out infinite; }
@keyframes rb-halo { 0%, 100% { stroke-opacity: .95; } 50% { stroke-opacity: .25; } }

/* The docked component panel (Strip + Map) and the Dynamics gallery (rb-components.js). */
.rb-botbar {
    z-index: 620; padding: 0 0 env(safe-area-inset-bottom, 0px); max-height: 60dvh; overscroll-behavior: contain;
    background: var(--bs-body-bg); box-shadow: 0 -2px 10px rgba(0, 0, 0, .18);
}
/* A phone on its side: the bar takes a third of the height at most, so the map keeps the rest. */
@media (max-height: 500px) { .rb-botbar { max-height: 34dvh; } }
main.rb-view.rb-dyn-active .rb-botbar, main.rb-view.rb-dyn-active .rb-controls,
main.rb-view.rb-dyn-active .rb-search-panel, main.rb-view.rb-dyn-active .rb-offset { display: none !important; }
.rb-dyn { padding: 0 0 env(safe-area-inset-bottom, 0px); }
.rb-dyn-eyebrow { font-family: var(--bs-font-monospace); font-size: .6rem; letter-spacing: .12em; color: var(--bs-secondary-color); margin: .35rem 0 .15rem; padding-left: var(--rb-edge); text-transform: uppercase; }
.rb-gallery .rb-dyn-eyebrow { margin: .35rem 0 0; }
.rb-comp.card { --bs-card-bg: var(--rb-panel); --bs-card-border-color: var(--bs-border-color); --bs-card-cap-bg: transparent; min-width: 0; }
.rb-botbar .rb-comp.card { border-bottom: 0; }
/* The one inset left: a hair between a card's figures and its edge. Not the Bootstrap p-2 utility, which is !important. */
.rb-comp-body { padding: 6px var(--rb-edge); }
.rb-comp-title { font-size: .6rem; letter-spacing: .1em; }
/* Gallery: the Pin choice. Bar: the small "next" step — quiet on purpose, it is a glance control
   on a driving screen, and the bar comes back to the pin on its own. */
.rb-comp-pin { font-size: .62rem; padding: .05rem .5rem; line-height: 1.4; }
.rb-comp-pin.active { color: var(--bs-body-bg); background: var(--bs-secondary-color); border-color: var(--bs-secondary-color); }
.rb-comp-next { padding: 0 .15rem; border: 0; line-height: 1; font-size: .8rem; color: var(--bs-secondary-color); opacity: .6; min-width: 28px; min-height: 22px; }
.rb-comp-next:hover, .rb-comp-next:focus-visible { opacity: 1; color: var(--bs-emphasis-color); }
.rb-stat-big { font-size: 2.5rem; color: var(--bs-emphasis-color); }
.rb-stat-spark { width: 130px; height: 34px; opacity: .9; }   /* the CSS size; the backing store is that × the pixel ratio */
.rb-stat-k { font-size: .54rem; letter-spacing: .08em; }
.rb-stat-v { font-size: 1.05rem; color: var(--bs-emphasis-color); }
/* A graph's box has a fixed height in BOTH the gallery and the bar: a canvas with no CSS height is
   laid out at its 300×150 intrinsic ratio until first painted, which made the bar measure itself
   far too tall the moment "next" landed on a graph. */
.rb-graph { height: 130px; background: var(--rb-geo-bg); }
.rb-graph-empty { height: 130px; display: flex; align-items: center; justify-content: center; background: var(--rb-geo-bg); font-size: .62rem; letter-spacing: .04em; padding: 0 1rem; }   /* display stays here: it is toggled with [hidden] */
.rb-trackpill { background: var(--bs-body-bg); padding: .3rem .7rem; font-size: .62rem; letter-spacing: .06em; color: var(--bs-tertiary-color); }
.rb-trackpill-muted { color: var(--bs-secondary-color); }
.rb-statlbl { font-size: .62rem; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rb-status-online, .rb-track-on { color: #2e9e5b; }
.rb-status-offline, .rb-track-off { color: var(--bs-secondary-color); }
/* A status light carries a glyph as well as a colour, so its state reads without colour. */
.rb-light { display: inline-flex; align-items: center; justify-content: center; width: 15px; height: 15px; border-radius: 50%; flex: none; background: var(--bs-border-color); color: var(--bs-body-bg); font-size: 9px; font-weight: 700; line-height: 1; }
.rb-light::after { content: "–"; }
.rb-light.on { background: #2e9e5b; box-shadow: 0 0 6px rgba(46, 158, 91, .85); }
.rb-light.on::after { content: "\2713"; }
.rb-light.off { background: var(--bs-border-color); box-shadow: none; color: var(--bs-secondary-color); }
.rb-light.off::after { content: "\2715"; }
.rb-disclaimer { padding: 0 var(--rb-edge); }
/* The Dynamics Set-up card: the same small-caps keys as the Stats tiles, a quiet status line
   (Bootstrap's .text-danger, which carries !important, colours a failure). */
.rb-setup-k { display: block; font-family: var(--bs-font-monospace); font-size: .54rem; letter-spacing: .08em; text-transform: uppercase; color: var(--bs-secondary-color); margin-bottom: .2rem; }
.rb-setup-status { font-size: .72rem; color: var(--bs-secondary-color); }

/* ============================================================================
   THE MAP SURFACE — drawn inside Leaflet by the shared renderers.
   ========================================================================== */
.rb-train-icon { color: var(--rb-train-color, var(--rb-terra)); will-change: transform; }
.rb-train-icon svg { display: block; transform-origin: 50% 50%; filter: drop-shadow(0 0 5px var(--rb-train-color, var(--rb-terra))) drop-shadow(0 0 2px var(--rb-train-color, var(--rb-terra))) drop-shadow(0 1px 1px rgba(0, 0, 0, .5)); }

/* Shared pin (RBPin): a themed circle carrying an optional icon; the list-row swatch matches it. */
.rb-pin { display: flex; align-items: center; justify-content: center; }
.rb-pin-face { width: 18px; height: 18px; box-sizing: border-box; border: 2px solid; border-radius: 50%; display: flex; align-items: center; justify-content: center; color: #fff; box-shadow: 0 1px 3px rgba(0, 0, 0, .45); }
.rb-pin-face .bi { font-size: 10px; line-height: 1; }
.rb-pin--drag { cursor: grab; }
.rb-pin--sel .rb-pin-face, .rb-pin-face:hover { box-shadow: 0 0 0 3px rgba(79, 163, 179, .65); }
.rb-swatch { display: inline-flex; align-items: center; justify-content: center; width: 20px; height: 20px; border-radius: 50%; flex: none; color: #fff; border: 1px solid rgba(0, 0, 0, .18); }
.rb-swatch .bi { font-size: 11px; }

/* Incident warnings (RBIncidents): an amber triangle at an active incident inside the driver's rail
   corridor. Deliberately the loudest thing on the map after the train — it is the only marker here
   that means "something is happening", and it is drawn in a dark-outlined amber that survives both
   themes and a sunlit cab. A drop shadow, not a glow: a glow reads as the train. */
.rb-incident-icon svg { display: block; filter: drop-shadow(0 1px 3px rgba(0, 0, 0, .55)); }
.rb-incident-icon:hover svg, .rb-incident-icon:focus svg { filter: drop-shadow(0 0 4px rgba(234, 179, 8, .9)) drop-shadow(0 1px 3px rgba(0, 0, 0, .55)); }

.rb-incident-popup .leaflet-popup-content-wrapper { border-radius: 12px; background: var(--bs-body-bg); color: var(--bs-body-color); border: 1px solid var(--bs-border-color); box-shadow: 0 8px 28px rgba(0, 0, 0, .22); }
.rb-incident-popup .leaflet-popup-content { margin: .8rem .95rem; width: 240px !important; max-width: calc(100vw - 3rem); font-family: inherit; font-size: .85rem; }
.rb-incident-popup .leaflet-popup-tip { background: var(--bs-body-bg); border: 1px solid var(--bs-border-color); }
.rb-incident-popup .leaflet-popup-close-button { display: block; color: var(--bs-secondary-color); }
.rb-incident-popup .leaflet-popup-close-button:hover { color: var(--bs-body-color); background: transparent; }
.rb-incident-title { font-weight: 600; line-height: 1.25; margin-bottom: .5rem; padding-right: .75rem; }
.rb-incident-facts { display: grid; grid-template-columns: auto 1fr; gap: .15rem .6rem; margin: 0; font-size: .8rem; }
.rb-incident-facts dt { font-weight: 400; color: var(--bs-secondary-color); }
.rb-incident-facts dd { margin: 0; font-variant-numeric: tabular-nums; }
.rb-incident-chip { color: #b45309; font-weight: 700; }
.rb-incident-note { margin: .6rem 0 0; font-size: .68rem; line-height: 1.35; color: var(--bs-secondary-color); }
.rb-layer-dot { width: 12px; height: 12px; border-radius: 3px; border: 1px solid var(--bs-border-color); }

/* Cluster bubbles (rb-cluster.js): three tiers by count. */
.rb-cluster-bubble { border-radius: 50%; color: #fff; display: flex; align-items: center; justify-content: center; font: 800 14px/1 system-ui, sans-serif; border: 2px solid rgba(255, 255, 255, .85); box-shadow: 0 0 4px rgba(0, 0, 0, .4); }
.rb-cluster-bubble--0 { width: 34px; height: 34px; background: rgba(45, 125, 50, .85); }
.rb-cluster-bubble--1 { width: 40px; height: 40px; background: rgba(224, 159, 62, .9); }
.rb-cluster-bubble--2 { width: 48px; height: 48px; font-size: 15px; background: rgba(214, 69, 80, .92); }

/* Name plates: the public layers' tooltips and the train-following divIcon labels. Industrial on
   purpose — bold black on an opaque white plate with a hard edge, in BOTH themes: a driver reads these
   at a glance in sun and at night, and a translucent plate over a busy map never did. The placement
   pass in map-view.js estimates a plate's size from these metrics; change them together. */
.leaflet-tooltip.rb-geo-label { background: #fff; color: #000; border: 1.5px solid #000; box-shadow: 0 1px 0 rgba(0, 0, 0, .6); padding: 2px 6px; border-radius: 2px; font-family: var(--bs-font-monospace); font-size: 12px; font-weight: 800; white-space: nowrap; }
.leaflet-tooltip.rb-geo-label::before { display: none; }
.leaflet-tooltip.rb-geo-label .rb-geo-lab-info { font-size: 10px; font-weight: 700; opacity: 1; }
.leaflet-marker-icon.rb-geo-lab { width: auto !important; height: auto !important; background: none; border: none; box-shadow: none; pointer-events: none; }
.rb-geo-lab-inner { display: inline-flex; flex-direction: column; line-height: 1.1; white-space: nowrap; max-width: min(250px, 60vw); background: #fff; color: #000; border: 1.5px solid #000; border-radius: 2px; padding: 2px 6px; box-shadow: 0 1px 0 rgba(0, 0, 0, .6); }
.rb-geo-lab-name, .rb-geo-lab-info { overflow: hidden; text-overflow: ellipsis; }   /* a long name is cut, never run off the glass */
.rb-geo-lab-inner.rb-geo-lab--off { padding: 1px 5px; }
.rb-geo-lab-inner.rb-geo-lab--off .rb-geo-lab-name { font-weight: 800; font-size: 12.5px; }
.rb-geo-lab-name { font-size: 14px; font-weight: 800; letter-spacing: .01em; color: #000; }
.rb-geo-lab-info { font-family: var(--bs-font-monospace); font-size: 10px; font-weight: 700; color: #000; }
.rb-geo-lab-info.alongside { color: #b45309; font-weight: 800; }
/* Alongside: the state is a tag, the line is the countdown until the rear clears the point. */
.rb-geo-lab-tag { display: inline-block; min-width: 1.2em; margin-right: .35em; padding: 0 .2em; border-radius: 2px; background: #b45309; color: #fff; font-family: var(--bs-font-family-sans-serif); font-weight: 800; font-size: .9em; line-height: 1.25; text-align: center; }
.rb-geo-lab-info.passed { color: #555; font-weight: 600; }
/* The Strip has room for larger plates (MapView adds .rb-geo-lab-lg to its container). */
.rb-geo-lab-lg .rb-geo-lab-inner { padding: 3px 9px; }
.rb-geo-lab-lg .rb-geo-lab-name { font-size: 19px; }
.rb-geo-lab-lg .rb-geo-lab-info { font-size: 12.5px; }
.rb-geo-lab-lg .rb-geo-lab-inner.rb-geo-lab--off .rb-geo-lab-name { font-size: 17px; }

/* Distance markers: a dashed tick across the rail with the forward km left of travel, reverse right. */
.leaflet-marker-icon.rb-dm { width: 0 !important; height: 0 !important; background: none; border: none; box-shadow: none; pointer-events: none; overflow: visible; }
.rb-dm-tick { position: absolute; left: 0; top: 0; width: 44px; height: 0; border-top: 2px dashed #000; opacity: .9; transform: translate(-50%, -50%) rotate(var(--rb-dm-brg, 0deg)); transform-origin: center; }
.rb-dm-num { position: absolute; font-family: var(--bs-font-monospace); font-size: 12px; font-weight: 800; line-height: 1; color: #000; background: #fff; border: 1px solid #000; border-radius: 2px; padding: 1px 3px; white-space: nowrap; transform: translate(-50%, -50%); }
.rb-dm-rev { transform: translate(-50%, -50%) rotate(180deg); }
.rb-dm-flip-row { display: flex; align-items: center; gap: .4rem; cursor: pointer; }
.rb-dm-flip-row input { margin: 0; }

/* Heatmap legends (heat-ramp.js). */
.rb-legend-bar { display: flex; height: 12px; border-radius: 3px; overflow: hidden; }
.rb-legend-bar > span { flex: 1; }
.rb-legend-labels { display: flex; justify-content: space-between; font-size: .6rem; color: var(--bs-secondary-color); }

/* Settings' heat-layer choice: five buttons in a row (wrapping on a phone), each its name over its own colour bar (the
   legend lives here; the driving screens carry none). "None" shows an empty, dashed bar. */
.rb-heat-choice { display: grid; grid-template-columns: repeat(auto-fit, minmax(96px, 1fr)); gap: .5rem; }
.rb-heat-choice > label { display: flex; flex-direction: column; gap: .35rem; padding: .5rem .5rem .45rem; }
.rb-heat-choice > label > .rb-legend-bar { height: 8px; width: 100%; }
.rb-legend-bar-none { border: 1px dashed var(--bs-border-color); background: transparent; }

/* Driver-map popups (a tapped pin's name) themed like the plates; tap-dismissable, no tip. */
.rb-rail .leaflet-popup-content-wrapper { background: #fff; color: #000; border: 1.5px solid #000; border-radius: 3px; box-shadow: 0 1px 0 rgba(0, 0, 0, .6); }
.rb-rail .leaflet-popup-content { font-family: var(--bs-font-monospace); font-size: 14px; font-weight: 700; color: #000; }
.rb-rail .leaflet-popup-content b { color: #000; }
.rb-rail .leaflet-popup-content a { color: var(--rb-terra); }
.rb-rail .leaflet-popup-tip-container, .rb-rail .leaflet-popup-close-button { display: none; }

/* ============================================================================
   THE PLANNER — its map body, list view, edit popups and readouts.
   ========================================================================== */
.rb-editor-body { background: var(--rb-geo-bg); }
.rb-editor-list { position: absolute; inset: 0; z-index: 1000; background: var(--bs-body-bg); }
.rb-editor-loading { position: absolute; inset: 0; z-index: 1200; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; background: var(--bs-body-bg); color: var(--bs-emphasis-color); font-weight: 500; }
.rb-editor-loading[hidden] { display: none; }
.rb-drag-readout { position: absolute; left: 50%; top: 12px; transform: translateX(-50%); z-index: 1150; background: var(--bs-emphasis-color); color: var(--bs-body-bg); padding: 5px 12px; border-radius: 20px; font-family: var(--bs-font-monospace); font-size: .8rem; white-space: nowrap; box-shadow: 0 2px 10px rgba(0, 0, 0, .3); pointer-events: none; }
.rb-drag-readout[hidden] { display: none; }
.rb-editor-busy { position: absolute; left: 50%; top: 12px; transform: translateX(-50%); z-index: 1150; display: inline-flex; align-items: center; gap: 8px; background: var(--rb-panel); border: 1px solid var(--bs-border-color); color: var(--bs-emphasis-color); padding: 5px 12px; border-radius: 20px; font-size: .82rem; box-shadow: var(--rb-card-shadow); }
.rb-editor-busy[hidden] { display: none; }

/* Edit popups (point, segment, datum): themed with Bootstrap variables and given a real width —
   Leaflet's auto-sizing collapses a form to a sliver. */
.rb-edit-popup .leaflet-popup-content-wrapper { border-radius: 12px; background: var(--bs-body-bg); color: var(--bs-body-color); border: 1px solid var(--bs-border-color); box-shadow: 0 8px 28px rgba(0, 0, 0, .22); }
.rb-edit-popup .leaflet-popup-content { margin: .9rem 1.05rem; width: 268px !important; max-width: calc(100vw - 3rem); }
.rb-edit-popup .leaflet-popup-tip { background: var(--bs-body-bg); border: 1px solid var(--bs-border-color); }
.rb-edit-popup .leaflet-popup-close-button { color: var(--bs-secondary-color); }
.rb-edit-popup .leaflet-popup-close-button:hover { color: var(--bs-body-color); background: transparent; }
.rb-edit-form { font-size: .875rem; }
.rb-edit-title { font-weight: 700; font-size: 1rem; color: var(--bs-emphasis-color); margin-bottom: .85rem; padding-bottom: .55rem; border-bottom: 1px solid var(--bs-border-color); }
.rb-frow { display: flex; align-items: center; gap: .65rem; margin-bottom: .75rem; }
.rb-frow > label { width: 54px; flex: none; color: var(--bs-secondary-color); font-size: .8rem; }
.rb-frow--col { flex-direction: column; align-items: stretch; gap: .35rem; }
.rb-frow--col > label { width: auto; margin-bottom: 0; }
.rb-edit-form .form-control, .rb-edit-form .form-select { min-height: 36px; }
.rb-edit-form .form-control-color { min-height: 36px; padding: .2rem; }
.rb-icon-search { margin-bottom: 0; }
.rb-icon-grid { display: grid; grid-template-columns: repeat(6, 1fr); gap: .35rem; max-height: 156px; overflow: auto; padding: .4rem; border: 1px solid var(--bs-border-color); border-radius: 8px; }
.rb-ico { display: flex; align-items: center; justify-content: center; height: 40px; border: 1px solid transparent; border-radius: 6px; background: var(--bs-body-bg); color: var(--bs-emphasis-color); cursor: pointer; }
.rb-ico .bi { font-size: 15px; }
.rb-ico:hover { background: var(--rb-panel); }
.rb-ico.active { border-color: var(--rb-terra); background: var(--rb-panel); color: var(--rb-terra); }
.rb-ico[hidden] { display: none; }
.rb-color-row { display: flex; align-items: center; gap: .6rem; }
.rb-color-presets { display: flex; gap: .5rem; flex-wrap: wrap; }
.rb-chip { width: 30px; height: 30px; border-radius: 50%; border: 1px solid rgba(0, 0, 0, .2); cursor: pointer; padding: 0; }
.rb-edit-actions { display: flex; justify-content: space-between; gap: .6rem; margin-top: 1rem; }
.rb-edit-actions .btn { min-height: 38px; padding-inline: 1rem; display: inline-flex; align-items: center; justify-content: center; }
.rb-edit-status { color: var(--rb-terra); min-height: 1em; margin-top: .45rem; font-size: .78rem; }

/* ══════════════════════════════════════════════════════════════════════════════
   MOBILE-FIRST FOUNDATION
   Last in the cascade deliberately: these are corrections that must beat the
   per-component rules above them.
   ══════════════════════════════════════════════════════════════════════════════ */

/* iOS Safari zooms the page when a form control smaller than 16px takes focus and never zooms
   back; 16px at phone widths prevents it. */
@media (max-width: 575.98px) {
  input, select, textarea,
  .form-control, .form-select { font-size: 16px !important; }
}

/* Nothing may push the page wider than the phone. `clip`, not `hidden`: overflow:hidden makes the
   element a scroll container, which breaks position:sticky for everything inside it. */
html, body { max-width: 100%; overflow-x: clip; height: 100%; }

/* Media and embeds shrink to their container rather than defining the page width — EXCEPT inside
   a Leaflet map. Leaflet lays its panes out at 0×0 and positions children by transform, so "shrink
   to my container" collapses the canvas the rail is painted on to zero width and the whole network
   disappears. Leaflet's own stylesheet guards img and svg against this reset but not canvas. */
img, svg, video, canvas, iframe { max-width: 100%; height: auto; }
.leaflet-container canvas { max-width: none !important; max-height: none !important; }

/* Long URLs, station names and ids are the usual culprits behind a phone-width blowout. */
p, li, td, th, dd, dt, h1, h2, h3, h4 { overflow-wrap: break-word; }

/* WCAG 2.5.8 asks for a 24×24px minimum target; Apple and Google both recommend 44px. Only where a
   coarse pointer is the input device, so a desktop keeps its denser controls. */
@media (pointer: coarse) {
  a.btn, button, [role="button"], input[type="submit"], input[type="button"] {
    min-height: 44px;
  }
}
