/* ==========================================================================
   LexicMedia — Motion layer
   Preloader, custom cursor, inertia scroll, masked text reveals, parallax,
   magnetic buttons, marquee, scroll progress, page-transition curtain.

   Modelled on Montfort's motion stack (Lenis smooth scroll, custom cursor,
   counting preloader, line masks) but hand-rolled — no dependencies.

   Everything here is transform/opacity only, and every effect is disabled
   under prefers-reduced-motion (see the block at the end of this file).
   ========================================================================== */

:root {
  --ease-expo:  cubic-bezier(0.16, 1, 0.3, 1);
  --ease-power: cubic-bezier(0.65, 0, 0.35, 1);
  --dur-mask:   0.9s;
}

/* --------------------------------------------------------------------------
   1. Preloader — counting number behind a sweeping progress ring
   -------------------------------------------------------------------------- */

.preloader {
  position: fixed;
  inset: 0;
  z-index: 9999;
  display: grid;
  place-items: center;
  background: var(--ink);
  pointer-events: all;
}

.preloader__inner {
  position: relative;
  display: grid;
  place-items: center;
  width: 160px;
  height: 160px;
  transition: opacity 0.3s var(--ease), transform 0.45s var(--ease-expo);
}

.preloader__ring { position: absolute; inset: 0; transform: rotate(-90deg); }
.preloader__ring circle {
  fill: none;
  stroke-width: 1.5;
  cx: 80px; cy: 80px; r: 76px;
}
.preloader__track { stroke: rgba(255, 255, 255, 0.1); }
.preloader__bar {
  stroke: var(--tint-1);
  stroke-dasharray: 477.5;          /* 2πr, r = 76 */
  stroke-dashoffset: 477.5;
  transition: stroke-dashoffset 0.18s linear;
}

.preloader__mark {
  display: block;
  width: 92px;
  animation: markIn .7s var(--ease-expo) both;
}
.preloader__mark svg { width: 100%; height: auto; }

@keyframes markIn {
  from { opacity: 0; transform: translateY(8px) scale(.94); }
  to   { opacity: 1; transform: none; }
}

/* The count sits under the mark as a quiet progress cue, not the main event */
.preloader__count {
  position: absolute;
  bottom: -2.4rem;
  font-family: var(--font-display);
  font-size: 0.72rem;
  font-weight: 400;
  letter-spacing: var(--track-mid);
  color: var(--text-on-dark-3);
  font-variant-numeric: tabular-nums;
}

.preloader__label {
  position: absolute;
  bottom: -2.6rem;
  font-family: var(--font-display);
  font-size: 0.62rem;
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--text-on-dark-3);
  white-space: nowrap;
}

/* Exit: the inner mark lifts away, then two panels split vertically */
.preloader.is-done .preloader__inner { opacity: 0; transform: translateY(-14px); }

.preloader__panel {
  position: absolute;
  left: 0;
  width: 100%;
  height: 50.5%;
  background: var(--ink);
  transition: transform 0.62s var(--ease-expo);
  transition-delay: 0.12s;
}
.preloader__panel--t { top: 0; }
.preloader__panel--b { bottom: 0; }
.preloader.is-done .preloader__panel--t { transform: translateY(-100%); }
.preloader.is-done .preloader__panel--b { transform: translateY(100%); }

.preloader.is-hidden { display: none; }

/* Hold the page still while the loader is up */
body.is-loading { overflow: hidden; }

/* --------------------------------------------------------------------------
   2. Custom cursor — lerped follower, grows over interactive targets
   -------------------------------------------------------------------------- */

.cursor {
  position: fixed;
  top: 0; left: 0;
  z-index: 9000;
  width: 34px; height: 34px;
  margin: -17px 0 0 -17px;
  border: 1px solid var(--tint-1);
  border-radius: 50%;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.35s linear,
              width 0.4s var(--ease-expo),
              height 0.4s var(--ease-expo),
              margin 0.4s var(--ease-expo),
              background 0.4s var(--ease),
              border-color 0.4s var(--ease);
  will-change: transform;
}
.cursor.is-active { opacity: 1; }

/* The small solid dot rides at the exact pointer position */
.cursor-dot {
  position: fixed;
  top: 0; left: 0;
  z-index: 9001;
  width: 5px; height: 5px;
  margin: -2.5px 0 0 -2.5px;
  border-radius: 50%;
  background: var(--tint-1);
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.35s linear, transform 0.3s var(--ease);
  will-change: transform;
}
.cursor-dot.is-active { opacity: 1; }

/* Over a link or button */
.cursor.is-hover {
  width: 64px; height: 64px;
  margin: -32px 0 0 -32px;
  background: rgba(127, 212, 203, 0.12);
  border-color: rgba(127, 212, 203, 0.5);
}
.cursor-dot.is-hover { transform: scale(0); }

/* Over a dark section, flip to white for contrast */
.cursor.is-light { border-color: rgba(255, 255, 255, 0.85); }
.cursor-dot.is-light { background: #fff; }

/* Pointer-fine devices only — never on touch */
@media (hover: none), (pointer: coarse) {
  .cursor, .cursor-dot { display: none !important; }
}

/* --------------------------------------------------------------------------
   3. Scroll progress
   -------------------------------------------------------------------------- */

.scroll-progress {
  position: fixed;
  top: 0; left: 0;
  z-index: 120;
  height: 2px;
  width: 100%;
  transform: scaleX(0);
  transform-origin: left center;
  background: linear-gradient(90deg, var(--primary), var(--tint-1));
  pointer-events: none;
  will-change: transform;
}

/* --------------------------------------------------------------------------
   4. Masked text reveal — the signature Montfort move
   -------------------------------------------------------------------------- */

.split { }

.split .word {
  display: inline-block;
  overflow: hidden;
  vertical-align: top;
  /* Breathing room so descenders (g, y, p) are not clipped by the mask */
  padding-bottom: 0.18em;
  margin-bottom: -0.18em;
}

.split .word__in {
  display: inline-block;
  transform: translateY(115%);
  transition: transform var(--dur-mask) var(--ease-expo);
  transition-delay: var(--wd, 0ms);
  will-change: transform;
}

.split.is-in .word__in { transform: translateY(0); }

/* Line-level variant for blocks we split by line rather than word */
.split-line {
  display: block;
  overflow: hidden;
  padding-bottom: 0.12em;
  margin-bottom: -0.12em;
}
.split-line > span {
  display: block;
  transform: translateY(110%);
  transition: transform var(--dur-mask) var(--ease-expo);
  transition-delay: var(--wd, 0ms);
}
.is-in > .split-line > span { transform: translateY(0); }

/* --------------------------------------------------------------------------
   5. Clip reveal — panels and cards wipe open
   -------------------------------------------------------------------------- */

.clip-reveal {
  clip-path: inset(0 0 100% 0);
  transition: clip-path 1.05s var(--ease-expo);
  transition-delay: var(--reveal-delay, 0ms);
}
.clip-reveal.is-in { clip-path: inset(0 0 0% 0); }

/* Sweeping highlight that passes over a card once as it enters */
.sheen { position: relative; overflow: hidden; }
.sheen::after {
  content: "";
  position: absolute;
  top: 0; left: -60%;
  width: 45%; height: 100%;
  background: linear-gradient(
    100deg,
    transparent 0%,
    rgba(127, 212, 203, 0.14) 50%,
    transparent 100%
  );
  transform: skewX(-18deg);
  pointer-events: none;
  opacity: 0;
}
.sheen.is-in::after { animation: sheen 1.5s var(--ease-expo) 0.35s 1; }
@keyframes sheen {
  0%   { left: -60%; opacity: 0; }
  25%  { opacity: 1; }
  100% { left: 130%; opacity: 0; }
}

/* --------------------------------------------------------------------------
   6. Parallax
   -------------------------------------------------------------------------- */

[data-parallax] { will-change: transform; }

/* Oversized so the layer can drift without exposing an edge.
   The hero clips it with overflow:hidden. */
.hero__bg { inset: -16% 0; }

/* Hero background layers drift at different rates for depth */
.hero__bg::before { will-change: transform; }

.hero__glow {
  position: absolute;
  top: 8%; right: 4%;
  width: min(46vw, 620px);
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(var(--brand-green-rgb), 0.30) 0%, rgba(var(--brand-green-rgb), 0) 68%);
  filter: blur(14px);
  pointer-events: none;
  animation: drift 16s var(--ease) infinite alternate;
}
@keyframes drift {
  from { transform: translate3d(0, 0, 0) scale(1); }
  to   { transform: translate3d(-5%, 6%, 0) scale(1.14); }
}

/* Slow vertical travel on the hero grid lines */
.hero__bg::after { animation: gridDrift 22s linear infinite; }
@keyframes gridDrift {
  from { background-position: 0 0; }
  to   { background-position: 0 220px; }
}

/* --------------------------------------------------------------------------
   6c2. Cinematic scroll stage

   One fixed, full-viewport canvas that the whole page scrolls over — the
   same structure Montfort uses. Light sections stay fully opaque so body
   copy is never compromised; dark bands go translucent so the scene shows
   through and keeps evolving as you scroll.
   -------------------------------------------------------------------------- */

.webgl-stage {
  position: fixed;
  inset: 0;
  z-index: 0;
  width: 100vw;
  height: 100vh;
  pointer-events: none;
  opacity: 0;
  transition: opacity 1.6s var(--ease) .2s;
}
.webgl-stage.is-on { opacity: 1; }

/* Everything above the stage. Only applied when the stage actually exists,
   so a WebGL failure leaves the original opaque design untouched. */
html.has-stage { background: var(--ink); }
html.has-stage body { background: transparent; }

/* Only the in-flow content needs lifting above the stage. The header and the
   mobile menu are position:fixed with their own z-index already — forcing
   them to `relative` here dropped the full-screen mobile menu into the
   document flow as a ~1000px invisible block above the hero, and un-stuck
   the header. It only showed below 1180px, where the mobile menu exists. */
html.has-stage main,
html.has-stage .footer { position: relative; z-index: 1; }

/* Light grounds must stay solid — text legibility beats atmosphere */
html.has-stage .section { background: var(--paper); }
html.has-stage .section--paper { background: var(--paper-2); }

/* Dark grounds let the scene through */
html.has-stage .hero { background: transparent; }
html.has-stage .hero__bg::before { opacity: .72; }

html.has-stage .section--dark { background: rgba(12, 17, 22, .80); }
html.has-stage .cta-band { background: rgba(12, 17, 22, .76); }
html.has-stage .proof-bar,
html.has-stage .stat { background: rgba(18, 27, 33, .82); }
html.has-stage .marquee { background: rgba(18, 27, 33, .78);   overflow: hidden;
  max-width: 100%;
}
html.has-stage .footer { background: rgba(7, 11, 15, .88); }

/* The pinned track is a dark section too */
html.has-stage .pin-track__panel { background: rgba(18, 27, 33, .88); }

html.motion-off .webgl-stage { display: none !important; }
@media (prefers-reduced-motion: reduce) {
  html:not(.motion-on) .webgl-stage { display: none !important; }
}

/* --------------------------------------------------------------------------
   6d. Matrix rain
   Rendered in the brand tints rather than the traditional green, and masked
   away from the headline column so text contrast is never compromised.
   -------------------------------------------------------------------------- */

.matrix-rain {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  opacity: 0;
  transition: opacity 1.4s var(--ease) 0.3s;
  /* Keep the left column clear. The lead paragraph runs to roughly 55% of
     the viewport at desktop widths, so the rain only starts beyond that —
     otherwise glyphs sit behind the copy and cost it contrast. */
  mask-image: linear-gradient(90deg, transparent 0%, transparent 58%, #000 88%, #000 100%);
  -webkit-mask-image: linear-gradient(90deg, transparent 0%, transparent 58%, #000 88%, #000 100%);
}
.matrix-rain.is-on { opacity: 0.5; }

@media (max-width: 859px) {
  /* No clear column on small screens, so fade it in from the bottom instead */
  .matrix-rain {
    mask-image: linear-gradient(180deg, transparent 0%, transparent 45%, #000 100%);
    -webkit-mask-image: linear-gradient(180deg, transparent 0%, transparent 45%, #000 100%);
  }
  .matrix-rain.is-on { opacity: 0.3; }
}

html.motion-off .matrix-rain { display: none !important; }
@media (prefers-reduced-motion: reduce) {
  html:not(.motion-on) .matrix-rain { display: none !important; }
}

/* --------------------------------------------------------------------------
   7. Magnetic buttons
   -------------------------------------------------------------------------- */

.magnetic {
  will-change: transform;
  transition: transform 0.5s var(--ease-expo);
}
.magnetic.is-pulling { transition: transform 0.15s linear; }

/* --------------------------------------------------------------------------
   8. Marquee
   -------------------------------------------------------------------------- */

.marquee {
  position: relative;
  display: flex;
  overflow: hidden;
  padding-block: clamp(1.5rem, 3vw, 2.5rem);
  border-block: 1px solid var(--hairline-dark-2);
  background: var(--ink-2);
  user-select: none;
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}

.marquee__track {
  display: flex;
  flex: none;
  gap: clamp(2rem, 5vw, 4rem);
  padding-right: clamp(2rem, 5vw, 4rem);
  animation: marquee 38s linear infinite;
  will-change: transform;
}
.marquee:hover .marquee__track { animation-play-state: paused; }

@keyframes marquee {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-100%, 0, 0); }
}

.marquee__item {
  display: flex;
  align-items: center;
  gap: clamp(2rem, 5vw, 4rem);
  font-family: var(--font-display);
  font-size: clamp(1.1rem, 0.8rem + 1.4vw, 2rem);
  font-weight: 300;
  letter-spacing: var(--track-mid);
  text-transform: uppercase;
  color: var(--text-on-dark-3);
  white-space: nowrap;
  transition: color var(--dur) var(--ease);
}
.marquee__item::after {
  content: "◆";
  font-size: 0.5em;
  color: var(--primary);
}
.marquee:hover .marquee__item { color: var(--text-on-dark); }

/* --------------------------------------------------------------------------
   9. Page transition curtain
   -------------------------------------------------------------------------- */

.curtain {
  position: fixed;
  inset: 0;
  z-index: 8000;
  background: var(--ink);
  transform: translateY(100%);
  pointer-events: none;
  will-change: transform;
}
.curtain.is-covering {
  transform: translateY(0);
  transition: transform 0.6s var(--ease-power);
}
.curtain.is-clearing {
  transform: translateY(-100%);
  transition: transform 0.7s var(--ease-expo);
}

/* --------------------------------------------------------------------------
   10. Nav + link micro-interactions
   -------------------------------------------------------------------------- */

/* Nav label swaps for a duplicate sliding up from below.
   The clip lives on its own element: putting overflow:hidden on .nav__link
   would leave the ghost label visible inside the link's vertical padding. */
.nav__clip {
  display: block;
  overflow: hidden;
  line-height: 1.5;
}
.nav__clip .nav__swap {
  display: block;
  position: relative;
  transition: transform 0.45s var(--ease-expo);
}
.nav__clip .nav__swap::after {
  content: attr(data-text);
  position: absolute;
  top: 100%; left: 0;
  width: 100%;
}
.nav__link:hover .nav__clip .nav__swap,
.nav__link:focus-visible .nav__clip .nav__swap { transform: translateY(-100%); }

/* Stat numbers get a subtle rise as they count */
.stat__num { overflow: hidden; }

/* Counter digits */
.counting { font-variant-numeric: tabular-nums; }

/* --------------------------------------------------------------------------
   11. Scroll cue refinement
   -------------------------------------------------------------------------- */

.scroll-cue { animation: cueFloat 2.8s var(--ease) infinite; }
@keyframes cueFloat {
  0%, 100% { transform: translateX(-50%) translateY(0); }
  50%      { transform: translateX(-50%) translateY(6px); }
}

/* --------------------------------------------------------------------------
   12. Reduced motion — switch the whole layer off
   -------------------------------------------------------------------------- */

/* Scoped to :not(.motion-on) so a visitor who has reduced motion set at the OS
   level can still opt back in via the footer toggle. Without the override,
   nothing here can be re-enabled from JavaScript — the !important wins. */
@media (prefers-reduced-motion: reduce) {
  html:not(.motion-on) .preloader { display: none !important; }
  html:not(.motion-on) body.is-loading { overflow: auto; }

  html:not(.motion-on) .cursor,
  html:not(.motion-on) .cursor-dot,
  html:not(.motion-on) .curtain,
  html:not(.motion-on) .scroll-progress { display: none !important; }

  html:not(.motion-on) .split .word__in,
  html:not(.motion-on) .split-line > span { transform: none !important; transition: none !important; }

  html:not(.motion-on) .clip-reveal { clip-path: none !important; transition: none !important; }
  html:not(.motion-on) .sheen::after { display: none; }

  html:not(.motion-on) .marquee__track { animation: none; transform: none; }
  html:not(.motion-on) .hero__glow { animation: none; }
  html:not(.motion-on) .hero__bg::after { animation: none; }
  html:not(.motion-on) .scroll-cue { animation: none; }
  html:not(.motion-on) .magnetic { transition: none; }
  html:not(.motion-on) .pin-track { height: auto !important; }
  html:not(.motion-on) .pin-track__sticky { position: static; height: auto; }
  html:not(.motion-on) .pin-track__rail {
    transform: none !important;
    flex-wrap: nowrap;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
  }
  html:not(.motion-on) .pin-track__panel { scroll-snap-align: start; flex: 0 0 min(76vw, 30rem); }
}

/* Explicit opt-out, regardless of OS setting */
html.motion-off .preloader,
html.motion-off .cursor,
html.motion-off .cursor-dot,
html.motion-off .curtain,
html.motion-off .scroll-progress { display: none !important; }
html.motion-off .split .word__in,
html.motion-off .split-line > span { transform: none !important; transition: none !important; }
html.motion-off .clip-reveal { clip-path: none !important; }
html.motion-off .marquee__track,
html.motion-off .hero__glow,
html.motion-off .hero__bg::after,
html.motion-off .scroll-cue { animation: none !important; }
html.motion-off [data-parallax],
html.motion-off [data-parallax-x],
html.motion-off [data-parallax-scale] { transform: none !important; }
/* Motion off: the phases still read as a horizontal strip, just driven by the
   visitor's own scroll instead of being scrubbed by the page. Wrapping them
   into a grid — which is what this used to do — lost the sequence that makes
   "four phases" legible at a glance. */
html.motion-off .pin-track { height: auto !important; }
html.motion-off .pin-track__sticky { position: static; height: auto; }
html.motion-off .pin-track__rail {
  transform: none !important;
  flex-wrap: nowrap;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  padding-bottom: 1rem;
  scrollbar-width: thin;
}
html.motion-off .pin-track__panel {
  scroll-snap-align: start;
  flex: 0 0 min(76vw, 30rem);
}
html.no-js .pin-track__rail { flex-wrap: nowrap; overflow-x: auto; }

/* --------------------------------------------------------------------------
   13. Motion toggle control
   -------------------------------------------------------------------------- */

.motion-toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  font-family: var(--font-display);
  font-size: var(--fs-xs);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-on-dark-3);
  transition: color var(--dur) var(--ease);
}
.motion-toggle:hover { color: #fff; }

.motion-toggle__track {
  position: relative;
  width: 30px; height: 16px;
  border: 1px solid currentColor;
  border-radius: 999px;
  flex: none;
}
.motion-toggle__dot {
  position: absolute;
  top: 50%; left: 3px;
  width: 8px; height: 8px;
  margin-top: -4px;
  border-radius: 50%;
  background: currentColor;
  transition: transform var(--dur) var(--ease);
}
.motion-toggle[aria-pressed="true"] { color: var(--tint-1); }
.motion-toggle[aria-pressed="true"] .motion-toggle__dot { transform: translateX(13px); }

/* --------------------------------------------------------------------------
   14. Pinned horizontal track
   -------------------------------------------------------------------------- */

.pin-track { position: relative; }

.pin-track__sticky {
  position: sticky;
  top: 0;
  /* Sized to its content, not to the screen. At 100vh the head and rail —
     together about 465px — sat in the middle of a 900px pinned viewport, so
     every screen of this section carried roughly 435px of empty dark. The
     JS reads this height back when it works out the scroll distance. */
  height: auto;
  max-height: 100svh;
  padding-top: calc(var(--header-h, 76px) + var(--space-l));
  padding-bottom: var(--space-xl);
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--space-m);
  overflow: hidden;
}

.pin-track__head {
  padding-inline: var(--gutter);
  max-width: var(--container);
  margin-inline: auto;
  width: 100%;
  margin-bottom: clamp(2rem, 4vw, 3.5rem);
}

.pin-track__rail {
  display: flex;
  gap: clamp(1.25rem, 2.5vw, 2rem);
  padding-inline: max(var(--gutter), calc((100vw - var(--container)) / 2 + var(--gutter)));
  will-change: transform;
}

.pin-track__panel {
  flex: none;
  /* The rail's overflow becomes vertical scroll distance: every pixel the
     panels stick out past the viewport is a pixel of scrolling where the page
     does not otherwise change. At 400px the five panels overhung by 816px,
     which read as a long stretch of empty dark. */
  width: min(78vw, 320px);
  padding: clamp(1.75rem, 3vw, 2.75rem);
  background: var(--ink-2);
  border: 1px solid var(--hairline-dark-2);
  border-radius: var(--radius);
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.pin-track__panel:hover { border-color: rgba(127, 212, 203,0.4); background: var(--ink-3); }

.pin-track__num {
  font-family: var(--font-display);
  font-size: var(--fs-xs);
  letter-spacing: var(--track-mid);
  color: var(--tint-1);
  margin-bottom: var(--space-m);
  display: block;
}
.pin-track__title { font-size: var(--fs-h3); font-weight: 400; margin-bottom: 0.75rem; color: var(--text-on-dark); }
.pin-track__body { font-size: var(--fs-sm); line-height: 1.72; color: var(--text-on-dark-3); }

.pin-track__bar {
  margin-top: clamp(2rem, 4vw, 3rem);
  height: 1px;
  background: var(--hairline-dark-2);
  max-width: var(--container);
  width: calc(100% - var(--gutter) * 2);
  margin-inline: auto;
  position: relative;
}
.pin-track__bar span {
  position: absolute;
  inset: 0 auto 0 0;
  width: 100%;
  background: var(--tint-1);
  transform: scaleX(0);
  transform-origin: left center;
}

/* Below the pin breakpoint the desktop pinning cannot work — but stacking the
   panels into a plain list threw away the horizontal motion entirely, which is
   the single most distinctive thing on the page. Instead the rail becomes a
   native swipeable snap carousel: same content, same sideways feel, driven by
   the gesture touch users already expect. */
@media (max-width: 859px) {
  .pin-track { height: auto !important; }
  .pin-track__sticky { position: static; height: auto; overflow: visible; }

  .pin-track__rail {
    flex-wrap: nowrap;
    transform: none !important;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    padding-inline: var(--gutter);
    padding-bottom: 0.5rem;
  }
  .pin-track__rail::-webkit-scrollbar { display: none; }

  .pin-track__panel {
    width: min(78vw, 340px);
    flex: none;
    scroll-snap-align: center;
  }

  /* The progress rail stays, now driven by the carousel's own scroll */
  .pin-track__bar {
    display: block;
    width: calc(100% - var(--gutter) * 2);
    margin-top: var(--space-m);
  }

  /* Nudge that the panels move sideways */
  .pin-track__head::after {
    content: "Swipe to explore →";
    display: block;
    margin-top: 1rem;
    font-family: var(--font-display);
    font-size: 0.66rem;
    letter-spacing: var(--track-mid);
    text-transform: uppercase;
    color: var(--tint-1);
  }
}

html.motion-off .webgl-stage { display: none !important; }
@media (prefers-reduced-motion: reduce) {
  html:not(.motion-on) .webgl-stage { display: none !important; }
}

/* No JavaScript — nothing may stay hidden */
.no-js .preloader { display: none; }
.no-js .split .word__in,
.no-js .split-line > span { transform: none; }
.no-js .clip-reveal { clip-path: none; }
