/* ============================================================================
 * mark-motion.css — HOW THE WORDMARK MOVES
 * ---------------------------------------------------------------------------
 * Loaded last on purpose. The mark's motion is one idea and it was previously
 * spread across scenes.css and polish.css, where half of it was overriding the
 * other half; this file owns it end to end and wins on cascade order rather
 * than on specificity tricks.
 *
 * THE TRANSFORMS ARE ON THREE SEPARATE ELEMENTS AND THAT IS LOAD-BEARING.
 * A single element can only hold one transform, so a float, a tilt and a
 * per-row displacement on one node means the last rule silently deletes the
 * other two. They are split by clock instead:
 *
 *   .hero__mark-stage   the viewer  — pointer tilt + idle tilt, eased, slow
 *   .hero__mark-drift   the body    — the float, written per frame from JS
 *   .hero__wordmark-row the surface — the sway, plus glitch displacement
 *
 * Because they nest, the three compose by multiplication and each one can be
 * retuned without touching the others.
 * ========================================================================== */

/* ---------------------------------------------------------------------------
 * THE VIEWER. Transitioned, so the pointer response has weight and the idle
 * tilt — which JS updates every frame — arrives damped rather than twitching.
 * ------------------------------------------------------------------------ */
/* EVERY LIVE VARIABLE IS DECLARED HERE, ON THE ELEMENT JAVASCRIPT WRITES TO.
   Declaring `--float-x` on .hero__mark-drift instead looks equivalent and is
   not: a custom property set on a descendant SHADOWS the inherited value, so
   the drift read its own 0px and the float resolved to an identity matrix while
   the stage was correctly updating sixty times a second. Defaults belong at the
   top of the inheritance chain; descendants only consume. */
/* THE STAGE DOES NOT MOVE. This carried a live transform built from four
   variables — `--mark-x/-y` (pointer translate) and `--mark-rx/-ry` +
   `--idle-rx/-ry` (pointer tilt and an idle tilt that took over when the
   pointer went still). That is cursor-reactive perspective on the largest
   object on the page, and it is exactly what should not happen: moving the
   mouse tilted and slid the whole title.
   No transform, no transition, no float/lift/shadow variables — they existed
   only to feed motion that is now gone (the JS that wrote them is deleted in
   mark.js). The mark holds its position; only its INTERNALS glitch. */
.hero__mark-stage {
  transform: none;
}

/* ---------------------------------------------------------------------------
 * THE BODY. No transition — this is written every frame and any easing here
 * would fight the oscillators and turn the float into a lag.
 *
 * The shadow is the levitation. Its offset, softness and opacity all come from
 * the same height value the translate does, so the mark casts further and
 * fainter at the top of the bob. A fixed shadow under a moving object is the
 * single clearest tell that something is a picture rather than a thing.
 * ------------------------------------------------------------------------ */
/* The body no longer drifts — no transform, no per-frame float, and no
   drop-shadow (a blurred shadow around the mark is a halo, and the glow is
   gone everywhere). It is a plain box that holds the three stacked layers. */
.hero__mark-drift {
  transform: none;
}

/* The cast shadow read the float's `--lift`/`--shadow-*`, which nothing writes
   any more, so it resolved to a static ellipse that only ever said "this is
   levitating" about an object that no longer levitates. Left to scenes.css,
   which sizes it; the levitation coupling is deleted. */

/* ---------------------------------------------------------------------------
 * THE SURFACE. Rows are block spans inside the <pre>, one per line of the
 * drawing, so each can be displaced independently.
 * ------------------------------------------------------------------------ */
.hero__wordmark-row {
  --row-shift: 0ch;
  display: block;
  white-space: pre;
  will-change: transform;
}

/* The mark holds still at rest — no idle sway. `--row-shift` is still a real
   transform, not a no-op: it's what a datamosh burst (mark.js `slide`) uses to
   physically displace a row instead of only corrupting its characters. */
.hero__wordmark-row,
.hero__wordmark--echo .hero__wordmark-row {
  transform: translate3d(var(--row-shift, 0ch), 0, 0);
}

/* Cursor-loosened character packets. The layer shares the wordmark's local
   coordinate system and is allowed to overflow downward while gravity runs. */
.hero__mark-fall-layer {
  position: fixed;
  /* Above the cinematic hero (z:1), below the white chapter sheet (z:7). */
  z-index: 6;
  inset: 0;
  overflow: visible;
  pointer-events: none;
  contain: strict;
}

.hero__mark-pixel {
  position: absolute;
  display: block;
  margin: 0;
  padding: 0;
  white-space: pre;
  color: #fffaf0;
  -webkit-text-stroke: 0.4px rgba(2, 4, 6, 0.94);
  paint-order: stroke fill;
  text-shadow:
    -1px 0 0 rgba(2, 4, 6, 0.76),
    1px 0 0 rgba(2, 4, 6, 0.76),
    0 1px 1px rgba(2, 4, 6, 0.98),
    0 2px 4px rgba(2, 4, 6, 0.68);
  transform-origin: center;
  will-change: transform, opacity;
  pointer-events: none;
}


/* ---------------------------------------------------------------------------
 * THE BREAK
 * The characters are corrupted in JS. What is left for CSS is the separation:
 * two registrations pulled apart in opposite directions so the burst reads as
 * split channels rather than as the element being shaken.
 * ------------------------------------------------------------------------ */
.hero__wordmark--echo {
  grid-area: 1 / 1;
  position: relative;
  z-index: 2;
  opacity: 0;
  pointer-events: none;
  mix-blend-mode: multiply;
}

.hero__mark-stage.is-glitching .hero__wordmark--echo-a {
  color: var(--world-accent, var(--ink));
  opacity: 0.4;
  transform: translate3d(var(--glitch-a, 4px), var(--glitch-y, 0px), 2px);
}

.hero__mark-stage.is-glitching .hero__wordmark--echo-b {
  color: var(--ink-dim);
  opacity: 0.3;
  transform: translate3d(var(--glitch-b, -3px), calc(0px - var(--glitch-y, 0px)), -2px);
}

/* Every burst chooses a registration geometry. The character damage comes
   from JavaScript; these masks decide how that damage occupies the mark. */
.hero__mark-stage[data-glitch-style="scan"] .hero__wordmark--echo-a {
  clip-path: polygon(0 4%, 100% 4%, 100% 13%, 0 13%, 0 41%, 100% 41%, 100% 49%, 0 49%, 0 78%, 100% 78%, 100% 86%, 0 86%);
}

.hero__mark-stage[data-glitch-style="scan"] .hero__wordmark--echo-b {
  clip-path: polygon(0 18%, 100% 18%, 100% 28%, 0 28%, 0 57%, 100% 57%, 100% 66%, 0 66%, 0 91%, 100% 91%, 100% 98%, 0 98%);
}

.hero__mark-stage[data-glitch-style="slice"] .hero__wordmark--echo-a {
  clip-path: polygon(0 22%, 100% 22%, 100% 39%, 0 39%, 0 63%, 100% 63%, 100% 72%, 0 72%);
}

.hero__mark-stage[data-glitch-style="slice"] .hero__wordmark--echo-b {
  clip-path: polygon(0 8%, 100% 8%, 100% 17%, 0 17%, 0 45%, 100% 45%, 100% 58%, 0 58%, 0 81%, 100% 81%, 100% 94%, 0 94%);
}

.hero__mark-stage[data-glitch-style="ghost"] .hero__wordmark--echo-a {
  opacity: 0.22;
  filter: blur(0.45px);
  transform: translate3d(var(--glitch-a, 4px), 1px, 2px) scale(1.003);
}

.hero__mark-stage[data-glitch-style="ghost"] .hero__wordmark--echo-b {
  opacity: 0.18;
  transform: translate3d(var(--glitch-b, -3px), -1px, -2px) scale(0.997);
}

.hero__mark-stage[data-glitch-style="crush"] .hero__wordmark:not(.hero__wordmark--echo) {
  transform: scaleY(0.985) skewX(-0.16deg);
  transform-origin: center;
}

.hero__mark-stage[data-glitch-style="vertical"] .hero__wordmark--echo-a {
  transform: translate3d(1px, 5px, 2px);
  clip-path: inset(7% 0 46% 0);
}

.hero__mark-stage[data-glitch-style="vertical"] .hero__wordmark--echo-b {
  transform: translate3d(-1px, -4px, -2px);
  clip-path: inset(52% 0 5% 0);
}

.hero__mark-stage[data-glitch-style="terminal"] .hero__wordmark--echo-a {
  opacity: 0.48;
  color: var(--world-accent, var(--signal));
  clip-path: polygon(0 0, 100% 0, 100% 10%, 0 10%, 0 32%, 100% 32%, 100% 45%, 0 45%, 0 70%, 100% 70%, 100% 100%, 0 100%);
}

.hero__mark-stage[data-glitch-style="strobe"] .hero__wordmark--echo-a,
.hero__mark-stage[data-glitch-style="strobe"] .hero__wordmark--echo-b {
  animation: mark-channel-strobe 96ms steps(2, jump-none) infinite;
}

/* Packet loss: isolated blocks lose registration independently instead of
   shifting the complete wordmark as one slab. */
.hero__mark-stage[data-glitch-style="packet"] .hero__wordmark--echo-a {
  opacity: 0.5;
  -webkit-mask-image: linear-gradient(#000 0 0), linear-gradient(#000 0 0), linear-gradient(#000 0 0);
  -webkit-mask-position: 4% 17%, 100% 52%, 29% 84%;
  -webkit-mask-repeat: no-repeat;
  -webkit-mask-size: 43% 9%, 57% 12%, 36% 8%;
  mask-image: linear-gradient(#000 0 0), linear-gradient(#000 0 0), linear-gradient(#000 0 0);
  mask-position: 4% 17%, 100% 52%, 29% 84%;
  mask-repeat: no-repeat;
  mask-size: 43% 9%, 57% 12%, 36% 8%;
  transform: translate3d(calc(var(--glitch-a, 4px) * 1.3), 0, 2px);
}

.hero__mark-stage[data-glitch-style="packet"] .hero__wordmark--echo-b {
  opacity: 0.36;
  -webkit-mask-image: linear-gradient(#000 0 0), linear-gradient(#000 0 0), linear-gradient(#000 0 0);
  -webkit-mask-position: 93% 28%, 0 66%, 72% 94%;
  -webkit-mask-repeat: no-repeat;
  -webkit-mask-size: 31% 7%, 48% 10%, 25% 6%;
  mask-image: linear-gradient(#000 0 0), linear-gradient(#000 0 0), linear-gradient(#000 0 0);
  mask-position: 93% 28%, 0 66%, 72% 94%;
  mask-repeat: no-repeat;
  mask-size: 31% 7%, 48% 10%, 25% 6%;
}

/* Barcode phase: alternating narrow columns reveal the damaged channels. */
.hero__mark-stage[data-glitch-style="barcode"] .hero__wordmark--echo-a {
  opacity: 0.48;
  -webkit-mask-image: repeating-linear-gradient(90deg, #000 0 3px, transparent 3px 9px);
  mask-image: repeating-linear-gradient(90deg, #000 0 3px, transparent 3px 9px);
  transform: translate3d(var(--glitch-a, 5px), 0, 2px) skewX(-0.45deg);
}

.hero__mark-stage[data-glitch-style="barcode"] .hero__wordmark--echo-b {
  opacity: 0.32;
  -webkit-mask-image: repeating-linear-gradient(90deg, transparent 0 4px, #000 4px 7px, transparent 7px 11px);
  mask-image: repeating-linear-gradient(90deg, transparent 0 4px, #000 4px 7px, transparent 7px 11px);
}

/* Wave desynchronisation: selected rows drift while the silhouette holds. */
.hero__mark-stage[data-glitch-style="wave"] .hero__wordmark--echo-a .hero__wordmark-row:nth-child(4n + 1) {
  translate: 5px 0;
}

.hero__mark-stage[data-glitch-style="wave"] .hero__wordmark--echo-a .hero__wordmark-row:nth-child(4n + 3) {
  translate: -3px 0;
}

.hero__mark-stage[data-glitch-style="wave"] .hero__wordmark--echo-b .hero__wordmark-row:nth-child(5n + 2) {
  translate: -5px 0;
}

/* This beam is clipped to the wordmark's own box, never the viewport. */
.hero__mark-stage[data-glitch-style="scanbeam"].is-glitching::after {
  content: "";
  position: absolute;
  z-index: 4;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(180deg, transparent 0 42%, rgba(255, 250, 240, 0.18) 46%, rgba(255, 250, 240, 0.48) 49%, transparent 53% 100%);
  mix-blend-mode: screen;
  animation: mark-scanbeam 240ms steps(5, jump-none) infinite;
  clip-path: inset(0 1%);
}

.hero__mark-stage[data-glitch-style="compression"] .hero__wordmark:not(.hero__wordmark--echo) .hero__wordmark-row:nth-child(5n + 1) {
  translate: -0.12em 0;
  scale: 1.008 0.82;
  transform-origin: center;
}

.hero__mark-stage[data-glitch-style="compression"] .hero__wordmark--echo-a {
  opacity: 0.34;
  clip-path: polygon(0 13%, 100% 13%, 100% 20%, 0 20%, 0 47%, 100% 47%, 100% 54%, 0 54%, 0 73%, 100% 73%, 100% 79%, 0 79%);
}

.hero__mark-stage.is-afterimage .hero__wordmark--echo-a {
  color: var(--world-accent, var(--ink));
  opacity: 0.075;
  transform: translate3d(2px, 0, -1px);
  filter: blur(0.3px);
}

.hero__mark-stage.is-afterimage .hero__wordmark--echo-b {
  color: var(--ink);
  opacity: 0.045;
  transform: translate3d(-2px, 0, -2px);
}

@keyframes mark-channel-strobe {
  0% { opacity: 0.08; }
  50% { opacity: 0.48; }
  100% { opacity: 0.18; }
}

@keyframes mark-scanbeam {
  0% { translate: 0 -44%; opacity: 0; }
  20% { opacity: 0.8; }
  100% { translate: 0 48%; opacity: 0; }
}

/* A hard burst additionally crushes the contrast of the true layer for the few
   frames it lasts. Steps, never a smooth curve — this is a signal fault. */
.hero__mark-stage.is-glitching-hard .hero__wordmark:not(.hero__wordmark--echo) {
  animation: mark-hard-hit 120ms steps(3, jump-none) infinite;
}

@keyframes mark-hard-hit {
  0%   { filter: none; }
  50%  { filter: contrast(1.5) brightness(0.94); }
  100% { filter: none; }
}
