/* Forecast Eagle — the locked viewer's chrome.
 *
 * The interactive explorers are documents: a page of controls, a map, a legend, and
 * an article under it, all of which scroll. That is right for a reader who arrived
 * from a search result and is being shown what the model says.
 *
 * This is the other kind of reader — the one who has the site open all afternoon and
 * is walking a field across twenty regions. For them the page *is* the instrument, so
 * it is an application shell: one screenful, nothing scrolls but the field list, and
 * every control is on screen at once because hunting for a control is the thing that
 * makes a viewer feel slow. That is the layout the legacy model sites converged on
 * twenty years ago and they were right about it.
 *
 * The design system is unchanged — this is the same Overpass, the same guide-sign
 * green, the same paper. What changes is density: 11 px controls, hard 2 px corners,
 * tabular numerals everywhere a number can move, and a matte behind the map rather
 * than a card floating on paper.
 */

/* One screenful, measured rather than assumed. The first cut subtracted the utility
   bar's height as a constant, which is right until the bar wraps to two lines on a
   phone and the ruler goes under the fold. A column flex asks the bar how tall it
   actually is. */
.lab-page {
  height: 100dvh; overflow: hidden;
  display: flex; flex-direction: column;
}
/* `z-index: auto` is not redundant. The site's utility bar is `position: sticky` with
   `z-index: 100`, and un-sticking it here is not enough to drop it out of the stack:
   z-index applies to a *flex item* whatever its position, and this bar is now a flex
   item of the shell. Left at 100 it painted over the region drawer — whose head sits
   at the top of the viewport, right underneath it — and swallowed the clicks on its
   close button. */
.lab-page .util { position: static; z-index: auto; flex: none; }

#lab {
  flex: 1 1 auto; min-height: 0; max-width: 100vw;
  display: grid;
  grid-template-rows: 42px minmax(0, 1fr);
  overflow: hidden;
  background: var(--paper);
}
#lab:fullscreen, #lab:-webkit-full-screen { height: 100dvh; }

/* ── top rail ──────────────────────────────────────────── */
/* The rail carries more than a phone is wide, and every one of its controls matters —
   so it scrolls sideways rather than dropping any of them. */
.lrail {
  display: flex; align-items: stretch; gap: 0; min-width: 0;
  background: var(--card); border-bottom: 2px solid var(--sign);
  padding-left: 8px; overflow-x: auto; overflow-y: hidden; scrollbar-width: none;
}
.lrail::-webkit-scrollbar { display: none; }
.lrail > * { flex: none; }
.lbrand {
  display: flex; align-items: center; gap: 7px; padding-right: 12px; margin-right: 10px;
  border-right: 1px solid var(--line2); white-space: nowrap;
}
.lbrand img { width: 24px; height: 24px; display: block; }
.lbrand b { font-weight: 900; font-size: 13px; letter-spacing: -.01em; }
.lbrand .tag {
  font-size: 9px; font-weight: 900; letter-spacing: .12em;
  background: var(--sign); color: var(--sign-tx); padding: 2px 5px; border-radius: 2px;
}
.lsegbar { display: flex; align-items: center; gap: 2px; overflow-x: auto; scrollbar-width: none; }
.lsegbar::-webkit-scrollbar { display: none; }
.lseg {
  padding: 5px 10px; border: 0; border-radius: 2px; background: none; cursor: pointer;
  font: inherit; font-weight: 800; font-size: 11px; letter-spacing: .05em;
  color: var(--ink2); white-space: nowrap;
}
.lseg:hover { background: var(--line2); color: var(--ink); }
.lseg[aria-pressed="true"] { background: var(--sign); color: var(--sign-tx); }
.lsep { width: 1px; background: var(--line2); margin: 6px 10px; flex: none; }
.lfield { display: flex; align-items: center; gap: 5px; white-space: nowrap; }
.lfield > label {
  font-size: 9px; font-weight: 900; letter-spacing: .12em; color: var(--mut);
}
.lfield select {
  font: inherit; font-size: 11px; font-weight: 700; padding: 4px 6px;
  border: 1px solid var(--line); border-radius: 2px; background: var(--paper); color: var(--ink);
  max-width: 190px;
}
.lspring { flex: 1 1 auto; min-width: 8px; }
.licons { display: flex; align-items: center; gap: 3px; padding-right: 8px; }
.lexport {
  font-family: var(--mono-font); font-size: 10.5px; font-weight: 700; color: var(--sign);
  white-space: nowrap; padding: 0 4px;
}
.lexport[hidden] { display: none; }

/* ── the one button style, in three sizes ──────────────── */
.lbtn {
  font: inherit; font-size: 11px; font-weight: 800; letter-spacing: .05em;
  padding: 5px 9px; border: 1px solid var(--line); border-radius: 2px;
  background: var(--card); color: var(--ink2); cursor: pointer; white-space: nowrap;
}
.lbtn:hover:not(:disabled) { border-color: var(--sign); color: var(--sign); }
.lbtn[aria-pressed="true"], .lbtn.on { background: var(--sign); border-color: var(--sign); color: var(--sign-tx); }
.lbtn:disabled { opacity: .38; cursor: default; }
.lbtn.wide { flex: 1 1 100%; min-width: 0; text-align: center; white-space: normal; font-size: 10px; padding: 6px; }
.lbtn.mini { font-size: 10px; padding: 3px 6px; letter-spacing: .04em; }
.lbtn.icon { padding: 5px 7px; font-size: 12px; line-height: 1; }
.lbtn.warn[aria-pressed="true"] { background: var(--shield-red); border-color: var(--shield-red); }
.lbtn.done { border-color: var(--sign); color: var(--sign); }

/* ── body: field list beside the instrument ────────────── */
.lbody {
  display: grid; grid-template-columns: 236px minmax(0, 1fr);
  min-height: 0; overflow: hidden;
}
.lside {
  display: flex; flex-direction: column; min-height: 0;
  background: var(--card); border-right: 1px solid var(--line);
}
.lside-head { padding: 7px; border-bottom: 1px solid var(--line2); }
.lside-head input {
  width: 100%; font: inherit; font-size: 11px; font-weight: 700; padding: 5px 7px;
  border: 1px solid var(--line); border-radius: 2px; background: var(--paper); color: var(--ink);
}
.lside-scroll { flex: 1 1 auto; min-height: 0; min-width: 0; overflow-y: auto; overscroll-behavior: contain; }
.lgrp { border-bottom: 1px solid var(--line2); }
.lgrp-h {
  width: 100%; display: flex; align-items: center; justify-content: space-between;
  font: inherit; font-size: 9.5px; font-weight: 900; letter-spacing: .13em; text-transform: uppercase;
  color: var(--mut); background: none; border: 0; cursor: pointer; padding: 7px 9px 5px;
}
.lgrp[data-open="false"] .lgrp-b { display: none; }
.lgrp[data-open="false"] .lchev { transform: rotate(-90deg); }
.lchev { transition: transform .12s; }
.lgrp-b { padding: 0 5px 6px; }
.lprod {
  display: block; width: 100%; text-align: left; font: inherit; font-size: 12px; font-weight: 700;
  padding: 5px 8px; border: 0; border-radius: 2px; background: none; color: var(--ink2); cursor: pointer;
}
.lprod:hover { background: var(--line2); color: var(--ink); }
.lprod[aria-pressed="true"] { background: var(--sign); color: var(--sign-tx); }
.lprod .u { float: right; font-size: 10px; font-weight: 700; opacity: .62; font-family: var(--mono-font); }
/* A field the product publishes but this run does not. Shown rather than dropped —
   losing three fields from the picker every other hour, with nothing to say why, is
   how "where did the precipitable water go" happens. The unit slot carries the run
   that has it instead of the units, because that is the useful thing to read here. */
.lprod.away { color: var(--mut); font-style: italic; }
.lprod.away:hover { background: var(--blue-sub); color: var(--navy); font-style: normal; }
.lprod.away .u { font-style: normal; color: var(--blue); opacity: 1; }

/* `minmax(0, 1fr)` and the `min-width: 0`s are load-bearing, not tidiness. A grid or
   flex item defaults to `min-width: auto`, which is its *max-content* width — so a row
   of seven boundary chips refused to wrap and instead stretched the whole rail past
   the 236 px column, taking the wide buttons' labels off the edge of the panel with
   it. Pinning the track to zero minimum is what lets the chips wrap. */
.lopts {
  border-top: 2px solid var(--line); padding: 8px 9px 10px;
  display: grid; grid-template-columns: minmax(0, 1fr); gap: 9px;
}
.lopt { display: grid; gap: 4px; min-width: 0; }
.lopt .k {
  font-size: 9px; font-weight: 900; letter-spacing: .13em; text-transform: uppercase; color: var(--mut);
}
.lopt > .v { display: flex; flex-wrap: wrap; gap: 3px; align-items: center; min-width: 0; }
.lopt select {
  font: inherit; font-size: 10.5px; font-weight: 700; padding: 4px 5px; max-width: 100%; min-width: 0;
  border: 1px solid var(--line); border-radius: 2px; background: var(--paper); color: var(--ink);
}
.lopt input[type="range"] { width: 92px; accent-color: var(--sign); }
/* The wind controls come from mapwind.js and are styled by the site stylesheet; only
   the density is this page's business. */
.lopt .seg button { font-size: 10px; padding: 4px 7px; }
.lopt .wind-opts { margin-top: 5px; }
.lopt .wind-opt select { min-width: 0; flex: 1 1 auto; }

/* ── the instrument column ─────────────────────────────── */
/* A column flex, not a grid with named rows. The breadcrumb row hides itself at the
   national level, and with fixed grid rows that shifted every item up one — handing
   the `1fr` row to the timeline and an `auto` row to the stage, whose content is
   absolutely positioned and therefore collapsed to nothing. A flex column does not
   care how many children are in flow. */
.lmain { display: flex; flex-direction: column; min-width: 0; min-height: 0; }
.lmain > * { flex: none; }
.lmain > .lstage-wrap { flex: 1 1 auto; min-height: 0; }

/* Label, a scroller of quick regions, and a tail that never scrolls away — the tail
   is how the other 160 regions are reached, so it has to stay on screen. */
.lregionbar {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center;
  gap: 6px; padding: 5px 8px;
  background: var(--card); border-bottom: 1px solid var(--line);
}
.lregion-scroll {
  display: flex; align-items: center; gap: 3px; min-width: 0;
  overflow-x: auto; scrollbar-width: thin; white-space: nowrap; padding-bottom: 1px;
}
.lregion-tail { display: flex; align-items: center; gap: 3px; padding-left: 6px; border-left: 1px solid var(--line2); }
.lregion-tail select {
  font: inherit; font-size: 10.5px; font-weight: 700; padding: 4px 5px; max-width: 148px;
  border: 1px solid var(--line); border-radius: 2px; background: var(--paper); color: var(--ink);
}
.lregionbar .lbtn { flex: none; }
.lregion-scroll .sep { width: 1px; align-self: stretch; background: var(--line2); margin: 0 4px; flex: none; }
.lregionbar .rlab {
  font-size: 9px; font-weight: 900; letter-spacing: .13em; color: var(--mut); flex: none;
}

/* The national and regional chips, as mapsectors.js renders them. Its markup is the
   interactive page's — shelved by the group the sector table carries — and only the
   density is this page's business. */
.lregion-scroll .sector-group { display: flex; align-items: center; gap: 3px; flex: none; }
.lregion-scroll .sector-group + .sector-group { margin-left: 8px; padding-left: 8px;
                                                border-left: 1px solid var(--line2); }
.lregion-scroll .sector-group-label {
  font-size: 8.5px; font-weight: 900; letter-spacing: .12em; text-transform: uppercase;
  color: var(--mut); white-space: nowrap;
}
.lregion-scroll .sector-btn {
  font: inherit; font-size: 11px; font-weight: 800; letter-spacing: .04em;
  padding: 5px 9px; border: 1px solid var(--line); border-radius: 2px;
  background: var(--card); color: var(--ink2); cursor: pointer; white-space: nowrap; flex: none;
}
.lregion-scroll .sector-btn:hover:not(:disabled) { border-color: var(--sign); color: var(--sign); }
.lregion-scroll .sector-btn.on { background: var(--sign); border-color: var(--sign); color: var(--sign-tx); }
/* A sector this grid cannot show is not dimmed here, it is dropped. The interactive
   page dims them, and it is right to: there the row wraps and a greyed "Alaska" tells
   you the domain exists. Here the model domains are already the top rail, so a dead
   "Alaska" chip in a horizontal scroller is a second, worse way to say the same thing
   sitting in front of the chips that work. */
.lregion-scroll .sector-btn:disabled { display: none; }
.lregion-scroll .sector-group:not(:has(.sector-btn:not(:disabled))) { display: none; }

/* Breadcrumb up the hierarchy, chips down it. One row, and it hides itself at the
   national level where the crumb would be one word and the children are the chips in
   the bar above. */
.ldrill {
  display: flex; align-items: center; gap: 10px; padding: 4px 8px;
  background: var(--card); border-bottom: 1px solid var(--line);
  overflow-x: auto; scrollbar-width: thin; white-space: nowrap;
}
.ldrill[hidden] { display: none; }
.lcrumbs { display: flex; align-items: center; gap: 4px; flex: none; }
.lcrumbs .crumb {
  font: 800 11.5px var(--font); letter-spacing: .01em; color: var(--navy);
  background: none; border: 0; padding: 2px 3px; cursor: pointer; border-radius: 2px;
  white-space: nowrap;
}
.lcrumbs .crumb:hover { background: var(--line2); }
.lcrumbs .crumb.on {
  color: var(--ink); cursor: default; text-decoration: underline;
  text-decoration-color: var(--sign); text-underline-offset: 3px; text-decoration-thickness: 2px;
}
.lcrumbs .crumb-sep { color: var(--mut); font-size: 10px; }
.ldrill .drill-label {
  font-size: 8.5px; font-weight: 900; letter-spacing: .12em; text-transform: uppercase;
  color: var(--mut); white-space: nowrap; flex: none;
}
.ldrill .drill-row { display: flex; align-items: center; gap: 8px; flex: none; }
.ldrill .drill-chips { display: flex; gap: 3px; flex: none; }
.ldrill .chip {
  font: 700 10.5px var(--font); color: var(--ink2); background: var(--paper);
  border: 1px solid var(--line); border-radius: 2px; padding: 3px 7px; cursor: pointer;
  white-space: nowrap;
}
.ldrill .chip:hover { border-color: var(--sign); color: var(--ink); }

/* Compass pad — the adjacent-region arrows, over the map because the map is the one
   place this page has room. On a locked viewer it earns its keep more than on a free
   one: it is the only way to walk to the next state without a picker. */
.compass {
  position: absolute; z-index: 6; top: 10px; left: 50%; transform: translateX(-50%);
  display: grid; grid-template-columns: repeat(3, 26px); grid-template-rows: repeat(3, 26px);
  background: rgba(8, 13, 20, .82); border: 1px solid rgba(255, 255, 255, .16);
  border-radius: 4px; padding: 3px; backdrop-filter: blur(3px);
}
.compass:empty { display: none; }
.compass-btn {
  background: none; border: 0; color: #e9e7e0; font-size: 11px; line-height: 1;
  cursor: pointer; border-radius: 2px; padding: 0;
}
.compass-btn:hover:not(:disabled) { background: rgba(255, 255, 255, .18); }
.compass-btn:disabled { opacity: .22; cursor: default; }
.compass-mid {
  grid-area: 2 / 2; display: grid; place-items: center;
  font: 800 9px var(--mono-font); color: #9fb0c2;
}
.dir-n { grid-area: 1 / 2; } .dir-w { grid-area: 2 / 1; }
.dir-e { grid-area: 2 / 3; } .dir-s { grid-area: 3 / 2; }

.lstage-wrap { position: relative; background: var(--figure); min-height: 0; overflow: hidden; }
.lstage { position: absolute; inset: 0; }
/* Locked: the camera is the region buttons' to move, so the map never advertises a
   grab handle. A crosshair says the right thing instead — this map is read, not
   dragged. */
.lstage .maplibregl-canvas-container,
.lstage .maplibregl-canvas { cursor: crosshair !important; }
.lstage .maplibregl-ctrl-bottom-left,
.lstage .maplibregl-ctrl-top-right { display: none; }
.lstage .maplibregl-ctrl-bottom-right { margin-bottom: 26px; }

.lov {
  position: absolute; z-index: 4; pointer-events: none;
  font-size: 11px; font-weight: 800; letter-spacing: .03em;
  background: rgba(8, 13, 20, .74); color: #f2f0ea;
  border: 1px solid rgba(255, 255, 255, .13); border-radius: 2px; padding: 5px 8px;
  backdrop-filter: blur(3px);
}
.lov .s { display: block; font-size: 10px; font-weight: 700; color: #b9c4cf; letter-spacing: .05em; }
.lov.tl { left: 8px; top: 8px; }
.lov.tr { right: 8px; top: 8px; text-align: right; }
.lov.bl { left: 8px; bottom: 8px; font-family: var(--mono-font); font-size: 11px; }
.lov:empty { display: none; }
.lov.br { right: 8px; bottom: 8px; font-family: var(--mono-font); font-size: 10.5px; }
.lov.br b { color: #ffd479; }
.lov.br.warn { border-color: var(--amber); }

/* Informational, and it covers the whole stage — so it must not eat clicks. It was
   swallowing the compass and the city probe underneath it while a domain loaded. */
.lstagemsg {
  position: absolute; inset: 0; display: grid; place-content: center; text-align: center;
  z-index: 6; background: rgba(10, 14, 20, .86); color: #e9e6df; padding: 24px;
  pointer-events: none;
}
.lstagemsg h4 { margin: 0 0 6px; font-size: 15px; font-weight: 900; letter-spacing: .02em; }
.lstagemsg p { margin: 0; font-size: 12px; font-weight: 700; color: #a9b4c0; max-width: 48ch; }

/* The colour bar rides the bottom of the map, the way a rendered chart carries it. */
.lscale {
  position: absolute; left: 8px; bottom: 26px; z-index: 3; pointer-events: none;
  width: min(560px, calc(100% - 220px));
  display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 8px; align-items: end;
}
.lscale .bar { height: 11px; border: 1px solid rgba(255, 255, 255, .35); border-radius: 1px; }
.lscale .ticks { position: relative; height: 13px; }
.lscale .ticks span {
  position: absolute; transform: translateX(-50%); white-space: nowrap;
  font-family: var(--mono-font); font-size: 9.5px; font-weight: 700; color: #e6e3dc;
  text-shadow: 0 1px 2px #000;
}
.lscale .units {
  font-size: 10px; font-weight: 900; letter-spacing: .1em; color: #e6e3dc; text-shadow: 0 1px 2px #000;
  padding-bottom: 13px;
}

/* The click-a-city time series, floated over the map rather than under it. */
.lstage-wrap .point-panel {
  position: absolute; left: 10px; bottom: 30px; z-index: 7; width: min(560px, calc(100% - 20px));
  max-height: 62%; overflow: auto; background: var(--card); color: var(--ink);
  border: 1px solid var(--line); border-radius: 3px; box-shadow: 0 10px 30px rgba(0, 0, 0, .45);
  padding: 9px 11px;
}

/* ── timeline ──────────────────────────────────────────── */
.ltimeline { background: var(--card); border-top: 1px solid var(--line); }
.ltl-bar {
  display: flex; align-items: center; gap: 8px; padding: 5px 8px; flex-wrap: wrap;
  border-bottom: 1px solid var(--line2);
}
.ltransport { display: flex; align-items: center; gap: 2px; }
.ltransport .lbtn { padding: 5px 8px; font-size: 12px; line-height: 1; }
.ltransport .play { min-width: 42px; background: var(--sign); border-color: var(--sign); color: var(--sign-tx); }
.ltransport .play:hover { color: var(--sign-tx); border-color: var(--sign-dk); }
.lreadout { display: flex; align-items: baseline; gap: 9px; font-family: var(--mono-font); }
.lreadout .tau { font-size: 15px; font-weight: 700; color: var(--ink); }
.lreadout .valid { font-size: 12px; font-weight: 700; color: var(--ink2); }
.lreadout .init { font-size: 10.5px; font-weight: 700; color: var(--mut); }
/* How much of the run is in hand. On this page that is a promise, not a diagnostic —
   once it is full the loop never touches the network again — so it sits in the
   transport bar with the other numbers rather than floating over the map. */
.lcache {
  font-family: var(--mono-font); font-size: 10.5px; font-weight: 700; color: var(--mut);
  white-space: nowrap; padding: 3px 7px; border: 1px solid var(--line2); border-radius: 2px;
}
.lcache b { color: var(--sign); font-weight: 800; }
.lcache.warn { border-color: var(--amber); color: var(--ink2); background: #fdf4dd; }
/* Playback held up by the decoder rather than by the reader — see `tick`. Worth saying
   out loud: a loop that has slowed to the rate frames can be decoded at is behaving
   correctly, and looks identical to one that is broken unless it says so. */
.lcache.is-waiting { border-color: var(--blue); color: var(--blue); }
.ltl-grp { display: flex; align-items: center; gap: 3px; }
.ltl-grp .k {
  font-size: 9px; font-weight: 900; letter-spacing: .13em; text-transform: uppercase; color: var(--mut);
}
.lrate { font-family: var(--mono-font); font-size: 11px; font-weight: 700; min-width: 52px; text-align: center; }

.lruler { height: 62px; position: relative; touch-action: none; cursor: ew-resize; }
.lruler svg { display: block; }
.lruler text { font-family: var(--mono-font); font-weight: 700; }
.lruler .daylab { font-size: 9px; fill: var(--mut); }
.lruler .curlab { font-size: 9.5px; font-weight: 800; fill: #fff; }

.lhint {
  padding: 4px 9px 6px; font-size: 9.5px; font-weight: 800; letter-spacing: .08em;
  color: var(--mut); border-top: 1px solid var(--line2); background: var(--card);
}

/* ── drawer: every region, and the keyboard card ───────── */
.lscrim {
  position: fixed; inset: 0; background: rgba(12, 16, 22, .5); z-index: 199; opacity: 0;
  pointer-events: none; transition: opacity .14s;
}
.lscrim[data-open="true"] { opacity: 1; pointer-events: auto; }
.ldrawer {
  position: fixed; z-index: 200; right: 0; top: 0; bottom: 0; width: min(620px, 94vw);
  background: var(--card); border-left: 2px solid var(--sign);
  display: flex; flex-direction: column; box-shadow: -12px 0 40px rgba(0, 0, 0, .3);
}
.ldrawer-head {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 10px 12px; border-bottom: 1px solid var(--line);
}
.ldrawer-head h3 { margin: 0; font-size: 14px; font-weight: 900; letter-spacing: .02em; }
.ldrawer-body { flex: 1 1 auto; overflow-y: auto; padding: 10px 12px 20px; }
.ldsec { margin-bottom: 14px; }
.ldsec > .k {
  font-size: 9.5px; font-weight: 900; letter-spacing: .13em; text-transform: uppercase;
  color: var(--mut); display: block; margin-bottom: 5px;
}
.ldgrid { display: flex; flex-wrap: wrap; gap: 4px; }
.lhelprow { display: grid; grid-template-columns: 132px minmax(0, 1fr); gap: 10px; padding: 4px 0; font-size: 12px; }
.lkbd {
  font-family: var(--mono-font); font-size: 11px; font-weight: 700;
  background: var(--paper); border: 1px solid var(--line); border-bottom-width: 2px;
  border-radius: 3px; padding: 2px 6px; justify-self: start;
}

/* ── narrow screens ────────────────────────────────────── */
@media (max-width: 900px) {
  .lbody { grid-template-columns: minmax(0, 1fr); }
  .lside {
    position: fixed; z-index: 201; left: 0; top: 0; bottom: 0; width: min(300px, 88vw);
    border-right: 2px solid var(--sign); transform: translateX(-100%); transition: transform .16s;
  }
  .lside[data-open="true"] { transform: none; }
  .lrail { padding-left: 4px; }
  .lbrand { padding-right: 8px; margin-right: 6px; }
  .lreadout .init { display: none; }
  .lhint { display: none; }
  .lruler { height: 54px; }
  .lfield > label { font-size: 8.5px; }
  .lregionbar { gap: 4px; padding: 5px 6px; }
  .lregion-tail select { max-width: 104px; }
  /* Below the valid-time badge rather than under it. */
  .compass { top: 46px; left: auto; right: 8px; transform: none; }
  .lregion-tail .lbtn { font-size: 10px; padding: 5px 6px; }
  .lscale { width: calc(100% - 16px); }
}
@media (min-width: 901px) { #btn-fields { display: none; } }
