/* ================================================================
   splash-hero.css - chapter 01's runtime stack, after splash.css.
   Computed material tokens drive WebGL in both stamped themes.
   The original CSS stack remains the no-WebGL fallback and accessible
   label list. The canvas contains the recessed, engraved nameplates,
   and one transparent button per nameplate sits over its projected
   plate: the pointer shortcut into the deck's entries.

   The stack stands on the page ground - no frame, no blueprint grid.
   The GL ground shadow and the daemon's ember are its only edges.
   ================================================================ */

/* ================================================================
   2 · TOKENS - the page's own tokens cover the ported hero CSS/JS
   (--ground --panel --raised --border --border-strong --text --accent
   --accent-text --term-bg --mono --display); only the hero's --stack-*
   materials and --lift are declared here.

   Four themes, exactly like splash.css: the bare block is day; night,
   titanium and gunmetal are the :root[data-theme] blocks below.
   ================================================================ */
/* the tokens sit on the deck (both columns), so the tab strip's slab
   glyphs read the same tints the stack does; the stack alone gets them
   on any other host */
body.splash .deck,body.splash .stackstage{
  --lift:0 1px 0 rgba(255,255,255,.7);
  /* read by splash-hero.js (readTheme) */
  --stack-shadow:rgba(63,39,24,.12);
  --stack-dark:0;                 /* 0 = light, 1 = dark. Numeric, never a name. */
  --stack-substrate:#18231f;      /* a chip is dark in both themes */
  --stack-gold:#e0ab57;
  --stack-metal:#aab3bd;
  --stack-rpc:#2e8f85;
  --stack-voice:#b0498e;
  --stack-ade:#c93d55;
  --stack-tui:#c07d16;
  --stack-cli:#2e7d52;
}
:root[data-theme="night"] body.splash .deck,:root[data-theme="night"] body.splash .stackstage{
  --lift:0 1px 0 rgba(255,255,255,.05);
  --stack-shadow:rgba(0,0,0,.32);
  --stack-dark:1;
  --stack-substrate:#101a18;
  --stack-gold:#f2c06d;
  --stack-metal:#bcc5d0;
  --stack-rpc:#4fd0c3;
  --stack-voice:#e07ac0;
  --stack-ade:#ff6b81;
  --stack-tui:#ffb84d;
  --stack-cli:#5fd39a;
}
/* Titanium and gunmetal: the same board, cut from steel. The layer accents
   stay a family of neutrals separated by lightness rather than by hue, so
   the five surfaces are still tellable apart without any chroma on the
   ground. splash-hero.js reads these the same way it reads the warm pair;
   only --stack-dark tells it which way the light falls. */
:root[data-theme="titanium"] body.splash .deck,:root[data-theme="titanium"] body.splash .stackstage{
  --lift:0 1px 0 rgba(255,255,255,.8);
  --stack-shadow:rgba(15,17,20,.14);
  --stack-dark:0;
  --stack-substrate:#1a1f24;
  --stack-gold:#c9cdd2;
  --stack-metal:#a9aeb5;
  --stack-rpc:#4f7096;
  --stack-voice:#868d96;
  --stack-ade:#6b7178;
  --stack-tui:#a1a7ae;
  --stack-cli:#79808a;
}
:root[data-theme="gunmetal"] body.splash .deck,:root[data-theme="gunmetal"] body.splash .stackstage{
  --lift:0 1px 0 rgba(255,255,255,.06);
  --stack-shadow:rgba(0,0,0,.4);
  --stack-dark:1;
  --stack-substrate:#12161a;
  --stack-gold:#c9ced6;
  --stack-metal:#bcc5d0;
  --stack-rpc:#7fa7cf;
  --stack-voice:#aeb4bc;
  --stack-ade:#959ba4;
  --stack-tui:#c9ced6;
  --stack-cli:#9ba3ad;
}

/* ================================================================
   3 · THE GROUND - the stack sits directly on the page. No panel,
   no blueprint grid, no caption: only what the GL scene draws.
   ================================================================ */
body.splash .stackstage .hero-visual{
  position:relative;
  display:grid;
  align-items:center;
  min-width:0;
}

/* ================================================================
   4 · THE CSS ISO STACK - what renders without WebGL, and the layer
   the canvas covers. This fills the chapter's visual column.
   ================================================================ */
body.splash .iso-stack{
  position:relative;
  /* the star of the chapter: the stack fills its half of the deck */
  height:clamp(26rem,46vw,42rem);
  margin:0;
  padding:0;
  list-style:none;
  isolation:isolate;
  perspective:1200px;
  perspective-origin:50% 50%;
  transform-style:preserve-3d;
  touch-action:pan-y;
}
body.splash .iso-layer{
  position:absolute;
  inset:auto auto calc(3.6rem + var(--layer) * 3.35rem) 50%;
  width:min(78%,20rem);
  height:4.6rem;
  min-height:0;
  display:flex;
  align-items:center;
  justify-content:space-between;
  gap:1rem;
  padding:1rem 1.25rem;
  border:1px solid var(--border-strong);
  border-radius:14px;
  background:linear-gradient(160deg,var(--raised),var(--panel));
  box-shadow:0 18px 34px -20px rgba(0,0,0,.55),var(--lift);
  color:var(--text);
  font-family:var(--mono);
  font-size:.8125rem;
  font-weight:600;
  letter-spacing:.06em;
  transform:translateX(-50%) rotateX(57deg) rotateZ(-41deg);
  transition:transform .4s cubic-bezier(.22,1,.36,1),box-shadow .4s ease;
}
body.splash .iso-layer::after{
  content:"surface / " attr(data-index);
  color:var(--text-2);
  font-size:.75rem;
  font-weight:500;
  letter-spacing:.1em;
  opacity:1;
}
body.splash .iso-layer--daemon{
  height:5.2rem;
  border-color:color-mix(in srgb,var(--accent) 70%,var(--border-strong));
  background:linear-gradient(160deg,color-mix(in srgb,var(--accent) 24%,var(--panel)),var(--panel));
  color:var(--accent-text);
  font-weight:700;
  box-shadow:
    0 0 0 1px color-mix(in srgb,var(--accent) 30%,transparent),
    0 30px 60px -26px color-mix(in srgb,var(--accent) 60%,transparent),
    0 18px 34px -20px rgba(0,0,0,.5);
}
body.splash .iso-layer--daemon::after{
  content:"runtime / 00";
  color:color-mix(in srgb,var(--accent-text) 78%,var(--text));
}
body.splash .iso-layer--daemon img{width:2.3rem;height:auto}
body.splash .iso-layer--daemon span{display:inline-flex;align-items:center;gap:.55rem}
body.splash .iso-stack:hover .iso-layer{transform:translateX(-50%) rotateX(57deg) rotateZ(-41deg) translateZ(.9rem)}

/* ================================================================
   5 · THE GL LAYER - canvas and fidget hint, injected into a
   presentation-only <li>. Engraved names belong to the GL materials.

   The host BLEEDS past the stack's layout box: the canvas, the hit
   layer and the glow all sit in it, so the model is fitted to this
   larger box (splash-hero.js reads the host's rect) and can spill over
   the gutter and the column gap rather than shrink to the column. The
   layout box itself does not change, so nothing on the page moves.
   The bleed tokens are the page's (splash.css sets --stack-bleed-x/-y
   on the deck's stage column, where the hint under the stack reads
   them too); without them the host is the stack box.
   ================================================================ */
body.splash .stack-gl{position:absolute;inset:calc(-1 * var(--stack-bleed-y,0px)) calc(-1 * var(--stack-bleed-x,0px));margin:0;padding:0;list-style:none}
/* One transparent button per engraved nameplate. Its size is the plate at
   rest, written once per layout; every frame after that splash-hero.js
   writes only a transform (translate + scale) from the plate's own
   projected corners, so the hit area rides the slab as it tumbles without
   ever costing a layout. Only the buttons take pointer events; the canvas
   keeps the drag. A plate facing away is data-off (no pointer events) but
   stays focusable, so the keyboard reaches every entry whatever the pose. */
body.splash .stack-hits{position:absolute;inset:0;z-index:4;pointer-events:none}
body.splash .plate-hit{
  position:absolute;left:0;top:0;width:0;height:0;
  transform-origin:0 0;transform:translate3d(-9999px,0,0);
  margin:0;padding:0;border:0;border-radius:5px;
  background:transparent;color:transparent;font:inherit;
  cursor:pointer;pointer-events:auto;
}
body.splash .plate-hit[data-off="1"]{pointer-events:none}
body.splash .plate-hit:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
/* under a finger a plate is about 33px tall, so the press area grows to
   the tap minimum above and below the plate; the visible plate is the
   canvas's and does not change */
@media (pointer: coarse), (max-width: 640px){
  body.splash .plate-hit::after{content:"";position:absolute;inset:-6px 0}
}
/* The mark on the plate under the pointer, or on the plate whose entry is
   open: one accent light clipped to that plate's projected quad, so it sits
   ON the slab at its own angle instead of drawing a box around it. The blur
   is on the wrapper because a filter is applied before the clip, not after,
   and it is what keeps the light soft-edged in both themes. */
body.splash .plate-glow{
  position:absolute;inset:0;z-index:3;
  pointer-events:none;
  filter:blur(6px);
  opacity:0;
  transition:opacity .28s ease;
}
/* --plate-light is only defined by the metal themes: there the light on a
   plate is steel, and dimmer, because those themes carry no coloured bloom. */
body.splash .plate-glow i{position:absolute;inset:0;display:block;background:var(--plate-light,var(--accent));clip-path:polygon(0 0,0 0,0 0,0 0)}
body.splash .plate-glow[data-on="1"]{opacity:.3}
/* the open entry's plate breathes: the same light, easing over 4 s; a
   plate under the pointer or asked for by its tab holds still */
@keyframes plateBreathe{0%,100%{opacity:1}50%{opacity:.4}}
body.splash .plate-glow[data-breathe="1"] i{animation:plateBreathe 4s ease-in-out infinite}
:root[data-theme="night"] body.splash .plate-glow[data-on="1"]{opacity:.42}
:root[data-theme="titanium"] body.splash .plate-glow[data-on="1"]{opacity:.22}
:root[data-theme="gunmetal"] body.splash .plate-glow[data-on="1"]{opacity:.3}
@media (prefers-reduced-motion: reduce){body.splash .plate-glow{transition:none}body.splash .plate-glow[data-breathe="1"] i{animation:none}}
body.splash .stack-canvas{position:absolute;inset:0;z-index:1;width:100%;height:100%;display:block;pointer-events:none}
body.splash .stack-hint{
  position:absolute;
  z-index:3;
  left:50%;
  bottom:.9rem;
  transform:translateX(-50%);
  padding:.35rem .65rem;
  border:1px solid var(--border);
  border-radius:999px;
  background:color-mix(in srgb,var(--panel) 86%,transparent);
  color:var(--text-2);
  font:600 .78rem / 1.2 var(--body);
  letter-spacing:.01em;
  white-space:nowrap;
  opacity:0;
  pointer-events:none;
  transition:opacity .4s ease .9s;
}

/* ================================================================
   6 · STATE - .is-gl hides the fallback list, .is-fallback restores it
   (no WebGL, context lost, or hcHeroStack.destroy()).
   ================================================================ */
body.splash .iso-stack.is-gl{
  perspective:none;
  transform-style:flat;
  cursor:grab;
  user-select:none;
  -webkit-user-select:none;
  border-radius:14px;
  outline-offset:-4px;
}
/* Preserve the six original list items for assistive technology. The
   fallback restores normal layout simply by removing .is-gl. */
body.splash .iso-stack.is-gl:not(.is-fallback) > .iso-layer{
  position:absolute;
  inset:0 auto auto 0;
  display:block;
  width:1px;
  height:1px;
  min-height:0;
  margin:-1px;
  padding:0;
  border:0;
  overflow:hidden;
  clip:rect(0,0,0,0);
  clip-path:inset(50%);
  white-space:nowrap;
  transform:none;
  box-shadow:none;
  pointer-events:none;
}
body.splash .iso-stack.is-gl .stack-hint{opacity:1}
body.splash .iso-stack.is-grabbing{cursor:grabbing}
body.splash .iso-stack.is-touched .stack-hint{opacity:0;transition-delay:0s}
/* .is-fallback wins over .is-gl, so forcing it always shows the list */
body.splash .iso-stack.is-fallback{perspective:1200px;transform-style:preserve-3d;cursor:auto}
body.splash .iso-stack.is-fallback > .iso-layer{visibility:visible;opacity:1;pointer-events:auto}
body.splash .iso-stack.is-fallback .stack-gl{display:none}
body.splash .iso-stack:focus-visible{outline:2px solid var(--accent);outline-offset:-4px}

/* ================================================================
   7 · REDUCED MOTION - no hover lift or hint transition. The GL scene
   draws one settled frame and parks (splash-hero.js).
   ================================================================ */
@media (prefers-reduced-motion: reduce){
  body.splash .iso-layer{transition:none}
  body.splash .iso-stack:hover .iso-layer{transform:translateX(-50%) rotateX(57deg) rotateZ(-41deg)}
  body.splash .stack-hint{transition:none}
}

/* ================================================================
   8 · NARROW - 52rem matches the layoutQuery splash-hero.js uses to pick
   its rest pose, so the CSS and the camera turn over together.
   ================================================================ */
@media (max-width:52rem){
  body.splash .iso-stack{height:clamp(21rem,86vw,30rem)}
  body.splash .iso-layer{width:min(84%,16rem);height:3.7rem;inset:auto auto calc(2.4rem + var(--layer) * 2.5rem) 50%}
  body.splash .iso-layer--daemon{height:4.2rem}
}
/* The keyboard hint is unnecessary on the narrowest touch layouts. */
@media (max-width:30rem){
  body.splash .stack-hint{display:none}
}

/* ================================================================
   9 · THE OTHER TWO OBJECTS - chapters 02 and 03 stand on the same
   engine as the stack: one canvas and one hit layer inside the box
   the object already reserves (splash.css gives .object its 600/480
   aspect ratio, so mounting a canvas over the SVG moves nothing).

   .is-gl hides the hand-drawn SVG and its own presses; without WebGL,
   or after a lost context, the class goes and the SVG is the object
   again. The canvas, the presses, the plate light and the drag hint
   are the stack's own elements and take its rules above.
   ================================================================ */
body.splash .object-gl{position:absolute;inset:0;z-index:2}
body.splash .object.is-gl > .object__art,
body.splash .object.is-gl > .part{display:none}
body.splash .object.is-gl{
  cursor:grab;
  touch-action:pan-y;
  user-select:none;
  -webkit-user-select:none;
  border-radius:14px;
  outline-offset:-4px;
}
body.splash .object.is-grabbing{cursor:grabbing}
body.splash .object.is-gl:focus-visible{outline:2px solid var(--accent);outline-offset:-4px}
/* the hint fades in once the object is live, and goes for good at the
   first drag or arrow key */
body.splash .object.is-gl .stack-hint{opacity:1}
body.splash .object.is-touched .stack-hint{opacity:0;transition-delay:0s}
/* The mark on the open part. A drawer face is twenty times the area of a
   nameplate, so the same light at the stack's strength would flood it: the
   objects take a quieter one, and it still breathes. */
body.splash .object-gl .plate-glow{filter:blur(10px)}
body.splash .object-gl .plate-glow[data-on="1"]{opacity:.16}
:root[data-theme="night"] body.splash .object-gl .plate-glow[data-on="1"]{opacity:.2}
:root[data-theme="titanium"] body.splash .object-gl .plate-glow[data-on="1"]{opacity:.11}
:root[data-theme="gunmetal"] body.splash .object-gl .plate-glow[data-on="1"]{opacity:.15}
/* a rating plate or a tag is a thin band under a finger: a press under
   44px grows above and below it, the drawn part does not; a press that is
   already tall enough (splash-hero.js marks it data-tall) keeps its own
   edge, so the drawer faces, which stand close, never cover each other */
@media (pointer: coarse), (max-width: 640px){
  body.splash .object-gl .plate-hit:not([data-tall="1"])::after{content:"";position:absolute;inset:-10px 0}
  /* a press in a stack grows only toward the side where no other press
     stands (splash-hero.js marks the side in the press's own frame) */
  body.splash .object-gl .plate-hit:not([data-tall="1"])[data-grow="top"]::after{inset:-10px 0 0 0}
  body.splash .object-gl .plate-hit:not([data-tall="1"])[data-grow="bottom"]::after{inset:0 0 -10px 0}
  body.splash .object-gl .plate-hit[data-grow="none"]::after{content:none}
}
/* .is-fallback wins, exactly as it does on the stack */
body.splash .object.is-fallback > .object__art,
body.splash .object.is-fallback > .part{display:block}
body.splash .object.is-fallback .object-gl{display:none}
