:root {
  /* Single source for the drawer width: the map controls slide by exactly this
     much, so the two cannot drift apart. */
  --drawer-w: clamp(420px, 50vw, 100vw);

  /* Light chrome, sharing the palette the drawer already used. The map floats
     several panels — the dash, the brand chip, the layers list, the smoke
     scrubber, charger popups, the toast — and they all read from these, so
     they cannot drift apart or half-convert. */
  --bg: #dfe6ee;
  --surface: rgba(255, 255, 255, 0.95);
  --border: #d3dce6;
  --text: #16202e;
  --muted: #5b6b7f;

  /* Fills, bars and anything that has to match a line drawn on the map keep
     the bright pair. The route is drawn in these two and the chrome should
     agree with it. */
  --behind: #38bdf8;
  --ahead: #f59e0b;
  --danger: #ef4444;

  /* Text needs contrast a fill does not. #38bdf8 on white is unreadable at
     12px, so labels and numbers use the darker ink instead. */
  --behind-ink: #0369a1;
  --ahead-ink: #b45309;
  --danger-ink: #b91c1c;

  --radius: 12px;
  --shadow: 0 10px 30px rgba(15, 23, 42, 0.16);
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  height: 100%;
  font-family: ui-sans-serif, -apple-system, "Segoe UI", Roboto, sans-serif;
  color: var(--text);
  background: var(--bg);
  overscroll-behavior: none;
}

#map {
  position: fixed;
  inset: 0;
  background: var(--bg);
}

/* Leaflet's default attribution needs to sit on the light chrome */
.leaflet-control-attribution {
  background: rgba(255, 255, 255, 0.82) !important;
  color: var(--muted) !important;
  font-size: 10px;
}
.leaflet-control-attribution a { color: var(--behind-ink) !important; }

/* ---------- Trip builder panel ---------- */

.panel {
  position: fixed;
  top: 12px;
  left: 12px;
  z-index: 1000;
  width: 340px;
  max-width: calc(100vw - 24px);
  background: var(--surface);
  backdrop-filter: blur(12px);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}

.panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 14px;
}

.brand { display: flex; align-items: center; gap: 9px; }

.brand-mark {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--behind);
  box-shadow: 0 0 0 4px rgba(56, 189, 248, 0.22);
  flex: none;
}

.panel h1 {
  margin: 0;
  font-size: 15px;
  font-weight: 650;
  letter-spacing: -0.01em;
}

.panel-body {
  padding: 0 14px 14px;
  display: grid;
  gap: 10px;
}

.panel.collapsed .panel-body { display: none; }

.stops { display: grid; gap: 8px; }

.stop {
  position: relative;
  display: flex;
  align-items: center;
  gap: 8px;
}

.stop-grip {
  flex: none;
  width: 12px;
  height: 20px;
  cursor: grab;
  touch-action: none;          /* let the drag win over page scroll on touch */
  border-radius: 3px;
  background-image: radial-gradient(currentColor 1px, transparent 1.2px);
  background-size: 4px 4px;
  background-position: 1px 4px;
  background-repeat: repeat;
  color: #9aa8ba;
}
.stop-grip:hover { color: var(--text); }
.stop-grip:active { cursor: grabbing; }

.stop.dragging {
  position: relative;
  z-index: 10;
  opacity: 0.92;
  filter: drop-shadow(0 6px 14px rgba(15, 23, 42, 0.22));
}
.stop:not(.dragging) { transition: transform 0.14s ease; }

.stop-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  border: 2px solid var(--muted);
  flex: none;
}
.stop:first-child .stop-dot { background: var(--behind); border-color: var(--behind); }
.stop:last-child .stop-dot { background: var(--ahead); border-color: var(--ahead); }

.stop input {
  flex: 1;
  min-width: 0;
  padding: 9px 10px;
  font-size: 13px;
  color: var(--text);
  background: #ffffff;
  border: 1px solid var(--border);
  border-radius: 8px;
  font-family: inherit;
}
.stop input:focus {
  outline: none;
  border-color: var(--behind);
  box-shadow: 0 0 0 3px rgba(56, 189, 248, 0.16);
}
.stop input.resolved { border-color: rgba(56, 189, 248, 0.5); }

.stop-remove {
  flex: none;
  width: 24px;
  height: 24px;
  border: none;
  border-radius: 6px;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
  font-size: 16px;
  line-height: 1;
}
.stop-remove:hover { color: var(--danger-ink); background: rgba(248, 113, 113, 0.12); }
.stop-remove[hidden] { display: none; }

.suggestions {
  position: absolute;
  top: calc(100% + 4px);
  left: 37px;                  /* clears the grip + colour dot */
  right: 32px;
  z-index: 20;
  background: #ffffff;
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: var(--shadow);
  overflow: hidden;
  max-height: 220px;
  overflow-y: auto;
}

.suggestion {
  display: block;
  width: 100%;
  text-align: left;
  padding: 9px 11px;
  font-size: 12.5px;
  color: var(--text);
  background: none;
  border: none;
  cursor: pointer;
  font-family: inherit;
}
.suggestion:hover, .suggestion.active { background: rgba(56, 189, 248, 0.16); }

.row { display: flex; gap: 8px; align-items: center; }
.row > select { flex: 1; min-width: 0; }

.btn {
  padding: 9px 13px;
  font-size: 13px;
  font-weight: 550;
  font-family: inherit;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: #ffffff;
  color: var(--text);
  cursor: pointer;
  white-space: nowrap;
}
.btn:hover { border-color: #94a3b8; }
.btn:disabled { opacity: 0.5; cursor: default; }

.btn-primary {
  margin-left: auto;
  background: var(--behind);
  border-color: var(--behind);
  color: #06263a;
  font-weight: 650;
}
.btn-primary:hover { background: #7dd3fc; }

.btn-sm { padding: 6px 10px; font-size: 12px; }

.msg {
  margin: 0;
  font-size: 12px;
  line-height: 1.45;
  color: var(--muted);
}
.msg.error { color: var(--danger-ink); }

.saved { display: grid; gap: 6px; border-top: 1px solid var(--border); padding-top: 10px; }

.mini-label { font-size: 11px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.05em; }

select, input[type="number"] {
  padding: 7px 9px;
  font-size: 12.5px;
  font-family: inherit;
  color: var(--text);
  background: #ffffff;
  border: 1px solid var(--border);
  border-radius: 8px;
}
input[type="number"] { width: 54px; }

.icon-btn {
  width: 26px;
  height: 26px;
  border: 1px solid var(--border);
  border-radius: 7px;
  background: #ffffff;
  color: var(--muted);
  cursor: pointer;
  font-size: 15px;
  line-height: 1;
}
.icon-btn:hover { color: var(--text); }

/* ---------- Progress dashboard ---------- */

.dash {
  position: fixed;
  left: 50%;
  transform: translateX(-50%);
  bottom: 14px;
  z-index: 1000;
  width: min(620px, calc(100vw - 24px));
  padding: 14px 16px 12px;
  background: var(--surface);
  backdrop-filter: blur(12px);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}

.dash-grid {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 12px;
}

.stat { display: grid; gap: 2px; }
.stat-ahead { text-align: right; }
.stat-pct { text-align: center; }

.stat-label {
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--muted);
}

.stat-value {
  font-size: 21px;
  font-weight: 680;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}
.stat-value.big { font-size: 26px; }
.stat-behind .stat-value { color: var(--behind-ink); }
.stat-ahead .stat-value { color: var(--ahead-ink); }

.stat-sub { font-size: 11.5px; color: var(--muted); font-variant-numeric: tabular-nums; }

.track {
  position: relative;
  margin: 12px 0 10px;
  height: 18px;
  display: flex;
  align-items: center;
}

.track::before {
  content: "";
  position: absolute;
  left: 0; right: 0;
  height: 5px;
  border-radius: 3px;
  background: rgba(245, 158, 11, 0.32);
}

.track-fill {
  position: absolute;
  left: 0;
  height: 5px;
  width: 0;
  border-radius: 3px;
  background: var(--behind);
}

/* Stop ticks sit on the bar but never intercept the pointer, so dragging the
   slider still works when the thumb passes over one. */
.track-marks {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.track-mark {
  position: absolute;
  top: 50%;
  width: 3px;
  height: 13px;
  margin-left: -1.5px;
  transform: translateY(-50%);
  border-radius: 2px;
  background: var(--ahead);
  box-shadow: 0 0 0 2px rgba(15, 23, 42, 0.9);
}
.track-mark.past { background: var(--behind); }

.track-labels {
  position: relative;
  height: 13px;
  margin: -4px 0 8px;
}
.track-labels:empty { height: 0; margin: 0 0 4px; }

.track-label {
  position: absolute;
  top: 0;
  transform: translateX(-50%);
  padding: 0 3px;
  font-size: 10px;
  line-height: 13px;
  white-space: nowrap;
  color: var(--muted);
  background: none;
  border: none;
  font-family: inherit;
  cursor: pointer;
}
.track-label:hover { color: var(--text); }
.track-label.past { color: var(--behind-ink); }

#slider {
  position: relative;
  width: 100%;
  margin: 0;
  background: none;
  -webkit-appearance: none;
  appearance: none;
}
#slider:focus { outline: none; }

#slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: #fff;
  border: 3px solid var(--behind);
  cursor: grab;
  box-shadow: 0 2px 6px rgba(15, 23, 42, 0.28);
}
#slider::-moz-range-thumb {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: #fff;
  border: 3px solid var(--behind);
  cursor: grab;
  box-shadow: 0 2px 6px rgba(15, 23, 42, 0.28);
}

.dash-foot {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

.foot-note { font-size: 11.5px; color: var(--muted); }

.car-line {
  margin: 8px 0 0;
  padding-top: 8px;
  border-top: 1px solid var(--border);
  font-size: 11.5px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.car-line strong { color: var(--text); font-weight: 600; }
.car-line.warn { color: var(--ahead-ink); }

.charge-mark {
  position: absolute;
  top: 50%;
  width: 7px;
  height: 7px;
  margin-left: -3.5px;
  transform: translateY(-50%);
  border-radius: 50%;
  background: #34d399;
  box-shadow: 0 0 0 2px rgba(15, 23, 42, 0.9);
}

.charge-pin {
  width: 11px;
  height: 11px;
  border-radius: 50%;
  background: #34d399;
  border: 2px solid #0f172a;
  box-shadow: 0 1px 5px rgba(0, 0, 0, 0.5);
}

/* ---------- Energy drawer ---------- */

/* A closed <dialog> is display:none from the UA stylesheet — but a bare
   `display: flex` here would override that and leave the drawer permanently on
   screen. Scope the flex layout to the open state. */
dialog.drawer:not([open]) { display: none; }

dialog.drawer {
  position: fixed;
  z-index: 2000;               /* above Leaflet's panes and controls */
  /* left:auto is required — the UA stylesheet sets left:0 on <dialog>, and with
     both edges pinned plus a fixed width the box is over-constrained, so `right`
     is ignored and the drawer lands on the left. */
  left: auto;
  right: 0;
  top: 0;
  bottom: 0;
  margin: 0;
  width: var(--drawer-w);
  max-width: 100vw;
  height: 100vh;
  max-height: 100vh;
  padding: 0;
  display: flex;
  flex-direction: column;
  color: var(--text);
  background: #111c33;
  border: none;
  border-left: 1px solid var(--border);
  border-radius: 0;
  box-shadow: -12px 0 40px rgba(0, 0, 0, 0.5);
}
dialog.drawer::backdrop { background: rgba(2, 6, 23, 0.45); }

.modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex: none;
  padding: 16px 18px;
  border-bottom: 1px solid var(--border);
}
.modal-header h3 { margin: 0; font-size: 16px; font-weight: 650; letter-spacing: -0.01em; }

.modal-close {
  background: none;
  border: none;
  font-size: 24px;
  line-height: 1;
  padding: 0 2px;
  color: var(--muted);
  cursor: pointer;
}
.modal-close:hover { color: var(--text); }

/* flex + min-height:0 is what lets the body scroll instead of the dialog
   growing past the viewport and hiding its own content */
.drawer-body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 16px 18px 22px;
}

.drawer-controls { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.drawer-controls input[type="date"] {
  padding: 6px 9px;
  font-size: 12.5px;
  font-family: inherit;
  color: var(--text);
  background: #ffffff;
  border: 1px solid var(--border);
  border-radius: 7px;
  color-scheme: light;
}

.drawer-note { margin: 8px 0 0; font-size: 11.5px; line-height: 1.5; color: var(--muted); }

.drawer-h4 {
  margin: 22px 0 8px;
  font-size: 11px;
  font-weight: 650;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--muted);
}

.summary-table {
  width: 100%;
  margin-top: 16px;
  border-collapse: collapse;
  font-variant-numeric: tabular-nums;
}
.summary-table td {
  padding: 7px 0;
  font-size: 13px;
  border-bottom: 1px solid rgba(148, 163, 184, 0.12);
}
.summary-table td:first-child { color: var(--muted); }
.summary-table td:last-child { text-align: right; font-weight: 600; }
.summary-table tr.headline td:last-child { font-size: 16px; color: var(--behind-ink); }
.summary-table tr.estimate td:last-child { color: var(--ahead-ink); }
.summary-table tr.spacer td { border-bottom: none; padding-top: 14px; }

.table-scroll { overflow-x: auto; }

.charges-table {
  width: 100%;
  border-collapse: collapse;
  font-variant-numeric: tabular-nums;
  font-size: 12.5px;
}
.charges-table th {
  text-align: left;
  padding: 6px 8px 6px 0;
  font-size: 10.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted);
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}
.charges-table td {
  padding: 8px 8px 8px 0;
  border-bottom: 1px solid rgba(148, 163, 184, 0.12);
  vertical-align: top;
}
.charges-table th:last-child, .charges-table td:last-child { padding-right: 0; text-align: right; }
.charges-table .num { text-align: right; white-space: nowrap; }
.charges-table .place { min-width: 130px; }
.charges-table tbody tr { cursor: pointer; }
.charges-table tbody tr:hover { background: rgba(56, 189, 248, 0.09); }
.charges-table .sub { display: block; font-size: 10.5px; color: var(--muted); }

@media (max-width: 640px) {
  :root { --drawer-w: 100vw; }
  dialog.drawer { border-left: none; }
}

/* ---------- Credentials dialog ---------- */

#car-dialog {
  width: min(420px, calc(100vw - 28px));
  max-height: calc(100vh - 40px);   /* a tall dialog otherwise clips its own buttons */
  overflow-y: auto;
  padding: 0;
  color: var(--text);
  background: #111c33;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
#car-dialog::backdrop { background: rgba(2, 6, 23, 0.62); backdrop-filter: blur(2px); }

#car-form { padding: 18px; display: grid; gap: 12px; }

#car-dialog h2 { margin: 0; font-size: 16px; font-weight: 650; letter-spacing: -0.01em; }

.dialog-note { margin: 0; font-size: 12px; line-height: 1.5; color: var(--muted); }
.dialog-note a { color: var(--behind-ink); }
.dialog-note code {
  font-size: 11px;
  padding: 1px 4px;
  border-radius: 4px;
  background: rgba(148, 163, 184, 0.16);
}

.field { display: grid; gap: 5px; }
.field input {
  padding: 9px 10px;
  font-size: 13px;
  font-family: inherit;
  color: var(--text);
  background: #ffffff;
  border: 1px solid var(--border);
  border-radius: 8px;
}
.field input:focus {
  outline: none;
  border-color: var(--behind);
  box-shadow: 0 0 0 3px rgba(56, 189, 248, 0.16);
}

.dialog-actions { display: flex; gap: 8px; justify-content: flex-end; margin-top: 2px; }
.dialog-actions .btn-primary { margin-left: 0; }

/* The dot on the map */
.trip-dot {
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: #fff;
  border: 4px solid var(--behind);
  box-shadow: 0 0 0 4px rgba(15, 23, 42, 0.55), 0 3px 10px rgba(0, 0, 0, 0.6);
  cursor: grab;
}
.trip-dot:active { cursor: grabbing; }

.endpoint-pin {
  width: 13px;
  height: 13px;
  border-radius: 50%;
  border: 3px solid #0f172a;
}

@media (max-width: 640px) {
  /* The panel spans the full width here, so there is no free corner for the
     zoom control. Pinch-zoom covers it on touch. */
  .leaflet-control-zoom { display: none; }

  .panel { width: calc(100vw - 20px); top: 10px; left: 10px; }
  .dash { bottom: 10px; padding: 12px 12px 10px; }
  .dash-grid { gap: 8px; }
  .stat-value { font-size: 17px; }
  .stat-value.big { font-size: 21px; }
  .stat-sub { font-size: 10.5px; }
  .dash-foot { gap: 8px; }
  .foot-note { order: 3; width: 100%; }
}

/* ---------- Chargers drawer ---------- */

.progress {
  height: 4px;
  margin-top: 12px;
  border-radius: 2px;
  background: rgba(148, 163, 184, 0.2);
  overflow: hidden;
}
.progress-bar {
  height: 100%;
  width: 0;
  border-radius: 2px;
  background: var(--behind);
  transition: width 0.25s ease;
}

.range-note {
  margin: 14px 0 0;
  padding: 9px 11px;
  font-size: 12px;
  line-height: 1.5;
  border-radius: 8px;
  background: rgba(52, 211, 153, 0.1);
  border: 1px solid rgba(52, 211, 153, 0.3);
  color: #a7f3d0;
}
.range-note.warn {
  background: rgba(245, 158, 11, 0.1);
  border-color: rgba(245, 158, 11, 0.35);
  color: #fcd34d;
}

/* A charger you cannot reach on the current charge */
.charges-table tr.out-of-range td { opacity: 0.45; }
.charges-table tr.out-of-range td:first-child { opacity: 0.7; }

.reach {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 5px;
  font-size: 9.5px;
  font-weight: 650;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  border-radius: 4px;
  vertical-align: 1px;
}
.reach.ok { background: rgba(52, 211, 153, 0.18); color: #6ee7b7; }
.reach.edge { background: rgba(245, 158, 11, 0.18); color: #fcd34d; }
/* Reachable only by spending the 20% margin — warmer than "tight", but still a
   tag rather than the dimming reserved for what the car cannot reach at all. */
.reach.reserve { background: rgba(251, 146, 60, 0.2); color: #fdba74; }

/* Colour is the network, matching the car's own map: Superchargers red,
   everyone else yellow. It used to be reachability (purple / green), which the
   route line now carries — a stretch of road says "this far" better than a
   colour on scattered dots ever did. */
.charger-pin {
  width: 9px;
  height: 9px;
  border-radius: 2px;
  background: #facc15;
  border: 2px solid #0f172a;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.5);
}
.charger-pin.tesla { background: #e82127; }

/* ---------- places ahead, and pins you drop ---------- */

.poi-hit { display: grid; place-items: center; background: none; border: 0; }

/* Round, so they never read as chargers — those are squares. One colour per
   category, since the whole point is telling fuel from food at a glance.

   Rest is blue and fuel is orange, which is a swap: rest used to be the violet
   and fuel the blue. Rest earned the stronger colour because it is the only one
   of the four with a LAYER of its own — it can sit on the map for a whole drive
   while the Find panel shows one of the others, so it is the one that has to be
   unmistakable next to another category rather than instead of it. Fuel takes
   orange, which suits a filling station and is a round dot where the amber
   remaining-line is a stroke and the yellow non-Tesla charger is a square. */
.poi-pin {
  width: 11px;
  height: 11px;
  border-radius: 50%;
  border: 2px solid #0f172a;
  box-shadow: 0 1px 4px rgba(15, 23, 42, 0.5);
  background: #64748b;
}
.poi-pin.fuel    { background: #ea580c; }
.poi-pin.food    { background: #db2777; }
.poi-pin.rest    { background: #2563eb; }
.poi-pin.lodging { background: #0d9488; }

/* A dropped pin is yours, so it is the odd one out: a teardrop, not a dot. */
.drop-pin {
  width: 13px;
  height: 13px;
  border-radius: 50% 50% 50% 2px;
  transform: rotate(-45deg);
  background: #16202e;
  border: 2px solid #fff;
  box-shadow: 0 2px 6px rgba(15, 23, 42, 0.55);
}

.find-panel {
  position: absolute;
  top: 0;
  right: calc(100% + 6px);
  width: 250px;
  padding: 6px;
  color: var(--text);
  background: var(--surface);
  backdrop-filter: blur(12px);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.find-panel[hidden] { display: none; }

.find-chips {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 4px;
  margin: 0 7px 6px;
}

.find-chip {
  padding: 6px 2px;
  font: 650 11px/1.2 inherit;
  color: var(--text);
  background: rgba(15, 23, 42, 0.05);
  border: 1px solid var(--border);
  border-radius: 8px;
  cursor: pointer;
}
.find-chip:hover { background: rgba(15, 23, 42, 0.09); }
.find-chip.is-on { color: #fff; background: #0369a1; border-color: #0369a1; }

.find-search { display: flex; gap: 5px; margin: 0 7px 6px; }
.find-search input {
  flex: 1;
  min-width: 0;
  padding: 6px 8px;
  font-size: 12.5px;
  font-family: inherit;
  color: var(--text);
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 8px;
}
.find-search input:focus { outline: none; border-color: var(--behind); }

/* Capped so a busy stretch cannot push the panel off the bottom of a phone. */
.find-list { max-height: 260px; overflow-y: auto; }
.find-row { text-align: left; }

.find-msg {
  margin: 4px 7px 2px;
  font-size: 11px;
  line-height: 1.4;
  color: var(--muted);
}
.find-msg[hidden] { display: none; }
.find-msg.error { color: var(--danger-ink); }

/* The hit area. Transparent and larger than the dot it centres, so a charger
   can be tapped with a thumb without the dot growing to match. */
.charger-hit {
  display: grid;
  place-items: center;
  background: none;
  border: 0;
}

/* ---------- charger popup ----------
   Leaflet's default popup is white on a dark map. Match the rest of the map
   chrome instead, so tapping a pin does not flash a light box at night. */

.leaflet-popup-content-wrapper,
.leaflet-popup-tip {
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border);
  box-shadow: var(--shadow);
}

.leaflet-popup-content-wrapper { border-radius: 10px; }
.leaflet-popup-content { margin: 10px 12px; font-size: 12.5px; line-height: 1.45; }
.leaflet-container a.leaflet-popup-close-button { color: var(--muted); }
.leaflet-container a.leaflet-popup-close-button:hover { color: var(--text); }

.charger-pop { display: grid; gap: 2px; }
.charger-pop strong { font-size: 13px; font-weight: 650; }
.charger-pop .pop-sub { font-size: 11.5px; color: var(--muted); }

/* The network, given its own weight — it is what people open the popup for. */
.charger-pop .pop-net {
  font-size: 12px;
  font-weight: 650;
  color: var(--behind-ink);
}
.charger-pop .pop-net.unknown {
  font-weight: 550;
  font-style: italic;
  color: var(--muted);
}
.charger-pop .pop-plugs { letter-spacing: 0.02em; }

.charger-pop .pop-reach {
  font-size: 11.5px;
  font-weight: 650;
  color: #047857;
}
.charger-pop .pop-reach.reserve { color: #b45309; }
.charger-pop .pop-reach.out { color: var(--danger-ink); }

/* Network dot, beside the name in the table and the popup. Same two colours as
   the map pin so the three cannot disagree. */
.net-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  margin-right: 6px;
  border-radius: 2px;
  background: #facc15;
  border: 1px solid rgba(15, 23, 42, 0.55);
  vertical-align: baseline;
}
.net-dot.tesla { background: #e82127; }

/* ---------- charging plan ---------- */

/* A charger you have decided to actually stop at. Ringed rather than
   recoloured — the fill still has to say which network it is. */
.charger-pin.planned {
  box-shadow: 0 0 0 2px #fff, 0 0 0 4px #0369a1, 0 1px 5px rgba(15, 23, 42, 0.5);
}

/* Planned stops on the timeline. Deliberately not green: the range limit
   (#22c55e) and the historical charge dots (#34d399) already own that end of
   the spectrum, and three greens on one 6px bar is unreadable. */
.plan-mark {
  position: absolute;
  top: 50%;
  width: 3px;
  height: 17px;
  margin-left: -1.5px;
  transform: translateY(-50%);
  border-radius: 2px;
  background: #0369a1;
  box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.9);
}

/* Two actions on a charger popup, wrapping rather than overflowing the 190px
   minimum width on a phone. */
.charger-pop .pop-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 7px;
}

.charger-pop .plan-btn {
  padding: 4px 9px;
  font-size: 11.5px;
  white-space: nowrap;
}
.charger-pop .plan-btn.on {
  color: #fff;
  background: #0369a1;
  border-color: #0369a1;
}

.charger-pop .pop-stalls {
  font-size: 11.5px;
  font-weight: 650;
  color: #047857;
}
.charger-pop .pop-stalls.out { color: var(--danger-ink); }

/* Last check-in. Deliberately quieter than the stall count above it: that is
   this minute from the network itself, this is one traveller months ago, and
   the type should not claim they carry the same weight. `unknown` is for "no
   reports" and "could not ask" — neither is bad news about the charger, and
   colouring them like the negative case would say a thing that is not true. */
/* Whether the station is meant to be working — stronger than a check-in, so it
   is set at the check-in's size but bolder, and sits above it. Drawn only when
   it says something; `none` collapses it so an empty span leaves no gap. */
.charger-pop .pop-status {
  font-size: 11.5px;
  font-weight: 650;
  color: #047857;
}
.charger-pop .pop-status.out { color: var(--danger-ink); }
.charger-pop .pop-status.none { display: none; }

.charger-pop .pop-seen {
  font-size: 11px;
  color: #047857;
}
.charger-pop .pop-seen.out { color: var(--danger-ink); font-weight: 650; }
.charger-pop .pop-seen.unknown { color: var(--muted); }

/* Live stall count in the chargers table, beside the built-bay count. */
dialog.drawer .stalls {
  margin-left: 6px;
  padding: 1px 6px;
  font-size: 10px;
  font-weight: 650;
  color: #065f46;
  background: #d1fae5;
  border-radius: 999px;
  white-space: nowrap;
}
dialog.drawer .stalls.out { color: #7f1d1d; background: #fee2e2; }

/* The route was drawn for a pale road map. On imagery it needs its own
   contrast — a halo, so both lines stay legible over forest and over snow. */
body.sat .leaflet-overlay-pane path {
  paint-order: stroke;
  stroke-linejoin: round;
}
body.sat .leaflet-control-attribution { background: rgba(255, 255, 255, 0.88) !important; }

.charger-pop .pop-how {
  margin-top: 4px;
  font-size: 10.5px;
  line-height: 1.35;
  color: var(--muted);
}

.charger-pop .send-car {
  justify-self: start;
  margin-top: 7px;
  padding: 4px 9px;
  font-size: 11.5px;
  white-space: nowrap;
}
.charger-pop .send-car:disabled { opacity: 0.65; cursor: default; }


/* ---------- Drawer and dialog palette ----------
   These kept their own --d-* set from when the map chrome was dark and only
   the drawer was light. The chrome is light too now and reads from :root, so
   the two are the same family; this block survives because the drawer sits on
   a tinted gray rather than on white, and its controls are sized and bordered
   for dense tables rather than for a floating panel. */

dialog.drawer,
#ocm-dialog,
#car-dialog {
  --d-bg: #eef2f7;
  --d-surface: #ffffff;
  --d-text: #16202e;
  --d-muted: #5b6b7f;
  --d-border: #d3dce6;
  --d-accent: #0369a1;
  --d-warn: #b45309;

  color: var(--d-text);
  background: var(--d-bg);
  border: none;
  border-left: 1px solid var(--d-border);
  box-shadow: -14px 0 44px rgba(15, 23, 42, 0.28);
}

#ocm-dialog, #car-dialog { border-left: none; border: 1px solid var(--d-border); }

dialog.drawer .modal-header,
#ocm-dialog h2, #car-dialog h2 { color: var(--d-text); }

dialog.drawer .modal-header {
  background: var(--d-surface);
  border-bottom: 1px solid var(--d-border);
}
dialog.drawer .modal-close, #ocm-dialog .modal-close { color: var(--d-muted); }
dialog.drawer .modal-close:hover { color: var(--d-text); }

dialog.drawer .drawer-note,
#ocm-dialog .dialog-note,
#car-dialog .dialog-note { color: var(--d-muted); }

dialog.drawer .drawer-h4 { color: var(--d-muted); }

dialog.drawer .mini-label { color: var(--d-muted); }

dialog.drawer .msg { color: var(--d-muted); }
dialog.drawer .msg.error { color: #b91c1c; }

/* Controls inside the light panels */
dialog.drawer .btn,
#ocm-dialog .btn, #car-dialog .btn {
  background: var(--d-surface);
  border-color: var(--d-border);
  color: var(--d-text);
}
dialog.drawer .btn:hover,
#ocm-dialog .btn:hover, #car-dialog .btn:hover { border-color: #94a3b8; }

dialog.drawer .btn-primary,
#ocm-dialog .btn-primary, #car-dialog .btn-primary {
  background: var(--d-accent);
  border-color: var(--d-accent);
  color: #fff;
}
dialog.drawer .btn-primary:hover,
#ocm-dialog .btn-primary:hover, #car-dialog .btn-primary:hover { background: #075985; }

dialog.drawer input[type="date"],
dialog.drawer input[type="number"],
#ocm-dialog .field input, #car-dialog .field input {
  color: var(--d-text);
  background: var(--d-surface);
  border: 1px solid var(--d-border);
  color-scheme: light;
}
dialog.drawer input:focus,
#ocm-dialog .field input:focus, #car-dialog .field input:focus {
  outline: none;
  border-color: var(--d-accent);
  box-shadow: 0 0 0 3px rgba(3, 105, 161, 0.15);
}

#ocm-dialog .dialog-note code, #car-dialog .dialog-note code {
  background: #e2e8f0;
  color: #334155;
}
#ocm-dialog .dialog-note a, #car-dialog .dialog-note a { color: var(--d-accent); }

/* Tabs */
.tabs {
  flex: none;
  display: flex;
  gap: 2px;
  padding: 0 12px;
  background: var(--d-surface);
  border-bottom: 1px solid var(--d-border);
  overflow-x: auto;
}

.tab {
  flex: none;
  padding: 10px 12px;
  font-family: inherit;
  font-size: 12.5px;
  font-weight: 550;
  white-space: nowrap;
  color: var(--d-muted);
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  cursor: pointer;
}
.tab:hover { color: var(--d-text); }
.tab.is-active { color: var(--d-accent); border-bottom-color: var(--d-accent); }

.tab-panel { display: none; }
.tab-panel.is-active { display: block; }

/* Tables on light */
dialog.drawer .summary-table td { border-bottom-color: #dde5ee; }
dialog.drawer .summary-table td:first-child { color: var(--d-muted); }
dialog.drawer .summary-table td:last-child { color: var(--d-text); }
dialog.drawer .summary-table tr.headline td:last-child { color: var(--d-accent); }
dialog.drawer .summary-table tr.estimate td:last-child { color: var(--d-warn); }

dialog.drawer .charges-table th {
  color: var(--d-muted);
  border-bottom-color: var(--d-border);
}
dialog.drawer .charges-table td { border-bottom-color: #dde5ee; }
dialog.drawer .charges-table .sub { color: var(--d-muted); }
dialog.drawer .charges-table tbody tr:hover { background: rgba(3, 105, 161, 0.07); }
dialog.drawer .charges-table tbody tr.here { background: rgba(3, 105, 161, 0.11); }

dialog.drawer .range-note {
  background: #e7f6ef;
  border-color: #a7d9c2;
  color: #14532d;
}
dialog.drawer .range-note.warn {
  background: #fdf3e3;
  border-color: #e6c88f;
  color: #7c4a03;
}

dialog.drawer .reach.ok { background: #d6f2e4; color: #14653c; }
dialog.drawer .reach.edge { background: #fbeccd; color: #8a5206; }
dialog.drawer .reach.reserve { background: #fbe4cd; color: #8a3f06; }

dialog.drawer .progress { background: #dbe3ec; }
dialog.drawer .progress-bar { background: var(--d-accent); }

dialog.drawer .charges-table tr.out-of-range td { opacity: 0.5; }

/* ---------- extra map controls ---------- */

/* Square icon buttons, matching the routing map in gridops-ft-aps. They were
   text, which never fitted Leaflet's 30px box — SMOKE and BORDER both ran off
   the right of the screen — and the labels are now on title/aria-label where
   they cost no width. */
.leaflet-bar a.map-btn {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  padding: 0;
  color: #1f2937;
}
.leaflet-bar a.map-btn:hover { color: #0f172a; }
.leaflet-bar a.map-btn.on { background: #0369a1; color: #fff; }


/* ---------- map layers panel ---------- */

.layers-ctl { position: relative; }

/* Layers sits permanently open in its own column, left of the zoom/framing
   stack. Leaflet floats every control right with clear:both, so the only way
   out of that single file is to leave the float flow entirely. The corner
   container is already position:absolute, so `right` here measures from ITS
   right edge — a larger value moves this further left, not right. */
/* Top left, under the brand chip — which is fixed at top:12 and 44px tall, so
   62px clears it with a 6px gap. Left-aligned to the chip rather than to
   Leaflet's default 10px, so the two edges line up.

   The smoke scrubber shares this column and is added later, so Leaflet's
   float+clear stacks it underneath without any positioning of its own. */
.leaflet-top.leaflet-left .layers-ctl { margin: 62px 0 0 12px; }

/* ---------- zoom-from-here menu ---------- */

.leg-ctl { position: relative; }

/* Opens clear of the layers column rather than on top of it. */
/* Position is set in JS from the left column's measured rect — see place().
   These are only the fallback values, used if that column is somehow absent. */
.leg-panel {
  position: absolute;
  top: 0;
  right: calc(100% + 6px);
  width: 226px;
  padding: 6px;
  color: var(--text);
  background: var(--surface);
  backdrop-filter: blur(12px);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.leg-panel[hidden] { display: none; }

.leg-row.is-off {
  opacity: 0.5;
  cursor: default;
}
.leg-row.is-off:hover { background: none; }

/* The distance is the thing you are actually reading — how far to the charger,
   how far is left — so it is set well above the place name it sits next to.
   Tabular figures because these are numbers being compared down a column, and
   proportional digits make "1,283" and "180" wander against each other. */
.leg-place, .leg-tail { font-size: 10.5px; }
.leg-dist {
  font-size: 15px;
  font-weight: 700;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}

/* The note line now mixes 10.5px and 15px text, so it needs room to breathe
   and a common baseline — without this the tall digits crowd the row above. */
.leg-row .layer-note { line-height: 1.35; }
.leg-row .layer-text { gap: 2px; }

/* Corner badge, because an icon on its own cannot say "two of these are on". */
.layers-badge {
  position: absolute;
  top: -5px;
  right: -5px;
  min-width: 15px;
  height: 15px;
  padding: 0 4px;
  font: 650 9.5px/15px ui-sans-serif, -apple-system, sans-serif;
  text-align: center;
  color: #fff;
  background: #0369a1;
  border: 1.5px solid #fff;
  border-radius: 999px;
  box-sizing: content-box;
}
.layers-badge[hidden] { display: none; }

/* ---------- box zoom ----------
   While the tool is armed the map's own targets have to stop intercepting: a
   charger pin is a 26px box and the route line takes clicks to move the dot, so
   without this the drag lands on one of them instead of drawing a rectangle.
   touch-action stops the browser panning the map out from under the drag. */
.leaflet-container.boxzoom {
  cursor: crosshair;
  touch-action: none;
}
.leaflet-container.boxzoom .leaflet-marker-pane,
.leaflet-container.boxzoom .leaflet-overlay-pane,
.leaflet-container.boxzoom .leaflet-smoke-pane { pointer-events: none; }
.leaflet-bar a.map-btn.on .layers-badge { background: #0f172a; }

.layers-panel {
  width: 232px;
  padding: 6px;
  color: var(--text);
  background: var(--surface);
  backdrop-filter: blur(12px);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}


.layers-head {
  padding: 4px 7px 6px;
  font-size: 9.5px;
  font-weight: 650;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--muted);
}

/* Base map is a choice of one, so it is a segmented control rather than more
   rows of switches — the shape says "pick one" before you read it. */
.base-seg {
  display: flex;
  gap: 4px;
  margin: 0 7px 4px;
}

.base-opt {
  flex: 1;
  min-width: 0;
  padding: 6px 6px;
  font: 600 11.5px/1.2 inherit;
  color: var(--text);
  background: rgba(15, 23, 42, 0.05);
  border: 1px solid var(--border);
  border-radius: 8px;
  cursor: pointer;
}
.base-opt:hover { background: rgba(15, 23, 42, 0.09); }
.base-opt.is-on {
  color: #fff;
  background: #0369a1;
  border-color: #0369a1;
}

/* Three across is fine at 232px but not at 190px — "Satellite" alone needs
   most of a third of that. Stack them rather than truncate. */
@media (max-width: 640px) {
  .base-seg { flex-direction: column; }
}

.layer-row {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  margin: 0;
  padding: 7px;
  font: inherit;
  text-align: left;
  color: var(--text);
  background: none;
  border: 0;
  border-radius: 8px;
  cursor: pointer;
}

.layer-row:hover { background: rgba(15, 23, 42, 0.06); }
.layer-row.is-on { background: rgba(3, 105, 161, 0.22); }
.layer-row.is-on:hover { background: rgba(3, 105, 161, 0.3); }
.layer-row.is-busy { cursor: progress; }

/* Placed AFTER the rules it overrides. A media query adds no specificity,
   so when this sat earlier in the file the plain .layers-panel width simply
   won and the phone kept the desktop width.

   Always open means the footprint is permanent, and on a phone the panel would
   otherwise eat a third of the map. The sub-notes explain each layer the first
   time and are noise after that, so they are the first thing to go. */
@media (max-width: 640px) {
  .layers-panel, .leg-panel { width: 190px; padding: 5px; }
  .layers-panel .layer-note { display: none; }
  .layers-panel .layer-row { padding: 6px 7px; }
  .layers-panel .layers-head { padding: 3px 7px 4px; }
  /* The chip sits 2px higher on a phone (top:10, bottom 54). */
  .leaflet-top.leaflet-left .layers-ctl { margin-top: 60px; }
}


.layer-text { display: grid; gap: 1px; flex: 1; min-width: 0; }
.layer-name { font-size: 12.5px; font-weight: 600; }
.layer-note { font-size: 10.5px; color: var(--muted); }

.layer-pill {
  flex: none;
  min-width: 30px;
  padding: 2px 7px;
  font-size: 9.5px;
  font-weight: 650;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  text-align: center;
  color: var(--muted);
  background: rgba(148, 163, 184, 0.16);
  border-radius: 999px;
}

.layer-row.is-on .layer-pill {
  color: #fff;
  background: #0369a1;
}


/* Keep the map's own controls clear of the open drawer. The drawer is
   non-modal, so both are usable at once and they must not overlap. */
body.drawer-open .leaflet-top.leaflet-right {
  transform: translateX(calc(-1 * var(--drawer-w)));
  transition: transform 0.2s ease;
}
.leaflet-top.leaflet-right { transition: transform 0.2s ease; }

@media (max-width: 640px) {
  /* The drawer covers the whole screen here, so the controls have nowhere to go. */
  body.drawer-open .leaflet-top.leaflet-right { display: none; }
}

/* ---------- compact brand chip (trip editing moved to the drawer) ---------- */

.panel-compact {
  display: flex;
  align-items: center;
  gap: 12px;
  width: auto;
  padding: 8px 10px 8px 14px;
}
.panel-compact h1 { font-size: 14px; }
.panel-compact .btn { padding: 5px 12px; }

/* ---------- stop editor, restyled for the light drawer ---------- */

dialog.drawer .stops { margin-bottom: 12px; }

dialog.drawer .stop input {
  color: var(--d-text);
  background: var(--d-surface);
  border: 1px solid var(--d-border);
}
dialog.drawer .stop input:focus {
  border-color: var(--d-accent);
  box-shadow: 0 0 0 3px rgba(3, 105, 161, 0.15);
}
dialog.drawer .stop input.resolved { border-color: #7cc0e0; }
dialog.drawer .stop input::placeholder { color: #94a3b8; }

dialog.drawer .stop-grip { color: #9aa8b8; }
dialog.drawer .stop-grip:hover { color: var(--d-text); }
dialog.drawer .stop-dot { border-color: #94a3b8; }

dialog.drawer .stop-remove { color: #94a3b8; }
dialog.drawer .stop-remove:hover { color: #b91c1c; background: rgba(185, 28, 28, 0.1); }

dialog.drawer .suggestions {
  background: var(--d-surface);
  border-color: var(--d-border);
  box-shadow: 0 8px 24px rgba(15, 23, 42, 0.18);
}
dialog.drawer .suggestion { color: var(--d-text); }
dialog.drawer .suggestion:hover { background: rgba(3, 105, 161, 0.1); }

dialog.drawer .row-actions { margin-bottom: 10px; }
dialog.drawer .row-actions .btn-primary { margin-left: auto; }

dialog.drawer .saved {
  border-top: 1px solid var(--d-border);
  padding-top: 12px;
}
dialog.drawer select {
  color: var(--d-text);
  background: var(--d-surface);
  border: 1px solid var(--d-border);
}

/* The drag ghost must clear the drawer's own stacking context */
dialog.drawer .stop.dragging { filter: drop-shadow(0 6px 14px rgba(15, 23, 42, 0.28)); }

/* ---------- time zone crossings ---------- */

.tz-label {
  padding: 2px 7px;
  font: 650 10px/1.4 ui-sans-serif, -apple-system, sans-serif;
  letter-spacing: 0.03em;
  white-space: nowrap;
  color: #fff;
  background: #7c3aed;
  border-radius: 5px;
  box-shadow: 0 2px 8px rgba(15, 23, 42, 0.45);
  /* Sit beside the line end, not on top of it */
  transform: translate(8px, -50%);
  width: max-content;
}

.tz-mark {
  position: absolute;
  top: 50%;
  width: 2px;
  height: 15px;
  margin-left: -1px;
  transform: translateY(-50%);
  border-radius: 1px;
  background: #a78bfa;
  box-shadow: 0 0 0 2px rgba(15, 23, 42, 0.9);
}

/* ---------- wildfire smoke ---------- */

/* Sits under the brand chip, which is a fixed-height compact panel — hence a
   fixed offset rather than anything measured. */
.smoke-panel.leaflet-bar {
  /* Matches the layers panel above it — they share a column and a ragged edge
     between them reads as a mistake. */
  width: 232px;
  /* Just a gap: the layers panel is above it in this column and already
     clears the brand chip. */
  margin: 8px 0 0 12px;
  padding: 9px 10px 8px;
  color: var(--text);
  background: var(--surface);
  backdrop-filter: blur(12px);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}

.smoke-panel[hidden] { display: none; }

/* Must sit AFTER .smoke-panel.leaflet-bar, not with the other mobile rules
   further up: a media query adds no specificity, so an earlier block loses to
   a later plain rule of equal weight and the phone keeps the desktop width. */
@media (max-width: 640px) {
  .smoke-panel.leaflet-bar { width: 190px; }
}

.smoke-legend {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  border-radius: 4px;
  overflow: hidden;
}

/* The band's own colour is the label's background, so the number has to read
   on both the palest and the darkest end of the ramp. Dark text with a light
   halo does that in one rule instead of six. */
.smoke-swatch {
  padding: 3px 0;
  font: 650 9px/1.2 ui-sans-serif, -apple-system, sans-serif;
  text-align: center;
  color: #1c1917;
  text-shadow: 0 0 3px rgba(255, 255, 255, 0.85);
}

/* Not uppercased, unlike the other small captions here: text-transform maps
   the micro sign onto a capital mu, which reads as "MG/M³" — a thousand times
   the concentration actually being shown. */
.smoke-cap {
  margin-top: 3px;
  font-size: 9.5px;
  letter-spacing: 0.04em;
  color: var(--muted);
}

.smoke-cap sub { font-size: 8px; }

.smoke-row {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 7px;
}

.smoke-step {
  flex: none;
  width: 22px;
  height: 22px;
  padding: 0;
  font-size: 14px;
  line-height: 1;
  color: var(--text);
  background: rgba(148, 163, 184, 0.16);
  border: 1px solid var(--border);
  border-radius: 6px;
  cursor: pointer;
}

.smoke-step:hover { background: rgba(148, 163, 184, 0.3); }

.smoke-range {
  flex: 1;
  min-width: 0;
  height: 20px;
  accent-color: var(--ahead);
  /* Without this the unfilled half of the track renders near-black, which the
     old dark panel hid and the white one does not. */
  color-scheme: light;
}

.smoke-when {
  margin-top: 5px;
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}

/* Where the trip puts you at the hour on show. Hollow, so it reads as a
   projection rather than as the dot, which is where you actually are. */
.smoke-ghost {
  width: 15px;
  height: 15px;
  margin: -7.5px 0 0 -7.5px;
  border: 2.5px dashed var(--ahead);
  border-radius: 50%;
  background: rgba(245, 158, 11, 0.18);
  box-shadow: 0 0 0 2px rgba(15, 23, 42, 0.55);
}

/* ---------- range on the route ---------- */

/* Sits at the end of the green stretch, same treatment as the timezone and
   border labels — it is the same kind of fact: a line you cross. */

.range-mark {
  position: absolute;
  top: 50%;
  width: 2px;
  height: 15px;
  margin-left: -1px;
  transform: translateY(-50%);
  border-radius: 1px;
  background: #22c55e;
  box-shadow: 0 0 0 2px rgba(15, 23, 42, 0.9);
}

.range-mark.faint {
  height: 10px;
  opacity: 0.55;
}

/* Where the forecast stops reaching, on the trip timeline. */
.smoke-mark {
  position: absolute;
  top: 50%;
  width: 2px;
  height: 15px;
  margin-left: -1px;
  transform: translateY(-50%);
  border-radius: 1px;
  background: #fb923c;
  box-shadow: 0 0 0 2px rgba(15, 23, 42, 0.9);
}

/* Status for map-level actions. #msg lives inside the drawer, which is often
   closed when you press a map button — so it cannot be the only feedback. */
#map-toast {
  position: fixed;
  top: 14px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 1500;
  max-width: min(460px, calc(100vw - 28px));
  padding: 8px 14px;
  font-size: 12.5px;
  line-height: 1.4;
  color: var(--text);
  background: var(--surface);
  backdrop-filter: blur(12px);
  border: 1px solid var(--border);
  border-radius: 9px;
  box-shadow: var(--shadow);
}
#map-toast.error { color: #fecaca; border-color: rgba(248, 113, 113, 0.5); }

/* Day-by-day "Ends near": town on top, mile marker beneath.
   Remote place names can be very long ("Area B (Finlay Valley/Beatton
   Valley)"), so clamp with an ellipsis and keep the full text in the tooltip
   rather than let one row blow out the table. */
dialog.drawer .charges-table td.place-cell { max-width: 190px; }
dialog.drawer .charges-table td.place-cell > span {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
dialog.drawer .charges-table td.place-cell .sub { text-align: right; }

/* Keep the narrow columns on one line */
dialog.drawer #arrive-table td:nth-child(1),
dialog.drawer #arrive-table td:nth-child(2),
dialog.drawer #arrive-table td:nth-child(3) { white-space: nowrap; }

/* Energy Used: date column keeps its two lines together and never wraps */
dialog.drawer .charges-table td.whence { white-space: nowrap; vertical-align: top; }
dialog.drawer .charges-table td.whence .sub { text-align: left; }
dialog.drawer .charges-table td.num .sub { text-align: right; }

/* Miles by day: ahead of plan reads green, behind reads amber */
dialog.drawer .charges-table td.gain { color: #15803d; font-weight: 600; }
dialog.drawer .charges-table td.lose { color: #b45309; font-weight: 600; }
dialog.drawer .charges-table tr.totals td {
  border-top: 1px solid var(--d-border);
  border-bottom: none;
  font-weight: 650;
  padding-top: 9px;
}

/* Schedule standing on the dash. It has to read at a glance in daylight, and
   now sits on white — so these are inks rather than the bright pair that
   worked against the old dark chrome. */
.sched { font-weight: 650; }
.sched.gain { color: #047857; }
.sched.lose { color: #b45309; }
.sched.even { color: var(--muted); }
/* Not yet committed: same reading, visibly less certain. */
.sched.provisional { opacity: 0.75; font-weight: 550; font-style: italic; }

/* Arrival day-by-day carries five columns; keep the numeric ones tight so the
   place name gets the slack. */
dialog.drawer #arrive-table td:nth-child(4),
dialog.drawer #arrive-table th:nth-child(4) { white-space: nowrap; }
dialog.drawer #arrive-table td.place-cell { max-width: none; }

/* Cumulative reads as the secondary of the two mileage columns */
dialog.drawer .charges-table td.cum { color: var(--d-muted); }

/* Drawer header keeps the units toggle beside the close button, so it is
   reachable from whichever tab you are reading. */
.header-actions { display: flex; align-items: center; gap: 10px; }
dialog.drawer .header-actions .btn { padding: 4px 11px; font-size: 12px; }

/* The dash foot now holds only what you touch while moving. */
.dash-foot .foot-note { margin-left: 4px; }

/* ---------- Drawer pull-tab ----------
   Sits on the edge the drawer opens from and rides with it, so the same
   control both opens and closes. Reads vertically to stay narrow. */

#drawer-handle {
  position: fixed;
  right: 0;
  top: 50%;
  z-index: 1500;
  transform: translateY(-50%);
  transition: transform 0.2s ease;

  writing-mode: vertical-rl;
  padding: 16px 7px;
  font-family: inherit;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--text);
  background: var(--surface);
  backdrop-filter: blur(12px);
  border: 1px solid var(--border);
  border-right: none;
  border-radius: 10px 0 0 10px;
  box-shadow: -4px 0 16px rgba(15, 23, 42, 0.18);
  cursor: pointer;
}
#drawer-handle:hover { color: #fff; border-color: rgba(148, 163, 184, 0.5); }

body.drawer-open #drawer-handle {
  transform: translateY(-50%) translateX(calc(-1 * var(--drawer-w)));
}

@media (max-width: 640px) {
  /* The drawer covers the screen here, so the handle would ride off the edge. */
  body.drawer-open #drawer-handle { display: none; }
}

/* Intermediate stops: hollow, so they read as waypoints rather than endpoints */
.via-stop .endpoint-pin {
  border-color: #475569;
  box-shadow: 0 1px 5px rgba(0, 0, 0, 0.45);
}

/* Stops table now carries six columns; keep the numeric ones from wrapping. */
dialog.drawer #stops-table td.num,
dialog.drawer #stops-table th.num { white-space: nowrap; }
dialog.drawer #stops-table td.place { min-width: 110px; }

/* Odometer readings need room for five or six digits */
dialog.drawer input[type="number"].wide { width: 92px; }

/* Next-stop ETA: the one line you want before pulling back onto the road */
dialog.drawer .next-stop {
  margin: 14px 0 0;
  padding: 10px 12px;
  font-size: 13px;
  line-height: 1.5;
  color: var(--d-text);
  background: var(--d-surface);
  border: 1px solid var(--d-border);
  border-radius: 8px;
}
dialog.drawer .next-stop strong { color: var(--d-accent); }
dialog.drawer .eta { font-weight: 650; color: var(--d-accent); }

dialog.drawer .eta-warn { color: var(--d-warn); font-size: 12px; }

/* ---------- send a destination to the car ---------- */

/* On the next-stop line the button goes on its own row: that paragraph already
   wraps to two or three lines on a phone, and an inline button lands in a
   different place every render as the text reflows. */
dialog.drawer .next-stop .send-car {
  display: block;
  margin-top: 9px;
}

dialog.drawer .charges-table td.send {
  width: 1%;
  padding-left: 6px;
  text-align: right;
  white-space: nowrap;
}

dialog.drawer .send-car {
  font-size: 11.5px;
  padding: 4px 9px;
  white-space: nowrap;
}

dialog.drawer .send-car:disabled {
  opacity: 0.65;
  cursor: default;
}

/* The row itself jumps the dot on click; the button must not look like part
   of that target. */
dialog.drawer .charges-table tr:hover td.send .send-car { border-color: #94a3b8; }

/* ---------- Drawer resize grip ----------
   A thin strip on the drawer's leading edge. Widening the panel is the whole
   point of tables this wide, so it beats picking one width for everyone. */

#drawer-resize {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 7px;
  z-index: 5;
  cursor: col-resize;
  touch-action: none;          /* the drag must win over scrolling on touch */
  background: transparent;
}
#drawer-resize:hover,
body.drawer-sizing #drawer-resize { background: rgba(3, 105, 161, 0.35); }

/* While dragging, stop the pointer selecting text or the map grabbing it */
body.drawer-sizing { user-select: none; cursor: col-resize; }
body.drawer-sizing .leaflet-container { pointer-events: none; }

/* Nothing to drag when the drawer is the whole screen */
@media (max-width: 640px) {
  #drawer-resize { display: none; }
}

/* By Day: the day's run, with its clock times beneath */
dialog.drawer .charges-table td.daytrip {
  max-width: 260px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
dialog.drawer .charges-table td.daytrip > span {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Days already driven, in the Arrival itinerary */
dialog.drawer .charges-table tr.done td { background: rgba(21, 128, 61, 0.045); }
dialog.drawer .charges-table tr.done.here td { background: rgba(3, 105, 161, 0.11); }
dialog.drawer .charges-table td .gain { color: #15803d; font-weight: 650; }
dialog.drawer .charges-table td .lose { color: #b45309; font-weight: 650; }

/* ---------- state and country crossings ---------- */

.border-label {
  padding: 2px 7px;
  font: 650 10px/1.4 ui-sans-serif, -apple-system, sans-serif;
  letter-spacing: 0.03em;
  white-space: nowrap;
  color: #fff;
  background: #0f766e;
  border-radius: 5px;
  box-shadow: 0 2px 8px rgba(15, 23, 42, 0.45);
  transform: translate(8px, -50%);
  width: max-content;
}
/* A country line is the one with a queue and a passport check */
.border-label.country { background: #be123c; font-size: 11px; padding: 3px 9px; }

.border-mark {
  position: absolute;
  top: 50%;
  width: 2px;
  height: 13px;
  margin-left: -1px;
  transform: translateY(-50%);
  border-radius: 1px;
  background: #2dd4bf;
  box-shadow: 0 0 0 2px rgba(15, 23, 42, 0.9);
}
.border-mark.country { width: 3px; height: 17px; background: #fb7185; }

/* The charging plan and dropped pins live inside a saved trip, so until the
   trip is saved they are held in memory only. Said in the panel rather than
   only in a toast, because it stays true after the toast has gone. */
.plan-unsaved {
  margin: 0 0 8px;
  padding: 7px 9px;
  font-size: 11.5px;
  color: var(--danger-ink);
  background: rgba(220, 38, 38, 0.08);
  border-radius: 8px;
}
.plan-unsaved[hidden] { display: none; }

/* ---------- Supercharger passport ---------- */

/* Round, and a palette of its own. The chargers-ahead pins are red/yellow
   squares and the two layers get shown over the same road, so a passport dot
   has to be tellable apart from one at a glance rather than on inspection.
   Green reads as collected; the hollow slate is plainly the absence of it. */
.pass-dot {
  display: inline-block;
  width: 9px;
  height: 9px;
  margin-right: 6px;
  border-radius: 50%;
  background: #ffffff;
  border: 1.5px solid #334155;
  vertical-align: 1px;
}
.pass-dot.seen { background: #22c55e; border-color: #14532d; }

/* Four numbers, and the first is the only one the competition scores — so it
   is the same size as the others rather than shouted, which would leave the
   other three looking like decoration. They are all facts about the same year. */
.pass-summary {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 8px;
  margin: 10px 0 4px;
}
.pass-summary[hidden] { display: none; }

.pass-stat {
  display: grid;
  gap: 1px;
  padding: 9px 10px;
  background: rgba(34, 197, 94, 0.09);
  border: 1px solid rgba(34, 197, 94, 0.28);
  border-radius: 10px;
}
.pass-stat strong {
  font-size: 17px;
  font-weight: 700;
  line-height: 1.15;
  color: #14532d;
}
.pass-stat span {
  font-size: 11.5px;
  font-weight: 600;
  color: var(--text);
}
.pass-stat em {
  font-size: 10.5px;
  font-style: normal;
  color: var(--muted);
}

/* A filter, pressed in rather than lit up. It sits beside Find chargers, which
   is the button that makes something happen, and the two must not read as the
   same kind of thing. */
dialog.drawer .btn.is-on {
  background: rgba(3, 105, 161, 0.14);
  border-color: var(--d-accent);
  color: var(--d-accent);
  font-weight: 650;
}

/* ---------- collecting runs ---------- */

/* Numbered, because the order IS the plan — an unnumbered line through forty
   sites says where but not in what sequence.

   Deliberately colourless. Violet was the first choice and was wrong: it was
   the rest-area POI at the time, which now has a layer of its own and would
   have put violet dots and violet badges on the same road. Rest has since gone
   blue and violet is free again — but every hue here is spoken for by
   something, so these still carry none at all and let the numeral do the work,
   which is the one thing no other marker on this map has. */
.collect-hit { display: grid; place-items: center; background: none; border: 0; }

.collect-pin {
  display: grid;
  place-items: center;
  width: 20px;
  height: 20px;
  font: 700 10px/1 system-ui, sans-serif;
  color: #fff;
  background: #1e293b;
  border: 1.5px solid #f8fafc;
  border-radius: 50%;
  box-shadow: 0 1px 5px rgba(15, 23, 42, 0.45);
}

/* The run whose 24-hour clock is still ticking. It is the only row you can
   still do anything about, so it is the only one marked. */
dialog.drawer .charges-table tr.run-live td {
  background: rgba(34, 197, 94, 0.12);
  font-weight: 650;
}

/* ---------- the login screen ---------- */

/* The GRC front door. Structure AND palette come from grc-todo and
   libre-nomnom, so the three apps open the same way — the first version copied
   the markup but kept Milemark's blues, and matching the bones without the skin
   turned out to look like neither.
   
   The values below were read off the running grc-todo rather than guessed, and
   they are a GitHub-ish neutral grey system: #fafbfc paper, #d0d7de rules,
   #1f2328 ink, #656d76 for anything secondary. Milemark's own palette is a
   colder blue-grey and is deliberately NOT used here.
   
   They are scoped to .login-screen rather than :root on purpose. The front door
   is shared; the app behind it is this app's own, and grc-todo's app UI does not
   look like libre-nomnom's either. Only the way in matches. */
.login-screen {
  --grc-bg: #fafbfc;
  --grc-surface: #ffffff;
  --grc-surface-2: #f6f8fa;
  --grc-border: #d0d7de;
  --grc-border-strong: #afb8c1;
  --grc-text: #1f2328;
  --grc-muted: #656d76;
  --grc-success: #1a7f37;

  display: none;
  position: fixed;
  inset: 0;
  z-index: 4000;
  width: 100%;
  height: 100vh;
  height: 100dvh;
  overflow-y: auto;
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
  font-family: -apple-system, "system-ui", "Segoe UI", system-ui, sans-serif;
  color: var(--grc-text);
  background: linear-gradient(180deg, #fafbfc 0%, #f6f8fa 60%, #eef1f4 100%);
}

body.locked { overflow: hidden; }

.landing {
  max-width: 1240px;
  margin: 0 auto;
  padding: 22px 18px 28px;
  display: flex;
  flex-direction: column;
  gap: 20px;
  min-height: 100vh;
  box-sizing: border-box;
}

.landing-top {
  display: grid;
  grid-template-columns: minmax(360px, 1fr) minmax(420px, 1.1fr);
  gap: 40px;
  align-items: center;
  flex: 0 0 auto;
  min-height: calc(100vh - 80px);
}

.landing-hero {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
  text-align: left;
}

.landing-logo {
  width: 64px;
  height: 64px;
  object-fit: contain;
  border-radius: 14px;
  box-shadow: 0 4px 14px rgba(31, 35, 40, 0.10);
  background: var(--grc-surface);
  padding: 3px;
}

/* The eyebrow takes the APP's accent, not a shared one — grc-todo's is its
   coral, and this one is Milemark's sky blue. It is the single place the front
   door says which app you are opening. */
.landing-brand {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--behind-ink);
}

.landing-headline {
  margin: 0;
  font-size: 28px;
  line-height: 1.1;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--grc-text);
}

.landing-subhead {
  margin: 0;
  font-size: 15px;
  line-height: 1.5;
  color: var(--grc-muted);
}
.landing-subhead em { font-style: italic; }

.landing-cta {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-top: 10px;
  width: 100%;
  max-width: 380px;
}

.landing-cta-divider {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 12px;
  color: var(--grc-muted);
}
.landing-cta-divider::before,
.landing-cta-divider::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--grc-border);
}

/* One column, not grc-todo's three: that app offers Microsoft, Apple and
   Email, this one offers Microsoft. A lone button stretched across a 3-column
   grid reads as two that failed to load. */
.landing-cta-secondary { display: grid; grid-template-columns: 1fr; gap: 8px; }

.login-btn {
  padding: 11px 18px;
  border: 1px solid var(--grc-border);
  border-radius: 8px;
  background: var(--grc-surface);
  color: var(--grc-text);
  font-size: 14px;
  font-weight: 500;
  font-family: inherit;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
}
.login-btn:hover { background: var(--grc-surface-2); }

/* One dominant button, the rest demoted beneath the divider. */
.login-btn-primary {
  width: 100%;
  padding: 14px 18px;
  font-size: 15px;
  font-weight: 600;
  border-color: var(--grc-border-strong);
  box-shadow: 0 2px 8px rgba(31, 35, 40, 0.10);
}
.login-btn-primary:hover {
  background: var(--grc-surface);
  box-shadow: 0 5px 16px rgba(31, 35, 40, 0.16);
}

.login-btn-sm { padding: 9px 8px; font-size: 13px; font-weight: 500; gap: 7px; }

.landing-trust {
  list-style: none;
  margin: 14px 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 7px 16px;
}
.landing-trust li {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12.5px;
  color: var(--grc-muted);
}
.landing-trust li::before {
  content: '✓';
  color: var(--grc-success);
  font-weight: 700;
  font-size: 12px;
}

.login-screen .msg { font-size: 13px; color: var(--grc-muted); }
.login-screen .msg.error { color: #cf222e; }

.landing-shot-wrap { display: flex; justify-content: center; }
.landing-shot {
  width: 100%;
  max-width: 480px;
  height: auto;
  border-radius: 14px;
  border: 1px solid var(--grc-border);
  box-shadow: 0 12px 34px rgba(31, 35, 40, 0.12);
}

/* One column on a phone, picture first — it explains the app faster than the
   headline does. Same breakpoint behaviour as the other two. */
@media (max-width: 860px) {
  .landing { padding: 18px 16px 24px; }
  .landing-top {
    grid-template-columns: 1fr;
    gap: 22px;
    min-height: 0;
    padding: 8px 0 20px;
  }
  .landing-shot-wrap { order: -1; }
  .landing-headline { font-size: 25px; }
  .landing-cta { max-width: none; }
}

/* ---------- street view, and moving data between origins ---------- */

/* Small enough not to push the actions out of a popup, big enough to tell a
   truck stop from a gravel pull-off — which is the only question it is there
   to answer. */
.charger-pop .sv-btn,
dialog.drawer .sv-btn {
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.charger-pop .pop-sv {
  width: 100%;
  height: 150px;
  border: 1px solid var(--border);
  border-radius: 8px;
  margin: 2px 0 4px;
  display: block;
}

dialog.drawer .mini-check {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-right: auto;
  font-size: 11.5px;
  color: var(--d-muted, var(--muted));
  white-space: nowrap;
}
dialog.drawer .mini-check input { margin: 0; }

/* ---------- state of charge along the road ---------- */

/* A reading, not a warning — so a circle rather than the squares and pills the
   rest of the map uses, and no exclamation about it. The colour carries the
   only judgement: green while there is margin, amber at the 20% reserve, red
   below it. Those are the same three states reachAt() returns for the table and
   the bands, so a bubble cannot disagree with the road it sits on. */
.soc-hit { display: grid; place-items: center; background: none; border: 0; }

.soc-bubble {
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  font: 700 10.5px/1 ui-sans-serif, -apple-system, sans-serif;
  color: #fff;
  border-radius: 50%;
  border: 2px solid #ffffff;
  box-shadow: 0 2px 7px rgba(15, 23, 42, 0.4);
  background: #16a34a;
}

/* No % sign. At 26px it costs a third of the width to say something the
   surrounding context already says, and dropping it is what lets the number
   stay legible at this size. */
.soc-bubble.reserve { background: #d97706; }
.soc-bubble.out { background: #dc2626; }

/* ---------- passport clusters ---------- */

/* The number is what you are hunting: how many sites are LEFT in that pocket.
   A cluster with nothing left goes green and shows its visited count instead —
   not a target, a trophy. Three sizes so a glance across a continent ranks the
   metros without reading a single number. */
.pass-cluster-hit { display: grid; place-items: center; background: none; border: 0; }

.pass-cluster {
  display: grid;
  place-items: center;
  min-width: 26px;
  height: 26px;
  padding: 0 5px;
  font: 700 11px/1 ui-sans-serif, -apple-system, sans-serif;
  color: #16202e;
  background: #ffffff;
  border: 2px solid #334155;
  border-radius: 999px;
  box-shadow: 0 2px 8px rgba(15, 23, 42, 0.35);
  cursor: pointer;
}
.pass-cluster.lg { min-width: 32px; height: 32px; font-size: 12px; }
.pass-cluster.xl { min-width: 38px; height: 38px; font-size: 13px; border-width: 3px; }

.pass-cluster.done {
  color: #ffffff;
  background: #22c55e;
  border-color: #14532d;
}

/* The hunt summary is two facts on two lines: what today costs, and what the
   whole radius costs. The second is smaller because it is the slower decision. */
dialog.drawer #collect-note { display: grid; gap: 2px; }
dialog.drawer .collect-job { font-size: 11.5px; color: var(--d-muted, var(--muted)); }
