:root {
  --primary: #1d6f5e;
  --primary-dark: #144c40;
  --accent: #3f7fd1;
  --bg: #f6f8f7;
  --panel: #ffffff;
  --text: #17211d;
  --muted: #5b6b64;
  --border: #e1e7e3;
  --band-high: #17784a;
  --band-mid: #9a6c07;
  --band-low: #6c7570;
  --header-h: 56px;
  --radius: 12px;
  --shadow: 0 4px 18px rgba(20, 40, 35, .10);
  --sheet-h: 46vh;
}

* { box-sizing: border-box; }

html, body {
  margin: 0; padding: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  color: var(--text); background: var(--bg);
  -webkit-text-size-adjust: 100%;
}
img { max-width: 100%; display: block; }
h1, h2, h3 { line-height: 1.25; }

/* ------------------------------------------------------------------ header */
.site-header {
  height: var(--header-h);
  background: var(--primary-dark); color: #fff;
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px; padding: 0 12px;
  position: sticky; top: 0; z-index: 1200;
  padding-top: env(safe-area-inset-top);
}
.brand {
  color: #fff; text-decoration: none; font-weight: 700;
  font-size: .98rem; display: flex; align-items: center; gap: 6px; white-space: nowrap;
}
.brand-mark { color: #7fd6c2; font-size: 1.15rem; }
.header-tools { display: flex; align-items: center; gap: 8px; min-width: 0; }
.city-label { display: none; font-size: .85rem; opacity: .85; white-space: nowrap; }
.city-select {
  border: none; border-radius: 8px; padding: 7px 8px; font-size: .85rem;
  background: rgba(255,255,255,.14); color: #fff; max-width: 130px;
}
.city-select option { color: #000; }
.search-input {
  border: none; border-radius: 18px; padding: 8px 12px;
  font-size: 16px; /* 16px prevents iOS zoom-on-focus */
  width: 150px; min-width: 0; outline: none; background: #fff; color: var(--text);
}
.search-input:focus-visible { box-shadow: 0 0 0 2px var(--accent); }
.icon-btn {
  background: rgba(255,255,255,.14); color: #fff; border: none;
  width: 38px; height: 38px; border-radius: 9px; font-size: 1rem;
  cursor: pointer; flex: 0 0 auto;
}
.icon-btn:hover { background: rgba(255,255,255,.26); }

/* ------------------------------------------------------------------ layout */
.app {
  position: relative;
  display: flex; flex-direction: column;
  height: calc(100svh - var(--header-h));
  min-height: 460px;
}
/* Sticky, not static. The shell is sized to the viewport and the footer sits
   below it, so the document is always ~200px scrollable — and on a phone one
   stray swipe used to drag the map off the top of the screen with no obvious way
   back. Sticky pins the map under the header while the sheet and the footer
   scroll past it, which is what a reader expects of a map that is the page. */
.map-pane {
  position: sticky; top: var(--header-h);
  flex: 1 1 auto; min-height: 0;
}
#map { position: absolute; inset: 0; background: #dce8e2; }

.loading {
  position: absolute; inset: 0; display: flex; gap: 10px;
  align-items: center; justify-content: center;
  background: var(--bg); color: var(--muted); font-size: .9rem; z-index: 900;
}
.spinner {
  width: 16px; height: 16px; border-radius: 50%;
  border: 2px solid var(--border); border-top-color: var(--primary);
  animation: spin .8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
.load-err { max-width: 320px; text-align: center; display: grid; gap: 6px; padding: 16px; }
.load-err span { font-size: .82rem; }

/* ------------------------------------------------------------------ legend */
/* An author `display` outranks the user agent's rule for [hidden], so every element
   the script hides — the guide link, the photo strip, the layer switches, the
   colour-by box — went on showing. The guide link was the visible one: it appeared
   on all 81 areas as a dead "Read the full guide to →" with no name after it,
   because no guide has been written yet. One reset rather than a patch per selector,
   so the next element someone hides is hidden. */
[hidden] { display: none !important; }

.map-legend {
  display: flex; flex-direction: column; gap: 5px;
  font-size: .7rem; color: var(--muted);
}
.lg-item { display: flex; align-items: center; gap: 6px; white-space: nowrap; }
.lg-swatch {
  width: 15px; height: 11px; border-radius: 2px; flex: 0 0 auto;
  border: 1px solid rgba(0,0,0,.25); opacity: .75;
}
.lg-muted { color: #8b978f; font-style: italic; }

/* ------------------------------------------------------------- state toggle */
/* Sits under the legend and reads as part of it: both answer "what am I looking
   at". A checkbox, not a button, so the state is announced correctly and the
   keyboard reaches it without any extra wiring. */
/* Lives inside the key panel now; the .map-key rule below strips the chrome it used
   to need as a floating box of its own. */
.state-toggle {
  display: flex; flex-direction: column; gap: 6px;
  font-size: .7rem; color: var(--muted);
}
.st-head { font-weight: 700; letter-spacing: .02em; text-transform: uppercase; font-size: .62rem; }
.st-switch { display: flex; align-items: center; gap: 7px; cursor: pointer; white-space: nowrap; }
.st-switch input { position: absolute; opacity: 0; width: 0; height: 0; }
.st-track {
  width: 26px; height: 15px; border-radius: 999px; flex: 0 0 auto;
  background: #c6cfc9; position: relative; transition: background .15s ease;
}
.st-track::after {
  content: ""; position: absolute; top: 2px; left: 2px;
  width: 11px; height: 11px; border-radius: 50%; background: #fff;
  box-shadow: 0 1px 2px rgba(0,0,0,.3); transition: transform .15s ease;
}
.st-switch input:checked + .st-track { background: var(--primary); }
.st-switch input:checked + .st-track::after { transform: translateX(11px); }
.st-switch input:focus-visible + .st-track { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) {
  .st-track, .st-track::after { transition: none; }
}

@media (max-width: 767.98px) {
  .state-toggle { font-size: .62rem; padding: 5px 7px; }
  .st-track { width: 22px; height: 13px; }
  .st-track::after { width: 9px; height: 9px; }
  .st-switch input:checked + .st-track::after { transform: translateX(9px); }
}

/* The legend competes with the map on every width where the map is only half the
   screen — that is the whole column layout, up to 767px, not just phones. At 600px
   the full-size legend and toggle were covering 49% of the map's height. */
@media (max-width: 767.98px) {
  .map-legend { font-size: .62rem; padding: 5px 7px; gap: 3px; border-radius: 7px; }
  .lg-swatch { width: 11px; height: 8px; }
}

.leaflet-tooltip.nb-tooltip { font-weight: 600; color: var(--primary-dark); border-radius: 6px; }
.leaflet-container path:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }
.leaflet-container { font: inherit; }

/* --------------------------------------------------------------- area labels */
/* Names on the shapes themselves. Hover tooltips cannot do this job: there is no
   hover on a phone, which is the device most of this map is read on. The halo is
   what keeps a name legible over both a saturated core and the pale filler. */
.area-label {
  font-size: .72rem; font-weight: 700; line-height: 1.15;
  color: #14302a; text-align: center; white-space: nowrap;
  pointer-events: none;   /* the shape underneath must stay clickable */
  text-shadow:
     0 0 3px rgba(255,255,255,.95),  0 1px 2px rgba(255,255,255,.95),
     1px 0 2px rgba(255,255,255,.95), -1px 0 2px rgba(255,255,255,.95),
     0 -1px 2px rgba(255,255,255,.95);
}
@media (max-width: 520px) { .area-label { font-size: .66rem; } }

/* Park names sit a size below the district names and in a green italic, so the two
   sets never read as competing for the same thing: one is where you might live,
   the other is what you would look at from the window. */
.park-label {
  font-size: .63rem; font-weight: 600; font-style: italic; line-height: 1.15;
  color: #2f5d33; text-align: center; white-space: nowrap;
  pointer-events: none;
  text-shadow:
     0 0 3px rgba(255,255,255,.92),  0 1px 2px rgba(255,255,255,.92),
     1px 0 2px rgba(255,255,255,.92), -1px 0 2px rgba(255,255,255,.92),
     0 -1px 2px rgba(255,255,255,.92);
}
.park-label.is-water { color: #2b5573; }
/* A carved-out compound is not green and not somewhere to live, so its name is
   the grey of the unclaimed land it sits on rather than the park green. */
.park-label.is-compound { color: #55605c; }
@media (max-width: 520px) { .park-label { font-size: .58rem; } }

/* ------------------------------------------------------- neighbourhood list */
.nb-drawer {
  position: absolute; z-index: 1150; inset: 0 auto 0 0;
  width: min(84vw, 320px);
  background: var(--panel); border-right: 1px solid var(--border);
  box-shadow: var(--shadow);
  display: flex; flex-direction: column;
  transform: translateX(-102%); transition: transform .22s ease;
}
body.list-open .nb-drawer { transform: translateX(0); }
.nb-drawer-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 12px 14px; border-bottom: 1px solid var(--border);
}
.nb-drawer-head h2 { margin: 0; font-size: .95rem; }
.nb-drawer-head .icon-btn { background: var(--bg); color: var(--text); }
.nb-list {
  list-style: none; margin: 0; padding: 6px; flex: 1 1 auto;
  overflow-y: auto; overscroll-behavior-y: contain;
}
.nb-group {
  position: sticky; top: 0; z-index: 2;
  background: var(--panel); color: var(--muted);
  font-size: .68rem; font-weight: 700; text-transform: uppercase; letter-spacing: .07em;
  padding: 10px 12px 5px; border-bottom: 1px solid var(--border); margin-bottom: 2px;
}
.nb-item {
  width: 100%; text-align: left; background: none; border: none;
  padding: 10px 12px; border-radius: 9px; cursor: pointer;
  display: grid; gap: 2px; font: inherit; color: var(--text);
}
.nb-item:hover { background: var(--bg); }
.nb-item.is-active { background: #e8f1ee; box-shadow: inset 3px 0 0 var(--primary); }
.nb-item-name { font-weight: 600; font-size: .92rem; }
.nb-item-meta { font-size: .74rem; color: var(--muted); }
.no-results { padding: 14px; color: var(--muted); font-size: .85rem; text-align: center; }

/* ------------------------------------------------------------- info panel */
.info-panel {
  flex: 0 0 auto; background: var(--panel);
  border-top: 1px solid var(--border);
  max-height: var(--sheet-h); overflow-y: auto; overscroll-behavior-y: contain;
  position: relative; z-index: 1000;
  -webkit-overflow-scrolling: touch;
  padding-bottom: env(safe-area-inset-bottom);
}
.panel-close {
  position: absolute; top: 10px; right: 10px; z-index: 6;
  width: 32px; height: 32px; border-radius: 50%;
  background: rgba(255,255,255,.92); border: 1px solid var(--border);
  cursor: pointer; display: none; font-size: .85rem;
}
.info-panel.is-open .panel-close { display: block; }

.panel-empty { padding: 18px 18px 22px; color: var(--muted); }
.panel-empty h2 { color: var(--text); margin: 0 0 8px; font-size: 1.12rem; }
.panel-empty p { margin: 0 0 8px; line-height: 1.5; font-size: .9rem; }
.panel-empty .hint { font-size: .78rem; }

.panel-photos { display: flex; gap: 2px; overflow-x: auto; scroll-snap-type: x mandatory; }
/* An author `display` beats the user agent's rule for [hidden], so the empty
   strip would still take part in the layout without this. */
.panel-photos[hidden] { display: none; }
.panel-photos img {
  height: 150px; width: auto; min-width: 72%; object-fit: cover;
  scroll-snap-align: start; background: var(--border);
}
.panel-body { padding: 16px 18px 22px; }
.panel-body h2 { margin: 0 0 6px; font-size: 1.3rem; }
.region-chip {
  display: inline-block; margin: 0 0 10px;
  font-size: .68rem; font-weight: 700; text-transform: uppercase; letter-spacing: .05em;
  color: #14342c; padding: 3px 9px; border-radius: 999px;
  background: var(--border); /* overridden per-region from JS */
}
.panel-body h3 { margin: 0 0 8px; font-size: .92rem; }
.panel-vibe { color: var(--muted); margin: 0 0 16px; line-height: 1.55; font-size: .92rem; }

.stat-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 9px; margin-bottom: 18px; }
.stat-box {
  background: var(--bg); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 9px 11px; display: grid; gap: 3px; min-width: 0;
}
.stat-wide { grid-column: 1 / -1; }
.stat-label { font-size: .68rem; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); }
.stat-value { font-size: 1.05rem; font-weight: 700; }
/* An unresearched field has to look unresearched. Styled like absent data rather
   than like a value, so it can never be mistaken for a very cheap area. */
.is-nodata { color: var(--muted); font-weight: 500; font-style: italic; font-size: .84rem; }
.stat-value-sm { font-size: .84rem; font-weight: 600; line-height: 1.4; }
.band-high { color: var(--band-high); }
.band-mid  { color: var(--band-mid); }
.band-low  { color: var(--band-low); }

.facts-list { margin: 0 0 16px; padding-left: 18px; }
.facts-list li { margin-bottom: 6px; line-height: 1.45; font-size: .89rem; }

.boundary-note {
  font-size: .74rem; line-height: 1.5; color: var(--muted);
  background: var(--bg); border: 1px solid var(--border);
  border-left: 3px solid var(--muted);
  border-radius: 8px; padding: 9px 11px; margin: 0 0 16px;
}
.boundary-note.is-exact    { border-left-color: var(--primary); }
.boundary-note.is-extended { border-left-color: #4f8fbe; }
.boundary-note.is-approx   { border-left-color: #c9a227; }
.boundary-note a { color: var(--primary); }

.cta-button {
  display: block; text-align: center; background: var(--primary); color: #fff;
  text-decoration: none; font-weight: 700; padding: 14px 18px;
  border-radius: var(--radius); font-size: 1rem; transition: background .15s ease;
}
.cta-button:hover { background: var(--primary-dark); }
.affiliate-note { font-size: .7rem; color: var(--muted); text-align: center; margin: 8px 0 0; }

/* ------------------------------------------------------------------ footer */
.site-footer { background: var(--primary-dark); color: #d8e7e1; font-size: .8rem; }
.footer-inner { max-width: 900px; margin: 0 auto; padding: 22px 18px; text-align: center; }
.footer-about { line-height: 1.6; margin: 0 0 12px; }
.footer-links { display: flex; flex-wrap: wrap; justify-content: center; gap: 14px; margin: 12px 0; }
.footer-links a, .footer-copy a { color: #9fe0ce; }
.footer-copy { opacity: .75; margin: 10px 0 0; line-height: 1.5; }

/* ====================== TABLET / SMALL LAPTOP (≥768px) ======================
   Map moves beside the info panel. The neighbourhood list stays an overlay
   drawer here — making it a permanent column too would crush the map, which is
   the whole point of the page. It only becomes persistent at ≥1100px. */
@media (min-width: 768px) {
  :root { --header-h: 60px; }
  .city-label { display: inline; }
  .search-input { width: 200px; }

  .app { flex-direction: row; }
  .map-pane { min-width: 0; }

  .info-panel {
    flex: 0 1 clamp(320px, 34vw, 380px);
    max-height: none; height: 100%;
    border-top: none; border-left: 1px solid var(--border);
  }
  .panel-photos img { height: 165px; min-width: 62%; }
  .panel-empty { padding: 26px 22px; }
  .map-legend { font-size: .74rem; left: 10px; top: 10px; }
}

/* ===================== DESKTOP (≥1100px): list column ===================== */
@media (min-width: 1100px) {
  .nb-drawer {
    position: static; transform: none;
    width: 260px; flex: 0 0 260px;
    box-shadow: none; border-right: 1px solid var(--border);
  }
  .nb-drawer-head .icon-btn, #listToggle { display: none; }
  .info-panel { flex: 0 1 clamp(340px, 30vw, 400px); }
  .search-input { width: 230px; }
}

@media (min-width: 1440px) {
  .nb-drawer { width: 280px; flex-basis: 280px; }
  .info-panel { flex-basis: clamp(380px, 28vw, 460px); }
  .panel-body { padding: 20px 22px 26px; }
}

/* --------------------------------------------------------- a11y / motion */
@media (prefers-reduced-motion: reduce) {
  * { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}
:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }

/* -------------------------------------------------------- screen-reader only */
/* Visible to assistive tech and to crawlers, not to the eye. The map app's only
   true document heading lives here — every visible heading is panel state. */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

/* -------------------------------------------------- guide link (in the panel) */
/* Only rendered for areas that have a hand-written guide, so it reads as a
   reward rather than as a nav item that is dead four times out of five. */
.guide-link {
  display: block; margin: 0 0 12px; padding: 11px 14px;
  background: #eef4f1; border: 1px solid var(--border); border-left: 3px solid var(--primary);
  border-radius: var(--radius);
  color: var(--primary-dark); font-weight: 600; font-size: .9rem; text-decoration: none;
}
.guide-link:hover { background: #e6efeb; }

/* ==================================================== generated guide pages */
.guide-body { background: var(--panel); }
.guide-body .site-header { justify-content: space-between; }
.guide-back { color: var(--muted); font-size: .85rem; text-decoration: none; white-space: nowrap; }
.guide-back:hover { color: var(--primary-dark); }

.guide { max-width: 760px; margin: 0 auto; padding: 24px 20px 56px; }
.guide-crumbs { font-size: .8rem; color: var(--muted); margin: 0 0 14px; }
.guide-crumbs a { color: var(--muted); }
.guide h1 { font-size: 1.9rem; margin: 0 0 10px; color: var(--primary-dark); }
.guide .region-chip { display: inline-block; margin-bottom: 14px; }
.guide-vibe { font-size: 1.06rem; line-height: 1.55; color: var(--muted); margin: 0 0 22px; }
.guide .stat-grid { margin-bottom: 24px; }

.guide-map {
  height: 280px; margin: 0 0 28px; border-radius: var(--radius);
  border: 1px solid var(--border); overflow: hidden; background: var(--bg);
}

/* The reason the page exists, so it gets the reading measure and the leading —
   everything above it is a summary the reader may already have seen in the panel. */
.guide-prose { font-size: 1.02rem; line-height: 1.72; }
.guide-prose h2 {
  font-size: 1.22rem; margin: 34px 0 10px; color: var(--primary-dark);
  padding-top: 14px; border-top: 1px solid var(--border);
}
.guide-prose h3 { font-size: 1.03rem; margin: 22px 0 8px; }
.guide-prose p, .guide-prose li { margin: 0 0 14px; }
.guide-prose ul, .guide-prose ol { padding-left: 22px; }
.guide-prose blockquote {
  margin: 20px 0; padding: 2px 0 2px 16px;
  border-left: 3px solid var(--primary); color: var(--muted); font-style: italic;
}
.guide-prose a { color: var(--primary-dark); }

.guide h2 { font-size: 1.22rem; margin: 34px 0 10px; color: var(--primary-dark); }
.guide .facts-list li { font-size: .95rem; }
.guide .boundary-note { margin: 24px 0; }

.guide-nearby { margin-top: 34px; }
.guide-nearby ul {
  list-style: none; padding: 0; margin: 0;
  display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 8px;
}
.guide-nearby li a {
  display: block; padding: 10px 12px; border: 1px solid var(--border);
  border-radius: var(--radius); text-decoration: none; color: var(--primary-dark);
  font-weight: 600; font-size: .9rem; background: var(--bg);
}
.guide-nearby li a:hover { border-color: var(--primary); }
.nb-map { display: block; font-weight: 400; font-size: .76rem; color: var(--muted); }

.guide-cta-map { margin-top: 30px; font-weight: 600; }
.guide-cta-map a { color: var(--primary-dark); }

/* Every ad on the site renders into one of these. Reserved height so switching a
   network on later does not shove the article down as the slot fills. */
.ad-slot { min-height: 90px; margin: 28px 0; }
.ad-slot:empty { display: none; }

.guide-body .site-footer { border-top: 1px solid var(--border); }

@media (min-width: 768px) {
  .guide { padding: 34px 20px 72px; }
  .guide h1 { font-size: 2.3rem; }
  .guide-map { height: 340px; }
}

/* ---------------------------------------------------------------- rail layer */
/* Station names sit beside their dot rather than on top of it, so the dot stays
   readable as a position and the name reads as an annotation of it. Both are
   click-through: the district underneath is what the reader is aiming at. */
.station-label {
  pointer-events: none;
  font: 600 .62rem/1.35 var(--sans, system-ui, sans-serif);
  color: #24323d;
  white-space: nowrap;
  text-shadow: 0 0 3px #fff, 0 0 3px #fff, 0 0 2px #fff;
  display: flex; align-items: center;
}
.station-label.is-interchange { font-weight: 700; color: #12202b; }
@media (max-width: 520px) { .station-label { font-size: .56rem; } }

/* The line list is long — twelve entries — so it wraps onto its own row under the
   region swatches instead of stretching the legend into a column. */
.lg-rail {
  display: flex; flex-wrap: wrap; gap: 2px 8px;
  margin-top: 5px; padding-top: 5px;
  border-top: 1px solid rgba(0, 0, 0, .09);
}
.lg-line { font-size: .64rem; }
.lg-dash {
  width: 12px; height: 3px; border-radius: 2px;
  display: inline-block; margin-right: 4px; vertical-align: middle;
}

/* ------------------------------------------------------------ neighbour chips */
.nb-borders { margin-top: 14px; }
.nb-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.nb-chip {
  font: 600 .74rem/1 var(--sans, system-ui, sans-serif);
  padding: 6px 10px; border-radius: 999px; cursor: pointer;
  background: #fff; color: var(--text, #22303a);
  border: 1.5px solid #cfd8d4;   /* replaced per chip with the region's own colour */
  transition: background .15s ease, transform .15s ease;
}
.nb-chip:hover { background: #f2f6f4; }
.nb-chip:active { transform: translateY(1px); }
@media (prefers-reduced-motion: reduce) { .nb-chip { transition: none; } }

/* ------------------------------------------------------------- colour-by mode */
.colour-by {
  /* Same corner and stacking as the legend, which JS then pushes down below it. */
  position: absolute; z-index: 620; top: 8px; left: 8px;
  display: flex; align-items: center; gap: 6px;
  background: rgba(255, 255, 255, .93); border: 1px solid var(--border, #d7ded9);
  border-radius: 8px; padding: 5px 8px; box-shadow: 0 1px 4px rgba(0, 0, 0, .12);
  font: 600 .68rem/1 var(--sans, system-ui, sans-serif); color: #46545e;
}
.colour-by select {
  font: 600 .72rem/1 var(--sans, system-ui, sans-serif);
  border: 1px solid var(--border, #d7ded9); border-radius: 6px;
  padding: 4px 6px; background: #fff; color: var(--text, #22303a);
}

/* ------------------------------------------------------------------- filters */
.nb-filters {
  display: flex; flex-direction: column; gap: 8px;
  padding: 10px 14px; border-bottom: 1px solid var(--border, #d7ded9);
}
.flt { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.flt > span { font: 600 .72rem/1.2 var(--sans, system-ui, sans-serif); color: #55636d; }
.flt select {
  font: 500 .74rem/1 var(--sans, system-ui, sans-serif);
  border: 1px solid var(--border, #d7ded9); border-radius: 6px;
  padding: 5px 6px; background: #fff; color: var(--text, #22303a);
  max-width: 55%;
}
.flt-check { justify-content: flex-start; }
.flt-check input { margin: 0 8px 0 0; }
.flt-clear {
  align-self: flex-start; background: none; border: 0; cursor: pointer; padding: 0;
  font: 600 .72rem/1 var(--sans, system-ui, sans-serif);
  color: var(--accent, #2f9e8f); text-decoration: underline;
}

/* The map controls stack down the left edge; on a phone the colour-by box would sit
   on top of the zoom buttons, so it drops to a single compact row. */
@media (max-width: 520px) {
  .colour-by { padding: 4px 6px; gap: 4px; font-size: .62rem; }
  .colour-by label { display: none; }
  /* Twelve rail lines wrapped across a phone made the key 98% of the map width, so
     it stopped being a key and became a lid. */
  .map-key { max-width: 66vw; }
  .map-key-body { max-height: calc(100vh - 320px); }
  .lg-item { white-space: normal; }
}

/* --------------------------------------------------------------- map key panel */
/* Shut, this is a button the width of the word "Key" with a row of the current
   colours on it. Open, it is the old legend plus the layer switches. It replaces
   two separate boxes that between them covered a third of the map. */
.map-key {
  position: absolute; left: 8px; top: 8px; z-index: 620;
  background: rgba(255, 255, 255, .94); border: 1px solid var(--border);
  border-radius: 9px; box-shadow: var(--shadow);
  max-width: min(300px, 46vw);
}
.map-key-toggle {
  display: flex; align-items: center; gap: 7px; width: 100%;
  background: none; border: 0; cursor: pointer; padding: 7px 9px;
  font: 700 .72rem/1 var(--sans, system-ui, sans-serif); color: var(--text, #22303a);
}
.mk-dots { display: flex; gap: 2px; }
.mk-dots i { width: 8px; height: 8px; border-radius: 2px; display: block; }
.mk-chevron {
  margin-left: auto; width: 7px; height: 7px; border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor; transform: rotate(45deg) translate(-2px, -2px);
  transition: transform .18s ease; opacity: .55;
}
.map-key.is-open .mk-chevron { transform: rotate(225deg) translate(-1px, -1px); }
@media (prefers-reduced-motion: reduce) { .mk-chevron { transition: none; } }

.map-key-body {
  padding: 0 9px 9px;
  /* However long the line list gets, the panel stops short of the bottom of the map
     and scrolls inside itself rather than pushing past it. */
  max-height: calc(100vh - 220px); overflow-y: auto;
}
.map-key .state-toggle {
  position: static; margin-top: 8px; padding-top: 8px;
  border-top: 1px solid rgba(0, 0, 0, .09);
  box-shadow: none; background: none; border-radius: 0;
}
