/* Train Station Density
 * Visual language adapted from the NSA Hub style guide.
 * Two-column shell: left panel + right content (tabs floating over map / chart view).
 */

:root {
  /* Surface */
  --bg:           #f3efe8;
  --ink:          #1e1c16;
  --muted:        #6c655d;

  /* Panel + cards */
  --panel:        rgba(241, 237, 246, 0.95);
  --panel-solid:  #f1edf6;
  --map-border:   #c7bfd2;
  --rule:         rgba(30, 28, 22, 0.08);

  /* Accents */
  --accent:       #d65a31;
  --accent-fg:    #ffffff;

  /* Active button (lavender pill) */
  --btn-active-bg:           #b9a7d5;
  --btn-active-border:       #8569b4;
  --btn-active-text:         #1f1430;
  --btn-active-hover-border: #744aa8;

  /* Mint */
  --mint-base:    #2f6d66;
  --mint-strong:  #226534;
  --mint-edge:    rgba(124, 186, 177, 0.55);

  /* Status */
  --status-bad-bg:   #fff1ef;
  --status-bad-edge: #e4a69c;
  --status-bad-fg:   #8f2f21;

  /* Shadows */
  --shadow:       0 18px 40px rgba(37, 33, 28, 0.18);
  --shadow-pop:   0 12px 24px rgba(35, 28, 20, 0.18);

  /* Type */
  --font-sans:    "Space Grotesk", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --font-serif:   "Source Serif 4", "Source Serif Pro", Georgia, serif;

  /* Radii */
  --r-sm:  8px;
  --r-md:  10px;
  --r-lg:  12px;

  color-scheme: light;
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; height: 100%; }
body {
  background: radial-gradient(circle at top left, #f9f4ea 0%, #efe6d7 45%, #f2ebe1 100%);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: 14px;
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

.noscript {
  position: fixed; inset: 1rem; padding: 1rem;
  background: var(--status-bad-bg); color: var(--status-bad-fg);
  border: 1px solid var(--status-bad-edge);
  border-radius: var(--r-md);
  z-index: 9999;
}

/* ---------- App shell ---------- */
.app {
  display: grid;
  grid-template-columns: minmax(260px, 300px) 1fr;
  height: 100vh;
  min-height: 100vh;
}

.panel {
  display: flex; flex-direction: column;
  gap: 22px;
  padding: 26px 22px;
  background: var(--panel-solid);
  border-right: 1px solid #d1cbdb;
  overflow-y: auto;
}

/* Brand: logo + multi-line eyebrow on its right */
.brand {
  display: flex; align-items: center;
  gap: 14px;
  margin-bottom: 2px;
}
.brand-logo {
  width: 100px; height: auto;
  display: block; flex-shrink: 0;
}
.brand-tag {
  margin: 0;
  font-size: 10.5px; font-weight: 700;
  letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--muted);
  line-height: 1.4;
}

/* Title */
.panel-title { display: flex; flex-direction: column; }
.panel-title h1 {
  margin: 0;
  font-family: var(--font-serif);
  font-size: 28px; font-weight: 600;
  line-height: 1.1;
}
.panel-title .subhead {
  margin: 10px 0 0;
  font-size: 13px; line-height: 1.55;
  color: var(--muted);
}

/* Section */
.control-group { display: flex; flex-direction: column; gap: 10px; }
.control-group[hidden] { display: none !important; }  /* parked sections (Stories) */
.section-label {
  margin: 0;
  font-size: 13px; font-weight: 600;
  color: var(--ink);
}

/* Layer pill toggles */
.layer-list { display: flex; flex-direction: column; gap: 8px; }
.layer-list--cols {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 6px;
}
.layer-pill {
  position: relative;
  display: flex; align-items: center; justify-content: center;
  padding: 8px 10px;
  border: 1px solid var(--map-border);
  border-radius: 8px;
  background: #fff;
  font-size: 12px; font-weight: 600;
  color: var(--ink);
  cursor: pointer;
  white-space: nowrap;
  text-overflow: ellipsis;
  overflow: hidden;
  transition: background-color 120ms ease, border-color 120ms ease, color 120ms ease;
}
/* `.layer-pill { display:flex }` outranks the UA `[hidden]{display:none}`, so the
   JS-set `hidden` on the Jobs pill was ignored — force it. */
.layer-pill[hidden] { display: none !important; }
/* "Seeable but not clickable" — a layer the active country lacks (e.g. Jobs in
   IL/BE) stays visible but greyed, mirroring the mode chips' .is-absent rule. */
.layer-pill.is-disabled { opacity: 0.4; cursor: not-allowed; }
.layer-pill:not(.is-disabled):hover { border-color: var(--accent); }
.layer-pill:has(input:checked) {
  background: var(--btn-active-bg);
  border-color: var(--btn-active-border);
  color: var(--btn-active-text);
}
.layer-pill:has(input:checked):hover { border-color: var(--btn-active-hover-border); }
.layer-pill:has(input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; }
.layer-pill input[type="checkbox"] {
  position: absolute;
  opacity: 0; pointer-events: none;
  width: 0; height: 0;
}

/* Inline filter checkbox under Buildings / Heatmap radios.  */
.layer-pill--inline {
  margin-top: 8px;
  padding: 6px 10px;
  font-size: 11px;
  background: rgba(255, 255, 255, 0.55);
}

/* Segmented mode toggle (Buildings, chart type, bar metric, etc.) */
.mode-toggle {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(0, 1fr);
  gap: 6px;
}
/* 2-column variant — used by sections with 4 modes (e.g. Population) */
.mode-toggle--grid2 {
  grid-auto-flow: row;
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
.mode-btn {
  padding: 8px 10px;
  border: 1px solid var(--map-border);
  border-radius: 8px;
  background: #fff;
  font-family: inherit;
  font-size: 12px; font-weight: 600;
  color: var(--ink);
  cursor: pointer;
  white-space: nowrap;
  text-overflow: ellipsis;
  overflow: hidden;
  transition: background-color 120ms ease, border-color 120ms ease, color 120ms ease;
}
.mode-btn:hover { border-color: var(--accent); }
.mode-btn.active {
  background: var(--btn-active-bg);
  border-color: var(--btn-active-border);
  color: var(--btn-active-text);
}
.mode-btn.active:hover { border-color: var(--btn-active-hover-border); }
.mode-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Station-type filter — a wrapping chip strip (All + 4 archetypes). Overrides
   the single-row .mode-toggle grid so chips flow onto multiple lines; "All
   types" spans the full width as the reset. Slightly smaller text than the
   standard mode-btn so the labels fit two-per-row. */
.station-type-toggle {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.station-type-toggle .mode-btn {
  flex: 1 1 calc(50% - 3px);
  padding: 6px 8px;
  font-size: 11px;
}
.station-type-toggle .mode-btn[data-station-type="all"] { flex-basis: 100%; }

/* Chart-type buttons outside the active view tab's group are hidden. */
.chart-btn-hidden { display: none !important; }

/* Clear-overlays utility button: subtle, full-width, sits at the bottom of
   the sidebar above the About link. */
.clear-btn {
  width: 100%;
  padding: 8px 12px;
  border: 1px dashed var(--map-border);
  border-radius: 8px;
  background: transparent;
  font-family: inherit;
  font-size: 12px; font-weight: 600;
  color: var(--muted);
  cursor: pointer;
  transition: background-color 120ms ease, border-color 120ms ease, color 120ms ease;
}
.clear-btn:hover {
  background: rgba(255, 255, 255, 0.6);
  border-color: var(--accent);
  border-style: solid;
  color: var(--ink);
}
.clear-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Country switcher — sits below the other section toggles, with its own
   centred header. Buttons aligned (no zigzag) and the same size as the
   .mode-btn used elsewhere in the sidebar — consistent control feel. */
.country-switcher-wrap {
  margin-top: 30px;
  padding: 0 12px 4px;
  display: flex;
  flex-direction: column;
  align-items: stretch;
}
.country-switcher-header {
  margin: 0 0 10px;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink);
  text-align: center;
}
/* 3+ countries: stack vertically so labels never truncate on a narrow
   sidebar. Each button takes the full column width. */
.country-switcher {
  grid-auto-flow: row;
  grid-auto-columns: unset;
  grid-template-columns: 1fr;
  gap: 6px;
}
/* "Explore by" Country/Metro toggle above the entity chips. */
.scope-strip {
  display: flex; gap: 6px;
  margin-bottom: 10px;
}
.scope-strip .mode-btn { flex: 1; }
.entity-strip[hidden] { display: none; }
/* Metro chips: wrapping strip, each with a country-coloured left accent so
   the metros group visually by network. */
.metro-switcher {
  display: flex; flex-wrap: wrap; gap: 6px;
  grid-template-columns: none;
}
.metro-switcher .mode-btn {
  flex: 1 1 calc(50% - 3px);
  border-left: 3px solid var(--chip-accent, transparent);
}
.scope-hint {
  margin: 6px 2px 0;
  font-size: 10.5px;
  color: var(--muted);
  text-align: center;
}
.scope-hint[hidden] { display: none; }
/* Small "?" help next to the chart-tab scope toggle. */
.scope-help {
  display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 18px; margin-left: 8px;
  border-radius: 50%;
  border: 1px solid var(--rule);
  font-size: 11px; font-weight: 700; color: var(--muted);
  cursor: help; user-select: none;
}
.scope-help:hover { border-color: var(--accent); color: var(--accent); }
.mode-btn.is-loading { cursor: progress; opacity: 0.65; }
.mode-btn.is-loading::after {
  content: '';
  display: inline-block;
  width: 8px; height: 8px; margin-left: 6px;
  border: 1.5px solid currentColor; border-top-color: transparent;
  border-radius: 50%;
  vertical-align: -1px;
  animation: mode-btn-spin 700ms linear infinite;
}
@keyframes mode-btn-spin { to { transform: rotate(360deg); } }

/* Bottom panel links — textual mint underline, pinned to bottom */
.panel-links {
  margin-top: auto;
  display: flex; flex-direction: column; gap: 6px;
  align-items: flex-start;
}
.panel-links a {
  padding: 0; background: none; border: none;
  font-family: inherit;
  font-size: 13px; font-weight: 600;
  color: var(--mint-base);
  text-decoration: underline; text-underline-offset: 3px;
  cursor: pointer;
  transition: color 120ms ease;
}
.panel-links a:hover { color: var(--mint-strong); }

/* ---------- Right content ---------- */
.content {
  position: relative;
  height: 100vh;
  min-width: 0;
}

/* Tabs float over the active view, top-left, like the reference app */
.view-tabs {
  position: absolute;
  top: 22px; left: 24px;
  z-index: 1000;
  display: flex; gap: 6px;
}
.view-tab {
  padding: 7px 18px;
  border: 1px solid var(--map-border);
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.92);
  font-family: inherit;
  font-size: 12.5px; font-weight: 600;
  color: var(--ink);
  cursor: pointer;
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  box-shadow: 0 4px 10px rgba(35, 28, 20, 0.08);
  transition: background 120ms ease, border-color 120ms ease, color 120ms ease;
}
.view-tab:hover { border-color: var(--accent); }
.view-tab.active {
  background: var(--btn-active-bg);
  border-color: var(--btn-active-border);
  color: var(--btn-active-text);
}
.view-tab:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.view {
  position: absolute;
  inset: 10px;
}
.view[hidden] { display: none; }

/* ---------- Map view ---------- */
.map-frame {
  position: absolute; inset: 0;
  border-radius: 14px; overflow: hidden;
  box-shadow: var(--shadow);
  background: var(--bg);
}
#map { position: absolute; inset: 0; }

/* Loader */
#loader {
  position: absolute; inset: 0; z-index: 1100;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 16px;
  background: var(--bg);
  transition: opacity 0.4s ease-out;
}
#loader.hide { opacity: 0; pointer-events: none; }
.spinner {
  width: 44px; height: 44px; border-radius: 50%;
  border: 3px solid var(--rule); border-top-color: var(--accent);
  animation: spin 0.9s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
#loader-text {
  margin: 0;
  font-size: 13px; font-weight: 400;
  color: var(--muted); letter-spacing: 0.01em;
}

/* Floating stats card (top-right) — same frosted-glass aesthetic as
   the legend.  Mirrors the chart-tab summary banner for the active
   country plus two extras (total area + total population). */
/* Top-right column holding the stats card + the density-compare card.
   60 px right keeps it clear of Leaflet's zoom +/− buttons. */
.map-cards {
  position: absolute;
  right: 60px; top: 16px;
  z-index: 900;
  width: 220px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.map-stats {
  width: 100%;
  padding: 12px 14px 14px;
  background: var(--panel);
  border: 1px solid var(--map-border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-pop);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  font-family: var(--font-sans);
  font-size: 11px;
  color: var(--muted);
}
/* Density compare card — same frosted aesthetic, sits under the stats card. */
.map-typecard {
  width: 100%;
  padding: 12px 14px 12px;
  background: var(--panel);
  border: 1px solid var(--map-border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-pop);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  font-family: var(--font-sans);
  color: var(--muted);
}
.map-typecard .map-stats-header { margin-bottom: 6px; }
.map-typecard-title { margin: 0; font-size: 13px; font-weight: 700; color: var(--ink); letter-spacing: -0.01em; }
.map-typecard.is-collapsed .map-typecard-body { display: none; }
.map-typecard.is-collapsed { padding-bottom: 10px; }
.map-typecard.is-collapsed .map-stats-header { margin-bottom: 0; }
.map-typecard-empty { font-size: 11px; padding: 4px 0 2px; }
.tc-scope { font-size: 10px; color: var(--muted); margin-bottom: 2px; }
.tc-note { font-size: 11px; font-weight: 600; color: var(--ink); margin-top: 3px; }
/* Per-mode density blocks (one per active mode) — cap height + scroll so 4
   modes don't overrun the map. */
.map-typecard-body { max-height: 46vh; overflow-y: auto; }
.tc-scopehdr { font-size: 9px; text-transform: uppercase; letter-spacing: 0.05em; color: var(--muted); margin-bottom: 4px; }
.tc-modeblock + .tc-modeblock { margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--rule); }
.tc-modehdr { display: flex; align-items: center; gap: 5px; font-size: 11px; font-weight: 700; color: var(--ink); }
.tc-modedot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; }
.tc-moden { margin-left: auto; font-size: 9.5px; font-weight: 500; color: var(--muted); }
.typecard-svg { display: block; }
.typecard-svg .tc-rowlabel { font-size: 10px; fill: var(--ink); font-weight: 600; }
.typecard-svg .tc-med { font-size: 10px; fill: var(--ink); font-variant-numeric: tabular-nums; }
.typecard-svg .tc-tick { font-size: 9px; fill: var(--muted); }
.typecard-svg .tc-na { font-size: 10px; fill: var(--muted); }
.typecard-svg .tc-whisk { stroke: #8a8290; stroke-width: 1; }
.typecard-svg .tc-axis { stroke: #d8d2c4; stroke-width: 1; }
/* Distance label rotated tangent to a centrality ring — text only, no box,
   with a soft parchment halo for legibility over the basemap. The outer
   div-icon is positioned by Leaflet; the inner span carries the rotation. */
.cbd-ring-label {
  background: transparent !important;
  border: none !important;
}
.cbd-ring-text {
  position: absolute;
  display: inline-block;
  transform-origin: center;
  white-space: nowrap;
  font: 700 10px var(--font-sans);
  letter-spacing: 0.02em;
  color: #b04a1e;
  text-shadow:
    0 0 3px var(--bg), 0 0 3px var(--bg),
    0 0 2px var(--bg), 0 0 2px var(--bg);
}
/* Gentle CBD label for the centrality-band scaffolding on the map. */
.leaflet-tooltip.cbd-label {
  background: rgba(255,255,255,0.82) !important;
  border: none !important;
  box-shadow: none !important;
  padding: 0 4px !important;
  font-size: 10px !important;
  font-weight: 600;
  color: #b04a1e !important;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}
.map-stats-header {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px;
  margin-bottom: 10px;
}
.map-stats-name {
  margin: 0;
  font-size: 16px;
  font-weight: 700;
  letter-spacing: -0.01em;
}
.map-stats-collapse {
  width: 22px; height: 22px;
  padding: 0;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid var(--map-border);
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.6);
  color: var(--muted);
  font-size: 14px; line-height: 1;
  cursor: pointer;
  flex-shrink: 0;
  transition: background 120ms ease, color 120ms ease, border-color 120ms ease;
}
.map-stats-collapse:hover { background: #fff; color: var(--ink); border-color: var(--accent); }
.map-stats.is-collapsed .map-stats-grid { display: none; }
.map-stats.is-collapsed .map-stats-scope,
.map-stats.is-collapsed .map-stats-metros,
.map-stats.is-collapsed .map-stats-modes,
.map-stats.is-collapsed .map-stats-year { display: none; }
.map-stats.is-collapsed { padding-bottom: 10px; }
.map-stats.is-collapsed .map-stats-header { margin-bottom: 0; }
/* National / Metro scope toggle — compact two-button strip above the
   stats grid. Re-uses .mode-btn from the sidebar but shrinks padding
   so two buttons fit comfortably inside the stats card width. */
.map-stats-scope {
  display: flex; gap: 4px;
  margin-bottom: 10px;
}
.map-stats-scope .mode-btn {
  flex: 1;
  padding: 4px 6px;
  font-size: 11px;
  letter-spacing: 0;
}
/* IDF / Madrid (and any future country whose metro polygon equals its
   country/region polygon) — drop the National button entirely on the
   floating map-stats card and lock the Metro button on as a single
   "Region" indicator. Detected via the 1 %-delta rule in updateMapStats. */
.map-stats-scope.is-metro-only [data-scope="national"] { display: none; }
.map-stats-scope.is-metro-only [data-scope="metro"] {
  flex: 0 0 auto;
  background: var(--btn-active-bg);
  border-color: var(--btn-active-border);
  color: var(--btn-active-text);
  pointer-events: none;
  cursor: default;
}
/* Census-year toggle — same compact strip styling as the scope row,
   sitting directly below it. Populated dynamically from
   manifest.available_years; hidden when the active country ships only
   the one default year. */
.map-stats-year {
  display: flex; gap: 4px;
  margin-bottom: 10px;
}
.map-stats-year[hidden] { display: none; }
.map-stats-year .mode-btn {
  flex: 1;
  padding: 4px 6px;
  font-size: 11px;
  letter-spacing: 0;
}
/* Per-metropolitan picker — wrapping chip strip shown under the scope
   toggle when Metro scope is active and the active country has ≥2 metros. */
.map-stats-metros {
  display: flex; flex-wrap: wrap; gap: 4px;
  margin-bottom: 10px;
}
.map-stats-metros[hidden] { display: none; }
.map-stats-metros .mode-btn {
  flex: 1 1 auto;
  padding: 4px 8px;
  font-size: 11px;
  letter-spacing: 0;
}
/* Per-mode station counts line under the stats grid (Train N · Metro N ·
   LRT N) — keeps the headline grid heavy-rail while surfacing mode presence. */
.map-stats-modes {
  display: flex; flex-wrap: wrap; gap: 3px 12px;
  margin: 10px 0 0;
  font-size: 10.5px;
  font-weight: 600;
}
.map-stats-modes .mode-count { display: inline-flex; align-items: center; gap: 5px; white-space: nowrap; }
.map-stats-modes .mode-count::before {
  content: ""; width: 8px; height: 8px; border-radius: 50%; background: currentColor; opacity: 0.85;
}
.map-stats-modes .mode-count--train { color: var(--ink); }
.map-stats-modes .mode-count--metro { color: #7a1d24; }
.map-stats-modes .mode-count--lrt   { color: #c75d1c; }
.map-stats-modes .mode-count--tram  { color: #b8862f; }
/* Disabled population radios (Buildings / Heatmap when train mode hidden). */
.mode-btn.is-disabled, .mode-btn:disabled { opacity: 0.4; cursor: not-allowed; }
/* A mode the active country lacks: dashed outline marks it as not-in-this-
   network. Combined with :disabled (above) it's dimmed + unclickable. */
.mode-filter-toggle .mode-btn.is-absent { border-style: dashed; }
/* Transit-mode chips laid out in a 2-column grid so the full label (with its
   colour dot) is always readable rather than squeezed into one row. */
.mode-filter-toggle {
  display: grid;
  grid-auto-flow: row;                 /* override .mode-toggle's column flow */
  grid-template-columns: 1fr 1fr;      /* so 4 modes wrap to a 2×2 grid */
  gap: 6px;
}
.mode-filter-toggle .mode-btn { text-align: center; }
.mode-filter-toggle .mode-btn::before {
  content: ""; display: inline-block; width: 8px; height: 8px; border-radius: 50%;
  margin-right: 5px; vertical-align: middle;
}
.mode-filter-toggle .mode-btn[data-mode="train"]::before { background: #5a6473; }
.mode-filter-toggle .mode-btn[data-mode="metro"]::before { background: #7a1d24; }
.mode-filter-toggle .mode-btn[data-mode="lrt"]::before   { background: #c75d1c; }
.mode-filter-toggle .mode-btn[data-mode="tram"]::before  { background: #b8862f; }
/* Inactive mode chip: dim its dot too. */
.mode-filter-toggle .mode-btn:not(.active)::before { opacity: 0.35; }
/* Inline scope toggle inside the Chart-tab controls row (was its own
   `.compare-scope-row` at the top of the frame; relocated 2026-05 so
   the chips above can show both scopes simultaneously and no longer
   depend on the toggle). The .compare-summary now owns the 70 px top
   clearance for the absolute .view-tabs. */
.compare-chart-controls .map-stats-scope {
  margin-bottom: 0;
  flex: 0 0 auto;
}
/* Chart-tab control rows: Chart-type + Scope + Metric buttons share one
   size so the three rows line up. Slightly bigger than the sidebar
   default to read at the same weight as the larger chart fonts. */
.compare-chart-controls .mode-btn {
  padding: 8px 14px;
  font-size: 13px;
}
.compare-chart-controls .map-stats-scope .mode-btn {
  flex: 0 0 auto;
  padding: 8px 14px;
  font-size: 13px;
}
.map-stats-grid {
  margin: 0;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px 14px;
}
.map-stats-grid > div { min-width: 0; }
.map-stats-grid dt {
  font-size: 10px;
  color: var(--muted);
  white-space: nowrap;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.map-stats-grid dd {
  margin: 1px 0 0;
  font-size: 15px;
  font-weight: 700;
  color: var(--ink);
  letter-spacing: -0.01em;
}

/* Floating legend (bottom-left) */
/* Raw-data inspector toggle — small pill, bottom-right of the map. */
.map-raw-toggle {
  position: absolute;
  right: 16px; bottom: 16px;
  /* Above the legend (900). On narrow viewports the legend grows to
     calc(100% - 20px) and reaches under this pill; at an equal z-index the
     legend won it on DOM order and the button became unclickable. */
  z-index: 901;
  padding: 7px 12px;
  font-family: inherit; font-size: 12px; font-weight: 600;
  color: var(--ink);
  background: var(--panel);
  border: 1px solid var(--map-border);
  border-radius: 999px;
  box-shadow: var(--shadow-pop);
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
  cursor: pointer;
  transition: background-color 120ms ease, border-color 120ms ease, color 120ms ease;
}
.map-raw-toggle:hover { border-color: var(--accent); }
.map-raw-toggle.is-on {
  background: var(--btn-active-bg);
  border-color: var(--btn-active-border);
  color: var(--btn-active-text);
}
/* Population/Jobs source toggle for the raw-data inspector — sits just above the
   Raw data button, shown only while the inspector is on in a jobs country. */
.map-raw-metrics {
  position: absolute;
  right: 16px; bottom: 58px;
  z-index: 901;   /* same reason as .map-raw-toggle */
  display: flex; gap: 4px;
  padding: 3px;
  background: var(--panel);
  border: 1px solid var(--map-border);
  border-radius: 999px;
  box-shadow: var(--shadow-pop);
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
}
.map-raw-metrics[hidden] { display: none !important; }
.map-raw-metrics .mode-btn { font-size: 11px; padding: 4px 10px; }
.map-legend {
  position: absolute;
  left: 16px; bottom: 16px;
  z-index: 900;
  width: 360px; max-width: calc(100% - 32px);
  padding: 12px 16px 14px;
  background: var(--panel);
  border: 1px solid var(--map-border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-pop);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}
.map-legend-header {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px;
  margin-bottom: 10px;
}
.map-legend .legend-title {
  margin: 0;
  font-size: 11px; font-weight: 700;
  letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--muted);
}
.legend-collapse {
  width: 22px; height: 22px;
  padding: 0;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid var(--map-border);
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.6);
  color: var(--muted);
  font-size: 14px; line-height: 1;
  cursor: pointer;
  flex-shrink: 0;
  transition: background 120ms ease, color 120ms ease, border-color 120ms ease;
}
.legend-collapse:hover { background: #fff; color: var(--ink); border-color: var(--accent); }
.map-legend-body { display: flex; flex-direction: column; gap: 12px; }
.map-legend.is-collapsed .map-legend-body { display: none; }
.map-legend.is-collapsed { padding-bottom: 10px; }
.map-legend.is-collapsed .map-legend-header { margin-bottom: 0; }

/* Legend rows: title left + small range right ABOVE the gradient bar */
.legend-row { display: flex; flex-direction: column; }
.legend-row.is-hidden { display: none; }
/* Compact variant for layers without a colour ramp (Train network, LRT) —
   single inline row with a small filled circle next to the title. */
.legend-row--inline {
  flex-direction: row;
  align-items: center;
  gap: 10px;
}
.legend-dot {
  width: 10px; height: 10px;
  border-radius: 50%;
  flex-shrink: 0;
  background: var(--ink); /* default; overridden inline for LRT, per-basemap for network */
}
/* Pair of inline (no-ramp) rows that share one slot. Used to put the
   Train network + LRT swatches on a single line when both are shown.
   When LRT is hidden via .is-hidden, Train network sits alone. */
.legend-row-pair {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 18px;
}
.legend-row-header {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px;
}
.legend-row h3 {
  margin: 0;
  font-size: 12px; font-weight: 600;
  color: var(--ink);
  letter-spacing: 0.005em;
}
.legend-row h3 small {
  font-weight: 400; font-size: 10.5px;
  color: var(--muted); letter-spacing: 0;
  margin-left: 4px;
}
.legend-range {
  font-size: 10.5px; font-weight: 500;
  color: var(--muted);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.ramp { display: block; margin-top: 6px; }
.ramp-bar {
  height: 10px;
  border-radius: 5px;
  box-shadow: inset 0 0 0 1px var(--rule);
}

/* ---------- Chart view ---------- */
.compare-frame {
  position: absolute; inset: 0;
  display: flex; flex-direction: column;
  border-radius: 14px;
  background: rgba(255, 255, 255, 0.6);
  border: 1px solid var(--map-border);
  box-shadow: var(--shadow);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  overflow: hidden;
  padding-top: 70px;  /* clears the absolute Map/Chart .view-tabs (constant,
                         so the summary can be hidden on non-Overview tabs) */
}

/* Chart-tab control stack — three rows (Chart type, Scope, Metric)
   stacked vertically, each row holding a left-aligned label + button
   group. The whole `.control-row` carries the `data-show-when` for
   the Metric row, so toggling chart type hides label + buttons together
   (no orphan "Metric" header floating without its buttons). */
.compare-chart-controls {
  display: flex;
  flex-flow: row wrap;          /* Chart + Scope groups on one line; wrap if narrow */
  align-items: center;
  gap: 8px 32px;                /* row-gap when wrapped · column-gap between groups */
  padding: 10px 24px 6px;
}
/* Chart-tab summary banner — header bar with title + collapse arrow.
   Clicking the arrow flips ▾↔▴ + adds .is-collapsed which hides the
   inner table via display:none. Mirrors the .map-stats-header UX. */
.compare-summary-wrap {
  position: relative;
  padding-top: 6px;
  flex: 0 0 auto;          /* sits below the chart, scrolled to as part of
                              the shared .compare-scroll page */
}
.compare-summary-wrap[hidden] { display: none; }
.compare-summary-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 4px 28px 4px;
  margin-bottom: 4px;
}
.compare-summary-title {
  margin: 0;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  color: var(--muted);
}
.compare-summary-collapse {
  width: 22px; height: 22px;
  padding: 0;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid var(--map-border);
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.6);
  color: var(--muted);
  font-size: 12px; line-height: 1;
  cursor: pointer;
  flex-shrink: 0;
  transition: background 120ms ease, color 120ms ease, border-color 120ms ease;
}
.compare-summary-collapse:hover {
  background: #fff;
  color: var(--ink);
  border-color: var(--accent);
}
.compare-summary-wrap.is-collapsed .compare-summary { display: none; }
.control-row {
  display: flex;
  align-items: center;
  gap: 14px;
}
/* `.control-row { display: flex }` above outranks the UA default
   `[hidden] { display: none }`, so the JS-set `hidden` attribute was
   silently ignored on the Metric row. Force display:none here. */
.control-row[hidden] { display: none !important; }
.control-row .compare-label {
  min-width: 52px;
}
.compare-label {
  font-size: 13px; font-weight: 700;
  letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--muted);
}

/* Single scroll region holding the chart + (Overview) summary. The whole
   thing scrolls as one page so on Overview the summary lives *below the
   fold* — you scroll down to it — rather than the chart having its own
   inner scrollbar that hid the bottom of the headline metrics. The control
   rows above stay pinned (they're outside this element). */
.compare-scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  display: flex;
  flex-direction: column;
}
.compare-chart {
  position: relative;
  flex: 0 0 auto;          /* natural height — the .compare-scroll parent scrolls */
  padding: 12px 24px 18px;
}
/* Hand-rolled half-violin density chart. */
.density-violin { display: block; width: 100%; height: auto; }
.density-violin .dv-typelabel { font-size: 12.5px; font-weight: 700; fill: var(--ink); }
/* Second level of the hierarchical axis: mode, with its catchment radius
   underneath — lighter than the archetype above it, heavier than the country
   code to its right, so the three levels read in order. */
.density-violin .dv-modelabel { font-size: 11px; font-weight: 600; fill: var(--ink); }
.density-violin .dv-moderadius { font-size: 9.5px; font-weight: 500; fill: var(--muted); }
.density-violin .dv-code { font-size: 10.5px; font-weight: 700; }
.density-violin .dv-perm { font-size: 10.5px; font-weight: 700; fill: var(--ink); font-variant-numeric: tabular-nums; }
/* Footer under a density chart: compact key line + selected-type definition. */
.chart-foot { padding: 6px 28px 12px; }
.chart-foot-key { font-size: 11.5px; color: var(--muted); }
.chart-foot-desc {
  margin-top: 7px; font-size: 13px; color: var(--ink);
  background: rgba(255, 255, 255, 0.55);
  border: 1px solid var(--rule); border-left: 3px solid var(--accent);
  border-radius: 8px; padding: 8px 12px;
}
.density-violin .dv-tick { font-size: 10px; fill: var(--muted); }
.density-violin .dv-axis { font-size: 11px; fill: var(--muted); }
/* Metrics chart — 6 mini dot plots in a 2-column grid, one per
   headline number. Each chart has its own x-axis on actual values.
   A single legend at the top identifies countries; per-Plot legends
   are suppressed. Drops to 1 column on narrow viewports. */
/* FIFA-style "skill star" radar over the six headline metrics — one coloured
   polygon per network, each spoke scaled v/leader so the outer ring = best
   among the shown networks. Sits above the per-metric dot strips. */
.metrics-radar-wrap {
  margin: 10px auto 6px;
  max-width: 560px;
  text-align: center;
}
.metrics-radar .mr-axis {
  font-size: 12.5px;
  font-weight: 700;
  fill: var(--ink);
  font-family: 'Space Grotesk', system-ui, sans-serif;
}
.metrics-radar-cap {
  margin: 4px auto 0;
  max-width: 520px;
  font-size: 11.5px;
  line-height: 1.45;
  color: var(--muted);
}
.metrics-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
  margin-top: 8px;
}
@media (max-width: 900px) {
  .metrics-grid { grid-template-columns: 1fr; }
}
.metrics-cell {
  background: rgba(255,255,255,0.7);
  border: 1px solid var(--map-border);
  border-radius: 8px;
  padding: 8px 10px 4px;
  display: flex; flex-direction: column;
  align-items: stretch;
}
.metrics-cell-title {
  margin: 2px 0 3px 14px;
  font-size: 14px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--ink);
}
/* Let the (now custom) tooltip extend slightly past the SVG when room
   is tight. */
.metrics-cell svg { display: block; margin: 0 auto; max-width: 100%; overflow: visible; }
.metrics-cell svg { width: 100%; max-width: 740px; }
/* Keep metrics axes compact without shrinking Plot's hover tooltip. */
.metrics-cell svg g[aria-label*="axis" i] text { font-size: 13px !important; }
/* Plot 0.6's built-in tip text size — match the compact .app-tooltip.is-chart-tip
   look used on Metrics + Dumbbell (which use our custom [data-tooltip] so the
   tooltip can follow the in-place dot morph). Same selector list as before —
   Plot's `fontSize` option is silently ignored by the tip renderer. */
.compare-chart svg path[filter] ~ text,
.compare-chart svg path[filter] ~ text tspan,
.compare-chart svg path[filter] + text,
.compare-chart svg path[filter] + text tspan,
.compare-chart svg text[paint-order],
.compare-chart svg text[paint-order] tspan,
.compare-chart svg g[pointer-events="none"] text,
.compare-chart svg g[pointer-events="none"] text tspan,
.compare-chart svg [aria-label*="tip" i] text,
.compare-chart svg [aria-label*="tip" i] tspan {
  font-size: 13px !important;
}
/* Smoothly slide dots when scope toggles (renderMetricsCompare updates
   each circle's `cx` attribute in-place rather than recreating the SVG).
   Our `[data-tooltip]` tooltip rides along because it positions via
   `getBoundingClientRect()` at hover time, which returns the live
   rendered cx — Plot's built-in `tip: true` did not. */
.metrics-cell svg circle {
  transition: cx 350ms cubic-bezier(0.4, 0, 0.2, 1), opacity 350ms ease;
}

.dumbbell-chart {
  font-family: var(--font-sans);
  overflow: visible;
}
.dumbbell-grid {
  stroke: rgba(58, 70, 84, 0.13);
  stroke-width: 1;
}
.dumbbell-tick,
.dumbbell-axis-label {
  fill: var(--muted);
  font-size: 13px;
  font-weight: 500;
}
.dumbbell-country {
  fill: var(--ink);
  font-size: 15px;
  font-weight: 700;
}
.dumbbell-link {
  stroke-opacity: 0.62;
  stroke-width: 7;
  stroke-linecap: round;
}
.dumbbell-dot {
  stroke-width: 2;
}
.dumbbell-value {
  font-variant-numeric: tabular-nums;
}
.dumbbell-value-rail {
  fill: #6b6b78;
  font-size: 12.5px;
  font-weight: 600;
}
.dumbbell-value-all {
  fill: #262633;
  font-size: 14px;
  font-weight: 800;
}
.dumbbell-context {
  fill: #6b6b78;
  font-size: 12px;
  font-weight: 600;
}
.dumbbell-delta {
  font-size: 12.5px;
  font-style: italic;
  font-weight: 700;
}
.dumbbell-morph {
  transition:
    x 360ms cubic-bezier(0.4, 0, 0.2, 1),
    y 360ms cubic-bezier(0.4, 0, 0.2, 1),
    x1 360ms cubic-bezier(0.4, 0, 0.2, 1),
    x2 360ms cubic-bezier(0.4, 0, 0.2, 1),
    y1 360ms cubic-bezier(0.4, 0, 0.2, 1),
    y2 360ms cubic-bezier(0.4, 0, 0.2, 1),
    cx 360ms cubic-bezier(0.4, 0, 0.2, 1),
    cy 360ms cubic-bezier(0.4, 0, 0.2, 1);
}

/* Boxplot — hand-rolled SVG so the scope toggle morphs in place
   (per-country box rects, country labels, outlier dots all keep their
   identity across renders). <line> endpoints aren't CSS-transitionable
   so whiskers / caps / median ticks are rAF-tweened via
   tweenLineEndpoints; <rect>/<text>/<circle> attrs are CSS-driven. */
.boxplot-chart { font-family: var(--font-sans); overflow: visible; }
.boxplot-grid {
  stroke: rgba(58, 70, 84, 0.13);
  stroke-width: 1;
}
.boxplot-tick,
.boxplot-axis-label {
  fill: var(--muted);
  font-size: 12px;
  font-weight: 500;
}
.boxplot-axis-label { font-weight: 600; }
/* Tick labels slide with their grid lines when the x-domain changes
   (metric toggle). textContent flips mid-slide, which reads fine
   alongside the data morph. */
.boxplot-tick {
  transition:
    x 360ms cubic-bezier(0.4, 0, 0.2, 1),
    y 360ms cubic-bezier(0.4, 0, 0.2, 1);
}
.boxplot-country {
  fill: var(--ink);
  font-size: 13px;
  font-weight: 700;
  transition:
    x 360ms cubic-bezier(0.4, 0, 0.2, 1),
    y 360ms cubic-bezier(0.4, 0, 0.2, 1);
}
.boxplot-whisker,
.boxplot-cap {
  stroke: #3a4654;
  stroke-width: 1.4;
}
.boxplot-median {
  stroke: white;
  stroke-width: 1.8;
}
.boxplot-box {
  transition:
    x 360ms cubic-bezier(0.4, 0, 0.2, 1),
    y 360ms cubic-bezier(0.4, 0, 0.2, 1),
    width 360ms cubic-bezier(0.4, 0, 0.2, 1),
    height 360ms cubic-bezier(0.4, 0, 0.2, 1);
}
.boxplot-outlier {
  transition:
    cx 360ms cubic-bezier(0.4, 0, 0.2, 1),
    cy 360ms cubic-bezier(0.4, 0, 0.2, 1),
    fill-opacity 280ms ease;
}
.boxplot-stnlabel {
  fill: #262633;
  font-size: 12.5px;
  font-weight: 600;
  transition:
    x 360ms cubic-bezier(0.4, 0, 0.2, 1),
    y 360ms cubic-bezier(0.4, 0, 0.2, 1);
}

/* Coverage — hand-rolled stacked bars so scope + mode-legend toggles
   morph in place. Each country owns 4 mode rects + 1 country label
   + 1 total-% label as stable refs. Active mode set masks rect widths
   with 0 so a re-enabled mode grows back in via the width transition. */
.coverage-chart { font-family: var(--font-sans); overflow: visible; }
.coverage-grid {
  stroke: rgba(58, 70, 84, 0.13);
  stroke-width: 1;
}
.coverage-tick,
.coverage-axis-label {
  fill: var(--muted);
  font-size: 12px;
  font-weight: 500;
}
.coverage-axis-label { font-weight: 600; }
.coverage-tick {
  transition:
    x 360ms cubic-bezier(0.4, 0, 0.2, 1),
    y 360ms cubic-bezier(0.4, 0, 0.2, 1);
}
.coverage-country {
  fill: var(--ink);
  font-size: 13px;
  font-weight: 700;
  transition:
    x 360ms cubic-bezier(0.4, 0, 0.2, 1),
    y 360ms cubic-bezier(0.4, 0, 0.2, 1);
}
.coverage-bar {
  transition:
    x 360ms cubic-bezier(0.4, 0, 0.2, 1),
    y 360ms cubic-bezier(0.4, 0, 0.2, 1),
    width 360ms cubic-bezier(0.4, 0, 0.2, 1),
    height 360ms cubic-bezier(0.4, 0, 0.2, 1);
}
.coverage-total {
  fill: #262633;
  font-size: 14px;
  font-weight: 600;
  transition:
    x 360ms cubic-bezier(0.4, 0, 0.2, 1),
    y 360ms cubic-bezier(0.4, 0, 0.2, 1);
}

/* Shared country legend above the stacked metric rows. */
.metrics-legend {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: 14px; row-gap: 6px;
  padding: 4px 6px 12px;
  font-size: 14px;
  color: var(--ink);
}
.metrics-legend-item {
  display: inline-flex; align-items: center; gap: 6px;
}
.metrics-legend-dot {
  display: inline-block;
  width: 12px; height: 12px;
  border-radius: 50%;
}

/* Interactive chart legend chips — replace Plot's static auto-legend.
   Click a chip to toggle that series on/off. Inactive chips dim out
   and strike through the label so the toggle is visually unambiguous. */
.chart-legend {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: 8px; row-gap: 5px;
  padding: 5px 6px 3px;
}
.chart-legend-item {
  appearance: none;
  background: none;
  border: 1px solid transparent;
  border-radius: 999px;
  padding: 5px 12px 5px 8px;
  cursor: pointer;
  display: inline-flex; align-items: center; gap: 7px;
  font: inherit;
  font-size: 13px;
  color: var(--ink);
  transition: background 120ms ease, border-color 120ms ease, opacity 120ms ease, color 120ms ease;
}
.chart-legend-item:hover {
  background: rgba(255,255,255,0.6);
  border-color: var(--map-border);
}
.chart-legend-item.is-inactive {
  opacity: 0.4;
  text-decoration: line-through;
}
.chart-legend-dot {
  display: inline-block;
  width: 12px; height: 12px;
  border-radius: 50%;
  flex-shrink: 0;
}

/* Summary table — rows = metrics, columns = countries (each split
   into Nat | Metro). One compact card above the chart that doesn't
   take much vertical space. Top clearance for the absolute .view-tabs
   lives on the wrapper now so the SUMMARY header bar isn't hidden
   behind them. */
.compare-summary {
  padding: 0 28px 14px;
}
.compare-summary-table {
  width: 100%;
  border-collapse: collapse;
  font-family: var(--font-sans);
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  background: rgba(255, 255, 255, 0.55);
  border: 1px solid var(--rule);
  border-radius: 12px;
  overflow: hidden;
  letter-spacing: 0;
}
.compare-summary-table th,
.compare-summary-table td {
  padding: 6px 10px;
  text-align: center;
  vertical-align: baseline;
  border-bottom: 1px solid var(--rule);
}
.compare-summary-table tbody tr:last-child th,
.compare-summary-table tbody tr:last-child td { border-bottom: none; }
/* Vertical divider between country pairs — applied to the Nat cell
   that opens each country block (i.e., every other column starting
   from col 2). The leftmost Nat (Israel) skips the divider. */
.compare-summary-table th:nth-child(2n + 2):not(:nth-child(2)),
.compare-summary-table td:nth-child(2n + 2):not(:nth-child(2)) {
  border-left: 1px solid var(--rule);
}
.compare-summary-table .ct-corner { background: transparent; }
.compare-summary-table .ct-country-head {
  font-size: 14px;
  font-weight: 700;
  letter-spacing: -0.01em;
  padding-top: 10px;
  padding-bottom: 3px;
  border-bottom: none;
}
.compare-summary-table .ct-region-tag {
  font-size: 9.5px; font-weight: 600; letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--muted);
  vertical-align: middle;
  opacity: 0.8;
}
.compare-summary-table .ct-country-head.is-active {
  text-decoration: underline;
  text-decoration-color: var(--accent);
  text-underline-offset: 4px;
  text-decoration-thickness: 2px;
}
.compare-summary-table .ct-scope-head {
  font-size: 11px;
  font-weight: 600;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  padding-top: 0;
  padding-bottom: 7px;
}
.compare-summary-table .ct-metric-label {
  text-align: left;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--muted);
  padding-left: 16px;
  white-space: nowrap;
}
.compare-summary-table .ct-val {
  font-size: 14px;
  font-weight: 700;
  color: var(--ink);
  letter-spacing: -0.01em;
  white-space: nowrap;
}
.compare-summary-table .ct-val-metro { color: var(--accent); }
@media (max-width: 600px) {
  .compare-summary-table { font-size: 12px; }
  .compare-summary-table .ct-val { font-size: 13px; }
}
.chart-title {
  margin: 0 0 10px;
  font-size: 18px; font-weight: 650;
  color: var(--ink);
  letter-spacing: 0;
}
/* Selected-station caption appended inline to a chart title. */
.chart-subnote {
  font-size: 13px; font-weight: 500;
  color: var(--muted);
}
.compare-chart svg {
  width: auto;
  max-width: 100%;
  height: auto;
  display: block;
  margin: 0 auto 4px;
}




/* Loading / error states for the lazy-loaded library charts. */
.lib-loading,
.lib-error {
  padding: 80px 24px;
  text-align: center;
  font-family: var(--font-sans);
  font-size: 13px;
  color: var(--muted);
}
.lib-error { color: var(--status-bad-fg, #8f2f21); }

/* Hover tooltip on the scatter */

/* ---------- About dialog ---------- */
dialog#about {
  position: fixed;
  width: 560px; max-width: 92vw; max-height: 80vh;
  padding: 28px 30px 14px;
  border: 1px solid var(--map-border);
  border-radius: var(--r-md);
  background: var(--panel-solid);
  color: var(--ink);
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.22);
  animation: aboutFadeIn 180ms ease-out;
}
dialog#about::backdrop {
  background: rgba(0, 0, 0, 0.35);
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
}
.dialog-close-form {
  position: absolute; top: 12px; right: 14px;
  margin: 0;
}
.dialog-close {
  width: 28px; height: 28px;
  padding: 0;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid var(--map-border);
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.7);
  color: var(--muted);
  font-size: 18px; line-height: 1;
  cursor: pointer;
  transition: background 120ms ease, color 120ms ease, border-color 120ms ease;
}
.dialog-close:hover { background: #fff; color: var(--ink); border-color: var(--accent); }
dialog#about h2 {
  margin: 0 0 10px;
  padding-right: 36px;
  font-family: var(--font-serif);
  font-size: 22px; font-weight: 600;
  line-height: 1.2;
}
dialog#about p {
  margin: 0 0 14px;
  font-size: 13px; line-height: 1.6;
  color: var(--ink);
}
dialog#about h3 {
  margin: 14px 0 8px;
  font-size: 11px; font-weight: 700;
  letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--muted);
}
dialog#about h3:first-of-type { margin-top: 8px; }
.typology-table {
  width: 100%;
  border-collapse: collapse;
  margin: 4px 0 8px;
  font-size: 12.5px;
}
.typology-table th, .typology-table td {
  text-align: left;
  padding: 5px 8px;
  border-bottom: 1px solid var(--rule);
}
.typology-table thead th {
  font-weight: 600; color: var(--muted);
  font-size: 11px; letter-spacing: 0.02em; text-transform: uppercase;
}
.typology-table tbody td:first-child { font-weight: 700; color: var(--ink); }
.typology-note { font-size: 12px !important; color: var(--muted); margin-top: 0 !important; }
.calc-list {
  margin: 0 0 14px;
  padding-left: 18px;
  font-size: 13px; line-height: 1.6;
}
.calc-list li { margin-bottom: 6px; }
.calc-list li::marker { color: var(--mint-edge); }
.calc-list strong { font-weight: 600; color: var(--ink); }
.calc-list em { color: var(--accent); font-style: normal; font-weight: 600; }
.sources {
  margin: 0 0 14px;
  padding-left: 18px;
  font-size: 13px; line-height: 1.65;
}
.sources li { margin-bottom: 2px; }
.sources li::marker { color: var(--mint-edge); }
.sources strong { font-weight: 600; color: var(--ink); }
.sources a, dialog#about a {
  color: var(--mint-base); font-weight: 600;
  text-decoration: underline; text-underline-offset: 2px;
}
.sources a:hover, dialog#about a:hover { color: var(--mint-strong); }
.dialog-contact {
  margin: 14px 0 0;
  padding: 12px 0 0;
  border-top: 1px solid var(--rule);
  font-size: 12px; line-height: 1.5;
  color: var(--muted);
  font-style: italic;
  text-align: center;
}
@keyframes aboutFadeIn {
  from { opacity: 0; transform: translateY(2px); }
  to   { opacity: 1; transform: none; }
}

/* ---------- Leaflet popups ---------- */
.leaflet-popup-content-wrapper {
  border: 1px solid var(--map-border);
  border-radius: var(--r-lg);
  background: var(--panel);
  color: var(--ink);
  box-shadow: var(--shadow-pop);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}
.leaflet-popup-content {
  margin: 12px 14px;
  font-family: var(--font-sans);
  font-size: 13px; line-height: 1.5;
  color: var(--ink);
}
.leaflet-popup-tip {
  background: var(--panel);
  box-shadow: var(--shadow-pop);
}
.popup-name {
  font-size: 13.5px; font-weight: 700;
  color: var(--ink);
  margin-bottom: 6px;
  padding-bottom: 4px;
  border-bottom: 1px solid var(--rule);
}
/* Mode chip in the station popup header (Train / Metro / LRT). */
.popup-mode {
  display: inline-block; vertical-align: middle;
  margin-left: 4px; padding: 1px 6px; border-radius: 9px;
  font-size: 10px; font-weight: 700; letter-spacing: 0.02em;
  color: #fff;
}
.popup-mode--train { background: #5a6473; }
.popup-mode--metro { background: #7a1d24; }
.popup-mode--lrt   { background: #c75d1c; }
.popup-mode--tram  { background: #b8862f; }
.popup-row {
  display: flex; justify-content: space-between; gap: 16px;
  padding: 2px 0;
}
.popup-row strong {
  font-weight: 400; color: var(--muted);
  font-size: 12px; letter-spacing: 0.01em;
}
.popup-row span {
  font-variant-numeric: tabular-nums;
  font-weight: 600;
}
/* "major interchange" badge on the Type row — the former central-hub
   distinction, kept as a flag on Central stations rather than its own type. */
.popup-badge {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 7px;
  border-radius: 999px;
  background: rgba(122, 29, 36, 0.12);
  color: #7a1d24;
  font-size: 10.5px; font-weight: 600;
  letter-spacing: 0.01em;
  vertical-align: middle;
}
body.basemap-dark .popup-badge { background: rgba(199, 93, 28, 0.22); color: #e7a06a; }
/* Low-confidence note under the typology block in the station popup. */
.popup-note {
  margin-top: 6px;
  font-size: 11px;
  font-style: italic;
  color: var(--muted);
}

/* Custom hover tooltip — single shared element driven by JS (wireTooltips).
   Mirrors the Leaflet sticky-tooltip styling so the whole app feels cohesive
   instead of using the OS-default browser title= bubble. */
.app-tooltip {
  position: fixed;
  z-index: 9999;
  padding: 10px 12px;
  background: var(--panel);
  border: 1px solid var(--map-border);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-pop);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  font-family: var(--font-sans);
  font-size: 12.5px; line-height: 1.45;
  color: var(--ink);
  pointer-events: none;
  max-width: 240px;
  white-space: normal;
  text-align: left;
  opacity: 0;
  transition: opacity 140ms ease;
}
.app-tooltip:not([hidden]) { opacity: 1; }
.app-tooltip[hidden] { display: none; }
/* Chart-tab variant — mimics Plot 0.6's built-in tip (compact opaque
   white card, thin border, smaller font, multi-line via \n). Used by
   the Metrics + Dumbbell charts so the popup matches the Plot tip the
   other chart types render natively. */
.app-tooltip.is-chart-tip {
  padding: 6px 10px;
  background: rgba(255, 255, 255, 0.97);
  border: 1px solid rgba(38, 38, 51, 0.22);
  border-radius: 4px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  font-size: 13px;
  line-height: 1.4;
  max-width: 320px;
  white-space: pre-line;
}

/* Leaflet sticky tooltip — sizes naturally to its content (the verbose note
   that used to stretch it wide is gone, so no max-width is needed). */
.leaflet-tooltip {
  border: 1px solid var(--map-border) !important;
  border-radius: var(--r-md) !important;
  background: var(--panel) !important;
  color: var(--ink) !important;
  box-shadow: var(--shadow-pop) !important;
  padding: 10px 12px !important;
  font-family: var(--font-sans) !important;
  font-size: 12.5px; line-height: 1.45;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}
.leaflet-tooltip:before { display: none !important; }

/* Heatmap canvas shouldn't intercept mouse events — lets bus-route hover work */
.leaflet-overlay-pane canvas { pointer-events: none; }

/* Leaflet zoom + attribution */
.leaflet-bar a {
  background: var(--panel) !important;
  color: var(--ink) !important;
  border: 1px solid var(--map-border) !important;
}
.leaflet-bar a:hover { background: rgba(255,255,255,0.7) !important; border-color: var(--accent) !important; }
.leaflet-bar a:first-child {
  border-top-left-radius: var(--r-md) !important;
  border-top-right-radius: var(--r-md) !important;
}
.leaflet-bar a:last-child {
  border-bottom-left-radius: var(--r-md) !important;
  border-bottom-right-radius: var(--r-md) !important;
}
.leaflet-control-attribution {
  background: rgba(255, 255, 255, 0.86) !important;
  color: var(--muted) !important;
  font-family: var(--font-sans) !important;
  font-size: 10.5px !important;
  border-radius: var(--r-sm) !important;
  padding: 2px 8px !important;
}
.leaflet-control-attribution a { color: var(--mint-base) !important; }

/* ---------- Mobile ---------- */
@media (max-width: 900px) {
  .app {
    grid-template-columns: 1fr;
    grid-template-rows: auto 1fr;
    height: 100vh;
  }
  .panel {
    max-height: 50vh;
    padding: 22px 20px;
    gap: 18px;
    border-right: none;
    border-bottom: 1px solid #d1cbdb;
  }
  .panel-title h1 { font-size: 24px; }
  .view { inset: 8px; }
  .view-tabs { top: 16px; left: 18px; }
}
@media (max-width: 600px) {
  .panel { padding: 20px 18px; gap: 16px; }
  .panel-title h1 { font-size: 22px; }
  .panel-title .subhead { font-size: 12.5px; }
  .map-legend { left: 10px; bottom: 10px; padding: 12px 14px 14px; width: calc(100% - 20px); max-width: 360px; }
  .leaflet-control-zoom { display: none; }
}

/* ---------- Reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0ms !important;
    scroll-behavior: auto !important;
  }
}

/* -------- Guided stories (sidebar) -------- */
.stories-group .story-list { display: flex; flex-direction: column; gap: 6px; }
.story-btn {
  display: flex; flex-direction: column; align-items: flex-start; gap: 1px;
  padding: 7px 10px;
  border: 1px solid var(--map-border);
  border-radius: 8px;
  background: #fff;
  font-family: inherit;
  color: var(--ink);
  cursor: pointer;
  text-align: left;
  transition: background-color 120ms ease, border-color 120ms ease;
}
.story-btn:hover { border-color: var(--accent); }
.story-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.story-title { font-size: 12px; font-weight: 600; }
.story-sub { font-size: 10.5px; color: var(--muted); }

/* -------- Node–place densification-headroom list -------- */
.headroom-list { margin-top: 10px; }
.headroom-title { font-size: 12.5px; font-weight: 600; color: var(--ink); margin: 0 0 6px; }
.headroom-note { font-size: 11px; color: var(--muted); margin: 4px 0 6px; }
.headroom-row {
  display: grid;
  grid-template-columns: 22px minmax(0, 1fr) auto auto;
  gap: 8px; align-items: baseline;
  width: 100%;
  padding: 5px 8px;
  border: 1px solid transparent;
  border-radius: 7px;
  background: transparent;
  font-family: inherit; font-size: 12px; color: var(--ink);
  cursor: pointer; text-align: left;
}
.headroom-row:hover { background: #fff; border-color: var(--accent); }
.headroom-row:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.headroom-row .hr-rank { color: var(--muted); font-size: 11px; }
.headroom-row .hr-name { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.headroom-row .hr-meta { color: var(--muted); font-size: 11px; white-space: nowrap; }
/* Same squeeze as .leader-row: keep the gap badge, drop the meta first. */
@media (max-width: 700px) {
  .headroom-row { grid-template-columns: 22px minmax(0, 1fr) auto; }
  .headroom-row .hr-meta { display: none; }
}
.headroom-row .hr-gap {
  font-weight: 700; font-size: 11.5px;
  color: var(--status-bad-fg);
  background: var(--status-bad-bg);
  border: 1px solid var(--status-bad-edge);
  border-radius: 999px;
  padding: 1px 7px;
}

/* -------- Density-tab leaderboard -------- */
.leader-list { margin-top: 10px; display: flex; flex-direction: column; gap: 2px; max-width: 860px; }
.leader-row {
  display: grid;
  grid-template-columns: 26px 10px minmax(0, 1fr) auto auto auto;
  gap: 9px; align-items: center;
  width: 100%;
  padding: 5px 9px;
  border: 1px solid transparent;
  border-radius: 7px;
  background: transparent;
  font-family: inherit; font-size: 12.5px; color: var(--ink);
  cursor: pointer; text-align: left;
}
.leader-row:hover { background: #fff; border-color: var(--accent); }
.leader-row:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.leader-row .hr-rank { color: var(--muted); font-size: 11px; }
.leader-row .hr-name { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.leader-row .hr-meta { color: var(--muted); font-size: 11px; white-space: nowrap; }
/* Narrow viewports: the row is a 6-column grid whose last cell is the density
   value — the number the chart exists to show. The nowrap meta column used to
   push it past the edge with nothing scrollable to reach it. Drop the meta
   (network is already the coloured dot, mode is in the foot) and let the type
   badge go before the value does. */
@media (max-width: 700px) {
  .leader-row { grid-template-columns: 22px 10px minmax(0, 1fr) auto auto; gap: 7px; }
  .leader-row .hr-meta { display: none; }
}
@media (max-width: 460px) {
  .leader-row { grid-template-columns: 22px 10px minmax(0, 1fr) auto; }
  .leader-row .type-badge { display: none; }
}
.leader-row .leader-val { white-space: nowrap; font-variant-numeric: tabular-nums; }
.leader-dot { width: 9px; height: 9px; border-radius: 50%; display: inline-block; }
.type-badge {
  font-size: 10.5px; font-weight: 600;
  border: 1px solid;
  border-radius: 999px;
  padding: 1px 7px;
  background: #fff;
  white-space: nowrap;
}
.leader-val { font-weight: 700; font-size: 12px; font-variant-numeric: tabular-nums; }
