/* Hero stage (system/3d/hero.js). The stage sits at the inline end of the hero (right in LTR, left in RTL) and always
   draws left to right inside (dir="ltr"); the copy stays above it. Below 900 px the stage goes on top of the copy.
   Every colour has a fallback: the stylesheet is loaded beside the view's token scope. */
:is(.nxo-view,html) .has-hero{position:relative;overflow:hidden}
:is(.nxo-view,html) .has-hero>.w,:is(.nxo-view,html) .has-hero>.in,:is(.nxo-view,html) .has-hero>.copy{position:relative;z-index:2}
.nxo-hero{position:absolute;inset:0;direction:ltr;z-index:1;pointer-events:none}
/* The 3D is the page's ground: full width, edge to edge, no frame, border, shadow or box. The scene fades into the page
   with fog (hero.js), and the canvas edges dissolve with an alpha mask so no seam shows into the next section. */
/* The stage carries dir="ltr" (its scene draws left to right), and logical insets resolve against the element's own
   direction, so under an RTL page the end side is set physically: the stage sits on the left, clear of the copy. */
.nxo-hero canvas,.nxo-hero img{display:block;width:100%;height:100%;object-fit:cover}
.nxo-hero canvas{opacity:0;transition:opacity .6s;-webkit-mask-image:linear-gradient(to bottom,transparent 0,#000 7%,#000 84%,transparent 100%);mask-image:linear-gradient(to bottom,transparent 0,#000 7%,#000 84%,transparent 100%)}
.nxo-hero.is-live canvas{opacity:1}
/* the copy's plate (hero.js scrim): the scrim token under the text and buttons, above the scene */
.nxo-hero-scrim{position:absolute;background:var(--scrim,rgba(0,0,0,.88));pointer-events:none}
.nxo-hero-scrim[hidden]{display:none}
/* the phone band's poster until the scene is live (hero.js, audit L28); it gives way as the canvas fades in */
.nxo-hero .nxo-hero-wait{position:absolute;inset:0;display:none;width:100%;height:100%;object-fit:cover;object-position:50% 0;transition:opacity .6s,visibility 0s .6s}
.nxo-hero.is-live .nxo-hero-wait{opacity:0;visibility:hidden}
@media (max-width:900px){.nxo-hero .nxo-hero-wait{display:block}}
.nxo-hero-pause{pointer-events:auto;position:absolute;inset-inline-end:16px;bottom:14px;height:28px;padding:0 10px;border-radius:5px;border:1px solid var(--hair2,rgba(127,127,127,.35));background:var(--bg,transparent);color:var(--t3,#8c8c8c);font:500 10.5px/1 var(--mono,monospace);letter-spacing:.08em;text-transform:uppercase;cursor:pointer;opacity:.75}
.nxo-hero-pause:hover,.nxo-hero-pause:focus-visible{opacity:1;color:var(--t1,currentColor);border-color:var(--accent,currentColor);outline:none}
.nxo-hero-pause[hidden]{display:none}
/* text-only page bands (.phero) gain a stage beside the copy */
:is(.nxo-view,html) .has-hero--band{min-height:620px}
:is(.nxo-view,html) .has-hero--band>.w>*{max-width:min(46vw,640px)}
/* a stage that fills its own box (the about stage, the atlas frame, the learn and spectrum figures) */
:is(.nxo-view,html) .has-hero--box{position:relative;overflow:hidden}
:is(.nxo-view,html) .has-hero--box .nxo-hero{inset:0;top:0;width:100%;height:100%}
:is(.nxo-view,html) .has-hero--band>:not(.nxo-hero):not(.w){max-width:min(46vw,640px)}
/* line homes and the about, protocol and master heroes keep their own heights */
@media (max-width:900px){
  :is(.nxo-view,html) .has-hero{display:flex;flex-direction:column}
  /* phones: the heading and copy come first (the first screen reads), the stage follows them; it mounts below the
     copy, so nothing the visitor is reading moves when it arrives */
  .nxo-hero{position:relative;inset:auto;width:100%;height:clamp(260px,52vh,420px);margin-top:0;order:2;flex:none}
  :is(.nxo-view,html) .has-hero>.cap{order:3}
  :is(.nxo-view,html) .hero.has-hero>.w{height:auto;padding-top:112px} /* a full-height hero runs under the bars: its copy clears them */
  :is(.nxo-view,html) .has-hero--band .nxo-hero,:is(.nxo-view,html) .has-hero--fill .nxo-hero{margin-top:24px}
  :is(.nxo-view,html) .has-hero--band{min-height:0;padding-top:88px}
  :is(.nxo-view,html) .has-hero--band>.w>*,:is(.nxo-view,html) .has-hero--band>:not(.nxo-hero):not(.w){max-width:none}
  :is(.nxo-view,html) .has-hero--box{display:block}
  :is(.nxo-view,html) .has-hero--box .nxo-hero{position:absolute;inset:0;height:100%;margin:0}
}
/* CAD viewport (cadview.js): the canvas takes the pointer (drag to orbit, hover to pick); the copy above stays clickable
   because only its own text and controls catch events, its layout boxes let them through to the stage. */
.nxo-hero.nxo-cad-on canvas{pointer-events:auto;cursor:grab;touch-action:pan-y;outline:none}
.nxo-hero.nxo-cad-on canvas:focus-visible{outline:1px solid var(--accent,currentColor);outline-offset:-1px}
:is(.nxo-view,html) .has-hero:has(.nxo-cad-on)>:is(.w,.in,.copy){pointer-events:none}
:is(.nxo-view,html) .has-hero:has(.nxo-cad-on)>:is(.w,.in,.copy) :is(a,button,input,select,textarea,label,summary,p,h1,h2,h3,h4,li,dl,dd,dt,nav,form,[role=button],[tabindex],small,span,b,code,kbd,img,svg){pointer-events:auto}
.nxo-cad{position:absolute;inset:0;pointer-events:none;font:500 10px/1.3 var(--mono,'IBM Plex Mono',monospace);color:var(--t3,#8c8c8c);letter-spacing:.06em}
.nxo-cad-triad{position:absolute;left:16px;bottom:12px;overflow:visible}
.nxo-cad-triad line{stroke:var(--t2,#bdbdbd);stroke-width:1}
.nxo-cad-triad line.bk{stroke:var(--t3,#8c8c8c);stroke-dasharray:2 2}
.nxo-cad-triad text{fill:var(--t2,#bdbdbd);font:500 8px var(--mono,monospace);text-anchor:middle}
.nxo-cad-ro{position:absolute;left:84px;bottom:20px;text-transform:uppercase;white-space:pre;font-variant-numeric:tabular-nums}
.nxo-cad-hint{position:absolute;left:84px;bottom:36px;text-transform:uppercase;opacity:.8;transition:color .2s}
.nxo-cad-hint.nudge{color:var(--t1,currentColor)}
.nxo-cad-hint[hidden]{display:none}
.nxo-cad-call{position:absolute;left:var(--x,0);top:var(--y,0);transform:translate(14px,14px);max-width:260px;padding:8px 10px;border-radius:5px;border:1px solid var(--accent,currentColor);background:var(--bg,#000);color:var(--t1,#f2f2f2);text-transform:none;letter-spacing:0}
.nxo-cad-call.flip{transform:translate(calc(-100% - 14px),14px)}
.nxo-cad-call[hidden]{display:none}
.nxo-cad-call b{display:block;font:600 11px/1.3 var(--mono,monospace);letter-spacing:.06em;text-transform:uppercase;color:var(--accent,currentColor)}
.nxo-cad-call span{display:block;margin-top:3px;font:400 12px/1.4 var(--sans,'IBM Plex Sans',sans-serif);color:var(--t1,#f2f2f2)}
.nxo-cad-call span:empty,.nxo-cad-call i:empty{display:none}
.nxo-cad-call i{display:block;margin-top:4px;font:500 9.5px/1.3 var(--mono,monospace);font-style:normal;letter-spacing:.08em;text-transform:uppercase;color:var(--t3,#8c8c8c)}
.nxo-cad-reset{pointer-events:auto;position:absolute;inset-inline-end:16px;bottom:48px;height:28px;padding:0 10px;border-radius:5px;border:1px solid var(--hair2,rgba(127,127,127,.35));background:var(--bg,transparent);color:var(--t3,#8c8c8c);font:500 10.5px/1 var(--mono,monospace);letter-spacing:.08em;text-transform:uppercase;cursor:pointer}
.nxo-cad-reset:hover,.nxo-cad-reset:focus-visible{color:var(--t1,currentColor);border-color:var(--accent,currentColor);outline:none}
.nxo-cad-reset[hidden]{display:none}
[dir=rtl] .nxo-cad-reset,[dir=rtl] .nxo-hero-pause{inset-inline-end:auto;inset-inline-start:16px}
@media (max-width:900px){.nxo-cad-hint,.nxo-cad-ro{display:none}.nxo-cad-triad{transform:scale(.8);transform-origin:0 100%}}
@media (hover:none){.nxo-cad-hint{display:none}}
/* Right to left: the stage draws left to right, but its controls mirror with the page, so the triad, readout and
   hint sit at the right and Pause and Reset at the left, never on top of each other. */
[dir=rtl] .nxo-cad-triad{left:auto;right:16px}
[dir=rtl] .nxo-cad-ro,[dir=rtl] .nxo-cad-hint{left:auto;right:84px;text-align:right}
/* A view's own stage caption ("drag to turn") gives way to the viewport's controls once the CAD viewport is live. */
:is(.nxo-view,html) .has-hero:has(.nxo-cad-on) .cap{display:none}

/* Story HUD (system/3d/story-director.js); on a wide hero the caption starts where the subject's free area does
   (--nxo-free-x, measured from the copy by hero.js): the scenario's caption and a slim chapter indicator, quiet text over the scene
   (no box, no fill). Legibility comes from the page tokens and a paper-coloured outline behind the glyphs, not a glow. */
.nxo-story{position:absolute;inset:0;pointer-events:none;color:var(--t1,#f2f2f2)}
.nxo-story-cap{position:absolute;left:var(--nxo-free-x,46%);bottom:90px;max-width:min(50%,460px);display:flex;flex-direction:column;gap:4px;opacity:0;transform:translateY(6px);transition:opacity .7s ease,transform .7s ease}
.nxo-story.in .nxo-story-cap{opacity:1;transform:none}
.nxo-story.out .nxo-story-cap{opacity:0;transition-duration:.45s}
.nxo-story-n{font:500 10px/1 var(--mono,'IBM Plex Mono',monospace);letter-spacing:.12em;color:var(--t2,#bdbdbd);font-variant-numeric:tabular-nums}
.nxo-story-n:empty{display:none}
/* the caption always sits on the scrim token, flat, no blur: the scene's lines (ground, props, orbits) pass under every slot, not only the subject (render sweep 2026-11-04; keepClear still moves it off the subject) */
.nxo-story .nxo-story-cap{background:var(--scrim,rgba(0,0,0,.88));padding:8px 12px;margin:-8px -12px;border-radius:5px}
.nxo-story .nxo-story-t{-webkit-text-stroke:0}
.nxo-story-t{font:500 clamp(15px,1.5vw,19px)/1.3 var(--sans,'IBM Plex Sans',sans-serif);color:var(--t1,#f2f2f2);letter-spacing:.005em;paint-order:stroke fill;-webkit-text-stroke:3px var(--bg,#000)}
.nxo-story-prog{position:absolute;left:var(--nxo-free-x,46%);bottom:78px;display:flex;gap:3px;margin:0;padding:0;list-style:none;width:min(50%,460px)}
.nxo-story-prog li{flex:1;height:2px;background:var(--hair2,rgba(127,127,127,.35));overflow:hidden}
.nxo-story-prog li i{display:block;height:100%;background:var(--t1,#f2f2f2);transform:scaleX(0);transform-origin:0 50%}
.nxo-story-prog li.on{background:var(--t3,#8c8c8c)}
.nxo-story-tags{position:absolute;inset:0;overflow:hidden}
.nxo-story-tag{position:absolute;left:0;top:0;margin:-5px 0 0 12px;font:500 9.5px/1 var(--mono,'IBM Plex Mono',monospace);letter-spacing:.1em;text-transform:uppercase;color:var(--t1,#f2f2f2);white-space:normal;max-width:24ch;line-height:1.35;opacity:0;transition:opacity .4s;padding:3px 5px;border-radius:4px;background:var(--bg,#000)}
.nxo-story-tag::before{content:"";display:inline-block;width:5px;height:5px;margin-inline-end:6px;border-radius:50%;background:var(--accent,currentColor);vertical-align:middle}
.nxo-story-tag[hidden]{display:none}
.nxo-story-step{position:absolute;inset-inline-end:16px;bottom:84px;display:flex;gap:6px;pointer-events:auto}
.nxo-story-step button{width:32px;height:32px;border-radius:5px;border:1px solid var(--hair2,rgba(127,127,127,.35));background:var(--bg,#000);color:var(--t1,#f2f2f2);font:500 18px/1 var(--sans,sans-serif);cursor:pointer}
.nxo-story-step button:hover,.nxo-story-step button:focus-visible{border-color:var(--accent,currentColor);outline:none}
/* on environment and scene pages the tour keeps the bottom: the story's caption sits at the top, under the view's title */
.nxo-story.top .nxo-story-cap{top:92px;bottom:auto;left:16px}
.nxo-story.top .nxo-story-prog{top:84px;bottom:auto;left:16px}
@media (max-width:900px){
  .nxo-story.top .nxo-story-cap{top:84px;bottom:auto}
  .nxo-story.top .nxo-story-prog{top:76px;bottom:auto}
  /* phones: the bottom 80 px belong to the controls (triad at the start, Pause and Reset view at the end); the story's bar
     and caption sit above them instead of running through them */
  .nxo-story-cap{left:16px;bottom:100px;max-width:calc(100% - 32px)}
  .nxo-story-prog{left:16px;bottom:86px;width:calc(100% - 32px)}
  .nxo-story-t{font-size:14px}
  .nxo-story-step{bottom:44px}
}
/* the other slot, taken when the subject is under the caption (story-director keepClear): below the site's top bar and
   sub-header (nav.js sets --nx-bar and --nx-sub), never under them */
.nxo-story.alt .nxo-story-cap{top:calc(var(--nx-bar,64px) + var(--nx-sub,0px) + 32px);bottom:auto}.nxo-story.alt .nxo-story-prog{top:calc(var(--nx-bar,64px) + var(--nx-sub,0px) + 24px);bottom:auto}
.nxo-story.top.alt .nxo-story-cap{top:auto;bottom:90px}.nxo-story.top.alt .nxo-story-prog{top:auto;bottom:78px}
[dir=rtl] .nxo-story-cap,[dir=rtl] .nxo-story-prog{left:16px}
@media (max-width:900px){/* the other slot, taken when the subject is under the caption (story-director keepClear) */
.nxo-story.alt .nxo-story-cap{top:calc(var(--nx-bar,64px) + var(--nx-sub,0px) + 32px);bottom:auto}.nxo-story.alt .nxo-story-prog{top:calc(var(--nx-bar,64px) + var(--nx-sub,0px) + 24px);bottom:auto}
.nxo-story.top.alt .nxo-story-cap{top:auto;bottom:90px}.nxo-story.top.alt .nxo-story-prog{top:auto;bottom:78px}
[dir=rtl] .nxo-story-cap,[dir=rtl] .nxo-story-prog{left:16px}}
@media (prefers-reduced-motion:reduce){.nxo-story-cap{transition:none}}
