* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html, body {
  height: 100%;
  font-family: -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
}

/* The bus camera pans the map pane by fractional pixels. Without this hint
   Chrome re-rasters the whole pane on every fractional move (~18% of frames
   dropped in testing); with it the pane is just re-composited on the GPU. */
.leaflet-map-pane {
  will-change: transform;
}

#map {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 226px;
  transition: bottom 0.8s ease-in-out;
}

body.panel-collapsed #map {
  bottom: 76px;
}

.collapse-strip {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 210px;
  height: 16px;
  background: #7c3aed; /* same purple as the control bar accent */
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 501;
  transition: transform 0.8s ease-in-out;
}

body.panel-collapsed .collapse-strip {
  /* Follows the control bar down by exactly the chart panel's height,
     so the strip stays flush against the control bar's top edge. */
  transform: translateY(150px);
}

.collapse-strip-btn {
  border: none;
  background: none;
  color: #ffffff;
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
  transform: rotate(90deg);
  transition: transform 0.15s ease;
}

.collapse-strip-btn.collapsed {
  transform: rotate(-90deg);
}

.bottom-panel {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 210px;
  display: flex;
  flex-direction: column;
  z-index: 500;
}

.control-bar {
  flex: 0 0 60px;
  background: #fff;
  border-top: 3px solid #7c3aed;
  display: flex;
  align-items: center;
  gap: 18px;
  padding: 0 16px;
  box-shadow: 0 -2px 6px rgba(0, 0, 0, 0.08);
  overflow: hidden;
  transition: transform 0.8s ease-in-out;
}

body.panel-collapsed .control-bar {
  /* Slides down into the space the (now fully hidden) chart panel vacates,
     landing flush against the bottom of the viewport. */
  transform: translateY(150px);
}

.icon-btn {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  border: none;
  background: #f1eafe;
  color: #7c3aed;
  font-size: 16px;
  cursor: pointer;
  flex: 0 0 auto;
}

.play-btn {
  background: #7c3aed;
  color: #fff;
  font-size: 14px;
}

.play-btn.playing::before {
  content: "";
}

#speedSlider {
  flex: 0 0 220px;
  accent-color: #7c3aed;
}

.readout {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 6px;
  flex: 0 0 auto;
  white-space: nowrap;
}

.readout-label {
  font-size: 11px;
  color: #6b7280;
}

.readout-value {
  display: inline-block;
  font-size: 12px;
  font-weight: 600;
  color: #111827;
  background: #f3f4f6;
  padding: 2px 8px;
  border-radius: 6px;
  text-align: center;
}

/* Fixed widths so these don't reflow the whole bar as playback numbers
   grow/shrink digits (e.g. "0 kmph" -> "38 kmph"). */
#curSpeed {
  min-width: 62px;
}

#curDistance {
  min-width: 70px;
}

#curTime {
  min-width: 150px;
}

.chip .readout-value {
  background: #f1eafe;
  color: #111827;
}

.chart-panel {
  flex: 1 1 150px;
  background: #fff;
  border-top: 1px solid #e5e7eb;
  padding: 8px 16px;
  min-height: 0;
}

/* While the opening flight is still under way, the chart is built (and would
   otherwise be hoverable) before the route/markers it seeks the bus along are
   actually drawn. Dimmed + a blocked cursor signals hover won't do anything
   yet, instead of it silently looking broken. */
.chart-not-ready {
  opacity: 0.5;
  cursor: not-allowed;
}

.chart-not-ready canvas {
  pointer-events: none;
}

.leaflet-popup-content {
  font-size: 13px;
  line-height: 1.5;
}

/* Stoppage popup: a card with a purple header (same accent as the control bar),
   the parked time as the headline figure, then arrival/departure and the
   since-last-stop numbers. */
.stop-popup .leaflet-popup-content-wrapper {
  padding: 0;
  border-radius: 12px;
  overflow: hidden;
  box-shadow: 0 12px 32px rgba(15, 23, 42, 0.28), 0 2px 6px rgba(15, 23, 42, 0.12);
}

.stop-popup .leaflet-popup-content {
  margin: 0;
  font-size: 12px;
  line-height: 1.35;
}

.leaflet-container .stop-popup a.leaflet-popup-close-button {
  top: 8px;
  right: 8px;
  width: 22px;
  height: 22px;
  padding: 0;
  border-radius: 50%;
  font: 16px/20px -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
  text-align: center;
  color: rgba(255, 255, 255, 0.9);
  transition: background 0.15s ease;
}

.leaflet-container .stop-popup a.leaflet-popup-close-button:hover {
  color: #fff;
  background: rgba(255, 255, 255, 0.2);
}

/* Overlapping-marker chooser: shown instead of a detail popup when a click
   lands on more than one marker at once (arrow/stop/flag stacked together). */
.marker-picker-popup .leaflet-popup-content-wrapper {
  padding: 0;
  border-radius: 12px;
  overflow: hidden;
  box-shadow: 0 12px 32px rgba(15, 23, 42, 0.28), 0 2px 6px rgba(15, 23, 42, 0.12);
}

.marker-picker-popup .leaflet-popup-content {
  margin: 0;
}

.marker-picker {
  display: flex;
  flex-direction: column;
  font-family: -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
}

.marker-picker-title {
  padding: 9px 12px;
  background: linear-gradient(135deg, #334155 0%, #0f172a 100%);
  color: #fff;
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.02em;
}

.marker-picker-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 9px 12px;
  border: none;
  border-bottom: 1px solid #f1f5f9;
  background: #fff;
  color: #111827;
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  text-align: left;
  cursor: pointer;
  transition: background 0.15s ease;
}

.marker-picker-item::after {
  content: "\2192";
  margin-left: auto;
  color: #94a3b8;
}

.marker-picker-item:last-child {
  border-bottom: none;
}

.marker-picker-item:hover,
.marker-picker-item:focus-visible {
  background: #f8fafc;
}

.sp {
  font-family: -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
  color: #111827;
  font-variant-numeric: tabular-nums;
}

.sp-header {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 36px 9px 12px;
  background: linear-gradient(135deg, #7c3aed 0%, #5b21b6 100%);
  color: #fff;
}

.sp-badge {
  flex: none;
  display: grid;
  place-items: center;
  min-width: 26px;
  height: 26px;
  padding: 0 5px;
  border-radius: 13px;
  background: #fff;
  color: #6d28d9;
  font-weight: 700;
  font-size: 12.5px;
}

.sp-heading {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.sp-title {
  font-size: 13.5px;
  font-weight: 600;
  letter-spacing: 0.01em;
}

.sp-subtitle {
  font-size: 11px;
  color: rgba(255, 255, 255, 0.78);
}

.sp-hero {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  padding: 7px 12px;
  background: #f5f3ff;
  border-bottom: 1px solid #ede9fe;
}

.sp-hero-label {
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #6d28d9;
}

.sp-hero-value {
  font-size: 17px;
  font-weight: 700;
  color: #4c1d95;
}

.sp-times {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 6px;
  padding: 9px 12px;
}

.sp-time {
  display: flex;
  flex-direction: column;
}

.sp-time:last-child {
  text-align: right;
}

.sp-label {
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #6b7280;
}

.sp-clock {
  margin-top: 1px;
  font-size: 14.5px;
  font-weight: 600;
}

.sp-day {
  font-size: 11px;
  color: #6b7280;
}

.sp-to {
  color: #a78bfa;
  font-size: 15px;
}

.sp-stats {
  border-top: 1px solid #f1f5f9;
}

/* Direction-arrow popup: same card, blue accent to match the route line. */
.sp-direction .sp-header {
  background: linear-gradient(135deg, #2563eb 0%, #1e3a8a 100%);
}

.sp-direction .sp-badge {
  color: #2563eb;
}

.sp-direction .sp-hero {
  background: #eff6ff;
  border-bottom-color: #dbeafe;
}

.sp-direction .sp-hero-label {
  color: #1d4ed8;
}

.sp-direction .sp-hero-value {
  color: #1e3a8a;
}

.leaflet-container .sp-direction .sp-link {
  color: #1d4ed8;
}

.sp-stats > div {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  padding: 5px 12px;
  border-bottom: 1px solid #f1f5f9;
}

.sp-stats dt {
  color: #4b5563;
  font-size: 11.5px;
}

.sp-stats dd {
  margin: 0;
  font-weight: 600;
  white-space: nowrap;
}

.sp-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 6px 12px;
  background: #f8fafc;
}

.sp-coords {
  font: 11px ui-monospace, Consolas, monospace;
  color: #64748b;
  white-space: nowrap;
}

.leaflet-container .sp-link {
  font-size: 11.5px;
  font-weight: 600;
  color: #6d28d9;
  text-decoration: none;
  white-space: nowrap;
}

.leaflet-container .sp-link:hover {
  text-decoration: underline;
}

.arrow-icon,
.flag-icon,
.bus-icon {
  background: transparent;
  border: none;
}

/* Direction arrow: navy disc, white rim and soft shadow so it reads on top of the
   blue route line and on any tile colour. */
.arrow-badge {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  box-sizing: border-box;
  border: 2px solid #ffffff;
  border-radius: 50%;
  background: #1e3a8a;
  box-shadow: 0 1px 3px rgba(15, 23, 42, 0.45);
  transition: background-color 0.15s ease;
}

.arrow-icon:hover .arrow-badge {
  background: #2563eb;
}

/* Flags, stop pins and arrows follow the zoom level: each icon sets --zs to its
   kind's scale (--flag-scale / --stop-scale / --arrow-scale, set on the map container). */
.zoom-scale {
  transform: scale(var(--zs, 1));
  transform-origin: var(--ox) var(--oy);
  transition: transform 0.25s ease-out;
}

.stop-pin:hover svg {
  filter: brightness(1.1);
}

/* Opening reveal: arrows, flags and stop pins pop in one after another (delay set
   inline per marker) as the route line is drawn in. The class is on the map only
   while it plays. Flags and pins grow from their foot (--ox / --oy). */
.route-reveal .arrow-inner {
  animation: arrow-pop-in 0.35s ease-out both;
}

.route-reveal .marker-pop {
  transform-origin: var(--ox) var(--oy);
  animation: marker-pop-in 0.45s cubic-bezier(0.34, 1.56, 0.64, 1) both;
}

@keyframes marker-pop-in {
  from {
    opacity: 0;
    transform: scale(0);
  }
  to {
    opacity: 1;
    transform: scale(1);
  }
}

@keyframes arrow-pop-in {
  from {
    opacity: 0;
    transform: scale(0.3);
  }
  to {
    opacity: 1;
    transform: scale(1);
  }
}

/* Card shown over the map while the playback data is loading: a bus
   bobbing along a moving dashed road. */
.loading-indicator {
  position: absolute;
  top: 16px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 1000; /* above Leaflet panes and controls */
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 7px 14px 8px;
  background: #fff;
  color: #374151;
  font-size: 12px;
  border-radius: 12px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25);
}

.loading-indicator.hidden {
  display: none;
}

.loading-scene {
  width: 86px;
  height: 26px;
  position: relative;
  overflow: hidden;
}

.loading-bus {
  position: absolute;
  left: 23px;
  top: 0;
  animation: loading-bob 0.5s ease-in-out infinite alternate;
}

.loading-road {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 3px;
  background: repeating-linear-gradient(90deg, #9ca3af 0 12px, transparent 12px 22px);
  background-size: 22px 3px;
  animation: loading-road 0.45s linear infinite;
}

@keyframes loading-bob {
  from { transform: translateY(0); }
  to { transform: translateY(-2px); }
}

@keyframes loading-road {
  to { background-position-x: -22px; }
}

/* ── Toast notifications ─────────────────────────────────────────────── */
.toast-container {
  position: fixed;
  bottom: 16px; /* sits over the bottom panel (z-index), so collapsing it doesn't move the toast */
  left: 50%;
  transform: translateX(-50%);
  z-index: 2000; /* above the loader and Leaflet */
  display: flex;
  flex-direction: column-reverse; /* newest toast nearest the bottom */
  gap: 10px;
  width: min(420px, calc(100vw - 24px));
  pointer-events: none;
}

.toast {
  --toast-color: #dc2626;
  --toast-bg: #fef2f2;
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 12px 10px 12px 14px;
  background: #fff;
  border-left: 4px solid var(--toast-color);
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18), 0 2px 6px rgba(0, 0, 0, 0.1);
  pointer-events: auto;
  animation: toast-in 0.25s ease-out;
}

.toast-warning { --toast-color: #d97706; --toast-bg: #fffbeb; }
.toast-info { --toast-color: #2563eb; --toast-bg: #eff6ff; }

.toast-out {
  animation: toast-out 0.2s ease-in forwards;
}

.toast-icon {
  flex: none;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--toast-bg);
  color: var(--toast-color);
  font-size: 13px;
  font-weight: 700;
  line-height: 22px;
  text-align: center;
}

.toast-body {
  flex: 1;
  min-width: 0;
}

.toast-title {
  font-size: 14px;
  font-weight: 600;
  color: #111827;
}

.toast-message {
  margin-top: 2px;
  font-size: 13px;
  line-height: 1.4;
  color: #4b5563;
  overflow-wrap: anywhere;
}

.toast-close {
  flex: none;
  width: 24px;
  height: 24px;
  border: 0;
  border-radius: 4px;
  background: transparent;
  color: #9ca3af;
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
}

.toast-close:hover {
  background: #f3f4f6;
  color: #374151;
}

@keyframes toast-in {
  from { opacity: 0; transform: translateY(12px); }
  to { opacity: 1; transform: translateY(0); }
}

@keyframes toast-out {
  to { opacity: 0; transform: translateY(12px); }
}
