/* A local instrument, not a publication.

   Deliberately its own stylesheet and not the documentation site's: the published
   site is a product whose look is part of what it says, and this is a tool for
   finding defects. The two should be free to diverge. Everything here is chosen so
   that a red line reads as WRONG at a glance over both a pale OpenStreetMap raster
   and a dark CARTO one. */

:root {
  --bg: #10141a;
  --panel: #171c24;
  --panel-2: #1e242e;
  --edge: #2b3340;
  --ink: #e6ebf2;
  --ink-dim: #98a3b3;
  --accent: #1b9ce6;
  --bad: #ff2d55;
  --warn: #ff9f1c;
  --add: #ffd21e;
  --rev: #00e0a4;
  --retired: #b06bff;
  --panel-w: 360px;
}

* { box-sizing: border-box; }

/* `.field { display: block }` is a class selector and beats the user agent's
   `[hidden] { display: none }`, so setting el.hidden on a field did nothing and the
   county picker showed under every backdrop. Anything hidden stays hidden. */
[hidden] { display: none !important; }

html, body { height: 100%; margin: 0; }

body {
  font: 13px/1.45 ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  color: var(--ink);
  background: var(--bg);
}

#map { position: absolute; inset: 0 0 0 var(--panel-w); }

#panel {
  position: absolute; inset: 0 auto 0 0; width: var(--panel-w);
  background: var(--panel); border-right: 1px solid var(--edge);
  overflow-y: auto; padding: 0 0 2rem;
}

#panel header { padding: 16px 16px 12px; border-bottom: 1px solid var(--edge); }
h1 { font-size: 15px; margin: 0 0 6px; letter-spacing: .01em; }
h2 { font-size: 12px; margin: 0 0 8px; text-transform: uppercase;
     letter-spacing: .08em; color: var(--ink-dim); font-weight: 600; }
.hint { text-transform: none; letter-spacing: 0; font-weight: 400; opacity: .7; }
.sub, .note { color: var(--ink-dim); font-size: 11.5px; margin: 4px 0 0; }
.warnnote { color: #ffd88a; background: #2a2410; border-left: 2px solid var(--warn);
            padding: 7px 9px; border-radius: 0 4px 4px 0; margin-top: 8px; }
code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 11px; }

.block { padding: 14px 16px; border-bottom: 1px solid var(--edge); }

.banner { margin: 0; padding: 10px 16px; font-size: 12px;
          background: #2a2410; color: #ffd88a; border-bottom: 1px solid var(--edge); }
.banner.bad { background: #2c1119; color: #ffb3c1; }
.banner button { margin-left: 8px; }

.tally { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.tally div { background: var(--panel-2); border-radius: 6px; padding: 10px; }
.tally b { display: block; font-size: 19px; font-variant-numeric: tabular-nums; }
.tally span { display: block; color: var(--ink-dim); font-size: 10.5px; margin-top: 2px; }

.field { display: block; margin: 0 0 10px; }
.field > span { display: block; color: var(--ink-dim); font-size: 11px; margin-bottom: 4px; }
.field.inline { display: grid; grid-template-columns: 1fr 140px; align-items: center; }
.field.inline > span { margin: 0; }

select, input[type="search"] {
  width: 100%; background: var(--panel-2); color: var(--ink);
  border: 1px solid var(--edge); border-radius: 5px; padding: 6px 8px; font: inherit;
}
input[type="range"] { width: 100%; }
button {
  background: var(--panel-2); color: var(--ink); border: 1px solid var(--edge);
  border-radius: 5px; padding: 4px 9px; font: inherit; cursor: pointer;
}
button:hover { border-color: var(--accent); }

.switch { display: flex; align-items: center; gap: 8px; padding: 3px 0; cursor: pointer; }
.switch input { margin: 0; }
.switch .sw { width: 14px; height: 6px; border-radius: 3px; flex: none; }
.switch .sw.dot { width: 9px; height: 9px; border-radius: 50%; }
.switch em { font-style: normal; color: var(--ink-dim); margin-left: auto;
             font-variant-numeric: tabular-nums; font-size: 11px; }

.rows { list-style: none; margin: 0; padding: 0; max-height: 260px; overflow-y: auto; }
.rows li { padding: 5px 6px; border-radius: 4px; cursor: pointer;
           display: grid; grid-template-columns: 1fr auto; gap: 6px; align-items: baseline; }
.rows li:hover { background: var(--panel-2); }
.rows li .m { color: var(--ink-dim); font-variant-numeric: tabular-nums; font-size: 11px; }
.rows li .t { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rows li.warnrow .m { color: var(--bad); }
.bar { grid-column: 1 / -1; height: 3px; background: var(--edge); border-radius: 2px; }
/* The row's numbers say what they are. "100% · 5 km" was read as a 5 km basin; it
   meant 5 km stranded out of 3,363. A bare number in a narrow column is a guess. */
.rows li .cap { grid-column: 1 / -1; color: var(--ink-dim); font-size: 10.5px;
                font-variant-numeric: tabular-nums; }
.bar i { display: block; height: 100%; background: var(--accent); border-radius: 2px; }

#detail dl { margin: 0; display: grid; grid-template-columns: auto 1fr; gap: 2px 10px; }
#detail dt { color: var(--ink-dim); font-size: 11px; }
#detail dd { margin: 0; font-size: 11.5px; word-break: break-word; }
#detail .quote { margin-top: 8px; padding: 8px; background: var(--panel-2);
                 border-left: 2px solid var(--warn); border-radius: 0 4px 4px 0;
                 font-size: 11px; color: #d6c9a8; }

#legend {
  /* Bottom-anchored and free to grow upward, but never off the top of the window: on a
     short window the form theme plus an overlay key plus the never-thinned block is
     taller than the map. It scrolls rather than being clipped, because a key with its
     first rows cut off is worse than one you have to scroll. */
  position: absolute; right: 10px; bottom: 10px;
  max-height: calc(100vh - 150px); overflow-y: auto; background: rgba(23,28,36,.93);
  border: 1px solid var(--edge); border-radius: 6px; padding: 9px 11px; font-size: 11px;
  max-width: 230px;
}
#legend b { display: block; font-size: 10px; text-transform: uppercase;
            letter-spacing: .07em; color: var(--ink-dim); margin: 6px 0 3px; }
#legend b:first-child { margin-top: 0; }
#legend span { display: flex; align-items: center; gap: 7px; }
#legend i { width: 16px; height: 3px; border-radius: 2px; flex: none; }
#legend i.dot { width: 9px; height: 9px; border-radius: 50%; }
/* The dashed key needs height to read as a broken line rather than as a grey smear. */
#legend i.dashed { height: 3px; border-radius: 0; }
#legend .foot { display: block; margin-top: 5px; color: var(--ink-dim); font-size: 10px;
                line-height: 1.35; }

.maplibregl-popup-content {
  background: var(--panel); color: var(--ink); border: 1px solid var(--edge);
  border-radius: 6px; font: 11.5px/1.45 ui-sans-serif, system-ui, sans-serif;
  max-width: 340px; max-height: 320px; overflow-y: auto;
}
.maplibregl-popup-tip { border-top-color: var(--panel) !important;
                        border-bottom-color: var(--panel) !important; }
.maplibregl-popup-content dl { margin: 0; display: grid;
                               grid-template-columns: auto 1fr; gap: 2px 8px; }
.maplibregl-popup-content dt { color: var(--ink-dim); }
.maplibregl-popup-content dd { margin: 0; word-break: break-word; }
.maplibregl-popup-close-button { color: var(--ink-dim); font-size: 16px; }
.maplibregl-ctrl-top-right .maplibregl-ctrl-scale { margin-top: 4px; clear: both; }
#legend { z-index: 2; }


/* ── The epoch selector ─────────────────────────────────────────────────────
   STEPPED, NEVER A SLIDER. A continuous control implies a precision the data does not
   have, and a sliding one implies a tween — but flow cannot be interpolated across
   epochs, because each is modelled on its own network and the control switches dataset
   rather than animating one. The widget has to say that, not a note beside it. */

.steps { display: flex; gap: 2px; align-items: stretch; margin-top: 2px; }
.steps button {
  flex: 1; padding: 6px 2px 5px; font-size: 10.5px; line-height: 1.1;
  border-radius: 4px; border: 1px solid var(--edge); background: var(--panel-2);
  color: var(--ink-dim); cursor: not-allowed; position: relative;
}
.steps button .yr { display: block; font-variant-numeric: tabular-nums; }
.steps button[data-state="built"] {
  background: #1d3a4d; border-color: var(--accent); color: var(--ink);
  cursor: default; font-weight: 600;
}
/* A forthcoming stop is legible, not greyed to invisibility: "1900, not built" is a
   stronger statement that this map is not 1900 than any paragraph would be. */
.steps button[data-state="planned"] { opacity: .55; border-style: dashed; }
.steps button[data-state="planned"]:hover { opacity: .85; border-color: var(--warn); }
#epoch-note { min-height: 2.4em; }

/* ── Links ─────────────────────────────────────────────────────────────────
   The browser default visited-purple is unreadable on this ground: #551a8b against
   #171c24 is barely above the background. Both states are set explicitly, because
   leaving :visited to the browser is what produced the illegible one. */
/* Scoped to nothing in particular ON PURPOSE. Scoping these to #panel and #legend is
   what left the browser default in place everywhere else — the modal, the popups and
   the map's own attribution control, all of which sit on the same dark ground. */
a { color: #6fc8ff; text-decoration: underline; text-underline-offset: 2px; }
a:visited { color: #a99bff; }
a:hover { color: #a8e0ff; }
.links { line-height: 1.9; }

/* A control that opens a box, wearing a link's clothes because it sits in a row of
   links. A real <a href="#"> there would overwrite the view this page keeps in its hash. */
.linkish {
  border: 0; background: none; padding: 0; font: inherit; cursor: pointer;
  color: #6fc8ff; text-decoration: underline; text-underline-offset: 2px;
}
.linkish:hover { color: #a8e0ff; }

/* ── The loading state ─────────────────────────────────────────────────────
   Twenty seconds of empty country is indistinguishable from a crash. */
#loading {
  position: absolute; inset: 0 0 0 var(--panel-w); display: grid; place-content: center;
  gap: 14px; justify-items: center; background: rgba(13, 17, 23, .72);
  z-index: 5; pointer-events: none; transition: opacity .35s;
}
#loading[hidden] { display: none !important; }
#loading p { margin: 0; color: var(--ink-dim); font-size: 12px; }
.spin {
  width: 34px; height: 34px; border-radius: 50%;
  border: 3px solid var(--edge); border-top-color: var(--accent);
  animation: spin 900ms linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .spin { animation-duration: 3s; } }

/* ── The modal ─────────────────────────────────────────────────────────────
   Where the long explanatory prose went, so the panel can be a set of controls. */
#about { position: absolute; inset: 0; z-index: 20; background: rgba(0, 0, 0, .55);
         display: grid; place-content: center; padding: 24px; }
#about[hidden] { display: none !important; }
#about .sheet {
  position: relative; max-width: 620px; max-height: 82vh; overflow-y: auto;
  background: var(--panel); border: 1px solid var(--edge); border-radius: 8px;
  padding: 22px 26px; font-size: 12.5px; line-height: 1.55;
}
#about h3 { margin: 18px 0 6px; font-size: 12px; text-transform: uppercase;
            letter-spacing: .07em; color: var(--ink-dim); }
#about h3:first-child { margin-top: 0; }
#about p { margin: 0 0 8px; }
#about-close { position: absolute; top: 10px; right: 12px; border: 0; background: none;
               color: var(--ink-dim); font-size: 22px; line-height: 1; cursor: pointer; }
#about-close:hover { color: var(--ink); }
#about code { background: var(--panel-2); padding: 1px 4px; border-radius: 3px; }

/* ── Collapsible blocks ────────────────────────────────────────────────── */
details.block > summary { cursor: pointer; list-style: none; }
details.block > summary::-webkit-details-marker { display: none; }
details.block > summary h2 { display: inline; }
details.block > summary::before { content: '▸ '; color: var(--ink-dim); }
details.block[open] > summary::before { content: '▾ '; }

/* ── The attribution control ───────────────────────────────────────────────
   It carries what the page footer used to — a licence condition, not decoration — so
   it has to be readable rather than a hairline, and it is in the BOTTOM-LEFT corner,
   because the bottom-right one is the legend's and a banner over the legend was the
   complaint that moved it here in the first place.

   TWO CLASSES IN THE SELECTOR, DELIBERATELY. MapLibre's own rule is
   `.maplibregl-ctrl.maplibregl-ctrl-attrib`, which outranks a single class however
   late it is loaded; with one class the max-width applied, the colour applied, and the
   background silently did not — leaving grey text on half-opaque white over a dark
   sea, which is the exact illegibility this block exists to fix. The link rule needs
   the same treatment for the same reason. */
.maplibregl-ctrl.maplibregl-ctrl-attrib,
.maplibregl-ctrl.maplibregl-ctrl-attrib.maplibregl-compact,
.maplibregl-ctrl.maplibregl-ctrl-attrib.maplibregl-compact-show {
  max-width: min(52ch, calc(100vw - var(--panel-w) - 270px));
  font-size: 10.5px; line-height: 1.45;
  background-color: rgba(23, 28, 36, .93); color: var(--ink-dim);
  border: 1px solid var(--edge);
}
/* COLOURS ONLY. The padding, the radius and which side the button sits on are all set
   by MapLibre per corner — in the bottom-left the toggle goes on the LEFT and the
   padding flips to suit — so overriding the geometry here would put the ⓘ on top of
   the first word in one corner and nowhere near it in another. */
.maplibregl-ctrl.maplibregl-ctrl-attrib a { color: #6fc8ff; text-decoration: underline; }
.maplibregl-ctrl.maplibregl-ctrl-attrib a:hover { color: #a8e0ff; }

/* THE TOGGLE HAS TO STAY VISIBLE WHILE THE PANEL IS OPEN. MapLibre gives the button a
   5%-black wash once open, which is designed against its white default and disappears
   completely on this dark ground — leaving an attribution that can be opened but, to
   the eye, not closed again. Both states get a wash that shows. */
.maplibregl-ctrl-attrib-button,
.maplibregl-ctrl-attrib.maplibregl-compact-show .maplibregl-ctrl-attrib-button {
  background-color: rgba(255, 255, 255, .82); border-radius: 12px;
}
.maplibregl-ctrl-attrib-button:hover { background-color: #fff; }
.maplibregl-ctrl-bottom-left { z-index: 2; }

/* A layer's own provenance, printed under it. Denser than the panel's other lists
   because it is reference rather than reading: you come to it with a question. */
.note dl.stamp { margin: 5px 0 0; display: grid; grid-template-columns: auto 1fr;
  gap: 1px 8px; font-size: 11px; }
.note dl.stamp dt { color: var(--ink-dim); }
.note dl.stamp dd { margin: 0; word-break: break-word; }

/* ── Small screens ──────────────────────────────────────────────────────────
   MEASURED BEFORE IT WAS WRITTEN, because "needs better mobile support" is not a
   specification and guessing at one is how you fix the wrong thing. At four phone
   viewports, with the panel at its fixed 360px and the map inset by it:

     iPhone SE   399 px wide   map  15 px —  4% of the screen
     iPhone 14   405 px        map  30 px —  7%
     Pixel 7     416 px        map  52 px — 13%
     iPad mini   744 px        map 384 px — 52%

   The legend, at 230px, covered TWELVE TIMES the area of the map on an iPhone SE.
   This is not a map with a cramped panel; it is a panel with a sliver of map beside
   it, and no `@media` rule existed anywhere in this file except one for reduced
   motion. The viewport meta was already correct, so nothing was scaled or overflowing
   — the layout simply assumed a desktop and got one 400 px wide.

   THE MAP TAKES THE WHOLE SCREEN AND THE PANEL BECOMES A DRAWER. A map you cannot see
   is not a map, and everything in the panel is ABOUT the map: the figures describe it,
   the layer switches change it, the basin list flies it somewhere. So the map is the
   thing that must always be visible and the panel is the thing that may be summoned.

   720px, not a device: it is where the panel stops leaving a usable map beside it.
   Above it the desktop layout is untouched. */
/* Hidden by default and revealed by the small-screen block, so the desktop layout is
   untouched and the button cannot appear where there is no drawer to open. */
#panel-toggle { display: none; }

@media (max-width: 720px) {
  /* NO DOCUMENT SCROLL. Everything here is absolutely positioned against the viewport,
     so a scrollbar has nothing to scroll — but the gutter is still reserved, and it
     showed as a dark strip down the right edge of a full-width map. A real phone
     overlays its scrollbars and would not show it; a desktop browser at this width
     does, which is where it was found. */
  html, body { height: 100%; overflow: hidden; }

  #map { inset: 0; }                       /* the whole screen, always */
  #panel-toggle { display: block; }

  #panel {
    width: min(var(--panel-w), 88vw);
    transform: translateX(-102%);          /* 102, so the border does not peek */
    transition: transform .22s ease;
    box-shadow: 0 0 24px rgba(0, 0, 0, .55);
    z-index: 5;
  }
  #panel.open { transform: none; }
  @media (prefers-reduced-motion: reduce) { #panel { transition: none; } }

  /* The handle stays put when the drawer moves, so it is never off-screen with the
     panel it opens. Sized for a thumb rather than a cursor: 44px is the smallest
     target most touch guidance will defend, and this is the control everything else
     on the page is reached through. */
  #panel-toggle {
    position: absolute; top: 10px; left: 10px; z-index: 6;
    min-width: 44px; min-height: 44px; padding: 0 12px;
    background: rgba(23, 28, 36, .93); color: var(--ink);
    border: 1px solid var(--edge); border-radius: 6px;
    font: 600 12px/1 ui-sans-serif, system-ui, sans-serif; letter-spacing: .04em;
  }
  #panel.open ~ #panel-toggle { left: calc(min(var(--panel-w), 88vw) + 10px); }

  /* The legend was covering the map twelve times over. It collapses to its heading,
     opens on a tap, and never takes more than a third of the height — a key that
     hides the thing it explains is worse than no key. */
  #legend {
    max-width: min(230px, 66vw); max-height: 34vh; font-size: 10.5px;
    bottom: 8px; right: 8px;
  }
  #legend.shut > :not(b:first-child) { display: none; }
  #legend b:first-child::after { content: ' ▾'; color: var(--ink-dim); }
  #legend.shut b:first-child::after { content: ' ▸'; }

  /* A 340px popup on a 375px screen leaves no map at all around what it points at. */
  .maplibregl-popup-content { max-width: min(340px, 84vw); max-height: 46vh; }

  /* MapLibre's own controls are 29px, which is under every touch target guideline
     going, and this map is panned and zoomed by hand on a phone. */
  .maplibregl-ctrl button { width: 36px; height: 36px; }
}
