/* ============================================================
   /legion - INLINE intro-then-release scroll-scrub hero (shared harness)
   Reuses the proven Tier-A engine from hero-motion.html: one --p progress
   (0..1) drives every layer via CSS clamp(); JS rAF-lerps for smoothness.

   Narrative (cofounder KG -> laptop -> agents, adapted to Signal-Blue/Hanken):
     KG context nodes feed INWARD into the center terminal (laptop) ->
     the terminal ignites -> a legion of agents bursts OUT to every channel.

   SELF-CONTAINED: index.html does not load site.css and leaves --shadow-float /
   --bevel undefined, so every shadow here carries a literal fallback. Scene image
   refs are relative to THIS file, so it works from assets/ (home) and ../assets/ (products).

   Degradation: default stage = one static 100vh composed frame. JS adds .mh--live
   only when motion is allowed -> full scroll runway + scrub. So no-JS AND
   reduced-motion both show a static frame with the real page one scroll below.
   ============================================================ */

/* Default hidden: the motion intro is a local-review preview, not shipped UX.
   motion.js adds .motion-local to <html> only on a local host / ?motion=1,
   which reveals it. On prod the section never renders (visitors land on the hero). */
.mh{display:none}
html.motion-local .mh{--p:0;--mh-shadow:var(--shadow-float,0 2px 4px rgba(20,25,40,.06),0 20px 48px rgba(20,25,40,.16),inset 0 1px 0 rgba(255,255,255,.6));
  --mh-bevel:var(--bevel,inset 0 1.5px 0 rgba(255,255,255,.9),inset 0 -1.5px 0 rgba(20,25,40,.09));
  display:block;position:relative;isolation:isolate}

/* stage: default one static screen (no-JS / reduced-motion safe). JS opts into the runway. */
.mh__stage{height:100vh}
.mh--live[data-variant="home"] .mh__stage{height:600vh}      /* 6 screens of scrub */
.mh--live[data-variant="product"] .mh__stage{height:320vh}   /* shorter product intro */

.mh__pin{position:sticky;top:0;height:100vh;overflow:hidden;isolation:isolate;
  display:grid;place-items:center;background:var(--bg)}
.mh:not(.mh--live) .mh__pin{position:relative}

/* ---- backdrop pixel world - parallax zoom off --p ---- */
.mh__sky{position:absolute;inset:0;z-index:0;pointer-events:none;
  background-image:
    linear-gradient(180deg,color-mix(in srgb,var(--bg) 30%,transparent) 0%,color-mix(in srgb,var(--bg) 12%,transparent) 46%,color-mix(in srgb,var(--bg) 70%,transparent) 82%,var(--bg) 100%),
    url(scene-bg.webp);
  background-size:cover,cover;background-position:center,50% calc(66% - var(--p)*22%);
  image-rendering:pixelated;
  transform:scale(calc(1.04 + var(--p)*0.18));transform-origin:50% 44%;
  filter:saturate(calc(1 + var(--p)*0.14))}
:root[data-theme="dark"] .mh__sky{background-image:
  linear-gradient(180deg,color-mix(in srgb,var(--bg) 34%,transparent) 0%,color-mix(in srgb,var(--bg) 14%,transparent) 46%,color-mix(in srgb,var(--bg) 72%,transparent) 82%,var(--bg) 100%),
  url(scene-bg-dark.webp)}
/* signal-blue bloom that intensifies as the terminal ignites the legion */
.mh__bloom{position:absolute;inset:0;z-index:1;pointer-events:none;
  background:radial-gradient(42% 40% at 50% 47%,color-mix(in srgb,var(--accent) calc(6% + var(--p)*24%),transparent) 0%,transparent 62%);
  opacity:calc(0.22 + var(--p)*0.78)}

/* the field where the whole scene composes */
.mh__field{position:relative;z-index:2;width:min(1120px,92vw);height:min(78vh,720px);margin:0 auto}

/* ---- KG context nodes (inner ring, feed INWARD into the terminal) ---- */
.mh__kg{position:absolute;left:50%;top:50%;z-index:4;transform:translate(-50%,-50%);
  /* per-node: --ix/--iy start offset (px) from center, --s stagger.
     fed = how far it has fed into the terminal (0 at ring, 1 at center). */
  --fed:clamp(0, calc((var(--p) - var(--s)) / 0.34), 1);
  transform:translate(-50%,-50%)
            translate(calc(var(--ix)*(1 - var(--fed))), calc(var(--iy)*(1 - var(--fed))))
            scale(calc(0.82 + (1 - var(--fed))*0.18));
  opacity:min(calc((var(--p) - var(--s) + 0.06) * 9), calc(1 - var(--fed)*1.05));
  will-change:transform,opacity}
.mh__kg__chip{display:inline-flex;align-items:center;gap:6px;padding:5px 10px;border-radius:9999px;
  font-family:var(--font-mono);font-size:11px;letter-spacing:.01em;white-space:nowrap;
  color:var(--text-strong);
  background:linear-gradient(160deg,color-mix(in srgb,var(--surface-1,#fcfcfa) 95%,transparent),color-mix(in srgb,var(--surface-2,#f0f0ec) 95%,transparent));
  border:1px solid color-mix(in srgb,var(--accent) 34%,var(--border,#dedfda));
  box-shadow:0 2px 8px rgba(20,25,40,.12),inset 0 1px 0 rgba(255,255,255,.4)}
.mh__kg__chip b{width:6px;height:6px;border-radius:50%;flex:0 0 auto;
  background:var(--accent);box-shadow:0 0 6px color-mix(in srgb,var(--accent) 70%,transparent)}

/* ---- the terminal (laptop) - the one operator's command surface, center ---- */
.mh__op{position:absolute;left:50%;top:50%;
  transform:translate(-50%,-50%) scale(calc(0.94 + var(--p)*0.08));
  z-index:6;width:min(380px,74vw);
  background:linear-gradient(180deg,color-mix(in srgb,var(--surface-1,#fcfcfa) 94%,transparent),color-mix(in srgb,var(--surface-2,#f0f0ec) 94%,transparent));
  border:1px solid var(--border,#dedfda);border-radius:14px;box-shadow:var(--mh-shadow),var(--mh-bevel);
  padding:14px 16px;font-family:var(--font-mono);font-size:12.5px;line-height:1.7;
  backdrop-filter:blur(3px)}
.mh__op::before{content:"";position:absolute;inset:0 0 auto;height:60%;z-index:-1;pointer-events:none;border-radius:14px 14px 0 0;
  background:radial-gradient(120% 100% at 84% -20%,color-mix(in srgb,var(--accent) calc(12% + var(--p)*16%),transparent) 0%,transparent 62%)}
/* laptop deck - a thin base plate under the terminal so it reads as a laptop */
.mh__op__deck{position:absolute;left:50%;bottom:-13px;transform:translateX(-50%) perspective(220px) rotateX(52deg);
  width:118%;height:20px;border-radius:0 0 10px 10px;pointer-events:none;
  background:linear-gradient(180deg,color-mix(in srgb,var(--surface-2,#f0f0ec) 96%,transparent),color-mix(in srgb,var(--surface-3,#e9e9e4) 96%,transparent));
  border:1px solid var(--border,#dedfda);border-top:none;
  box-shadow:0 10px 22px rgba(20,25,40,.16)}
.mh__op .ln{display:block}
.mh__op .pr{color:var(--accent-ink)}
.mh__op .cm{color:var(--text-strong)}
.mh__op .ok{color:var(--success)}
.mh__op .ot{color:var(--text-muted)}
.mh__op .cur{display:inline-block;width:7px;height:15px;vertical-align:-2px;margin-left:2px;
  background:var(--accent);animation:mh-blink 1s steps(1) infinite}
@keyframes mh-blink{50%{opacity:0}}
.mh__opbadge{position:absolute;top:-11px;left:16px;display:inline-flex;align-items:center;gap:6px;
  padding:3px 9px;border-radius:9999px;font-family:var(--font-mono);font-size:10px;letter-spacing:.1em;text-transform:uppercase;
  background:var(--btn-fill-bg,#1f1f29);color:var(--btn-fill-fg,#fff)}
.mh__opbadge b{width:6px;height:6px;border-radius:50%;background:var(--accent)}

/* ---- agent legion (JS-spawned, burst OUT of the terminal to channels) ---- */
.mh__agent{position:absolute;left:50%;top:50%;z-index:5;width:14px;height:14px;border-radius:4px;
  /* per-token: --tx/--ty target offset (px), --s ignite start, --r spin */
  --lp:clamp(0, calc((var(--p) - var(--s)) / 0.40), 1);
  transform:translate(-50%,-50%)
            translate(calc(var(--tx)*var(--lp)), calc(var(--ty)*var(--lp)))
            scale(calc(0.5 + var(--lp)*0.5)) rotate(calc(var(--r)*1deg));
  opacity:clamp(0, calc((var(--p) - var(--s)) * 7), calc(1 - var(--lp)*0.12));
  background:linear-gradient(150deg,color-mix(in srgb,#fff 30%,var(--accent)) 0%,var(--accent-surface,#0081c0) 100%);
  border:1px solid color-mix(in srgb,var(--accent) 55%,#fff 20%);
  box-shadow:0 0 0 2px color-mix(in srgb,var(--accent) 22%,transparent),0 2px 6px rgba(20,25,40,.28);
  will-change:transform,opacity}
.mh__agent::after{content:"";position:absolute;inset:3px;border-radius:2px;background:color-mix(in srgb,#fff 70%,var(--accent))}

/* ---- channel / outcome nodes (outer ring) ---- */
.mh__ch{position:absolute;z-index:7;transform:translate(-50%,-50%);
  display:flex;flex-direction:column;align-items:center;gap:6px;width:96px;text-align:center;
  --act:clamp(0, calc((var(--p) - var(--ca)) / 0.14), 1);
  /* stay out of the way until the agents are almost here - keeps early beats a clean KG read */
  opacity:clamp(0, calc((var(--p) - var(--ca) + 0.15) / 0.15), 1)}
.mh__ch__ic{width:44px;height:44px;border-radius:12px;display:grid;place-content:center;
  font-family:var(--font-mono);font-size:16px;font-weight:600;
  background:linear-gradient(160deg,color-mix(in srgb,var(--surface-1,#fcfcfa) 96%,transparent),color-mix(in srgb,var(--surface-2,#f0f0ec) 96%,transparent));
  border:1px solid color-mix(in srgb,var(--border,#dedfda) calc(100% - var(--act)*100%), color-mix(in srgb,var(--accent) 62%,transparent));
  color:color-mix(in srgb,var(--text-muted,#5c5c5a) calc(100% - var(--act)*100%), var(--accent-ink,#2f7fa6));
  box-shadow:0 2px 8px rgba(20,25,40,.10),
    0 0 0 calc(var(--act)*3px) color-mix(in srgb,var(--accent) calc(var(--act)*26%),transparent),
    inset 0 1px 0 rgba(255,255,255,.4);
  transform:scale(calc(0.9 + var(--act)*0.14))}
.mh__ch__lbl{font-family:var(--font-sans);font-size:12px;font-weight:600;letter-spacing:-.01em;
  color:color-mix(in srgb,var(--text-muted,#5c5c5a) calc(100% - var(--act)*70%), var(--text-strong,#171717));
  opacity:calc(0.5 + var(--act)*0.5)}
.mh__ch__st{font-family:var(--font-mono);font-size:9.5px;letter-spacing:.06em;text-transform:uppercase;
  color:var(--success,#2e9e58);opacity:var(--act);height:11px}

/* ---- beams (SVG) - inflow KG->terminal draw early, outflow terminal->channel draw late ---- */
.mh__beams{position:absolute;inset:0;z-index:3;pointer-events:none;overflow:visible}
.mh__beam{fill:none;stroke:url(#mhGrad);stroke-linecap:round;stroke-dasharray:var(--len);
  stroke-dashoffset:calc(var(--len) * (1 - clamp(0, calc((var(--p) - var(--bs)) / 0.36), 1)));
  filter:drop-shadow(0 0 3px color-mix(in srgb,var(--accent) 40%,transparent))}
.mh__beam--in{stroke-width:1.7;opacity:calc(0.14 + clamp(0, calc((var(--p) - var(--bs)) / 0.36), 1)*0.5)}
.mh__beam--out{stroke-width:2.1;opacity:calc(0.18 + clamp(0, calc((var(--p) - var(--bs)) / 0.36), 1)*0.6)}

/* ---- narrative captions (beat-gated) ---- */
.mh__cap{position:absolute;left:0;right:0;bottom:calc(9vh + env(safe-area-inset-bottom,0px));z-index:8;text-align:center;pointer-events:none;padding:0 24px}
.mh__cap__eyebrow{font-family:var(--font-mono);font-size:11px;letter-spacing:.16em;text-transform:uppercase;color:var(--accent-ink,#2f7fa6);margin-bottom:10px}
.mh__cap__line{font-family:var(--font-serif);font-weight:500;font-size:clamp(1.4rem,3vw,2.3rem);line-height:1.14;letter-spacing:-.03em;color:var(--text-strong,#171717);text-wrap:balance;max-width:20ch;margin:0 auto}
.mh__cap__line em{font-style:italic;color:var(--accent-ink,#2f7fa6)}
.mh__beat{opacity:0;transform:translateY(10px);transition:opacity .5s ease,transform .5s ease;position:absolute;left:0;right:0;bottom:0}
.mh[data-beat="0"] .mh__beat--0,.mh[data-beat="1"] .mh__beat--1,.mh[data-beat="2"] .mh__beat--2,
.mh[data-beat="3"] .mh__beat--3,.mh[data-beat="4"] .mh__beat--4{opacity:1;transform:none;position:relative}

/* scroll hint */
.mh__hint{position:absolute;top:calc(2vh + 84px);left:50%;transform:translateX(-50%);z-index:8;
  font-family:var(--font-mono);font-size:11px;letter-spacing:.14em;text-transform:uppercase;color:var(--text-muted,#5c5c5a);
  opacity:calc(1 - var(--p)*5);display:flex;flex-direction:column;align-items:center;gap:7px;pointer-events:none}
.mh__hint .ar{animation:mh-bob 1.6s ease-in-out infinite;font-size:14px}
@keyframes mh-bob{0%,100%{transform:translateY(0)}50%{transform:translateY(4px)}}

/* skip-intro affordance - always available, never a scroll-trap */
.mh__skip{position:absolute;right:calc(3vw + env(safe-area-inset-right,0px));bottom:calc(11vh + env(safe-area-inset-bottom,0px));z-index:9;
  display:inline-flex;align-items:center;gap:7px;padding:9px 15px;border-radius:9999px;text-decoration:none;
  font-family:var(--font-sans);font-size:13px;font-weight:600;color:var(--text-strong,#171717);
  background:color-mix(in srgb,var(--surface-1,#fcfcfa) 86%,transparent);backdrop-filter:blur(12px);
  border:1px solid color-mix(in srgb,var(--accent) 32%,var(--border,#dedfda));box-shadow:0 3px 14px rgba(20,25,40,.14);
  transition:transform .18s ease,box-shadow .18s ease,opacity .3s ease;
  /* stay clearly visible through the intro, fade only near the release */
  opacity:calc(1 - max(0, calc(var(--p) - 0.7)) * 3.2)}
.mh__skip:hover{transform:translateY(-1px);box-shadow:0 6px 18px rgba(20,25,40,.16)}
.mh:not(.mh--live) .mh__skip{display:none}   /* nothing to skip when static */

/* ---- reduced-motion / no-JS: static composed frame, real page one scroll below ---- */
@media (prefers-reduced-motion: reduce){
  .mh--live .mh__stage{height:auto !important}
  .mh--live .mh__pin{position:relative !important;height:auto !important;min-height:86vh;padding:44px 0}
  .mh{--p:0.92 !important}
  .mh__kg{--fed:1}            /* KG fully fed in -> one clean composed payoff frame */
  .mh__agent{--lp:0.9}
  .mh__field{height:56vh}     /* leave room so the full composed caption fits above the fold */
  .mh__hint,.mh__skip{display:none}
  .mh__cap{position:relative;bottom:auto;margin-top:22px}
  /* NB: no .mh__beat override here on purpose - JS sets data-beat to the LAST beat, so only the
     composed caption shows (inactive beats keep their default position:absolute/opacity:0). */
}

/* ---- mobile ---- */
@media (max-width:720px){
  .mh__field{height:66vh}
  .mh__ch{width:72px}
  .mh__ch__ic{width:38px;height:38px;font-size:14px}
  .mh__ch__lbl{font-size:11px}
  .mh__kg__chip{font-size:10px;padding:4px 8px}
  .mh__op{width:min(300px,82vw);font-size:11.5px}
  .mh__skip{right:4vw;bottom:calc(9vh + env(safe-area-inset-bottom,0px));padding:7px 12px;font-size:12px}
}
