/* Nullsend landing motion effects (scramble headings, statement-band resolve,
 * WebGL hero noise). Pairs with assets/js/decrypt.js. Loaded by index.html and
 * enterprise.html. Theme-agnostic: it uses the existing brand tokens, so the
 * palette is unchanged. Everything degrades to plain, full-opacity text when JS
 * is off, when GSAP is absent, and under prefers-reduced-motion.
 */

/* Per-word spans the scramble engine creates. inline-block lets the JS pin each
 * word to its plaintext width, so cipher glyphs never reflow the line. The real
 * text lives in the source until JS replaces it, so crawlers/JS-off see plain. */
.sw { display: inline-block; white-space: nowrap; }

/* Statement band: words rest faint and resolve to full opacity on scroll scrub.
 * These spans exist only once decrypt.js wraps them (full-motion only), so JS-off
 * and reduced-motion show the paragraph at full opacity. The .nsx-reduced guard
 * is belt-and-braces. The .mute/.accent colour wrappers are preserved underneath. */
.band h2 .w { opacity: 0.15; }
html.nsx-reduced .band h2 .w { opacity: 1; }

/* WebGL hero noise canvas: an absolute layer inside the hero (which is already
 * position:relative; overflow:hidden; isolation:isolate). It sits above the
 * hero's decorative ::before/::after grid and below the hero content. decrypt.js
 * only ever shows it on desktop + dark; on mobile, in light mode, and under
 * reduced-motion it is removed, leaving today's hero look untouched. */
#nsx-bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  display: block;
  pointer-events: none;
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 80%, transparent 100%);
          mask-image: linear-gradient(to bottom, #000 0%, #000 80%, transparent 100%);
}
.hp .hero-inner,
.ent .hero-inner { position: relative; z-index: 1; }

@media (prefers-reduced-motion: reduce) {
  #nsx-bg { display: none !important; }
}
