/* app.css — the whole stylesheet. The map is the page; everything floats on it except the AR view
   cards, which push the map aside. Colours are never written here: theme.js publishes every token
   as a --group-key custom property and this file reads them, so dark mode is a palette swap. */

/* the page owns its box model: border-box came from the vendored search box's `*` rule until its 1.18 build scoped it */
*, *::before, *::after { box-sizing: border-box; }
/* `hidden` MEANS hidden: any `display` rule beats the UA's [hidden], and per-class patches missed one. One rule */
[hidden]:not(.morph) { display: none !important; } /* …but a FOLD shutting (util/dom.js `.morph`) is hidden and laid out, its edges closing over it */
/* clip, not hidden: a parked AR pane past the screen's edge let a phone's page be dragged and bounced; body's `position` leaves
   code nothing to scroll either (Scars) */
html { overflow: clip; }
body {
  margin: 0;
  /* the shell's scale (--ui, below); zoom inflates dvh too, so the height is brought back */
  zoom: var(--ui); height: calc(100dvh / var(--ui));
  /* relative: the containing block of every absolute box under it (#ar-cards, its parked pane), so its clip holds them (Scars) */
  position: relative;
  /* from the palette, NIGHT swapping both; clip, not hidden: a hidden box still scrolls for scrollIntoView (a focused sheet row
     lifted the phone's app over a black band) */
  background: var(--surface-page); color: var(--text-ink); overflow: clip;
  font: 14px/20px var(--font);
  /* ONE UI FACE: the platform's own, as Primer, Atlassian, Polaris and Fluent ship. Sizes and lines: rules.test's TYPE */
  --font: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  /* CORNERS (rules.test): s a chip or key · m a control · l a panel or picture · xl a card or sheet · full a capsule;
     a corner inside a rimmed one is the outer less its inset */
  --radius-s: 4px; --radius-m: 8px; --radius-l: 12px; --radius-xl: 16px; --radius-full: 999px;
  --thumb: 44px; /* a thumb's target (WCAG 2.5.5): every control under a coarse pointer, and the phone's circles */
  /* THE PAGE'S STACK, low to high: the panels on the map (the Overlays, the tool row, the cards' column), what rises over
     them (the seam, the drive pad), the phone's fixed controls, its sheet, the skip link and the map's error, the promotion
     bar and Rewind's frame, the tooltip and the search list, the callouts. Inside a picture or a plate z is local: 1–3 bare */
  --z-under: -1; --z-panel: 3; --z-raised: 4; --z-float: 5; --z-sheet: 7; --z-banner: 10; --z-bar: 20; --z-pop: 40; --z-top: 60;
  --row-h: 24px; /* a track row's pitch: shell/overlaysPanel/rows.js places rows at multiples of it (44 under a thumb) */
  /* THE SHELL'S SCALE: 1 up to 1920, more on a 4K desk at 100 %. The FURNITURE zooms, never a picture: GL JS sizes a canvas
     off getBoundingClientRect, which zoom inflates (Scars). What a zoomed element shares with an unzoomed one (--dock, the
     viewport) is divided by --ui where it crosses; util/dom.js's uiScale() is the same for a JS writer */
  --ui: 1;
  /* the cards' width; the seam drag writes it inline. REGISTERED (@property below), so arview/ reads a length back */
  --fw: calc(380px * var(--ui));
  /* MOTION: seven clocks and two curves, read by every transition and animation here (one line a pace, one block reduced
     motion). --slide a layout move, --fade opacity and colour, --tap hover and press, --reveal-open/-shut M and N's pair,
     --handover a pin handing over to the map's symbol, --wake the cluster setting into its dash (60 % of it back out);
     --ease decelerates onto its mark, --ease-exit accelerates away, neither past it (rules.test). IN MS: dom.js's msOf() reads
     the number, and `2s` would read as 2 */
  --slide: 280ms; --fade: 200ms; --tap: 130ms; --handover: 2000ms; --wake: 1000ms;
  --loader-spin: 1.1s; --loader-breathe: 1.8s; /* .loader's ring and its glyph (the map at boot, the camera card) */
  --reveal-open: 300ms; --reveal-shut: 190ms;
  --hud-hold: 5s; /* a driver's-seat HUD frame stands this long, then fades (.hud-frame): a HOLD, not motion — reduced motion
     keeps it (the frame is where the HUD's picture is), and no JS reads it, so seconds and none of the clocks above */
  --ease: cubic-bezier(.22, 1, .36, 1);
  --ease-exit: cubic-bezier(.32, 0, .67, 0);
  /* the column's height, from which a stacked card's WIDTH follows; read INSIDE the zoomed card, so brought back to its pixels */
  --dockh: calc((100dvh - 20px - env(safe-area-inset-bottom, 0px)) / var(--ui));
  /* EVERYTHING UNDER A CARD'S PICTURE (the 44px pill + its 6px margin): the desk card, the phone sheet and arview/'s usableFw()
     size the picture off this one number (Scars). Declared here so the coarse block's override wins on order */
  --chrome-h: 50px;
  /* the Overlays's width; the tool row and the message stack start where it ends */
  --sidew: min(300px, calc((100vw - var(--dock, 0px)) / var(--ui) - 40px));
}
@property --fw { syntax: '<length>'; inherits: true; initial-value: 380px; }
/* a form control never inherits `color` (the UA hands it `buttontext`, deaf to the palette): one rule, not one per control */
:is(button, input, select, textarea) { color: inherit; }
/* …and the UA's control box (ButtonFace, a 2px outset) reset once for every glyph-on-nothing control; :where, so a plate wins */
:where(#menu-btn, .ar-pin, .overlays-row button, button.overlays-row, .callout-x, .key-hint, .nato-q,
       .nato-sw, .nato-chev, .rewind-play, .rewind-shut, #performance button, #phone-dots button, #phone-hide, #phone-plus,
       #phone-help, #phone-light, #phone-share, #phone-full) { border: none; background: none; }
:where(#toolbar > button, .seg > button, #rewind .rewind-open) { border: none; } /* the UA's; the tool row's circles are glass */
/* THE ROUND GLYPH BUTTON: a glyph centred in a circle; each keeps its place, size and ink (`color` here would lose to the
   form-control rule above) */
:where(#toolbar > button, #rewind .rewind-open, #phone-pill > button, #phone-hide, #phone-plus, #phone-help, #phone-light, #phone-share,
       #phone-full, .rewind-play, .rewind-shut) { display: grid; place-items: center; padding: 0; border-radius: 50%; cursor: pointer; }
/* the surfaces WE do not draw (scrollbar, caret) follow the palette too */
body[data-light="night"] { color-scheme: dark; }
::selection { background: var(--fov-line); color: var(--text-on-dark); }
body.cards { --dock: calc(var(--fw) + 10px); }
/* narrow windows: the cards give ground first */
@media (max-width: 900px) { body { --fw: 280px; } }
/* wide desks at 100 %: the furniture grows, the map stays the map, and the AR column keeps the desk's share (380 of 1440;
   by --ui alone a 660 px picture over 1,700 px of column). A dragged width still wins */
@media (min-width: 2560px) { body { --ui: 1.35; --fw: max(calc(380px * var(--ui)), 26vw); } }
@media (min-width: 3600px) { body { --ui: 1.75; } }
/* THE PICTURES STAY AT 1 (see --ui): the map, every AR frame and the pop-out canvas, the seam, the cockpit's GL pods; the
   furniture inside a picture (the card round its frame, Mapbox's controls, the promotion bar, a details card, the cluster,
   the readout) zooms again */
#map, #ar-cards, #ar-seam, .ar-frame, .ar-cast { zoom: calc(1 / var(--ui)); }
.ar-card, .mapboxgl-control-container, .nato-pill, .callout, #cockpit, #ck-exit, #performance { zoom: var(--ui); }
/* what APPEARS rather than slides (a new card, the drive pad, the promotion bar) fades in */
.ar-card, #drive-pad, .nato-bar { transition: opacity var(--fade); }
@starting-style { .ar-card, #drive-pad, .nato-bar { opacity: 0; } }
.nato-bar.leaving { opacity: 0; pointer-events: none; } /* and leaves as it came (nato.js finish): it vanished in one frame */
/* day ↔ night: daynight.js wears `relight` for one --fade so the furniture crosses with the basemap's sweep. NAMED surfaces,
   never `*`: a blanket transition would replace --slide on whatever is mid-toggle */
body.relight, body.relight :is(#overlays, #toolbar button, .pill-button-bar, .search-box, .mapboxgl-ctrl-group, .mapboxgl-ctrl-scale, .co-card,
                                .ar-frame, .ar-head > *, .callout, .nato-pill, .rewind-bar,
                                .rewind-live, .cg, #performance) {
  transition: background-color var(--fade), color var(--fade), border-color var(--fade);
}
/* PUSHED by the cards: the right edge is the only thing that moves; the 10 px inset is the desk */
#map {
  position: absolute; top: 10px; bottom: 10px; left: 10px;
  right: calc(10px + var(--dock, 0px));
  /* its own stacking context: a full-bleed child (draw/'s surface) must not cover the controls */
  z-index: 0;
  /* the two PICTURES, this and every AR view frame, wear one outline and radius */
  border: 2px solid var(--line-frame); border-radius: var(--radius-l);
  /* the right edge rides the column, the bottom a phone's or an upright tablet's sheet (arview.js lands on either's end) */
  transition: right var(--slide) var(--ease), bottom var(--slide) var(--ease);
}
/* The Overlays floats ON the map, a plate of the THICK glass while open (theme.test holds every text token to AA on it), the
   thin glass shut to the ☰. Nothing paints the bare id: a cream on it once outranked `.glass` and the ☰ was a solid disc */
#overlays {
  position: absolute; z-index: var(--z-panel); border-radius: var(--radius-l);
  top: 20px; left: 20px;
  width: var(--sidew);
  /* stops short of the Performance readout in the bottom-left corner — the MAP's, so above a docked sheet of cards (an
     upright tablet's; --sheet is screen px, the panel's are --ui's) */
  max-height: calc(100% - 80px - var(--sheet, 0px) / var(--ui));
  display: flex; flex-direction: column;
  /* the box glides between the ☰ and the panel with the tool row; the moving edge REVEALS contents that swapped at once
     (#overlays-box keeps the open width, so nothing reflows mid-slide) */
  overflow: hidden;
  transition: width var(--slide) var(--ease), border-radius var(--slide) var(--ease), background-color var(--slide) var(--ease);
}
#overlays-box {
  /* the panel's width less its 2 px rim a side, or the box ran 4 px under the right rim */
  flex: 1; min-height: 0; width: calc(var(--sidew) - 4px);
  /* the head and the filter stand still; only the list scrolls (overlaysPanel.js Scars) */
  padding: 8px 12px; display: flex; flex-direction: column; overflow: hidden;
  /* sides 12, not 8: at 8 the rows met the rim (the owner: "it used to be better before") */
  position: relative;
}
/* …and what stands above it (the head, the filter, the phone's Rewind row) keeps its height: a flex column shrank them */
#overlays-box > :not(#overlays-list) { flex: none; }
/* the one scroller, and the context overlaysPanel/ measures its row windows against */
#overlays-list { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; /* the end of the list is not the page's */
  position: relative; }
/* shut, the ☰ fills the box, nothing clipped, its focus ring shown; its radius half its height, never --radius-full (999 → 12
   held the opening panel a tall capsule). While it FOLDS (.morph, shutPanel) the box still clips for the closing edges to cover,
   and the inset, the head's gap and the ☰'s size ease too, so nothing jumps when the classes flip */
#overlays.shut { width: var(--thumb); border-radius: calc(var(--thumb) / 2); }
#overlays.shut #overlays-box { flex: none; padding: 0; }
#overlays.shut #overlays-head { margin: 0; }
#overlays.shut:not(.morph), #overlays.shut:not(.morph) #overlays-box { overflow: visible; }
#overlays.shut:not(.morph) :is(#overlays-head h2, #overlays-list) { display: none; }
#overlays-head { display: flex; align-items: center; gap: 8px; font-weight: bold; margin-bottom: 8px; }
/* shut, the ☰ IS the 44px circle the toolbar lines up against; open, a 32px chip beside the title */
#menu-btn { cursor: pointer;
            width: 32px; height: 32px; padding: 0 4px;
            position: relative; border-radius: 50%; } /* the wash under the pointer is round, as the ☰ is */
#overlays.shut #menu-btn { width: 40px; height: 40px; } /* inside the PillButtonBar edge */
#menu-btn .icon { width: 20px; height: 20px; }
/* open, the layers glyph turns into a back chevron: pressing it leaves the panel */
#overlays:not(.shut) #menu-btn .icon { --i: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M15.4 6.4 9.8 12l5.6 5.6-1.7 1.7L6.4 12l7.3-7.3z'/%3E%3C/svg%3E"); }
/* a feed is broken and the panel is shut: one dot on the only control still on screen */
#menu-btn.warn::after {
  content: ''; position: absolute; top: 2px; right: 0;
  width: 7px; height: 7px; border-radius: 50%; background: var(--text-danger);
}

/* The AR view cards: a COLUMN at the right edge the map is pushed aside for, slid in when it has something to show.
   `visibility`, not display (a display:none map measures 0×0 and drops its tiles), flipping at the END of the slide out */
#ar-cards {
  overflow-anchor: none; /* a new live card is prepended; the strip must not hold the old one */
  position: absolute; z-index: var(--z-panel);
  /* #map's own 10px inset: the column stands BESIDE the map, tops on one line */
  top: 10px; right: 10px; bottom: calc(10px + env(safe-area-inset-bottom, 0px)); /* a tablet's foot: off its home indicator */
  width: var(--fw);
  display: flex; flex-direction: column; gap: 8px;
  /* a card with its Compute Graph open outgrows its share: the column scrolls rather than run off the map */
  overflow-y: auto;
  pointer-events: none; /* the column is a layout; only its cards take the pointer */
  overscroll-behavior: contain; /* a scroll that reaches the column's end stays in the column */
  /* where it stands AWAY (off the right edge, or below a phone's screen): one spelling for every rule that puts it away */
  --away: translateX(calc(100% + 20px));
  transform: var(--away);
  visibility: hidden;
  transition: transform var(--slide) var(--ease), visibility 0s var(--slide);
}
/* the 10px gap between the two pictures IS the splitter (dragging sets --fw, arview/): faint at rest, full under the pointer */
#ar-seam {
  position: absolute; z-index: var(--z-raised); top: 10px; bottom: 10px;
  right: calc(var(--fw) + 10px); width: 10px;
  display: none; cursor: col-resize; touch-action: none;
  /* it fades in once the column has slid into place: it stood at its final x ahead of the edge it belongs to */
  transition: right var(--slide) var(--ease), opacity var(--fade) var(--ease) var(--slide);
}
body.cards #ar-seam { display: block; }
@starting-style { body.cards #ar-seam { opacity: 0; } }
#ar-seam::after {
  content: ''; position: absolute; inset: 0 4px; border-radius: var(--radius-full);
  background: var(--line-frame); opacity: .2; transition: opacity var(--tap);
}
body.sizing #ar-seam::after { opacity: .55; }
/* mid-drag the edges follow the POINTER: no eased transition */
body.sizing :is(#map, #ar-seam, #toolbar) { transition: none; }
body.cards #ar-cards {
  transform: none; visibility: visible;
  transition: transform var(--slide) var(--ease), visibility 0s;
}
/* One card (arview/), up to four: a 3:2 PICTURE plus --chrome-h. Every card is the column's width, so the seam grows them all and
   the column scrolls; the min() keeps one card no taller than the column; right-aligned, the gap to the map narrows */
.ar-card {
  pointer-events: auto;
  flex: none; align-self: flex-end;
  /* a QUERY CONTAINER: a card's width is the splitter's, which no media query sees */
  container: arcard / inline-size;
  /* --aspect: the picture's own width over height — a land vehicle's HUD lens (card.js shape), else 3:2 */
  width: min(100%, calc((var(--dockh) - var(--chrome-h)) * var(--aspect, 1.5)));
  display: flex; flex-direction: column;
}
/* a card showing nothing takes no room while there are others; the LAST keeps its box, so the column slides out carrying it */
body.cards .ar-card.idle { display: none; }
/* an OPEN Compute Graph is the one thing in a card with no natural height: the card claims the column's free space for it, and
   with none (a full column, a second card) the column scrolls */
.ar-card:has(> .cg:not([hidden])) { flex: 1 1 auto; min-height: 0; }
/* a map's first second is a bare frame while the style loads: one line that FADES off under the first tiles (visibility after) */
.ar-frame::after {
  content: 'loading the map…'; position: absolute; inset: 0; z-index: 1; display: grid; place-content: center;
  font: bold 12px/16px var(--font); color: var(--text-soft); pointer-events: none;
  opacity: 0; visibility: hidden;
  transition: opacity var(--fade), visibility 0s var(--fade);
}
.ar-frame.loading::after { opacity: 1; visibility: visible; transition: opacity var(--fade); }

/* THE LOADER for every picture not there yet (the map's first seconds, a camera card until its still lands): a glyph breathing
   in an endless ring, `<div class="loader icon-x" role="img" aria-label>`, any .icon-* (--i inherits into ::after). The HOST
   hides it: #map by dropping `loading` on the first frame, .cam-frame by gaining `live` */
.loader {
  position: absolute; inset: 0; z-index: 2; display: grid; place-items: center; pointer-events: none;
  color: var(--text-ink);
  transition: opacity var(--fade), visibility 0s var(--fade);
}
.cam-frame .loader { color: var(--anno-blank-ink); } /* light on the void, in every light */
/* the map's loader is #map's next sibling in #map's own box (GL JS warns of any child in its container) */
#map + .loader { top: 10px; bottom: 10px; left: 10px; right: calc(10px + var(--dock, 0px)); zoom: calc(1 / var(--ui)); }
/* --loader-run pauses the hidden ring: the map's stays for the session, and an unseen animation still ticks the style */
#map:not(.loading) + .loader, .cam-frame.live .loader { opacity: 0; visibility: hidden; --loader-run: paused; }

.loader::before {
  content: ''; grid-area: 1 / 1; width: 64px; height: 64px; border-radius: 50%;
  background: conic-gradient(currentColor 0 28%, transparent 28% 100%);
  mask: radial-gradient(farthest-side, transparent calc(100% - 3px), #000 calc(100% - 2.5px));
  animation: loader-spin var(--loader-spin) linear infinite var(--loader-run, running);
}

.loader::after {
  content: ''; grid-area: 1 / 1; width: 30px; height: 30px;
  background: currentColor; mask: var(--i) center / contain no-repeat;
  animation: loader-breathe var(--loader-breathe) ease-in-out infinite var(--loader-run, running);
}

@keyframes loader-spin { to { transform: rotate(1turn); } }

@keyframes loader-breathe { 50% { transform: scale(1.12); } }
/* the picture, FIRST in the card so its top edge is the map's; no panel around it */
.ar-frame {
  flex: none; aspect-ratio: var(--aspect, 1.5);
  position: relative; overflow: hidden;
  background: var(--surface-panel);
  border: 2px solid var(--line-frame); border-radius: var(--radius-l);
}
.ar-map { position: absolute; inset: 0; }
/* THE GLASS (card.js): what the picture wears, the card's or in a first-person view the main map's; its instruments in .ar-rect
   (the whole card, or his visor's or a HUD car's box placed per frame inline, the glass clipped to it) */
.ar-glass, .ar-rect { position: absolute; inset: 0; }
.ar-frame > .parked { visibility: hidden; }
/* THE THUMB'S HANDS (card.js): a finger up or down tilts the picture's gimbal and two pinch its lens, so the browser keeps only
   the sideways pan — the strip's swipe between cards; a gunner's picture takes every finger (a drag across traverses the gun) */
.ar-frame { touch-action: pan-x; }
.ar-frame.gunner { touch-action: none; }
/* …but a KEPT card on the side column is a watched picture in a scrolling list: its vertical drag is the column's (card.js keep);
   the strips below scroll sideways, so there it keeps the sideways pan and the tilt */
.ar-frame.kept { touch-action: pan-y; }
/* the pop-out (arview/card/popout.js): the frame goes offscreen and THIS canvas, the second screen's exact bytes, stands in its
   place at the window's aspect */
.ar-cast {
  flex: none; display: block; width: 100%;
  background: var(--surface-void);
  border: 2px solid var(--line-frame); border-radius: var(--radius-l);
}
/* the chrome sits UNDER the frame: the name, the feed's extras, the card's buttons as ONE .seg PillButtonBar (desk, thumb and
   phone alike), at a fixed height so following never nudges the picture */
.ar-head {
  flex: none; display: flex; align-items: center; gap: 6px;
  min-height: 24px; margin-top: 6px; font-size: 12px; line-height: 16px; font-weight: bold;
  white-space: nowrap;
}
/* the name is the caption of the window, not a chip: TWO balanced lines in the bar's 44 px (on one, 96 px read "Cruiser WTPD…";
   unbalanced it broke at the hyphen). It keeps 7 characters and the readout gives way four times as fast ("I / S." for ISS) */
.ar-label { padding: 0; flex: 1 1 auto; min-width: 7ch; overflow: hidden; text-overflow: ellipsis;
            white-space: normal; text-wrap: balance; overflow-wrap: anywhere; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; }
/* the 📌 (NOT .ar-pin: that is the teardrop inside the frame); disabled, the column is full */
.ar-keep:disabled { opacity: .35; cursor: default; }
/* the one chip left: a readout, not a control. Both ends ellipsise; colour per track by arview/ (transit lateness) */
.ar-info { margin-left: auto; flex: 0 4 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis;
           padding: 2px 8px; border-radius: var(--radius-s); } /* its plate: the glass rule */
/* …and where it cannot be read it is not drawn: the seven-button bar (312 px) and the name's 7ch leave a 380 px card no room,
   and the readout's plate pushed the bar's last button, Close, off the window (a ship's "MMSI 276582000" crushed to "M") */
.ar-head { container-type: inline-size; }
/* a finger held on the name is the Compute Graph's (chrome.js onHold): no text selection or callout rises under it */
@media (any-pointer: coarse) { .ar-label { -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; } }
@container (max-width: 479px) { .ar-info { display: none; } }
/* the readouts over the picture */
.ar-near {
  position: absolute; z-index: 2; font-weight: bold;
  pointer-events: none; white-space: nowrap; inset: 0;
}
/* under the sight (arview/card/sight/) the frame is a sensor picture: the picture and the night sight's boxes (.ar-box) alone */
.ar-glass[data-sight]:not([data-sight="off"]) :is(.ar-hud, .ar-markers, .ar-near, .ar-callout, .ar-minimap-box, .orbit-hud) { display: none; } /* the cluster hides itself (card.js), lent or not */
/* the PoI NATO frames over a card (arview/card/markers.js/): at its projected point, sized by distance, under the pins, no pointer;
   the img's margins stand its bottom centre on the point */
.ar-markers { position: absolute; inset: 0; z-index: 2; overflow: hidden; pointer-events: none; }
/* the navigation disc (parts/fleet/disc.js/): disc.js tilts .ego-disc by the map's pitch and turns the chevron per frame */
.ego { width: 36px; height: 36px; display: grid; place-items: center; pointer-events: none; }
.ego-disc { width: 32px; height: 32px; border-radius: 50%; background: var(--drawn-ego); box-shadow: 0 0 0 2px var(--drawn-ego-ink);
  display: grid; place-items: center; }
.ego-chevron { width: 16px; height: 16px; display: grid; }
.ego-chevron svg { width: 100%; height: 100%; fill: var(--drawn-ego-ink); }
/* THE REROUTE'S ONE LINE (waypoints/reroute.js): the tooltip's chip over the picture above the parked turn sign, read in one
   glance, eased in and out, never blinking */
.nav-notice { position: absolute; z-index: 3; left: 50%; top: 16%; padding: 4px 12px; border-radius: var(--radius-full);
  color: var(--text-ink); font-size: 12px; line-height: 16px; white-space: nowrap; pointer-events: none;
  opacity: 0; transform: translate(-50%, -4px); transition: opacity var(--fade) var(--ease-exit), transform var(--fade) var(--ease-exit); }
.nav-notice.on { opacity: 1; transform: translate(-50%, 0); transition: opacity var(--fade) var(--ease), transform var(--fade) var(--ease); }
/* the ARRIVED pill (waypoints/arrival.js): the turn badge's gold and black, as the reroute chip wears them; over the glass's own */
.glass.nav-notice.is-arrived { background: var(--badge-fill); color: var(--waypoints-badge-ink); border-color: var(--waypoints-badge-ink); font-weight: 600; }
/* a reroute's cue on the main map (waypoints/cues.js): GL JS places a marker by its OWN element's transform, so it animates
   its inner element */
/* the chip: what the detour costs, the fix-quality pill (gnss/tags.js) in the turn badge's gold and black, every light, no shadow */
.reroute-chip { pointer-events: none; padding-bottom: 8px; }
.reroute-chip > div { padding: 2px 12px; border: 2px solid var(--waypoints-badge-ink); border-radius: var(--radius-full);
  background: var(--badge-fill); color: var(--waypoints-badge-ink); font-size: 12px; line-height: 16px; font-weight: 600; white-space: nowrap;
  animation: reroute-chip calc(var(--handover) * 1.6) var(--ease) both; }
@keyframes reroute-chip { 0% { opacity: 0; transform: translateY(6px); } 8% { opacity: 1; transform: none; }
  85% { opacity: 1; } 100% { opacity: 0; transform: translateY(-6px); } }
.ar-marker { position: absolute; left: 0; top: 0; }
.ar-marker.behind { visibility: hidden; }
.ar-glass.hud-nav :is(.ar-markers, .ar-near) { display: none; } /* a worn HUD on a route is the turn's alone (card.js isNav) */
/* REAL HUD LIGHT (the owner, 2026-11-02: "the same gold color, just a tiny bit translucent"): a HUD's glass a little see-through, its
   colours its own — the plus-lighter wash paled the gold; the turn sign is translucent the same way (turnsign.js, HUD.light) */
.ar-glass.hud-light { opacity: .85; }
/* a worn HUD's place off the box's side: a small frame on that edge, its distance beside it, inward (markers.js placeTabs) */
.ar-marker:is(.tab-l, .tab-r) .ar-marker-name { top: -19px; transform: none; }
.ar-marker.tab-l .ar-marker-name { left: 12px; }
.ar-marker.tab-r .ar-marker-name { left: auto; right: 12px; } /* behind a building: occluded, as everything in an AR view (markers.js isBehind) */
.ar-marker img { position: absolute; left: 0; top: 0; transform-origin: 50% 100%; }
/* the map's own name in its ink, no halo, on a backing so a nearer name covers a farther one rather than the inks crossing */
.ar-marker-name { position: absolute; left: 0; top: 3px; transform: translateX(-50%); white-space: nowrap; padding: 0 4px;
  font-size: 12px; line-height: 16px; color: var(--text-on-dark); background: var(--flight-phosphor-plate); border-radius: var(--radius-s); }
.dark-ink .ar-marker-name { color: var(--line-glyph); background: var(--surface-panel); } /* the glass's special case (arview/ink.js) */
/* the line of contact (markers.js): APP-6E's graphic level on its point, its distance under it on a name's backing, in the glass's hostile ink */
.ar-contact { color: var(--flight-phosphor-foe); }
.dark-ink .ar-contact { color: var(--flight-dark-foe); }
.ar-contact svg { position: absolute; left: -31px; top: -9px; fill: none; stroke: currentColor; stroke-width: 2;
  filter: drop-shadow(0 0 2px var(--flight-phosphor-glow)); }
.dark-ink .ar-contact svg { filter: drop-shadow(0 0 2px var(--flight-dark-glow)); }
.ar-contact.inside svg { display: none; } /* inside held ground: the words alone, under the band (markers.js placeInside) */
.ar-contact .ar-marker-name { top: 12px; color: inherit; } /* a PoI name's backing, under the line: over it, his horizon puts it on the compass band */
/* nearby incidents (arview/card/incidents.js/): the map's own pin per incident at its projected point, off-frame ones holding the
   edge with a chevron; no plate (a scrim box turns markers back into a list). The row IS the pin's box, its margin the TIP */
.ar-near-row {
  position: absolute; left: 0; top: 0; width: 17px; height: 24px;
  margin: -24px 0 0 -8.5px; /* the anchor, applied here so arview/ writes translate() alone */
}
/* the teardrop at map scale, the only thing here taking the pointer; the shared bare-control rule resets the UA's ButtonFace,
   which squeezed it to about 1px */
.ar-pin {
  position: absolute; inset: 0; width: 17px; height: 24px; padding: 0;
  pointer-events: auto; cursor: pointer;
  /* the hand-over to the map's own symbol (incidents.js .merged at the far plane): a long fade covering the symbol's first
     placement, seconds on a card idling at 1 fps */
  transition: opacity var(--handover) linear;
}
.ar-near-row.merged .ar-pin { opacity: 0; }
.ar-pin > svg {
  width: 100%; height: 100%; display: block;
  fill: var(--pin-fill); stroke: var(--line-glyph); stroke-width: 1.5;
  filter: drop-shadow(0 1px 2px var(--overlay-shadow));
}
/* the head disc is centred at (21,21) of 42×60: 50% across, 35% down */
.ar-pin-glyph {
  position: absolute; left: 50%; top: 35%; width: 62%;
  transform: translate(-50%, -50%); line-height: 0;
}
.ar-pin-glyph > svg { width: 100%; height: auto; display: block; }
/* off-frame: the chevron points out of the panel, rotated about the pin's HEAD */
.ar-pin-chev {
  position: absolute; left: 8.5px; top: 8.4px; margin: -6px 0 0 -6px;
  width: 12px; height: 12px; line-height: 0;
  color: var(--pin-fill); filter: drop-shadow(0 0 3px var(--line-glyph));
}
/* the arrowhead is a path (incidents.js), so the glow is a filter, not a text-shadow */
.ar-pin-chev > svg { width: 100%; height: 100%; display: block; fill: currentColor; }
/* the card a clicked pin expands into (details/), placed by the AR view's own projection */
.ar-callout { position: absolute; inset: 0; z-index: 3; pointer-events: none; }
.ar-callout > div { position: absolute; left: 0; top: 0; pointer-events: auto; }
/* the map's card is sized for the map; this panel starts at ~330×240 and clips */
.ar-glass .callout { max-width: 200px; font-size: 12px; line-height: 16px; padding: 8px 28px 8px 12px; }
.ar-glass .callout b { font-size: 14px; line-height: 20px; }
.ar-glass .callout-glyph { width: 26px; height: 26px; margin-right: 8px; padding-right: 8px; }
.ar-label:empty, .ar-info:empty { display: none; }
/* display:flex above would otherwise beat :empty's display:none */
.ar-near:empty { display: none; }
/* the minimap's box (arview/minimap3d/), inert, sized off its slot (the cluster's pod, the visor's), so it scales with the card */
.ar-minimap-box {
  position: absolute; z-index: 1; pointer-events: none;
  aspect-ratio: 1;
  overflow: visible; /* the N and its arrow stand OUTSIDE the rim */
  /* M grows and shrinks it from its CENTRE (util/keys.js/): `gone` the shrunk state out, @starting-style the same in; card.js
     gives the WebGL context back only after the shrink, or an empty box would animate */
  transition: transform var(--reveal-open) var(--ease), opacity var(--tap) linear;
}
/* out: the fade delayed to END with the shrink, one way out for the springloaded pair M and N (the disc, the BRAKE word) */
.ar-minimap-box.gone, .ck-brake.gone .ck-brake-word {
  transform: scale(.35); opacity: 0;
  transition: transform var(--reveal-shut) var(--ease-exit),
              opacity var(--tap) linear calc(var(--reveal-shut) - var(--tap));
}
/* in, a disc arrives whole in its slot; slept (scrolled out of the strip, or showing a camera), it is hidden */
.ar-minimap-box.parked { visibility: hidden; }

/* ── the 3D minimap (arview/minimap3d/): `.ar-mini3d` is the RIG, half again the disc's width (minimap3d.js box()) for the hover
   buttons' air, the disc in its middle. Map and readout clip at the rim; the ink overlay does not (the N stands outside). At
   night canvas and ink ADD (plus-lighter): black paints as nothing, as on a see-through display ── */
.ar-mini3d, .m3-rig { pointer-events: none; }
.m3-disc { position: absolute; left: 16.667%; top: 16.667%; width: 66.667%; height: 66.667%; }
/* the GL canvas rounded by its box, not a clip-path (Chrome drew it square under one in the visor's turned display); 0.3% in so
   the ring covers its edge and GL's zoom stays a hair OVER the dial's (streets-v8's footprints are a cliff at z15) */
.m3-map { position: absolute; inset: 0.3%; border-radius: 50%; overflow: hidden; background: none; }
.m3-map .mapboxgl-ctrl { display: none !important; }
.m3-ov, .m3-lab { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
.m3-ov { overflow: visible; }
.m3-rig.additive .m3-map canvas { mix-blend-mode: plus-lighter; } /* the overlay is plain: the chevron's dark edge must paint */
.m3-ctl { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; opacity: 0; transition: opacity var(--tap); overflow: visible; }
.m3-ctl.pin, .m3-ctl:focus-within { opacity: 1; } /* a tabbed-to button shows the bar as a hover does */
/* a thumb has no hover (always up, the bar covered a phone's pane): a tap on the disc shows it a moment (disc.js `pin`), and
   hidden its buttons take no tap, so the tap that shows it never acts */
@media (hover: none) { .m3-disc { pointer-events: auto; } .m3-ctl:not(.pin) .btn { pointer-events: none; } }
.m3-ctl .btn { pointer-events: all; cursor: pointer; outline: none; }
.m3-ctl .btn:focus-visible .face { fill-opacity: .12; stroke: currentColor; stroke-width: 2px; } /* the wash and a 2 px ring in the bar's own ink: the bar has no plate to outline */
.m3-rig.parked { visibility: hidden; }
.ar-mini3d.max { z-index: 5; }
/* maximized: the minimap alone over the picture, its bar always up so the way back is never hidden */
.mm-max .ar-glass { visibility: hidden; }
.ar-mini3d.max .m3-ctl { opacity: 1; }
.ar-mini3d.max .m3-ctl .btn { pointer-events: all; }

/* the HUD canvas (arview/hud.js) */
.ar-hud, .ar-box { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 1; pointer-events: none; }
/* the camera monitor (corners.js openCam → roadcams/monitor/): the <video>'s poster carries the still, so a still-only camera
   and a dead stream need no extra element */
.ar-video, .ar-yt {
  position: absolute; inset: 0; width: 100%; height: 100%; z-index: 1;
  /* void: the absence of a picture, black in every light */
  border: 0; background: var(--surface-void);
}
.ar-video { object-fit: contain; }
/* the embeds must not look like YouTube: no hover, and .warmup blacks the frame out while the opening chrome fades (brightness,
   so the backing stays painted) */
.ar-yt { pointer-events: none; transition: filter var(--fade); }
.ar-yt.warmup { filter: brightness(0); transition: none; }
/* basemap off: annotations on black */
.ar-frame.blank { background: var(--surface-void); }

/* The Compute Graph (arview/card/graph/graph.js): one column of pills, each the function that runs the step; green on time,
   orange slow or late, red stopped, dashed a path this map is not on */
.cg {
  /* it TAKES the column's leftover height (.ar-card:has), a flex column .cg-scroll fills: no max-height guess */
  flex: 1 1 auto; min-height: 120px; margin-top: 6px;
  display: flex; flex-direction: column;
  background: var(--overlay-veil);
  border: 1px solid var(--line-rule); border-radius: var(--radius-l);
  font: 12px/16px var(--font);
}
.cg-scroll {
  flex: 1 1 auto; min-height: 0; padding: 12px 8px;
  overflow: auto; overscroll-behavior: contain;
}
/* a phone's card head floats over the pane's foot (788–832 of a 843 scroll): the graph's end scrolls clear of it (pick F4) */
body.phone .cg-scroll { padding-bottom: 64px; }
/* the flow: each child after the first hangs off a centred stem with a CHEVRON at its foot at the stem's weight (a filled
   triangle left a shoulder either side of a 1.5px line) */
.cg-flow { display: flex; flex-direction: column; align-items: center; gap: 16px; }
.cg-flow > * + *, .cg-engine > * + *, .cg-kids > * + * { position: relative; }
.cg-flow > * + *::before, .cg-engine > * + *::before, .cg-kids > * + *::before {
  content: ''; position: absolute; left: calc(50% - 0.75px); top: -16px; height: 11px;
  border-left: 1.5px solid var(--line-strong);
}
.cg-flow > * + *::after, .cg-engine > * + *::after, .cg-kids > * + *::after {
  content: ''; position: absolute; left: calc(50% - 3px); top: -8px; width: 6px; height: 6px;
  border-right: 1.5px solid var(--line-strong);
  border-bottom: 1.5px solid var(--line-strong);
  border-bottom-right-radius: 0; transform: rotate(45deg);
}

/* A NODE is one pill and everything it calls when open, SHRINKWRAPPED to its name: the graph's shape is information */
.cg-node {
  --cg-tone: var(--text-on);
  display: flex; flex-direction: column; align-items: center;
  width: max-content; max-width: 100%;
}
.cg-pill {
  --cg-tone: var(--text-on);
  display: flex; align-items: center; justify-content: center; gap: 6px;
  width: max-content; max-width: 100%;
  padding: 4px 12px; border-radius: var(--radius-full);
  font: inherit; text-align: center; color: var(--text-ink);
  border: 1px solid color-mix(in srgb, var(--cg-tone) 55%, transparent);
  background: color-mix(in srgb, var(--cg-tone) 16%, transparent);
}
.cg-ok { --cg-tone: var(--text-on); }        /* running, and on time */
.cg-stale { --cg-tone: var(--text-warn); }    /* later or slower than usual */
.cg-down { --cg-tone: var(--text-danger); }   /* it has stopped working */
/* a path the code has that this map is not on */
.cg-pill.off {
  background: none; border-style: dashed; border-color: var(--line-border);
  color: var(--text-faint);
}
.cg-pill.cg-fold { cursor: pointer; }
/* OPENED BY A FINGER (card.js onHold → .cg.touch): a finger has no hover, so each pill prints its tip — the figures paint() already
   writes in place — on a line under its name, and the pill is a thumb's 44 px */
.cg.touch .cg-node { min-width: min(100%, 320px); } /* on the panel's width: a pill's own % would be of its own shrinkwrap */
.cg.touch .cg-pill { align-self: stretch; width: auto; flex-wrap: wrap; row-gap: 0; min-height: 44px; border-radius: var(--radius-l); }
/* contain: its line wraps inside the pill, never widens it (a pill is max-content: the long line pushed it past the panel) */
.cg.touch .cg-pill::after {
  content: attr(data-tip); flex: 1 0 100%; contain: inline-size; white-space: normal; overflow-wrap: anywhere;
  font-weight: normal; color: var(--text-soft);
}
/* the chevron says the pill opens; a count badge answered how MANY, which no reader asks */
.cg-c {
  flex: none; width: 7px; height: 7px; margin-left: -1px;
  border-right: 1.5px solid color-mix(in srgb, var(--cg-tone) 85%, var(--text-ink));
  border-bottom: 1.5px solid color-mix(in srgb, var(--cg-tone) 85%, var(--text-ink));
  transform: rotate(-45deg); transition: transform var(--reveal-open) var(--ease);
}
.cg-node[data-open] > .cg-pill > .cg-c { transform: rotate(45deg); }

/* GROWN: the pill heads a box and what it calls is drawn inside; these three rules are the whole of the nesting, at every depth */
.cg-node[data-open] {
  border: 1px solid color-mix(in srgb, var(--cg-tone) 42%, transparent);
  border-radius: var(--radius-xl);
  background: color-mix(in srgb, var(--cg-tone) 6%, transparent);
}
.cg-node[data-open] > .cg-pill {
  /* width:auto, or the max-content above stops the head short of its own box */
  align-self: stretch; width: auto;
  border: none; border-radius: calc(var(--radius-xl) - 1px) calc(var(--radius-xl) - 1px) 0 0;
  border-bottom: 1px solid color-mix(in srgb, var(--cg-tone) 26%, transparent);
  background: color-mix(in srgb, var(--cg-tone) 22%, transparent);
}
.cg-kids {
  display: flex; flex-direction: column; align-items: center; gap: 16px;
  width: max-content; max-width: 100%; padding: 12px 12px;
}
/* only the node just clicked unfolds (graph.js marks it; every open node's kids replayed a redraw); its chevron turns from where it stood */
.cg-kids.unfold { animation: cg-unfold var(--reveal-open) var(--ease) both; }
.cg-node[data-turned="open"] > .cg-pill > .cg-c { animation: cg-turn-open var(--reveal-open) var(--ease); }
.cg-node[data-turned="shut"] > .cg-pill > .cg-c { animation: cg-turn-shut var(--reveal-open) var(--ease); }
@keyframes cg-turn-open { from { transform: rotate(-45deg); } }
@keyframes cg-turn-shut { from { transform: rotate(45deg); } }
@keyframes cg-unfold {
  from { opacity: 0; clip-path: inset(0 0 100% 0); }
  to { opacity: 1; clip-path: inset(0 0 0 0); }
}

/* the engine's half, above the browser's: same pills and colours; the connector leaving its hairline box IS the WebSocket */
.cg-engine {
  align-self: stretch; display: flex; flex-direction: column; align-items: center; gap: 16px;
  padding: 8px 8px 12px; border: 1px dashed var(--line-border); border-radius: var(--radius-l);
}
.cg-band {
  align-self: flex-start; font-size: 12px; line-height: 16px; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--text-faint);
}
/* the caption is a label, not a stage: nothing flows INTO the first module from it */
.cg-engine > .cg-band + *::before, .cg-engine > .cg-band + *::after { display: none; }

/* the one starting point: the upstreams behind this picture, curving into a single line */
.cg-feeds { align-self: stretch; }
.cg-feed-row {
  display: flex; flex-wrap: wrap; gap: 8px;
  justify-content: center; align-items: flex-start; /* one line is one `top` — see fitFan */
}
/* the merge elbow ╰──╯ under what it collects, the graph's only curve */
.cg-join {
  height: 13px; margin: 0 16%;
  border: 1.5px solid var(--line-strong); border-top: none; border-radius: 0 0 var(--radius-l) var(--radius-l);
}
/* a brace over one pill is no brace: the plain stem to the next pill stands in (graph.js fitFan) */
.cg-join.one { display: none; }
/* …and the last row collects into nothing below it (the acquire node stood there until round eight's A1) */
.cg-flow > :last-child > .cg-join { display: none; }

/* the search is the tool row's LAST item: a 44px circle like every tool, a pill while focused (:focus-within is the whole
   mechanism), taking what the row has left so nothing beside it is overlapped */
#searchbar { flex: 0 0 var(--thumb); min-width: 0; transition: flex-basis var(--slide) var(--ease); }
/* the pill stays open while it holds a query: the query also filters the Overlays rows, and a folded pill hid that filter */
#searchbar:is(:focus-within, :has(input:not(:placeholder-shown))) { flex: 0 1 420px; }
#searchbar input { height: 40px; color: var(--text-ink); } /* inside the PillButtonBar edge */
/* the span index.html leaves in the circle: only a NARROW row shows it (the container block below) */
#searchbar > .icon { display: none; }
/* collapsed, the glyph alone: font-size 0 hides placeholder and text in one property, once the capsule has folded (the delay)
   so its closing edge covers them */
#searchbar:not(:focus-within):has(input:placeholder-shown) input { padding: 0; font-size: 0; transition: font-size 0s var(--slide), padding 0s var(--slide); }
/* the placeholder in meta: a fixed grey failed AA both ways */
#searchbar input::placeholder { color: var(--text-meta); opacity: 1; }
/* shell/search/ builds the pill: .search-box (the capsule: a PillButtonBar's plate, 44 = 40 + the 2px edge, a circle when
   shut, positioned so the list hangs off it) > .icon + input.search-q + ul.search-list */
.search-box { position: relative; height: var(--thumb); border-radius: var(--radius-full); }
/* the magnifier over the field's left end at every width (≈ the shut circle); pointer-events off: it once ate the circle's tap */
.search-box > .icon { position: absolute; inset: 0 auto 0 11px; color: var(--text-meta); pointer-events: none; }
#searchbar:not(:focus-within):has(input:placeholder-shown) .search-box > .icon { color: var(--text-ink); }
/* the field is TRANSPARENT in the capsule; ink, placeholder and height are #searchbar input's */
.search-q { width: 100%; padding: 0 16px 0 40px; border: none; background: none;
            font: 14px/1 var(--font); caret-color: var(--text-ink); }
/* NO RING: a text input matches :focus-visible on a CLICK, so an outline boxed every opened pill; the opening is the
   indication and the rim goes to ink (`.glass:focus-within`). The id outranks the later global input rule */
#searchbar .search-q:focus-visible { outline: none; }
/* the suggestions hang from BODY, placed by search.js: a glass plate inside the glass pill blurs nothing (a backdrop filter
   sees only its backdrop root) and showed the sharp map through its tint. On the tooltip's layer */
.search-list { position: fixed; z-index: var(--z-pop); margin: 0; padding: 6px 0; list-style: none;
               border-radius: var(--radius-xl); overflow: hidden; } /* its plate: the thick glass (search.js) */
/* block, not flex: the name ellipsises; the place prints under it in meta */
.search-opt { padding: 8px 16px; cursor: pointer; font: 14px/20px var(--font); color: var(--text-ink);
              white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.search-opt i { display: block; margin-top: 2px; font: 12px/16px var(--font); font-style: normal;
                color: var(--text-meta); }
.search-opt.cur { background: var(--highlight-wash); } /* the current row: the highlight's wash, .nato-hit.cur's */
.search-none { padding: 8px 16px; font: 14px/20px var(--font); color: var(--text-faint); cursor: default; } /* the one row a query with no hit draws */
/* ── PillButtonBar: THE look of a bar of buttons on the map, a capsule of the glass (the owner put it on every one). A row;
   `.vertical` a column; `.seg` a segmented control (with the tool row). util/pill/pill.js is the one builder (a card's bar, the
   phone's pill, GL JS's groups); the tool row's is markup. The buttons size themselves, the bar owns only the plate; the 3D
   minimap's bar (minimap3d/disc.js paintCtl) is the same recipe in SVG.
   ── GLASS: the LIQUID plate (theme/glass; the owner's pick, then "universally"), within noise of no plate on the desk. ONE class,
   put on by ONE function, glass(node): every PillButtonBar and each one-off plate's builder (not the scale bar, a ruler).
   `.thick` is the plate under a PANEL OF TEXT, surface.panel at 55 % (iOS's regular material) so meta text keeps its contrast;
   `.readout` a plate with NO rim, a figure that only informs. A plate is for a control, a panel or a readout; a caption over
   the picture wears a halo, never a plate ("this border should not appear anywhere"). A plate never sits INSIDE a plate: a
   backdrop filter there sees only the outer plate's paint and doubles the tint. A thin tint over a strong blur, the 2px rim
   in the unselected glyph's grey (a 1px white one vanished by day), a lip of light from four inset shadows. Its values sit on
   BODY, where daynight writes the night tokens, for the CSS-only plates ── */
body { --glass-filter: blur(28px) saturate(1.9);
       --glass-thick: color-mix(in srgb, var(--surface-panel) 55%, transparent); /* a panel of text: iOS's REGULAR material (85 % read as a solid slab) */
       --glass-lip-side: color-mix(in srgb, var(--overlay-lip) 40%, transparent);
       --glass-shadow: inset 0 1px 1px var(--overlay-lip), inset 0 -1px 1px var(--glass-lip-side),
                       inset 1px 0 1px var(--glass-lip-side), inset -1px 0 1px var(--glass-lip-side),
                       0 10px 30px -10px var(--overlay-shadow);
       /* THE HIGHLIGHT's two washes (theme.js line.highlight): 24 % for selected or pressed, 10 % for hovered: one look for all three */
       --highlight-wash: color-mix(in srgb, var(--line-highlight) 24%, transparent);
       --highlight-hover: color-mix(in srgb, var(--line-highlight) 10%, transparent);
       --highlight-inset: 4px; } /* how far a selected capsule stands inside its control's 2px rim: 32 of a 40 px segment */
/* …and the plates no builder reaches, by selector: the phone's fan circles and their names, its key chips, mirror mode's hint */
.glass, .draw-touch, body.phone :is(#toolbar .seg, #vehicle-bar) > :is(button, .place-fan), body.phone #toolbar :is(.seg > button, .place-lead)::after, body.phone .key-hint[data-run],
body.mirror::after {
  isolation: isolate; background: var(--overlay-glass);
  -webkit-backdrop-filter: var(--glass-filter); backdrop-filter: var(--glass-filter); /* -webkit-: iOS before 18 */
  border: 2px solid var(--overlay-rim); box-shadow: var(--glass-shadow); }
.glass.thick, body.phone #toolbar :is(.seg > button, .place-lead)::after { background: var(--glass-thick); }
/* a READOUT (the shut Performance row, a card's info chip, a note, the tooltip) informs and is not pressed: no rim, the border
   kept 2px and transparent so nothing moves when one comes on */
.glass.readout, body.phone #toolbar :is(.seg > button, .place-lead)::after, body.mirror::after { border-color: transparent; }
/* a field inside a plate says it holds focus by its rim going to full ink */
.glass:focus-within { border-color: var(--text-ink); }
.pill-button-bar { display: flex; overflow: hidden; border-radius: var(--radius-full); color: var(--text-ink); }
.pill-button-bar.vertical { flex-direction: column; }
/* the FANCY BUTTON: a capsule verb that stands out inside a panel, the highlight's wash under its 2px edge; a button, not a
   plate (a plate in a plate doubles the tint). `.drag` / a press fills it with ink */
.fancy-button {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 36px; padding: 0 12px; font: inherit; font-weight: 600; cursor: pointer;
  color: var(--text-ink); border-radius: var(--radius-full); border: 2px solid var(--line-highlight);
  background: var(--highlight-wash);
  transition: background var(--tap), color var(--tap);
}
.fancy-button .icon { width: 16px; height: 16px; margin: 0; }
.fancy-button:disabled { color: var(--text-faint); cursor: default; }
.fancy-button.drag, .fancy-button:active:not(:disabled) { background: var(--text-ink); color: var(--surface-panel); }
/* NO dividers between a bar's buttons (the owner): the capsule says which is on and the spacing where one ends, as on iOS 26's
   glass bars; GL JS draws its own #ddd hairline, off here */
.mapboxgl-ctrl-group button + button { border-top: 0; }

/* the map tools ON THE MAP (behind a shut Overlays nobody reached them): right of the ☰ or the open panel, left of the control
   stack riding the cards; a query container, so Rewind wraps by the ROW's width (a card narrows it as a phone does) */
#toolbar {
  position: absolute; z-index: var(--z-panel); top: 20px;
  left: 74px; /* 20 + the ☰'s 44px square + 10 gap */
  right: calc(var(--dock, 0px) / var(--ui) + 70px);
  /* both edges glide: the right one rides the cards, and the search pill between them with it */
  transition: left var(--slide) var(--ease), right var(--slide) var(--ease);
  display: flex; flex-wrap: wrap; gap: 8px; align-items: center; /* wrap: the open Rewind takes a line of its own under 700 px (the query below) */
  container-type: inline-size;
}
/* the row's OWN buttons: a bare `#toolbar button` caught one inside the search pill and blew it up into a 44px tile */
#toolbar > button, .seg > button, #rewind .rewind-open {
  flex: none; /* the pill beside them absorbs the row's slack, never the circles */
  width: var(--thumb); height: var(--thumb); color: var(--text-ink);
}
/* .seg: a PillButtonBar as a SEGMENTED CONTROL, 40px segments in its 2px edge so it stands 44 like the circles: the tool row's
   arming tools and a card's bar (arview/card/chrome.js), whose buttons say pressed three ways (data-on, aria-pressed, aria-expanded) */
.seg { flex: none; }
.seg > button { background: none; height: 40px; border-radius: 0; cursor: pointer; } /* 40 inside the 2px edge = the circles' 44 */
/* GREYED: aria-disabled, never `disabled`, so a hover still reaches its tip ("Select a drivable vehicle"); faint, no wash */
.seg > button[aria-disabled="true"] { color: var(--text-faint); cursor: default; box-shadow: none; }
/* THE SELECTED VEHICLE'S BAR (#vehicle-slot): shut, the slot is no width (the row's 8px gap given back) and the bar nothing; a
   selection (app.js `.on`) opens the slot to --vehicle-w as the bar grows from its middle, the clock and search gliding over;
   shutting runs it back on --ease-exit. No overshoot (a bounce was "a little too distracting"). The bar keeps its own width,
   overflowing a narrower slot, so its buttons never squeeze */
#vehicle-slot { display: flex; width: 0; margin-left: -8px;
  transition: width var(--reveal-shut) var(--ease-exit), margin-left var(--reveal-shut) var(--ease-exit); }
#vehicle-slot.on { width: var(--vehicle-w, auto); margin-left: 0;
  transition: width var(--reveal-open) var(--ease), margin-left var(--reveal-open) var(--ease); }
#vehicle-bar { flex: none; transform: scale(.2); opacity: 0;
  transition: transform var(--reveal-shut) var(--ease-exit), opacity var(--reveal-shut) var(--ease-exit); }
#vehicle-slot.on #vehicle-bar { transform: none; opacity: 1;
  transition: transform var(--reveal-open) var(--ease), opacity var(--fade) var(--ease); }
/* THE NAV TOOL SAYS ITS STEP while waypoints go down (placing.js `data-say`): its segment widens for the words (slidePick watches
   the row's size) and is the glyph again when the placing ends; a phone's fan prints the same words as its name */
#nav-btn { display: flex; align-items: center; justify-content: center; }
#nav-btn > .say { display: none; }
#nav-btn[data-say] { width: auto; gap: 8px; padding: 0 16px 0 12px; }
#nav-btn[data-say] > .icon { margin: 0; }
#nav-btn[data-say] > .say { display: block; font: 600 14px/1 var(--font); white-space: nowrap; }
/* ── SELECTED, on the glass: THE HIGHLIGHT (the owner: "uniform everywhere"; pick C off the AR Bar Highlights playground): a
   capsule of the 24 % wash inset --highlight-inset, concentric with the rim, NO edge, the glyph in the highlight. ONE rule for
   every control on the map that is ON (a segment's three ways, Rewind's open circle, HQ and Task force, the pad's slot, the
   phone's ⊕ while fanned); a new on/off control joins this list and paints no fill of its own (rules.test). The capsule is a
   ::before under the glyph and never moves its host: `position: relative` at zero specificity (the fixed ⊕ keeps its place, Scars) ── */
:is(.seg:not(:has(> .seg-pick)) > :is([aria-pressed="true"], [data-on="1"], [aria-expanded="true"]), #rewind-open[aria-expanded="true"],
    :where(body.phone #toolbar) .seg > :is([aria-pressed="true"], [data-on="1"], [aria-expanded="true"]),
    .nato-tog[aria-pressed="true"], .slot button.on, body.tools #phone-plus, .draw-touch > [aria-pressed="true"]) {
  isolation: isolate; color: var(--line-highlight);
  :where(&) { position: relative; }
  &::before { content: ''; position: absolute; inset: var(--highlight-inset); z-index: var(--z-under); border-radius: var(--radius-full);
              background: var(--highlight-wash); }
  /* THE CARD'S BAR (arview/card/chrome.js), where several are on at once: a lit run joins into one shape (pick C; an edge per
     cell drew seven strokes) — a side whose nearest SHOWN neighbour is lit runs square to the cell's edge, across up to three
     [hidden] buttons. shortcut: a phone hides more by class (MIRROR MODE's `.ar-head` rule), so runs don't join across those;
     join by class too if a phone shows two lit apart */
  :where(.ar-head) &:is(:is([aria-pressed="true"], [data-on="1"], [aria-expanded="true"]):not([hidden]) + *, :is([aria-pressed="true"], [data-on="1"], [aria-expanded="true"]):not([hidden]) + [hidden] + *, :is([aria-pressed="true"], [data-on="1"], [aria-expanded="true"]):not([hidden]) + [hidden] + [hidden] + *, :is([aria-pressed="true"], [data-on="1"], [aria-expanded="true"]):not([hidden]) + [hidden] + [hidden] + [hidden] + *)::before {
    left: 0; border-start-start-radius: 0; border-end-start-radius: 0; }
  :where(.ar-head) &:has(+ :is([aria-pressed="true"], [data-on="1"], [aria-expanded="true"]):not([hidden]), + [hidden] + :is([aria-pressed="true"], [data-on="1"], [aria-expanded="true"]):not([hidden]), + [hidden] + [hidden] + :is([aria-pressed="true"], [data-on="1"], [aria-expanded="true"]):not([hidden]), + [hidden] + [hidden] + [hidden] + :is([aria-pressed="true"], [data-on="1"], [aria-expanded="true"]):not([hidden]))::before {
    right: 0; border-start-end-radius: 0; border-end-end-radius: 0; }
}
/* …except where ONE of a bar is on (the tool row): the capsule is one element that SLIDES to the armed tool (util/pill slidePick;
   one per button jumped); it fades where it stood when nothing is armed, appears in place when one is (`snap`) */
.seg:has(> .seg-pick) { position: relative; }
.seg:has(> .seg-pick) > button { position: relative; z-index: 1; }
.seg-pick { position: absolute; top: var(--highlight-inset); bottom: var(--highlight-inset); left: 0; border-radius: var(--radius-full); pointer-events: none;
            /* as far in as SELECTED's on every side: slidePick sizes it to the button, so its sides are a transparent border */
            background: var(--highlight-wash); opacity: 0;
            border-inline: var(--highlight-inset) solid transparent; background-clip: padding-box; /* after `background`: its shorthand resets the clip */
            transition: transform var(--slide) var(--ease), width var(--slide) var(--ease), opacity var(--fade) var(--ease); }
.seg-pick.on { opacity: 1; }
.seg:has(> .seg-pick) > :is([aria-pressed="true"], [data-on="1"], [aria-expanded="true"]) { color: var(--line-highlight); } /* the armed glyph, as SELECTED's */
.seg-pick.snap { transition: opacity var(--fade) var(--ease); }
/* THE PLACE FAN (shell/mapcontrols/placefan.js): a PILL INSIDE THE PILL. Shut, it is the row's last segment, the lead
   wearing the place tool picked last; on the lead's aria-expanded it widens into an inner pill of the five, the worn one
   first (--i 0) where the lead stood, the others sliding out to its right a beat apart. The buttons move by transform and
   opacity alone; the fan's own width is the one layout, the tool row's (as #vehicle-slot's). Folding has no stagger: the
   picked one slides back under the lead as the rest fade there. Shut, the five are hidden, out of the tab order */
.place-fan { position: relative; z-index: 1; flex: none; width: var(--thumb); height: 40px; color: var(--text-ink);
  --slot: 36px; --fan-w: calc(5 * var(--slot) + 8px); /* five 36px buttons and the rim's 4px each end */
  transition: width var(--slide) var(--ease); }
.place-fan::before { content: ''; position: absolute; inset: 2px; border-radius: var(--radius-full); pointer-events: none;
  border: 1.5px solid var(--overlay-rim); background: var(--highlight-hover); opacity: 0; transition: opacity var(--fade) var(--ease); }
.place-fan > button { position: absolute; top: 0; left: 0; padding: 0; border: none; background: none; color: inherit; cursor: pointer;
  border-radius: var(--radius-full); transition: opacity var(--fade) var(--ease), visibility 0s, box-shadow var(--tap); }
.place-fan > .place-lead { width: var(--thumb); height: 40px; }
.place-fan > .place { top: 4px; left: 4px; width: var(--slot); height: 32px;
  opacity: 0; visibility: hidden; pointer-events: none; transform: translateX(0);
  transition: transform var(--slide) var(--ease), opacity var(--fade) var(--ease), visibility 0s var(--slide), box-shadow var(--tap); }
.place-fan:has(> [aria-expanded="true"]) {
  width: var(--fan-w);
  &::before { opacity: 1; }
  & > .place-lead { opacity: 0; visibility: hidden; transition: opacity var(--fade) var(--ease), visibility 0s var(--fade); }
  & > .place { opacity: 1; visibility: visible; pointer-events: auto; transform: translateX(calc(var(--i) * var(--slot)));
    transition-delay: calc(var(--i) * var(--slide) / 12), calc(var(--i) * var(--slide) / 12), 0s, 0s; }
}
/* ONE way a control draws its glyph: a silhouette in `--i`, masked and painted in currentColor, so it follows the palette, the
   press and :disabled. No emoji: an emoji paints its own colour and stays black after dark */
.icon {
  display: block; width: 20px; height: 20px; margin: auto;
  background: currentColor;
  mask: var(--i) center / contain no-repeat;
}
.icon-pin { --i: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill-rule='evenodd' d='M12 2a7 7 0 0 0-7 7c0 5.25 7 13 7 13s7-7.75 7-13a7 7 0 0 0-7-7zm0 9.5a2.5 2.5 0 1 1 0-5 2.5 2.5 0 0 1 0 5z'/%3E%3C/svg%3E"); }
.icon-poly { --i: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill-rule='evenodd' d='M12 1.5 22.5 9.1 18.5 21.5h-13L1.5 9.1zM12 5.2 5 10.2l2.7 8.3h8.6l2.7-8.3z'/%3E%3C/svg%3E"); }
.icon-soldier { --i: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 1.6a2.4 2.4 0 1 1 0 4.8 2.4 2.4 0 0 1 0-4.8zM9.1 7.4h5.8l3.4 2.1-1 1.7-2.4-1.5V13l2.6 8.6h-2.3L13.4 15h-2.8L8.8 21.6H6.5L9.1 13V9.7l-2.4 1.5-1-1.7z'/%3E%3C/svg%3E"); }
/* the place fan's vehicles (shell/mapcontrols/placefan.js), side views nose right as the soldier stands: the Eagle 4x4, the
   tracked ASCOD with its gun, the RAV4's two boxes; the FPV drone from above */
.icon-eagle { --i: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill-rule='evenodd' d='M1.5 15.2V10.6l1.3-.8 3.1-4.3h7.6l2.2 4.3h5.6l1.2 1.4v4zM7.1 7.1l-1.8 2.7h4.3V7.1zm4 0v2.7h3.4l-1.4-2.7z'/%3E%3Ccircle cx='6.3' cy='17.4' r='2.9'/%3E%3Ccircle cx='17.7' cy='17.4' r='2.9'/%3E%3C/svg%3E"); }
.icon-ascod { --i: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M1.8 13.3 3.4 11h17.2l1.6 2.3z'/%3E%3Cpath d='M7.3 11l1-3.2h5.9l1 3.2z'/%3E%3Cpath d='M13.6 8.6h9.1v1.4h-9.1z'/%3E%3Cpath fill-rule='evenodd' d='M4 14.3h16a2.6 2.6 0 0 1 0 5.2H4a2.6 2.6 0 0 1 0-5.2zm1.3 1.5a1.1 1.1 0 1 0 0 2.2 1.1 1.1 0 0 0 0-2.2zm4.5 0a1.1 1.1 0 1 0 0 2.2 1.1 1.1 0 0 0 0-2.2zm4.4 0a1.1 1.1 0 1 0 0 2.2 1.1 1.1 0 0 0 0-2.2zm4.5 0a1.1 1.1 0 1 0 0 2.2 1.1 1.1 0 0 0 0-2.2z'/%3E%3C/svg%3E"); }
.icon-rav4 { --i: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill-rule='evenodd' d='M1.5 15.4v-4.6l1.7-3.9Q3.7 6 4.7 6h10.1l3.6 4.3 2.6.4q1.5.3 1.5 1.9v2.8zM4.7 7.6l-1.2 3h4.8v-3zm5.2 0v3h6.4l-2.3-3z'/%3E%3Ccircle cx='6.4' cy='16.9' r='2.5'/%3E%3Ccircle cx='17.6' cy='16.9' r='2.5'/%3E%3C/svg%3E"); }
.icon-drone { --i: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M6.3 6.3l11.4 11.4M17.7 6.3 6.3 17.7' stroke='%23000' stroke-width='2.2' stroke-linecap='round'/%3E%3Ccircle cx='5.2' cy='5.2' r='3.4' fill='none' stroke='%23000' stroke-width='1.8'/%3E%3Ccircle cx='18.8' cy='5.2' r='3.4' fill='none' stroke='%23000' stroke-width='1.8'/%3E%3Ccircle cx='5.2' cy='18.8' r='3.4' fill='none' stroke='%23000' stroke-width='1.8'/%3E%3Ccircle cx='18.8' cy='18.8' r='3.4' fill='none' stroke='%23000' stroke-width='1.8'/%3E%3Crect x='9.2' y='9.2' width='5.6' height='5.6' rx='1.4'/%3E%3C/svg%3E"); }
.icon-pen { --i: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04a1 1 0 0 0 0-1.41l-2.34-2.34a1 1 0 0 0-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z'/%3E%3C/svg%3E"); }
/* route: a start dot, the road along and up, the destination pin (the nav tool, overlays/generic/waypoints/) */
.icon-route { --i: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Ccircle cx='6' cy='19' r='2.8'/%3E%3Cpath fill-rule='evenodd' d='M18 2.5a4 4 0 0 0-4 4c0 3 4 7.5 4 7.5s4-4.5 4-7.5a4 4 0 0 0-4-4zm0 2.5a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3z'/%3E%3Cpath d='M9.4 19H15a3 3 0 0 0 3-3v-.5' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round'/%3E%3C/svg%3E"); }
.icon-search { --i: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill-rule='evenodd' d='M9.8 2.5a7.3 7.3 0 0 1 5.8 11.7l5.9 5.9-1.6 1.6-5.9-5.9A7.3 7.3 0 1 1 9.8 2.5zm0 2.3a5 5 0 1 0 0 10 5 5 0 0 0 0-10z'/%3E%3C/svg%3E"); }
.icon-clock { --i: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill-rule='evenodd' d='M12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20zm0 2.2a7.8 7.8 0 1 1 0 15.6 7.8 7.8 0 0 1 0-15.6zM10.9 6.6h2.2v5.9l4.1 2.4-1.1 1.9-5.2-3z'/%3E%3C/svg%3E"); }
.icon-play { --i: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M7 4.5 19.5 12 7 19.5z'/%3E%3C/svg%3E"); }
.icon-pause { --i: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M6.5 4.5h4v15h-4zM13.5 4.5h4v15h-4z'/%3E%3C/svg%3E"); }
/* the loaders' glyphs (.loader::after): LINE drawings on a 48 box — at 30 px a filled silhouette is a blot */
.icon-map { --i: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 48 48' fill='none' stroke='%23000' stroke-width='2.6' stroke-linejoin='round' stroke-linecap='round'%3E%3Cpath d='M6 12l12-4 12 4 12-4v28l-12 4-12-4-12 4zM18 8v28M30 12v28'/%3E%3C/svg%3E"); }
.icon-camera { --i: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 48 48' fill='none' stroke='%23000' stroke-width='2.6' stroke-linejoin='round' stroke-linecap='round'%3E%3Cpath d='M9 16h7l3-4h10l3 4h7a3 3 0 0 1 3 3v16a3 3 0 0 1-3 3H9a3 3 0 0 1-3-3V19a3 3 0 0 1 3-3z'/%3E%3Ccircle cx='24' cy='27' r='6'/%3E%3C/svg%3E"); }
.icon-live { --i: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill-rule='evenodd' d='M12 9a3 3 0 1 1 0 6 3 3 0 0 1 0-6zM6.9 5.2 8.4 6.8a7.2 7.2 0 0 0 0 10.4l-1.5 1.6a9.4 9.4 0 0 1 0-13.6zm10.2 0a9.4 9.4 0 0 1 0 13.6l-1.5-1.6a7.2 7.2 0 0 0 0-10.4z'/%3E%3C/svg%3E"); }
.icon-copy { --i: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill-rule='evenodd' d='M8 3h11a2 2 0 0 1 2 2v11h-2V5H8zM4 7h11a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V9a2 2 0 0 1 2-2zm0 2v10h11V9z'/%3E%3C/svg%3E"); }
.icon-chev { --i: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M6.4 8.6 12 14.2l5.6-5.6 1.7 1.7L12 17.6 4.7 10.3z'/%3E%3C/svg%3E"); }
/* layers: a sheet over two edges, the Overlays' stack — the ☰ read as a generic menu */
.icon-layers { --i: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linejoin='round' stroke-linecap='round'%3E%3Cpath d='M12 2 21 7 12 12 3 7zM4.6 11.1 3 12l9 5 9-5-1.6-.9M4.6 16.1 3 17l9 5 9-5-1.6-.9'/%3E%3C/svg%3E"); }
/* keep: a bookmark, not a push-pin — .icon-pin is already the PoI */
.icon-keep { --i: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M5.5 2h13v20.6L12 16.9 5.5 22.6z'/%3E%3C/svg%3E"); }
.icon-close { --i: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M19 6.4 17.6 5 12 10.6 6.4 5 5 6.4 10.6 12 5 17.6 6.4 19 12 13.4 17.6 19 19 17.6 13.4 12z'/%3E%3C/svg%3E"); }
/* the glasses: the AR view sent to a pair of them or a second screen (card/popout.js) */
.icon-compass { --i: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill-rule='evenodd' d='M12 1.8a10.2 10.2 0 1 0 0 20.4 10.2 10.2 0 0 0 0-20.4zm0 2.1a8.1 8.1 0 1 1 0 16.2 8.1 8.1 0 0 1 0-16.2zM12 5l2.5 7-2.5 7-2.5-7z'/%3E%3C/svg%3E"); }
.icon-glasses { --i: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M1.5 8h8.2a1.3 1.3 0 0 1 1.3 1.3V10h2v-.7A1.3 1.3 0 0 1 14.3 8h8.2v2.2h-1.2v3.3a3.5 3.5 0 0 1-3.5 3.5h-1.6a3.5 3.5 0 0 1-3.5-3.5V12h-1.4v1.5a3.5 3.5 0 0 1-3.5 3.5H6.2a3.5 3.5 0 0 1-3.5-3.5v-3.3H1.5z'/%3E%3C/svg%3E"); }
/* the phone's pill and ⊕ (shell/mapcontrols/phone.js): where am I and the tools */
.icon-locate { --i: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 2.5a1 1 0 0 1 1 1V5a7 7 0 0 1 6 6h1.5a1 1 0 1 1 0 2H19a7 7 0 0 1-6 6v1.5a1 1 0 1 1-2 0V19a7 7 0 0 1-6-6H3.5a1 1 0 1 1 0-2H5a7 7 0 0 1 6-6V3.5a1 1 0 0 1 1-1zm0 4.5a5 5 0 1 0 0 10 5 5 0 0 0 0-10zm0 2.6a2.4 2.4 0 1 1 0 4.8 2.4 2.4 0 0 1 0-4.8z'/%3E%3C/svg%3E"); }
.icon-folder { --i: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill-rule='evenodd' d='M2.5 4.5A1.5 1.5 0 0 1 4 3h5.2a1.5 1.5 0 0 1 1.06.44L11.8 5H20a1.5 1.5 0 0 1 1.5 1.5v13A1.5 1.5 0 0 1 20 21H4a1.5 1.5 0 0 1-1.5-1.5zM4.9 9.4v9.2h14.2V9.4z'/%3E%3C/svg%3E"); }
.icon-plus { --i: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M10.8 4h2.4v6.8H20v2.4h-6.8V20h-2.4v-6.8H4v-2.4h6.8z'/%3E%3C/svg%3E"); }
.icon-help { --i: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M7.8 8.6a4.2 4.2 0 1 1 6.2 3.7c-1.3.7-2 1.5-2 3v.5M12 20h.01'/%3E%3C/svg%3E"); }
.icon-sun { --i: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 7a5 5 0 1 0 0 10 5 5 0 0 0 0-10zm-1-6h2v3.6h-2zm0 19.4h2V24h-2zM0 11h3.6v2H0zm20.4 0H24v2h-3.6zM3.5 4.9 4.9 3.5l2.5 2.5L6 7.4zm13.1 13.1 1.4-1.4 2.5 2.5-1.4 1.4zM19.1 3.5l1.4 1.4-2.5 2.5-1.4-1.4zM3.5 19.1 6 16.6l1.4 1.4-2.5 2.5z'/%3E%3C/svg%3E"); }
.icon-mic { --i: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 2a3.5 3.5 0 0 0-3.5 3.5v6a3.5 3.5 0 0 0 7 0v-6A3.5 3.5 0 0 0 12 2zM5 11h2a5 5 0 0 0 10 0h2a7 7 0 0 1-6 6.93V21h3v2H8v-2h3v-3.07A7 7 0 0 1 5 11z'/%3E%3C/svg%3E"); }
/* push-to-talk (shell/voice/): the last segment of the selected vehicle's bar; HELD it grows into a long pill of bars that
   follow the voice (wave.js), ink with the panel's colour on it — turned round in either light, so it reads as live; the bar's
   own width follows it (app.js --vehicle-w), so Rewind and the search glide over. On a phone the bar is a column: it stays a circle.
   Let go, the mic again: the ping says how it went, never a reply */
#voice-btn { touch-action: none; user-select: none; -webkit-user-select: none; transition: width var(--fade) var(--ease); }
#voice-btn .voice-wave { display: none; }
#voice-btn.held, body.phone #vehicle-bar > #voice-btn.held { background: var(--text-ink); border-radius: var(--radius-full); } /* the phone's: over its glass circles' rule */
body:not(.phone) #voice-btn.held { width: 132px; } /* long, the wave the point (the owner); a phone's column keeps its own width */
body:not(.phone) #voice-btn.held .voice-wave { gap: 8px; } /* nine bars across the pill, not bunched in its middle */
body.phone #voice-btn .voice-wave i:nth-child(n+6) { display: none; } /* five of the nine fit its circle */
#voice-btn.held > .icon { display: none; }
#voice-btn.held .voice-wave { display: flex; align-items: center; justify-content: center; gap: 4px; height: 24px; }
#voice-btn.held .voice-wave i { will-change: transform; } /* their own layers while held: a bar's frame never repaints the bar's blurred glass */
#voice-btn .voice-wave i { display: block; width: 4px; height: 24px; border-radius: var(--radius-full); background: var(--surface-panel); transform: scaleY(.18); }
/* a spoken question's answer (shell/voice/answer.js): the arrived pill's gold in the middle of the picture, under the red dot,
   eased in and out; colours from THEME by the script (badge.fill, voice.answerInk, a warning's danger rim) */
.voice-answer { position: absolute; z-index: 6; /* over a maximised minimap (5) */ left: 50%; top: 56%; padding: 4px 12px; border: 2px solid; border-radius: var(--radius-l);
  font-size: 14px; line-height: 20px; font-weight: 600; text-align: center; max-width: 86%; pointer-events: none;
  opacity: 0; transform: translate(-50%, -4px); transition: opacity var(--fade) var(--ease-exit), transform var(--fade) var(--ease-exit); }
.voice-answer.on { opacity: 1; transform: translate(-50%, 0); transition: opacity var(--fade) var(--ease), transform var(--fade) var(--ease); }
.voice-said { position: fixed; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; } /* the answer said to a screen reader (answer.js): off the screen */
.voice-answer > div:first-child:not(:only-child) { font-size: 12px; line-height: 16px; font-weight: 500; opacity: .75; }
.voice-answer.narrow { top: 50%; max-width: 94%; padding: 4px 8px; font-size: 12px; line-height: 16px; }
.voice-text { position: fixed; left: 50%; bottom: 72px; transform: translateX(-50%); width: min(360px, calc(100vw - 32px)); z-index: 5;
  font: 14px/20px var(--font); padding: 8px 12px; border-radius: var(--radius-full); border: 1px solid var(--line-strong); }
.icon-moon { --i: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 3a9 9 0 1 0 9 9 7 7 0 1 1-9-9z'/%3E%3C/svg%3E"); }
.icon-link { --i: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71'/%3E%3C/svg%3E"); }
/* save a file (shell/nvg/): an arrow down into a tray */
.icon-save { --i: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 3v12M7 10l5 5 5-5M4 17v3h16v-3'/%3E%3C/svg%3E"); }
/* full screen (the phone sheet's button, phone.js): four corners out, and in */
.icon-full { --i: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M4 10V4h6v2H6v4zm10-6h6v6h-2V6h-4zM4 14h2v4h4v2H4zm14 0h2v6h-6v-2h4z'/%3E%3C/svg%3E"); }
.icon-shrink { --i: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M10 4v6H4V8h4V4zm4 0h2v4h4v2h-6zM4 14h6v6H8v-4H4zm10 0h6v2h-4v4h-2z'/%3E%3C/svg%3E"); }
/* the satellite map's Earth, and a narrow card's two toggles: a folded map, and the disc with its ownship (.icon-minimap) */
.icon-satellite { --i: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linejoin='round' stroke-linecap='round'%3E%3Ccircle cx='12' cy='12' r='9.2'/%3E%3Cpath d='M2.8 12h18.4M4 7.4h16M4 16.6h16M12 2.8c2.6 2.6 3.9 5.7 3.9 9.2s-1.3 6.6-3.9 9.2c-2.6-2.6-3.9-5.7-3.9-9.2s1.3-6.6 3.9-9.2z'/%3E%3C/svg%3E"); } /* the Earth: the photographs' button (shell/mapcontrols/) */
.icon-basemap { --i: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M2 6l6-2.5v14L2 20zM9 3.5L15 6v14l-6-2.5zM16 6l6-2.5v14l-6 2.5z'/%3E%3C/svg%3E"); }
/* the sight (T): a lens ring with its spot and the span bar's ticks either side */
.icon-sight { --i: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill-rule='evenodd' d='M12 4a8 8 0 1 0 0 16 8 8 0 0 0 0-16zm0 2.2a5.8 5.8 0 1 1 0 11.6 5.8 5.8 0 0 1 0-11.6zM12 9.5a2.5 2.5 0 1 1 0 5 2.5 2.5 0 0 1 0-5zM1 11h3v2H1zm19 0h3v2h-3z'/%3E%3C/svg%3E"); }
/* look ahead from the aircraft: an arrow over the horizon */
.icon-altview { --i: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cdefs%3E%3Cmask id='m'%3E%3Crect width='24' height='24' fill='%23fff'/%3E%3Cg fill='none' stroke='%23000' stroke-width='2'%3E%3Cpath d='M8 13a4 4 0 0 1 7.06-2.57'/%3E%3Cpath d='M16 13a4 4 0 0 1-7.06 2.57'/%3E%3C/g%3E%3Cpath d='M16.02 11.59 16.18 9.11 13.56 11.29zM7.98 14.41 7.82 16.89 10.44 14.71z'/%3E%3C/mask%3E%3C/defs%3E%3Cpath mask='url(%23m)' d='M9 3.5h6l1.6 2.2H20a2 2 0 0 1 2 2V18a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V7.7a2 2 0 0 1 2-2h3.4z'/%3E%3C/svg%3E"); }
.icon-minimap { --i: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill-rule='evenodd' d='M12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20zm0 2.2a7.8 7.8 0 1 1 0 15.6 7.8 7.8 0 0 1 0-15.6zm0 3.3-4 9.2 4-2 4 2z'/%3E%3C/svg%3E"); }
/* the compute graph: one node branching into two — a flowchart, not a chart */
.icon-graph { --i: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M8.5 2h7v5h-7zM11 7h2v3h-2zM3 10h18v1.6H3zM5 11.6h1.8V14H5zM17.2 11.6H19V14h-1.8zM2 14h7.6v5H2zM14.4 14H22v5h-7.6z'/%3E%3C/svg%3E"); }
/* gnss/'s GNSS fix: a satellite, its two panels and its body, sending */
.icon-accuracy { --i: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill-rule='evenodd' d='M12 5a7 7 0 1 1 0 14 7 7 0 0 1 0-14zm0 2a5 5 0 1 0 0 10 5 5 0 0 0 0-10z'/%3E%3Cpath d='M11 2h2v7h-2zm0 13h2v7h-2zM2 11h7v2H2zm13 0h7v2h-7z'/%3E%3C/svg%3E"); } /* gnss/'s fix accuracy: a crosshair through a ring (an ellipse round a dot read as the Overlays' eye) */
.icon-gnss { --i: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M3.5 7.3 7.3 3.5l3.5 3.5L7 10.8zM13.2 17l3.8-3.8 3.5 3.5-3.8 3.8zM8.6 12 12 8.6l3.4 3.4-3.4 3.4zM2 14h2a6 6 0 0 0 6 6v2a8 8 0 0 1-8-8zm3.6 0h2a2.4 2.4 0 0 0 2.4 2.4v2A4.4 4.4 0 0 1 5.6 14z'/%3E%3C/svg%3E"); }
/* applies on reload: a circular arrow, for the dials GL JS took at construction */
.icon-reload { --i: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M17.65 6.35A8 8 0 1 0 19.73 14h-2.08A6 6 0 1 1 12 6c1.66 0 3.14.69 4.22 1.78L13 11h7V4z'/%3E%3C/svg%3E"); }
/* each tool's pointer is what it is about to put down (Pegman): aoi/ soldier/ bake --cursor-<mode> at setup (a cursor image cannot read a var) */
body[data-mode="poi"] .mapboxgl-canvas-container.mapboxgl-interactive {
  cursor: crosshair; }
body[data-mode="aoi"] .mapboxgl-canvas-container.mapboxgl-interactive {
  cursor: var(--cursor-aoi, crosshair); }
body[data-mode="soldier"] .mapboxgl-canvas-container.mapboxgl-interactive {
  cursor: var(--cursor-soldier, crosshair); }
body[data-mode="nav"] .mapboxgl-canvas-container.mapboxgl-interactive { cursor: crosshair; } /* a stop wants the exact pixel */
body:is([data-mode="eagles"], [data-mode="ascod"], [data-mode="rav4"], [data-mode="drone"]) .mapboxgl-canvas-container.mapboxgl-interactive {
  cursor: crosshair; } /* the place fan's vehicles: where the tap lands is where it parks */
/* a symbol or a pin under the pointer (tooltip.js probes) answers a click: a class, never inline, so an armed crosshair is never shadowed */
.mapboxgl-canvas.over-symbol { cursor: pointer; }
/* an area under the pointer (overlays/generic/aoi/corners.js): a click selects it; its corner a press drags */
.mapboxgl-canvas.over-area { cursor: pointer; }
.mapboxgl-canvas.over-corner { cursor: grab; }
.mapboxgl-canvas.dragging-corner { cursor: grabbing; }
/* the Overlays open: the row slides right of it (20 + its width + 12) */
body:has(#overlays:not(.shut)) #toolbar { left: calc(32px + var(--sidew)); }
.draw-surface { position: absolute; inset: 0; z-index: 4; display: none;
               cursor: var(--cursor-draw, crosshair); touch-action: none; }
body.drawing .draw-surface { display: block; }
/* THE PEN'S PILL (draw.js): Keep and Wipe, a touch screen's Shift-drag and Backspace, at the map's foot while the pen is armed;
   its plate .glass's list, Keep's press the SELECTED capsule; shown in the (pointer: coarse) block */
.draw-touch { display: none; }
/* Mapbox's groups wear the PillButtonBar (mapcontrols.js; a white slab was the night map's brightest object). GL JS's own stays here:
   its halo off, its buttons' type and ink, and `order` lifting the where-am-I button (built LATE, appended LAST) over the compass */
.mapboxgl-ctrl-group:not(:empty) { box-shadow: var(--glass-shadow); } /* GL JS's own ring is 0-2-0 and would win */
.mapboxgl-ctrl-group button { font: 16px/1 var(--font); color: var(--text-ink); }
.mapboxgl-ctrl-group .mapboxgl-ctrl-compass { order: 1; }
/* a real compass: dark north, salmon-red south (GL JS bakes it grey; its night variants outrank a lone class) */
.mapboxgl-ctrl-group button.mapboxgl-ctrl-compass .mapboxgl-ctrl-icon { background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23333' viewBox='0 0 29 29'%3E%3Cpath d='M10.5 14l4-8 4 8h-8z'/%3E%3Cpath d='M10.5 16l4 8 4-8h-8z' fill='%23fa7268'/%3E%3C/svg%3E"); }
/* GL JS's own hover was 5 % black, invisible at night, and at (0,3,1) replaced a pressed fill; `:not(:disabled)` puts ours level and later.
   Its #eee hover is off here and back as ours under (hover: hover): a tap's hover STICKS, and at night left a near-white glyph on #eee */
.mapboxgl-ctrl-group button:not(:disabled):hover { background-color: transparent; }
.mapboxgl-ctrl-group button:not(:disabled):active {
  background-color: color-mix(in srgb, var(--text-ink) 20%, transparent); }
/* no inversion: nothing in the stack is a toggle (mapcontrols.js Scars). Mapbox's blue focus shadow off: the app's ring is enough */
.mapboxgl-ctrl-group button:focus, .mapboxgl-ctrl-group button:focus:focus-visible { box-shadow: none; }
/* the ring INSIDE the capsule's buttons: 2 px outside, the neighbours covered it */
.mapboxgl-ctrl-group button:focus-visible { outline-offset: -2px; }
/* the map's own Tab stop: .mapboxgl-map's overflow: hidden clips a ring drawn outside the canvas that fills it (Scars) */
.mapboxgl-map .mapboxgl-canvas:focus-visible { outline-offset: -2px; } /* over the later global ring rule (0,2,0) */
.mapboxgl-ctrl-group .icon { width: 16px; height: 16px; margin: 6px auto; }
/* Mapbox's nav glyphs are baked images: inverted after dark, the compass's hue turned back (or its red needle goes cyan) */
.mapboxgl-ctrl-icon { transition: filter var(--fade); } /* …and cross over with the palette, as the chips do */
body[data-light="night"] .mapboxgl-ctrl-icon { filter: invert(1); }
body[data-light="night"] .mapboxgl-ctrl-compass .mapboxgl-ctrl-icon { filter: invert(1) hue-rotate(180deg); }
/* mid-chase two fingers are the drone's radius (mapcam/) and GL JS's touch handlers stand down, dropping their touch-action */
body.chase .mapboxgl-canvas-container { touch-action: none; }
/* a layer over its picture that takes no pointer: the satellites' canvas (it paints between the map's frames), gnss/'s
   names, the dial's wedge highlight */
.sat-overlay, .gnss-overlay, .radial-wedge-hl { position: absolute; left: 0; top: 0; pointer-events: none; }
/* the scale bar from the palette (Mapbox's #333 read nothing at night). A RULER, not a plate: GL JS's open bracket is the
   measure (glassed for an hour; the owner: "this entity is supposed to be a map ruler") */
.mapboxgl-ctrl-scale {
  background-color: var(--overlay-scale);
  color: var(--text-ink); border-color: var(--text-ink);
  font-size: 12px; line-height: 16px; /* GL JS ships 10: under the type floor (12) */
}
/* THE F1 CALLOUTS (shell/mapcontrols/callouts.js): a scrim, and beside each thing a card of the keys that act on it now on a
   dotted ink leader with no head; one grid a card, the caps centred in a column, a row ONE line unless long */
#callouts { position: fixed; inset: 0; z-index: var(--z-top); pointer-events: none;
            font: 12px/16px var(--font); color: var(--text-ink); }
#callouts * { box-sizing: border-box; }
body.callouts .key-hints { visibility: hidden; } /* the pills say the same: one voice while the cards are up */
.co-scrim { position: absolute; inset: 0; background: var(--overlay-backdrop); pointer-events: auto; animation: co-fade var(--fade) both; }
@keyframes co-fade { from { opacity: 0; } }
.co-leaders { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.co-leaders path { fill: none; stroke: var(--text-ink); stroke-width: 2; stroke-dasharray: 0 5; stroke-linecap: round; stroke-linejoin: round; }
.co-card { position: absolute; left: 0; top: 0; max-width: 340px; display: grid; grid-template-columns: auto 1fr; gap: 8px 8px;
           align-items: center; padding: 8px 12px; border-radius: var(--radius-l); color: var(--text-ink); /* its plate: the thick glass (callouts.js) */
           pointer-events: auto; animation: co-pop var(--fade) var(--ease) both; }
@keyframes co-pop { from { opacity: 0; scale: .9; } }
.co-card.stay { animation: none; } /* redrawn in place (callouts.js): it is already there */
/* LEAVING (callouts.js hide): out the way they came on --tap and --ease-exit, the DOM going after (F1 off dropped all in one frame) */
#callouts.leaving .co-card { animation: co-out var(--tap) var(--ease-exit) both; }
@keyframes co-out { to { opacity: 0; scale: .9; } }
@keyframes co-fade-out { to { opacity: 0; } }
#callouts.leaving :is(.co-scrim, svg) { animation: co-fade-out var(--tap) var(--ease-exit) both; } /* the full-screen leaders fade, they do not shrink */
.co-row { display: contents; } /* the rows share the card's two columns */
.co-head { grid-column: 1 / -1; margin-bottom: -2px; font-size: 12px; line-height: 16px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; color: var(--text-meta); }
.co-caps { display: inline-flex; align-items: center; gap: 2px; justify-self: center; }
.co-caps kbd.wide { padding: 0 8px 2px; }
.co-what { min-width: 0; line-height: 16px; }
.co-say { font-weight: 700; white-space: nowrap; }
.co-more { color: var(--text-soft); font-weight: 400; }
.co-plus { font-weight: 700; margin: 0 1px; }
/* a mouse cap: the body, the acting button filled, the gesture's word */
.co-mouse { gap: 2px; padding: 0 4px 2px; }
.co-mouse svg rect, .co-mouse svg path { fill: none; stroke: var(--hud-key-rim); stroke-width: 1.5; }
.co-mouse svg .f { fill: var(--hud-key-rim); stroke: none; }
.co-mouse span { font-size: 12px; line-height: 16px; }
.co-touch { gap: 4px; padding: 0 4px 2px; } /* a finger's gesture: its fingers as dots, then the word (callouts.js TOUCH) */
.co-touch svg circle { fill: var(--hud-key-rim); }
.co-touch span { font-size: 12px; line-height: 16px; }
/* a pressed key lights its cap for a moment (callouts.js LIT_MS) */
.co-caps kbd { transition: background var(--tap), color var(--tap); }
.co-caps kbd.lit { background: var(--hud-key-rim); color: var(--hud-key-face); }
#overlays-list {
  /* one level's step, half the 16 px lead column: the triangles carry the nesting, and a deep track keeps 32 px more name */
  --indent: 8px;
  details { border-bottom: 1px solid var(--line-rule); }
  /* the section headers scroll WITH their rows: a pinned one needs a backdrop, and a backdrop inside a translucent plate doubles
     its tint (only the map under the panel is replaced), a band in a second colour (the owner).
     ONE ROW, three kinds (a summary, a bare row, a track): a 16 px LEAD column (the fold's triangle, a tone dot, or nothing), the
     label, the number, the eye, all in flow — every label at a level on one x, every number on one edge 4 px short of the eye.
     The native marker's font-width and an absolute count put labels at four x's and the count under a phone's 44 px eye */
  :is(summary, .overlays-row) { display: flex; align-items: center; justify-content: flex-start; min-height: var(--row-h); }
  summary { padding: 4px 0; font-weight: bold; cursor: pointer; list-style: none; }
  /* an empty list (satellites/ with no hits) is no padded strip; never the windowed .row-list, whose unfilled hidden box read
     offsetTop 0 and was never filled (at --n 0 it is 0 tall anyway) */
  summary::-webkit-details-marker, details > div:empty:not(.row-list) { display: none; }
  :is(summary, .overlays-row)::before { content: ''; flex: none; width: 16px; height: 8px; }
  summary::before {
    background: currentColor; mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath d='M1.5 0 7 4 1.5 8z'/%3E%3C/svg%3E") 0 50% / 8px 8px no-repeat;
    transition: rotate var(--tap) var(--ease); transform-origin: 4px 50%; /* the triangle's own centre, open AND shut */
  }
  details[open] > summary::before { rotate: 90deg; }
  button.overlays-row::before { width: 8px; height: 8px; margin-right: 8px; border-radius: 50%; background: var(--tone, transparent); }
  :is(summary, .overlays-row) > .show { order: 1; }
  :is(summary, .overlays-row) > .count, :is(summary, .overlays-row):not(:has(> .count)) > .show { margin-left: auto; }
  :is(summary, .overlays-row) > .count { padding: 0 4px 0 8px; }
  /* the show button: one masked eye; a 24px box (WCAG 2.5.8) round a 16px glyph */
  .show {
    width: 24px; height: 24px; padding: 0;
    border: none; cursor: pointer; background: var(--text-soft);
    --eye: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill-rule='evenodd' d='M12 5C6.5 5 2.3 9.7 1 12c1.3 2.3 5.5 7 11 7s9.7-4.7 11-7c-1.3-2.3-5.5-7-11-7zm0 10.5a3.5 3.5 0 1 1 0-7 3.5 3.5 0 0 1 0 7z'/%3E%3C/svg%3E");
    mask: var(--eye) center / 16px 16px no-repeat;
  }
  /* hidden: a slash punched through the eye; .65 clears 3:1 on the glass over a road (theme.test) */
  .show.hidden {
    opacity: .65;
    --eye: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill-rule='evenodd' d='M12 5C6.5 5 2.3 9.7 1 12c1.3 2.3 5.5 7 11 7s9.7-4.7 11-7c-1.3-2.3-5.5-7-11-7zm0 10.5a3.5 3.5 0 1 1 0-7 3.5 3.5 0 0 1 0 7zM3.1 1.7 22.3 20.9l-1.4 1.4L1.7 3.1z'/%3E%3C/svg%3E");
  }
  details > div { padding: 2px 0 6px var(--indent); }
  /* A SECTION EASES OPEN AND SHUT (the owner's pick): its content's height 0 ↔ `auto` (interpolate-size), rendered until
     folded (content-visibility, discrete); without ::details-content or interpolate-size it opens at once */
  interpolate-size: allow-keywords;
  details::details-content { height: 0; overflow: clip;
    transition: height var(--slide) var(--ease), content-visibility var(--slide) allow-discrete; }
  details[open]::details-content { height: auto; }
  /* nested sections: plain rows, not bold bordered sections */
  details details { border-bottom: 0; }
  details details > summary { font-weight: normal; padding: 0; }
  /* the in-view count. Not a flex summary: that loses the disclosure triangle */
  .count {
    color: var(--text-meta); font-size: 12px; line-height: 16px; font-weight: normal; font-variant-numeric: tabular-nums;
  }
  /* every row on one pitch, --row-h: the eye in flow sets it, so a row has no padding (14px/1.4 gave 23.6 and 28) */
  .overlays-row { padding-block: 0; }
  /* never answered AND the last poll threw: '!' with the reason as its title */
  .count.warn { color: var(--text-danger); font-weight: bold; }
  /* answered once and gone quiet: greyed, the age on the tooltip */
  .count.stale { color: var(--text-faint); font-style: italic; }
  /* the world's count with none of it in view; a row out of coverage or parked by its eye (overlaysPanel/), nothing
     fetched, fades whole — one muted line says it where six '—' did not */
  .count.none, :is(details.off > summary, .overlays-row.off) { color: var(--text-faint); }
  /* windowed rows (overlaysPanel/): `--n` rows of height reserved, the visible slice placed in it at --row-h (rowH() reads it) */
  .row-list {
    contain: content; position: relative;
    height: calc(var(--n, 0) * var(--row-h));
  }
  .row-list > .overlays-row { position: absolute; left: 0; right: 0; height: var(--row-h); }
  /* the "nothing in view" line is not a windowed row */
  .row-list > .overlays-row.empty { position: static; height: auto; }
  /* an empty list reserves 0 rows, or its one line of explanation hides under the next header */
  .row-list:has(.empty) { height: auto; }
  /* a link in the panel is a 24px target (WCAG 2.5.8): NEPTUN's is a licence term, not a courtesy */
  a { display: inline-flex; align-items: center; min-height: 24px; }
  /* "Show all" (overlaysPanel/): a control over the list outside .row-list (the windowing never sees it), 24px tall,
     underlined: the one row that changes what the list IS rather than flying the map */
  button.overlays-row.more {
    font-size: 12px; line-height: 16px; color: var(--text-meta);
    min-height: 24px; display: flex; align-items: center; text-decoration: underline;
  }
  /* the track list and Show all hang off the <details> beside the rows' box: its indent, as a margin (the rows are placed from it) */
  details > .row-list { margin-left: var(--indent); }
  details > button.overlays-row.more { padding-left: var(--indent); }
  :is(button.overlays-row, summary, .show):focus-visible {
    outline: 2px solid var(--text-ink); outline-offset: -2px;
  }
  /* the Splats section's one verb (overlays/generic/splats/): it fills while a folder is dragged over the map or over it */
  .splat-load { width: 100%; margin: 6px 0 8px; }
}

/* display:flex would beat [hidden] here but for the one [hidden] rule: an empty note row held a blank line open */
.overlays-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 2px 0;
  cursor: pointer;
}

.overlays-row button { /* the delete: the same 24px target as every other verb */
  min-width: 24px; min-height: 24px; padding: 0;
  cursor: pointer;
  color: var(--text-danger);
}

.overlays-row button .icon { width: 12px; height: 12px; }

/* a meta shrinks and ellipsises like a name: held whole it cut the name to nothing and put the ✕ past the panel ("unable to delete splat") */
.overlays-row .meta { color: var(--text-meta); font-size: 12px; line-height: 16px; margin-left: auto; padding: 0 4px 0 8px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* a track row has no eye: its meta ends where a count does. The NAME gives way first ("1.7 km" read "1…"), the meta held whole
   up to half the row so a long one still ellipsises */
button.overlays-row > .meta { padding-right: 28px; }
button.overlays-row:not(.item) > .meta { flex-shrink: 0; max-width: calc(50% + 28px); } /* an item's meta has its own line; the
   half is its words', the 28 px beside the eye column on top of it ("0 km/h · 9131 km" read "0 km/h · 9131 …" at z3) */

/* with nothing followed the waypoints list is a bare hint (a text node, not a counted row) */
:is(#waypoints-list, #splats-list):not(:has(.overlays-row)) { color: var(--text-faint); font-size: 12px; line-height: 16px; }

/* EVERY item (PoI, waypoint, AoI, splat) is M3's dense two-line row, one rule: the name over its meta, the ✕ beside both. On one
   line the meta held its width and cut 14 of 17 names to "Command L…", and a waypoint's pushed its ✕ off ("can't delete") */
#overlays-list .overlays-row.item { display: grid; grid-template-columns: 16px minmax(0, 1fr) auto; }
#overlays-list .overlays-row.item::before { grid-area: 1 / 1 / 3 / 2; }
#overlays-list .overlays-row.item > .lbl { grid-area: 1 / 2; }
#overlays-list .overlays-row.item > .meta { grid-area: 2 / 2; margin: 0; padding: 0; }
#overlays-list .overlays-row.item > button { grid-area: 1 / 3 / 3 / 4; align-self: center; }

/* the other self-filled lists say so instead of an 8px blank */
:is(#poi-list, #aoi-list, #draw-list):empty::before {
  content: 'nothing drawn yet'; color: var(--text-faint); font-size: 12px; line-height: 16px; }

.overlays-row [contenteditable="true"] { outline: 1px solid var(--text-dim); padding: 0 2px; }

/* lists filled by features: content-visibility skips those scrolled out, contain-intrinsic-size keeps the scrollbar steady */
#settings-list, #poi-list, #aoi-list, #waypoints-list, #draw-list {
  content-visibility: auto;
  contain-intrinsic-size: auto 200px;
}

#aoi-list details { border-bottom: 0; }

#aoi-list summary { font-weight: normal; padding: 0; }

/* ---- track lists (overlaysPanel/) ---- */
/* EVERY field in the panel is the search pill's twin (the owner): no fill, the glass rim, ink while focused — a plate inside the
   Overlays' plate doubles the tint */
.dial-num {
  color: var(--text-ink); border: 2px solid var(--overlay-rim); border-radius: var(--radius-full); background: transparent; }
.dial-num:focus-visible { outline: none; border-color: var(--text-ink); }

/* long names ellipsise; min-width:0 lets a flex item shrink below its content */
.overlays-row .lbl { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.overlays-row.empty { color: var(--text-faint); font-size: 12px; line-height: 16px; cursor: default; }

/* track rows are <button>s (overlaysPanel/), keyboard-reachable */
button.overlays-row {
  width: 100%; margin: 0;
  font: inherit; color: inherit; text-align: left;
  /* the row wears its pin's fill as the lead column's dot (#overlays-list); a row with no pin keeps the column */
  padding-inline: 0;
}

.mapboxgl-ctrl-logo { display: none !important; }
/* the callout (details/): a clicked pin morphs into this card from its own anchor, transform + opacity only (no layout) */
.callout {
  position: relative;
  display: flex; align-items: center;
  /* --dx (details/) steps a card back inside its container; the grow still runs from the pin */
  left: var(--dx, 0px); transform-origin: calc(50% - var(--dx, 0px)) 100%;
  max-width: min(340px, calc(100vw - 40px)); padding: 12px 32px 12px 12px;
  color: var(--text-ink); /* its plate: the thick glass (details.js) */
  font: 14px/20px var(--font);
  /* collapsed = the pin's head (details/ measures both and sets the vars) */
  opacity: 0; border-radius: 50%;
  transform: translateY(var(--ty, -20px)) scale(var(--sx, .16), var(--sy, .6));
  /* CLOSING: the shrink on --ease (a card folding into its own pin is not leaving the screen), the plate fading over its last
     --tap (faded from the first frame it was gone before the shrink showed). OPENING (.open's): the plate at once, words after */
  transition: transform var(--slide) var(--ease), border-radius var(--slide) var(--ease),
              opacity var(--tap) var(--ease-exit) calc(var(--slide) - var(--tap));
  will-change: transform, opacity;
  /* the disc's own black edge, one ink in both lights, and no lip: the glass's light and rim drew a bevel round the pin's fill
     (the owner). &.glass outranks .glass:focus-within */
  &.glass { border: 1.5px solid var(--symbol-outline); box-shadow: 0 10px 30px -10px var(--overlay-shadow); }
  &.open { opacity: 1; transform: none; border-radius: var(--radius-xl);
           transition: transform var(--slide) var(--ease), border-radius var(--slide) var(--ease), opacity var(--tap) var(--ease); }
  &.open .callout-body, &.open .callout-glyph, &.open .callout-x {
    opacity: 1; transition-delay: calc(var(--slide) - var(--tap));
  }
  b { display: block; font-size: 16px; line-height: 24px; margin-bottom: 2px;
               overflow: hidden; text-overflow: ellipsis; }
  img { display: block; max-width: 100%; border-radius: var(--radius-m); margin-top: 6px; }
  /* the card's gauge (details/gauge): the FILL grades green to red (an open card is one question; the map's wears its disc's
     colour); track and rim in the card's own ink mixed, like the glyph divider, so it holds on every fill pastel to dark red */
  .gauge {
    display: block; height: 9px; margin: 6px 0 2px; max-width: 220px;
    background: color-mix(in srgb, currentColor 16%, transparent);
    border: 1px solid color-mix(in srgb, currentColor 45%, transparent);
    border-radius: var(--radius-s); overflow: hidden;
  }
  /* min-width: one free space in four hundred is a cap you can see (badge/'s rule on the map) */
  .gauge i { display: block; height: 100%; min-width: 5px; border-radius: var(--radius-s); }
  /* the count at the bar's right end: four characters do not earn a line, and the bar and its figure are one reading */
  .gauge-row { display: flex; align-items: center; gap: 8px; margin: 6px 0 2px; }
  .gauge-row .gauge { flex: 1; margin: 0; }
  .gauge-n { flex: none; font-variant-numeric: tabular-nums; font-size: 12px; line-height: 16px;
                      opacity: .85; }
  /* the row's name where one bar is not the story: three classes queue at a border post */
  .gauge-k { flex: none; width: 3.6em; font-size: 12px; line-height: 16px; opacity: .8; }
  /* WHEN, as a state (details/'s `chip`): a tinted dot and two characters for the line each feed spent */
  .chip { display: inline-flex; align-items: center; gap: 4px;
                   font-size: 12px; line-height: 16px; opacity: .85; font-variant-numeric: tabular-nums; }
  .chip i { flex: none; width: 7px; height: 7px; border-radius: 50%; }
  /* small facts side by side, so two of them do not cost two lines */
  .row { margin-top: 4px; font-size: 12px; line-height: 16px; overflow: hidden; text-overflow: ellipsis; }
  /* block, not flex, so it can END in an ellipsis; the facts space themselves */
  .row > * + * { margin-left: 8px; }
  .row > *, .sub > * { vertical-align: middle; }
  /* the symbol in words (APP-6D is not universally read, a screen reader gets nothing from a frame), under the name at the meta
     weight, a ROW so the age chip rides its end */
  .sub { display: flex; align-items: center; gap: 8px;
                  font-weight: 400; font-size: 12px; line-height: 16px; opacity: .75; }
  /* the WORDS give way, the tail (an age, a bar) does not: it is the one reading on the line */
  .sub-t { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
  .sub > :not(.sub-t) { flex: none; }
  /* how far through a works is, how well a track is placed: as long as the line leaves it, never longer than a reading. The floor
     is on the BAR: a basis it could not fill sized the card without it ("→ Kyiv" read "→ …") */
  .sub > .gauge-row { flex: 1 1 auto; max-width: 110px; margin: 0; }
  .sub .gauge { min-width: 48px; }
  /* one pip per reporting source, tinted by the feed's confidence: dots are read without counting, "high, 3 src" is not */
  .pips { display: inline-flex; gap: 2px; }
  .pips i { width: 6px; height: 6px; border-radius: 50%; }
  /* a grade's price against the local median (fuel/): a bar reading OUT FROM ITS CENTRE, the median tick drawn, not implied;
     colour is the direction, length how far */
  .price { display: flex; align-items: center; gap: 8px; margin: 4px 0;
                    font-variant-numeric: tabular-nums; }
  .price-k { flex: none; width: 3.4em; font-size: 12px; line-height: 16px; opacity: .8; }
  .price-v { flex: none; font-size: 12px; line-height: 16px; }
  .price-bar {
    position: relative; flex: 1; min-width: 104px; height: 7px; border-radius: var(--radius-s);
    background: color-mix(in srgb, currentColor 14%, transparent);
  }
  .price-bar::before { /* the median, OVER the segment it is read against */
    content: ''; position: absolute; left: 50%; top: -2px; bottom: -2px; width: 1px; z-index: 1;
    background: color-mix(in srgb, currentColor 55%, transparent);
  }
  /* a pump AT the median still marks its tick; square at the centre, round at the far end, so it reads as running OUT */
  .price-bar i { position: absolute; top: 0; bottom: 0; min-width: 3px; }
  .price-bar i[style*="right:50%"] { border-radius: var(--radius-s) 0 0 var(--radius-s); }
  .price-bar i[style*="left:50%"] { border-radius: 0 var(--radius-s) var(--radius-s) 0; }
  /* the tick is NAMED once, hung off the last bar: an unnamed centre is decoration, and the word sits on what it names */
  .price:last-of-type { margin-bottom: 12px; }
  .price:last-of-type .price-bar::after {
    content: 'median'; position: absolute; left: 50%; top: 9px; transform: translateX(-50%);
    font-size: 12px; line-height: 16px; letter-spacing: .03em; opacity: .55;
  }
  /* the one thing a card offers to DO (details/'s `act`): outlined in the card's ink, never filled (the card is already the
     feed's colour), on its own line */
  .card-act {
    display: block; margin-top: 8px; padding: 4px 8px;
    font: inherit; font-size: 12px; line-height: 16px; cursor: pointer;
    color: inherit; background: color-mix(in srgb, currentColor 10%, transparent);
    border: 1px solid color-mix(in srgb, currentColor 45%, transparent); border-radius: var(--radius-m);
  }
  /* a licence link in the card's ink, underlined: the UA's blue is a third colour and under 3:1 on the darker fills */
  a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }
  /* the tail, painted over the card's bottom border so the outline runs unbroken */
  &::after {
    content: ''; position: absolute; left: 50%; bottom: -7px;
    width: 14px; height: 14px; margin-left: calc(-7px - var(--dx, 0px)); /* stays on the point */
    background: inherit; border-radius: 0 0 var(--radius-s) 0;
    border-right: 1.5px solid var(--symbol-outline); border-bottom: 1.5px solid var(--symbol-outline);
    transform: rotate(45deg);
  }
}

/* the contents arrive once the shape is most of the way there, and LAND with it */
.callout-body, .callout-glyph, .callout-x {
  opacity: 0; transition: opacity var(--tap) var(--ease);
}

/* NOTHING ON A CARD WRAPS: each line cut with an ellipsis, the whole of it on its tooltip (details/); a paragraph of an
   upstream's prose was a wall of text over the map it explains */
.callout-body { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* THE CAMERA CARD (roadcams/camcard.js): the name, a rounded picture, a short stem over the badge; --w per frame from metres
   on the map's third; .kept is the card in the cards' column (no stem). The Marker owns the element's transform, so the grow is
   on the card inside it */
.cam-card {
  display: flex; flex-direction: column; align-items: center;
  width: var(--w, 320px); pointer-events: none;
}

.cam-card > * { transition: opacity var(--fade) var(--ease), transform var(--slide) var(--ease); }

.cam-card:not(.open) > * { opacity: 0; }

.cam-card.kept { width: 100%; flex: none; pointer-events: auto; }

.cam-card.kept :is(.cam-stem, .cam-keep) { display: none; }

.cam-card:not(.open) .cam-frame { transform: translateY(12px) scale(.92); }

.cam-card:not(.open) .cam-stem { transform: scaleY(0); }

.cam-title {
  align-self: flex-start; max-width: 100%; margin: 0 0 6px 4px;
  font: bold 14px/20px var(--font); color: var(--text-ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  /* the halo is the app's glass, so the name reads on any ground */
  text-shadow: 0 0 3px var(--overlay-scrim), 0 0 8px var(--overlay-scrim), 0 0 14px var(--overlay-scrim);
}

.cam-frame {
  position: relative; width: 100%; aspect-ratio: 16 / 9; overflow: hidden; isolation: isolate;
  border-radius: var(--radius-xl); border: 1.5px solid var(--symbol-outline); /* its badge's black edge, both lights (.callout) */
  background: var(--surface-void); box-shadow: 0 8px 24px var(--overlay-shadow);
  pointer-events: auto; transform-origin: 50% 100%;
}

/* the monitor's elements (roadcams/monitor/, the AR card's own classes) arrive when a picture is there */
.cam-frame :is(.ar-video, .ar-yt) { opacity: 0; transition: opacity var(--fade); background: transparent; }

.cam-frame .ar-video { object-fit: cover; }

.cam-frame .ar-yt { pointer-events: none; }

.cam-frame.live :is(.ar-video, .ar-yt) { opacity: 1; }

/* THE CORNER ✕, one control wherever a box closes (a camera card, F1 timing, a details card, the camera over a card's pod):
   24 px, 4 px in from the corner, a plate by its builder's glass() (the details card's wears its card's ink, .callout-x).
   The camera card's 📌 stands beside it, 4 px apart */
.corner-x, .cam-keep {
  position: absolute; top: 4px; right: 4px; z-index: 3;
  display: grid; place-items: center; width: 24px; height: 24px; padding: 0;
  border-radius: var(--radius-s); color: var(--text-ink); cursor: pointer;
}
.corner-x .icon { width: 12px; height: 12px; }

.cam-keep { right: 32px; }

.cam-keep .icon { width: 16px; height: 16px; }

.cam-note {
  position: absolute; left: 8px; bottom: 8px; z-index: 2; padding: 2px 8px; border-radius: var(--radius-s);
  color: var(--text-ink); font: 12px/16px var(--font); /* its plate: glass (camcard.js) */
}

.cam-note:empty { display: none; }
.cam-note a { color: inherit; text-decoration: underline; pointer-events: auto; }

/* the stem is INK haloed in the glass, like the title: a hairline in the frame's grey vanished on the night map */
.cam-stem { width: 2px; height: 28px; margin-top: 8px; border-radius: var(--radius-full); background: var(--text-ink);
            box-shadow: 0 0 0 1.5px var(--overlay-scrim); transform-origin: 50% 0; }

/* F1 LIVE TIMING (racetracks/timing.js): the camera card's chassis, a glass panel for the tower in place of the picture */
.f1-card { --w: 340px; }
.f1-frame { position: relative; width: 100%; padding: 8px 12px; border-radius: var(--radius-xl); pointer-events: auto;
  display: grid; gap: 8px; max-height: 60vh; overflow-y: auto; font: 12px/16px var(--font); color: var(--text-ink); }
.f1-card:not(.open) .f1-frame { transform: translateY(12px) scale(.92); }
.f1-status { font-weight: bold; color: var(--text-meta); padding-right: 32px; }
.f1-status.live { color: var(--text-danger); }
.f1-wx { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; }
.f1-wx div { display: grid; } .f1-wx small { color: var(--text-meta); font: 12px/16px var(--font); } .f1-wx b { font-variant-numeric: tabular-nums; }
.f1-tower { width: 100%; border-collapse: collapse; font-variant-numeric: tabular-nums; }
.f1-tower th { text-align: left; font: 12px/16px var(--font); color: var(--text-meta); font-weight: normal; padding: 2px 4px; border-bottom: 1px solid var(--line-rule); }
.f1-tower td { padding: 2px 4px; white-space: nowrap; border-bottom: 1px solid var(--line-rule); }
.f1-tower tr.ferrari td { font-weight: bold; background: color-mix(in srgb, var(--racetracks-ferrari) 16%, transparent); }
.f1-team { display: inline-block; width: 3px; height: 12px; margin-right: 4px; vertical-align: -1px; }
.f1-tyre { font-weight: bold; } .f1-tyre.t-S { color: var(--racetracks-tyre-soft); } .f1-tyre.t-M { color: var(--racetracks-tyre-medium); } .f1-tyre.t-H { color: var(--text-meta); } .f1-tyre.t-I { color: var(--racetracks-tyre-inter); } .f1-tyre.t-W { color: var(--racetracks-tyre-wet); }
.f1-rc p { margin: 2px 0; color: var(--text-soft); }
.f1-radio { display: flex; flex-wrap: wrap; gap: 6px; }
.f1-radio:empty, .f1-rc:empty { display: none; }
.f1-radio button { font: inherit; color: var(--text-ink); background: none; border: 1px solid var(--racetracks-ferrari); border-radius: var(--radius-full); padding: 0 8px; cursor: pointer; }
.f1-note { color: var(--text-faint); font: 12px/16px var(--font); }

/* the pin's glyph as a column down the left edge, as TALL as the card: a symbol with a movement leader in a 36 px square was
   smaller than the words beside it */
.callout-glyph {
  flex: none; align-self: stretch; width: 60px; margin-right: 12px; padding-right: 12px;
  display: flex; align-items: center;
  /* the divider is the card's own ink at a quarter: one fixed black hairline vanished on half the fills */
  border-right: 1px solid color-mix(in srgb, currentColor 25%, transparent);
}

/* a SQUARE whatever the symbol's box (a leader makes milsymbol's SVG 3× taller than wide, a 158 px card); `height: auto` is
   load-bearing: aspect-ratio yields to any height not auto, the SVG's attribute included */
.callout-glyph svg, .callout-glyph img { display: block; width: 100%; height: auto; aspect-ratio: 1; object-fit: contain; }

/* …and on its disc where the glyph is a RASTER with dark ink baked in (the siren, the boom gate), which no card can re-ink:
   the plate is the symbol's own fill, leaving the card's body neutral */
.callout-glyph.plated {
  align-self: center; width: 48px; height: 48px; /* a disc: its own square, whatever the card's height */
  border-right: none; border-radius: 50%; padding: 4px;
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--line-glyph) 45%, transparent);
}

/* the details card's ✕ inherits the CARD's ink; .6 stays above 4.5:1 on either ground */
.callout-x { color: inherit; opacity: .6; }


/* one focus ring everywhere, offset outside the control so it survives pressed fills */
:is(button, a, summary, input, select, [tabindex], [contenteditable="true"]):focus-visible {
  outline: 2px solid var(--text-ink); outline-offset: 2px;
}
/* …and ONE hover and ONE press for every control: THE HIGHLIGHT's washes inside its box, its shape by the control's own
   radius. Not a brightness filter: half of these are a glyph on nothing, which a filter cannot touch (Scars). `:where`, so a
   control that shades its own way wins on its own rule; GL JS's buttons wash by background-color (their focus owns box-shadow) */
:where(#toolbar button, #menu-btn, .mapboxgl-ctrl-scale, .ar-head button, .show,
       button.overlays-row, #overlays-list summary, .overlays-row button, .callout-x, .card-act, .rewind-play, .rewind-shut,
       .rewind-live, .nato-sw, .nato-chev, .nato-tog, #performance button,
       .cg-fold, .fancy-button, .draw-touch > button) {
  transition: box-shadow var(--tap);
  /* hover is a POINTER's state: a tap left the wash stuck until the next one */
  @media (hover: hover) {
    &:hover { box-shadow: inset 0 0 0 100vmax var(--highlight-hover); }
  }
  &:active { box-shadow: inset 0 0 0 100vmax var(--highlight-wash); }
}
#overlays-head h2 { font-size: inherit; font-weight: inherit; margin: 0; }
#skip-link {
  position: absolute; z-index: var(--z-banner); top: -100px; left: 20px;
  padding: 8px 12px; border-radius: var(--radius-m);
  color: var(--text-ink); text-decoration: none; /* its plate: the thick glass (index.html) */
}
#skip-link:focus-visible { top: 20px; }
/* the boot failure banner (app.js): the one failure a demo hits was a silent beige desk */
#map-error {
  position: absolute; z-index: var(--z-banner); top: 72px; left: 50%; transform: translateX(-50%); /* under the tool row, off the search pill */
  max-width: min(560px, calc(100% - 40px));
  padding: 8px 16px; border-radius: var(--radius-l);
  color: var(--text-danger); /* its plate: the thick glass (app.js) */
  font-weight: bold;
}
#map-error.ok { color: var(--text-ink); } /* news, not a fault: a link copied (shell/share/) */
/* THE TOUCH PAD (fleet/drive/touchpad.js): ONE STICK under the left thumb, ONE SLOT under the right, nothing over the road
   between. The ring rests in its corner until a thumb lands in the zone; pushed to the rim the car boosts, the man sprints. The
   slot is the key the stick cannot say (a handbrake, a gun's fire, a pistol and sights, the drone's climb), the driven kind's alone */
#drive-pad {
  position: absolute; z-index: var(--z-raised); left: 0; right: calc(var(--dock, 0px) / var(--ui)); bottom: 24px;
  display: flex; justify-content: space-between; align-items: flex-end; padding: 0 16px;
  pointer-events: none; /* only the stick's zone and the slot take the pointer */
  :is(.slot, .stick-zone) {
    pointer-events: auto; touch-action: none; -webkit-user-select: none; user-select: none; }
  :is(.slot, .stick) { color: var(--text-ink); } /* their plate: glass (touchpad.js) */
  .slot { display: flex; flex-direction: column; border-radius: var(--radius-full); overflow: hidden; }
  /* its own reset (the plate rule outranks the shared :where one); a half takes no pointer: the plate decides which half */
  .slot button { width: 64px; height: 64px; border: none; border-radius: 0; background: none; color: inherit;
                 display: grid; place-items: center; pointer-events: none; }
  /* the stick's zone: the left half, up to a thumb's reach; the ring's rest is its corner */
  .stick-zone { position: relative; width: 44%; height: 200px; }
  .stick {
    position: absolute; left: 70px; top: calc(100% - 70px); translate: -50% -50%;
    width: 124px; height: 124px; border-radius: 50%; pointer-events: none;
    opacity: .72; transition: opacity var(--fade); }
  .stick.on { opacity: 1; }
  .stick.sprint { border-color: var(--text-ink); box-shadow: 0 0 0 3px color-mix(in srgb, var(--time-fill) 55%, transparent); }
  .knob {
    position: absolute; inset: 0; margin: auto; width: 52px; height: 52px; border-radius: 50%;
    background: var(--text-ink); }
}

/* THE PERFORMANCE READOUT, bottom-left (shell/overlaysPanel/performance/), styled here so it follows the night swap: shut,
   one row (frame rate, repaints, worst frame) and a chevron, a rimless readout of the thick glass; open, a panel with its rim.
   Pointer off on the shut box and ON for the chevron alone, so it never eats a map drag from the corner */
#performance { position: absolute; bottom: 8px; left: 8px; z-index: 2; /* under the Overlays */ padding: 2px 8px;
           font: 12px/16px ui-monospace, Menlo, monospace; font-variant-numeric: tabular-nums;
           text-align: left; color: var(--text-ink); border-radius: var(--radius-l); pointer-events: none;
           transition: left var(--slide) var(--ease); /* its size and inset FOLD (performance.js, util/dom.js fold) */
  .top { display: flex; align-items: center; gap: 6px; }
  /* the row's text: the readout while shut, the drawer's title while open — one grid cell, crossfaded */
  .face { display: grid; flex: 1; }
  /* the readout and the title share a cell, never a moment: the leaver fades on --tap, the arrival waits (crossfaded they garbled) */
  .face > * { grid-area: 1 / 1; transition: opacity var(--tap) var(--ease) var(--tap); }
  &:not(.open) .title, &.open .rate { transition-delay: 0s; }
  .title { opacity: 0; font-weight: 600; }
  &.open .rate { opacity: 0; }
  &.open .title { opacity: 1; }
  /* a 24px HIT AREA round a 12px glyph; negative margins keep the row the text's height */
  button { pointer-events: auto; display: grid; place-items: center;
                    color: inherit; cursor: pointer; border-radius: 50%; /* a round wash under the pointer */
                    width: 24px; height: 24px; padding: 0; margin: -6px -6px -6px 0; }
  /* the chevron points where the box will go */
  button .icon { width: 12px; height: 12px; transform: rotate(180deg); transition: transform var(--slide) var(--ease); }
  &.open button .icon, .copy .icon { transform: none; } /* the copy glyph escapes the chevron's half-turn */
  /* OPEN: the drawer unfolds up (0fr → 1fr) and right (0 → 300px) on the panel's slide; .perf-drawer keeps its 300px, so a
     plot drawn mid-unfold is its real size, clipped. Open, it takes the pointer like the Overlays */
  &.open { z-index: 4; padding: 6px 8px 8px; pointer-events: auto; }
  .more { display: grid; grid-template-rows: 0fr; width: 0; opacity: 0; overflow: hidden; }
  /* folding shut (.morph) the drawer stays whole under the panel's closing edges: its own transitions drifted from the panel's */
  &:is(.open, .morph) .more { grid-template-rows: 1fr; width: 300px; opacity: 1; }
  &.morph { overflow: hidden; }
  /* minmax(0, …): a no-wrap line ellipsises rather than widen the box; a short viewport scrolls it clear of the tool row; its top
     padding comes in with the unfold (a 0fr row still holds padding) */
  .perf-drawer { display: grid; grid-template-columns: minmax(0, 1fr); gap: 12px; min-height: 0;
                    width: 300px; max-height: calc(100dvh - 180px); overflow-y: auto; padding-top: 0;
                    scrollbar-width: thin; scrollbar-color: var(--hud-fps-grid) transparent; }
  &:is(.open, .morph) .perf-drawer { padding-top: 8px; }
  /* open together on a wide screen the drawer steps out beside the Overlays: #map is its own stacking context, no z can lift it */
  @media (min-width: 720px) {
    body:has(#overlays:not(.shut)) &.open { left: calc(var(--sidew) + 20px); }
  }
  p { margin: 0; }
  .dim { opacity: .7; }
  /* a group per question: Smooth? · Cost · Loading · Where the time goes */
  section { display: grid; gap: 6px; }
  section + section { padding-top: 8px; border-top: 1px solid var(--hud-fps-grid); }
  h3 { display: flex; justify-content: space-between; margin: 0; font: inherit; font-weight: 600; opacity: .7; }
  h3 .note { font-weight: 400; }
  canvas { display: block; width: 100%; height: 16px; border-radius: var(--radius-s); background: var(--hud-fps-well); }
  canvas.plot { height: 56px; }
  canvas.strip { height: 20px; }
  canvas.bars { height: 28px; }
  .cap { display: flex; justify-content: space-between; gap: 8px; }
  /* the copy button rides the title row, open only */
  .copy { margin-right: 2px; }
  &:not(.open, .morph) .copy { display: none; }
  /* the three numbers the owner judges by, large, each with its state in a word */
  .hero, .load-plots { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
  .stat b { margin-right: 4px; font-size: 24px; line-height: 32px; font-weight: 600; }
  .state { display: flex; align-items: center; gap: 4px; min-width: 0; white-space: nowrap; }
  .state i { flex: none; width: 7px; height: 7px; border-radius: 50%; }
  .state i:not(.good, .warn, .bad) { display: none; }
  i.good { background: var(--text-on); }
  i.warn { background: var(--text-warn); }
  i.bad { background: var(--text-danger); }
  /* cost: CPU and GPU a column each, name, gauge toward the budget and reading, over their bars */
  .meters { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
  .gauge { display: grid; gap: 4px; }
  .gauge p { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 6px; align-items: center; }
  :is(.gauge, .ram) b { font-size: 14px; line-height: 20px; font-weight: 600; }
  b.over { color: var(--text-danger); }
  .track { display: block; height: 6px; margin-top: 2px; border-radius: var(--radius-s); overflow: hidden;
                    background: var(--hud-fps-well); }
  /* SCALED, NOT SIZED (performance.js writes scaleX): easing widths was 275 layouts a second with the drawer open */
  .track i { display: block; height: 100%; border-radius: var(--radius-s); transform-origin: 0 50%;
                      transition: transform var(--fade) var(--ease); }
  i.cpu { background: var(--hud-fps-cpu); }
  i.gpu { background: var(--hud-fps-gpu); }
  .track i.over { background: var(--text-danger); }
  /* the figures with a what-is-counted chip take the keyboard too */
  :is(.gauge, .ram) { border-radius: var(--radius-s); }
  :is(.gauge, .ram):focus-visible { outline: 2px solid var(--text-ink); outline-offset: 2px; }
  .ram { display: grid; gap: 2px; }
  .key { display: inline-flex; align-items: center; gap: 4px; margin-right: 8px; }
  .key i { width: 8px; height: 8px; border-radius: var(--radius-s); }
  /* RAM's title row: the name, its trend beside it, the reading pushed right; the caption is the legend */
  .ram p:first-child { display: flex; align-items: baseline; justify-content: flex-start; gap: 8px; }
  .ram b { margin-left: auto; }
  .ram .cap { justify-content: flex-start; white-space: nowrap; }
  .load-plot p { display: flex; justify-content: space-between; gap: 4px; margin-bottom: 2px; }
  .gauge .track { margin: 0; }
  /* where the time goes: the longest frame tinted by its state, then the top three tinted to their share of the first: the row is the chart */
  :is(.rank, .hitch) { position: relative; display: grid; grid-template-columns: minmax(0, 1fr) auto;
                                gap: 8px; align-items: center; padding: 2px 6px; border-radius: var(--radius-s); }
  .hitch { grid-template-columns: auto minmax(0, 1fr) auto; }
  .hitch.warn { background: color-mix(in srgb, var(--text-warn) 16%, transparent); }
  .hitch.bad { background: color-mix(in srgb, var(--text-danger) 14%, transparent); }
  .rank > i { position: absolute; inset: 0; border-radius: var(--radius-s); transform-origin: 0 50%;
                       background: color-mix(in srgb, var(--hud-fps-cpu) 22%, transparent);
                       transition: transform var(--fade) var(--ease); }
  .rank > span { position: relative; }
  .name .dim { margin-left: .6em; }
  :is(.name, .load-plot p span:last-child) {
    display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
}

/* the camera readout: ONE status line under the scale bar, bottom-right (Google Earth's place, the owner's pick), right-aligned
   and reaching left as far as it needs (at the column's top it ran under an open Rewind or search). A narrow map wraps it in the
   corner rather than under the Performance pill (~260 px, bottom-left) */
#map .mapboxgl-ctrl-bottom-right { max-width: calc(100% - 270px); }
.zoom-readout {
  padding-right: 4px; text-align: right;
  /* 10/12, under the floor on purpose: a glance, not text (its old 9's nearest step; 12 crowded the corner, the owner) */
  font: bold 10px/12px var(--font); font-variant-numeric: tabular-nums;
  color: var(--text-ink); text-shadow: 0 0 3px var(--surface-panel), 0 0 6px var(--surface-panel);
}
.dial-row { display: flex; align-items: center; gap: 6px; padding: 1px 0; font-size: 12px; line-height: 16px;
            accent-color: var(--line-highlight); } /* a switch dial's checkbox, ticked in THE HIGHLIGHT, not the UA's blue */
/* THE app's tooltip (theme/tooltip/), for the shell and the map's entities alike. Not `title=`: the native one is suppressed
   over a dragging range, cannot go dark with the basemap, and two looks is not a design. Over every floating control */
.tip { position: fixed; z-index: var(--z-pop); display: none; max-width: 280px; padding: 4px 8px;
       border-radius: var(--radius-m); color: var(--text-ink); /* its plate: the thick glass (tooltip.js) */
       font-size: 12px; line-height: 16px; pointer-events: none; }
/* THE KEY HINTS (parts/tracks/hint.js/): a cap and its verb over what the key acts on; only a pill that DOES something takes a tap */
.key-hints { position: absolute; inset: 0; overflow: hidden; pointer-events: none; z-index: 2; }
/* a cluster is the whole display (arview/cluster/cockpit.js): no chip over it. The keys still act */
body.cockpit .key-hint:not([data-globe]) { display: none; } /* the cluster says its own keys; a satellite's HUD has none, so its F pill (data-globe) stays */
/* the cockpit's exit: a frosted round X, top right, over the map and every face of I; gone with the mode */
#ck-exit { display: none; }
body.cockpit:not(.ck-leaving) #ck-exit {
  display: block; position: absolute; z-index: var(--z-banner); top: 16px; right: 16px;
  width: var(--thumb); height: var(--thumb); padding: 0; border-radius: 50%; /* the rim is .glass's own 2px, as the pill buttons' */
  color: var(--text-ink); cursor: pointer;
}
#ck-exit .icon { --i: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3.2' stroke-linecap='round'%3E%3Cpath d='M6 6l12 12M18 6 6 18'/%3E%3C/svg%3E"); }
.key-hint { position: absolute; left: 0; top: 0; display: flex; align-items: center; gap: 6px;
            margin: 0; padding: 0; color: var(--hud-key-text);
            font: inherit; font-size: 12px; font-weight: 700; line-height: 1; white-space: nowrap;
            text-shadow: 0 0 3px var(--hud-key-halo), 0 1px 2px var(--hud-key-halo); pointer-events: none;
            /* a pill arrives on a fade, not in one frame; it follows its anchor by transform, which is not eased */
            transition: opacity var(--fade); @starting-style { opacity: 0; } }
.key-hint[data-run] { pointer-events: auto; cursor: pointer; }
/* shell furniture in the map's px: its CONTENTS take the shell's zoom, never its box (a zoomed box's translate scales too) */
.key-hint > * { zoom: var(--ui); }
/* a KEYCAP as game prompts draw one, on no plate: a white face in a dark rim, a darker skirt, the legend on the face */
.key-caps { display: flex; gap: 2px; }
.key-wasd { display: grid; grid-template-columns: repeat(3, auto); }
.key-wasd kbd:nth-child(1) { grid-area: 1 / 2; }
.key-wasd kbd:nth-child(2) { grid-area: 2 / 1; }
.key-wasd kbd:nth-child(3) { grid-area: 2 / 2; }
.key-wasd kbd:nth-child(4) { grid-area: 2 / 3; }
/* W A S D with Q E under A S D (the owner): six half-columns, every cap spanning two */
.key-six { grid-template-columns: repeat(6, auto); }
.key-six kbd:nth-child(1) { grid-area: 1 / 3 / 2 / 5; } .key-six kbd:nth-child(2) { grid-area: 2 / 1 / 3 / 3; }
.key-six kbd:nth-child(3) { grid-area: 2 / 3 / 3 / 5; } .key-six kbd:nth-child(4) { grid-area: 2 / 5 / 3 / 7; }
.key-six kbd:nth-child(5) { grid-area: 3 / 2 / 4 / 4; } .key-six kbd:nth-child(6) { grid-area: 3 / 4 / 4 / 6; }
:is(.key-hint, .co-caps) kbd { box-sizing: border-box; min-width: 22px; height: 22px; padding: 0 4px 2px;
                display: inline-flex; align-items: center; justify-content: center;
                border: 1.5px solid var(--hud-key-rim); border-radius: var(--radius-s);
                background: var(--hud-key-face); color: var(--hud-key-rim); text-shadow: none;
                box-shadow: inset 0 -3px 0 color-mix(in srgb, var(--hud-key-face) 72%, var(--hud-key-rim)),
                            0 1px 3px var(--overlay-tip-shadow);
                font: inherit; font-size: 12px; font-weight: 700; line-height: 1; }
.key-wasd kbd { min-width: 18px; height: 18px; padding: 0 2px 2px; font-size: 12px; line-height: 16px;
                box-shadow: inset 0 -2px 0 color-mix(in srgb, var(--hud-key-face) 72%, var(--hud-key-rim)),
                            0 1px 3px var(--overlay-tip-shadow); }
.key-hint[data-run]:active kbd { padding-bottom: 1px; /* pressed: the face sinks onto the skirt */
                box-shadow: inset 0 -1px 0 color-mix(in srgb, var(--hud-key-face) 72%, var(--hud-key-rim)); }
.dial-name { flex: none; width: 108px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } /* the longest leaf whole (settings.test) */
.dial-num { flex: none; width: 62px; font: inherit; font-size: 12px; line-height: 16px; padding: 0 4px; } /* its rim: the panel's field (track lists) */
/* ONE thumb for every dial slider, single or paired: the UA's belongs to no design system, and two native tracks each filled
   from the left read one range as two broken sliders */
.dial-range { flex: 1; min-width: 40px; height: 14px;
              appearance: none; background: none; }
.dial-range::-webkit-slider-runnable-track { height: 4px; border-radius: var(--radius-full);
                                            background: var(--line-border); }
.dial-range::-webkit-slider-thumb { appearance: none;
  width: 12px; height: 12px; margin-top: -4px; border-radius: 50%;
  background: var(--text-ink); border: 1px solid var(--surface-card); cursor: pointer; }
/* the ring goes on the THUMB: an outline round a 100%-wide transparent input says nothing */
.dial-range:focus-visible { outline: none; }
.dial-range:focus-visible::-webkit-slider-thumb { box-shadow: 0 0 0 2px var(--text-ink); }

/* the chase shot from the side (settings/): an EXTRA view of two dials that keep their own sliders */
.dial-pad-row { padding: 4px 0; }
/* a field in the panel: the glass rim, no fill */
.dial-pad { width: 100%; max-width: 190px; height: auto; cursor: crosshair; touch-action: none;
            border: 2px solid var(--overlay-rim); border-radius: var(--radius-m); }
.dial-pad-ground { stroke: var(--line-border); stroke-width: 1; }
.dial-pad-car { fill: var(--text-faint); }
.dial-pad-ray { stroke: var(--line-strong); stroke-width: 1; stroke-dasharray: 3 2; }
.dial-pad-eye { fill: var(--text-ink); }
/* the steep half, where every degree of pitch drags the horizon's tile pyramid into frame */
.dial-pad-costly { fill: var(--text-faint); opacity: 0.13; }
.dial-reload { flex: none; width: 13px; height: 13px; margin: 0; color: var(--text-faint); }

/* ── THE PROMOTION BAR (parts/nato/nato.js): ONE pill, a question, a hairline and its four answers, in the map's container so it
   speaks map.project()'s pixels and nothing is centre-anchored (place() aligns the column). The liquid glass (theme/glass) with
   the card of names INSIDE it: one shape that grows down over the building and eases its radius. --nato-w steps up under a
   thumb (the coarse block) so four 44px frames leave the field room ── */
.nato-bar { position: absolute; z-index: var(--z-bar); width: calc(var(--nato-w, 340px) * var(--ui)); display: flex; flex-direction: column; }
.nato-pill { position: relative; border-radius: calc(48px / 2); overflow: hidden; /* half its row: it eases to xl as the list opens */ display: flex; flex-direction: column;
             transition: border-radius var(--slide) var(--ease), border-color var(--tap); }
.nato-pill:has(.nato-list:not(.folded)) { border-radius: var(--radius-xl); }
.nato-row { display: flex; align-items: center; gap: 8px; height: 48px; padding: 0 8px 0 16px; }
.nato-q { flex: 1; min-width: 0;
          font: 14px/1 var(--font); color: var(--text-ink); padding: 0;
          caret-color: var(--text-ink); }
.nato-q::placeholder { color: var(--text-meta); opacity: 1; }
/* the FOCUS RING IS THE PILL, as #searchbar's: a box inside a focused pill read as a second widget; it moves to the rim */
.nato-q:focus-visible { outline: none; } /* the pill's rim goes to ink instead: `.glass:focus-within` */
.nato-div { flex: none; width: 1px; height: 22px; background: var(--line-border); }

/* the four frames INSIDE the pill: gap, not a grid (four shapes a third apart in width; one square overflowed the widest). The
   armed one stands forward; NO MARK EVER TOUCHES A FRAME: a bar under an APP-6 symbol is its STATUS field */
.nato-swatches { display: flex; align-items: center; gap: 6px; flex: none; }
.nato-sw { flex: none; width: auto; height: 30px; padding: 0;
           cursor: pointer; display: grid; place-items: center; opacity: .58;
           transition: opacity var(--tap) var(--ease), transform var(--tap) var(--ease); }
.nato-sw[data-armed] { opacity: 1; transform: scale(1.12); }
.nato-sw img { display: block; height: 26px; width: auto; pointer-events: none; }

/* the amplifier drawer's handle, quiet at the row's end: the three amplifiers are for those who need them */
.nato-chev { flex: none; width: 26px; height: 26px; border-radius: var(--radius-m);
             cursor: pointer; color: var(--text-meta); display: grid;
             place-items: center; padding: 0; opacity: .5;
             transition: opacity var(--tap) var(--ease), color var(--tap) var(--ease), box-shadow var(--tap); }
.nato-chev .icon { flex: none; width: 16px; height: 16px;
                   transition: transform var(--slide) var(--ease); }
.nato-pill.expanded .nato-chev { opacity: 1; color: var(--text-ink); }
.nato-pill.expanded .nato-chev .icon { transform: rotate(180deg); }

/* the amplifier drawer (nato/), one row inside the pill, opening 0fr → 1fr to the height it really is (nato.js's transitionend
   keys on this property). `minmax(0, 0fr)`, not `0fr`: a bare fr track keeps an AUTO minimum, the row's padding, and stood 21px open */
.nato-amp { display: grid; grid-template-rows: minmax(0, 0fr); overflow: hidden;
            border-top: 0 solid var(--line-rule); visibility: hidden; /* folded, its four controls leave the Tab order (Scars) */
            transition: grid-template-rows var(--slide) var(--ease), visibility 0s var(--slide); }
.nato-pill.expanded .nato-amp { grid-template-rows: minmax(0, 1fr); border-top-width: 1px; visibility: visible;
                                transition: grid-template-rows var(--slide) var(--ease), visibility 0s; }
.nato-amp-row { min-height: 0; display: flex; align-items: center; gap: 6px; padding: 8px 12px 12px; }
.nato-amp select { flex: 1 1 0; min-width: 0; font: 12px/1 var(--font); color: var(--text-ink);
                   background: var(--overlay-glass); border: 2px solid var(--overlay-rim);
                   border-radius: var(--radius-m); padding: 6px 4px; cursor: pointer; }
/* HQ and Task force are the app's ARMED control, not a UA checkbox: on, they wear SELECTED's highlight */
.nato-tog { flex: none; font: 12px/1 var(--font); color: var(--text-ink); cursor: pointer;
            background: var(--overlay-glass); border: 2px solid var(--overlay-rim);
            border-radius: var(--radius-m); padding: 6px 8px;
            transition: background var(--tap) var(--ease), color var(--tap) var(--ease), box-shadow var(--tap); }

/* THE CARD OF NAMES, under the row and the drawer: the GRID, not display, folds it (so it animates); nato.js's `.folded` (and
   inert, out of the tab order at once) is "folded but laid out", never [hidden]. No symbol per row: the frames are in the pill,
   and 36 px symbols turned five names into a wall */
.nato-list { display: grid; grid-template-rows: minmax(0, 1fr); overflow: hidden; opacity: 1;
             transition: grid-template-rows var(--slide) var(--ease), opacity var(--fade); }
/* `visibility` takes the folded list out of the accessibility tree once the fold has played */
.nato-list.folded { grid-template-rows: minmax(0, 0fr); opacity: 0; visibility: hidden;
                    transition: grid-template-rows var(--slide) var(--ease), opacity var(--fade), visibility 0s var(--slide); }
/* 5.5 rows: the sixth peeking is the scroll affordance; place() lowers the cap when the place leaves less room */
.nato-hits { min-height: 0; overflow-y: auto; max-height: var(--nato-hits, 276px); overscroll-behavior: contain;
             scrollbar-width: thin; scrollbar-color: var(--line-strong) transparent; }
/* the rule over the first name is inset like the rows' own, and scrolls with them */
.nato-hits::before { content: ''; display: block; height: 1px; margin: 0 16px; background: var(--line-rule); }
/* BLOCK, not flex: a flex container's own text never ellipsises (2525D has a 120-character name) */
.nato-hit { position: relative; height: 46px; padding: 0 16px; cursor: pointer;
            font: 14px/44px var(--font); color: var(--text-ink);
            white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* the rule is INSET: a hairline into the rounded corner gives a stack of names away as a table */
.nato-hit::after { content: ''; position: absolute; left: 18px; right: 18px; bottom: 0;
                   height: 1px; background: var(--line-rule); }
.nato-hit:last-child::after { display: none; }
.nato-hit.cur { background: var(--highlight-wash); } /* the current row: the highlight's wash, day and night */
/* only on the rows that COLLIDE in this list — see render() */
.nato-hit i { font: 12px/1 var(--font); font-style: normal; color: var(--text-meta);
              margin-left: 6px; }
.nato-none { padding: 16px 16px; color: var(--text-meta); font-size: 12px; line-height: 16px; }

/* ── ONE PHONE BLOCK: the panes, the pill, the ⊕, the sheet, the strip, the pad and the promotion bar, one place to read, after
   the bar's base rules. THE SHAPE (the owner's sketch): the two pictures fill the screen edge to edge, the map over the AR pane
   (16:9 of the width) with 8 px of desk between, and the chrome clears them: one pill (shell/mapcontrols/phone.js), one ⊕ in
   the thumb corner, the Overlays a sheet, Rewind a strip, the stick and slot on the map. env(safe-area-inset-*) keeps controls
   off the notch and the home indicator; --homeb is the bottom inset only while the map's foot IS the screen's ── */
/* THE BOTTOM STRIP, a phone's and an upright tablet's (both blocks below): the cards a row along the foot, one snapped at a
   time, away DOWN */
@media (max-width: 560px), ((max-height: 560px) and (any-pointer: coarse)), (orientation: portrait) and (min-width: 561px) {
  #ar-cards { top: auto; width: auto; flex-direction: row; overflow-x: auto; overflow-y: hidden; scroll-snap-type: x mandatory;
              --away: translateY(calc(100% + 20px)); }
  .ar-frame.kept { touch-action: pan-x; }
}
/* THE PHONE: a phone's width, or its height under a thumb (on its side it is still a phone); phone.js asks the same query */
@media (max-width: 560px), ((max-height: 560px) and (any-pointer: coarse)) {
  /* the AR pane is 16:9 of the width (the pop-out's shape: one picture in the app and on the glasses) plus what the home
     indicator covers; the map takes the rest */
  body { --sheeth: calc(100vw * 9 / 16); --homeb: env(safe-area-inset-bottom, 0px); }
  body.cards {
    --dock: 0px;                             /* the map keeps its full width */
    --sheet: calc(var(--sheeth) + 8px + env(safe-area-inset-bottom, 0px)); /* the pane, which runs under the home indicator, + 8 px of desk */
    --homeb: 0px;                            /* the pane stands under the map's edge: nothing there to clear */
  }
  body.cards.nocard { --sheet: 0px; --homeb: env(safe-area-inset-bottom, 0px); } /* the picture put away (H, the pane's ✕ #phone-hide): the map takes its height back */
  /* the map and its loader: the screen less the pane, no frame, under the status bar and the home indicator */
  #map, #map + .loader { top: 0; left: 0; right: var(--dock, 0px); bottom: var(--sheet, 0px); border: 0; border-radius: 0; }
  /* the map's bottom edge (the scale bar, the readout) clears the home indicator by --homeb, and the notch on its side */
  #map .mapboxgl-ctrl-bottom-left, #map .mapboxgl-ctrl-bottom-right { bottom: var(--homeb, 0px); }
  #map .mapboxgl-ctrl-bottom-left { left: env(safe-area-inset-left, 0px); }
  #map .mapboxgl-ctrl-bottom-right { right: env(safe-area-inset-right, 0px); }
  #performance { bottom: calc(8px + var(--homeb, 0px)); left: calc(8px + env(safe-area-inset-left, 0px)); }
  /* the AR pane: a horizontal snap strip, the live card leftmost, each card the whole pane */
  #ar-cards {
    left: 0; right: 0;
    height: calc(var(--sheeth) + env(safe-area-inset-bottom, 0px)); /* the picture runs under the home indicator; its chrome lifts (.ar-head, .ar-minimap-box) */
    bottom: 0;
  }
  body.cards #ar-cards { transform: none; }
  .ar-card { position: relative; width: 100%; height: 100%; max-height: 100%; scroll-snap-align: start; align-self: stretch; }
  .ar-frame { flex: 1 1 auto; min-height: 0; aspect-ratio: auto; border: 0; border-radius: 0; }
  #ar-seam, body.cards #ar-seam { display: none; } /* upright the 8 px of desk is the gap, nothing to drag; on its side it is the handle (below) */
  /* the corners' gauges lift off the home indicator (the frame's foot is under it), the pod's minimap with them, and on its side
     the right one off the notch; the pill between them centres between them */
  .cluster.corners :is(.ck-gauge, .ar-cam) { translate: 0 calc(0px - env(safe-area-inset-bottom, 0px)); }
  .cluster.corners :is(.ck-rpm, .ar-cam), .cluster.corners.lens .ck-speed { translate: calc(0px - env(safe-area-inset-right, 0px)) calc(0px - env(safe-area-inset-bottom, 0px)); }
  /* THE STACK and the row's clock leave: the pill has ☰, search and locate, the sheet the clock and day/night, two
     fingers turn the map (no compass: the owner); the scale bar keeps the bottom-right under the ⊕, the readout the left */
  .mapboxgl-ctrl-top-right, #rewind-open { display: none; }
  .zoom-readout { display: none; } /* the corner is the ruler's and the ⊕'s */
  /* THE PILL over the map pane's top; its search box is the pill's middle (no capsule) and stays open */
  #phone-pill {
    position: fixed; z-index: var(--z-float); top: calc(22px + env(safe-area-inset-top, 0px));
    left: calc(22px + env(safe-area-inset-left, 0px)); right: calc(22px + env(safe-area-inset-right, 0px));
    height: 48px; align-items: center; padding: 0 2px;
    overflow: visible; /* the pill class clips to its capsule — and clipped the search list hanging under it */ }
  /* the suggestions hang under the WHOLE pill, so the field and capsule stop anchoring them; the magnifier joins the flow or it lands on the ☰ */
  #phone-pill :is(#searchbar, .search-box) { position: static; }
  #phone-pill .search-box { display: flex; align-items: center; }
  #phone-pill .search-box > .icon { position: static; margin: 0 0 0 12px; flex: none; }
  /* a native feel under a thumb: no grey tap flash, no double-tap-to-zoom wait */
  :is(#phone-pill, #phone-plus, #phone-dots, #toolbar, #overlays, #drive-pad, .ar-head, .rewind-bar) :is(button, summary, a, input), #phone-plus, .key-hint[data-run] {
    -webkit-tap-highlight-color: transparent; }
  :is(#phone-pill, #phone-plus, #phone-dots, #toolbar, #overlays, .ar-head, .rewind-bar) :is(button, summary, a), #phone-plus, .key-hint[data-run] {
    touch-action: manipulation; }
  /* flex: none — the search box's intrinsic width shrank its neighbours to 43px; one inset divider on the left, none on the first */
  #phone-pill > button { flex: none; width: var(--thumb); height: var(--thumb); border-width: 0 0 0 1px; background: none; color: inherit; position: relative; }
  #phone-pill > :first-child { border-left: 0; }
  #phone-pill #searchbar { flex: 1 1 auto; min-width: 0; height: var(--thumb); }
  /* NO PLATE where a plate stands in a plate or each child is its own: the pill's search box, the fan's column, the vehicle's */
  :is(#phone-pill .search-box, #toolbar .seg, #vehicle-bar) { background: none; border: 0; box-shadow: none; -webkit-backdrop-filter: none; backdrop-filter: none; }
  #phone-pill .search-box, #phone-pill .search-box:focus-within { height: var(--thumb); border-radius: 0; }
  #phone-pill #searchbar input, #phone-pill #searchbar:not(:focus-within) input { font-size: 16px; line-height: 24px; padding: 0 8px; height: var(--thumb); min-width: 0; }
  #phone-pill #searchbar:not(:focus-within) .search-box > .icon { color: var(--text-meta); }
  #phone-menu.warn::after { content: ''; position: absolute; top: 4px; right: 4px; width: 8px; height: 8px; border-radius: 50%; background: var(--text-danger); }
  /* with a track up the middle is its name and speed, and locate becomes ✕ */
  #phone-pill[data-track] :is(#searchbar, #phone-locate, #phone-compass), #phone-pill:not([data-track]) :is(.phone-track, #phone-close) { display: none; }
  #phone-compass .icon { rotate: var(--north, 0deg); } /* phone.js writes --north off the map's bearing */
  /* the track line is a BUTTON (phone.js): with the picture put away a tap brings it back, its chevron pointing up */
  #phone-pill > .phone-track { flex: 1 1 auto; width: auto; min-width: 0; height: var(--thumb); display: flex; align-items: center; gap: 8px;
                 padding: 0 0 0 8px; border: 0; border-radius: 0; background: none; color: inherit; cursor: pointer; text-align: left;
                 font: inherit; font-size: 16px; line-height: 24px; font-weight: 700; white-space: nowrap; overflow: hidden;
                 font-variant-numeric: tabular-nums; }
  .phone-track::before { content: ''; flex: none; width: 9px; height: 9px; border-radius: 50%; background: var(--text-danger); }
  .phone-track .phone-name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
  .phone-track .icon { display: none; flex: none; width: 20px; height: 20px; margin-right: 8px; rotate: 180deg; }
  body.nocard .phone-track .icon { display: block; }
  /* THE STRIP'S DOTS (phone.js) over the pane's top-left, under the heading band: a 44px target round each 8px dot */
  #phone-dots { position: fixed; z-index: var(--z-float); left: 18px; display: flex;
                bottom: calc(env(safe-area-inset-bottom, 0px) + var(--sheeth) - 80px); }
  #phone-dots button { width: 28px; height: var(--thumb); padding: 0; display: grid; place-items: center; cursor: pointer; } /* a dot's target, not a circle */
  #phone-dots button::before { content: ''; width: 9px; height: 9px; border-radius: 50%; background: var(--overlay-glass);
                               border: 2px solid var(--overlay-rim); box-shadow: var(--glass-shadow); } /* a ::before: the glass by its two values */
  #phone-dots button.on::before { background: var(--text-ink); border-color: var(--text-ink); }
  body.nocard #phone-dots { display: none; }
  /* THE PANE'S ✕ (#phone-hide): H — the picture slides away, the drive goes on, the pill's name brings it back; gone with no
     card, the picture away, or mirror mode (the pill's ✕ is the way back there) */
  #phone-hide { position: fixed; z-index: var(--z-float); right: 20px; bottom: calc(env(safe-area-inset-bottom, 0px) + var(--sheeth) - 82px); /* 82: under the heading band, whose NE it covered at 54 */
                width: var(--thumb); height: var(--thumb); color: var(--text-ink); /* its plate: glass (phone.js) */ }
  #phone-hide .icon { width: 20px; height: 20px; }
  body:not(.cards) #phone-hide, body.nocard #phone-hide, body.mirror #phone-hide { display: none; }
  /* THE COCKPIT'S ✕ (a satellite's HUD, the one cockpit a thumb reaches): the pill is off with the rest of the shell, so this is the way out —
     at the right edge's middle, under the thumb and clear of the four corner widgets and the compass marks, upright and on its side */
  body.cockpit:not(.ck-leaving) #ck-exit { top: 50%; translate: 0 -50%; right: calc(16px + env(safe-area-inset-right, 0px)); }
  /* QUIET (phone.js): a few touchless seconds into a drive the chrome whispers and any touch wakes it at once (no transition
     back); the stick, the Exit chip and the pictures keep their ink */
  body.quiet :is(#phone-pill, #phone-hide, #phone-dots, .mapboxgl-ctrl-scale, .ar-head, #performance:not(.open)) {
    opacity: .3; transition: opacity var(--fade); }
  /* THE READOUT (performance/) keeps the bottom-left under the stick's zone: its whole row is the tap, 44 tall by a ::before
     so the box stays the desk's (the chevron is a mouse target) */
  #performance .top { position: relative; pointer-events: auto; }
  #performance:not(.open) .top::before { content: ''; position: absolute; inset: -12px -8px; }
  /* the drawer stays INSIDE the map pane: the desk's 100dvh − 180 ran its title row under the pill */
  #performance .perf-drawer { max-height: calc(100dvh - var(--sheet, 0px) - 200px); }
  /* THE ⊕ in the thumb corner over the scale bar; it leaves with a track up (the picture's chrome is enough) */
  #phone-plus {
    position: fixed; z-index: var(--z-float); right: calc(20px + env(safe-area-inset-right, 0px)); bottom: calc(64px + env(safe-area-inset-bottom, 0px)); /* 64: at 56 it sat 6 px into the ruler; the inset: the notch, on its side */
    width: 56px; height: 56px; color: var(--text-ink); } /* its plate: glass (phone.js) */
  #phone-plus .icon { width: 24px; height: 24px; }
  body.cards #phone-plus { display: none; }
  /* …but a DRIVABLE one keeps it, over the picture: its fan holds the nav tool, a touch screen's only way to waypoints
     (placing.js marks body.drivable). Not while chased (the pad's slot stands beside it) unless the tool is armed */
  :is(body.cards.drivable:not(.chase), body.cards[data-mode="nav"]) #phone-plus {
    display: grid; bottom: calc(var(--sheet, 0px) + var(--homeb, 0px) + 64px); }
  body.cards.drivable #toolbar { bottom: calc(var(--sheet, 0px) + var(--homeb, 0px) + 128px); }
  /* the tool row IS the fan: a column of named circles over the open ⊕; an armed one wears SELECTED's capsule, not the desk's
     sliding pick, which is a row's and banded the whole column (Scars) */
  #toolbar { position: fixed; z-index: var(--z-float); top: auto; left: auto; right: calc(24px + env(safe-area-inset-right, 0px)); bottom: calc(128px + env(safe-area-inset-bottom, 0px));
             width: auto; flex-direction: column; align-items: flex-end; container-type: normal; }
  body:not(.tools) #toolbar { display: none; }
  /* the fan's names and the sheet's rise stand the others down: the key chips under the fan (its Drive chip read through
     their glass), the fan, the pad and the ⊕ under the sheet, the pad and the ⊕ under the Performance drawer (the ⊕ stood over its rows' right edge) */
  body.tools .key-hints, body:has(#overlays:not(.shut)) :is(#toolbar, #drive-pad, #phone-plus), body:has(#performance.open) :is(#toolbar, #drive-pad, #phone-plus) { visibility: hidden; }
  #toolbar .seg-pick { display: none; }
  #toolbar .seg { flex-direction: column-reverse; align-items: flex-end; gap: 12px; overflow: visible; } /* no plate: each circle is its own glass; flush right, or the place fan's open width dragged every circle left */
  #toolbar .seg > button, #vehicle-bar > button { width: 48px; height: 48px; border-radius: 50%; position: relative; } /* its plate: .glass's list */
  /* the place fan is the column's top circle; fanned, its inner pill grows to the LEFT (the column hugs the right edge), the
     worn tool at the right where the circle was */
  #toolbar .place-fan { width: 48px; height: 48px; border-radius: var(--radius-full); --slot: -44px; --fan-w: 228px;
    &:has(> [aria-expanded="true"]) { width: var(--fan-w); } }
  #toolbar .place-fan > .place-lead { width: 44px; height: 44px; }
  #toolbar .place-fan > .place { left: auto; right: 6px; top: 6px; width: 36px; }
  #toolbar .place-fan > .place::before { content: ''; position: absolute; inset: -6px -4px; } /* 44 to a thumb, the 36 px circles unchanged */
  /* touch has no hover to name a circle, and two of the five are cars side on: open, each says its name over itself, in the
     map's ink with its halo, no plate — five words a slot apart (the owner's pick D, 2026-11-04) */
  #toolbar .place-fan > .place::after { content: attr(data-name); position: absolute; bottom: calc(100% + 10px); left: 50%;
    translate: -50% 0; white-space: nowrap; pointer-events: none; color: var(--text-ink); font: 600 12px/1 var(--font);
    text-shadow: 0 0 3px var(--surface-panel), 0 0 6px var(--surface-panel); }
  /* THE SELECTED VEHICLE'S BAR (phone.js puts the slot on <body>): a column of circles over the ⊕, nav nearest the thumb,
     out of the way while the fan stands there */
  #vehicle-slot { position: fixed; z-index: var(--z-float); right: calc(24px + env(safe-area-inset-right, 0px)); margin: 0; width: auto; transition: none;
    bottom: calc(var(--sheet, 0px) + var(--homeb, 0px) + 128px); } /* the inset is in --homeb or --sheet already, as #toolbar's */
  body.tools #vehicle-slot { display: none; }
  #vehicle-bar { flex-direction: column-reverse; gap: 12px; overflow: visible; transform-origin: 50% 100%; }
  #vehicle-bar #nav-btn { width: 48px; padding: 0; } /* a circle: its said step is the tip, not words inside (two ids: over [data-say]) */
  #vehicle-bar #nav-btn > .say { display: none; }
  #vehicle-bar #nav-btn > .icon { margin: auto; }
  #toolbar :is(.seg > button, .place-lead)::after {
    content: attr(aria-label); position: absolute; right: 58px; top: 50%; translate: 0 -50%; white-space: nowrap;
    padding: 6px 8px; border-radius: var(--radius-m); color: var(--text-ink); font: 600 14px/1 var(--font); } /* its plate: .glass's list, thick, a readout */
  /* THE SHEET: the Overlays rises from the bottom, half the screen, a grabber at its head; shut it is nothing (the pill's ☰ opens it) */
  #overlays { top: auto; left: 0; right: 0; bottom: 0; width: auto; --sidew: 100vw; max-height: 56dvh;
             z-index: var(--z-sheet); /* over the AR pane (3), the pad and the ⊕ (5): a sheet is the top of the stack */
             border-radius: var(--radius-xl) var(--radius-xl) 0 0; box-shadow: 0 -6px 24px var(--overlay-shadow);
             padding-bottom: env(safe-area-inset-bottom, 0px); }
  #overlays.shut { display: none; }
  /* TWO SNAP HEIGHTS (phone.js): half, or full to 16px under the pill; the step eases and follows the thumb, `translate` too, or a
     pull let go short of the snap jumped back */
  #overlays { transition: max-height var(--slide) var(--ease), translate var(--slide) var(--ease); }
  #overlays.full { max-height: calc(100dvh - 86px - env(safe-area-inset-top, 0px)); }
  #overlays.dragging { transition: none; }
  #overlays-box { width: auto; }
  /* the head stands OUTSIDE the scrolling box (phone.js moves it): grabber and ☰ stay under the thumb, the pull is the head's */
  /* its 12 px over the buttons is PADDING, not margin: the grabber is drawn there, and a margin is no part of the head — the
     painted grabber took no pull, and with the ? beside day/night the head's middle is a button (2026-11-02) */
  #overlays-head { margin: 0; padding: 12px 12px 0; touch-action: none; } /* the box's side inset: the ☰ over the rows */
  /* iOS zooms on focusing a field under 16px and stays zoomed until a pinch */
  [contenteditable="true"] { font-size: 16px; line-height: 24px; } /* not [contenteditable="false"]: a renamed row goes back to false and must size down again */
  /* the pane takes no gestures, so a pinch on it was the page's zoom; pan-x keeps the strip's swipe */
  #ar-cards { touch-action: pan-x; }
  #overlays-head::before { content: ''; position: absolute; top: 8px; left: 50%; translate: -50% 0; width: 36px; height: 5px;
                        border-radius: var(--radius-full); background: color-mix(in srgb, var(--text-ink) 22%, transparent); }
  #phone-help, #phone-light, #phone-share, #phone-full { width: var(--thumb); height: var(--thumb); color: inherit; }
  #overlays-head > button { flex: none; } /* a narrow head shortens its title, never a thumb's target */
  #overlays-head h2 { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  #phone-help { margin-left: auto; } /* help, day/night, then full screen (phone.js builds it where the browser has one), at the head's right */
  #phone-tm { display: flex; align-items: center; gap: 8px; width: 100%; height: 52px; margin-bottom: 4px; padding: 0 6px;
              border: 0; border-top: 1px solid var(--line-rule); border-bottom: 1px solid var(--line-rule);
              background: none; color: inherit; font: inherit; font-size: 16px; line-height: 24px; font-weight: 600; cursor: pointer; }
  #phone-tm .icon { width: 16px; height: 16px; margin: 0; }
  #phone-tm small { margin-left: auto; font-size: 12px; line-height: 16px; font-weight: 400; color: var(--text-meta); }
  /* THE STRIP: Rewind's bar on the bottom edge, its row on its own line (the desk's row-container rules miss it: it hangs off <body>) */
  body.phone #rewind .rewind-bar {
    position: fixed; z-index: 6; left: 0; right: 0; bottom: 0; height: auto; border-radius: var(--radius-xl) var(--radius-xl) 0 0;
    padding: 12px calc(16px + env(safe-area-inset-right, 0px)) calc(12px + env(safe-area-inset-bottom, 0px)) calc(16px + env(safe-area-inset-left, 0px)); flex-wrap: wrap; row-gap: 8px;
    animation: none; } /* its plate: the glass it wears on the desk */
  /* with a card up it floats over the map's foot, above the pane, so the picture it scrubs stays in view */
  body.phone.cards #rewind .rewind-bar { bottom: calc(var(--sheet, 0px) + 10px); left: 10px; right: 10px; border-radius: var(--radius-xl); padding-bottom: 12px; }
  body.phone #rewind .rewind-row { flex: 1 1 100%; order: -1; }
  body.phone #rewind .rewind-shut { margin-left: auto; }
  /* the strip stands where the ⊕, its fan, the vehicle's column and the map's corners stand: they rise over it by its height and
     8 px (10 more with a card up, where it floats over the pane). shortcut: --strip is the strip's measured height (the row 34,
     8, the live chip 44, padding 24, the rim 4); a strip that grows a line needs it re-measured */
  body { --strip: 114px; }
  body:has(#rewind .rewind-bar:not([hidden])) { --lift: calc(var(--strip) + 8px); }
  body.cards:has(#rewind .rewind-bar:not([hidden])) { --lift: calc(var(--strip) + 18px); }
  :is(#phone-plus, #toolbar, #vehicle-slot, #performance, #map .mapboxgl-ctrl-bottom-right, #map .mapboxgl-ctrl-bottom-left) {
    translate: 0 calc(-1 * var(--lift, 0px)); }
  /* THE PAD rides the MAP (the owner): the stick's zone lower-left over the readout, 140px wide so the F · Exit chip under a
     centred car is never its; the slot (a pistol, the drone's plate) lower-right beside the ⊕'s column. Its box IS the map's */
  #drive-pad { position: fixed; z-index: var(--z-float); display: block; padding: 0; height: auto;
               left: env(safe-area-inset-left, 0px); right: env(safe-area-inset-right, 0px); top: 0;
               bottom: calc(var(--sheet, 0px) + var(--homeb, 0px));
               transition: bottom var(--slide) var(--ease); }
  #drive-pad .stick-zone { position: absolute; left: 0; bottom: 40px; width: 140px; height: min(300px, 55%); }
  #drive-pad .stick { left: 80px; top: calc(100% - 100px); }
  /* 88: left of the ⊕ and the vehicle's column (76 px), never under them (Scars) */
  #drive-pad .slot { position: absolute; right: 88px; bottom: 56px; }
  /* a keycap means nothing to a thumb (parts/tracks/hint.js): a hint that RUNS something is a chip of its word, the rest go */
  .key-hint:not([data-run]) { display: none; }
  .key-hint[data-run] { height: var(--thumb); padding: 0 16px; border-radius: var(--radius-full); font-size: 14px; line-height: 20px; text-shadow: none; color: var(--text-ink); } /* a chip here, a cap on the desk: its plate .glass's list */
  .key-hint[data-run] .key-caps { display: none; }
  /* the promotion bar is a bottom SHEET stacking upward: no room beside a place on a phone. place() writes no inline left/top here */
  .nato-bar { position: fixed; left: 0; right: 0; bottom: calc(var(--sheet, 0px) + var(--homeb, 0px)); top: auto; width: auto; /* above the AR sheet, off the home indicator */
    flex-direction: column-reverse; padding: 0 8px 8px;
    filter: drop-shadow(0 -6px 24px var(--overlay-shadow)); }
  /* …and a sheet covers what is under it: the fps readout, the scale and the ⊕ stood through its glass and over its hits
     (the owner's sweep, 2026-11-01, once the readout was back on every page) — they step aside while it is up */
  body:has(.nato-bar) :is(#performance, .mapboxgl-ctrl-scale, #phone-plus) { visibility: hidden; }
  .nato-pill { flex-direction: column-reverse; } /* the names over the drawer over the row: the thumb's row stays at the foot */
  .nato-row { height: 52px; }
  .nato-hits { max-height: 40vh; }
  /* ON ITS SIDE the pane stands BESIDE the map, half the width each (a 45dvh pane under a 390px map is two letterboxes); the
     8 px seam is the HANDLE (260 px to 60 %), the pill and the pad keep the map's half, the sheet rises higher */
  @media (orientation: landscape) {
    body { --fw: calc(50vw - 4px); --homeb: env(safe-area-inset-bottom, 0px); } /* the pane's width: half, less half the seam; the map's foot is the screen's */
    body.cards { --dock: calc(var(--fw) + 8px); --sheet: 0px; --homeb: env(safe-area-inset-bottom, 0px); }
    #ar-cards {
      top: 0; bottom: 0; left: auto; right: 0; width: var(--fw); height: auto;
      /* away is still DOWN: parked off the right edge it widened the page, and a phone's layout viewport grew to 1261 px */
    }
    /* body.cards and margin: 0, or the later coarse block's thumb seam wins on order (the line 0 px wide, the box over the picture) */
    body.cards #ar-seam { display: block; top: 0; bottom: 0; right: var(--fw); width: 8px; margin: 0; }
    body.cards #ar-seam::after { inset: 0 3px; } /* the desk's 2 px line, centred in the 8 */
    #ar-seam::before { content: ''; position: absolute; inset: 0 -18px; } /* a thumb's 44 px over an 8 px bar */
    body.cards #phone-pill { right: calc(var(--dock) + 22px); } /* the map's half */
    /* …the ⊕ and its fan too, off the picture; --dock is 0 with the picture away, so they go back to the edge */
    body.cards #phone-plus { right: calc(var(--dock) + 20px); }
    body.cards #toolbar { right: calc(var(--dock) + 24px); }
    body.cards #vehicle-slot { right: calc(var(--dock) + 24px); } /* its column over the ⊕, not over the picture */
    #toolbar { z-index: 6; }
    /* …and five tools at 48 + 12 are 288 px, past the top of a 390 px screen: Drop a soldier stood at −26 (the satellite map
       made five, 2026-10-31). The thumb's 44 and a 4 px gap, and past the room under the pill (its foot at 70 px, and 4) a
       second column to the left, as the vehicle's: one column of 236 stood over the pill's locate and compass (2026-11-04) */
    #toolbar .seg { gap: 4px; flex-wrap: wrap-reverse;
      max-height: calc(100dvh - 202px - env(safe-area-inset-top, 0px) - var(--homeb, 0px) - var(--lift, 0px)); }
    /* …two columns leave no room for the circles' names (one ran under the other column's): the fan names its own; and the
       fan's circle the thumb's 44 as its column's (it stood 48, its top 4 px off theirs) */
    #toolbar :is(.seg > button, .place-lead)::after { content: none; }
    #toolbar .place-fan { height: var(--thumb); &:not(:has(> [aria-expanded="true"])) { width: var(--thumb); } }
    #toolbar .place-fan > .place { top: 4px; }
    #toolbar .seg > button { width: var(--thumb); height: var(--thumb); }
    /* …and the vehicle's column, which stands for as long as a vehicle is picked: four circles at 48 + 12 rose to 34 px, over
       the pill's ✕ (the mic took the tap meant to let the track go, Scars) → the thumb's 44, 4 apart, and past the room under
       the pill (its foot at 70 px, and 4) a second column to the left */
    #vehicle-bar { gap: 4px; flex-wrap: wrap-reverse;
      max-height: calc(100dvh - 202px - env(safe-area-inset-top, 0px) - var(--homeb, 0px) - var(--lift, 0px)); }
    #vehicle-bar > button, #vehicle-bar #nav-btn { width: var(--thumb); height: var(--thumb); }
    #phone-dots { left: calc(100vw - var(--fw) + 18px); bottom: auto; top: calc(46px + env(safe-area-inset-top, 0px)); }
    body.cards:not(.nocard) #drive-pad { right: var(--dock); } /* the map's half */
    #phone-hide { bottom: auto; top: calc(38px + env(safe-area-inset-top, 0px)); right: calc(20px + env(safe-area-inset-right, 0px)); } /* 38: under the heading band, as upright (at 20 it sat on its NE), 12 px over the vehicle's column */
    /* the SHEET is a SIDE PANEL (ATAK's drawer): a bottom sheet in 390 px showed two rows. Its pull is LEFT (phone.js), no grabber */
    #overlays, #overlays.full { top: 0; bottom: 0; left: 0; right: auto; --sidew: min(360px, 50vw); width: calc(var(--sidew) + env(safe-area-inset-left, 0px)); max-height: none; /* the notch's inset is padding ON TOP of the panel's width */
      border-radius: 0 var(--radius-xl) var(--radius-xl) 0; box-shadow: 6px 0 24px var(--overlay-shadow);
      padding: env(safe-area-inset-top, 0px) 0 env(safe-area-inset-bottom, 0px) env(safe-area-inset-left, 0px); }
    #overlays-head::before { display: none; }
    body.phone.cards #rewind .rewind-bar { right: calc(var(--dock) + 10px); } /* the map's half (the phone block's own specificity): it spanned both and lay over the pane's foot, the stick zone */
  }
}

/* ── A CARD'S HEAD ON A PHONE AND IN MIRROR MODE: its pill alone in the picture's BOTTOM-right (where the handbrake stood): the
   glasses, then the background map and the forward/ground view when the card has them. The name and ✕ are the phone pill's, the
   picture's ✕ is #phone-hide's, the rest the desk's. body.mirror too: on its side a phone leaves the width query, and in mirror
   mode this pill is the way back (top-right there, under the band) ── */
body:is(.phone, .mirror) .ar-head { position: absolute; z-index: 3; right: calc(12px + env(safe-area-inset-right, 0px)); top: auto;
  bottom: calc(12px + env(safe-area-inset-bottom, 0px)); /* the picture's foot is under the home indicator on a phone */ margin: 0; min-height: 0;
  container-type: normal; } /* floated, an inline-size container is 0 wide: the pill hung off its edge, not centred (Scars) */
body:is(.phone, .mirror) .ar-head :is(.ar-label, .ar-info, .ar-close, .ar-minimap, .ar-sight, .ar-keep) { display: none; }
/* …a car's card has gauges in both bottom corners (`corners`), so its pill stands between them */
body:is(.phone, .mirror) .ar-card:has(.cluster:not(.bare)) .ar-head { right: calc(50% + env(safe-area-inset-right, 0px) / 2); translate: 50% 0; }

/* ── MIRROR MODE (card/popout.js mirror(), a phone or tablet): the live card's picture IS the screen, as USB-C glasses show it.
   The map and the ⊕ stand down; the pill drops between the thumbs and fades until touched, the stick and slot alike ── */
body.mirror :is(#map, #phone-plus, #phone-dots, #toolbar, #performance, .mapboxgl-control-container) { visibility: hidden; }
body.mirror #ar-cards { position: fixed; inset: 0; width: auto; height: auto; z-index: 8; transform: none; visibility: visible; overflow: hidden; }
body.mirror .ar-card { position: relative; width: 100%; height: 100%; max-height: 100%; margin: 0; }
body.mirror .ar-card:not(.mirrored) { display: none; } /* the card whose glasses button was pressed (popout.js mirror), not the column's first */
body.mirror .ar-frame { flex: 1 1 auto; min-height: 0; aspect-ratio: auto; border: 0; border-radius: 0; }
body.mirror .ar-head { position: absolute; z-index: 3; right: calc(12px + env(safe-area-inset-right, 0px)); top: calc(48px + env(safe-area-inset-top, 0px)); bottom: auto; }
body.mirror #phone-pill { z-index: 9; top: auto; bottom: calc(22px + env(safe-area-inset-bottom, 0px)); left: 50%; right: auto; width: min(360px, 92vw);
                          translate: -50% 0; opacity: .3; transition: opacity var(--fade) var(--wake); }
body.mirror #drive-pad { position: fixed; z-index: 9; display: block; top: auto; height: 300px; padding: 0;
                         left: calc(10px + env(safe-area-inset-left, 0px)); right: calc(10px + env(safe-area-inset-right, 0px));
                         bottom: calc(8px + env(safe-area-inset-bottom, 0px));
                         width: auto; } /* width: auto — the sideways block's half-width pad is not this one */
/* sideways the disc grows with the frame: the zone reaches past it and the ring rests to its right, clear of the pill */
body.mirror #drive-pad .stick-zone { position: absolute; left: 0; bottom: 0; width: 440px; height: 300px; }
body.mirror #drive-pad .stick { left: 350px; top: calc(100% - 150px); }
body.mirror #drive-pad .slot { position: absolute; right: 12px; bottom: 30px; }
body.mirror :is(#drive-pad .stick:not(.on), #drive-pad .slot, .ar-head) { opacity: .3; transition: opacity var(--fade) var(--wake); }
body.mirror :is(#phone-pill, .ar-head):is(:hover, :focus-within, :active), body.mirror #drive-pad .slot:active { opacity: 1; transition: none; }
/* the picture IS the screen: its gauges lift off the home indicator and each off its own side's notch; the head stays centred */
body.mirror .cluster.corners .ck-speed { translate: env(safe-area-inset-left, 0px) calc(0px - env(safe-area-inset-bottom, 0px)); }
body.mirror .cluster.corners :is(.ck-rpm, .ar-cam), body.mirror .cluster.corners.lens .ck-speed {
  translate: calc(0px - env(safe-area-inset-right, 0px)) calc(0px - env(safe-area-inset-bottom, 0px)); }
body.mirror .ar-card:has(.cluster:not(.bare)) .ar-head { right: 50%; }
/* an iPhone's Safari has no element full screen and no orientation lock (WebKit, won't fix): the glasses mirror it upright, a
   strip down their middle, and the page can only say so until the phone is turned */
@media (orientation: portrait) {
  /* upright: the pill under the hint, off the minimap disc; the card's own pill under that, clear of the band */
  body.mirror #phone-pill { top: calc(108px + env(safe-area-inset-top, 0px)); bottom: auto; }
  body.mirror .ar-head { top: calc(168px + env(safe-area-inset-top, 0px)); } /* under the pill: upright, the band is three times its size */
  body.mirror::after {
    content: 'Turn the phone sideways'; position: fixed; z-index: 9; top: calc(60px + env(safe-area-inset-top, 0px)); left: 50%; translate: -50% 0;
    padding: 8px 12px; border-radius: var(--radius-full); color: var(--text-ink); /* its plate: .glass's list, a readout */
    font: 600 14px/1 var(--font); white-space: nowrap; }
}

/* ── UPRIGHT AND WIDER THAN A PHONE (an iPad upright, a monitor on its side): the cards dock along the BOTTOM, a row the map's
   width at most 45 % of the height, as the phone's sheet — the right column left ~750 px bare under one card beside a 410 px map.
   The landing pans the map by what its bottom gave (arview.js land, keepInSight) ── */
@media (orientation: portrait) and (min-width: 561px) {
  body.cards { --dock: 0px; --sheet: calc(min(45dvh, calc((100vw - 20px) / 1.5 + var(--chrome-h) + 8px)) + env(safe-area-inset-bottom, 0px));
               --dockh: calc((var(--sheet) - 8px - env(safe-area-inset-bottom, 0px)) / var(--ui)); } /* the sheet counts the home indicator, the card does not */
  body.cards.nocard { --sheet: 0px; }
  #map { bottom: calc(10px + var(--sheet, 0px)); }
  #map + .loader { bottom: calc(10px + var(--sheet, 0px)); }
  #ar-cards { left: 10px; height: calc(var(--sheet, 0px) - 8px - env(safe-area-inset-bottom, 0px)); justify-content: safe flex-end; } /* safe: an overflow at the START is past any scroll (the live card lost) */
  #ar-cards > .ar-card { scroll-snap-align: end; }
  body.cards #ar-seam { display: none; }
}

/* ── REWIND (shell/overlaysPanel/rewind.js/): a circle in the tool row until opened. `display: contents` makes the button
   and the bar the ROW's items: on a wide row the bar takes the circle's place and the slack, the search the rest; on a
   narrow one (the container block below) the circle stays pressed and the bar takes the line under ── */
#rewind { display: contents;
  /* one of the row's circles: never squeezed by the pill beside it */
  .rewind-open { flex: none; }
  .rewind-bar { height: var(--thumb); border-radius: var(--radius-full); color: var(--text-ink); /* its plate: glass (rewind.js) */
    flex: 1; display: flex; align-items: center; gap: 8px; padding: 0 6px 0 6px; } /* no min-width: too short for its controls it wraps */
  .rewind-open:disabled { opacity: .45; cursor: not-allowed; }
  /* the track and the record's shape share one box: the band is the thing scrubbed */
  .rewind-row { position: relative; flex: 1; min-width: 80px; height: 26px; }
  /* the instant under the pointer, before committing to it */
  .rewind-tip {
    position: absolute; bottom: 26px; translate: -50% 0; z-index: 2; pointer-events: none;
    padding: 2px 6px; border-radius: var(--radius-s); white-space: nowrap; background: var(--glass-thick); /* a chip INSIDE the glass bar: the thick tint alone, no blur (a plate in a plate doubles the tint) */
    font-size: 12px; line-height: 16px; font-weight: 700; font-variant-numeric: tabular-nums; }
  /* --v is the module's: the fill is the same number the thumb sits on, never two that drift */
  .rewind-track {
    position: absolute; left: 0; right: 0; bottom: 0; width: 100%; height: 22px; margin: 0;
    appearance: none; background: none; cursor: ew-resize; }
  /* the history already played is the blue, the rest of the tube the rule */
  .rewind-track::-webkit-slider-runnable-track {
    height: 10px; border-radius: var(--radius-full);
    background: linear-gradient(90deg, var(--time-fill) var(--v, 100%), var(--line-rule) var(--v, 100%)); }
  .rewind-track::-webkit-slider-thumb {
    appearance: none; width: 18px; height: 18px; margin-top: -4px;
    border-radius: 50%; background: var(--time-thumb);
    border: 2.5px solid var(--time-mark); box-shadow: 0 1px 3px var(--overlay-shadow); transition: transform var(--tap) var(--ease); }
  .rewind-play, .rewind-shut { width: 30px; height: 30px; flex: none; color: var(--text-ink); }
  .rewind-shut { color: var(--text-meta); }
  /* the wall clock is the readout; how far back is the small print under it */
  .rewind-clock {
    flex: none; display: flex; flex-direction: column; min-width: 7.2em; }
  .rewind-at { font-size: 14px; line-height: 16px; font-variant-numeric: tabular-nums; }
  .rewind-ago {
    font-size: 12px; line-height: 12px; color: var(--text-meta); font-variant-numeric: tabular-nums; }
  &[data-scrubbed] .rewind-at { color: var(--text-danger); }
  &[data-scrubbed] .rewind-ago { color: var(--text-danger); opacity: .8; }
  .rewind-live {
    flex: none; display: flex; align-items: center; gap: 4px; padding: 4px 8px 4px 8px;
    border: 1px solid var(--line-border); border-radius: var(--radius-full); cursor: pointer;
    background: none; color: var(--text-soft); font: inherit; font-size: 12px; line-height: 16px;
    font-weight: 700; }
  &:not([data-scrubbed]) .rewind-live {
    color: var(--text-on); border-color: var(--text-on); }
  /* in the past it is THE button: solid green, the one that brings now back */
  &[data-scrubbed] .rewind-live {
    background: var(--text-on); color: var(--surface-panel); border-color: var(--text-on); }
  .rewind-live .icon, .rewind-play .icon, .rewind-shut .icon { width: 16px; height: 16px; }
  /* on a wide row the bar FOLDS out of the clock and back (util/dom.js fold): easing its max-width it jumped 852 px each way */
  .rewind-bar.morph { overflow: hidden; } /* folding shut it is [hidden] and still laid out: the [hidden] rule spares .morph */
  &:has(.rewind-bar.morph) .rewind-open { display: none; }
  .rewind-track:active::-webkit-slider-thumb { transform: scale(1.3); }
  &[data-scrubbed] .rewind-live .icon { animation: rewind-pulse var(--handover) ease-in-out infinite; }
}

#rewind-open[aria-expanded="true"] { display: none; }

/* THE PAST, framed: a hairline of the clock's red round the page, so any corner says this is not now; under every click */
.rewind-frame { position: fixed; inset: 0; z-index: var(--z-bar); pointer-events: none;
  box-shadow: inset 0 0 0 2px var(--text-danger); }

/* ── the search with Rewind open: the circle opened has nowhere to go, so it lays over the row's whole width. Not on a
   phone, where the open pill answers to the screen and this left/right pushed it off the right edge ── */
@media (min-width: 561px) {
  body:has(#rewind .rewind-bar:not([hidden])) #searchbar:is(:focus-within, :has(input:not(:placeholder-shown))) {
    position: absolute; top: 0; left: 0; right: 0; z-index: 4; flex: 0 0 var(--thumb); } /* top: over the first line of a wrapped row */
}

/* the bar grows out of the button it replaced; the knob answers the pointer (both stand down under reduced motion) */
@keyframes rewind-in { from { opacity: 0; transform: scaleX(.94); transform-origin: left center; } }

/* live pulses only when it is NOT where you are: a live map has nothing blinking */
@keyframes rewind-pulse { 50% { opacity: .45; } }

/* A NARROW ROW (a phone, a card beside a laptop's map): the OPEN Rewind takes a line of its own, the row's own width
   deciding (#toolbar is the query container). After the rules above: same specificity, source order decides */
@container (max-width: 700px) {
  /* `order`: after the search circle, so the row above the bar stays whole */
  #rewind .rewind-bar { flex: 1 0 100%; order: 1; animation: rewind-in var(--fade) var(--ease) both; } /* a line of its own: it fades in, nothing to fold from */
  /* the circle stays in the row, pressed: the bar is UNDER it, not in its place */
  #rewind-open[aria-expanded="true"] { display: block; }
  /* a whole line is still ~100 px short of its min-content, so it wraps (overflowing walked live and ✕ off the map), and
     wrapped it is a card, not a capsule (a 999 px corner made a 118 px bar an oval) */
  #rewind .rewind-bar { flex-wrap: wrap; height: auto; padding: 6px; row-gap: 8px; border-radius: var(--radius-xl); }
  #rewind .rewind-row { flex: 1 1 140px; }
  #rewind .rewind-clock { order: 1; }
  #rewind .rewind-play { order: 2; }
  #rewind .rewind-live { order: 4; }
  #rewind .rewind-shut { order: 5; margin-left: auto; }
}
/* A ROW NARROWER THAN THE OPEN SEARCH (a phone): the box pops out UNDER the row at its full width (`top: 100%` is under the
   open Rewind too), the circle stays pressed; a tap on it blurs the input, which closes it */
@container (max-width: 500px) {
  /* the circles keep the tools' line, the vehicle's bar opening the next with the search (in DOM order the search stood alone on a third) */
  #vehicle-slot, #searchbar { order: 1; }
  #rewind .rewind-bar { order: 2; } /* still the last line */
  #searchbar:is(:focus-within, :has(input:not(:placeholder-shown))) { flex: 0 0 var(--thumb); height: var(--thumb); display: grid; place-items: center;
    border-radius: 50%; background: var(--highlight-wash); } /* pressed: the SELECTED rule's highlight */
  #searchbar:is(:focus-within, :has(input:not(:placeholder-shown))) > .icon { display: block; color: var(--line-highlight); }
  #searchbar:is(:focus-within, :has(input:not(:placeholder-shown))) .search-box {
    position: absolute; left: 0; right: 0; top: calc(100% + 10px);
    animation: rewind-in var(--fade) var(--ease) both; }
}

/* A ROW WITH NO ROOM FOR THE TOOLS (5 × 44 + its 2 px rims) stands down while the panel claims the room, as the phone's fan
   waits under its sheet: an iPad upright with the Overlays and a card open spilled the pill under the card */
@container (max-width: 223px) {
  #toolbar > * { display: none; }
}

/* ── COCKPIT MODE (arview/cluster/cockpit.js): the cluster the MAIN MAP wears, edge to edge, every floating control off, the
   night basemap forced (so `cockpit` has no NIGHT twin). An arc is an SVG path (a gradient stop can never end round) with
   pathLength=100, so a reading is a dash in per cent; one width for the channel and its run (a recess reads from its
   colour); both fill from the sweep's bottom, km/h left, rpm right. Decoration only: the chase's gestures reach the canvas ── */
body.chase:is(.cockpit, .eye), body.cards.nocard { --dock: 0px; } /* outranks body.cards: the map takes the cards' width back */
/* the cluster fills its screen in ONE STEP, under the cards sliding away, and stays full-bleed until they are back
   (`ck-leaving`). Never transitioned: GL JS clears a moving box's canvas and redraws a frame late, a blank map (Scars) */
body.chase:is(.cockpit, .eye) #map, body.ck-leaving #map { inset: 0; border: none; border-radius: 0; transition: none; }
/* the furniture by KEYFRAMES, not a transition (the Overlays, the tool row and body.relight own `transition` here already):
   out over the wake's first 30 %, back in the exit's last 40 % (`ck-leaving`, cockpit.js), and for his eye over the camera's
   blend (`eye-leaving`, mapcam.js) so the shell does not pop while the picture moves */
body.chase.cockpit :is(#overlays, #toolbar, #performance, .mapboxgl-control-container, #ar-seam, #phone-pill, #phone-plus, #phone-dots, #phone-hide, #rewind .rewind-bar),
body.chase.eye :is(#overlays, #toolbar, .mapboxgl-control-container, #ar-seam) {
  animation: ck-shell-out calc(var(--wake) * .3) var(--ease) forwards;
}
body.ck-leaving :is(#overlays, #toolbar, #performance, .mapboxgl-control-container, #ar-seam, #phone-pill, #phone-plus, #phone-dots, #phone-hide, #rewind .rewind-bar),
body.eye-leaving :is(#overlays, #toolbar, .mapboxgl-control-container, #ar-seam) {
  animation: ck-shell-in calc(var(--wake) * .24) var(--ease) calc(var(--wake) * .36) both;
}
@keyframes ck-shell-out { to { opacity: 0; visibility: hidden; } }
@keyframes ck-shell-in { from { opacity: 0; visibility: hidden; } }
/* …and the column lands just before the exit ends, with the shell, not over a cluster still on the glass */
body.ck-leaving #ar-cards {
  transition: transform var(--slide) var(--ease) calc(var(--wake) * .3),
              visibility 0s calc(var(--wake) * .3);
}

/* EYE MODE (maps/mapcam/eye.js): the MAIN map is his eye; the shell and the cards step away as under the cluster (the map's
   edge and --dock are the cockpit's rules), the Performance readout stays (the owner's verdict). His card's glass is over
   the main map in .eye-frame (card/worn.js) */
body.chase.eye #ar-cards { transform: var(--away); visibility: hidden; transition: none; }
body.eye .key-hints { display: none; }
/* THE HUD FRAME in a driver's seat (card/worn.js): the HUD's virtual image in the FoV's pen, the fancy button's look by day
   and the yellow after dark; placed per frame inline. An outline alone, no wash over the road, and it and its words fade 5 s
   after the HUD goes on — it says where the HUD's picture is, then leaves the road to it (the owner, 2026-11-02). The border and
   the words fade, never the box: the speed and the sign are inside it. A class put back restarts it */
.hud-frame {
  position: absolute; z-index: 1; pointer-events: none; box-sizing: border-box; border-radius: var(--radius-s);
  border: 2px solid var(--fov-line-day); animation: hud-frame-out var(--fade) linear var(--hud-hold) forwards;
}
body[data-light="night"] .hud-frame { border-color: var(--fov-line); }
.hud-frame-said {
  position: absolute; left: -2px; bottom: calc(100% + 4px); white-space: nowrap;
  font-size: 12px; line-height: 16px; font-weight: 600; color: var(--fov-line-day); text-shadow: 0 0 3px var(--overlay-scrim);
  animation: hud-said-out var(--fade) linear var(--hud-hold) forwards;
}
body[data-light="night"] .hud-frame-said { color: var(--fov-line); }
@keyframes hud-frame-out { to { border-color: transparent; } }
@keyframes hud-said-out { to { opacity: 0; } }
/* H, and the cockpit: the column SLIDES away with the map's edge, keeping `visibility` (a display:none map measures 0×0 and
   drops its tiles; hidden at once it showed bare page until the edge caught up), arview.js holding GL for it */
body.nocard #ar-seam { display: none; }
body.chase.cockpit #ar-cards, body.nocard #ar-cards {
  transform: var(--away); visibility: hidden;
  transition: transform var(--slide) var(--ease), visibility 0s var(--slide);
}
.eye-frame { position: absolute; inset: 0; z-index: 1; pointer-events: none; overflow: hidden; }
body:not(.eye) .eye-frame { display: none; }

/* ── THE CLUSTER (arview/cluster/cluster.js): ONE OVERLAY for every driving view, the cockpit (#cockpit) and a car's card
   alike, only the map under it differs. A size container: `cqh`/`cqw` lay it out at a dashboard's size and a card's, a 12 px floor ── */
.cluster {
  /* z 2, as the picture's markers: last in the glass, so the instruments read over them (a badge's stem ran through the
     drone's readout); a callout (3) opens over both */
  position: absolute; inset: 0; z-index: 2; pointer-events: none; overflow: hidden;
  container-type: size; font-variant-numeric: tabular-nums;
  color: var(--cluster-ink);
  --g: min(42cqh, 26cqw, 400px);   /* the gauge's own box */
  --w: 3.44;                       /* the channel AND the run in it, as a share of that box */
  --glow: 7px;                     /* the bloom around the reading, never around the channel */
  --num: .294;                     /* the big numeral, as a share of the box */
  --edge: .18;                     /* how far in from the edge a gauge stands, in gauges */
  /* the sweep: 137° of a radius-41 circle, 0 at its bottom; the scale's ends set out to radius 48, never on the arc */
  --d: path("M 31.39 86.53 A 41 41 0 0 1 38.70 10.59");
  --lo-x: 28.2%; --lo-y: 92.8%; --hi-x: 36.8%; --hi-y: 3.9%;
}
.cluster > * { position: absolute; }
/* an emptied card: nothing followed, no instruments (a clicked camera closes with it, card/pip.js) */
.cluster.bare { display: none; }
/* ── THE SATELLITE HUD (arview/orbitview): an orbiting track's card wears it where it wears the cluster — the fade round the ring, four
   corner widgets, the compass marks and the ground track, in the glass's phosphor ink, the amber and shade of THEME.orbitview. One SVG
   in the picture's px (its viewBox is the pane's own size), under the same z as the cluster; its lettering is laid out at a scale
   orbitview/geometry.js layoutOf keeps at or over a floor of 0.8 (a 12 px caption never under 9.6 px): a card too narrow wears four 12 px text chips instead, not a smaller drawing ── */
.orbit-hud { position: absolute; inset: 0; z-index: 2; pointer-events: none; overflow: hidden; color: var(--flight-phosphor-ink); font-variant-numeric: tabular-nums;
  --safe-top: env(safe-area-inset-top, 0px); } /* read by orbitview.js: its top corners stand under a phone's status bar */
.orbit-hud.gone { display: none; }
.orbit-hud { transition: opacity var(--fade); }
/* THE MAP OUTSIDE THE RING, over the main map (orbitview's `frost` layer, cut by cockpit.js): frosted glass with a vignette — the map blurred and
   darkened, the ring cut out of it by a mask (its radius, --ring, and the distance to a corner, --far, written per frame), a soft 22 px edge so
   the photographs' own fade meets glass, not a line, and starts 3 px OUT: the ring's line is 2 px wide and a blur over its outer half read thinner
   than the main map's. Opacity is the caller's (orbitview fade(): with the camera). Under the HUD (z 2), over the map's markers */
.orbit-frost {
  position: absolute; inset: 0; z-index: 1; pointer-events: none; --ring: 300px; --far: 900px; --cx: 50%; --cy: 50%;
  -webkit-backdrop-filter: blur(6px) saturate(1.1) brightness(.92); backdrop-filter: blur(6px) saturate(1.1) brightness(.92);
  background: radial-gradient(circle at var(--cx) var(--cy), transparent var(--ring), rgba(2, 10, 14, .42) var(--far));
  -webkit-mask-image: radial-gradient(circle at var(--cx) var(--cy), transparent calc(var(--ring) + 3px), #000 calc(var(--ring) + 26px));
  mask-image: radial-gradient(circle at var(--cx) var(--cy), transparent calc(var(--ring) + 3px), #000 calc(var(--ring) + 26px));
  transition: opacity var(--fade);
}
.orbit-frost.gone { display: none; }
.orbit-frost.shaped { -webkit-mask-image: none; mask-image: none; } /* cut to the ring's outline by clip-path (orbitview.js): a circular hole would cut it again */
.orbit-hud.held { opacity: 0; } /* the ring still gliding down to the size its chips were laid for: faded in now they would sit on the old, bigger ring (orbitview.js) */
/* …and the picture it waits for is the old one STRETCHED over the box (GL is held for the drag, and drew a small rectangle in a corner of an empty card): the canvas fills its
   container while `sizing`, and is itself again, resized, when the drag lands (arview.js) */
body.sizing .ar-map .mapboxgl-canvas-container { position: absolute; inset: 0; }
body.sizing .ar-map .mapboxgl-canvas { width: 100% !important; height: 100% !important; }
body.sizing :is(.ar-markers, .ar-near, .ar-callout) { visibility: hidden; } /* …and the pins and callouts are placed in the old picture's pixels: they would drift off the stretched one */
.orbit-hud-svg { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.orbit-hud text { font-family: ui-monospace, Menlo, monospace; font-weight: 500; fill: currentColor; }
.orbit-hud .l { opacity: .62; letter-spacing: .1em; }
.orbit-hud .a { fill: var(--orbitview-amber); }
.orbit-hud .rl { paint-order: stroke; stroke: rgba(2, 8, 12, .75); stroke-width: 3px; stroke-linejoin: round; }
/* AN AR VIEW (`corners`, cluster.js): the gauges in the picture's two bottom corners at the card minimap's old size, a clicked
   camera over the right one, no rail; a disc 18 % of the width (never under 84 px), its centre 14.1 % in, card and visor alike */
.cluster.corners { --g: max(20.45cqw, 95.45px); --in: 14.1cqw; }
.cluster.corners :is(.ck-gauge, .ar-cam) { top: auto; transform: none; bottom: calc(var(--in) - var(--g) / 2); }
.cluster.corners .ck-speed { left: calc(var(--in) - var(--g) / 2); }
.cluster.corners :is(.ck-rpm, .ar-cam) { right: calc(var(--in) - var(--g) / 2); }
/* the compass band across the top: never under 43 px, the height band.js letters at 1× (BAND_UNITS) */
.cluster.corners .ck-compass { top: 0; width: 100%; height: max(43px, 17.2cqh); }
.cluster.corners :is(.ck-gear, .ck-batt) { display: none; }
/* the unit and the end figures grow with the dial as its numeral does (12 px at the 95 px floor): fixed, they read a third of the
   shell's floor on the 4K desk, where the picture stays at 1 under --ui */
.cluster.corners :is(.ck-cap, .ck-lo, .ck-hi, .ck-per) { font-size: max(12px, calc(var(--g) * .1257)); }
/* the rail is a face's facts alone, centred between the corners (a soldier's grid, a plane's squawk) */
.cluster.corners .ck-facts { margin: 0 auto; }
:where(.dark-ink .cluster.corners) .ck-facts { color: var(--text-ink); } /* the glass's special case (arview/ink.js) */
/* A WORN CAR HUD (cluster.js isLens): the speed figure, its unit and the posted limit in one row at the box's bottom-left, sized
   off the box's height — the dials, the pod and its minimap, the band, BRAKE and the rail were made for a wider field (the owner,
   2026-11-02); the next turn stands in the bottom-right (turnsign.js), the places and the turn sign over the rest */
.cluster.corners.lens :is(.ck-rpm, .ar-cam, .ck-compass, .ck-brake, .ck-rail, .ck-arc, .ck-lo, .ck-hi, .ck-glass) { display: none; }
/* …the figure, and the posted limit over its unit beside it, the three flush to the box's bottom-right (the owner, 2026-11-02) */
.cluster.corners.lens .ck-speed { left: auto; right: 3cqw; bottom: 5cqh; width: auto; height: auto;
  display: grid; grid-template-areas: "val sign" "val cap"; justify-items: end; align-items: end; column-gap: 1.5cqh; row-gap: 1cqh; }
.cluster.corners.lens .ck-read { display: contents; }
.cluster.corners.lens .ck-val { grid-area: val; font-size: max(18px, 26cqh); line-height: .8; }
.cluster.corners.lens .ck-cap { grid-area: cap; margin: 0; font-size: max(9px, 7cqh); line-height: 1; }
.cluster.corners.lens .ck-sign { grid-area: sign; position: relative; left: auto; top: auto; translate: none; --sz: max(20px, 17cqh);
  background: transparent; color: var(--cluster-ink); } /* the prototype's roundel: the red ring round a white figure, nothing filled */
/* a side the face neither dials nor paints (`none`: a man has no speedometer) draws nothing; its slot still holds the minimap */
.ck-gauge.none > :not(.ck-minimap-slot) { display: none; }
/* the wake's stages (#cockpit) registered at 1: wherever the cockpit is not waking them (a card) every stage is whole */
@property --s-glass { syntax: '<number>'; inherits: true; initial-value: 1; }
@property --s-house { syntax: '<number>'; inherits: true; initial-value: 1; }
@property --s-draw { syntax: '<number>'; inherits: true; initial-value: 1; }
@property --s-fill { syntax: '<number>'; inherits: true; initial-value: 1; }
@property --s-read { syntax: '<number>'; inherits: true; initial-value: 1; }
@property --s-rail { syntax: '<number>'; inherits: true; initial-value: 1; }

/* ── the two gauges: one arc, two readings ── */
.ck-gauge {
  width: var(--g); height: var(--g); top: 50%; transform: translateY(-50%);
  display: grid; place-content: center; text-align: center;
}
/* the number on the arc's own centre: that ties the reading to its sweep */
.ck-speed { left: calc(var(--g) * var(--edge)); }
.ck-rpm { right: calc(var(--g) * var(--edge)); }
/* no `vector-effect: non-scaling-stroke`: it measures dashes in screen px against a path in user units, and the pattern
   repeated 1.8×. Stroke weight is a share of the gauge box instead: the ring thickens with the instrument */
.ck-arc { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.ck-arc-rpm { transform: scaleX(-1); } /* mirrored, so both sweeps open toward the road */
.ck-arc path { d: var(--d); fill: none; stroke-linecap: round; stroke-width: var(--w); }
/* the channel in the ground colour with some track mixed back, or a groove over dark buildings is a groove over nothing */
.ck-track { stroke: color-mix(in srgb, var(--cluster-ground) 52%, var(--cluster-track));
  /* draws in from the sweep's bottom as the cluster wakes; faded under a pixel, as a zero-length dash is a dot */
  stroke-dasharray: calc(var(--s-draw) * 100px) 100px;
  opacity: min(1, calc(var(--s-draw) * 400));
}
/* A ZERO READING DRAWS NOTHING: a round cap on a zero-length dash is a dot at the gauge's foot and CSS has no conditional
   cap, so the run fades out, the multiplier large enough that a pixel-wide reading is already opaque */
.ck-lit { filter: drop-shadow(0 0 var(--glow) currentcolor); }
.ck-arc-speed .ck-lit { opacity: min(1, calc(var(--speed, 0) * var(--s-fill) * 400)); }
.ck-arc-rpm .ck-lit { opacity: min(1, calc(var(--rpm, 0) * var(--s-fill) * 400)); }
/* every dash length carries px: a bare calc() in stroke-dasharray serialises as a percentage of the viewport diagonal */
.ck-arc-speed .ck-lit {
  stroke: var(--cluster-speed); color: var(--cluster-speed);
  /* × the wake's fill: it fills TO the reading, never past it (a self-test sweep would show 160 for a car doing 50) */
  stroke-dasharray: calc(var(--speed, 0) * var(--s-fill) * 100px) 100px;
}
/* THE REDLINE IS PAINT, NOT A READING: the channel's last 8 %, where the simulated box changes up; it never blooms. Red is
   for faults everywhere else in the cluster, the tachometer's redline the exception every car already makes */
.ck-arc-rpm .ck-band {
  stroke: var(--cluster-redline); filter: none;
  stroke-dasharray: 8px 100px; stroke-dashoffset: -92px;
  /* it lies in the last 8% of the channel, so it arrives as the channel's draw reaches it */
  opacity: clamp(0, (var(--s-draw) - .92) / .08, 1);
}
.ck-arc-speed .ck-band, .ck-rpm:not(.redline) .ck-band { display: none; } /* the redline: a face's that says so (a car's) */
.ck-arc-rpm .ck-lit {
  stroke: var(--cluster-rpm); color: var(--cluster-rpm);
  stroke-dasharray: calc(var(--rpm, 0) * var(--s-fill) * 100px) 100px;
}
/* the tachometer's four figures against the speed's two: the numeral is sized off the gauge box, so it narrows, never runs over the sweep */
.ck-val {
  /* SF Pro Rounded at 300 (the owner's pick of six): a rounded terminal reads as a figure a fraction sooner; a system face, as
     the app ships no fonts, the grotesk behind it */
  font: 300 calc(var(--g) * var(--num)) / .9 ui-rounded, 'SF Pro Rounded', system-ui, sans-serif;
  letter-spacing: -.01em;
  /* the two figures wear the card's old speedometer glow (the owner): light on dark, dark on light in the dark ink */
  text-shadow: 0 0 4px var(--anno-night-glow), 0 0 9px var(--anno-night-glow);
}
:where(.dark-ink .cluster.corners) .ck-val {
  color: var(--text-ink); text-shadow: 0 0 4px var(--text-on-dark), 0 0 8px var(--text-on-dark);
}
/* …and their captions a tighter one: KM/H, 0 and 160 read 2.7:1 on a day road bare (the owner's pick E, 2026-11-04) */
.ck-cap, .ck-lo, .ck-hi { text-shadow: 0 0 3px var(--anno-night-glow), 0 0 6px var(--anno-night-glow); }
:where(.dark-ink .cluster.corners) :is(.ck-cap, .ck-lo, .ck-hi) { color: var(--text-soft); text-shadow: 0 0 3px var(--text-on-dark), 0 0 6px var(--text-on-dark); } /* the soft ink was 2.9:1 on a day road even haloed */
/* THE NUMERALS ARE INK (the owner put the gauge colours back): the colour belongs to the glanced sweep, not the read
   figure — except for a tenth of a second at an upshift, which is what a shift light is */
.ck-rpm.shift .ck-val {
  color: var(--cluster-rpm); text-shadow: 0 0 26px var(--cluster-rpm);
}
.ck-rpm.shift .ck-lit { filter: drop-shadow(0 0 calc(var(--glow) * 2.8) currentcolor); }
.ck-rpm .ck-val { transition: color var(--fade) linear, text-shadow var(--fade) linear; }
/* the tachometer's unit (cluster.js `per`), FLUSH under its figure in hundreds: a roundel's gap lower it met the scale's 0 at
   2.7 px on a card's 95 px gauge and read "×1000" */
.ck-per { position: absolute; left: 50%; top: 100%; translate: -50%; line-height: 1;
  font-size: 12px; letter-spacing: .1em; color: var(--cluster-soft); white-space: nowrap; }
.ck-per:empty { display: none; } /* a face's own dial carries its unit in its cap */
.ck-cap, .ck-lo, .ck-hi {
  font-size: 12px; letter-spacing: .1em; text-transform: uppercase; color: var(--cluster-soft);
}
.ck-cap { margin-bottom: 5px; }
/* the figures come up once the channels are drawn, the pod's disc and camera with them */
:is(.ck-cap, .ck-read, .ck-lo, .ck-hi, .ck-minimap-slot) { opacity: var(--s-read); }
.ck-lo, .ck-hi { position: absolute; transform: translate(-50%, -50%); }
.ck-lo { left: var(--lo-x); top: var(--lo-y); }
.ck-hi { left: var(--hi-x); top: var(--hi-y); }
.ck-rpm .ck-lo { left: calc(100% - var(--lo-x)); }
.ck-rpm .ck-hi { left: calc(100% - var(--hi-x)); }

/* ── the posted limit, in a European driver's roundel, RIDES THE NUMERAL: the speed you do and the speed you may are one
   reading. It hangs under the figure (a row or column would push the speed off the arc's centre), absolute so the figure
   never moves, a sixth of the gauge and never under 26 px ── */
.ck-read { position: relative; display: grid; place-items: center; }
.ck-sign {
  --sz: max(calc(var(--g) * .17), 26px);
  position: absolute; left: 50%; top: 100%; translate: -50% calc(var(--g) * .065);
  width: var(--sz); height: var(--sz);
  display: grid; place-items: center; border-radius: 50%;
  background: var(--cluster-ink); color: var(--cluster-ground);
  box-shadow: inset 0 0 0 calc(var(--sz) * .13) var(--cluster-sign);
  font: 700 max(calc(var(--sz) * .44), 12px) / 1 system-ui, sans-serif; font-variant-numeric: tabular-nums;
  transition: transform var(--reveal-open) var(--ease), opacity var(--tap) linear;
}
.ck-sign.gone { transform: scale(.3); opacity: 0;
  transition: transform var(--reveal-shut) var(--ease-exit), opacity var(--tap) linear; }
/* over the limit it PULSES, no bloom: a glow round a regulatory roundel reads as ours, not the road's */
.ck-sign.over { animation: ck-over calc(var(--handover) / 2) ease-in-out infinite; }
@keyframes ck-over { 50% { transform: scale(1.13); } }

/* ── M: the minimap TAKES THE WHOLE RING. The slot is the size and the disc fills it: minimap3d/ sizes its map once, so a
   stylesheet that grew the disc left the roads in one corner and the scale label lying by 2× ── */
.ck-minimap-slot {
  position: absolute; left: 6%; bottom: 6%; width: 88%; aspect-ratio: 1; display: none;
}
.cluster.minimap .ck-minimap-slot { display: block; }
.cluster.minimap .ck-rpm :is(.ck-read, .ck-cap, .ck-lo, .ck-hi) { display: none; } /* .ck-read: the figure and its ×100 */
/* the whole sweep goes: at 88 % the disc covers the channel, and a ring under an opaque disc is seen by nobody */
.cluster.minimap .ck-arc-rpm { display: none; }

/* ── N: the compass band (arview/cluster/band.js), folded to N's one switch (folded it draws nothing). `ppd` is width/120, so
   a wider band spreads the same 120° further rather than showing more; its letters grow with its height ── */
.ck-compass {
  top: calc(var(--f-band, 0px) + 1.5cqh); left: 50%; transform: translateX(-50%);
  width: calc(100% - clamp(16px, 2.8cqw, 40px)); height: clamp(28px, 8.7cqh, 78px);
}
/* the periphery arrives last and goes first, as a cluster's do */
.ck-compass, .ck-rail { opacity: var(--s-rail); }
.ck-hud { width: 100%; height: 100%; display: block; }

/* ── the status rail, sized for a dashboard at arm's length (the first set was "barely legible"), the 12 px floor on a card;
   everything on it in its own em ── */
.ck-rail {
  left: 0; right: 0; bottom: var(--f-band, 0px); height: clamp(28px, 8.4cqh, 76px);
  padding: 0 clamp(8px, 2.1cqw, 30px) calc(env(safe-area-inset-bottom, 0px));
  display: flex; align-items: center; gap: .77em;
  font-size: clamp(12px, 2.9cqh, 26px);
}
/* the charge: a bar that is the reading, its number beside it, at the rail's right end where a cluster carries the car's one number */
.ck-batt { display: flex; align-items: center; gap: .42em; }
.ck-batt-bar {
  width: 2.3em; height: .65em; border-radius: 4px; position: relative;
  box-shadow: inset 0 0 0 2px var(--cluster-track);
}
.ck-batt-bar::after {
  content: ''; position: absolute; inset: 4px; width: auto; border-radius: 2px;
  background: linear-gradient(90deg, var(--cluster-speed) 0 var(--pct, 100%),
                              transparent var(--pct, 100%));
}
.ck-batt.low .ck-batt-bar::after { background: linear-gradient(90deg, var(--cluster-brake) 0 var(--pct, 100%), transparent var(--pct, 100%)); }
.ck-batt-pct { font: 500 max(.77em, 12px)/1 system-ui, sans-serif; }
.ck-gear { margin-left: auto; display: flex; gap: .73em; font: 700 1em/1 system-ui, sans-serif; }
/* a face's facts (track.js `cluster` `rail`) take the gear's end; PRND is a face's with a gear, the pack one's with a charge */
.ck-facts { margin-left: auto; font: 500 max(.85em, 12px)/1 system-ui, sans-serif;
  letter-spacing: .02em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ck-facts:empty { display: none; }
/* THE GLASS: a face that paints its own instrument (a PFD, an ND, an orbit) takes the gauge's box, wider than the arc's square */
.ck-glass { position: absolute; inset: -12%; width: 124%; height: 124%; display: none;
  opacity: var(--s-read); }
.ck-gauge.painted .ck-glass { display: block; } /* `painted`, not `glass`: that class is theme/glass's plate (every face went frosted) */
.ck-gauge.painted :is(.ck-arc, .ck-cap, .ck-read, .ck-lo, .ck-hi) { display: none; }
.cluster.minimap .ck-rpm .ck-glass { display: none; } /* M: the minimap takes the pod, as over the tach */
.ck-g { color: var(--cluster-track); transition: color var(--fade) linear; }
.ck-g.on { color: var(--cluster-ink); }
/* the gear you are IN is worth a hue */
.ck-g.on:nth-child(4) { color: var(--cluster-speed); text-shadow: 0 0 14px var(--cluster-speed); }
.ck-g.on:nth-child(2) { color: var(--cluster-brake); text-shadow: 0 0 14px var(--cluster-brake); }
/* ── the brake badge: an OUTLINED pill, light without hiding road, popping on M and N's spring. The wrapper positions and the
   word is the pill: one doing both is its own pseudo-element's containing block, and its translate fights the pop's transform ── */
.ck-brake { left: 0; right: 0; top: 44%; display: grid; place-items: center; }
.ck-brake-word {
  padding: .53em 1.35em; border-radius: .6em;
  background: color-mix(in srgb, var(--cluster-ground) 82%, transparent);
  color: var(--cluster-brake);
  font: 700 clamp(12px, 3.8cqh, 34px)/1 system-ui, sans-serif; letter-spacing: .26em; text-indent: .26em;
  box-shadow: inset 0 0 0 2.5px var(--cluster-brake),
    0 0 40px color-mix(in srgb, var(--cluster-brake) 40%, transparent);
  transition: transform var(--reveal-open) var(--ease), opacity var(--tap) linear;
}
/* the right pod's screen, a camera clicked in a card's picture (card/pip.js): at the picture's shape, in the housing and the speed's glow */
.ar-cam {
  height: var(--g); right: calc(var(--g) * var(--edge)); top: 50%; transform: translateY(-50%);
  aspect-ratio: 16 / 9; overflow: hidden; border-radius: calc(var(--g) * .06);
  background: var(--surface-void); pointer-events: auto;
  box-shadow: 0 0 0 3px var(--cluster-housing),
              0 0 calc(var(--g) * .16) color-mix(in srgb, var(--cluster-speed) 42%, transparent);
}
.ar-cam .ar-video { object-fit: cover; }

/* ── COCKPIT MODE'S OWN (arview/cluster/cockpit.js). THE WAKE IS ONE CLOCK: `--wake-t` runs 0 → 1 over --wake and back over 60 %
   of it, and every stage is a slice of it (the exit reverses the entry for free): glass, housing, channels, runs, figures, then
   compass and rail, as a production cluster wakes. The readings are multiplied by a stage, never eased: a late needle reads as
   lag. VISIBILITY, not display: display:none → block has no `from` ── */
@property --wake-t { syntax: '<number>'; inherits: true; initial-value: 0; }
#cockpit {
  visibility: hidden;
  --wake-t: 0;
  transition: --wake-t calc(var(--wake) * .6) ease-in-out, visibility 0s calc(var(--wake) * .6);
  --s-glass: var(--wake-t);
  --s-house: clamp(0, var(--wake-t) / .5, 1);
  --s-draw: clamp(0, (var(--wake-t) - .15) / .45, 1);
  --s-fill: clamp(0, (var(--wake-t) - .4) / .5, 1);
  --s-read: clamp(0, (var(--wake-t) - .45) / .35, 1);
  --s-rail: clamp(0, (var(--wake-t) - .6) / .4, 1);
  --f-max: 10%;                    /* the housing above and below the window, each */
  --f-band: calc(var(--f-max) * var(--s-house)); /* what it is at this moment of the wake */
}
body.chase.cockpit #cockpit {
  visibility: visible; --wake-t: 1;
  transition: --wake-t var(--wake) ease-in-out, visibility 0s;
}
/* the GL slot steps back out of the cockpit's --ui zoom, as .ar-frame does */
#cockpit .ck-minimap-slot { zoom: calc(1 / var(--ui)); }

/* THE VIGNETTE IS THE BEZEL: glass falling away on all four sides, the corners to the ground outright — a falloff ellipse, a
   square-edged wash per axis (an ellipse cannot square a corner), and a foot that carries the rail out of the road */
.ck-vignette {
  /* in SCREEN coordinates, never clipped to the housing's window: the badge patch is measured in the screen, and clipping only let
     raw sky through under a shallow frame */
  inset: 0; opacity: calc(.92 * var(--s-glass)); /* how dark the corners go: the map reads as seen THROUGH a cluster */
  background:
    radial-gradient(ellipse 74% 66% at 50% 54%, /* the shade starts 38 % out; 100 % turns it off */
      transparent 38%, var(--cluster-ground) 104%),
    linear-gradient(var(--cluster-ground), transparent 26% 68%, var(--cluster-ground)),
    linear-gradient(90deg, var(--cluster-ground), transparent 21% 79%, var(--cluster-ground)),
    radial-gradient(ellipse 120% 40% at 50% 100%,
      color-mix(in srgb, var(--cluster-ground) 85%, transparent), transparent 70%);
  /* …THINNED, not cut, over the turn sign, drawn inside the map's canvas (waypoints/turnsign.js) where no DOM can lift it: the
     parked badge's box (18 % of the height at `park`) keeps half its shade, the falloff over the patch's full radius */
  mask: radial-gradient(ellipse 19% 9% at 50% 23%, rgba(0, 0, 0, .5) 0 26%, #000 100%);
}

/* ── THE HOUSING: a cluster is a panel set in a dash (a 12.3" cluster is ~2.2:1), so the frame is the WINDOW the rail, compass and
   shade measure from. ONE band top and bottom (symmetry is the property; the owner's pick of ten), under ~18 %: the gold instruction
   parks at 22 % of the screen (turnsign.js) and the car at 78 % (chase.headroom). A card wears no housing ── */
.ck-frame {
  /* the housing IS the shadow: a spread this large paints every pixel outside the window and none inside */
  inset: var(--f-band) 0;
  box-shadow: 0 0 0 100vmax var(--cluster-housing);
}

/* ── THE DIAL (theme/radial/radial.js; an area's meaning, the ping wheel): a ring of clear wedges over ONE glass disc, open in the middle; the picked
   wedge wears THE HIGHLIGHT, the name under the pointer over the disc. Mounted shut and opened a frame later, so the fold-out
   always runs; the script cuts each wedge's clip-path ── */
.radial { position: absolute; left: 0; top: 0; z-index: 4; pointer-events: none; }
/* shell furniture in the map's px: its PARTS take the shell's zoom, never its box, as a key chip's (radial.js keeps R·ui round it) */
.radial > * { zoom: var(--ui); }
/* sized by the dial's radii (theme/radial: --R, --r; the area picker's 84 and 22, the ping wheel's 128 and 56) */
.radial-disc, .radial-grooves, .radial-wedge { position: absolute; left: calc(-1 * var(--R)); top: calc(-1 * var(--R)); width: calc(2 * var(--R)); height: calc(2 * var(--R)); }
.radial-disc { border-radius: 50%; mask: radial-gradient(circle, transparent calc(var(--r) - 3px), #000 calc(var(--r) - 2px)); opacity: 0; transform: scale(.72);
  transition: opacity var(--fade) var(--ease), transform var(--slide) var(--ease); }
.radial-grooves { pointer-events: none; stroke: var(--overlay-rim); stroke-width: 2; opacity: 0; transition: opacity var(--fade) var(--ease); }
.radial.open :is(.radial-disc, .radial-grooves) { opacity: 1; transform: none; }
.radial-wedge { border: 0; padding: 0; margin: 0; background: none; cursor: pointer; color: var(--text-ink); pointer-events: auto; }
.radial-wedge.danger { color: var(--text-danger); }
.radial-wedge-hl path { fill: transparent; stroke: transparent; stroke-width: 2; transition: fill var(--tap) var(--ease), stroke var(--tap) var(--ease); }
.radial-wedge:focus-visible { outline: none; }
.radial-wedge:focus-visible .radial-wedge-hl path { stroke: var(--text-ink); } /* the one focus ring: 2 px of ink, on the wedge's own edge */
.radial-wedge[aria-checked="true"] .radial-wedge-hl path { fill: var(--highlight-wash); } /* SELECTED's look: the wash, no edge */
.radial-wedge[aria-checked="true"]:not(.danger) { color: var(--line-highlight); }
.radial-wedge-c { position: absolute; width: 72px; display: flex; flex-direction: column; align-items: center; gap: 2px; pointer-events: none;
  opacity: 0; transform: translate(-50%, -50%) scale(.7); transition: opacity var(--fade) var(--ease), transform var(--slide) var(--ease); }
.radial.open .radial-wedge-c { opacity: 1; transform: translate(-50%, -50%); }
.radial-wedge-c .icon { margin: 0; }
.radial-wedge-c .glyph svg { display: block; height: 28px; width: auto; } /* an APP-6E frame (the ping wheel's), in its .ink or not */
body[data-light="night"] .radial-wedge-c .ink { filter: invert(1); } /* a control measure is milsymbol's black line art */
.radial-wedge-c b { font: 600 12px/16px var(--font); text-align: center; }
.radial-cap { position: absolute; left: 0; top: calc(-1 * var(--R) - 8px); transform: translate(-50%, -100%); white-space: nowrap; padding: 4px 12px;
  border-radius: var(--radius-full); font: 600 12px/16px var(--font); color: var(--text-ink); pointer-events: none; opacity: 0;
  transition: opacity var(--tap) var(--ease); }
.radial-cap.on { opacity: 1; }
.radial.below .radial-cap { top: calc(var(--R) + 8px); transform: translate(-50%, 0); }
/* THE AUDIENCE (overlays/generic/aoi/): Police | NATO, a neutral radial's presets; inside the panel, a hairline capsule, never a
   plate; the pressed one wears SELECTED's capsule */
.aoi-audience { display: flex; width: max-content; margin: 4px 0 8px 16px; border: 1px solid var(--line-border); border-radius: var(--radius-full); }
.aoi-audience > button { width: auto; height: 36px; padding: 0 16px; font: 600 12px/16px var(--font); border-radius: var(--radius-full); }
/* AN AREA'S ALERT (aoi/alerts.js): the engine's newest in ONE pill at the map's foot; an urgent one (a minefield, a hot zone
   entered) rimmed red with its word */
.aoi-alert { position: absolute; left: 50%; bottom: 72px; transform: translateX(-50%); z-index: 5; display: flex; align-items: center; gap: 12px;
  max-width: calc(100% - 32px); padding: 4px 4px 4px 16px; border-radius: var(--radius-full); font: 500 14px/20px var(--font); color: var(--text-ink); }
.aoi-alert > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.aoi-alert.urgent { border-color: var(--text-danger); padding-left: 6px; }
.aoi-alert > .urg { font: 700 12px/16px var(--font); color: var(--text-on-danger); background: var(--text-danger); border-radius: var(--radius-full); padding: 2px 8px; }

/* HOVER IS A POINTER'S STATE: a tap leaves :hover stuck until the next tap lands elsewhere, so every :hover lives here
   (rules.test); mirror mode's wake rides :hover with :active and :focus-within on purpose */
@media (hover: hover) {
  #ar-seam:hover::after { opacity: .55; }
  .m3-rig:hover .m3-ctl, .callout-x:hover, .nato-sw:hover, .nato-chev:hover { opacity: 1; } /* a reveal, not a shade: the shared wash is the shade */
  .search-opt:hover { background: var(--highlight-hover); }
  .m3-ctl .btn:hover .face { fill: var(--line-highlight); fill-opacity: .1; } /* the one wash on a no-fill bar: the highlight's hover, as the shell's buttons */
  /* the innermost node under the cursor lights whole (:has() hands the glow down); its parents stand back */
  .cg-node:hover:not(:has(.cg-node:hover)) > .cg-pill {
    background: color-mix(in srgb, var(--cg-tone) 26%, transparent);
    border-color: color-mix(in srgb, var(--cg-tone) 80%, transparent);
  }
  .cg-node:not([data-open]):hover:not(:has(.cg-node:hover)) > .cg-pill {
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--cg-tone) 16%, transparent);
  }
  .cg-node[data-open]:hover:not(:has(.cg-node:hover)) {
    border-color: color-mix(in srgb, var(--cg-tone) 70%, transparent);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--cg-tone) 16%, transparent);
  }
  .mapboxgl-ctrl-group button:not(:disabled):hover {
    background-color: var(--highlight-hover); }
  .key-hint[data-run]:hover { text-decoration: underline; text-underline-offset: 3px; } /* no plate to wash: its word says it is a verb */
  .nato-amp select:hover { border-color: var(--line-strong); }
  .rewind-track:hover::-webkit-slider-thumb { transform: scale(1.15); }
  .radial-wedge:hover .radial-wedge-hl path { fill: var(--highlight-hover); }
  .radial-wedge[aria-checked="true"]:hover .radial-wedge-hl path { fill: var(--highlight-wash); }
}

/* ── THE LAST WORD: these three blocks re-declare selectors above at the same specificity, so they come last (rules.test).
   Reduced motion is ONE block, every clock; the infinite pulses stop outright, as a loop at 1ms strobes */
@media (prefers-reduced-motion: reduce) {
  body { --slide: 1ms; --fade: 1ms; --tap: 1ms; --handover: 1ms; --reveal-open: 1ms; --reveal-shut: 1ms; --wake: 1ms; }
  /* a reroute's ping is motion and nothing else: not drawn; its pins and chip simply appear */
  #rewind[data-scrubbed] .rewind-live .icon, .ck-sign.over, .loader::before, .loader::after,
  .reroute-chip > div { animation: none; }
}
/* touch: every target grows to a thumb. `pointer: coarse` is the PRIMARY input, so a trackpad laptop stays as it is */
@media (pointer: coarse) {
  .mapboxgl-ctrl-group button { width: var(--thumb); height: var(--thumb); display: grid; place-items: center; }
  /* the drive pill: a thumb's 44 px on a tablet too (the chip is 22 tall); the phone's is a 44 px plate */
  body:not(.phone) .key-hint[data-run]::before { content: ''; position: absolute; inset: -11px -4px; }
  .mapboxgl-ctrl-group .icon { margin: 0; }
  /* the where-am-I button, the scale bar's unit switch, the Overlays' eyes and a row's ✕ (as tall as its row, no taller:
     the panel's one destructive verb must not take the neighbour's tap) and the promotion bar's frames and chevron */
  .mapboxgl-ctrl-top-right button, .mapboxgl-ctrl-bottom-right button, #overlays-list .show, #overlays .overlays-row button,
  .nato-sw, .nato-chev { min-width: var(--thumb); min-height: var(--thumb); }
  .nato-amp :is(select, .nato-tog), .nato-q { min-height: var(--thumb); } /* the drawer's two fields and two toggles, and the field in its row */
  .nato-tog { min-width: var(--thumb); } /* HQ is two letters */
  .mapboxgl-ctrl-scale { min-height: 30px; line-height: 28px; padding: 0 8px; position: relative; }
  .mapboxgl-ctrl-scale::before { content: ''; position: absolute; inset: -8px -2px; } /* 44 to a thumb (its 28 px padding box + 16), the ruler stays 30 */
  /* a card's verbs (44px squares, eight at most) left "Cruiser …" of a 380px card's name: the name takes the first
     line, the pill the second; --chrome-h is 16 + 6 + 44 + 6 */
  .ar-head { flex-wrap: wrap; }
  .ar-label { flex: 1 0 100%; line-height: 16px; white-space: nowrap; display: block; } /* its own line: one, as --chrome-h counts it */
  body { --chrome-h: 72px; }
  /* the time cursor: a 16px rail is not a drag target */
  #rewind .rewind-row { height: 34px; }
  #rewind .rewind-track { height: 32px; }
  #rewind .rewind-track::-webkit-slider-thumb { width: 22px; height: 22px; margin-top: -6px; }
  #rewind :is(.rewind-play, .rewind-shut) { width: 40px; height: 40px; position: relative; }
  #rewind :is(.rewind-play, .rewind-shut)::before, #overlays.shut #menu-btn::before { content: ''; position: absolute; inset: -2px; } /* 44 to a thumb, the bar unchanged */
  /* the Overlays's rows: 205 tab stops stacked touching, where 2.5.8's spacing cannot save an under-size target */
  #rewind .rewind-live, #overlays-list .overlays-row, #overlays-list details > summary, #overlays #overlays-list a,
  #overlays-list button.overlays-row.more, #overlays-list details > button.overlays-row.more { min-height: var(--thumb); } /* "Show all": its own 24 outranked a bare row's */
  body { --row-h: 44px; } /* windowed rows are PLACED at the pitch: a min-height alone overlapped them */
  #performance button { width: 36px; height: 36px; margin: -6px -6px -6px 0; position: relative; }
  #performance button::before { content: ''; position: absolute; inset: -4px; } /* 44 to a thumb, the row unchanged */
  /* the ☰ beside the panel's title, the same square it is when the panel is shut */
  #overlays:not(.shut) #menu-btn { width: var(--thumb); height: var(--thumb); }
  /* A CONTROL 40 INSIDE A 44 PLATE'S 2px RIM (a pill's segment, the shut ☰, the search circle): the rim is the
     control's too, the pill unclipped for the hit areas and its ends rounded so a press's wash stays inside. Not the
     phone's fan (::after is its name) nor a vertical stack (GL JS's, 44 already). shortcut: a HIDDEN first segment leaves
     the next one square, a press's wash 6 px past the curve */
  body:not(.phone) .pill-button-bar:not(.vertical) { overflow: visible; }
  body:not(.phone) .pill-button-bar:not(.vertical) > button { position: relative; }
  body:not(.phone) .pill-button-bar:not(.vertical) > button::after { content: ''; position: absolute; inset: -2px 0; }
  body:not(.phone) .pill-button-bar:not(.vertical) > button:first-of-type { border-start-start-radius: calc(40px / 2); border-end-start-radius: calc(40px / 2); }
  body:not(.phone) .pill-button-bar:not(.vertical) > button:last-of-type { border-start-end-radius: calc(40px / 2); border-end-end-radius: calc(40px / 2); }
  body:not(.phone) #searchbar .search-q { width: calc(100% + 4px); height: var(--thumb); margin: -2px; } /* its words 2 px nearer the glyph */
  /* the pen's pill (draw.js): a touch screen's alone, at the map's foot over the armed pen's surface */
  body.drawing .draw-touch { display: flex; gap: 4px; padding: 2px; position: fixed; z-index: var(--z-float); left: calc((100% - var(--dock, 0px)) / 2); translate: -50% 0;
    bottom: calc(24px + max(var(--sheet, 0px), var(--homeb, env(safe-area-inset-bottom, 0px)))); border-radius: var(--radius-full); } /* over the map: a card's sheet under it counts (it holds the inset then) */
  .draw-touch > button { min-width: 72px; height: var(--thumb); padding: 0 16px; border: none; background: none; cursor: pointer;
    border-radius: var(--radius-full); color: var(--text-ink); font: 600 14px/1 var(--font); }
  /* the phone's pen pill clear of the Performance chip under it (it hid the chip's words and its ⌃) */
  body.phone .draw-touch { bottom: calc(48px + max(var(--sheet, 0px), var(--homeb, env(safe-area-inset-bottom, 0px)))); }
  /* a tablet's fan names its circles under the row, as the phone's over its pill: touch has no hover, and two are cars side on */
  body:not(.phone) .place-fan > .place::after { content: attr(data-name); position: absolute; top: calc(100% + 10px); left: 50%;
    translate: -50% 0; white-space: nowrap; pointer-events: none; color: var(--text-ink); font: 600 12px/1 var(--font);
    text-shadow: 0 0 3px var(--surface-panel), 0 0 6px var(--surface-panel); }
  /* …and its lead the 44 its row's segments get (.pill-button-bar > button::after does not reach into the fan) */
  body:not(.phone) .place-fan > .place-lead { position: relative; }
  body:not(.phone) .place-fan > .place-lead::after { content: ''; position: absolute; inset: -2px 0; }
  /* a tablet's top row under its status bar (viewport-fit=cover): the ☰, the tools and GL JS's stack clear the inset */
  body:not(.phone) :is(#overlays, #toolbar) { top: calc(20px + env(safe-area-inset-top, 0px)); }
  body:not(.phone) .mapboxgl-ctrl-top-right { top: env(safe-area-inset-top, 0px); }
  /* the place fan's five a thumb apart on a tablet as on the phone: 36 apart, a tap 20 px off a circle's centre armed its neighbour */
  body:not(.phone) .place-fan { --slot: 44px; }
  body:not(.phone) .place-fan > .place::before { content: ''; position: absolute; inset: -6px 0; }
  /* hit areas round glyphs that stay small, so the card's own layout never grows */
  :is(.callout-x, .ar-pin, :is(.ar-cam, .cam-card) .corner-x, .cam-keep)::before { content: ''; position: absolute; }
  .callout-x::before { inset: -10px; }
  :is(.ar-cam, .cam-card) .corner-x::before { inset: -4px -4px -16px -16px; } /* 44 inside the box, which clips: 4 px to its corner */
  /* the camera card's 📌 stands a thumb's width from the ✕ (24 px off it, at 52): two 44 px areas side by side, neither
     taking the other's tap — at 4 px apart the ✕'s area covered half the 📌 */
  .cam-keep { right: 52px; }
  .cam-keep::before { inset: -4px -8px -16px -12px; }
  .ar-pin::before { inset: -12px -14px; }
  /* the promotion bar's frames and chevron: 44px squares in a bar widened to hold them */
  body { --nato-w: 400px; }
  /* Settings' slider thumbs (#overlays-list: the dials' own rules come later and would win a tie) */
  #overlays-list .dial-range { height: 22px; }
  #overlays-list .dial-range::-webkit-slider-thumb { width: 22px; height: 22px; margin-top: -9px; }
  /* the seam: 24px to grab, standing 7px over each picture's edge; the hairline stays 2 */
  #ar-seam { width: 24px; margin-right: -7px; }
  #ar-seam::after { inset: 0 11px; }
}
/* a phone on its side: the control column stood taller than the map. After the coarse block, or it loses on order. A THUMB
   KEEPS 44 (WCAG 2.5.5, the owner's pick 2026-10-31): the column shrinks to 36 for a mouse alone */
@media (max-height: 500px) {
  .zoom-readout { display: none; }
  @media not (pointer: coarse) {
    .mapboxgl-ctrl-group button, .mapboxgl-ctrl-top-right button, .mapboxgl-ctrl-bottom-right button {
      width: 36px; height: 36px; min-width: 36px; min-height: 36px; display: grid; place-items: center; }
  }
  .mapboxgl-ctrl-group .icon { margin: 0; }
}

/* ── Scars ──
   · Cockpit mode first opened the map's frame out over --slide: filmed at a tenth of the speed the map was BLANK the whole
     run — every frame the box moved, our per-container ResizeObserver (maps.js; GL JS 3.32 tracks window resize only)
     cleared the canvas and the redraw landed a frame later → the box steps once, under something that moves by
     transform. The column's own `right` transition no longer blanks it: GL is held for the slide and resized once (arview.js
     slide/land). Measured 2026-10-31 (a private Chrome, 6 runs): an H slide costs 0.44 ms of layout a frame (~22 layouts a
     frame, 11 ms a slide) where the same slide snapped costs 0.01; no transform keeps a box whose width changes, so the
     glide stays (snapping is the owner's call). The Overlays' 0.5 ms a frame is fold()'s height, by design, not a transition.
   · The column FLOATED on the map as tall as its cards for an afternoon (2026-10-22: one card left 888 of 1,064 px of
     column bare) → the owner: "go back to the old style" — the map beside the cards, the column the window's height.
     Don't re-propose a column over the map; the bare desk under one card is the price of the map never being covered.
   · A full-window map CLIPPED to the desk (clip-path, the frame as ::after, the camera's padding following the cards)
     cost frame rate, repaints and Δt the owner saw at once (the canvas drew under the cards, the padding tween read
     computed styles on every body mutation). Reverted: "not worth it".
   · Everything under the picture is ONE token: the sheet wrote .ar-head's 24px + margin as a bare 30, and a 44px thumb
     head pushed Close 14px off a 390×844 phone → --headh (arview.js usableFw() reads it off <body>). It forgot the
     command bar (two touch cards in a 748px column measured 864px) → --chrome-h, stepped whole in the coarse block.
   · The time cursor was absolute to the SCREEN's bottom, on a phone INSIDE the bottom sheet, its 16px thumb 26px from
     Close: anything absolute to the viewport's bottom collides with the sheet → #rewind in the tool row. The coarse
     block still grows its rail and thumb: 16px is not a thumb target wherever it lives.
   · 4K at 100 %: `zoom` on <body> alone fails twice — dvh scales with it (a 3780px body on a 2160 screen) and GL JS sizes
     every canvas off getBoundingClientRect, which zoom inflates (a 6659px canvas) → the pictures zoom back to 1 and the
     furniture zooms; a JS writer of client px (tooltip, promotion bar, details card) divides by the same --ui, read off
     <body> because `zoom` does not inherit.
   · The tool row wrapped by a 760px MEDIA query: a card open beside a 1000px map never wrapped, and the shut Rewind was
     forced onto its own line → the row is a query container.
   · The shared hover was `filter: brightness(k)`: a filter multiplies the pixels an element paints, and half the controls
     paint a glyph on nothing (☰, the eyes, every ✕, the transport), so their hover was invisible → an inset wash of
     currentColor: one number, no night twin.
   · Coarse-pointer rules sat at the same specificity as rules further DOWN this file and lost on order (a 24px ✕ where 44
     was written) → a coarse override of something declared later carries the panel's id, or the base rule reads a
     variable the block sets.
   · H took the column off with display:none while the map's edge eased 280 ms: the ground showed where the column stood
     and the canvas resized every frame (2026-10-04) → it slides away on the clock and GL hold; `--away` is the one
     spelling of "off the screen".
   · The tool row eased its left edge for the Overlays and snapped its right for the cards → both ease on --slide.
   · The search field had `outline: none` under the pill's own :focus-visible ring: a text input matches :focus-visible
     on a click, and the later global input rule outranked the none → two rings. Border ink on focus, no ring
     (2026-10-08).
   · Sixteen :hover rules sat outside the one (hover: hover) guard: on a phone each stayed lit after a tap until the next
     tap landed elsewhere (2026-10-21) → one block under the one query, before the last-word blocks; rules.test fails on
     a :hover outside it. Mirror mode's wake keeps its :hover by name.
   · The boot loader's caption went (the owner, 2026-10-25: "Just the loader ring icon on top is enough"). It had sat in
     a phone's lower half: a place-items: center grid stretches its two implicit rows over the box (align-content packs).
   · Every slider rule's ::-moz-range-* twin went (2026-10-23, the owner's tick): the app meets Chrome and WebKit only, and
     a Firefox visitor's slider falls back to its own look and still works.
   · The two pictures stood 10 px in with the desk's 2 px frame and 22 px radii: on a 390 px phone 44 px of desk across —
     "wasted space on top, bottom, left and right" (the owner, 2026-10-15) → edge to edge, the 8 px gap the only seam;
     --homeb lifts the map's foot off the home indicator only when the map's foot is the screen's.
   · The Rewind's strip as `#rewind .rewind-bar` lost to the later row-container block (the same selector): one 44px line,
     the lane 168px. Chrome answers a size query with no container ancestor as if it matched → the strip's rules carry
     body.phone.
   · The desk's capture of the map for the phone prototypes carried the desk's 2px frame inside the pane's → every pane is
     the picture's edge, and the picture is whatever the pane's shape is (no aspect-ratio).
   · The search pill floated centred on the map, kept clear of the row and the control stack by hand-written pixel sums
     (234/304/492/562) a fourth button or a resized column broke → a flex item of #toolbar: the row bounds it.
   · #performance's chevron pointed where the box came from; the owner: it points where the box will go. The owner also
     put the hero unit on its number's line and each cost gauge between its name and its reading.
   · #performance shut stood 8px taller below its readout: the folded drawer's padding-top held its 0fr row open → the
     padding comes in with .open.
   · The owner (2026-10-13): the stick on the map's lower-left with the readout under it, the scale bar bottom-right under
     the ⊕, the handbrake cut (the stick pulled back brakes), the card's bar to the picture's lower-right, and a ✕ on the
     picture that is H — the drive goes on on the map. The same round's two kept ideas: the sheet snaps half/full and
     remembers, the chrome goes quiet through a drive.
   · The drive pad was five round buttons for a car only → the racing game's layout (a steering plate whose pointer picks
     the half, pedals shaped like pedals) and a stick for the man; with it up on a phone the control column goes, or the
     throttle sat on its locate button.
   · The SELECTED capsule's `position: relative` carried the :is() list's top specificity: the fixed ⊕ went relative when
     its fan opened, dropped to (-20, -56) and could not fold (2026-10-18) → the capsule positions a host at :where(&).
   · The desk's sliding pick (theme/glass slidePick) assumes a ROW: in the phone's fan (a column) an armed tool drew one
     dark band behind the whole column (2026-10-24) → the phone puts the pick away and the armed circle joins SELECTED's
     list inside :where(); the bar's `background: none` still left its glass blur and shadow over the 48×288 column → no
     plate.
   · SELECTED was a lifted white capsule while the AoI board wore the highlight; the owner (2026-10-24): "standardize to
     the whole app, so that it's uniform everywhere" → selected, hovered, pressed and a list's current row read
     line.highlight's washes, the map's selection glow its lit cyan; a new control never paints a pick of its own. Its
     capsule stood 3px inside the rim; the owner (2026-10-25): "less padding than what we have in the prototype" →
     --highlight-inset 5px, the board's 30px ring 7px inside the outer edge.
   · The card bar's lit button was a circle 5 px in, then a cell 2 px in with --radius-m corners, then edge to edge (reverted
     the same hour): each "felt off" (the owner, 2026-10-27) → the AR Bar Highlights playground (six variants off Apple's and
     Google's guidance) and the owner's pick C: a tinted capsule 3 px in, no edge, lit runs joined, Close in its own circle.
   · `html { overflow: clip }` is the VIEWPORT's `hidden` on the root, which code still scrolls, and body's own clip
     missed the absolute boxes hung off the root (the parked pane, 1083 px of an 844 px phone): a scrollIntoView lifted
     the whole app 239 px (2026-10-26) → body is `position: relative`, their containing block, and clips them.
   · The phone's vehicle column added env(safe-area-inset-bottom) to --sheet + --homeb, which carry it already: on a notched
     iPhone it stood ~34 px over the ⊕ fan it lines up with (2026-10-27, the live run, read off the CSS) → #toolbar's sum.
   · The camera readout ran nowrap under the Performance pill on a narrow map (iPad portrait with a card: 456 px of map, the
     line clipped to "…40° / 62° / 1.3 km…"; 2026-10-27, the live run) → the bottom-right corner keeps 270 px clear and the
     line wraps there; a wide map keeps it on one line (laptop measured 12 px tall).
   · A phone on its side has its notch at a side edge (~47 px): the ⊕, its fan, the vehicle column and Rewind's strip
     stood 16–24 px from the screen's edge, under it (2026-10-29, read off the CSS) → each adds env(safe-area-inset-*).
   · The road camera's ✕ over a card's pod was 24 px under a thumb (2026-10-29) → a ::before to 44, inside the camera's
     box: it clips, so a centred hit area would lose 7 px at the corner.
   · On an iPad (a thumb, not a phone) the pills' segments, the shut ☰ and the search circle were 40 inside a 2px rim the
     plate kept, and Show all 24 tall (2026-10-29) → under a thumb the rim is the control's (the pill unclipped, a hit area
     over it, its ends rounded for the press), Show all 44. A ::before was the house pattern, but a segment's ::before is
     THE HIGHLIGHT and the pill's clip ate anything past it.
   · Overlays and a card open on an iPad left the tool row 232 px: tools, then the vehicle's bar with the clock, then the
     search alone on a third line (2026-10-29) → under 500 px the circles keep the tools' line (`order`).
   · The card's name had 96 px beside its bar and the ✕'s own circle, "Cruiser WTPD…" at 1440 (2026-10-29) → two balanced
     lines in the bar's 44 px height; under a thumb it keeps its one line of its own.
   · The AoI dial and the ping wheel were not in the --ui zoom list: 256 px and 12 px words at 4K (2026-10-29) → its parts
     zoom, as a key chip's do.
   · A soldier's slot stood at the phone map's right edge under the vehicle's column and the ⊕ (2026-10-29, the live run): the
     pistol's tap armed the nav tool, the sights' opened the fan → the slot stands left of the column, 88 px in, any kind driven.
   · An iPad in portrait with the Overlays and a card open left the tool row 76 px (2026-10-29): the tools ran under the card,
     the vehicle's bar over the map's controls → under the tools' pill (180 px) the row stands down while the panel is open.
   · The promotion bar's frames sat OUTSIDE its pill until 2026-09-07 (two objects to keep in line, a width that changed as you
     typed, a tail to say which pointed at the building), then on an opaque plate until 2026-10-17: the frames are read as
     colours a translucent plate shifts, a cost the owner accepted off four prototypes → one pill of the liquid glass.
   · SELECTED was an ink slab ("too dark, in your face", 2026-10-17) before the white capsule the entry above replaced.
   · Rule comments told each incident's story again beside its rule (1,240 comment lines of 3,190, 2026-10-31) → a rule's
     comment is its one-line why; the story, once, here.
   · Deep scan 2026-11-01, the live run: an iPad upright docked its card over the open Overlays' rows (the panel capped to the
     window, the card to the sheet) → the panel caps to the map, --sheet included; the camera card's ✕ and 📌 were 24 px,
     4 apart, under a thumb → 44 px areas side by side, the 📌 moved 20 px off; a track row's meta cut "9131 km" at half the
     row counting its 28 px pad → half for the words; Rewind's strip HID the ⊕ and the scale bar → they rise by --strip.
   · A phone in a satellite's HUD could not leave it (deep scan 2026-11-01): #ck-exit stood under the pill's compass (a tap faced
     north), the pill had no ✕ for a track with no card, and the pill and an open Rewind strip covered the corner chips and the S mark →
     the cockpit takes the phone's chrome off as it takes the desk's, and the ✕ stands at the right edge's middle.
   · On its side with a card up the vehicle's column stood over the AR picture while the ⊕ moved to the map's half → it moves too.
   · On a 390 px phone the ⊕ stood over the right edge of the open Performance drawer's rows (2026-11-01) → it steps aside while
     the drawer is open, as under the NATO bar; the drawer keeps its 300 px.
   · 2026-11-02: on a phone a car's card pill started at the picture's middle and ran 37 px over the minimap disc (390 px: pill
     195–330, disc 293–377) — the floated .ar-head was still an inline-size container, which sizes it to 0 wide, so translate 50%
     moved nothing and the pill overflowed from its edge → no container there (its one query hides .ar-info, gone on a phone).
   · 2026-11-02: a phone on its side (844×390) with a vehicle picked stood its column (four 48 px circles, 12 apart, from 128 px
     over the foot) at 34–262 px, over the pill's ✕ at 24–68: the tap meant to let the track go started the mic → on its side the
     column is the fan's thumb and 4 px gap, held under the pill, and wraps leftward past that.
   · 2026-11-02: at 3840 an AR view's dial grew to 204 px with the card while its unit and end figures stayed 12 px (net zoom 1
     in the picture, 21 px is the shell's floor there) → they are sized off --g as the numeral is, 12 at the dial's 95 px floor.
   · 2026-11-02: 1280×720, a car's card and Rewind open: the row (736 px, the vehicle bar in it) passed the 700 px query and the
     bar's min-width 0 squeezed it to 266 px of its 344, "live" and ✕ under the search circle (a click on ✕ opened the search)
     → no min-width: short of its controls the bar wraps; folding it is overflow-hidden, whose automatic minimum is 0.
   · 2026-11-02 touch scan: a phone card's gauges sat under the home indicator (speedometer 741–837 of 844, the limit sign to
     846) while only the minimap disc was lifted, and on its side the right gauge under the notch → the gauges lift (the disc
     rides its pod: its own lift would double), the pill centred between them; mirror mode lifts off both sides.
   · 2026-11-02 touch scan: on its side the sheet's notch inset was padding INSIDE min(360px, 50vw), and the head's five buttons
     shrank to 37–38 px → the inset adds to the width, the buttons never shrink, the title ellipsises.
   · 2026-11-02 touch scan: the scale bar's unit switch was a 30 px target under a thumb, the NATO drawer's fields and toggles 33
     and 28 → 44 by a ::before (GL JS leaves the ruler static: position relative) and min-heights.
   · 2026-11-02 touch scan: GL JS's #eee button hover stood outside any hover query; on a tablet a tap's hover sticks, and at
     night the stack's ? was a near-white glyph on #eee (1.03:1) until the next tap → off, ours under (hover: hover).
   · 2026-11-02 touch scan: an upright iPad's card bar ended at 1014 of 1024, in its 20 px home indicator → the column's foot
     clears the inset; the upright sheet counts it, the card's height does not.
   · 2026-11-04 scan: the phone's place fan put its five 36×32 circles 40 px apart, under a thumb's 44 → slots of 44 and a
     ::before to 44×44 round each circle; the circles and the inner pill's look unchanged, the pill 20 px longer.
   · 2026-11-04 round four: the thumb's tilt made every picture pan-x, so a tablet's side column no longer scrolled under one →
     a kept card's picture is pan-y there (the strips keep pan-x); and an upright tablet's strip of three docked flex-end, its
     overflow off the START where no scroll reaches: the live card at x −972 for good → safe flex-end.
   · 2026-11-04 polish review: the side-on phone's wrapped column printed its names over each other, the pen pill hid the
     Performance chip, Keep/Wipe gave no press, the day captions stayed 2.9:1, a tablet's fan had no names and its lead a 44×40
     hit area, and a tablet's top row sat under its status bar → each its rule above.
   · 2026-11-04 round six: the pen's pill, fixed to the window, stood 48 px off the screen's foot with a card up — on the AR
     picture, under the map's foot (--sheet), and centred on the window over a side-on card column (--dock) → its bottom counts
     the sheet, which holds the inset then, and its middle is the map's.
   · 2026-11-05 a11y scan: the APP-6E bar's folded drawer (0fr, clipped) kept four controls in the Tab order, focused unseen →
     visibility hidden once the fold lands; the focused main map showed no ring (.mapboxgl-map's overflow clipped one drawn
     outside the canvas) → its ring 2 px inside. */
