/* AutonomeX governed execution environment: SCENE styles.

   Shared by every page that shows the globe (homepage, InboxOS logistics,
   InboxOS financial services) and by /globe-lab/. Only what the scene itself
   needs lives here: the stage, the canvas, the grain, the drag hint, the
   failed-init fallback and the narrative caution. Lab instrumentation stays
   in globe-lab/globe.css, so no production page can inherit it. */

/* The stage runs full bleed while the copy stays in the shell. A canvas that
   stops at the text column shows its own rectangle through the atmosphere. */
.globe-bleed { width: 100%; }

.globe-stage {
  position: relative;
  width: 100%;
  height: clamp(420px, 68vh, 760px);
  outline: none;
  /* pan-y is what keeps a phone scrollable: vertical swipes go to the page,
     horizontal intent becomes a drag. No wheel handler exists at all. */
  touch-action: pan-y;
}
.globe-stage canvas { display: block; width: 100%; height: 100%; cursor: grab; }

/* Static grain over the whole stage. On a smooth dark violet field 8-bit
   banding is the loudest "rendered" tell, and a couple of percent of noise
   removes it. Deliberately CSS rather than canvas: as a background layer the
   compositor handles it once, where a per-frame blended fillRect measured a
   44fps drop on the same scene. */
.globe-stage::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image: url('grain.png');
  background-repeat: repeat;
  background-size: 128px 128px;
  mix-blend-mode: overlay;
  opacity: 0.16;
  pointer-events: none;
}
.globe-stage:focus-visible { outline: 2px solid var(--violet-bright); outline-offset: 6px; }

.globe-hint {
  position: absolute; left: 50%; bottom: 14px; transform: translateX(-50%);
  /* It is a <p>: without this the UA 1em margin pushed the pill ~9px below
     its anchor, past the canvas and onto the legend on phones and at 768. */
  margin: 0;
  display: inline-flex; align-items: center; gap: 8px;
  padding: 7px 14px; border: 1px solid var(--hairline-strong); border-radius: 999px;
  background: rgba(18, 13, 28, 0.7);
  font-family: var(--mono); font-size: 0.62rem; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--caption);
  transition: opacity 600ms var(--ease-control);
}
[data-globe-hint="gone"] .globe-hint { opacity: 0; pointer-events: none; }

/* Nothing to drag until the engine is live, and the pill was previously the
   ONLY thing drawn in every failure state — a lone label floating in a void. */
.globe-stage:not([data-globe-live]) .globe-hint { display: none; }

/* The canvas is OFF until the engine says it is live (GLB-01, FN-07). It was
   hidden only by [data-globe-fallback], which only globe.js sets, so whenever
   globe.js never ran (blocked, 404, parse error, no JS, or still downloading
   on slow wi-fi) the empty canvas kept the whole stage and the panel below
   was pushed out of it, over the content that follows. */
.globe-stage:not([data-globe-live]) canvas { display: none; }

/* ---- static panel: the DEFAULT state, not just the failure state ------- */
/* The globe leads the homepage, which is the printed-QR destination, so the
   stage must never be an empty box: not on slow conference wi-fi (measured
   ~19-20s to first paint on Slow 3G), not with JS blocked, not on a failed
   or aborted globe.js. So the composed static panel renders by default and
   the engine hides it only once it has actually taken over. */
/* An overlay INSIDE the stage, so it can never flow out of the stage box and
   overprint what follows, whatever height the stage has. */
.globe-fallback {
  position: absolute; inset: 0;
  display: grid; place-items: center; height: 100%;
  border: 1px solid var(--hairline); border-radius: var(--radius-lg);
  background:
    radial-gradient(120% 120% at 30% 20%, rgba(109, 40, 217, 0.26), transparent 62%),
    rgba(18, 13, 28, 0.85);
  text-align: center; padding: 28px;
}
.globe-stage[data-globe-live] .globe-fallback { display: none; }
/* The attribute is set ON .globe-stage, so the canvas rule must qualify the
   stage itself. As a descendant selector it never matched: the blank canvas
   stayed and the fallback panel rendered beneath it, 612px below the stage. */
.globe-stage[data-globe-fallback] canvas { display: none; }
/* The old panel measured barely above its own background, so it read as empty
   space rather than a designed state. A visible violet edge and a lifted
   surface make it legible as a composition on its own. */
.globe-fallback {
  border-color: rgba(167, 139, 250, 0.30);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05);
}
.globe-fallback p { max-width: 42ch; margin: 10px auto 0; font-size: 0.9rem; color: var(--caption); }
/* On the page the stage runs full bleed, so a full-bleed panel put its
   rounded border on the viewport edges. It sits on the page's text column
   instead (the same 24px gutter / shell the copy uses). */
.gx-env .globe-fallback {
  left: max(var(--gutter, 24px), calc((100% - var(--shell, 1240px)) / 2));
  right: max(var(--gutter, 24px), calc((100% - var(--shell, 1240px)) / 2));
}
/* Above 900px the page lays SIGNALS / SITUATION / GOVERNED ACTION over the
   stage, and SITUATION sits at 56% of its height: a vertically centred
   panel printed its sentence straight through that label (measured at 1440
   with JS off). The panel's words go to the top third, clear of all three. */
@media (min-width: 901px) {
  .gx-env .globe-fallback { place-items: start center; padding-top: 96px; }
}
.globe-fallback .mono-label { color: var(--violet-bright); }
.globe-fallback .globe-fallback-lede {
  font-size: clamp(1.05rem, 1.6vw, 1.35rem);
  line-height: 1.3;
  color: var(--text);
  max-width: 24ch;
  margin: 14px auto 0;
}

/* A limit the configured narrative states about itself (see narratives.js).
   Real text, so it reaches assistive technology and survives a screenshot;
   top-centre so the DRAG TO EXPLORE pill at the bottom can never cover it. */
.globe-caution {
  position: absolute;
  top: 14px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 3;
  /* Inside the page's 24px gutter, and weight 500: only 400 and 500 are
     shipped, so 600 was synthesised (GLB-14). "AX Globe Mono" is the
     display:swap face globe.js registers for the canvas, so the caution and
     the canvas under it never disagree about the face when the page's own
     font-display: optional Plex Mono misses its window on a first visit. */
  /* max-content: with left: 50% an absolutely positioned box shrinks to
     half the stage, so at 360px the disclosure broke into three lines. */
  width: max-content;
  max-width: calc(100% - 48px);
  margin: 0;
  padding: 6px 12px;
  border: 1px solid rgba(167, 139, 250, 0.32);
  border-radius: 6px;
  background: rgba(10, 7, 20, 0.72);
  font: 500 0.62rem/1.35 "AX Globe Mono", "IBM Plex Mono", ui-monospace, monospace;
  letter-spacing: 0.06em;
  text-align: center;
  color: rgba(221, 214, 254, 0.86);
  pointer-events: none;
}

@media (max-width: 820px) {
  .globe-stage { height: clamp(360px, 58vh, 480px); }
}

/* ---- the band layout (phones, portrait tablets) ------------------------ */
/* When the canvas has no room beside the sphere, the engine sets
   data-globe-mode="band": words and the situation readout live in the band
   ABOVE the sphere (see layoutGeometry in globe.js). */

/* PHONE AND TABLET STAGE HEIGHT (DS-03 / GLB-09). The stage was sized by the
   viewport's HEIGHT (clamp(380px, 52vh, 460px)) while the sphere is sized by
   its WIDTH, so the difference became ~85-120px of empty canvas above and
   below the sphere. It is now sized from the width, to exactly what the
   composition uses: the band (four ~17px rows plus insets, ~100px) and the
   boundary ring (2 x 1.16 x 0.30W = 69.6vw), plus a 16px foot the drag hint
   docks into. Capped at 560px for portrait tablets and at 90% of a short
   landscape viewport (where the engine switches back to the field layout).
   A narrative caution adds its own height (--gx-caution-h, set by the
   engine) so the band starts under it. 900px is the same breakpoint at which
   the page moves its SIGNALS / SITUATION / GOVERNED ACTION labels off the
   stage, so the canvas and the labels switch together (GLB-03).
   The [data-globe] qualifier outranks site.css's .gx-env .globe-stage. */
@media (max-width: 900px) {
  .gx-env .globe-stage[data-globe] {
    height: calc(min(69.6vw + 122px, 560px, max(320px, 90vh)) + var(--gx-caution-h, 0px));
    height: calc(min(69.6vw + 122px, 560px, max(320px, 90svh)) + var(--gx-caution-h, 0px));
  }
}

/* The page feathers the canvas top and bottom by 14% so the atmosphere does
   not end in a line; in the band that fade would sit on the words and the
   readout. A 12px feather does the same job there. */
.gx-env .globe-stage[data-globe-mode="band"] canvas {
  -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 12px, #000 calc(100% - 14px), transparent 100%);
          mask-image: linear-gradient(180deg, transparent 0, #000 12px, #000 calc(100% - 14px), transparent 100%);
}

/* The drag hint docks ON the bottom of the boundary ring, the arc the scene
   reserves for it (no cluster, gate or word is ever placed there), instead
   of holding an empty band of its own under the sphere. --gx-hint-y is the
   ring's bottom, from the engine. */
.globe-stage[data-globe-mode="band"] .globe-hint {
  top: var(--gx-hint-y, auto);
  bottom: auto;
  transform: translate(-50%, -50%);
  gap: 6px;
  padding: 5px 11px;
  font-size: 0.56rem;
  white-space: nowrap;
}

/* ---- one SITUATION at a time (GLB-13) ---------------------------------- */
/* On desktop the page's SITUATION label sits inside the sphere while, for
   40% of each pass, the canvas captions the live situation beside its node:
   the scene said SITUATION twice. The engine marks the stage while its
   caption is on, and the page label steps back. */
/* Only when the labels are OVERLAID on the scene (field layout). Fully out,
   not dimmed to 20%: at 1024x768 the canvas caption and primary node still
   printed over a 20% label (QA). In the band layout the labels are a legend
   below the stage and must stay readable (portrait tablets). */
@media (min-width: 901px) {
  .gx-env-stage .gx-node-situation { transition: opacity 600ms ease; }
  .gx-env-stage:has(.globe-stage[data-globe-mode="field"][data-globe-caption="on"]) .gx-node-situation { opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .globe-hint { transition: none; }
  .gx-env-stage .gx-node-situation { transition: none; }
}
