/* ==========================================================================
   THE WORLD LEDGER — real node/validator globe
   ========================================================================== */

body.globe-page {
  background: var(--color-bg);
  overflow-x: hidden;
}

.globe-header {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 20;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  padding: var(--space-4) var(--space-6);
  background: linear-gradient(180deg, rgba(5, 7, 10, 0.92) 0%, rgba(5, 7, 10, 0) 100%);
  gap: var(--space-3) var(--space-4);
}

.globe-header .brand {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-family: var(--font-display);
  font-weight: 600;
  color: var(--color-text);
  text-decoration: none;
  grid-column: 1;
  justify-self: start;
}
.globe-header .globe-nav { grid-column: 2; justify-self: center; }
.globe-header .globe-actions { grid-column: 3; justify-self: end; position: relative; display: flex; align-items: center; gap: var(--space-2); }
.globe-header .brand svg { width: 28px; height: 28px; color: var(--color-primary); }

.globe-sound-toggle {
  width: 34px;
  height: 34px;
  display: grid;
  place-items: center;
  flex-shrink: 0;
  border-radius: var(--radius-full);
  color: var(--color-text-muted);
  border: 1px solid color-mix(in srgb, var(--color-primary) 28%, transparent);
  background: color-mix(in srgb, var(--color-primary) 6%, transparent);
  backdrop-filter: blur(6px);
  box-shadow: 0 1px 8px rgba(0, 0, 0, 0.4);
  transition: var(--transition-interactive);
  position: relative;
}
.globe-sound-toggle svg { width: 16px; height: 16px; }
.globe-sound-toggle:hover { color: var(--color-text); border-color: var(--color-primary); background: color-mix(in srgb, var(--color-primary) 12%, transparent); }
.globe-sound-toggle svg line { transition: opacity 150ms ease; }
.globe-sound-toggle.is-on svg line { opacity: 0; }
.globe-sound-toggle.is-on { color: var(--color-primary); border-color: var(--color-primary); background: color-mix(in srgb, var(--color-primary) 16%, transparent); }

.globe-ambient-toggle svg .icon-collapse { opacity: 0; }
.globe-ambient-toggle svg .icon-expand,
.globe-ambient-toggle svg .icon-collapse { transition: opacity 150ms ease; }
.globe-ambient-toggle.is-on svg .icon-expand { opacity: 0; }
.globe-ambient-toggle.is-on svg .icon-collapse { opacity: 1; }

/* -------------------------------------------------------------------- */
/* Ambient / screensaver mode                                           */
/* Hides every UI layer and lets the globe run full-bleed with live     */
/* data + a rotating real nature soundscape underneath — nothing here   */
/* touches state.                                                       */
/* -------------------------------------------------------------------- */
body.is-ambient .globe-header,
body.is-ambient .globe-intro,
body.is-ambient .globe-panel,
body.is-ambient .globe-hint,
body.is-ambient .node-card {
  opacity: 0 !important;
  pointer-events: none !important;
  transition: opacity 700ms ease;
}
body.is-ambient,
body.is-ambient .globe-stage,
body.is-ambient #globe-canvas {
  cursor: none;
}

.globe-ambient-hint {
  position: fixed;
  left: 50%;
  bottom: var(--space-8);
  transform: translateX(-50%);
  z-index: 40;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.04em;
  color: var(--color-text);
  background: rgba(6, 12, 18, 0.55);
  border: 1px solid color-mix(in srgb, var(--color-primary) 30%, transparent);
  padding: var(--space-2) var(--space-5);
  border-radius: var(--radius-full);
  opacity: 0;
  pointer-events: none;
  transition: opacity 600ms ease;
  backdrop-filter: blur(6px);
}
.globe-ambient-hint.is-visible { opacity: 1; }
.globe-sound-toggle.is-on:not(.is-unlocked)::after {
  content: '';
  position: absolute;
  inset: -5px;
  border-radius: var(--radius-full);
  border: 1.5px solid color-mix(in srgb, var(--color-primary) 55%, transparent);
  animation: globe-cue-pulse 1.8s ease-out infinite;
  pointer-events: none;
}
@keyframes globe-cue-pulse {
  0% { transform: scale(0.85); opacity: 0.9; }
  100% { transform: scale(1.55); opacity: 0; }
}

.sound-cue {
  /* Fixed at the bottom-right corner, raised well above the bottom-center
     hints, rather than anchored near the toggle button or centered under
     the header: the top band is contested (nav pills to the button's
     left, the live-data panel starting almost flush with the header's
     bottom edge on the right). Bottom-center is used by .globe-ambient-hint
     and .globe-hint, and at narrower desktop widths (measured: overlaps
     below ~1300px at a naive 28px offset) those hints extend far enough
     right to reach a bottom-right-anchored cue — 110px of clearance keeps
     this above both at every tested width down to 900px, while staying
     far below the panel's bottom edge — same fix applied to aurora.css's
     equivalent cue. */
  position: fixed;
  top: auto;
  bottom: 110px;
  left: auto;
  right: 28px;
  transform: none;
  display: flex;
  align-items: center;
  gap: 6px;
  white-space: nowrap;
  padding: 7px 12px 7px 10px;
  border-radius: var(--radius-full);
  background: rgba(6, 12, 18, 0.92);
  border: 1px solid color-mix(in srgb, var(--color-primary) 30%, transparent);
  color: var(--color-text);
  font-size: 12.5px;
  font-family: var(--font-mono);
  letter-spacing: 0.01em;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
  opacity: 0;
  animation: globe-cue-in 600ms ease 900ms forwards;
  transition: opacity 400ms ease;
  z-index: 20;
}
.sound-cue svg { width: 14px; height: 14px; color: var(--color-primary); flex-shrink: 0; }
.sound-cue.is-hidden { opacity: 0 !important; pointer-events: none; }
.sound-cue .short { display: none; }
@keyframes globe-cue-in { to { opacity: 1; } }


.globe-stage {
  position: relative;
  width: 100%;
  height: 100vh;
  height: 100dvh;
  min-height: 560px;
  /* Defensive clip: see reef.css .reef-stage for why this guards the
     absolutely-positioned .globe-panel against off-screen rendering. */
  overflow: hidden;
}

#globe-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  cursor: grab;
  touch-action: none;
}
#globe-canvas:active { cursor: grabbing; }

.globe-intro {
  position: absolute;
  top: calc(var(--space-16) + var(--space-8));
  left: var(--space-6);
  max-width: 460px;
  z-index: 10;
  pointer-events: none;
}
.globe-intro .eyebrow { color: var(--color-blue, #4fd1ff); }
.globe-intro h1 {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  margin: var(--space-3) 0 var(--space-3);
  color: var(--color-text);
}
.globe-intro p {
  color: #d6e7f0;
  font-size: var(--text-sm);
  line-height: 1.6;
}
.globe-intro .globe-sound-note {
  margin-top: var(--space-3);
  padding-top: var(--space-3);
  border-top: 1px solid color-mix(in srgb, var(--color-primary) 20%, transparent);
  color: color-mix(in srgb, var(--color-primary) 55%, var(--color-text));
}
.globe-intro .globe-sound-note a {
  pointer-events: auto;
  color: inherit;
  text-decoration: underline;
  text-decoration-color: color-mix(in srgb, var(--color-primary) 45%, transparent);
}
.globe-intro .globe-live-features-note {
  margin-top: var(--space-3);
  padding-top: var(--space-3);
  border-top: 1px solid color-mix(in srgb, var(--color-warning) 20%, transparent);
}
.globe-intro .text-accent-green {
  color: #34e0a1;
}
.globe-intro .text-accent-orange {
  color: var(--color-warning);
}

.globe-hint {
  position: absolute;
  bottom: var(--space-6);
  left: 50%;
  transform: translateX(-50%);
  z-index: 10;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--color-text-faint);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  opacity: 0;
  animation: globe-hint-in 600ms ease 900ms forwards;
  transition: opacity 400ms ease;
}
.globe-hint.is-hidden { opacity: 0 !important; }
@keyframes globe-hint-in { to { opacity: 1; } }
.globe-hint svg { width: 16px; height: 16px; }

.globe-panel {
  position: absolute;
  top: var(--space-16);
  right: var(--space-6);
  z-index: 10;
  width: 280px;
  max-height: calc(100dvh - 112px);
  overflow-y: auto;
  overscroll-behavior-y: contain;
  background: rgba(10, 14, 19, 0.72);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}
.globe-panel .panel-title {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-text-faint);
  margin-bottom: var(--space-3);
}
.globe-stat-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  padding: var(--space-2) 0;
  border-top: 1px solid var(--color-divider);
}
.globe-stat-row:first-of-type { border-top: none; }
.globe-stat-row .label {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}
.globe-stat-row .value {
  font-family: var(--font-mono);
  font-weight: 600;
  color: var(--color-text);
  font-size: var(--text-sm);
}
.legend-dot {
  width: 9px; height: 9px; border-radius: 50%; display: inline-block; flex: none;
}
.legend-dot.validator { background: #ffd76a; box-shadow: 0 0 8px #ffd76a; }
.legend-dot.peer { background: #4fd1ff; box-shadow: 0 0 6px #4fd1ff; }
.legend-dot.iss { background: #b98bff; box-shadow: 0 0 8px #b98bff; }
.legend-dot.aurora { background: #34e0a1; box-shadow: 0 0 8px #34e0a1; }

/* Storm-level badge -- color tracks NOAA's own G-scale severity, computed
   from the real Kp value already shown in the row above. G0 stays neutral
   (matches every other stat); G1-G2 warm to amber; G3+ reads as a genuine
   alert since a strong storm is a rare, noteworthy real event. */
.value.storm-g0 { color: var(--color-text); }
.value.storm-g1 { color: var(--color-warning); }
.value.storm-g2 { color: var(--color-warning); }
.value.storm-g3 { color: #ff8a5c; }
.value.storm-g4 { color: #ff6b6b; }

.globe-panel-divider {
  margin: var(--space-4) 0 var(--space-3);
  border-top: 1px solid var(--color-divider);
}
.globe-panel .panel-title:not(:first-child) { margin-top: 0; }

.globe-status {
  margin-top: var(--space-4);
  padding-top: var(--space-4);
  border-top: 1px solid var(--color-divider);
  font-size: var(--text-xs);
  color: var(--color-text-faint);
  line-height: 1.6;
}
.globe-status.is-live { color: var(--color-primary); }
.globe-status a { color: inherit; text-decoration: underline; text-decoration-color: var(--color-border); }

.globe-loading {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 15;
  background: var(--color-bg);
  transition: opacity 500ms ease;
  flex-direction: column;
  gap: var(--space-3);
}
.globe-loading.is-hidden { opacity: 0; pointer-events: none; }
.globe-loading .spinner {
  width: 34px; height: 34px;
  border-radius: 50%;
  border: 2px solid var(--color-border);
  border-top-color: var(--color-blue, #4fd1ff);
  animation: globe-spin 900ms linear infinite;
}
.globe-loading p { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--color-text-faint); letter-spacing: 0.05em; text-transform: uppercase; }
@keyframes globe-spin { to { transform: rotate(360deg); } }

.globe-sources {
  padding: var(--space-8) var(--space-6) var(--space-16);
  max-width: var(--content-default);
  margin: 0 auto;
  color: var(--color-text-faint);
  font-size: var(--text-xs);
  line-height: 1.7;
  border-top: 1px solid var(--color-divider);
}
.globe-sources a { color: var(--color-text-muted); }
.globe-sources strong { color: var(--color-text-muted); }
/* Same embed-only fix as aurora.css/reef.css: unreachable by scroll inside
   the flagship's cropped iframe, but still keyboard-tabbable — hide it in
   embed mode so Tab can't jump into content no mouse user could ever see. */
.lv-embedded .globe-sources { display: none; }

/* -- tap-to-identify node card -- */
.node-card {
  position: absolute;
  left: var(--space-6);
  bottom: var(--space-6);
  z-index: 12;
  width: 300px;
  max-width: calc(100vw - var(--space-8));
  background: rgba(10, 14, 19, 0.82);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  opacity: 0;
  transform: translateY(8px);
  pointer-events: none;
  transition: opacity 220ms ease, transform 220ms ease;
}
.node-card.is-visible {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}
.node-card .node-kind {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-text-faint);
  margin-bottom: var(--space-2);
}
.node-card .node-name {
  font-size: var(--text-lg);
  font-weight: 600;
  color: var(--color-text);
  word-break: break-word;
  line-height: 1.3;
}
.node-card .node-meta {
  margin-top: var(--space-1);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}
.node-card .node-meta-faint {
  color: var(--color-text-faint);
  font-size: var(--text-xs);
}
.node-badge {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.04em;
  text-transform: none;
  padding: 2px 7px;
  border-radius: var(--radius-full, 999px);
  border: 1px solid var(--color-border);
  color: var(--color-text-faint);
}
.node-badge.is-verified {
  color: #ffd76a;
  border-color: rgba(255, 215, 106, 0.4);
  background: rgba(255, 215, 106, 0.08);
}

@media (max-width: 640px) {
  .globe-header { grid-template-columns: 1fr; justify-items: center; row-gap: var(--space-2); }
  .globe-header .brand { justify-self: center; }
  .globe-header .globe-nav { grid-column: 1; }
  .globe-header .globe-actions { grid-column: 1; justify-self: center; }
  .globe-nav { justify-content: center; }
}

/* The header's nav wraps to a second line below ~965px (measured max
   119.5px tall in this range vs 72px above it), which runs directly into
   .globe-panel's fixed top:var(--space-16) (64px) — the sound/fullscreen
   icons and the panel's rounded top-right corner visibly collided at
   900px (confirmed by screenshot: icons sitting on top of the panel's
   border/background). Same root cause and fix shape as aurora.css's
   equivalent squeeze-zone rule. */
@media (max-width: 1024px) and (min-width: 761px) {
  .globe-panel { top: 132px; }
}

@media (max-width: 760px) {
  /* Bottom-right is NOT safe once the data panel goes full-width across
     the bottom of the viewport (below, left/right: var(--space-4)) — any
     bottom-anchored cue would sit on top of it, and the header is fully
     packed too (logo + wrapping nav + actions). Rather than hide the
     cue outright and lose the only affordance telling a mobile visitor
     sound is available, globe.js measures the header's actual rendered
     bottom edge at runtime and pins the cue in whatever gap is left
     below it, hiding it only if that gap is genuinely too tight. */
  .sound-cue {
    top: 0; bottom: auto; left: 50%; right: auto;
    transform: translateX(-50%);
    font-size: 11px;
    padding: 6px 11px 6px 9px;
  }
  .sound-cue .full { display: none; }
  .sound-cue .short { display: inline; }
  .sound-cue.no-room { opacity: 0 !important; pointer-events: none; }
  .globe-panel {
    top: auto;
    bottom: var(--space-6);
    right: var(--space-4);
    left: var(--space-4);
    width: auto;
    /* Keep the globe visible and all readings reachable on short phones
       and inside the flagship's shorter embedded viewport. */
    max-height: min(42dvh, 22rem);
    overflow-y: auto;
    overscroll-behavior-y: contain;
  }
  /* On mobile the intro copy has no room to sit beside the globe, so it has
     to overlay it directly — pointer-events:auto (overriding the desktop
     none) lets a tap on it fire the tap-to-hide handler in globe.js instead
     of silently falling through to the canvas underneath. */
  /* 9.5rem (152px) cleared the header at wider mobile widths, but the
     header wraps across more lines the narrower it gets (measured up to
     204px tall at 320px) — below ~480px that put the intro's eyebrow
     label crowding right underneath the header's icons (confirmed at
     390px). 220px clears the tallest measured mobile header (204px)
     with margin, applied across the whole range like aurora.css's
     equivalent fallback. */
  .globe-intro { left: var(--space-4); right: var(--space-4); top: 220px; max-width: none; pointer-events: auto; cursor: pointer; }
  .globe-intro .overlay-hide-hint { display: flex; }
  .globe-hint { display: none; }
  .node-card { left: var(--space-4); right: var(--space-4); width: auto; top: 220px; bottom: auto; transform: translateY(-8px); }
  .node-card.is-visible { transform: translateY(0); }
  /* Set by globe.js whenever a tapped node's card is showing on mobile:
     the card and .globe-intro share this exact top-left rectangle here
     (see .node-card above), so without this the card rendered directly
     on top of the intro's heading (confirmed at 390px). A tap on the
     globe requesting node detail should take over from the intro copy,
     not stack on it. */
  .globe-intro.is-card-active { opacity: 0 !important; pointer-events: none !important; }
}

/* Sibling-concept navigation (added so visitors can browse all concepts) */
.globe-nav {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
}

/* -------------------------------------------------------------------- */
/* Embedded mode — this page nested as one act inside the flagship's    */
/* single scroll journey (index.html). Hides the logo + cross-page pill */
/* nav (redundant inside the flagship's own header), keeps this act's    */
/* own sound/ambient toggle so it still feels alive on its own.          */
/* -------------------------------------------------------------------- */
html.lv-embedded .globe-header {
  /* The flagship page's own header already supplies an equivalent
     global sound toggle, immersive toggle, and live-status badge --
     keeping this page's own header visible too would show two of
     each control on screen at once near the top of this act, the
     clearest possible tell that this is four pages stitched
     together rather than one converged experience. Audio unlock
     and mute/duck are already driven by postMessage from the
     parent (see embed-bridge.js), so hiding this header loses no
     functionality inside the flagship. */
  display: none !important;
}

/* Panel-hide toggle — a small always-tappable button that only ever
   hides/shows the intro copy + vitals panel, nothing else (no wake lock,
   no sound change, no cursor hiding). It only renders when embedded in
   the flagship (html.lv-embedded), because that's the one context where
   the header — and its full ambient-mode toggle — is hidden and there is
   otherwise no way to see the globe unobstructed. Standalone, the
   header's own ambient toggle already covers this. */
.lv-panel-toggle {
  display: none;
}
html.lv-embedded .lv-panel-toggle {
  display: flex;
  position: fixed;
  top: var(--space-3);
  right: var(--space-3);
  z-index: 40;
  width: 36px;
  height: 36px;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-full);
  background: rgba(6, 16, 20, 0.72);
  border: 1px solid color-mix(in srgb, var(--color-primary) 30%, transparent);
  color: rgba(214, 245, 240, 0.8);
  cursor: pointer;
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  transition: color 200ms ease, border-color 200ms ease, background 200ms ease;
}
.lv-panel-toggle svg { width: 17px; height: 17px; position: absolute; }
.lv-panel-toggle .icon-eye-off { opacity: 0; }
.lv-panel-toggle.is-hidden .icon-eye { opacity: 0; }
.lv-panel-toggle.is-hidden .icon-eye-off { opacity: 1; }
.lv-panel-toggle.is-hidden {
  color: var(--color-primary);
  border-color: var(--color-primary);
  background: color-mix(in srgb, var(--color-primary) 16%, transparent);
}
body.lv-panel-hidden .globe-intro,
body.lv-panel-hidden .globe-panel {
  opacity: 0 !important;
  pointer-events: none !important;
  transition: opacity 320ms ease;
}
