/* ===========================================================================
   Hero globe (Phase 1, 2026-04-26)
   ---------------------------------------------------------------------------
   Full-viewport interactive 3D globe that sits between the masthead and the
   rest of the page. globe.js hydrates `#globe-canvas` with a Three.js scene;
   this stylesheet only owns the geometry of the wrapper plus the two text
   overlays (hint at the bottom, country label at the top).
   Phase 2 will overlay a sliding right-side panel on top of `.globe-hero`,
   Phase 3 will wire responsive sizing rules. (prefers-reduced-motion is
   now handled in JS — see globe.js / globe-panel.js — because the
   relevant motion is OrbitControls auto-rotate + the WebGL mesh morph,
   neither of which a CSS transition rule can reach.)
   =========================================================================== */
.globe-hero {
  position: relative;
  width: 100%;
  height: 100dvh;
  overflow: hidden;
  background: var(--bg);
}
.globe-hero__canvas {
  position: absolute;
  /* Phase 3 Step 1 (2026-04-28): canvas top inset = topbar-float
   * collapsed height (~64px) so the globe's render area starts BELOW
   * the floating bar. The bar itself is `position: fixed` and z-indexed
   * above the canvas, so it floats over even the canvas's own padding
   * area at the very edge. Bottom/left stay 0; right is overridden by
   * the panel-state="open" rule. */
  /* Canvas top inset = topbar-float collapsed height (~64px) so the globe's render
   * area starts just below the floating bar (its original default framing). */
  inset: 64px 0 0 0;
  display: block;
  /* Three.js writes a <canvas> child here. Cursor signal hints
     drag-to-rotate before the user reads the bottom hint copy. */
  cursor: grab;
}
.globe-hero__canvas:active { cursor: grabbing; }

/* Cesium viewer chrome (Cesium migration, 2026-06-21). The Viewer injects a
   .cesium-viewer > .cesium-widget > canvas stack into #globe-canvas; fill the
   mount, drop Cesium's default black background to our page bg, and reduce the
   credit furniture to a tiny NASA/GIBS line (logo + expander hidden — no Ion
   assets in use). */
#globe-canvas .cesium-viewer,
#globe-canvas .cesium-widget,
#globe-canvas .cesium-widget canvas {
  width: 100%;
  height: 100%;
  display: block;
}
#globe-canvas .cesium-viewer,
#globe-canvas .cesium-widget { background: var(--bg); }
#globe-canvas .cesium-widget canvas { cursor: inherit; }
#globe-canvas .cesium-viewer-bottom { right: 10px; bottom: 6px; left: auto; }
#globe-canvas .cesium-widget-credits,
#globe-canvas .cesium-credit-container {
  font-size: var(--text-2xs);
  opacity: 0.6;            /* legible — Esri / EOX licences require visible attribution */
  color: var(--ink-dim);
}
#globe-canvas .cesium-credit-container a,
#globe-canvas .cesium-widget-credits a { color: var(--link, currentColor); }
/* (Glass Terminal, 2026-07-11) The Cesium engine writes inline `display` on both
   of these itself — the logo container once at construction
   (`u.style.display="inline"`) and the expand link every frame in
   CreditDisplay.endFrame() (`_expandLink.style.display = t.length ? "inline"
   : "none"`). An inline style outranks every selector, so `!important` is the
   ONLY thing that keeps the Ion logo + "Data attribution" expander suppressed
   (only the licence-required NASA / GIBS / Esri / EOX text-credit line should
   remain). design_lint flags this because `display` is normally JS-inline-owned;
   here the JS is Cesium's and hiding its furniture is the intent — the
   !important is load-bearing, not vestigial. Verified against vendor/cesium. */
#globe-canvas .cesium-credit-logoContainer,
#globe-canvas .cesium-credit-expand-link { display: none !important; }

.globe-hero__country-label {
  /* Centred over the globe — only visible while a country is hovered.
     Editorial serif lockup matches the rest of the brand voice (no UI
     chrome, no chip background).
     D2a (2026-07-07): dropped BELOW the top-centre chip bar so the hover
     label, the chip bar and the (now top-right) brief no longer triple-stack
     in the top-centre zone. --globe-top is the chip-bar row (84px); + the
     chip pill height (~24px) + a gutter clears it. */
  position: absolute;
  top: calc(var(--globe-top) + 24px + var(--globe-gutter));
  left: 50%;
  transform: translateX(-50%);
  font-family: var(--font-serif);
  font-size: var(--text-2xl, 28px);
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--ink);
  /* (Glass Terminal, 2026-07-11) The hover label now rides in a subtle glass
     pill. It TRACKS the hovered country under the cursor, so it is tint-only
     (tier-2, NO backdrop-filter — a per-frame blur would jank the hover); the
     kept text-shadow carries legibility over bright imagery. There is no
     coordinate child in this label (country name only), so the "mono coords"
     treatment lands on .globe-sst-tip instead. */
  padding: var(--sp-1) var(--sp-4);
  border-radius: 999px;
  background: var(--glass-2-bg);
  border: 1px solid var(--glass-hairline);
  box-shadow: var(--shadow-2), inset 0 1px 0 var(--glass-highlight);
  pointer-events: none;
  opacity: 0;
  transition: opacity var(--dur-base) var(--ease, ease-out);
  text-shadow: 0 1px 0 var(--bg);
  white-space: nowrap;
  max-width: 60vw;
  overflow: hidden;
  text-overflow: ellipsis;
}
.globe-hero__country-label.is-visible { opacity: 1; }

/* Environment-layer chip bar (B1c) — top-centre, below the floating topbar. */
.globe-layers {
  position: absolute;
  top: var(--globe-top);   /* D1: shared top grid line, snapped below the topbar (was 82px) */
  left: 50%;
  transform: translateX(-50%);
  z-index: var(--z-globe-3);
  display: flex;
  gap: 3px;
  padding: 3px;
  border-radius: 999px;
  /* (Glass Terminal, 2026-07-11) tier-1 glass. Opaque fallback first; the shared
     @supports block (near the status stamp) adds translucency + ONE backdrop
     blur for the whole pill (was an unconditional blur(8px) + 92% mix). Trio =
     1px hairline + inset top highlight + tier shadow. */
  background: var(--glass-1-fallback);
  border: 1px solid var(--glass-hairline);
  box-shadow: var(--shadow-2), inset 0 1px 0 var(--glass-highlight);
}
.globe-layer-chip {
  font: inherit;
  font-size: var(--text-xs);
  line-height: 1;
  padding: 4px 9px;
  border-radius: 999px;
  /* 1px transparent border in the rest state reserves the box so the selected
     state's 1px border (below) can't nudge the pill by a hair. */
  border: 1px solid transparent;
  background: transparent;
  color: var(--ink-dim);
  cursor: pointer;
  white-space: nowrap;
  transition: color var(--dur-fast) var(--ease), background-color var(--dur-fast) var(--ease),
              border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease);
}
.globe-layer-chip:hover { color: var(--ink); background: color-mix(in srgb, var(--ink) 8%, transparent); }
/* W#6 — the SELECTED base-layer chip / open Layers toggle no longer uses the red
   accent family (a big red fill collided with danger / surge "alert" semantics).
   Selected now reads as an ink-on-glass INVERSION: a high-contrast keycap fill
   (--ink text colour, --bg text) so it is instantly scannable as "this one is
   active" over any imagery, finished with a lit top edge + a whisper of lift.
   Accent is reserved for focus rings + the layer-count badge (scarce = premium). */
.globe-layer-chip[aria-checked="true"],
.globe-layer-chip[aria-pressed="true"],
.globe-data-layers__toggle[aria-expanded="true"] {
  background: var(--ink);
  color: var(--bg);
  border-color: var(--ink);
  box-shadow: 0 1px 2px var(--scrim-15), inset 0 1px 0 var(--glass-highlight);
}
@media (max-width: 640px) {
  .globe-layers { flex-wrap: wrap; max-width: 92vw; justify-content: center; top: 70px; }
  .globe-hero[data-panel-state="open"] .globe-layers { display: none; }
}

/* Data-layer "Layers" popover trigger — sits inline in the base-imagery chip bar,
   right of Sea temp, separated by a hairline divider. Independent toggles inside. */
.globe-data-layers {
  position: relative;
  display: inline-flex;
  align-items: center;
  z-index: var(--z-globe-4);
}
.globe-data-layers::before {
  content: "";
  width: 1px;
  height: 14px;
  margin: 0 4px 0 1px;
  background: var(--border);
}
/* D4b — the toggle hosts the text + the active-layer count badge inline. */
.globe-data-layers__toggle { display: inline-flex; align-items: center; gap: 5px; }
.globe-layer-badge {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 15px; height: 15px; padding: 0 4px;
  border-radius: 999px;
  background: var(--accent);
  color: #fff;
  font-size: var(--text-3xs); font-weight: 600; line-height: 1;
  font-variant-numeric: tabular-nums;
  /* When the toggle itself is active (popover open) it's already accent-filled,
     so flip the badge to a contrasting light chip so it stays legible. */
}
/* On the ink-inverted open toggle, an accent (or white) badge would clash; flip
   it to a surface chip (--bg fill + --ink text) that stays legible on the ink field. */
.globe-data-layers__toggle[aria-expanded="true"] .globe-layer-badge {
  background: var(--bg); color: var(--ink);
}
.globe-layer-badge[hidden] { display: none; }
.globe-data-pop {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  min-width: 184px;
  padding: 4px;
  border-radius: var(--r-md);
  /* (Glass Terminal, 2026-07-11) tier-3 glass. This popover already blurred the
     globe behind it (audit #25 allowed it here); now tokenised with an opaque
     fallback + hairline + 1px inset highlight + tier-3 shadow. The backdrop blur
     moves into the @supports block below. */
  background: var(--glass-3-fallback);
  border: 1px solid var(--glass-hairline);
  box-shadow: var(--shadow-3), inset 0 1px 0 var(--glass-highlight);
  /* The popover opens downward inside `.globe-hero`, which is overflow:hidden
   * and shrinks to 40vh / min 240px on phones (see the `max-width: 520px`
   * rule) — without a cap the lower toggles (Ship traffic / Dark vessels /
   * Ports) get clipped by the hero and can't be reached. Cap the height and
   * let the rows scroll. The trigger sits ~110px below the hero top, so on the
   * 240px-min hero this leaves ~120px of scrollable list; the min(...) keeps
   * it from ever exceeding the viewport on taller heroes/desktop. */
  max-height: min(60vh, calc(100vh - 140px));
  overflow-y: auto;
  overscroll-behavior: contain;
}
@supports ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
  .globe-data-pop {
    background: var(--glass-3-bg);
    -webkit-backdrop-filter: blur(var(--glass-3-blur)) saturate(var(--glass-sat));
    backdrop-filter: blur(var(--glass-3-blur)) saturate(var(--glass-sat));
  }
}
.globe-data-pop[hidden] { display: none; }
.globe-data-pop__item {
  display: grid;
  grid-template-columns: auto auto 1fr auto;
  grid-template-areas: "cb sw label period" "cb sw hint opacity";
  column-gap: 8px;
  align-items: center;
  padding: 5px 8px;
  border-radius: var(--r-sm);
  cursor: pointer;
}
.globe-data-pop__item:hover { background: color-mix(in srgb, var(--ink) 7%, transparent); }
.globe-data-pop__item input[type="checkbox"] { grid-area: cb; accent-color: var(--accent); width: 14px; height: 14px; }
.globe-data-pop__label { grid-area: label; font-size: var(--text-xs); color: var(--ink); line-height: 1.25; }
.globe-data-pop__hint { grid-area: hint; font-size: var(--text-2xs); color: var(--ink-dim); line-height: 1.2; }
/* G7: period/window select archetype — bg-elev-2 + 1px --border + --r-sm (was bg-elev-1 + --r-md). */
.globe-data-pop__period {
  grid-area: period; align-self: center; justify-self: end; margin-left: 10px;
  font: inherit; font-size: var(--text-2xs); padding: 2px 4px; cursor: pointer;
  background: var(--bg-elev-2); color: var(--ink);
  border: 1px solid var(--border); border-radius: var(--r-sm);
}
/* Per-layer legend swatch (the colour the layer draws in). A 1px hairline gives
   each colour chip a crisp edge on the glass surface. */
.globe-data-pop__sw {
  grid-area: sw; align-self: center; width: 12px; height: 12px;
  border-radius: 3px; border: 1px solid var(--glass-hairline); flex: none;
}
.globe-data-pop__sw--density { background: linear-gradient(135deg, #440154, #21918c, #fde725); }
.globe-data-pop__sw--breaking { background: #ff3b6b; border-radius: 50%; }
.globe-data-pop__sw--trade { background: #3987e5; }
.globe-data-pop__sw--ships { background: #38bdf8; }
.globe-data-pop__sw--darkships { background: #e879f9; }
.globe-data-pop__sw--portwatch { background: #f5b301; }
/* Per-layer opacity slider (raster/fill layers only). */
.globe-data-pop__opacity {
  grid-area: opacity; align-self: center; justify-self: end;
  width: 72px; margin-left: 10px; cursor: pointer; accent-color: var(--accent);
}
/* Inline in the chip bar now — hides with the bar on mobile when a panel opens
   (the .globe-layers rule already covers it); the popover drops downward. */

/* Reset-view button — bottom-right of the world view; hidden while a panel is
   open (you're zoomed into a country then, with other ways back). */
.globe-reset {
  position: absolute;
  right: var(--globe-gutter);              /* D1: right grid line (was 18px) */
  /* 2026-07-08: lifted +12px so the bottom-right feedback FAB (bottom:--sp-5,
     ~40px tall → top ~64px) clears the pill stack (=72px, was 60px). */
  bottom: calc(var(--globe-gutter) + 56px);
  z-index: var(--z-globe-3);
  width: 38px;
  height: 38px;
  display: grid;
  place-items: center;
  padding: 0;
  border-radius: 999px;
  /* (Glass Terminal, 2026-07-11) tier-1 glass circle. Opaque fallback ships
     first; the shared @supports block (near the status stamp) layers
     translucency + backdrop blur. This supersedes audit #25's blur-drop — it is
     now a progressive enhancement with an opaque fallback + the local
     prefers-reduced-transparency gate (the @media block just after that shared
     @supports), so unsupported / low-power paths stay opaque; Wave 3 measures the
     on-drag recompute of the two small circles. */
  background: var(--glass-1-fallback);
  border: 1px solid var(--glass-hairline);
  box-shadow: var(--shadow-2), inset 0 1px 0 var(--glass-highlight);
  color: var(--ink-dim);
  cursor: pointer;
  transition: transform var(--dur-fast) var(--ease-out),
              box-shadow var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease);
}
.globe-reset:hover {
  color: var(--ink);
  transform: translateY(-1px);
  box-shadow: var(--shadow-3), inset 0 1px 0 var(--glass-highlight);
}
.globe-reset:active { transform: scale(0.96); }
.globe-reset:focus-visible { outline: none; box-shadow: var(--focus-ring), var(--shadow-2); }
.globe-hero[data-panel-state="open"] .globe-reset { display: none; }

/* "My location" toggle — same pill as reset, stacked just above it. */
.globe-geo {
  position: absolute;
  right: var(--globe-gutter);               /* D1: right grid line (was 18px) */
  /* 2026-07-08: +12px in lock-step with .globe-reset's FAB-clearance lift
     (stacked one button+gap above it → =116px, was 104px). */
  bottom: calc(var(--globe-gutter) + 100px);
  z-index: var(--z-globe-3);
  width: 38px;
  height: 38px;
  display: grid;
  place-items: center;
  padding: 0;
  border-radius: 999px;
  /* (Glass Terminal, 2026-07-11) tier-1 glass circle — matches .globe-reset;
     opaque fallback + shared @supports blur below (supersedes audit #25). */
  background: var(--glass-1-fallback);
  border: 1px solid var(--glass-hairline);
  box-shadow: var(--shadow-2), inset 0 1px 0 var(--glass-highlight);
  color: var(--ink-dim);
  cursor: pointer;
  transition: transform var(--dur-fast) var(--ease-out),
              box-shadow var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease),
              background-color var(--dur-fast) var(--ease);
}
.globe-geo:hover {
  color: var(--ink);
  transform: translateY(-1px);
  box-shadow: var(--shadow-3), inset 0 1px 0 var(--glass-highlight);
}
.globe-geo:active { transform: scale(0.96); }
.globe-geo:focus-visible { outline: none; box-shadow: var(--focus-ring), var(--shadow-2); }
/* "My location" ON — same ink-inversion "active" language as the selected layer
   chip (was an accent fill; keeps the red accent out of the persistent
   bottom-right control rail). */
.globe-geo[aria-pressed="true"] { background: var(--ink); color: var(--bg); border-color: var(--ink); }
.globe-geo[aria-busy="true"] { opacity: 0.55; cursor: progress; }
.globe-hero[data-panel-state="open"] .globe-geo { display: none; }

/* Sea-temp colour legend (bottom-CENTRE, above the hint) + cursor probe.
   Centre keeps it clear of the feedback button (bottom-left) AND of both side
   panels (profile left / headlines right) when a country is selected. */
/* Legends stack in one bottom-centre column so multiple active data layers
   (Sea temp / Density / Breaking) never overlap. */
.globe-legends {
  position: absolute;
  /* D1: sit just LEFT of the reset/geo pill column — one gutter + the 38px pill
     + a --sp-3 gap off the right grid line (=66px, now token-derived). */
  right: calc(var(--globe-gutter) + 38px + var(--sp-3));
  /* 2026-07-08: lifted to share the reset pill's baseline (=72px) so the
     bottom-right feedback FAB (~40px tall from --sp-5) can't sit under a legend
     card. The pills sit just to the right; the legends now align to their bottom. */
  bottom: calc(var(--globe-gutter) + 56px);
  z-index: var(--z-globe-3);
  display: flex;
  flex-direction: column;
  gap: 7px;
  align-items: flex-end;
  pointer-events: none;
  /* B2: cap the column so many active layers can't overrun the hero.
   * Hero is overflow:hidden; legends sit bottom:18px and the layers bar
   * occupies the top ~120px, so reserve ~140px. Children have explicit
   * widths, so flex-end + scroll coexist without width:auto handling.
   * The container is pointer-events:none but the trade <select> re-enables
   * pointer-events:auto on itself, so it stays clickable inside the scroll.
   * 2026-07-08: reserve grew 140→196 to match the +56 bottom lift (top
   * clearance under the layers bar is preserved). */
  max-height: calc(100% - 196px);
  overflow-y: auto;
  scrollbar-width: thin;
}
/* Country selected: the LEFT profile panel would sit under a left-anchored legend,
   so mirror the feedback button — it shifts right of the LEFT panel, the legends
   shift left of the RIGHT headlines panel (symmetric, clears both panels). */
@media (min-width: 641px) {
  .globe-hero[data-panel-state="open"] .globe-legends {
    right: calc(max(25vw, 320px) + calc(var(--globe-gutter) * 2));   /* clear the right panel (=+32px) */
    /* 2026-07-08: the panel-open FAB dodges LEFT to this same right offset, so
       keep the legend lifted above it (matches the panel-closed +56 baseline). */
    bottom: calc(var(--globe-gutter) + 56px);
  }
}
.globe-legend {
  width: 166px;
  padding: 7px 10px 6px;
  border-radius: var(--r-md);
  /* (Glass Terminal, 2026-07-11) tier-1 glass — opaque fallback + shared
     @supports blur below (was 82% mix + unconditional blur(8px)); trio edges. */
  background: var(--glass-1-fallback);
  border: 1px solid var(--glass-hairline);
  box-shadow: var(--shadow-2), inset 0 1px 0 var(--glass-highlight);
  pointer-events: none;
}
.globe-legend[hidden] { display: none; }
.globe-legend__pulserow {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: var(--text-xs);
  color: var(--ink-dim);
}
.globe-legend__pulsedot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--surge);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--surge) 30%, transparent);
  flex: none;
}
/* Watchlist legend (feature D): gold ring = watched country, violet dot =
   where watched topics/entities are active. Hues match cesium-globe.js. */
.globe-legend__watchrow {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: var(--text-xs);
  color: var(--ink-dim);
  margin-top: 3px;
}
.globe-legend__watchring {
  width: 11px;
  height: 11px;
  border-radius: 50%;
  border: 2px solid #c8860a;
  flex: none;
}
.globe-legend__watchdot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: #6b4cff;
  box-shadow: 0 0 0 3px color-mix(in srgb, #6b4cff 28%, transparent);
  flex: none;
}
[data-theme="dark"] .globe-legend__watchring { border-color: #ffc24d; }
[data-theme="dark"] .globe-legend__watchdot {
  background: #a690ff;
  box-shadow: 0 0 0 3px color-mix(in srgb, #a690ff 28%, transparent);
}
.globe-legend__title {
  font-size: var(--text-xs);
  color: var(--ink-dim);
  margin-bottom: 5px;
  display: flex; align-items: center; justify-content: space-between; gap: 6px;
}
/* Ship-traffic legend: per-type colour chips + honest coverage notes. */
.globe-legend__chips { display: flex; flex-wrap: wrap; gap: 3px 8px; margin: 1px 0 5px; }
.globe-legend__chips[hidden] { display: none; }   /* [hidden] must beat display:flex (UA [hidden]{display:none} loses to the class) */
/* Sub-caption scoping the type chips to the live AIS points (not the density). */
.globe-legend__sub { font-size: var(--text-2xs); color: var(--ink-dim); margin: 2px 0 3px; opacity: 0.9; }
/* Interactive per-type FILTER buttons (live AIS points). Each is a toggle:
   aria-pressed=false greys the chip + dot + strikes the label (a strikethrough
   reads as "off" without relying on contrast alone). MUST re-enable pointer
   events — the legend is pointer-events:none so globe drags pass through it. */
.globe-ships-chip {
  display: inline-flex; align-items: center; gap: 5px;
  font: inherit; font-size: var(--text-xs); color: var(--ink);
  padding: 1px 8px 1px 6px; cursor: pointer; pointer-events: auto;
  background: color-mix(in srgb, var(--bg-elev-1) 55%, transparent);
  border: 1px solid var(--border); border-radius: 999px;
  transition: opacity var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
.globe-ships-chip::before {
  content: ""; width: 8px; height: 8px; border-radius: 50%;
  background: var(--c, #888); flex: none;
}
.globe-ships-chip[aria-pressed="false"] {
  opacity: .6; color: var(--ink-dim); text-decoration: line-through;
}
.globe-ships-chip[aria-pressed="false"]::before { background: var(--ink-dim); }
.globe-ships-chip:hover { border-color: var(--border-strong, var(--ink-dim)); }
.globe-ships-chip:focus-visible { outline: none; box-shadow: var(--focus-ring); }
/* (Glass Terminal, 2026-07-12) Coarse-pointer tap height for the per-type AIS
   filter chips. The central @media(pointer:coarse) block in 70-aux (audit #65)
   bumps the base-imagery chips / Layers-popover rows / period selects but not
   these legend filters; give them the same 44px floor so a fingertip can toggle
   a vessel type. align-items:center is already set, so the dot+label stay
   centred; the pill radius + horizontal padding are unchanged (visual look
   preserved). Coarse-only → desktop density untouched. */
@media (pointer: coarse) {
  .globe-ships-chip { min-height: 44px; }
}
/* Density colour ramp (turbo): quiet → busy. Shown only when GFW density is on. */
.globe-legend__ramp { display: flex; align-items: center; gap: 6px; margin: 5px 0 1px; }
.globe-legend__ramp[hidden] { display: none; }
.globe-legend__ramp-bar {
  order: 2; flex: 1 1 auto; height: 7px; border-radius: 4px;
  background: linear-gradient(90deg,
    rgba(13,90,138,0.55) 0%, #16b8c0 30%, #7ee06b 50%, #fbd24b 70%, #f5793b 86%, #ef4444 100%);
}
.globe-legend__ramp-lab { order: 1; font-size: var(--text-3xs); color: var(--ink-dim); flex: none; }
.globe-legend__ramp-lab--hi { order: 3; }
.globe-legend__credit { font-style: normal; }
/* Dark-vessel (SAR) legend ramp — magenta, distinct from the turbo density. */
.globe-legend__ramp-bar--sar {
  background: linear-gradient(90deg, rgba(42,15,58,.6) 0%, #a021c4 42%, #e879f9 78%, #fbcfe8 100%);
}
/* PortWatch click-to-detail card (chokepoint/port) — bottom-left floating card. */
.pw-detail {
  position: absolute; left: 14px; bottom: 14px; width: 282px; max-width: 46vw;
  z-index: var(--z-globe-4); pointer-events: auto;
  /* (Glass Terminal, 2026-07-11) tier-3 glass detail card — matches
     .globe-data-pop. Fixed corner (not cursor-tracking), so the @supports blur
     below is safe (recomputes only during a globe drag). */
  background: var(--glass-3-fallback);
  border: 1px solid var(--glass-hairline); border-radius: var(--r-md);
  padding: 11px 13px; color: var(--ink);
  box-shadow: var(--shadow-3), inset 0 1px 0 var(--glass-highlight); font-size: var(--text-xs); line-height: 1.4;
}
@supports ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
  .pw-detail {
    background: var(--glass-3-bg);
    -webkit-backdrop-filter: blur(var(--glass-3-blur)) saturate(var(--glass-sat));
    backdrop-filter: blur(var(--glass-3-blur)) saturate(var(--glass-sat));
  }
}
.pw-detail[hidden] { display: none; }
.pw-detail__close {
  position: absolute; top: 5px; right: 7px; border: 0; background: none;
  color: var(--ink-dim); font-size: 18px; line-height: 1; cursor: pointer; padding: 2px;
}
.pw-detail__kind { font-size: var(--text-3xs); text-transform: uppercase; letter-spacing: 0.08em; color: var(--ink-dim); }
.pw-detail__name { font-size: 15px; font-weight: 600; margin: 1px 0 6px; padding-right: 16px; }
.pw-detail__metric { margin-bottom: 4px; }
.pw-detail__metric b { font-family: var(--font-mono); font-size: 18px; font-weight: 600; font-variant-numeric: tabular-nums; }   /* G8: mono data face */
.pw-detail__metric span { color: var(--ink-dim); }
.pw-detail__row { display: flex; justify-content: space-between; gap: 8px; color: var(--ink-dim); margin-bottom: 5px; }
.pw-detail__bars { margin: 6px 0; display: flex; flex-direction: column; gap: 3px; }
.pw-bar { display: grid; grid-template-columns: 56px 1fr 30px; align-items: center; gap: 6px; }
.pw-bar__lab { color: var(--ink-dim); font-size: var(--text-2xs); }
.pw-bar__track { height: 6px; border-radius: 3px; background: color-mix(in srgb, var(--ink) 11%, transparent); overflow: hidden; }
.pw-bar__fill { display: block; height: 100%; background: #f5a524; border-radius: 3px; }
.pw-bar__val { font-family: var(--font-mono); text-align: right; font-size: var(--text-2xs); font-variant-numeric: tabular-nums; }   /* G8: mono data face */
.pw-detail__spark { margin: 6px 0 2px; min-height: 14px; }
.pw-spark { display: block; }
.pw-detail__sparklab { font-size: var(--text-3xs); color: var(--ink-dim); }
.pw-detail__note { font-size: var(--text-3xs); color: var(--ink-dim); opacity: .9; margin-top: 5px; }
.pw-detail__src { font-size: var(--text-3xs); color: var(--ink-dim); opacity: .82; margin-top: 2px; }
@media (max-width: 640px) {
  .pw-detail { max-width: 70vw; }
  .globe-hero[data-panel-state="open"] .pw-detail { display: none; }
}
.globe-legend__note { font-size: var(--text-2xs); color: var(--ink-dim); opacity: 0.82; margin-top: 3px; line-height: 1.3; }
/* G7: period/window select archetype — bg-elev-2 + 1px --border + --r-sm (was a translucent bg-elev-1 mix). */
.globe-legend__period {
  font: inherit; font-size: var(--text-2xs); padding: 0 2px; cursor: pointer; flex: 0 0 auto;
  color: var(--ink); background: var(--bg-elev-2);
  border: 1px solid var(--border); border-radius: var(--r-sm);
  /* The legend itself is pointer-events:none (so globe drags pass through); the
     period <select> must re-enable hit-testing so it stays clickable. */
  pointer-events: auto;
}
.globe-legend__bar {
  height: 8px;
  border-radius: 4px;
  /* gradient background is set inline from the GIBS SST colormap */
}
.globe-legend__ticks {
  display: flex;
  justify-content: space-between;
  margin-top: 3px;
  font-size: var(--text-3xs);
  color: var(--ink-dim);
  font-family: var(--font-mono);   /* G8: mono data face */
  font-variant-numeric: tabular-nums;
}

/* Desktop: keep the legend visible while a panel is open (it sits centred over
   the globe, between the two side panels). Mobile: the panel is a bottom sheet
   that covers the bottom, so hide it there. */
@media (max-width: 640px) {
  .globe-legends { right: var(--globe-gutter); bottom: calc(var(--globe-gutter) + 54px); }
  .globe-legend { width: 150px; }
  .globe-hero[data-panel-state="open"] .globe-legends { display: none; }
}

.globe-sst-tip {
  position: absolute;
  z-index: var(--z-globe-4);
  pointer-events: none;
  padding: 4px 8px;
  border-radius: var(--r-sm);
  text-align: center;
  line-height: 1.25;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  /* (Glass Terminal, 2026-07-11) This probe readout TRACKS THE CURSOR (JS writes
     .style.left/top per pointer move), so it must NOT backdrop-blur — a per-frame
     blur recompute over the live globe would jank the probe. Tint-only glass:
     translucent fill + 1px hairline + tier shadow, no backdrop-filter. */
  background: var(--glass-3-bg);
  border: 1px solid var(--glass-hairline);
  box-shadow: var(--shadow-3), inset 0 1px 0 var(--glass-highlight);
}
/* Coordinate + temperature readouts are instrument data → mono + tabular. */
.globe-sst-tip__coord { display: block; font-family: var(--font-mono); font-size: var(--text-3xs); color: var(--ink-dim); }
.globe-sst-tip__temp { display: block; font-family: var(--font-mono); font-size: var(--text-xs); font-weight: 600; color: var(--ink); }

/* (audit #32) .globe-event-marker block removed — the class was referenced in
   no JS/HTML (dead since the event-feed globe pulses moved to WebGL); its
   infinite globe-event-pulse keyframe was pure idle GPU cost. */

/* A2 (2026-07-07) — LIVE data-stamp convention. A single quiet pulse keyframe
   + a reusable dot. Used by the globe status stamp and the feed results-header
   "updated" line. The global prefers-reduced-motion block (`* { animation:
   none !important }`) neutralises the pulse for motion-sensitive users. */
@keyframes live-pulse {
  0%   { opacity: 1; }
  50%  { opacity: 0.35; }
  100% { opacity: 1; }
}
.live-dot {
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--positive);
  animation: live-pulse 2.4s ease-in-out infinite;
  flex: 0 0 auto;
}

/* Globe mini status stamp — small frosted pill, bottom-left, that signals the
   page is live: pulse dot + a ticking UTC clock + "updated Nm" from the last
   successful data poll. Built by app.js (globe page only). Same frosted
   material as the other globe overlays. Hidden while a country panel is open
   (the left profile panel occupies this corner) to avoid a collision. */
.globe-status-stamp {
  position: absolute;
  left: var(--globe-gutter);    /* D1: bottom-left grid line */
  bottom: var(--globe-gutter);
  z-index: var(--z-globe-3);
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 10px;
  border-radius: 999px;
  /* (Glass Terminal, 2026-07-11) tier-1 glass — opaque fallback + shared
     @supports blur below (was 92% mix + unconditional blur(8px)); trio edges. */
  background: var(--glass-1-fallback);
  border: 1px solid var(--glass-hairline);
  box-shadow: var(--shadow-2), inset 0 1px 0 var(--glass-highlight);
  font-family: var(--font-sans);
  font-size: var(--text-2xs);
  letter-spacing: 0.04em;
  font-variant-numeric: tabular-nums;
  color: var(--ink-muted);
  pointer-events: none;
  white-space: nowrap;
}
.globe-status-stamp__sep { color: var(--ink-dim); }
/* The "LIVE" label reads as an instrument legend: small letterspaced caps set
   against the mono UTC readout, so the whole stamp feels like a status panel. */
.globe-status-stamp__live {
  text-transform: uppercase;
  letter-spacing: 0.12em;
  font-size: var(--text-3xs);
  font-weight: 600;
  color: var(--ink-muted);
}
/* (Glass Terminal, 2026-07-11) UTC clock + "updated" stamp adopt the mono data
   face (the pill is nowrap + sizes to content, so wider mono digits can't break
   layout). Tabular figures keep the ticking clock from jittering. */
.globe-status-stamp__clock,
.globe-status-stamp__updated { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }

/* (Glass Terminal, 2026-07-11) Shared tier-1 backdrop enhancement for the STATIC
   edge overlays (chip bar, reset/geo FABs, legend cards, status stamp). Kept in
   ONE @supports so the translucent fill + single backdrop blur apply only where
   supported; unsupported browsers and the prefers-reduced-transparency gate
   (the local @media block directly below — 70-aux's central gate does NOT list
   these five) keep each surface's opaque fallback. These sit at the viewport edges
   and only recompute the blur during an actual globe drag (requestRenderMode);
   cursor-tracking overlays (country label, SST tip) are deliberately excluded.
   Note: legends can stack N-deep (one card per active layer) → N blur regions;
   flagged for Wave 3 perf measurement, with the fallback/gate as the mitigation. */
@supports ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
  .globe-layers,
  .globe-reset,
  .globe-geo,
  .globe-status-stamp,
  .globe-legend {
    background: var(--glass-1-bg);
    -webkit-backdrop-filter: blur(var(--glass-1-blur)) saturate(var(--glass-sat));
    backdrop-filter: blur(var(--glass-1-blur)) saturate(var(--glass-sat));
  }
}
/* (Glass Terminal, 2026-07-11) prefers-reduced-transparency gate for the blurred
   globe edge overlays. The central gate at the end of 70-aux.css enumerates a
   fixed surface list that, from this file, covers ONLY .globe-data-pop; this
   local block covers the remaining blurred surfaces — the five shared tier-1
   overlays in the @supports block directly above (.globe-layers / .globe-reset /
   .globe-geo / .globe-status-stamp / .globe-legend) plus the tier-3 .pw-detail
   card (its own @supports blur sits earlier in this file, ~line 517) — until the
   orchestrator folds them into that central gate (see deviations). It sits LATER
   in this file than BOTH @supports blocks, so it forces each surface back to its
   opaque --glass-*-fallback and drops the blur at equal specificity WITHOUT
   !important; backdrop-filter is never written inline by JS, so forcing it off is
   safe, and JS never writes `background` on these six containers either. */
@media (prefers-reduced-transparency: reduce) {
  .globe-layers,
  .globe-reset,
  .globe-geo,
  .globe-status-stamp,
  .globe-legend {
    background: var(--glass-1-fallback);
  }
  .pw-detail {
    background: var(--glass-3-fallback);
  }
  .globe-layers,
  .globe-reset,
  .globe-geo,
  .globe-status-stamp,
  .globe-legend,
  .pw-detail {
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
}
.globe-hero[data-panel-state="open"] .globe-status-stamp { opacity: 0; pointer-events: none; }
@media (max-width: 640px) {
  /* On phones the profile bottom sheet + FAB own the lower area; keep the
     stamp out of the way. */
  .globe-status-stamp { display: none; }
}
/* (Glass Terminal, 2026-07-12) Safe-area insets for the floating globe EDGE
   overlays. viewport-fit=cover (added centrally in parallel) lets the 100dvh
   hero bleed under the notch / home indicator, so these corner controls gain
   env() margins to stay clear of the unsafe zones. @supports-gated per spec —
   engines without env() keep the original offsets; env() resolves to 0 on
   non-notch devices, so this is a no-op on desktop. Margins are purely additive:
   none of these four containers set margin elsewhere, and JS writes margin only
   on .globe-profile__lab / individual .globe-legend cards (never these
   containers), so no inline conflict. The existing bottom/right calc offsets are
   left intact — margin shifts the whole rail off the unsafe edge while
   preserving the reset↔geo↔legend relative stacking (all get the same
   margin-bottom). */
@supports (margin-bottom: env(safe-area-inset-bottom)) {
  .globe-reset,
  .globe-geo {
    margin-right: env(safe-area-inset-right);
    margin-bottom: env(safe-area-inset-bottom);
  }
  .globe-legends {
    margin-right: env(safe-area-inset-right);
    margin-bottom: env(safe-area-inset-bottom);
  }
  .globe-status-stamp {
    margin-left: env(safe-area-inset-left);
    margin-bottom: env(safe-area-inset-bottom);
  }
}

.globe-hero__hint {
  /* Bottom-centre micro-hint. Uppercase tracking + muted ink so it
     reads as a quiet affordance, not a CTA. Localised via data-i18n.
     A4 (2026-07-07): now actually rendered (globe page, first visit only);
     fades out via the opacity transition below after 8s or first click. */
  position: absolute;
  bottom: var(--sp-6);
  left: 50%;
  transform: translateX(-50%);
  max-width: min(70vw, 420px);
  padding: var(--sp-1) var(--sp-3);
  text-align: center;
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-dim);
  /* (Glass Terminal, 2026-07-11) tier-2 tint card — a quiet rounded backing so
     the caps hint stays legible over any imagery without a blur (it is a
     transient first-visit affordance that fades on click). Tint only, no
     backdrop-filter. */
  background: var(--glass-2-bg);
  border: 1px solid var(--glass-hairline);
  border-radius: 999px;
  box-shadow: var(--shadow-2), inset 0 1px 0 var(--glass-highlight);
  pointer-events: none;
  opacity: 0.85;
  transition: opacity var(--dur-base, 180ms) var(--ease);
}
.globe-hero__hint.is-hiding { opacity: 0; }

/* Fallback when globe.js calls hideHero(): instead of collapsing the
   block to display:none (silent — confusing for users on locked-down
   networks), the script swaps the hero contents for a single
   .globe-hero__notice paragraph. We shrink the hero to a small
   inline strip rather than its normal 100dvh so the legacy 2D map
   below moves up into the natural reading position. */
.globe-hero--unavailable {
  height: auto;
  min-height: auto;
  padding: var(--sp-5) var(--sp-4);
  display: flex;
  align-items: center;
  justify-content: center;
}
.globe-hero__notice {
  margin: 0;
  /* (Glass Terminal, 2026-07-11) tier-2 tint card — the graceful fallback when
     the WebGL globe can't load gets a real surface (tint + hairline + trio) and
     a calmer reading measure instead of bare floating text. Tint only, no blur. */
  padding: var(--sp-4) var(--sp-5);
  background: var(--glass-2-bg);
  border: 1px solid var(--glass-hairline);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-2), inset 0 1px 0 var(--glass-highlight);
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  line-height: 1.5;
  color: var(--ink-muted);
  text-align: center;
  max-width: 60ch;
}
/* Retry affordance for the unavailable notice. Styled AHEAD of the markup so a
   <button class="globe-hero__retry"> (or <a>) appended in hideHero() is ready to
   render — see html_js_requests. Quiet secondary button that reloads the page. */
.globe-hero__retry {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  margin-top: var(--sp-3);
  padding: var(--sp-1) var(--sp-3);
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  font-weight: 500;
  color: var(--ink);
  background: var(--bg-elev-1);
  border: 1px solid var(--glass-hairline);
  border-radius: var(--r-sm);
  cursor: pointer;
  text-decoration: none;
  transition: transform var(--dur-fast) var(--ease-out),
              box-shadow var(--dur-fast) var(--ease-out),
              background-color var(--dur-fast) var(--ease);
}
.globe-hero__retry:hover { transform: translateY(-1px); box-shadow: var(--shadow-2); }
.globe-hero__retry:active { transform: translateY(0); }
.globe-hero__retry:focus-visible { outline: none; box-shadow: var(--focus-ring); }

