/* =========================================================================
   COPERNICUS-ALIGNED — light, institutional, and not a dashboard.
   =========================================================================
   The dark console with coloured accents reads as a product demo whatever the
   accents are. This page's claim is that it is a TECHNICAL RECORD, and the
   register a European due-diligence reader expects for that is a document:
   paper ground, black-blue text, hairline rules, one institutional blue, and
   colour only where it carries meaning.

   The blue is Copernicus Marine's own. That is not decoration by association —
   the sargassum product, the currents, the waves and the licence quoted in the
   footer are all theirs. Borrowing the agency's visual language is the honest
   move where inventing a house palette would be pretending the data is ours.

   CONTRAST MEASURED AGAINST BOTH GROUNDS, not eyeballed. Every token below
   clears 3.0:1 for graphics and all but four clear 4.5:1 for body text; the
   four that do not (muted, assumed, sev-0) are never body text. Audited
   2026-09-11.

   THE TWO SEPARATIONS SURVIVE, as they did through the dark palette:
     · `synthetic` sits off the severity ramp and off measured/modelled.
     · `unknown` sits off the ramp too — an unobserved coast must never borrow
       a pale severity colour, which is how "nobody looked" becomes "nothing
       there".
   ========================================================================= */
:root {
  /* ground ---------------------------------------------------------------- */
  --nm-ground:   #FFFFFF;
  --nm-panel:    #F2F6F9;
  --nm-panel-2:  #E8EEF3;
  --nm-rule:     #C9D6E0;
  --nm-rule-soft:#E1E9EF;

  /* text ------------------------------------------------------------------ */
  --nm-ink:      #0B2B40;
  --nm-ink-2:    #4A6274;
  --nm-muted:    #6B7D8C;

  /* provenance — the four words, as colour --------------------------------- */
  --nm-measured: #0E5AA7;   /* Copernicus blue */
  --nm-modelled: #41729B;
  --nm-assumed:  #71808E;
  --nm-synthetic:#6B4E8A;   /* off both axes, on purpose */

  /* marks ----------------------------------------------------------------- */
  --nm-accent:   #9A5B00;   /* sargassum ochre, dark enough to read on paper */
  --nm-signal:   #B3121C;

  /* severity ramp: grey -> green -> amber -> burnt -> red -------------------- */
  --nm-sev-0:    #71808E;
  --nm-sev-1:    #2F6B44;
  --nm-sev-2:    #8A6000;
  --nm-sev-3:    #A8451A;
  --nm-sev-4:    #B3121C;
  --nm-unknown:  #41729B;   /* off the ramp: not a severity, a missing one */
}

/* Dark stays available behind the toggle — a crew opening this on a beach at
   05:00 is a real case and a white screen there is hostile. It keys on the
   ABSENCE of .theme-light rather than a class of its own, because rx-tokens.css
   already flips 45 tokens on that class and two competing theme classes is one
   more than any page needs. Light is now applied by default at boot. */
html:not(.theme-light) {
  /* the chrome has to come with it: without these the palette went dark
     while the panels stayed white, which is worse than either theme */
  --map-bg-tile: var(--nm-ground);
  --panel-bg: rgba(26, 33, 40, 1);
  --panel-bg-solid: rgba(26, 33, 40, 0.96);
  --panel-border: rgba(42, 51, 60, 0.85);
  --panel-border-strong: rgba(62, 73, 84, 0.95);
  --panel-shadow: none;
  --nm-ground:   #12171C;
  --nm-panel:    #1A2128;
  --nm-panel-2:  #161C22;
  --nm-rule:     #2A333C;
  --nm-rule-soft:#1F262D;
  --nm-ink:      #E6E8EA;
  --nm-ink-2:    #97A1AA;
  --nm-muted:    #6B747D;
  --nm-measured: #6FA3D0;
  --nm-modelled: #6E93A8;
  --nm-assumed:  #8A857C;
  --nm-synthetic:#9C86AB;
  --nm-accent:   #C08F4A;
  --nm-signal:   #D8615C;
  --nm-sev-0:    #68757F;
  --nm-sev-1:    #6FA37E;
  --nm-sev-2:    #C0A05A;
  --nm-sev-3:    #C4794A;
  --nm-sev-4:    #D8615C;
  --nm-unknown:  #6E93A8;
}

/* tramos.css — VBK-SAR-01 arrival console (per-tramo), RX-OS idiom.
 *
 * MOBILE FIRST, and that is not a slogan here: the reader is a hotel ops
 * manager holding a phone on the sand. The base rules below ARE the phone
 * layout — a plain vertical stack in document flow, which cannot overflow
 * horizontally because nothing is positioned. The floating-panel desktop
 * layout only switches on at 901px.
 *
 * The panel / chip / metric / button chrome is the same idiom as playas.css
 * (which is the gps-RD Fleet idiom). It is restated here rather than imported
 * because playas.css also carries its own absolute layout, and that layout is
 * not this screen's. Colours, radii, fonts and durations all come from
 * rx-tokens.css — nothing is invented locally except the severity ramp.
 */

/* --- second token layer: panel chrome + the severity ramp ---------------- */
:root {
  --map-bg-tile: #EDF2F6;
  --panel-bg: rgba(255, 255, 255, 1);
  --panel-bg-solid: rgba(255, 255, 255, 0.99);
  --panel-border: rgba(11, 43, 64, 0.12);
  --panel-border-strong: rgba(11, 43, 64, 0.24);
  --panel-shadow: none;
  --panel-radius: 2px;

  /* Severity 0–4. Same 0–4 scale the drone observation already uses
     (`categoria` in observaciones.geojson), so one number means one thing
     across the product. Levels 0/1/2/4 are RX tokens; only level 3 needs a
     hue of its own — the gap between anomaly amber and guard red. */
  /* Not --rx-fog-4: at severity 0 a 7 px line in #3A4458 is invisible on the
     dark basemap, and severity 0 is the FIRST thing the demo shows — "here is
     your beach, these are your tramos". It has to read as a drawn coastline. */
  --sev-0: var(--nm-sev-0);
  --sev-1: var(--nm-sev-1);
  --sev-2: var(--nm-sev-2);
  --sev-3: var(--nm-sev-3);
  --sev-4: var(--nm-sev-4);

  /* Anything synthetic is drawn in this one colour, everywhere, so the eye
     learns "violet = not a measurement" in about four seconds. */
  --synthetic: var(--nm-synthetic);

  /* The drift arrows stopped being synthetic when they started reading the
     server's own field, so they stopped being violet. Keeping them violet
     would teach the opposite of what that colour means here: it would say
     "not a measurement" about the one ocean the ETA is actually computed in.
     Teal is off the severity ramp on purpose — an arrow must never read as
     a severity. */
  --modelled: var(--nm-modelled);
  /* Swell sits under the current arrows and must not compete with them: a
     dimmer, cooler line that reads as water rather than as a vector. */
  --swell: var(--nm-modelled);
}

html.theme-light {
  --map-bg-tile: #E7ECF1;
  --panel-bg: rgba(255, 255, 255, 1);
  --panel-bg-solid: rgba(255, 255, 255, 0.98);
  --panel-border: rgba(15, 20, 25, 0.10);
  --panel-border-strong: rgba(15, 20, 25, 0.20);
  --panel-shadow: none;
  --sev-0: #55647C;
  --sev-3: #A85A18;
  --synthetic: #6B3FA0;
  --modelled: #2E6F80;
  --swell: #7FA6B4;
}

* { box-sizing: border-box; }
html, body {
  /* Every digit on this page lines up. A console where 11.5 and 108.9 h do not
     share a column is a console someone has to read twice, and the numbers are
     the whole product. */
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--rx-ff-sans);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;               /* the 390px rule, enforced at the root */
}

/* ======================================================================
   BASE = PHONE. Document flow, one column, nothing positioned.
   ====================================================================== */
.stage {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 0 8px 12px;
  min-height: 100vh;
  background: var(--bg);
}

/* Phone reading order IS the demo walkthrough: 1 your beach · 2 something is
   coming · 3 it lands here at this hour · 4 it was measured · 5 your bulletin.
   The scrubber therefore sits directly under the map it drives, before the
   answer panel, which is not its DOM position. */
.stage > .mockbar   { order: 0; }
.stage > .topbar    { order: 1; }
.stage > .map-wrap  { order: 2; }
.stage > .scrubber  { order: 3; }
.stage > .leftcol   { order: 4; display: flex; flex-direction: column; gap: 8px; }
/* Equal order to .leftcol, so among them DOM order decides: the answer, then
   the layer control, then the weather, then the rail. On a phone the map is
   already above all of this; a control for the map has to follow it. */
.stage > .layers    { order: 4; }
.stage > .weather   { order: 4; }
.stage > .rail      { order: 5; }
.stage > .credits   { order: 6; }
.stage > .toast     { order: 7; }

.panel {
  background: var(--panel-bg);
  border: 1px solid var(--panel-border);
  border-radius: var(--panel-radius);
  color: var(--fg);
  max-width: 100%;
  min-width: 0;
}

.panel-header {
  display: flex; align-items: center; gap: 8px;
  padding: 10px 12px;
  border-bottom: 1px solid var(--panel-border);
  font-size: 10px; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--fg-2); min-height: 38px;
}
.panel-header .marker { color: var(--accent); font-size: 12px; letter-spacing: 0; }
.panel-header .title { color: var(--fg-1); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.panel-header .right { margin-left: auto; display: flex; gap: 6px; align-items: center; flex: 0 0 auto; }

/* ---------- the synthetic-data banner --------------------------------- */
/* Full bleed, first thing on the page, present in BOTH views and in both
   themes. It is not dismissible. A mock that reads as a measurement is the
   worst failure this project can produce, so this is the loudest element on
   the screen and it is deliberately not pretty. */
.mockbar {
  margin: 0 -8px;
  padding: 7px 10px;
  /* A full-width fill in the synthetic colour shouted louder than anything it
     was labelling. Tinted ground, synthetic ink, and the colour kept as the
     left rule so it still reads as "this is generated" without becoming the
     loudest thing on the page. Light default; the dark set is below. */
  background: #F1ECF5;
  color: #52356E;
  border-left: 3px solid var(--synthetic);
  font-size: 10px;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  line-height: 1.45;
  display: flex; align-items: baseline; gap: 8px;
  border-bottom: 1px solid rgba(0,0,0,0.25);
}
.mockbar .b { font-weight: 700; letter-spacing: 0.16em; flex: 0 0 auto; }
.mockbar .x { font-weight: 400; opacity: 0.95; text-transform: none; letter-spacing: 0.02em; font-size: 11px; }

/* ---------- top bar ---------------------------------------------------- */
.topbar { display: flex; flex-direction: column; gap: 8px; padding: 10px 12px; }
.brand-row {
  display: flex; align-items: baseline; gap: 7px;
  font-size: 12px; letter-spacing: 0.06em; color: var(--fg-2);
}
.brand-row .brand-strong { color: var(--fg); font-weight: 600; letter-spacing: -0.01em; font-size: 13px; }
.brand-row .sep { color: var(--accent); }
.brand-row .path {
  color: var(--fg-3); font-size: 10px; letter-spacing: 0.10em;
  margin-left: auto; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.info-btn {
  background: transparent; cursor: pointer;
  border: 1px solid var(--panel-border-strong); border-radius: 50%;
  width: 18px; height: 18px; padding: 0; flex: 0 0 18px;
  font-family: var(--rx-ff-sans); font-size: 10px; font-style: italic; line-height: 1;
  color: var(--fg-3);
}
.info-btn:hover { color: var(--fg); border-color: var(--fg-3); }
/* The breadcrumb is the only decorative string in the bar and the first thing
   to go: below 640px it pushes the brand onto two lines. */
@media (max-width: 640px) { .brand-row .path { display: none; } }

.bar-row { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.bar-row .spacer { flex: 1 1 auto; min-width: 0; }
.site-note {
  font-size: 10px; color: var(--fg-3); line-height: 1.45; letter-spacing: 0.02em;
}
.site-note:empty { display: none; }

/* SEA STATE IN THE TOP BAR. Carries the MODELLED colour, not the accent:
   MFWAM is an analysis/forecast model and the bar must not lend it the weight
   the interface gives a measurement. `.out` is the wall clock having fallen
   off the end of the horizon — dimmed, and the value itself is prefixed with
   ~ in the markup, because colour alone is not a channel. */
.hs-now {
  display: inline-flex; align-items: baseline; gap: 4px;
  padding: 2px 8px; border-radius: 2px;
  border: 1px solid color-mix(in srgb, var(--modelled) 45%, transparent);
  background: color-mix(in srgb, var(--modelled) 8%, transparent);
  font-size: 11px; line-height: 1.3; white-space: nowrap;
}
.hs-now .k {
  font-size: 9px; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--fg-3);
}
.hs-now b { font-size: 13px; font-weight: 700; color: var(--modelled); letter-spacing: 0; }
.hs-now .u { font-size: 9px; color: var(--fg-3); }
.hs-now.out { opacity: 0.62; border-style: dashed; }
.hs-now.none { border-color: var(--fg-3); background: transparent; color: var(--fg-3); }

/* the demo walkthrough: 1 site · 2 drift · 3 arrival · 4 measurement · 5 aviso */
.stepno {
  display: inline-flex; align-items: center; justify-content: center;
  width: 16px; height: 16px; flex: 0 0 16px; border-radius: 50%;
  background: var(--accent); color: var(--on-status);
  font-size: 10px; font-weight: 700; line-height: 1; letter-spacing: 0;
}
html.theme-light .stepno { color: var(--rx-paper); }

/* point-of-read marker — sits next to the value, not in a legend */
.sim-chip {
  display: inline-block; margin-left: 6px;
  font-size: 9px; font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--synthetic); border: 1px solid var(--synthetic);
  border-radius: 2px; padding: 1px 5px; vertical-align: 1px;
}

.chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 10px; border-radius: 2px;
  font-family: var(--rx-ff-sans); font-size: 10px;
  letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--fg-1); background: transparent;
  border: 1px solid var(--panel-border-strong);
  cursor: pointer; transition: all var(--rx-dur-fast) var(--rx-ease);
  user-select: none; white-space: nowrap;
}
.chip:hover { border-color: var(--line-strong); color: var(--fg); }
.chip .count { font-size: 10px; color: var(--fg-3); font-variant-numeric: tabular-nums; }
.chip[data-active="true"] { background: var(--rx-signal-500); border-color: var(--rx-signal-500); color: var(--on-status); }
html.theme-light .chip[data-active="true"] { background: var(--rx-deep-500); border-color: var(--rx-deep-500); color: var(--rx-paper); }
.chip[data-active="true"] .count { color: var(--on-status); opacity: 0.7; }
html.theme-light .chip[data-active="true"] .count { color: var(--rx-paper); }

/* view switch — a two-position segmented control, not a checkbox */
.seg {
  display: inline-flex; border: 1px solid var(--panel-border-strong);
  border-radius: 2px; overflow: hidden; flex: 0 0 auto;
}
.seg button {
  background: transparent; border: 0; cursor: pointer;
  font-family: var(--rx-ff-sans); font-size: 10px; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--fg-2); padding: 6px 11px; white-space: nowrap;
}
.seg button[aria-pressed="true"] { background: var(--surface-2); color: var(--fg); }

.btn {
  background: transparent; border: 1px solid var(--panel-border-strong);
  border-radius: 2px; padding: 6px 10px;
  font-family: var(--rx-ff-sans); font-size: 10px;
  letter-spacing: 0.10em; text-transform: uppercase; color: var(--fg-1);
  cursor: pointer; transition: all var(--rx-dur-fast) var(--rx-ease);
  text-decoration: none; display: inline-flex; align-items: center; gap: 5px;
  white-space: nowrap;
}
.btn:hover { color: var(--fg); border-color: var(--line-strong); }
.btn[aria-pressed="true"] { border-color: var(--accent); color: var(--fg); }
.btn.primary { background: var(--rx-signal-500); color: var(--on-status); border-color: var(--rx-signal-500); }
.btn.primary:hover { background: var(--rx-signal-600); }
html.theme-light .btn.primary { background: var(--rx-deep-500); border-color: var(--rx-deep-500); color: var(--rx-paper); }
.btn.wide { flex: 1 1 auto; justify-content: center; }

/* ---------- map -------------------------------------------------------- */
.map-wrap {
  position: relative;
  height: 38vh; min-height: 210px;
  border-radius: var(--panel-radius);
  border: 1px solid var(--panel-border);
  overflow: hidden;
}
#map {
  position: absolute; inset: 0;
  background: var(--map-bg-tile);
  z-index: 0;
}
/* The banner travels with the map: a screenshot cropped to the map still
   carries the word SIMULACIÓN. Above Leaflet's overlay panes (400–600),
   below its controls (800). */
.map-stamp {
  position: absolute; left: 8px; bottom: 8px; z-index: 650;
  pointer-events: none;
  background: var(--synthetic); color: #FFFFFF;
  font-size: 10px; font-weight: 700; letter-spacing: 0.18em; text-transform: uppercase;
  padding: 4px 9px; border-radius: 2px;
  box-shadow: 0 1px 4px rgba(0,0,0,0.35);
}
#map .leaflet-control-attribution {
  font-size: 9px; background: rgba(0,0,0,0.45); color: #8a93a3;
  font-family: var(--rx-ff-sans);
}
html.theme-light #map .leaflet-control-attribution { background: rgba(255,255,255,0.82); color: #55606E; }
#map .leaflet-control-attribution a { color: var(--fg-2); }
#map .leaflet-control-zoom { border: 0; margin: 0 10px 10px 0; }
#map .leaflet-control-zoom a {
  background: var(--panel-bg-solid); color: var(--fg-1);
  border: 1px solid var(--panel-border-strong);
}
#map .leaflet-control-zoom a:hover { background: var(--surface-2); color: var(--fg); }
#map .leaflet-popup-content-wrapper, #map .leaflet-popup-tip {
  background: var(--panel-bg-solid); color: var(--fg);
  border: 1px solid var(--panel-border-strong);
  box-shadow: var(--panel-shadow); border-radius: 2px;
}
#map .leaflet-popup-content { margin: 9px 11px; font-size: 12px; line-height: 1.5; }
#map .leaflet-tooltip {
  background: var(--panel-bg-solid); color: var(--fg-1);
  border: 1px solid var(--panel-border-strong); box-shadow: none;
  font-family: var(--rx-ff-mono); font-size: 10px; letter-spacing: 0.06em;
}
#map .leaflet-tooltip::before { display: none; }

/* ---------- the answer ------------------------------------------------- */
/* Everything above the fold on a phone. One question, one answer. */
.answer { overflow: hidden; }
.ans-site {
  padding: 10px 14px 0;
  font-size: 10px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--fg-3);
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
}
.ans-site .tid { font-family: var(--rx-ff-mono); color: var(--accent); letter-spacing: 0.04em; }
.ans-name {
  padding: 3px 14px 0; font-size: 15px; color: var(--fg); letter-spacing: -0.01em;
  line-height: 1.3;
}
.ans-head {
  padding: 10px 14px 12px;
  display: flex; align-items: flex-end; gap: 14px; flex-wrap: wrap;
}
.ans-eta { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.ans-eta .k { font-size: 9px; letter-spacing: 0.16em; text-transform: uppercase; color: var(--fg-3); }
/* Generated numbers are violet EVERYWHERE, including the hero figure. The
   urgency red belongs to the severity badge; the arrival figure's job is to
   say "this came out of a simulation" at the instant it is read. */
.ans-eta .v {
  font-size: 44px; font-weight: 500; line-height: 0.95; letter-spacing: -0.03em;
  color: var(--synthetic); font-variant-numeric: tabular-nums;
}
.ans-eta .v .u { font-size: 0.4em; letter-spacing: 0; color: var(--fg-2); margin-left: 0.2em; }
.ans-eta .v.now { font-size: 34px; }
.ans-eta .v.clear { color: var(--fg-3); font-size: 24px; letter-spacing: -0.01em; line-height: 1.2; }
.ans-sev { display: flex; flex-direction: column; gap: 5px; margin-left: auto; align-items: flex-end; }
.ans-sev .k { font-size: 9px; letter-spacing: 0.16em; text-transform: uppercase; color: var(--fg-3); }
.sev-badge {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 7px 12px; border-radius: 2px;
  font-size: 12px; letter-spacing: 0.10em; text-transform: uppercase; font-weight: 600;
  color: var(--on-status); background: var(--sev-0); white-space: nowrap;
}
html.theme-light .sev-badge { color: #FFFFFF; }
.sev-badge .n { font-variant-numeric: tabular-nums; opacity: 0.75; font-weight: 500; }
.sev-badge[data-sev="0"] { background: var(--sev-0); }
.sev-badge[data-sev="1"] { background: var(--sev-1); }
.sev-badge[data-sev="2"] { background: var(--sev-2); }
.sev-badge[data-sev="3"] { background: var(--sev-3); }
.sev-badge[data-sev="4"] { background: var(--sev-4); }

.ans-line {
  padding: 10px 14px; border-top: 1px solid var(--panel-border);
  font-size: 13px; color: var(--fg-1); line-height: 1.5;
}
.ans-line .lead { color: var(--fg); font-weight: 600; }
.ans-when {
  padding: 0 14px 10px; font-size: 11px; color: var(--fg-3);
  letter-spacing: 0.04em; font-variant-numeric: tabular-nums;
}
.ans-flags { display: flex; gap: 6px; flex-wrap: wrap; padding: 0 14px 12px; }
.tag {
  font-size: 10px; letter-spacing: 0.06em; padding: 3px 8px;
  border: 1px solid var(--panel-border-strong); border-radius: 2px; color: var(--fg-2);
  white-space: nowrap;
}
.tag.synthetic { border-color: var(--synthetic); color: var(--synthetic); }
.tag.measured { border-color: var(--rx-sense-500); color: var(--info-text); }

/* the PLACEHOLDER strap that rides under every synthetic number */
.mock-strap {
  margin: 0 14px 12px; padding: 8px 10px;
  border: 1px dashed var(--synthetic); border-radius: 2px;
  color: var(--synthetic); font-size: 10px; line-height: 1.5; letter-spacing: 0.02em;
  background: transparent;
}
.mock-strap b { letter-spacing: 0.14em; text-transform: uppercase; font-size: 10px; }

/* ---------- 4 · the measurement, in the operator view ------------------- */
.ans-meas { padding: 10px 14px 12px; border-top: 1px solid var(--panel-border); }
.ans-meas > .k {
  display: flex; align-items: center; gap: 7px;
  font-size: 9px; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--fg-3); margin-bottom: 8px;
}
.meas-grid { display: flex; gap: 14px; align-items: flex-end; flex-wrap: wrap; }
.meas-cell { display: flex; flex-direction: column; gap: 2px; }
.meas-cell .mk { font-size: 9px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--fg-3); }
.meas-cell .mv { font-size: 20px; line-height: 1; color: var(--fg); font-variant-numeric: tabular-nums; }
.meas-cell .mv small { font-size: 11px; color: var(--fg-2); }
.meas-when { font-size: 10px; color: var(--fg-3); margin-top: 8px; line-height: 1.5; }
.meas-none { font-size: 12px; color: var(--fg-2); line-height: 1.5; }

/* ---------- 5 · the bulletin ------------------------------------------- */
.aviso pre {
  margin: 0; padding: 12px 14px;
  font-family: var(--rx-ff-mono); font-size: 11px; line-height: 1.65;
  color: var(--fg-1); white-space: pre-wrap; word-break: break-word;
}
.aviso-note {
  padding: 0 14px 12px; font-size: 10px; color: var(--synthetic); line-height: 1.5;
}

/* ---------- scrubber --------------------------------------------------- */
.scrubber { padding: 10px 12px 12px; }
.scrub-row { display: flex; align-items: center; gap: 10px; }
.scrub-status { min-width: 0; flex: 1 1 auto; }
.scrub-status .label { font-size: 9px; letter-spacing: 0.16em; text-transform: uppercase; color: var(--fg-3); display: block; }
.scrub-status .value { font-size: 13px; color: var(--fg); font-variant-numeric: tabular-nums; }
.scrub-status .value .rel { color: var(--fg-3); font-size: 11px; margin-left: 6px; }
.play {
  width: 40px; height: 40px; flex: 0 0 40px; border-radius: 50%;
  border: 1px solid var(--panel-border-strong); background: transparent;
  color: var(--fg); cursor: pointer; font-size: 13px; line-height: 1;
  display: inline-flex; align-items: center; justify-content: center;
}
.play[aria-pressed="true"] { background: var(--accent); border-color: var(--accent); color: var(--on-status); }
html.theme-light .play[aria-pressed="true"] { color: var(--rx-paper); }

input[type="range"].tscrub {
  -webkit-appearance: none; appearance: none;
  width: 100%; margin: 12px 0 6px; height: 22px; background: transparent; cursor: pointer;
}
input[type="range"].tscrub::-webkit-slider-runnable-track {
  height: 4px; border-radius: 2px; background: var(--panel-border-strong);
}
input[type="range"].tscrub::-moz-range-track {
  height: 4px; border-radius: 2px; background: var(--panel-border-strong);
}
input[type="range"].tscrub::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 18px; height: 18px; border-radius: 50%; margin-top: -7px;
  background: var(--synthetic); border: 2px solid var(--bg-raised);
}
input[type="range"].tscrub::-moz-range-thumb {
  width: 18px; height: 18px; border-radius: 50%;
  background: var(--synthetic); border: 2px solid var(--bg-raised);
}
input[type="range"].tscrub:focus-visible { outline: none; box-shadow: var(--focus-ring); border-radius: 2px; }

.ticks {
  display: flex; justify-content: space-between;
  font-size: 9px; letter-spacing: 0.10em; color: var(--fg-3);
  font-variant-numeric: tabular-nums;
}
.legend-row {
  display: flex; gap: 10px; align-items: center; flex-wrap: wrap;
  padding-top: 10px; margin-top: 10px; border-top: 1px solid var(--panel-border);
}
.legend-row .lg {
  display: flex; align-items: center; gap: 5px; font-size: 10px;
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--fg-2);
}
.legend-row .lg .sw { width: 9px; height: 9px; border-radius: 2px; flex: 0 0 9px; }
.legend-row .lg .sw.patch {
  border-radius: 50%; background: transparent;
  border: 1.5px dashed var(--synthetic);
}
/* The current swatch follows the arrows off the synthetic colour: it is the
   server's field now, not the browser's invention. */
.legend-row .lg .sw.vec { border-radius: 0; background: transparent; border-top: 2px solid var(--modelled); height: 2px; width: 14px; flex: 0 0 14px; }
.legend-row .lg .sw.swell { border-radius: 0; background: transparent; border-top: 2px solid var(--swell); height: 2px; width: 14px; flex: 0 0 14px; opacity: 0.75; }
/* The wind swatch is a STAFF WITH A FEATHER, not a bar: the map draws barbs
   and a legend that draws a line teaches the reader to look for a line. Its
   colour comes in from the renderer as --wb, because the wind layer's basis
   is not fixed — a served field is modelled, an absent one is an assumed
   trade wind and must be violet here and violet on the map. */
.legend-row .lg .sw.wind {
  border-radius: 0; background: transparent;
  border-top: 2px solid var(--wb, var(--nm-modelled));
  height: 2px; width: 14px; flex: 0 0 14px; position: relative;
}
.legend-row .lg .sw.wind::after {
  content: ""; position: absolute; right: 0; top: -1px;
  width: 6px; height: 0; border-top: 2px solid var(--wb, var(--nm-modelled));
  transform: rotate(-52deg); transform-origin: right top;
}


/* ---------- layer toggle ------------------------------------------------
   The house .panel / .panel-header chrome, and entries that are real
   <button role="switch"> elements: focusable in source order, driven by
   Enter and Space with no JS, and carrying a visible ring from the shared
   --focus-ring token rather than the UA outline the rest of this page
   suppresses. Two columns, because six entries in one column cost more
   vertical space than the rail can spare on a 900 px screen.
   ---------------------------------------------------------------------- */
.layer-list {
  display: grid; grid-template-columns: 1fr 1fr; gap: 2px;
  padding: 8px 10px;
}
.lay-item {
  display: grid;
  grid-template-columns: 11px 8px minmax(0, 1fr);
  grid-template-rows: auto auto;
  column-gap: 6px; row-gap: 1px; align-items: center;
  min-width: 0; width: 100%;
  padding: 5px 6px; border: 1px solid transparent; border-radius: 2px;
  background: transparent; cursor: pointer; text-align: left;
  font-family: var(--rx-ff-sans); font-size: 10px;
  letter-spacing: 0.06em; text-transform: uppercase; color: var(--fg-2);
  transition: background var(--rx-dur-fast) var(--rx-ease),
              border-color var(--rx-dur-fast) var(--rx-ease);
}
.lay-item:hover { background: var(--surface-2); border-color: var(--panel-border); }
.lay-item:focus-visible {
  outline: none; box-shadow: var(--focus-ring); border-color: var(--panel-border-strong);
}
/* The checkbox is drawn, not borrowed: a native one cannot be tinted with the
   provenance colour in both themes without a vendor property per browser. */
.lay-item .box {
  grid-column: 1; grid-row: 1 / span 2; align-self: center;
  width: 11px; height: 11px; border-radius: 2px;
  border: 1px solid var(--panel-border-strong); background: transparent;
  position: relative;
}
.lay-item[aria-checked="true"] .box { background: var(--fg-2); border-color: var(--fg-2); }
.lay-item[aria-checked="true"] .box::after {
  content: ""; position: absolute; left: 3px; top: 0px;
  width: 3px; height: 6px; border: solid var(--panel-bg);
  border-width: 0 1.5px 1.5px 0; transform: rotate(42deg);
}
/* THE SWATCH IS THE POINT. A layer name without the colour it is drawn in is
   half a label; this control is also the provenance key. */
.lay-item .sw {
  grid-column: 2; grid-row: 1 / span 2; align-self: center;
  width: 8px; height: 8px; border-radius: 2px;
}
.lay-item .nm {
  grid-column: 3; grid-row: 1; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  color: var(--fg-1);
}
.lay-item[aria-checked="false"] { opacity: 0.55; }
.lay-item[aria-checked="false"] .nm { text-decoration: line-through; }
.lay-item .bs {
  grid-column: 3; grid-row: 2; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-family: var(--rx-ff-mono); font-size: 8px;
  letter-spacing: 0.08em; text-transform: uppercase; opacity: 0.92;
}
.lay-item .bs[data-b="measured"]  { color: var(--nm-measured); }
.lay-item .bs[data-b="modelled"]  { color: var(--nm-modelled); }
.lay-item .bs[data-b="assumed"]   { color: var(--nm-assumed); }
.lay-item .bs[data-b="synthetic"] { color: var(--nm-synthetic); }
.layer-hint {
  padding: 0 12px 10px; font-size: 9px; line-height: 1.45;
  letter-spacing: 0.04em; color: var(--fg-3);
}

/* ---------- weather readout --------------------------------------------
   Wind and sea state for the selected site at the scrubber's hour. The
   NUMBERS are in --rx-ff-mono and nothing else on the row is: that face is
   reserved for machine values, and spending it on a label would spend the
   one signal that says "this came out of a dataset".
   ---------------------------------------------------------------------- */
.wx-body { padding: 8px 12px 10px; display: flex; flex-direction: column; gap: 6px; }
.wx-row {
  display: grid; grid-template-columns: minmax(0, 6.2em) minmax(0, 1fr); gap: 1px 10px;
  padding-top: 6px; border-top: 1px solid var(--panel-border);
}
.wx-row:first-child { border-top: 0; padding-top: 0; }
.wx-k {
  grid-row: 1 / span 2; align-self: center; min-width: 0;
  font-size: 9px; letter-spacing: 0.13em; text-transform: uppercase;
  color: var(--fg-3); overflow-wrap: anywhere;
}
.wx-v {
  font-family: var(--rx-ff-mono); font-size: 11px; color: var(--fg);
  display: flex; align-items: baseline; gap: 4px; flex-wrap: wrap;
  font-variant-numeric: tabular-nums;
}
.wx-v b { font-weight: 600; font-size: 14px; color: var(--fg); }
.wx-v .u { font-family: var(--rx-ff-sans); font-size: 9px; color: var(--fg-3);
           letter-spacing: 0.08em; text-transform: uppercase; }
.wx-v .none { color: var(--fg-3); }
.wx-b { display: flex; align-items: baseline; gap: 6px; min-width: 0; flex-wrap: wrap; }
.wx-n { font-size: 9px; line-height: 1.4; color: var(--fg-3); min-width: 0;
        overflow-wrap: anywhere; }

@media (max-width: 400px) {
  .layer-list { grid-template-columns: 1fr; }
  .wx-row { grid-template-columns: 1fr; }
  .wx-k { grid-row: auto; }
}

/* ---------- rail (the tramo list) -------------------------------------- */
.rail { display: flex; flex-direction: column; overflow: hidden; }
.rail-list { overflow-y: auto; max-height: 44vh; }
.layers, .weather { display: flex; flex-direction: column; overflow: hidden; }
.rail-item {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 12px; border-bottom: 1px solid var(--panel-border);
  cursor: pointer; transition: background var(--rx-dur-fast) var(--rx-ease);
}
.rail-item:last-child { border-bottom: 0; }
.rail-item:hover { background: var(--surface-2); }
.rail-item.sel { background: var(--surface-2); box-shadow: inset 2px 0 0 var(--accent); }
.rail-item .dot { width: 9px; height: 9px; border-radius: 50%; flex: 0 0 9px; }
.rail-item .txt { min-width: 0; flex: 1; display: flex; flex-direction: column; gap: 2px; }
.rail-item .n { font-size: 12px; color: var(--fg); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rail-item .n .tid { font-family: var(--rx-ff-mono); color: var(--fg-2); font-size: 11px; margin-right: 6px; }
.rail-item .m { font-size: 10px; color: var(--fg-3); letter-spacing: 0.08em; text-transform: uppercase; }
.rail-item .eta {
  font-size: 13px; color: var(--fg-1); font-variant-numeric: tabular-nums;
  font-family: var(--rx-ff-mono); flex: 0 0 auto;
}
.rail-item .eta { color: var(--synthetic); }
.rail-item .eta.now { color: var(--synthetic); font-weight: 700; }
.rail-item .eta.clear { color: var(--fg-3); }

/* site summary strip above the list */
.summary {
  display: flex; border-bottom: 1px solid var(--panel-border);
  background: var(--panel-bg-solid);
}
.summary .s-item {
  flex: 1; padding: 9px 10px; border-right: 1px solid var(--panel-border);
  display: flex; flex-direction: column; gap: 3px; min-width: 0;
}
.summary .s-item:last-child { border-right: 0; }
.summary .k { font-size: 9px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--fg-3); }
.summary .v { font-size: 19px; line-height: 1; color: var(--fg); font-variant-numeric: tabular-nums; }
.summary .v.sim { color: var(--synthetic); }
.summary .v.sim::after {
  content: "sim"; font-size: 8px; letter-spacing: 0.1em; text-transform: uppercase;
  margin-left: 4px; vertical-align: 3px; opacity: 0.8;
}

/* ---------- analyst-only blocks ---------------------------------------- */
.analyst-only { display: none; }
body[data-view="analyst"] .analyst-only { display: block; }
body[data-view="analyst"] .summary.analyst-only { display: flex; }

.sec { padding: 9px 14px; border-top: 1px solid var(--panel-border); }
.sec > .k { font-size: 9px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--fg-3); margin-bottom: 6px; }
.kv { display: flex; gap: 10px; align-items: baseline; padding: 3px 0; font-size: 12px; }
.kv .kk { color: var(--fg-3); flex: 0 0 40%; min-width: 0; word-break: break-word; }
.kv .vv { color: var(--fg-1); flex: 1 1 auto; min-width: 0; word-break: break-word; font-variant-numeric: tabular-nums; }
.kv .vv.mono { font-family: var(--rx-ff-mono); font-size: 11px; }

/* basis tag — measured / modelled / assumed / synthetic, on every value the
   curator is asked to believe. */
.basis {
  font-size: 9px; letter-spacing: 0.12em; text-transform: uppercase;
  padding: 2px 6px; border-radius: 2px; border: 1px solid currentColor;
  flex: 0 0 auto; white-space: nowrap;
}
.basis[data-b="measured"]  { color: var(--info-text); }
.basis[data-b="modelled"]  { color: var(--warn-text); }
.basis[data-b="assumed"]   { color: var(--fg-3); }
.basis[data-b="synthetic"] { color: var(--synthetic); }

/* layer matrix — what it is now, what replaces it in production. This is the
   curator's table: one row per layer, status first, replacement last. */
.mx { display: flex; flex-direction: column; }
.mx-row {
  padding: 8px 0; border-top: 1px solid var(--panel-border);
  display: flex; flex-direction: column; gap: 4px;
}
.mx-row:first-child { border-top: 0; }
.mx-head { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
.mx-head .lay { font-size: 12px; color: var(--fg); }
.mx-row .now { font-size: 10px; color: var(--fg-2); line-height: 1.5; }
.mx-row .prod { font-size: 10px; color: var(--fg-3); line-height: 1.5; }
.mx-row .prod::before { content: "→ "; color: var(--accent); }
.st-chip {
  font-size: 9px; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase;
  padding: 2px 6px; border-radius: 2px; border: 1px solid currentColor; white-space: nowrap;
}
.st-chip[data-s="sim"]  { color: var(--synthetic); }
.st-chip[data-s="real"] { color: var(--info-text); }
.st-chip[data-s="off"]  { color: var(--danger-text); }
.st-chip[data-s="none"] { color: var(--danger-text); }

/* validation status — the badge that matters most on this project */
.validation {
  margin: 10px 14px; padding: 10px 12px; border-radius: 2px;
  border: 1px solid var(--rx-guard-500); background: var(--rx-guard-900);
}
.validation .st {
  font-size: 12px; letter-spacing: 0.14em; text-transform: uppercase;
  font-weight: 700; color: var(--danger-text); display: flex; align-items: center; gap: 8px;
}
.validation .why { font-size: 10px; color: var(--fg-1); margin-top: 6px; line-height: 1.55; }
.validation ul { margin: 6px 0 0; padding-left: 16px; }
.validation li { font-size: 10px; color: var(--fg-2); line-height: 1.5; margin-bottom: 3px; }

.stale { color: var(--warn-text); }
.ok { color: var(--ok-text); }
.bad { color: var(--danger-text); }

/* ---------- credits ---------------------------------------------------- */
.credits { display: none; }
.credits.open { display: block; }
.credits-body { padding: 10px 14px 12px; display: flex; flex-direction: column; gap: 8px; }
.credits-body .credit-item { font-size: 10px; color: var(--fg-2); letter-spacing: 0.02em; line-height: 1.6; }
.credits-body .credit-item b { color: var(--fg-1); letter-spacing: 0.1em; text-transform: uppercase; font-size: 9px; }
.credits-body a { color: var(--fg-1); }

/* ---------- toast ------------------------------------------------------ */
.toast {
  display: none; padding: 9px 12px; font-size: 11px; letter-spacing: 0.04em;
  border-color: var(--panel-border-strong);
}
.toast.show { display: block; }
.toast.err { border-color: var(--rx-guard-500); color: var(--danger-text); }

/* scrollbars */
.rail-list, .leftcol { scrollbar-width: thin; scrollbar-color: var(--panel-border-strong) transparent; }
.rail-list::-webkit-scrollbar, .leftcol::-webkit-scrollbar { width: 8px; }
.rail-list::-webkit-scrollbar-track, .leftcol::-webkit-scrollbar-track { background: transparent; }
.rail-list::-webkit-scrollbar-thumb, .leftcol::-webkit-scrollbar-thumb {
  background: var(--panel-border-strong); border-radius: 2px;
}

/* map marks */
.tramo-label {
  font-family: var(--rx-ff-mono); font-size: 9px; color: var(--fg-2);
}

/* ======================================================================
   MOTION — THE INSTRUMENT COMES UP

   rx-tokens.css has declared the philosophy since the first commit: "Everything
   is fast and firm. This is an instrument, not a storefront. No bouncing, no
   spring overshoot." It shipped four transition declarations in 44 KB of
   stylesheet, so the philosophy was written and never executed. This is the
   execution, and it does not invent a second vocabulary: every duration and
   every curve below is one of the four tokens already defined.

   THE RULE THAT DECIDES EVERYTHING HERE: motion may describe the INTERFACE
   arriving. It may never describe the DATA changing. A number that eases into
   place reads as a measurement in motion, and none of these measurements move
   — they are a satellite pass from hours ago. So panels rise, buttons respond,
   the map settles; values cut, hard, with no transition on any figure.

   Everything animated is transform or opacity. Nothing here triggers layout,
   so the 7 fps scrubber repaint is untouched: the panels that rebuild their
   innerHTML on every frame carry NO entrance animation, or they would replay
   it seven times a second.
   ====================================================================== */

@keyframes rx-rise {
  from { opacity: 0; transform: translate3d(0, 10px, 0); }
  to   { opacity: 1; transform: none; }
}
@keyframes rx-settle {
  /* The map, which has no edge to rise from. A hair of scale, released — the
     way an optical instrument finishes focusing. 1.006, not 1.04: at this size
     anything larger reads as a slide deck. */
  from { opacity: 0; transform: scale(1.006); }
  to   { opacity: 1; transform: none; }
}
@keyframes rx-sweep {
  /* One pass of the accent along the top bar, at power-on. The single moment
     in this interface that exists to be watched rather than read. */
  from { transform: scaleX(0); opacity: 1; }
  70%  { transform: scaleX(1); opacity: 1; }
  to   { transform: scaleX(1); opacity: 0; }
}

.map-wrap  { animation: rx-settle var(--rx-dur-slow) var(--rx-ease-out) both; }
.mockbar   { animation: rx-rise var(--rx-dur-slow) var(--rx-ease-out) 40ms both; }
.topbar    { animation: rx-rise var(--rx-dur-slow) var(--rx-ease-out) 90ms both; }
.leftcol   { animation: rx-rise var(--rx-dur-slow) var(--rx-ease-out) 150ms both; }
.scrubber  { animation: rx-rise var(--rx-dur-slow) var(--rx-ease-out) 210ms both; }
.layers    { animation: rx-rise var(--rx-dur-slow) var(--rx-ease-out) 250ms both; }
.weather   { animation: rx-rise var(--rx-dur-slow) var(--rx-ease-out) 290ms both; }
.rail      { animation: rx-rise var(--rx-dur-slow) var(--rx-ease-out) 330ms both; }
/* Deliberately absent: .toast and .credits. Both are summoned, not present —
   an entrance animation on a panel that starts hidden fires at boot against a
   display:none element and is simply thrown away. */

.topbar { position: relative; }
.topbar::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
  background: linear-gradient(90deg, transparent, var(--accent), transparent);
  transform-origin: 0 50%;
  animation: rx-sweep 900ms var(--rx-ease-out) 260ms both;
  pointer-events: none;
}

/* ---- response: every control answers in the same 80 ms ------------------
   These were the four declarations that existed, now applied to everything a
   cursor can reach, so the console does not feel half-alive: three buttons
   that respond and a dozen that do not is worse than none that do. */
.btn, .info-btn, .seg button, .chip, .lay-item, .rail-item, .hs-now,
.s-item, .panel-header .right > * {
  transition: background var(--rx-dur-fast) var(--rx-ease),
              border-color var(--rx-dur-fast) var(--rx-ease),
              color var(--rx-dur-fast) var(--rx-ease),
              opacity var(--rx-dur-fast) var(--rx-ease),
              box-shadow var(--rx-dur-med) var(--rx-ease),
              transform var(--rx-dur-fast) var(--rx-ease);
}
.btn:active, .info-btn:active, .seg button:active, .chip:active {
  /* Firm, not springy: it goes down and it stays down until released. */
  transform: translate3d(0, 1px, 0);
}

/* The selected segment's rule grows from the top rather than appearing, so the
   eye can follow the selection between rows instead of re-finding it. */
.rail-item { box-shadow: inset 0 0 0 var(--accent); }
.rail-item.sel { box-shadow: inset 2px 0 0 var(--accent); }
.rail-item:hover { transform: translate3d(2px, 0, 0); }

/* The sea state is the one figure that carries a state change rather than a
   value change — inside the horizon or outside it — so the border is allowed
   to move between the two. The NUMBER still cuts. */
.hs-now { transition: opacity var(--rx-dur-med) var(--rx-ease),
                      border-color var(--rx-dur-med) var(--rx-ease); }

@media (prefers-reduced-motion: reduce) {
  /* animation-delay MATTERS HERE and was missing. Every panel above is `both`
     filled with a delay of up to 330 ms, so killing only the DURATION leaves
     the element pinned at the `from` keyframe — opacity 0 — for the whole
     delay. A reader who asked for no motion would have watched the console
     assemble itself anyway, just in hard cuts. Both are zeroed. */
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-delay: 0ms !important;
    transition-duration: 0.01ms !important;
    transition-delay: 0ms !important;
  }
  .topbar::after { display: none; }
}

/* ======================================================================
   DESKTOP — floating panels over a full-bleed map. Only above 901px.
   ====================================================================== */
@media (min-width: 901px) {
  html, body { height: 100%; overflow: hidden; }
  .stage {
    position: fixed; inset: 0; display: block; padding: 0;
    background: var(--map-bg-tile);
  }
  .panel {
    position: absolute;
    background: var(--panel-bg);
    box-shadow: var(--panel-shadow);
    z-index: 5;
  }
  .map-wrap {
    position: absolute; inset: 0; height: auto; min-height: 0;
    border: 0; border-radius: 0; overflow: visible;
  }
  .map-stamp { left: 16px; bottom: 16px; }

  .mockbar {
    position: absolute; top: 0; left: 0; right: 0; margin: 0;
    z-index: 8; justify-content: center;
  }

  .topbar {
    left: 16px; right: 16px; top: 42px;
    flex-direction: row; align-items: center; gap: 14px;
    padding: 8px 14px;
  }
  .topbar .brand-row { flex: 0 1 auto; }
  .topbar .brand-row .path { margin-left: 10px; }
  .topbar { flex-wrap: nowrap; }
  .topbar .bar-row { flex-wrap: nowrap; }
  .topbar .bar-row { flex: 1 1 auto; }
  /* The site note keeps the top bar one row tall — the panels below are
     anchored at a fixed 110px and a wrapping note would collide with them.
     The full text is on the title attribute and repeated in the analyst view. */
  .topbar .site-note {
    flex: 0 1 auto; max-width: 240px;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  /* Clear of the left column, the rail and the scrubber. */
  .map-stamp { left: 416px; top: 118px; bottom: auto; }

  /* left column: the answer. A scroll container, so a long analyst body
     cannot push anything into anything else. */
  .leftcol {
    position: absolute; left: 16px; top: 110px; bottom: 16px; width: 384px;
    overflow-y: auto; z-index: 5; display: flex; flex-direction: column; gap: 10px;
  }
  /* flex: 0 0 auto is load-bearing — as flex items with overflow:hidden these
     panels shrink to fit the column and silently truncate their own content.
     That ate the PLACEHOLDER strap and the flight measurement on first run. */
  .leftcol .panel { position: relative; left: auto; top: auto; width: 100%; flex: 0 0 auto; }

  /* The right column is now three stacked panels. Heights are FIXED rather
     than auto because these are absolutely positioned siblings — auto height
     on the first two would let a long German string slide the rail under
     them. Each body scrolls inside its own box instead. */
  .layers {
    right: 16px; top: 110px; width: 336px; height: 182px;
    display: flex; flex-direction: column; overflow: hidden;
  }
  .layers .layer-list { overflow-y: auto; }
  .weather {
    right: 16px; top: 300px; width: 336px; height: 132px;
    display: flex; flex-direction: column; overflow: hidden;
  }
  .weather .wx-body { overflow-y: auto; }
  .rail {
    right: 16px; top: 440px; bottom: 16px; width: 336px;
  }
  /* THE RAIL LOST 330 PX to the two panels now stacked above it, and in the
     ANALYST view it carries the validation block, the layer matrix, the run
     and the licences ABOVE its 44-item list. With overflow:hidden on a
     shorter box those were about to be silently cut off — the same failure
     that ate the placeholder strap when .leftcol panels were left shrinkable.
     One scroll container for the whole panel instead of a nested one. */
  .rail { overflow-y: auto; overscroll-behavior: contain; }
  .rail-list { max-height: none; flex: 0 0 auto; overflow-y: visible; }

  .scrubber {
    left: 416px; right: 368px; bottom: 16px;
  }

  .credits {
    left: 16px; bottom: 16px; width: 384px; z-index: 9;
  }
  .toast {
    left: 50%; transform: translateX(-50%); bottom: 150px; z-index: 9;
    background: var(--panel-bg-solid);
  }
  #map .leaflet-control-zoom { margin: 0 16px 116px 0; }
}

/* Between 901 and 1180 the three columns are tight; the scrubber gives up
   its legend rather than the map giving up its width. */
@media (min-width: 901px) and (max-width: 1499px) {
  .topbar .brand-row .path { display: none; }
}
@media (min-width: 901px) and (max-width: 1180px) {
  .leftcol { width: 330px; }
  .rail { width: 292px; }
  .layers, .weather { width: 292px; }
  /* The rail needs every pixel in this band; the hint is the one thing in
     these two panels that is prose rather than data, so it is what goes. */
  .layers { height: 152px; }
  .layer-hint { display: none; }
  .weather { top: 270px; }
  .rail { top: 410px; }
  .scrubber { left: 358px; right: 320px; }
  .legend-row { display: none; }
  .topbar .brand-row .path { display: none; }
  .topbar .site-note { display: none; }
  .map-stamp { left: 358px; }
}

/* The demo strap in dark mode. Same job, same rule, inverted ground. */
html:not(.theme-light) .mockbar { background: #262030; color: #CDBCD3; }

/* THE WAY BACK. vbk.html links out to this console and this console linked
   nowhere — every sub-page was a dead end, so a reader who followed a link
   from the record had to use the browser's back button or retype the URL.
   The brand lockup is the way home, which is where a reader already looks. */
.brand-row .home-link {
  color: inherit;
  text-decoration: none;
  border-radius: 2px;
  outline-offset: 2px;
}
.brand-row .home-link:hover,
.brand-row .home-link:focus-visible { text-decoration: underline; }

/* ------------------------------------------------- basis block (the strap)
   One row per basis, strongest claim first. This was a single paragraph
   carrying four facts in one run of purple text, and a reader had to parse a
   sentence to learn whether a number was measured. The page already has a
   four-word vocabulary for exactly this; the caveat is now shaped like it. */
/* The container was a dashed SYNTHETIC border wrapping everything, which was
   honest when the block said one thing and every part of it was generated. It
   now holds a MEASURED row, and a purple dashed box around a measurement says
   the opposite of what the row inside it says. The rows carry their own basis
   colour; the container carries none. */
.mock-strap {
  display: flex;
  flex-direction: column;
  gap: 0;
  border: 1px solid var(--panel-border);
  border-style: solid;
  color: var(--fg-2, inherit);
}
.bq-row {
  display: grid;
  grid-template-columns: 5.6em 1fr;
  gap: 0 10px;
  align-items: baseline;
  padding: 5px 0;
  border-top: 1px solid var(--panel-border);
}
.bq-row:first-child { border-top: 0; }
.bq-k {
  font-family: var(--rx-ff-mono);
  font-size: 9px;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--st);
  white-space: nowrap;
  /* the rule under the label is the colour of the claim it introduces */
  border-bottom: 2px solid var(--st);
  padding-bottom: 2px;
  justify-self: start;
}
.bq-v { font-size: 10px; line-height: 1.5; color: var(--fg-2, inherit); }
.bq-v b { font-weight: 600; color: var(--st); }
.bq-measured  { --st: var(--nm-measured); }
.bq-modelled  { --st: var(--modelled); }
.bq-synthetic { --st: var(--synthetic); }

@media (max-width: 520px) {
  .bq-row { grid-template-columns: 1fr; gap: 2px; }
}
