/* ============================================================
   DriveProof — shared design system
   Used by: index, day, journey, trip, reports, drivers,
            locations, account, settings, review, outing, raw,
            game, welcome, connect, landing.
   Financial-terminal take: Inter Tight + JetBrains Mono,
   ink scale, hairlines, badges, tables, calendar, sparklines.
   ============================================================ */

/* ─── palette-independent tokens ────────────────────────────── */
:root {
  /* layout chrome */
  --nav-height: 48px;
  --map-col-gutter: 16px;
  --rail-w: 56px;
  --topbar-h: 40px;

  /* type */
  --font-sans: 'Inter Tight', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --font-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, monospace;

  /* spacing */
  --space-1: 4px;  --space-2: 8px;  --space-3: 12px; --space-4: 16px;
  --space-5: 24px; --space-6: 32px; --space-7: 48px;

  /* radii */
  --r-1: 3px; --r-2: 4px; --r-3: 6px; --r-4: 10px;

  /* font sizes */
  --fs-xs: 11px; --fs-sm: 12px; --fs-md: 13px;
  --fs-lg: 15px; --fs-xl: 18px; --fs-2xl: 22px;
}

/* ─── light palette (default) ──────────────────────────────── */
:root, [data-theme="light"] {
  /* canonical surfaces / ink */
  --bg:         #f3f3f5;
  --surface:    #ffffff;
  --surface-1:  #f4f4f5;
  --surface-2:  #fafafb;
  --border:     #e1e1e6;
  --border-2:   #d0d0d6;

  --ink-0: #1c1c1e; --ink-1: #323236; --ink-2: #58585c;
  --ink-3: #8a8a90; --ink-4: #c0c0c6;

  --link: #0e639c; --link-hov: #0a4d7a;
  --accent: #0078d4; --accent-bg: #e6f2fb;
  --brand:  #e03131;

  --ok:   #107c10; --ok-bg:   #dff6dd;
  --warn: #a86b00; --warn-bg: #fdf3d4; --warn-bdr: #f0d995;
  --err:  #a4262c; --err-bg:  #fde7e9;
  --info: #0078d4; --info-bg: #e6f2fb;

  /* category tokens — light tints */
  --cat-commute:    #c25a00;  --cat-commute-bg:    #fde9d3;
  --cat-business:   #107c10;  --cat-business-bg:   #dff6dd;
  --cat-personal:   #5a5a63;  --cat-personal-bg:   #ececef;
  --cat-medical:    #0078d4;  --cat-medical-bg:    #e6f2fb;
  --cat-robotaxi:   #6f3fa3;  --cat-robotaxi-bg:   #f0e6f8;
  --cat-charity:    #a86b00;  --cat-charity-bg:    #fdf3d4;
  --cat-untagged:   #a4262c;  --cat-untagged-bg:   #fde7e9;
  --cat-rental:     #0078d4;  --cat-rental-bg:     #e6f2fb;
  --cat-mixed:      #6f3fa3;  --cat-mixed-bg:      #f0e6f8;
  --cat-inprog:     #0078d4;  --cat-inprog-bg:     #e6f2fb;

  /* rail (always dark — intentional inversion against light surfaces) */
  --rail-bg:        #1f1f23;
  --rail-ink:       #c9c9d0;
  --rail-ink-2:     #888892;
  --rail-active-bg: #2d2d33;
  --rail-divider:   #2c2c33;
  --rail-accent:    #2899f5;

  --selected-bg:    #e6f2fb;
  --selected-bar:   #0078d4;
  --row-hover:      #fafafb;

  --map-bg:         linear-gradient(135deg, #f4f5f7 0%, #e8eaf0 100%);
  --map-line:       #d8dbe4;
  --map-water:      #e0e7f0;
  --map-route:      #0078d4;
  --map-route-2:    #6fdb6f;
  --map-pin-start:  #1c1c1e;
  --map-pin-end:    #a86b00;
  --map-badge-bg:   rgba(255,255,255,0.95);

  --acct-grad: linear-gradient(135deg, #6b7c93 0%, #4a5568 100%);
  --acct-fg:   #fff;

  --shadow-1:   0 1px 0 var(--border);
  --shadow-2:   0 2px 8px rgba(15,20,30,.08);
  --shadow-pop: 0 4px 14px rgba(15,20,30,.14);

  /* ── backward-compat aliases (existing pages reference these) ── */
  --bg-0:        var(--bg);
  --bg-1:        var(--surface);
  --bg-2:        var(--surface-2);
  --bg-3:        #ececef;
  --hairline:    var(--border);
  --hairline-2:  var(--border-2);

  --pos:         var(--ok);
  --pos-bg:      var(--ok-bg);
  --neg:         var(--err);
  --neg-bg:      var(--err-bg);

  --rental:      var(--cat-rental);
  --rental-bg:   var(--cat-rental-bg);
  --business:    var(--cat-business);
  --business-bg: var(--cat-business-bg);
  --commute:     var(--cat-commute);
  --commute-bg:  var(--cat-commute-bg);
  --medical:     var(--cat-medical);
  --robotaxi:    var(--cat-robotaxi);
  --robotaxi-bg: var(--cat-robotaxi-bg);
  --charity:     var(--cat-charity);
  --charity-bg:  var(--cat-charity-bg);
  --untagged:    var(--cat-untagged);
  --in-prog:     var(--cat-inprog);
  --in-prog-bg:  var(--cat-inprog-bg);
  --mixed:       var(--cat-mixed);
}

/* ─── dark palette ─────────────────────────────────────────── */
[data-theme="dark"] {
  --bg:         #0a0a0b;
  --surface:    #16161a;
  --surface-1:  #1a1a1f;
  --surface-2:  #1c1c22;
  --border:     #232329;
  --border-2:   #2c2c34;

  --ink-0: #f4f4f5; --ink-1: #c8c8cf; --ink-2: #8a8a93;
  --ink-3: #5a5a63; --ink-4: #3d3d45;

  --link: #6ab0ff; --link-hov: #8cc1ff;
  --accent: #4a9eff; --accent-bg: #14202e;
  --brand:  #e03131;

  --ok:   #6fdb6f; --ok-bg:   #16261a;
  --warn: #ffcc44; --warn-bg: #251a00; --warn-bdr: #4a3a00;
  --err:  #ff7070; --err-bg:  #2a1818;
  --info: #6ab0ff; --info-bg: #14202e;

  --cat-commute:    #f0a050;  --cat-commute-bg:    #2a1f12;
  --cat-business:   #6fdb6f;  --cat-business-bg:   #14261a;
  --cat-personal:   #c8c8cf;  --cat-personal-bg:   #232329;
  --cat-medical:    #74b4ff;  --cat-medical-bg:    #14243a;
  --cat-robotaxi:   #c070f0;  --cat-robotaxi-bg:   #1f1228;
  --cat-charity:    #ffd266;  --cat-charity-bg:    #2a2410;
  --cat-untagged:   #ff7070;  --cat-untagged-bg:   #2a1818;
  --cat-rental:     #74b4ff;  --cat-rental-bg:     #14243a;
  --cat-mixed:      #c070f0;  --cat-mixed-bg:      #1f1228;
  --cat-inprog:     #6ab0ff;  --cat-inprog-bg:     #14202e;

  --rail-bg:        #111114;
  --rail-ink:       #8a8a93;
  --rail-ink-2:     #5a5a63;
  --rail-active-bg: #1c1c22;
  --rail-divider:   #232329;
  --rail-accent:    #e03131;

  --selected-bg:    #14202e;
  --selected-bar:   #4a9eff;
  --row-hover:      #1c1c22;

  --map-bg:         linear-gradient(135deg, #12131a 0%, #1a1c26 100%);
  --map-line:       #2c2c34;
  --map-water:      #1a2230;
  --map-route:      #4a9eff;
  --map-route-2:    #6fdb6f;
  --map-pin-start:  #f4f4f5;
  --map-pin-end:    #ffd266;
  --map-badge-bg:   rgba(22,22,26,0.95);

  --acct-grad: linear-gradient(135deg, #3a4658 0%, #1f2733 100%);
  --acct-fg:   #f4f4f5;

  --shadow-1:   0 1px 0 var(--border);
  --shadow-2:   0 2px 8px rgba(0,0,0,.45);
  --shadow-pop: 0 4px 14px rgba(0,0,0,.55);

  /* ── backward-compat aliases (existing pages reference these) ── */
  --bg-0:        var(--bg);
  --bg-1:        var(--surface);
  --bg-2:        var(--surface-2);
  --bg-3:        #1c1c22;
  --hairline:    var(--border);
  --hairline-2:  var(--border-2);

  --pos:         var(--ok);
  --pos-bg:      var(--ok-bg);
  --neg:         var(--err);
  --neg-bg:      var(--err-bg);

  --rental:      var(--cat-rental);
  --rental-bg:   var(--cat-rental-bg);
  --business:    var(--cat-business);
  --business-bg: var(--cat-business-bg);
  --commute:     var(--cat-commute);
  --commute-bg:  var(--cat-commute-bg);
  --medical:     var(--cat-medical);
  --robotaxi:    var(--cat-robotaxi);
  --robotaxi-bg: var(--cat-robotaxi-bg);
  --charity:     var(--cat-charity);
  --charity-bg:  var(--cat-charity-bg);
  --untagged:    var(--cat-untagged);
  --in-prog:     var(--cat-inprog);
  --in-prog-bg:  var(--cat-inprog-bg);
  --mixed:       var(--cat-mixed);
}

/* The single source of brand accent — kept fixed across themes for the
   nav underline, sparkline overlays, and bolt glyph. Pages that should
   theme-respond use var(--accent) instead. */
:root, [data-theme="light"], [data-theme="dark"] {
  --brand-red: #e03131;
}

/* ─── reset ────────────────────────────────────────────── */
* { box-sizing: border-box; margin: 0; padding: 0; }
html, body {
  font-family: var(--font-sans);
  background: var(--bg-0);
  color: var(--ink-1);
  min-height: 100vh;
  -webkit-font-smoothing: antialiased;
  font-feature-settings: 'ss01', 'cv11';
}
.num  { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.mono { font-family: var(--font-mono); }
a { color: inherit; }

/* ─── top nav ──────────────────────────────────────────── */
nav {
  background: var(--bg-1);
  border-bottom: 1px solid var(--hairline);
  padding: 0 1.25rem;
  display: flex;
  align-items: center;
  gap: 1.5rem;
  height: var(--nav-height);
  /* Always-visible top nav site-wide. Sticky (not fixed) so it still
     participates in normal flow — page content scrolls underneath while
     the bar pins to the top. The map-layout column heights subtract
     --nav-height so the map + replay panel always fit on screen below
     it without producing a second scroll bar. Tune --nav-height in
     :root and every map page updates together. */
  position: sticky;
  top: 0;
  z-index: 900;
}
nav .brand {
  font-weight: 700;
  font-size: 0.95rem;
  color: var(--ink-0);
  text-decoration: none;
  letter-spacing: -0.01em;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
nav .brand .bolt { color: var(--brand-red); font-size: 1.05rem; }
nav a {
  color: var(--ink-2);
  text-decoration: none;
  font-size: 0.82rem;
  font-weight: 500;
  padding: 14px 0;
  height: 48px;
  border-bottom: 1.5px solid transparent;
  transition: color .12s, border-color .12s;
}
nav a:hover { color: var(--ink-0); }
nav a.active { color: var(--ink-0); border-bottom-color: var(--accent); }
nav .spacer { flex: 1; }
nav .ts {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  color: var(--ink-3);
  letter-spacing: 0.02em;
}
nav .ts::before {
  content: '●';
  color: var(--pos);
  margin-right: 6px;
  font-size: 0.6rem;
  vertical-align: middle;
}
.nav-badge {
  background: var(--brand-red);
  color: #fff;
  border-radius: 3px;
  padding: 1px 6px;
  font-family: var(--font-mono);
  font-size: 0.6rem;
  margin-left: 5px;
  font-weight: 600;
}

/* ─── layout ───────────────────────────────────────────── */
.container {
  margin: 0 auto;
  padding: 1.25rem 1.25rem 3rem;
  /* No max-width cap: pages run edge-to-edge so wide screens don't show
     large empty gutters on either side. Map+data pages already use the
     .dp-map-layout 33%/67% grid; non-map pages rely on natural content
     widths + the container's horizontal padding for breathing room. */
}

.page-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin: 0.5rem 0 1.25rem;
  padding-bottom: 1rem;
  border-bottom: 1px solid var(--hairline);
  gap: 1rem;
  flex-wrap: wrap;
}
.page-header h1 {
  font-size: 1.5rem;
  font-weight: 600;
  color: var(--ink-0);
  letter-spacing: -0.015em;
}
.page-header .meta {
  display: flex;
  gap: 1.5rem;
  align-items: baseline;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  color: var(--ink-3);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.page-header .meta b { color: var(--ink-1); font-weight: 500; }
.page-header .meta > span + span::before {
  content: '';
  display: inline-block;
  width: 1px; height: 9px;
  background: var(--ink-4);
  margin-right: 1.5rem;
  vertical-align: middle;
}

.section-head {
  display: flex;
  align-items: baseline;
  gap: 0.85rem;
  margin: 1.75rem 0 0.85rem;
  padding-bottom: 0.55rem;
  border-bottom: 1px solid var(--hairline);
  flex-wrap: wrap;
}
.section-head .vname {
  font-size: 1.05rem;
  font-weight: 600;
  color: var(--ink-0);
  letter-spacing: -0.01em;
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
.section-head .vname .bolt { color: var(--brand-red); }
.section-head .vmeta {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  color: var(--ink-3);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.section-head .pills { margin-left: auto; display: flex; gap: 0.4rem; flex-wrap: wrap; }

/* ─── cards + grids ────────────────────────────────────── */
.card {
  background: var(--bg-1);
  border: 1px solid var(--hairline);
  border-radius: 6px;
  padding: 1.1rem 1.15rem;
  transition: border-color .12s, background .12s;
}
.card-title {
  font-family: var(--font-mono);
  font-size: 0.66rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--ink-3);
  margin-bottom: 0.85rem;
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.grid { display: grid; gap: 0.875rem; }
.grid-2 { grid-template-columns: repeat(2, 1fr); }
.grid-3 { grid-template-columns: repeat(3, 1fr); }
.grid-4 { grid-template-columns: repeat(4, 1fr); }

/* ─── stat cards ───────────────────────────────────────── */
.stat-card { position: relative; overflow: hidden; }
.stat-card .accent-bar {
  position: absolute; top: 0; left: 0;
  height: 2px; width: 24px;
  background: var(--ink-3);
  transition: width .25s ease;
}
.stat-card[data-tone="primary"]  .accent-bar { background: var(--ink-1); }
.stat-card[data-tone="rental"]   .accent-bar { background: var(--rental); }
.stat-card[data-tone="business"] .accent-bar { background: var(--business); }
.stat-card[data-tone="commute"]  .accent-bar { background: var(--commute); }
.stat-card:hover .accent-bar { width: 100%; }

.stat-row { display: flex; align-items: baseline; gap: 0.5rem; }
.stat-value {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 1.95rem;
  font-weight: 500;
  line-height: 1;
  color: var(--ink-0);
  letter-spacing: -0.02em;
}
.stat-card[data-tone="rental"]   .stat-value { color: var(--rental); }
.stat-card[data-tone="business"] .stat-value { color: var(--business); }
.stat-card[data-tone="commute"]  .stat-value { color: var(--commute); }
.stat-unit {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  color: var(--ink-3);
  text-transform: lowercase;
  letter-spacing: 0.04em;
}
.stat-delta {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 0.7rem;
  padding: 1px 6px;
  border-radius: 3px;
  margin-left: auto;
}
.stat-delta.pos  { background: var(--pos-bg); color: var(--pos); }
.stat-delta.neg  { background: var(--neg-bg); color: var(--neg); }
.stat-delta.flat { background: var(--bg-3);   color: var(--ink-3); }

.stat-label {
  font-size: 0.78rem;
  color: var(--ink-2);
  margin-top: 0.6rem;
  letter-spacing: 0.005em;
}
.stat-sub {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  color: var(--ink-3);
  margin-top: 2px;
  font-variant-numeric: tabular-nums;
}
.spark-wrap { margin-top: 0.8rem; height: 38px; position: relative; }
.spark-wrap canvas { width: 100%; height: 100%; display: block; }
.spark-axis {
  position: absolute; bottom: -14px; left: 0; right: 0;
  display: flex; justify-content: space-between;
  font-family: var(--font-mono);
  font-size: 0.6rem;
  color: var(--ink-4);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

/* ─── badges + pills ───────────────────────────────────── */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 7px;
  border-radius: 3px;
  font-family: var(--font-mono);
  font-size: 0.65rem;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.badge::before {
  content: '';
  width: 5px; height: 5px;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.9;
}
.badge-rental_property { background: var(--rental-bg);   color: var(--rental); }
.badge-business        { background: var(--business-bg); color: var(--business); }
.badge-personal        { background: var(--bg-3);        color: var(--ink-2); }
.badge-commuting       { background: var(--commute-bg);  color: var(--commute); }
.badge-medical         { background: var(--rental-bg);   color: var(--medical); }
.badge-robotaxi        { background: var(--robotaxi-bg); color: var(--robotaxi); }
.badge-charity         { background: var(--charity-bg);  color: var(--charity); }
.badge-untagged        { background: var(--neg-bg);      color: var(--untagged); }
.badge-in_progress     { background: var(--in-prog-bg);  color: var(--in-prog); }
.badge-in_progress::before { animation: dp-pulse 1.4s ease-in-out infinite; }
.badge-mixed           { background: var(--robotaxi-bg); color: var(--mixed); }
@keyframes dp-pulse { 0%,100% { opacity: 0.4; } 50% { opacity: 1; } }

.pill-meta {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  background: var(--bg-2);
  border: 1px solid var(--hairline);
  border-radius: 3px;
  padding: 2px 7px;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}
.pill-meta b { color: var(--ink-0); font-weight: 500; }
.pill-meta.rental   { background: var(--rental-bg);   color: var(--rental);   border-color: transparent; }
.pill-meta.commute  { background: var(--commute-bg);  color: var(--commute);  border-color: transparent; }
.pill-meta.business { background: var(--business-bg); color: var(--business); border-color: transparent; }

/* ─── alerts ───────────────────────────────────────────── */
.alert {
  padding: 0.7rem 0.95rem;
  border-radius: 5px;
  font-size: 0.825rem;
  margin-bottom: 1rem;
  display: flex;
  align-items: center;
  gap: 0.6rem;
}
.alert-warn {
  background: var(--warn-bg);
  border: 1px solid var(--warn-bdr);
  color: var(--warn);
}

/* Toggle target for the "hide GPS dots" button in the replay panel.
   drawRawWaypoints stamps `className: 'dp-raw-dot'` on every circleMarker
   so a single body class hides all of them across every map on the page.
   Pref persists under localStorage `dp.hideRawDots`. */
body.dp-hide-raw-dots .leaflet-overlay-pane path.dp-raw-dot,
body.dp-hide-raw-dots .leaflet-marker-pane path.dp-raw-dot {
  display: none !important;
}

/* Interactive GPS dots — when the trip/journey page wires an onDotClick
   callback, drawRawWaypoints opts the markers into pointer events. The
   cursor cue + hover bump tell the user the dot is actionable.
   Leaflet renders circleMarkers as <path> inside the SVG overlay pane.
   We bump stroke-width on hover so the dot LOOKS bigger without needing
   to animate the SVG `r` attribute (which Safari doesn't transition).
   The clickTolerance on the SVG renderer adds ~8px of slop so the
   tap target is generous on touch even at 4px visual radius. */
.leaflet-overlay-pane path.dp-raw-dot,
.leaflet-interactive.dp-raw-dot {
  cursor: pointer;
  transition: stroke-width 80ms ease-out;
}
.leaflet-overlay-pane path.dp-raw-dot:hover,
.leaflet-interactive.dp-raw-dot:hover {
  stroke-width: 6px;
  stroke-opacity: 0.5;
}

/* Stationary-stop candidate dot — a qualifying GPS dot (>60s stationary
   in Drive) renders as a yellow diamond instead of a circle (see
   tagStationaryStops / drawRawWaypoints). It's a real interactive marker
   so clicking it opens the inspector / drop-stop flow like any dot. The
   marker pane sits above the dots, so no overlay-click issue. */
.dp-stationary-dot { cursor: pointer; }

/* Stream dot inspector — click a GPS dot to see the Pub/Sub package. */
.dp-dot-inspector-popover {
  position: fixed;
  z-index: 2500;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: var(--shadow-pop, 0 8px 24px rgba(0,0,0,.45));
  font-size: 12px;
  color: var(--ink-1);
  overflow-y: auto;
  overflow-x: hidden;
}
.dp-dot-inspector { padding: 10px 12px 12px; }
.dp-dot-inspector-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 8px;
  font-size: 13px;
}
.dp-dot-inspector-close {
  border: none;
  background: transparent;
  color: var(--ink-3);
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  padding: 0 4px;
}
.dp-dot-inspector-timing .hero {
  font-size: 14px;
  font-weight: 600;
  margin-bottom: 4px;
}
.dp-dot-inspector-timing .hero-val {
  color: var(--accent, #74b4ff);
}
.dp-dot-inspector-timing .sub,
.dp-dot-inspector .muted {
  color: var(--ink-3);
  font-size: 11px;
  line-height: 1.4;
}
.dp-dot-inspector-summary {
  margin: 8px 0;
  padding: 8px;
  border-radius: 6px;
  background: var(--surface-2, rgba(255,255,255,.04));
  border: 1px solid var(--border);
  line-height: 1.45;
}
.dp-dot-inspector-summary .lbl,
.dp-dot-inspector-pkg .lbl {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--ink-3);
  margin-bottom: 4px;
}
.dp-dot-inspector-table {
  width: 100%;
  border-collapse: collapse;
  margin-top: 4px;
}
.dp-dot-inspector-table td {
  padding: 3px 0;
  vertical-align: top;
  border-top: 1px solid var(--border);
}
.dp-dot-inspector-table tr:first-child td { border-top: none; }
.dp-dot-inspector-table .k {
  width: 38%;
  color: var(--ink-3);
  padding-right: 8px;
}
.dp-dot-inspector-table .v {
  font-family: var(--mono, ui-monospace, monospace);
  font-size: 11px;
  word-break: break-word;
}
.dp-dot-inspector-stop {
  display: block;
  width: 100%;
  margin-top: 10px;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: transparent;
  color: var(--ink-1);
  cursor: pointer;
  font: inherit;
  font-size: 12px;
  text-align: left;
}
.dp-dot-inspector-stop:hover {
  background: var(--surface-2, rgba(255,255,255,.04));
}

/* Stop pins. Rendered via L.divIcon by DriveProofMap.drawStopPins.
   Three visual classes:
     - dp-stop-pin-pending  — diamond, orange hollow (auto-detected, awaiting user)
     - dp-stop-pin-confirmed — diamond, yellow solid (auto-detected, user-confirmed)
     - dp-stop-pin-manual   — octagonal stop-sign (user-defined, ALWAYS confirmed).
                              Red fill + white border. Visual cue: "you stopped here."
   Plus dp-stop-pin-dismissed for translucent rendering when "show hidden" is on. */
.dp-stop-pin {
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: auto;
}
.dp-stop-pin-inner {
  width: 12px;
  height: 12px;
  transform: rotate(45deg);
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.5);
  cursor: pointer;
}
.dp-stop-pin-pending .dp-stop-pin-inner {
  background: transparent;
  border: 2px solid #f0b232;        /* warn-orange — matches inferred-leg style */
}
.dp-stop-pin-confirmed .dp-stop-pin-inner {
  background: #ffd266;              /* charity-yellow — distinct from leg colors */
  border: 1.5px solid #4a3a10;
}
/* Manual stops: real stop-sign octagon — flat-top, red with white border.
   The clip-path can't draw a CSS border, so we render a white parent box
   (the "border") with the same octagonal clip-path, then absolutely-position
   a slightly-inset red ::after that's also clip-path'd. The 1.5px gap
   between the two octagon edges is the visible white ring. */
.dp-stop-pin-manual .dp-stop-pin-inner {
  width: 16px;
  height: 16px;
  transform: none;
  background: #fff;
  clip-path: polygon(30% 0%, 70% 0%, 100% 30%, 100% 70%, 70% 100%, 30% 100%, 0% 70%, 0% 30%);
  box-shadow: none;
  position: relative;
}
.dp-stop-pin-manual .dp-stop-pin-inner::after {
  content: '';
  position: absolute;
  inset: 1.5px;
  background: #e03131;
  clip-path: polygon(30% 0%, 70% 0%, 100% 30%, 100% 70%, 70% 100%, 30% 100%, 0% 70%, 0% 30%);
}
.dp-stop-pin:hover .dp-stop-pin-inner {
  filter: brightness(1.2);
}
.dp-stop-pin-dismissed {
  opacity: 0.35;
}
.dp-stop-pin-dismissed .dp-stop-pin-inner {
  filter: grayscale(0.4);
}

/* Mobile / touch — bump dot + pin hit targets and confirm-popup item
   height. Leaflet's circleMarker hit area = visible radius; bumping the
   rendered radius is the simplest tap-friendliness lever.
   `pointer: coarse` matches every touch device (phones, tablets) without
   penalizing desktop. */
@media (pointer: coarse) {
  .leaflet-overlay-pane path.dp-raw-dot,
  .leaflet-interactive.dp-raw-dot {
    /* SVG paths don't honor padding; rely on bumping circleMarker radius
       in the page-level code (passes opts.radius). This rule is the
       hover affordance hook for future enhancement. */
    cursor: pointer;
  }
  .dp-stop-pin-inner {
    width: 16px;
    height: 16px;
  }
  .inline-popup-item {
    min-height: 44px;
    display: flex;
    align-items: center;
  }
}
.alert-warn::before {
  content: '';
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--warn);
  box-shadow: 0 0 8px var(--warn);
}
.alert a {
  color: var(--warn);
  font-weight: 600;
  text-decoration: none;
  border-bottom: 1px solid var(--warn-bdr);
  padding-bottom: 1px;
}
.alert a:hover { border-bottom-color: var(--warn); }

/* ─── tables ───────────────────────────────────────────── */
table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.82rem;
  font-variant-numeric: tabular-nums;
}
thead th { position: sticky; top: 0; background: var(--bg-1); z-index: 1; }
th {
  text-align: left;
  color: var(--ink-3);
  font-family: var(--font-mono);
  font-size: 0.62rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-weight: 500;
  padding: 0.6rem 0.65rem;
  border-bottom: 1px solid var(--hairline);
}
td {
  padding: 0.65rem;
  border-bottom: 1px solid var(--bg-2);
  color: var(--ink-1);
  vertical-align: middle;
}
td strong { color: var(--ink-0); font-weight: 500; }
tbody tr { transition: background .08s; }
tr:last-child td { border-bottom: none; }
tr:hover td { background: var(--bg-2); }
tr:hover td:first-child { box-shadow: inset 2px 0 0 var(--accent); }
tr.journey-summary td {
  background: linear-gradient(90deg, rgba(106,176,255,0.06), transparent 30%);
  border-left-color: var(--in-prog);
}
tr.journey-summary td:first-child {
  box-shadow: inset 3px 0 0 var(--in-prog);
}
tr.journey-summary:hover td {
  background: linear-gradient(90deg, rgba(106,176,255,0.10), var(--bg-2) 40%);
}
tr.journey-summary:hover td:first-child {
  box-shadow: inset 3px 0 0 var(--in-prog);
}

/* ─── buttons ──────────────────────────────────────────── */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  border-radius: 4px;
  font-size: 0.82rem;
  font-weight: 500;
  cursor: pointer;
  border: 1px solid transparent;
  text-decoration: none;
  font-family: var(--font-sans);
  transition: background .1s, border-color .1s, color .1s;
}
.btn-ghost { background: transparent; color: var(--ink-1); border-color: var(--hairline-2); }
.btn-ghost:hover { background: var(--bg-2); border-color: var(--ink-3); color: var(--ink-0); }
.btn-primary {
  background: var(--accent); color: #fff; border-color: var(--accent);
}
.btn-primary:hover { background: var(--link-hov); border-color: var(--link-hov); }
.btn-sm { padding: 4px 10px; font-size: 0.76rem; }
.btn-lg { padding: 9px 18px; font-size: 0.9rem; }

/* ─── form controls ────────────────────────────────────── */
input[type="text"], input[type="email"], input[type="password"],
input[type="number"], input[type="date"], input[type="search"],
select, textarea {
  background: var(--bg-2);
  border: 1px solid var(--hairline-2);
  border-radius: 4px;
  padding: 7px 10px;
  color: var(--ink-0);
  font-family: var(--font-sans);
  font-size: 0.85rem;
  outline: none;
  transition: border-color .12s, background .12s;
}
input:focus, select:focus, textarea:focus {
  border-color: var(--ink-2);
  background: var(--bg-1);
}
label {
  font-family: var(--font-mono);
  font-size: 0.66rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--ink-3);
  display: block;
  margin-bottom: 0.4rem;
}

/* ─── helpers ──────────────────────────────────────────── */
.text-muted { color: var(--ink-3); }
.text-pos { color: var(--pos); }
.text-neg { color: var(--neg); }
.text-sm { font-size: 0.8rem; }
.text-xs { font-size: 0.72rem; }
.mt-1 { margin-top: 0.5rem; }
.mt-2 { margin-top: 1rem; }
.mt-3 { margin-top: 1.5rem; }
.mt-4 { margin-top: 2rem; }
.mb-1 { margin-bottom: 0.5rem; }
.mb-2 { margin-bottom: 1rem; }
.mb-3 { margin-bottom: 1.5rem; }
.flex { display: flex; }
.flex-between { display: flex; align-items: center; justify-content: space-between; }
.gap-1 { gap: 0.5rem; }
.gap-2 { gap: 1rem; }

/* ─── empty / zen states ───────────────────────────────── */
.empty-zen { text-align: center; padding: 2.5rem 1rem; color: var(--ink-3); }
.empty-zen .glyph { font-size: 2.4rem; opacity: 0.3; }
.empty-zen .msg {
  margin-top: 0.65rem;
  font-size: 0.875rem;
  max-width: 28rem;
  margin-left: auto;
  margin-right: auto;
  line-height: 1.5;
}

/* ─── chips, tags, day-rail ────────────────────────────── */
.driver-chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px; height: 24px;
  border-radius: 50%;
  color: #fff;
  font-size: 0.62rem;
  font-weight: 600;
  text-decoration: none;
  letter-spacing: 0.02em;
}
.auto-tag {
  font-family: var(--font-mono);
  font-size: 0.6rem;
  color: var(--ink-3);
  margin-left: 4px;
  background: var(--bg-2);
  border: 1px solid var(--hairline);
  border-radius: 3px;
  padding: 1px 5px;
  vertical-align: middle;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.leg-tag {
  margin-left: 6px;
  font-family: var(--font-mono);
  font-size: 0.6rem;
  color: var(--in-prog);
  background: var(--in-prog-bg);
  border-radius: 3px;
  padding: 1px 6px;
  vertical-align: middle;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.day-rail { display: flex; flex-direction: column; gap: 2px; }
.day-link {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 7px 10px;
  border-radius: 4px;
  text-decoration: none;
  color: var(--ink-1);
  font-size: 0.8rem;
  transition: background .1s;
  font-variant-numeric: tabular-nums;
  font-family: var(--font-mono);
}
.day-link:hover { background: var(--bg-2); }
.day-link:hover span:last-child { color: var(--accent); transform: translateX(2px); }
.day-link span:last-child { color: var(--ink-4); transition: color .1s, transform .1s; }

/* ─── calendar (per-vehicle dashboard card) ────────────── */
.calendar-card { padding: 0.85rem 0.95rem 0.95rem; }
.cal-head { display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.7rem; }
.cal-title {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--ink-1);
  flex: 1;
}
.cal-title b { color: var(--ink-0); font-weight: 600; }
.cal-nav {
  display: inline-flex;
  align-items: center;
  width: 22px; height: 22px;
  justify-content: center;
  border: 1px solid var(--hairline-2);
  border-radius: 3px;
  color: var(--ink-2);
  cursor: pointer;
  background: transparent;
  font-family: inherit;
  font-size: 0.8rem;
  line-height: 1;
  transition: all .1s;
}
.cal-nav:hover { border-color: var(--ink-2); color: var(--ink-0); background: var(--bg-2); }
.cal-nav:disabled { opacity: 0.3; cursor: not-allowed; }
.cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
.cal-dow {
  font-family: var(--font-mono);
  font-size: 0.6rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--ink-4);
  text-align: center;
  padding: 4px 0 6px;
}
.cal-cell {
  aspect-ratio: 1 / 1;
  border-radius: 3px;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  color: var(--ink-3);
  display: flex;
  align-items: center;
  justify-content: center;
  text-decoration: none;
  position: relative;
  font-variant-numeric: tabular-nums;
  background: transparent;
  transition: background .1s, color .1s;
}
.cal-cell.outside { color: var(--ink-4); opacity: 0.35; }
.cal-cell.today {
  box-shadow: inset 0 0 0 1px var(--accent);
  color: var(--ink-0);
}
.cal-cell.has-trips { color: var(--ink-0); cursor: pointer; }
.cal-cell.has-trips:hover { background: var(--bg-3) !important; }
.cal-cell.selected {
  box-shadow: inset 0 0 0 2px var(--accent);
  background: var(--accent);
  color: #fff !important;
}
.cal-cell .dot {
  position: absolute; bottom: 3px; left: 50%;
  transform: translateX(-50%);
  display: flex; gap: 1.5px;
}
.cal-cell .dot i {
  width: 3px; height: 3px;
  border-radius: 50%;
  background: var(--ink-2);
  display: block;
}
.cal-foot {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: 0.7rem;
  padding-top: 0.6rem;
  border-top: 1px solid var(--hairline);
  font-family: var(--font-mono);
  font-size: 0.65rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-3);
}
.cal-foot .legend { display: inline-flex; align-items: center; gap: 4px; }
.cal-foot .swatch { display: inline-block; width: 10px; height: 10px; border-radius: 2px; }
.cal-foot b { color: var(--ink-0); font-weight: 500; }

/* ─── responsive ───────────────────────────────────────── */
.hide-mobile {}
@media (max-width: 900px) {
  .grid-4 { grid-template-columns: repeat(2, 1fr); }
  .grid-3 { grid-template-columns: 1fr; }
  .grid-2 { grid-template-columns: 1fr; }
  .hide-mobile { display: none; }
  nav { gap: 1rem; overflow-x: auto; }
  nav a { white-space: nowrap; }
  .page-header { flex-direction: column; align-items: flex-start; gap: 0.5rem; }
}

/* ============================================================
   Shared map-page layout — data column + map column.
   Used by trip.html, journey.html, day.html (any page that
   pairs a stats/list panel with a Leaflet map). Activated at
   ≥1100px; collapses to single-column below. Side-toggle
   (`.dp-map-layout-flipped`) swaps which column sits where —
   the choice is persisted under localStorage `dp.mapSide`
   site-wide via DriveProofMap.applyMapSide.

   Width split: data column is min(360px, 33%); map gets the
   rest. Tune both knobs in this one rule and every map page
   updates together — that's the point of centralizing it.
   ============================================================ */
@media (min-width: 1100px) {
  .dp-map-layout {
    display: grid;
    grid-template-columns: minmax(360px, 33%) 1fr;
    gap: 1.5rem;
    align-items: start;
    width: 100%;
  }
  /* Flipped: map on the left, data on the right. Grid `order`
     swap (not flex-direction) so the source DOM order is unchanged. */
  .dp-map-layout.dp-map-layout-flipped {
    grid-template-columns: 1fr minmax(360px, 33%);
  }
  .dp-map-layout.dp-map-layout-flipped > .dp-map-layout-data { order: 2; }
  .dp-map-layout.dp-map-layout-flipped > .dp-map-layout-map  { order: 1; }

  .dp-map-layout-data {
    /* Data column scrolls internally. Height fills the viewport below
       the sticky nav (var --nav-height) with a small gutter for the
       page's container padding. */
    height: calc(100vh - var(--nav-height) - var(--map-col-gutter) * 2);
    overflow-y: auto;
    padding-right: 0.5rem;
  }
  .dp-map-layout-data::-webkit-scrollbar { width: 8px; }
  .dp-map-layout-data::-webkit-scrollbar-thumb {
    background: var(--border-2); border-radius: 4px;
  }
  /* Map column is a fixed-height flex column. The MAP stretches to fill
     leftover space (`flex: 1 1 auto`); the replay panel + any legend /
     hint text under it stay at their natural height and are ALWAYS
     visible at the bottom. Without this, the map ate the full column
     height and pushed the replay button off-screen — chris's report. */
  .dp-map-layout-map {
    /* Sticks just below the nav so map + replay panel are always on
       screen even as the data column scrolls. Height matches the data
       column so both panes line up. */
    position: sticky;
    top: calc(var(--nav-height) + var(--map-col-gutter));
    height: calc(100vh - var(--nav-height) - var(--map-col-gutter) * 2);
    min-height: 520px;
    display: flex;
    flex-direction: column;
  }
  .dp-map-layout-map .map-card {
    padding: 0.5rem;
    margin-bottom: 0;
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    min-height: 0;
  }
  /* Inside a .map-card wrapper: #map flexes, replay sits underneath. */
  .dp-map-layout-map .map-card > #map,
  .dp-map-layout-map .map-card > [data-dp-map],
  .dp-map-layout-map .map-card > .dp-map {
    flex: 1 1 auto;
    min-height: 0;
    width: 100%;
  }
  .dp-map-layout-map .map-card > #replay-panel-host,
  .dp-map-layout-map .map-card > [data-dp-replay-host] {
    flex: 0 0 auto;
    margin-top: 0.5rem;
  }
  /* For pages where #map is a direct child of .dp-map-layout-map
     (day.html, trip.html's renderMap return) — same idea but applied
     one level higher. */
  .dp-map-layout-map > #map,
  .dp-map-layout-map > [data-dp-map],
  .dp-map-layout-map > .dp-map {
    flex: 1 1 auto;
    min-height: 0;
    width: 100%;
  }
  .dp-map-layout-map > #day-replay-host,
  .dp-map-layout-map > #replay-panel-host,
  .dp-map-layout-map > [data-dp-replay-host] {
    flex: 0 0 auto;
    margin-top: 0.5rem;
  }
}

/* ============================================================
   Portal primitives — new design-system shell + components.
   Adopted incrementally as pages migrate from <nav> to .shell.
   Existing pages keep working via legacy `nav` + `.container`
   styles above; these primitives are scoped to new wrappers
   (.shell, .panel, .props, .toolbar, .tabs, .stat-strip, etc.)
   and don't override anything legacy.
   ============================================================ */

/* shell + rail + topbar (page chrome) */
.shell { display: grid; grid-template-columns: var(--rail-w) 1fr; min-height: 100vh; }
.main { display: flex; flex-direction: column; min-width: 0; }

.rail {
  background: var(--rail-bg); color: var(--rail-ink);
  display: flex; flex-direction: column; padding: 8px 0;
  position: sticky; top: 0; height: 100vh;
}
.rail .logo {
  width: var(--rail-w); height: 48px;
  display: flex; align-items: center; justify-content: center;
  color: var(--rail-accent); font-size: 1.2rem; font-weight: 700;
  border-bottom: 1px solid var(--rail-divider);
  margin-bottom: 8px;
  text-decoration: none;
}
.rail-btn {
  width: var(--rail-w); height: 48px;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 2px;
  color: var(--rail-ink-2);
  text-decoration: none; font-size: 9px;
  cursor: pointer;
  background: transparent; border: 0;
  transition: background .12s, color .12s;
  position: relative;
}
.rail-btn:hover { background: var(--rail-active-bg); color: var(--rail-ink); text-decoration: none; }
.rail-btn.active { color: #fff; background: var(--rail-active-bg); }
.rail-btn.active::before {
  content: ''; position: absolute; left: 0; top: 8px; bottom: 8px;
  width: 3px; background: var(--rail-accent); border-radius: 0 2px 2px 0;
}
.rail-btn svg { width: 18px; height: 18px; opacity: 0.9; }
.rail .spacer { flex: 1; }

.topbar {
  height: var(--topbar-h);
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  display: flex; align-items: center;
  padding: 0 16px; gap: 12px;
  position: sticky; top: 0; z-index: 5;
}
.topbar .search {
  width: 320px; height: 26px;
  background: var(--bg); border: 1px solid var(--border);
  border-radius: var(--r-1);
  padding: 0 8px 0 28px;
  font-family: inherit; font-size: var(--fs-sm);
  color: var(--ink-1); outline: none;
  background-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%238a8a90' stroke-width='1.5'%3E%3Ccircle cx='7' cy='7' r='5'/%3E%3Cpath d='M11 11l3 3'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: 8px center; background-size: 12px;
}
.topbar .search:focus { border-color: var(--accent); }
.topbar .search::placeholder { color: var(--ink-3); }
.topbar .spacer { flex: 1; }
.topbar .top-action {
  height: 26px; padding: 0 10px;
  font-size: var(--fs-sm); color: var(--ink-2);
  background: transparent; border: 1px solid transparent;
  border-radius: var(--r-1); cursor: pointer;
  display: inline-flex; align-items: center; gap: 6px;
}
.topbar .top-action:hover { background: var(--bg); }
.topbar .acct {
  width: 28px; height: 28px;
  background: var(--acct-grad); color: var(--acct-fg);
  font-size: var(--fs-xs); font-weight: 600;
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  cursor: pointer;
}

/* theme toggle (sun/moon pill) */
.theme-toggle {
  display: inline-flex;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 2px; height: 26px;
}
.theme-toggle button {
  width: 32px; height: 20px;
  background: transparent; border: none;
  border-radius: 10px;
  color: var(--ink-3); cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  transition: background .12s, color .12s;
}
.theme-toggle button:hover { color: var(--ink-1); }
.theme-toggle button.active {
  background: var(--surface); color: var(--ink-0);
  box-shadow: 0 1px 2px rgba(0,0,0,0.15);
}
.theme-toggle button svg { width: 13px; height: 13px; }

/* breadcrumb */
.crumb-bar {
  background: var(--surface);
  padding: 8px 24px;
  border-bottom: 1px solid var(--border);
  font-size: var(--fs-sm); color: var(--ink-2);
  display: flex; align-items: center; gap: 6px;
}
.crumb-bar a { color: var(--link); }
.crumb-bar .sep { color: var(--ink-4); }
.crumb-bar .here { color: var(--ink-1); font-weight: 500; }

/* page header (new) */
.pgh {
  background: var(--surface);
  padding: 14px 24px 0;
  border-bottom: 1px solid var(--border);
}
.pgh-top { display: flex; align-items: flex-start; gap: 16px; }
.pgh-icon {
  width: 36px; height: 36px;
  background: var(--accent-bg); color: var(--accent);
  border-radius: var(--r-2);
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}
.pgh-title-block { flex: 1; min-width: 0; }
.pgh h1 {
  font-size: var(--fs-xl); font-weight: 600;
  color: var(--ink-0); letter-spacing: -0.005em;
  margin-bottom: 2px;
}
.pgh-sub {
  font-size: var(--fs-sm); color: var(--ink-3);
  display: flex; gap: 12px; align-items: center; flex-wrap: wrap;
}
.pgh-sub .sep { color: var(--ink-4); }
.pgh-sub .mono { color: var(--ink-2); }

/* toolbar (button group) — scoped class, does NOT touch legacy .btn */
.toolbar {
  display: flex; gap: 1px;
  margin-top: 14px;
  background: var(--border);
  border-radius: var(--r-1); padding: 1px;
  align-self: flex-start;
}
.toolbar button, .toolbar a {
  background: var(--surface);
  border: none; cursor: pointer;
  padding: 6px 11px;
  font-family: inherit; font-size: var(--fs-sm);
  color: var(--ink-1);
  display: inline-flex; align-items: center; gap: 6px;
  text-decoration: none;
}
.toolbar button:first-child, .toolbar a:first-child { border-radius: var(--r-1) 0 0 var(--r-1); }
.toolbar button:last-child,  .toolbar a:last-child  { border-radius: 0 var(--r-1) var(--r-1) 0; }
.toolbar button:hover, .toolbar a:hover {
  background: var(--accent-bg); color: var(--accent);
}
.toolbar .ico { width: 14px; height: 14px; opacity: 0.8; }
.toolbar .danger:hover { background: var(--err-bg); color: var(--err); }

/* tabs */
.tabs {
  display: flex; gap: 0;
  padding: 0 24px;
  margin-top: 14px;
  border-bottom: 1px solid var(--border);
  background: var(--surface);
}
.tabs a {
  padding: 9px 14px;
  font-size: var(--fs-md);
  color: var(--ink-2);
  text-decoration: none;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  transition: color .12s, border-color .12s;
}
.tabs a:hover { color: var(--ink-0); text-decoration: none; }
.tabs a.active {
  color: var(--accent);
  border-bottom-color: var(--accent);
  font-weight: 500;
}

/* content + grids */
.content {
  flex: 1;
  padding: 16px 24px 32px;
  overflow-y: auto;
}
.row-grid { display: grid; grid-template-columns: 1.4fr 1fr; gap: 16px; }
.row-grid-2-1 { display: grid; grid-template-columns: 2fr 1fr; gap: 16px; }
.row-grid-1-1 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }

/* panel (card) */
.panel {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-1);
  margin-bottom: 16px;
}
.panel-head {
  padding: 9px 14px;
  border-bottom: 1px solid var(--border);
  display: flex; align-items: center; gap: 10px;
}
.panel-head h2 {
  font-size: var(--fs-md); font-weight: 600;
  color: var(--ink-0); letter-spacing: -0.005em;
}
.panel-head .sub { font-size: var(--fs-xs); color: var(--ink-3); }
.panel-head .actions { margin-left: auto; display: flex; gap: 4px; }
.panel-head .actions a {
  font-size: var(--fs-xs); color: var(--link);
  padding: 2px 6px; border-radius: 2px;
}
.panel-head .actions a:hover { background: var(--accent-bg); text-decoration: none; }
.panel-body { padding: 12px 14px; }

/* properties (key/value grid) */
.props {
  display: grid; grid-template-columns: 140px 1fr;
  column-gap: 14px; row-gap: 6px;
  font-size: var(--fs-sm);
}
.props .k { color: var(--ink-3); padding: 4px 0; }
.props .v { color: var(--ink-1); padding: 4px 0; }
.props .v.mono { font-size: 11.5px; color: var(--ink-0); }
.props .v.link a { color: var(--link); }
.props .v code {
  background: var(--bg); padding: 1px 5px;
  border-radius: 2px; font-size: var(--fs-xs);
  border: 1px solid var(--border); color: var(--ink-1);
}

/* semantic pills (.pill is new — legacy class is .pill-meta, .badge-*) */
.pill {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 1px 7px;
  border-radius: 10px;
  font-size: var(--fs-xs); font-weight: 500;
  line-height: 1.5;
}
.pill::before {
  content: ''; width: 6px; height: 6px;
  border-radius: 50%; background: currentColor;
}
.pill.ok      { background: var(--ok-bg);   color: var(--ok); }
.pill.warn    { background: var(--warn-bg); color: var(--warn); }
.pill.err     { background: var(--err-bg);  color: var(--err); }
.pill.info    { background: var(--info-bg); color: var(--info); }
.pill.neutral { background: var(--bg);      color: var(--ink-2); }
.pill.cat-commute   { background: var(--cat-commute-bg);  color: var(--cat-commute); }
.pill.cat-business  { background: var(--cat-business-bg); color: var(--cat-business); }
.pill.cat-personal  { background: var(--cat-personal-bg); color: var(--cat-personal); }
.pill.cat-medical   { background: var(--cat-medical-bg);  color: var(--cat-medical); }
.pill.cat-robotaxi  { background: var(--cat-robotaxi-bg); color: var(--cat-robotaxi); }
.pill.cat-charity   { background: var(--cat-charity-bg);  color: var(--cat-charity); }
.pill.cat-untagged  { background: var(--cat-untagged-bg); color: var(--cat-untagged); }
.pill.cat-rental    { background: var(--cat-rental-bg);   color: var(--cat-rental); }
.pill.cat-mixed     { background: var(--cat-mixed-bg);    color: var(--cat-mixed); }
.pill.cat-inprog    { background: var(--cat-inprog-bg);   color: var(--cat-inprog); }

/* System-managed status pills (no manual editing) */
.pill.system-managed {
  opacity: 0.7;
  cursor: default;
}

/* stat-strip (new dense KPI bar; legacy is .stat-card) */
.stat-strip {
  display: grid; grid-template-columns: repeat(5, 1fr);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-1);
  margin-bottom: 16px;
  overflow: hidden;
}
.stat-strip > div {
  padding: 12px 16px;
  border-right: 1px solid var(--border);
}
.stat-strip > div:last-child { border-right: none; }
.stat-strip .l {
  font-size: var(--fs-xs); color: var(--ink-3);
  text-transform: uppercase; letter-spacing: 0.04em;
  margin-bottom: 4px;
}
.stat-strip .v {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: var(--fs-xl); font-weight: 500;
  color: var(--ink-0); letter-spacing: -0.01em; line-height: 1;
}
.stat-strip .v small {
  font-size: var(--fs-xs); color: var(--ink-3);
  margin-left: 2px; font-weight: 400;
}
.stat-strip .v .accent { color: var(--accent); }
.stat-strip .delta {
  font-size: var(--fs-xs); color: var(--ink-3); margin-top: 5px;
}
.stat-strip .delta.pos { color: var(--ok); }
.stat-strip .delta.neg { color: var(--err); }
.stat-strip .delta.warn { color: var(--warn); }
.stat-strip.cols-4 { grid-template-columns: repeat(4, 1fr); }
.stat-strip.cols-3 { grid-template-columns: repeat(3, 1fr); }

/* map-mini (placeholder card; real Leaflet maps drop in here) */
.map-mini {
  aspect-ratio: 16 / 8;
  background: var(--map-bg);
  position: relative; overflow: hidden;
  margin: -12px -14px 12px;
}
.map-mini.flat { margin: 0; border-radius: var(--r-1); }
.map-mini.tall { aspect-ratio: 4 / 5; }
.map-mini svg { position: absolute; inset: 0; width: 100%; height: 100%; }
.map-mini .badge {
  position: absolute; top: 8px; left: 10px;
  background: var(--map-badge-bg);
  border: 1px solid var(--border);
  padding: 3px 8px; font-size: var(--fs-xs);
  color: var(--ink-2); border-radius: 2px;
  font-family: var(--font-mono);
  backdrop-filter: blur(4px);
}

/* activity log */
.log { font-family: var(--font-mono); font-size: 11.5px; }
.log-row {
  display: grid; grid-template-columns: 130px 1fr auto;
  gap: 14px; padding: 6px 0;
  border-bottom: 1px solid var(--surface-2);
  align-items: baseline;
}
.log-row:last-child { border-bottom: none; }
.log-row .t { color: var(--ink-3); font-variant-numeric: tabular-nums; }
.log-row .m { color: var(--ink-1); }
.log-row .m code {
  background: var(--bg); padding: 1px 4px;
  border-radius: 2px; font-size: 10.5px;
  border: 1px solid var(--border); color: var(--ink-1);
}
.log-row .m a { color: var(--link); }
.log-row .u { color: var(--ink-3); font-size: var(--fs-xs); }

/* quick-action link */
.qa-link {
  display: flex; align-items: center; justify-content: space-between;
  padding: 8px 0; color: var(--link);
  border-bottom: 1px solid var(--surface-2);
}
.qa-link:last-child { border-bottom: none; }
.qa-link:hover { text-decoration: none; color: var(--link-hov); }
.qa-link .arrow { color: var(--ink-4); }

/* driver avatar */
.avatar {
  width: 28px; height: 28px;
  border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  color: #fff; font-size: var(--fs-xs); font-weight: 700;
  flex-shrink: 0;
}
.avatar.lg { width: 56px; height: 56px; font-size: var(--fs-xl); }
.avatar.sm { width: 22px; height: 22px; font-size: 10px; }

/* model-tag — compact vehicle chip, e.g. "Evee Y", "Jarvis 3" */
.model-tag {
  display: inline-block;
  padding: 1px 6px;
  margin-left: 6px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-1);
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 600;
  color: var(--ink-2);
  vertical-align: 1px;
  line-height: 1.5;
  letter-spacing: 0.02em;
}

/* segmented control */
.seg {
  display: inline-flex;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--r-1);
  padding: 1px;
  gap: 1px;
  align-self: center;
}
.seg button, .seg a {
  padding: 4px 10px;
  background: transparent;
  border: none;
  border-radius: 2px;
  color: var(--ink-2);
  cursor: pointer;
  font-family: inherit;
  font-size: var(--fs-xs);
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  line-height: 1.4;
}
.seg button:hover:not(.active), .seg a:hover:not(.active) {
  background: var(--surface);
  color: var(--ink-0);
}
.seg button.active, .seg a.active {
  background: var(--surface);
  color: var(--ink-0);
  font-weight: 500;
  box-shadow: 0 1px 2px rgba(0,0,0,0.15);
}
.seg button.pending, .seg a.pending {
  color: var(--ink-3);
  font-style: italic;
}
.seg .model-tag { margin-left: 2px; padding: 0 4px; }

/* form rows (settings) — scoped class, doesn't touch legacy label */
.form-row {
  display: grid; grid-template-columns: 220px 1fr;
  gap: 24px; padding: 18px 0;
  border-bottom: 1px solid var(--border);
  align-items: start;
}
.form-row:last-child { border-bottom: none; }
.form-row .label {
  font-family: var(--font-sans);
  font-size: var(--fs-md);
  text-transform: none;
  letter-spacing: normal;
  color: var(--ink-1);
  margin-bottom: 0;
  display: block;
}
.form-row .label h3 {
  font-size: var(--fs-md); font-weight: 600;
  color: var(--ink-0); margin-bottom: 4px;
}
.form-row .label p {
  font-size: var(--fs-sm); color: var(--ink-3); line-height: 1.45;
}
.form-row .control { font-size: var(--fs-sm); }

.radio-row {
  display: flex; gap: 8px; flex-wrap: wrap;
}
.radio-row label {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 8px 12px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-2); cursor: pointer;
  font-family: var(--font-sans);
  font-size: var(--fs-sm); color: var(--ink-1);
  text-transform: none; letter-spacing: normal;
  margin-bottom: 0;
  transition: border-color .12s, background .12s;
}
.radio-row label:hover { border-color: var(--border-2); }
.radio-row label.checked {
  background: var(--accent-bg); border-color: var(--accent);
  color: var(--accent);
}
.radio-row input { accent-color: var(--accent); }

/* empty state (new) — distinct from legacy .empty-zen */
.empty {
  text-align: center; padding: 48px 24px;
  color: var(--ink-3); font-size: var(--fs-sm);
}
.empty h3 { color: var(--ink-1); font-size: var(--fs-md); margin-bottom: 6px; }

/* alert / callout (new) — distinct from legacy .alert / .alert-warn */
.callout {
  display: flex; gap: 12px;
  padding: 12px 14px;
  background: var(--warn-bg); border: 1px solid var(--warn);
  border-left-width: 3px;
  border-radius: var(--r-1);
  margin-bottom: 16px;
  font-size: var(--fs-sm); color: var(--ink-1);
  align-items: center;
}
.callout.info { background: var(--info-bg); border-color: var(--info); }
.callout.err  { background: var(--err-bg);  border-color: var(--err); }
.callout .ico { color: var(--warn); flex-shrink: 0; }
.callout.info .ico { color: var(--info); }
.callout.err  .ico { color: var(--err); }
.callout strong { color: var(--ink-0); margin-right: 4px; }
.callout .cta { margin-left: auto; }

/* timeline (day view) */
.timeline {
  position: relative;
  padding-left: 80px;
}
.timeline::before {
  content: ''; position: absolute;
  left: 64px; top: 8px; bottom: 8px;
  width: 1px; background: var(--border);
}
.tl-row {
  position: relative; padding: 8px 0 12px;
  border-bottom: 1px dashed var(--surface-2);
}
.tl-row:last-child { border-bottom: none; }
.tl-row .tl-time {
  position: absolute; left: -80px; top: 10px;
  width: 70px; text-align: right;
  font-family: var(--font-mono); font-size: var(--fs-xs);
  color: var(--ink-3);
}
.tl-row .tl-dot {
  position: absolute; left: -22px; top: 13px;
  width: 12px; height: 12px;
  border-radius: 50%;
  background: var(--surface); border: 2px solid var(--accent);
}
.tl-row.parked .tl-dot { border-color: var(--ink-3); background: var(--bg); }
.tl-row.parked { opacity: 0.7; }
.tl-row .tl-title {
  font-size: var(--fs-md); color: var(--ink-0); font-weight: 500;
  margin-bottom: 2px;
}
.tl-row .tl-meta {
  font-size: var(--fs-xs); color: var(--ink-3);
  font-family: var(--font-mono);
}
.tl-row .tl-meta .pill { font-family: var(--font-sans); }

/* bar chart placeholder */
.bar-chart {
  display: flex; align-items: flex-end; gap: 6px;
  height: 120px; padding: 8px 0;
}
.bar-chart .bar {
  flex: 1;
  background: transparent;
  border-radius: 2px 2px 0 0;
  min-height: 4px;
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  opacity: 0.95;
}
.bar-chart .bar:hover { opacity: 1; }
.bar-chart .bar-stack {
  flex: 1;
  width: 100%;
  display: flex;
  flex-direction: column-reverse;
  border-radius: 2px 2px 0 0;
  overflow: hidden;
  min-height: 0;
}
.bar-chart .bar-seg { width: 100%; min-height: 0; }
.bar-chart .bar .lbl {
  position: absolute; bottom: -18px; left: 0; right: 0;
  text-align: center;
  font-size: 10px; color: var(--ink-3); font-family: var(--font-mono);
}
.bar-chart .bar.today .lbl { color: var(--accent); font-weight: 600; }
.bar-chart .bar.dim { background: var(--ink-4); opacity: 0.5; }
.bar-chart-wrap { padding-bottom: 22px; }

/* category split bar (horizontal stacked) */
.split-bar {
  display: flex; height: 8px;
  border-radius: 999px; overflow: hidden;
  background: var(--surface-2);
  margin-bottom: 8px;
}
.split-bar > span { display: block; }
.split-legend {
  display: flex; flex-wrap: wrap; gap: 10px;
  font-size: var(--fs-xs); color: var(--ink-2);
}
.split-legend .dot {
  display: inline-block; width: 8px; height: 8px; border-radius: 2px;
  margin-right: 5px; vertical-align: middle;
}

/* big stat callouts (reports) */
.big-stat {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-3);
  padding: 20px 22px;
}
.big-stat .l {
  font-size: var(--fs-xs); color: var(--ink-3);
  text-transform: uppercase; letter-spacing: 0.04em;
  margin-bottom: 8px;
}
.big-stat .v {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 28px; font-weight: 600;
  color: var(--ink-0); letter-spacing: -0.015em;
  line-height: 1;
}
.big-stat .v small {
  font-size: var(--fs-md); color: var(--ink-3);
  margin-left: 4px; font-weight: 400;
}
.big-stat .delta { font-size: var(--fs-xs); color: var(--ink-3); margin-top: 10px; }
.big-stat .delta.pos { color: var(--ok); }

/* row-flag helper for legacy tables; tints background + adds left bar */
tbody tr.flag-warn td { background: var(--warn-bg); box-shadow: inset 3px 0 0 var(--warn); }
tbody tr.flag-info td { background: var(--info-bg); box-shadow: inset 3px 0 0 var(--info); }
tbody tr.flag-err  td { background: var(--err-bg);  box-shadow: inset 3px 0 0 var(--err); }
tbody tr.flag-ok   td { background: var(--ok-bg);   box-shadow: inset 3px 0 0 var(--ok); }

/* portal-shell responsive */
@media (max-width: 1100px) {
  .row-grid, .row-grid-2-1 { grid-template-columns: 1fr; }
}
@media (max-width: 720px) {
  .shell { grid-template-columns: 1fr; grid-template-rows: auto 1fr; }
  /* 2026-05-26: mobile rail tightened per chris's screenshot feedback.
     Was: 56x48 buttons with text labels stacking under the icon — 8
     buttons + 2-line text wrapped awkwardly + ate ~96px of viewport
     before page chrome / content even appeared. Now: icon-only at
     44x44, text labels hidden visually but still in DOM (and the
     title="…" attr was already on every .rail-btn for accessibility,
     so hover/long-press still reveals the label). Active indicator
     flipped from vertical left-bar to horizontal bottom-bar to match
     the new orientation. */
  .rail {
    flex-direction: row; padding: 0; height: 44px;
    position: static; overflow-x: auto; overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
  }
  .rail .logo { width: 44px; height: 44px; margin-bottom: 0; border-bottom: none; border-right: 1px solid var(--rail-divider); flex-shrink: 0; }
  .rail-btn {
    width: 44px; height: 44px; flex-shrink: 0;
    /* Icon-only: hide the text node, keep title attr for a11y */
    font-size: 0; line-height: 0; gap: 0;
  }
  .rail-btn svg { width: 20px; height: 20px; opacity: 0.85; }
  /* Re-orient the active indicator from left-bar (vertical) to
     bottom-bar (horizontal) to match the new flex direction. */
  .rail-btn.active::before {
    inset: auto 4px 0 4px;   /* bottom edge */
    width: auto; height: 2px;
    border-radius: 2px 2px 0 0;
  }
  .rail .spacer { display: none; }
  .topbar .search { width: 100%; max-width: 160px; }
  .topbar .top-action span { display: none; }
  .content { padding: 12px 12px 32px; }
  .row-grid-1-1 { grid-template-columns: 1fr; }
  .stat-strip { grid-template-columns: 1fr 1fr; }
  .stat-strip > div:nth-child(2n) { border-right: none; }
  .stat-strip > div { border-bottom: 1px solid var(--border); }
  .tabs { padding: 0 12px; overflow-x: auto; }
  .crumb-bar, .pgh { padding-left: 14px; padding-right: 14px; }
  .props { grid-template-columns: 110px 1fr; }
  .form-row { grid-template-columns: 1fr; gap: 8px; }
}

/* ============================================================
   §4.4.4 — replay panel (migrated from dashboard-replay.js's
   injected <style id="dp-replay-styles">). Themed via tokens so
   the strip respects light/dark just like the rest of the page.
   ============================================================ */
.dp-replay-panel {
  display: flex; align-items: center; gap: 10px;
  margin-top: 8px; padding: 8px 10px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-3);
  font-size: 0.82rem; color: var(--ink-2);
}
.dp-replay-btn {
  background: var(--surface); color: var(--ink-1);
  border: 1px solid var(--border); border-radius: var(--r-2);
  padding: 4px 11px; font-size: 0.85rem;
  cursor: pointer; font-family: inherit; line-height: 1;
}
.dp-replay-btn:hover { background: var(--bg); }
.dp-replay-btn.playing {
  background: var(--accent-bg);
  border-color: var(--accent);
  color: var(--accent);
}
.dp-replay-speed {
  display: inline-flex; gap: 0;
  border: 1px solid var(--border); border-radius: var(--r-2);
  overflow: hidden;
}
.dp-replay-speed button {
  background: transparent; color: var(--ink-3);
  border: none; padding: 3px 8px; font-size: 0.76rem;
  cursor: pointer; font-family: inherit;
}
.dp-replay-speed button.active { background: var(--accent-bg); color: var(--ink-0); }
.dp-replay-speed button:hover:not(.active) { background: var(--bg); color: var(--ink-1); }
.dp-replay-readout {
  flex: 1; text-align: right;
  color: var(--ink-3); font-size: 0.76rem;
  font-family: var(--font-mono);
}
.dp-replay-readout strong { color: var(--ink-1); font-weight: 600; }
.dp-replay-gear {
  background: transparent; color: var(--ink-3);
  border: none; padding: 0 4px;
  font-size: 1rem; cursor: pointer; line-height: 1;
  font-family: inherit;
  /* Issue #15 (chris 2026-05-23): basemap-picker gear is admin-only
     during Beta. Default hidden; revealed by body.dp-admin set in
     driveproof-ui.js after a successful admin /auth/me check.
     Default-hidden so non-admin users never see a flash of the gear
     while the auth fetch races on cold load. */
  display: none;
}
body.dp-admin .dp-replay-gear { display: inline-block; }
.dp-replay-gear:hover { color: var(--ink-1); }
.dp-replay-dots {
  background: transparent; color: var(--ink-3);
  border: 1px solid var(--border);
  padding: 3px 8px; font-size: 0.72rem;
  cursor: pointer; line-height: 1.2;
  font-family: inherit; border-radius: var(--r-2);
  letter-spacing: 0.02em;
}
.dp-replay-dots:hover { color: var(--ink-1); border-color: var(--border-2); }
body.dp-hide-raw-dots .dp-replay-dots { color: var(--ink-3); }

/* ============================================================
   §4.4.5 — basemap picker modal (migrated from dashboard-map.js
   openBasemapPicker self-injected <style>). Backdrop stays
   rgba black-60 (works either palette); the panel + options +
   side-toggle go to tokens.
   ============================================================ */
#dp-basemap-picker {
  position: fixed; inset: 0; z-index: 2000;
  background: rgba(0,0,0,0.6); display: none;
  align-items: center; justify-content: center;
}
#dp-basemap-picker.open { display: flex; }
#dp-basemap-picker .dp-bp-panel {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-3);
  width: min(420px, 90vw); max-height: 80vh; overflow: hidden;
  display: flex; flex-direction: column;
  font-family: var(--font-sans);
  color: var(--ink-1);
}
#dp-basemap-picker .dp-bp-title {
  padding: 12px 16px 4px; font-size: 0.78rem; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.5px;
  color: var(--ink-3);
}
#dp-basemap-picker .dp-bp-list {
  padding: 4px 8px 8px; overflow-y: auto; flex: 1;
}
#dp-basemap-picker .dp-bp-opt {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px; border-radius: var(--r-3); cursor: pointer;
  font-size: 0.86rem; color: var(--ink-1);
}
#dp-basemap-picker .dp-bp-opt:hover { background: var(--row-hover); }
#dp-basemap-picker .dp-bp-opt.selected { background: var(--accent-bg); color: var(--accent); }
#dp-basemap-picker .dp-bp-opt .badge {
  margin-left: auto; font-size: 0.66rem; padding: 2px 6px;
  border-radius: 999px;
  background: var(--ok-bg); color: var(--ok);
  text-transform: uppercase; letter-spacing: 0.4px;
}
#dp-basemap-picker .dp-bp-footer {
  padding: 8px 12px; border-top: 1px solid var(--border); text-align: right;
}
#dp-basemap-picker .dp-bp-close {
  background: var(--surface-2); color: var(--ink-1);
  border: 1px solid var(--border);
  border-radius: var(--r-2); padding: 5px 14px; cursor: pointer;
  font-family: inherit; font-size: 0.85rem;
}
#dp-basemap-picker .dp-bp-close:hover { background: var(--bg); }
#dp-basemap-picker .dp-bp-side-row .dp-bp-title { border-top: 1px solid var(--border); margin-top: 4px; }
#dp-basemap-picker .dp-bp-side-toggle {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: 6px; padding: 6px 8px 0;
}
#dp-basemap-picker .dp-bp-side {
  background: var(--bg); color: var(--ink-2);
  border: 1px solid var(--border);
  border-radius: var(--r-3); padding: 8px; cursor: pointer;
  font-family: inherit; font-size: 0.82rem;
}
#dp-basemap-picker .dp-bp-side.selected {
  background: var(--accent-bg); color: var(--accent); border-color: var(--accent);
}
