/* ============================================================
   AREA 52 — chrome / deep-space hero
   Reference: area52htx.netlify.app (Spline link-in-bio scene)
   ============================================================ */

/* v1 brand palette: void #0b0a18 · nebula #241640 · violet #4d3a85
   bone #f2ede0 · beam #a6ff4d · amber #ffae42 · ember #ff6b35 */
/* wordmark face (client pick 2026-08-25, from a 4-font exploration):
   Super Sliced, self-hosted — freeware whose COMMERCIAL use asks a
   donation to the author (see assets/fonts/SuperSliced-license.txt;
   flagged to the client). Michroma stays for the CTAs. */
@font-face {
  font-family: 'Super Sliced';
  src: url('../assets/fonts/SuperSliced.ttf') format('truetype');
  font-display: block;
}

:root {
  --void:   #0b0a18;
  --tint:   #241640;   /* nebula core */
  --chrome-hi: #eef1f5;
  --chrome-mid:#9aa3ae;
  --chrome-lo: #3f4854;
  --ink:    #04060a;
  --bone:   #f2ede0;
  --text:   #bdbccb;   /* body gray, violet-cooled */
  --faint:  #8d8b9c;   /* corner labels */
  --amber:  #ffae42;
  --amber-hi:#ffd9a0;
  --beam:   #a6ff4d;
  --beam-soft:#d6ff9e;
  --violet: #a98fe8;   /* the "52" chrome family, text-weight tint */
}

* { margin: 0; padding: 0; box-sizing: border-box; }

html, body {
  height: 100%;
  background: var(--void);
  overflow: hidden;
}

body {
  font-family: "Space Mono", ui-monospace, monospace;
  color: var(--text);
  -webkit-font-smoothing: antialiased;
}

/* ── backdrop ─────────────────────────────────────────────── */

.space-tint {
  position: fixed;
  inset: 0;
  background: radial-gradient(ellipse 80% 62% at 50% 42%, rgba(36, 22, 64, 0.5) 0%, rgba(11, 10, 24, 0) 70%);
  z-index: 0;
}

#stars {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 1;
  opacity: 0;
  animation: fade-in 1.4s ease 0.1s forwards;
}

#meteors { position: fixed; inset: 0; z-index: 1; pointer-events: none; }

/* the HEAD leads: the streak travels along its rotated +x axis, so the
   hot end lives at the RIGHT edge (the old build had the bright end
   trailing) — tinted tapering tail, glowing core dot on the tip */
.meteor {
  position: absolute;
  width: var(--len, 150px);
  height: 2px;
  background: linear-gradient(90deg,
    rgba(184, 204, 255, 0) 0%,
    rgba(184, 204, 255, 0.35) 55%,
    rgba(255, 255, 255, 0.85) 92%,
    #ffffff 100%);
  border-radius: 2px;
  opacity: 0;
  transform: rotate(var(--angle)) translateX(0);
  animation: meteor var(--dur) linear forwards;
  filter: drop-shadow(0 0 4px rgba(220, 230, 255, 0.55));
}
.meteor::after {
  content: '';
  position: absolute;
  right: -3px;
  top: 50%;
  width: 7px;
  height: 7px;
  margin-top: -3.5px;
  border-radius: 50%;
  background: radial-gradient(circle, #ffffff 0%, rgba(255, 255, 255, 0.7) 40%, transparent 70%);
}
.meteor.green {
  background: linear-gradient(90deg,
    rgba(166, 255, 77, 0) 0%,
    rgba(166, 255, 77, 0.4) 55%,
    rgba(214, 255, 158, 0.9) 92%,
    #ffffff 100%);
  filter: drop-shadow(0 0 5px rgba(166, 255, 77, 0.5));
}
.meteor.green::after {
  background: radial-gradient(circle, #ffffff 0%, rgba(214, 255, 158, 0.8) 45%, transparent 70%);
}

@keyframes meteor {
  0%   { opacity: 0; transform: rotate(var(--angle)) translateX(0); }
  6%   { opacity: 1; }
  70%  { opacity: 0.9; }
  100% { opacity: 0; transform: rotate(var(--angle)) translateX(var(--dist)); }
}

/* ── corner HUD ───────────────────────────────────────────── */

.corners { position: fixed; inset: 0; z-index: 4; pointer-events: none; }

.corner {
  position: fixed;
  font-size: 10px;
  letter-spacing: 0.28em;
  color: #cf9c4d;
  opacity: 0;
  animation: fade-in 0.9s ease 1.5s forwards;
}
.corner.tl { top: 22px; left: 26px; }
.corner.bl { bottom: 22px; left: 26px; }
.corner.br { bottom: 22px; right: 26px; }

/* ── mothership badge (logo, top-left) ────────────────────── */

/* Round 28 (client 2026-09-07): the badge wears the site menu, like every
   other page — a DROPDOWN under it on hover-capable devices; on touch the
   badge itself is the button since round 31 (a tap toggles the panel,
   main.js gates it on data-nav="js" so a no-JS visitor keeps a plain
   badge that goes home). The badge links HOME on hover layouts, not to
   the Shopify site. .brand-head owns the fixed slot and the entrance
   fade; .brand keeps its size and tilt. z-index 30: above the world, the
   console (6) and the CTAs. */
.brand-head {
  position: fixed;
  top: 46px;
  left: 26px;
  z-index: 30;
  display: flex;
  align-items: center;
  gap: 10px;
  opacity: 0;
  animation: fade-in 0.9s ease 1.6s forwards;
}
.brand {
  position: relative;
  display: block;
  width: clamp(48px, 6vw, 85px);   /* halved (client round 6) */
  filter: drop-shadow(0 8px 22px rgba(0, 0, 0, 0.55));
}
.brand img {
  display: block;
  width: 100%;
  height: auto;
  transition: transform 0.3s ease;
}
.brand:hover img { transform: rotate(-8deg) scale(1.06); }
.brand:focus-visible {
  outline: 2px solid var(--amber);
  outline-offset: 4px;
  border-radius: 50%;
}
/* the panel: closed = opacity 0 + pointer-events none (never visibility
   hidden — the <nav> landmark must stay in the accessibility tree) */
.brand-nav {
  position: absolute;
  top: 100%;
  left: 0;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  min-width: 216px;                /* SELECT CATEGORY is the longest item */
  padding: 6px 0 0;                /* the hover bridge: inside the panel, so leaving the badge for the menu never closes it */
  opacity: 0;
  pointer-events: none;
  transform: translateY(-6px);
  transition: opacity 0.18s cubic-bezier(0.2, 0.7, 0.2, 1), transform 0.18s cubic-bezier(0.2, 0.7, 0.2, 1);
}
.brand-nav::before {
  content: '';
  position: absolute;
  inset: 6px 0 0 0;
  background: rgba(11, 10, 24, 0.94);
  border: 1px solid rgba(169, 143, 232, 0.22);
  box-shadow: 0 14px 40px rgba(0, 0, 0, 0.55);
  z-index: -1;
}
.brand-nav a {
  font-family: "Space Mono", ui-monospace, monospace;
  font-size: 10px;
  letter-spacing: 0.28em;
  text-decoration: none;
  color: #cf9c4d;
  padding: 11px 18px;
  white-space: nowrap;
  transition: color 0.25s ease;
}
.brand-nav a + a { border-top: 1px solid rgba(169, 143, 232, 0.1); }
.brand-nav a:hover { color: var(--amber-hi); }
.brand-nav a:focus-visible { outline: 2px solid var(--amber); outline-offset: 3px; }
/* the caret beside the badge, drawn with borders (no ▾ glyph in the served subsets) */
.brand::after {
  content: '';
  position: absolute;
  top: 50%;
  right: -13px;
  width: 0;
  height: 0;
  margin-top: -2px;
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  border-top: 5px solid #cf9c4d;
  transition: border-top-color 0.2s ease;
}
.brand-head:hover .brand::after,
.brand-head:focus-within .brand::after { border-top-color: var(--amber-hi); }
@media (hover: hover) {
  /* …unless the pointer or focus is on the SEARCH beside the badge
     (round 32b) or its panel is open — a menu popping open under the
     badge while the pointer rests on the magnifier reads as a glitch */
  .brand-head:hover:not(.search-open):not(:has(.search-btn:hover)) .brand-nav,
  .brand-head:focus-within:not(.search-open):not(:has(.search-btn:focus)) .brand-nav { opacity: 1; pointer-events: auto; transform: translateY(0); }
}
/* touch (round 31: the badge IS the menu button — a tap toggles the
   panel, main.js gates it on data-nav="js"; the caret stays as the tap
   affordance and lights while the panel is open) */
@media (hover: none) {
  .brand-head[data-nav="js"].nav-open .brand-nav { opacity: 1; pointer-events: auto; transform: translateY(0); }
  .brand-head[data-nav="js"].nav-open .brand::after { border-top-color: var(--beam); }
}
/* the SEARCH beside the badge (round 32b — client: "add the search
   feature here as well", circled right of the badge): the shared
   css/search.css + js/search.js panel, mounted by main.js right after
   the badge; only its place lives here. The button's margin clears the
   caret (right: −13px of the badge); the panel hangs under the badge
   row. No cursor rule is added: invariant 8's order is untouched. */
.brand-head .search-btn { margin-left: 14px; }
.brand-head .site-search {
  top: 100%;
  left: 0;
  margin-top: 8px;
  width: min(440px, calc(100vw - 52px));
}
/* the CART entry's count (round 31): the site pages' cart, read from the
   same localStorage; a bare beam-green number that only exists once
   something is in (no pill — client 2026-09-08: "remove the circle
   bordering the number", everywhere) */
.brand-nav .cart-count {
  margin-left: 8px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--beam);
  text-shadow: 0 0 10px rgba(166, 255, 77, 0.55);
}

/* ── camera / world (drag-to-orbit 3D) ────────────────────── */

.camera {
  position: fixed;
  inset: 0;
  z-index: 2;
  perspective: 1200px;
  overflow: hidden;
  touch-action: pinch-zoom;   /* one-finger drag orbits; pinch still zooms */
}

.world {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
  will-change: transform;
}

body.grabbing { user-select: none; -webkit-user-select: none; }

/* ── scene / stage ────────────────────────────────────────── */

.scene {
  /* no min-height floor: inside the clipping camera a floor just
     pushes the CTAs below the fold with no scroll to reach them —
     short viewports center in the real height and shrink via the
     max-height media queries instead */
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  transform-style: preserve-3d;
}

.stage {
  display: flex;
  flex-direction: column;
  align-items: center;
  transform-style: preserve-3d;
  padding: 0 20px;
  margin-top: -3svh;
}

/* ── alien ────────────────────────────────────────────────── */

.alien-wrap {
  /* deepest plane — but NEVER negative: Chromium drops hit-testing for
     perspective content behind Z=0 (verified −20/−70 miss, 0/+10 hit),
     which made the alien unclickable. Every other plane shifts up to
     keep the relative order. */
  --z: 0px;
  width: clamp(150px, 22vh, 230px);
  margin-bottom: calc(clamp(150px, 22vh, 230px) * -0.20);
  position: relative;
  z-index: 1;
  transform: translateZ(var(--z, 0px));
  /* keep the 3D chain continuous down to the ufo layers — a flat,
     transformed wrap re-opening 3D below it makes hit-testing flaky */
  transform-style: preserve-3d;
  opacity: 0;
  animation: alien-digitalize 0.9s steps(1, end) 1.15s both;
}

/* digitalize entrance (client 2026-08-25, replaced the hyperspace
   warp-in): the mascot materializes like the AREA glitch scramble —
   hard-cut static blinks, horizontal slice bands locking in, dropouts,
   then settle. steps(1, end) makes every change a digital cut, no
   fades. Deliberately animates ONLY opacity + clip-path — no transform
   in any keyframe, so the wrap's translateZ(var(--z)) is never touched
   (invariant 2 cannot be tripped). Negative top insets keep the
   antennae inside the "full" flashes; the final frame is clip-path:
   none so nothing stays clipped at rest. */
/* the sides/bottom carry −60%/−50% margins wherever they are NOT an
   intentional glitch slice: the glow filter paints far outside the
   border box, and a 0 inset shears it into a harsh rectangle (client
   bug report 2026-08-25). Only the horizontal band edges stay hard. */
@keyframes alien-digitalize {
  0%       { opacity: 0;    clip-path: inset(-45% -60% 100% -60%); }
  6%       { opacity: 0.7;  clip-path: inset(-45% -60% -50% -60%); }
  9%       { opacity: 0;    clip-path: inset(-45% -60% 100% -60%); }
  16%      { opacity: 0.85; clip-path: inset(-45% -60% 55% -60%); }
  21%      { opacity: 0.25; clip-path: inset(-45% -60% 55% -60%); }
  27%      { opacity: 1;    clip-path: inset(30% -60% 20% -60%); }
  33%      { opacity: 0.5;  clip-path: inset(-45% -60% 34% -60%); }
  40%      { opacity: 1;    clip-path: inset(-45% -60% -50% -60%); }
  46%      { opacity: 0.35; clip-path: inset(12% -60% 40% -60%); }
  53%      { opacity: 1;    clip-path: inset(-45% -60% -50% -60%); }
  60%      { opacity: 0.75; clip-path: inset(-45% -60% 18% -60%); }
  68%      { opacity: 1;    clip-path: inset(-45% -60% -50% -60%); }
  78%      { opacity: 0.9;  clip-path: inset(4% -60% -50% -60%); }
  86%, 100% { opacity: 1;   clip-path: none; }
}

.alien-btn {
  display: block;
  position: relative;
  width: 100%;
  background: none;
  border: 0;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transform-style: preserve-3d;   /* the ufo variant stacks depth layers */
}

/* Chromium loses hit-testing for perspective content behind Z=0
   (verified: wrap at −20/−70 misses, 0/+10 hits). The mascot sits at
   −70, so this invisible plane rides at net-positive Z (−70+80=+10)
   and catches the clicks — they bubble to the button. */
.alien-btn .alien-hit {
  position: absolute;
  inset: 0;
  transform: translateZ(80px);
}
.alien-btn:focus-visible {
  outline: 2px solid var(--beam);
  outline-offset: 6px;
  border-radius: 50%;
}

.alien {
  display: block;
  width: 100%;
  height: auto;
  animation: bob 6.5s ease-in-out infinite;
}

/* antennae OFF but SAVED (client 2026-08-25: "remove the antennas but
   keep them saved") — the geometry stays in both svg copies, gated
   here exactly like the mascot variant switch. Delete this rule to
   bring them back; the overflow: visible below is their headroom. */
.antennae { display: none; }
/* the scribble antennae are drawn above the viewBox (negative y) —
   without overflow: visible the svg clips them at the head apex. The
   animation shorthand must keep bob AND the glow: it overrides
   .alien's bob (same specificity, later in document) for the bust. */
.alien--v2 {
  overflow: visible;
  animation: bob 6.5s ease-in-out infinite,
             alien-glow-in 0.02s linear 1.15s both;
}

/* faint beam glow, on from the digitalize's first frame (client:
   "have the glow flicker with the alien in the start"): the filter
   lives on the svg INSIDE the flickering wrap, so the wrap's hard
   opacity/clip cuts modulate the glow in perfect sync — it strobes
   with every static blink, then holds once the picture settles.
   The 0.02s duration is still a hard cut, no fade (previous round's
   "TV finally connected" rule). Filter on a leaf svg plane — same
   pattern as the social icon faces, no 3D flattening risk. */
@keyframes alien-glow-in {
  from { filter: drop-shadow(0 0 16px rgba(166, 255, 77, 0))
                 drop-shadow(0 0 42px rgba(166, 255, 77, 0)); }
  to   { filter: drop-shadow(0 0 16px rgba(166, 255, 77, 0.3))
                 drop-shadow(0 0 42px rgba(166, 255, 77, 0.14)); }
}

/* mascot variant gate — REVERSIBLE: <body data-alien="ufo"> shows the
   brand UFO pilot; remove the attribute (or set "v2") to restore the
   original low-poly bust. Both svgs stay in the markup. */
.alien--ufo { display: none; }
body[data-alien="ufo"] .alien--v2 { display: none; }
body[data-alien="ufo"] .alien--ufo { display: block; }

/* the ufo is three stacked planes with real Z-depth: saucer (in flow,
   sets the box height) / pilot / glass. They parallax with the camera.
   Rest paint order matches the old single-svg exactly. */
.alien--ufo { position: relative; transform-style: preserve-3d; }
.alien--ufo .ufo-layer { display: block; width: 100%; height: auto; }
.alien--ufo .ufo-l1,
.alien--ufo .ufo-l2 { position: absolute; inset: 0; }
.alien--ufo .ufo-l1 { transform: translateZ(12px); }
.alien--ufo .ufo-l2 { transform: translateZ(24px); }
body[data-alien="ufo"] .alien-wrap {
  width: clamp(215px, 32vh, 320px);
  margin-bottom: calc(clamp(215px, 32vh, 320px) * -0.10);
}

@keyframes bob {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-9px); }
}

.eye { transition: fill 0.3s ease; }
/* the pupils carry a zero-size beam drop-shadow at rest so the hover glow
   (round 44, below the zap rules) interpolates instead of popping */
.glints ellipse { transition: fill 0.3s ease, filter 0.35s ease; filter: drop-shadow(0 0 0 rgba(166, 255, 77, 0)); }

/* hull subwoofers (ufo l0): player.js pumps each cone's scale and the
   glow ring's opacity from the live bass envelope every frame */
.js-sub { transform-box: fill-box; transform-origin: 50% 50%; will-change: transform; }
.js-subglow { transition: opacity 0.06s linear; }

/* easter-egg progress whisper, floats above the head */
.egg-hint {
  position: absolute;
  left: 50%;
  top: -20px;
  transform: translateX(-50%);
  font-size: 9px;
  letter-spacing: 0.3em;
  white-space: nowrap;
  color: var(--beam);
  opacity: 0;
  transition: opacity 0.25s ease;
  pointer-events: none;
}
.egg-hint.show { opacity: 0.9; }

/* warp flash into v1 — tractor-beam green, a wink at where you're going */
body::after {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 99;
  background: radial-gradient(circle at 50% 42%, #ffffff 0%, #d6ff9e 46%, #a6ff4d 100%);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.55s ease;
}
body.warp::after { opacity: 1; }

/* click reaction */
.alien-btn.zap .eye { fill: #0d1806; }
.alien-btn.zap .glints ellipse { fill: var(--beam-soft); }
/* round 44: the pupils glow beam green while ENTER SHOP is hovered or
   focused — main.js puts .eyes-lit on #alienBtn from the CTA's
   pointerenter / focus and takes it off on pointerleave / blur. Fill +
   drop-shadow only; no transform, no markup (both svg copies share the
   .glints class). Sits after the zap rule so a click mid-hover stays lit. */
.alien-btn.eyes-lit .glints ellipse {
  fill: var(--beam);
  filter: drop-shadow(0 0 2px #a6ff4d) drop-shadow(0 0 6px rgba(166, 255, 77, 0.8));
}
.alien-btn.zap .ping-ring { animation: ping 0.9s ease-out; }

@keyframes ping {
  0%   { opacity: 0.85; r: 26; stroke-width: 2.5; }
  100% { opacity: 0;    r: 95; stroke-width: 0.5; }
}

/* ── wordmark ─────────────────────────────────────────────── */

.wordmark-wrap {
  --z: 8px;   /* just in front of the alien: the neck still tucks behind */
  position: relative;
  z-index: 2;
  width: min(92vw, 960px);
  transform: translateZ(var(--z, 0px));
  /* click-transparent: this box sits IN FRONT of the alien in 3D and
     its invisible rectangle was stealing mascot clicks — the hover
     sheen is driven from JS (pointermove rect check) instead */
  pointer-events: none;
  opacity: 0;
  animation: wm-rise 1.1s cubic-bezier(0.22, 1, 0.36, 1) 0.55s forwards;
}

@keyframes wm-rise {
  from { opacity: 0; transform: translateY(34px) translateZ(var(--z, 0px)); }
  to   { opacity: 1; transform: translateY(0) translateZ(var(--z, 0px)); }
}

.wordmark { display: block; width: 100%; height: auto; }

/* sparkle stars flanking the sign — 3D particle clouds drawn by
   main.js (green beside AREA, violet beside 52). They live inside
   the wordmark plane, so they inherit its z8 depth, entrance rise,
   and pointer-events: none (no click stealing — invariant 1 safe). */
.sparkle {
  /* SYMMETRICAL by client rule: same size both sides, centers sitting
     exactly on the wrap edges (left: -0.5*sp mirrors right: -0.5*sp).
     The glyphs are inset ~10% from the wrap edge, so a half-width reach
     of 0.5*sp stays clear of all text at every size below. */
  --sp: clamp(120px, 18.75vh, 210px);   /* +25% (client round 6) */
  position: absolute;
  top: 42%;
  width: var(--sp);
  height: var(--sp);
  margin-top: calc(var(--sp) * -0.5);
  pointer-events: none;
  /* decoupled entrance (client): the stars do NOT ride the wordmark's
     0.55s rise — they fade in on their own after the alien has fully
     digitalized (entrance ends 2.05s) */
  opacity: 0;
  animation: sparkle-in 0.8s ease 2.25s forwards;
}

@keyframes sparkle-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}
.sparkle--l { left: calc(var(--sp) * -0.5); }
.sparkle--r { right: calc(var(--sp) * -0.5); }

/* narrow desktops: only ~4vw of margin flanks the 92vw wrap — shrink
   the stars so the centered-on-edge layout never clips at the camera */
@media (max-width: 1150px) {
  /* drawn extent is 0.4*sp from center; keep it inside the ~4vw flank
     margin: 0.4*sp <= 4vw → sp <= 10vw, with a hair of slack */
  .sparkle { --sp: clamp(72px, 9.5vw, 105px); }
}

/* phones: the wordmark fills the width; there is no flank room that
   avoids both text overlap and edge clipping — hide the sparkles */
@media (max-width: 720px) {
  .sparkle { display: none; }
}
@media (max-height: 450px) {
  .sparkle { display: none; }
}

.wm-text {
  /* Super Sliced's caps measure ~1.03em — 164px is the vertical
     maximum against the 168 units above the y=168 baseline (202px
     overshot the viewBox top by 39 units, verified). Width comes
     from main.js: the `.wm-stretch` group is scaled horizontally so
     the natural line (~746 units) spans WM_TARGET (930), a mild
     ~1.25× widening that suits the chunky sliced letterforms — a
     transform, not textLength, which WebKit mis-applies on tspans
     (round 48). */
  font-family: "Super Sliced", "Arial Black", sans-serif;
  font-size: 164px;
  letter-spacing: 0.04em;
  text-anchor: middle;
  paint-order: stroke fill;
}

/* v1 decade glow behind the beam-green AREA */
.wm-glow {
  filter: blur(11px);
  opacity: 0.5;
}

.sheen { transform: translateX(0) skewX(-18deg); }
.sheen.sweep { animation: sheen-sweep 1.5s ease-out forwards; }

@keyframes sheen-sweep {
  from { transform: translateX(0) skewX(-18deg); }
  to   { transform: translateX(1750px) skewX(-18deg); }
}

.ground-glow {
  position: absolute;
  left: 50%;
  bottom: -8px;
  width: 74%;
  height: 46px;
  transform: translateX(-50%);
  background: radial-gradient(ellipse 50% 50% at 50% 50%, rgba(190, 205, 225, 0.10), transparent 70%);
  pointer-events: none;
}

/* ── tagline + CTAs ───────────────────────────────────────── */

.tagline {
  --z: 16px;
  margin-top: clamp(8px, 1.6vh, 18px);
  font-size: 11px;
  letter-spacing: 0.34em;
  color: #ffc16b;
  text-align: center;
  text-wrap: balance;
  transform: translateZ(var(--z, 0px));
  opacity: 0;
  animation: fade-up 0.8s ease 1.7s forwards;
}

.cta-row {
  --z: 34px;
  display: flex;
  gap: 18px;
  margin-top: clamp(20px, 3.4vh, 34px);
  transform: translateZ(var(--z, 0px));
  transform-style: preserve-3d;
  opacity: 0;
  animation: fade-up 0.8s ease 1.95s forwards;
}

.cta {
  font-family: "Michroma", "Arial Black", sans-serif;
  font-size: 13px;
  letter-spacing: 0.16em;
  text-decoration: none;
  padding: 15px 30px;
  position: relative;
  white-space: nowrap;
  transition: transform 0.25s ease, box-shadow 0.25s ease, border-color 0.25s ease, color 0.25s ease;
}
.cta:focus-visible { outline: 2px solid var(--amber); outline-offset: 4px; }
.cta:hover  { transform: translateY(-2px) translateZ(14px); }
.cta:active { transform: translateY(0); }

.cta-primary {
  color: var(--ink);
  background: linear-gradient(180deg, #ffffff 0%, #dde2e8 38%, #a7b0bb 52%, #8b95a1 56%, #b7c0c9 74%, #eef1f5 100%);
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.4), 0 4px 14px rgba(0, 0, 0, 0.55);
  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.45);
}
.cta-primary:hover {
  box-shadow: 0 0 0 1px var(--amber), 0 6px 18px rgba(0, 0, 0, 0.55), 0 0 24px rgba(255, 174, 66, 0.18);
}

.cta-ghost {
  color: #e8bd77;
  border: 1px solid rgba(255, 174, 66, 0.42);
  background: rgba(255, 174, 66, 0.03);
}
.cta-ghost:hover {
  border-color: var(--amber);
  color: var(--amber-hi);
  box-shadow: 0 10px 30px rgba(216, 180, 90, 0.10);
}

/* ── ENTER SHOP → INVADE (client 2026-09-05) ─────────────────
   Hover/focus swaps the label to the data-hover text and turns the
   chrome button beam green. The real text stays in flow (invisible) so
   the button keeps its width; the swap text is an ::after overlay. */
/* The two labels sit on the same spot, so they must never be visible at
   once (client 2026-09-07: "ENTER SHOP" and "INVADE" overlapped into
   "ENTVRASDEOP" on the way out). The transitions are ASYMMETRIC: whichever
   word is leaving cuts out fast with no delay; the arriving word waits.
   These rest-state rules govern the move BACK to rest. */
.cta-invade .cta-text { display: inline-block; transition: opacity 0.14s ease 0.1s; }   /* returns after INVADE has cleared */
.cta-invade::after {
  content: attr(data-hover);
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  opacity: 0;
  transition: opacity 0.16s ease;
  letter-spacing: 0.22em;
  text-indent: 0.22em;                 /* optical centre for the tracked caps */
}
/* the green arrives as LIQUID (main.js builds .cta-lq, an svg wave clip
   rising through the chrome, same mechanism as the social icons); the
   button's own background stays chrome so the pour reads */
.cta-invade { overflow: hidden; }
.cta-invade .cta-lq { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; z-index: 0; }
.cta-invade .cta-text { position: relative; z-index: 1; }
.cta-invade::after { z-index: 2; transition: opacity 0.08s ease 0s; }                  /* INVADE cuts out at once on leave */
.cta-invade:hover,
.cta-invade:focus-visible {
  color: var(--ink);
  box-shadow: 0 0 0 1px var(--beam), 0 6px 18px rgba(0, 0, 0, 0.55), 0 0 28px rgba(166, 255, 77, 0.35);
  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.35);
}
/* …and these hover-state rules govern the move INTO hover */
.cta-invade:hover .cta-text,
.cta-invade:focus-visible .cta-text { opacity: 0; transition: opacity 0.08s ease 0s; }   /* the label cuts out at once */
.cta-invade:hover::after,
.cta-invade:focus-visible::after { opacity: 1; transition: opacity 0.22s ease 0.16s; }  /* INVADE lands after the pour */


/* ── bottom bar ───────────────────────────────────────────── */
/* Spline-scene icons: bone faces on a stack of darkening depth
   clones (built by JS) — real extrusion that parallaxes when the
   world orbits, plus a slow float like the netlify reference. */

.bottom-bar {
  /* nearest plane. The projection displacement of a +Z plane grows
     linearly with viewport height, and the steady cursor-look tilt
     (±3.2° rotateX) adds more — so the compensation MUST be
     viewport-relative. calc(16px + 4.2vh) keeps the locus on-screen
     with ~25px projected margin from 568px through 4K-tall windows,
     tilt included. Re-derive if you touch --z or the look angles. */
  --z: 48px;
  position: absolute;
  left: 50%;
  transform: translateX(-50%) translateZ(var(--z, 0px));
  transform-style: preserve-3d;
  width: fit-content;
  bottom: calc(16px + 4.2vh);
  z-index: 3;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  /* rise-from-below entrance: an opacity fade would flatten the
     preserve-3d icon stacks mid-animation (opacity<1 groups) */
  animation: bar-rise 0.9s cubic-bezier(0.22, 1, 0.36, 1) 2.2s both;
}

@keyframes bar-rise {
  from { transform: translateX(-50%) translateY(240px) translateZ(var(--z, 0px)); }
  to   { transform: translateX(-50%) translateY(0) translateZ(var(--z, 0px)); }
}

.socials {
  display: flex;
  gap: clamp(22px, 3.4vw, 40px);
  transform-style: preserve-3d;
}

.socials a {
  --size: clamp(46px, 8.5vh, 68px);
  position: relative;
  width: var(--size);
  height: var(--size);
  color: #e9e4d7;             /* bone face, like the reference icons */
  transform: translateZ(0);
  transform-style: preserve-3d;
  transition: color 0.25s ease, transform 0.25s ease;
}
/* hover grows in place (scale about own center) — a Z-lift would
   shift the projected box away from the viewport center and can
   flicker when the cursor sits near the icon's edge */
.socials a:hover  { transform: translateZ(0) scale(1.12); }   /* colour now comes from the liquid brand fill (main.js) */
.lq-fill { pointer-events: none; }
.socials a:focus-visible { outline: 2px solid var(--amber); outline-offset: 5px; }

/* the 3D body: face svg last, depth clones behind it */
.s3d-stack {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
  animation: icon-float 5.4s ease-in-out infinite alternate;
}
.socials a:nth-child(1) .s3d-stack { animation-delay: -0.4s; }
.socials a:nth-child(2) .s3d-stack { animation-delay: -1.9s; }
.socials a:nth-child(3) .s3d-stack { animation-delay: -3.2s; }
.socials a:nth-child(4) .s3d-stack { animation-delay: -4.6s; }

@keyframes icon-float {
  from { transform: translateY(2.5px); }
  to   { transform: translateY(-4px); }
}

.s3d-stack svg {
  position: absolute;
  inset: 11%;
  width: 78%;
  height: 78%;
  filter: drop-shadow(0 10px 16px rgba(0, 0, 0, 0.45));
}

/* depth clones (JS sets --i 1…N and a darkening color per layer) */
.s3d-stack .s3d-depth {
  filter: none;
  transform: translate3d(calc(var(--i) * 0.35px),
                         calc(var(--i) * 0.9px),
                         calc(var(--i) * -2.4px));
}

.locus {
  font-size: 10px;
  letter-spacing: 0.26em;
  color: #cf9c4d;
}
.locus a {
  color: inherit;
  text-decoration: none;
  transition: color 0.25s ease;
}
.locus a:hover { color: var(--amber-hi); }
.locus a:focus-visible { outline: 2px solid var(--amber); outline-offset: 3px; }
.locus .dot { margin: 0 10px; opacity: 0.6; }

/* ── shared keyframes ─────────────────────────────────────── */

@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }

@keyframes fade-up {
  from { opacity: 0; transform: translateY(14px) translateZ(var(--z, 0px)); }
  to   { opacity: 1; transform: translateY(0) translateZ(var(--z, 0px)); }
}

/* ── responsive ───────────────────────────────────────────── */

@media (max-width: 720px) {
  .corner.bl, .corner.br { display: none; }
  .corner { font-size: 9px; letter-spacing: 0.22em; }
  .corner.tl { left: 18px; top: 18px; }

  .brand-head { top: 40px; left: 18px; }
  .brand { width: 36px; }                          /* halved (round 6) */
  .brand-head .site-search { width: calc(100vw - 36px); }   /* the search panel spans the width (round 32b) */

  /* no mobile font-size bump: the stretch (main.js) pins the line to
     930 units at every size, and Super Sliced above 164px clips the
     viewBox top (caps ~1.03em vs 168 units of room) */

  .cta-row {
    flex-direction: column;
    gap: 12px;
    width: min(78vw, 300px);
  }
  .cta { text-align: center; padding: 15px 10px; }

  .tagline { font-size: 9.5px; letter-spacing: 0.26em; }

  .socials { gap: clamp(16px, 4.5vw, 26px); }
  .socials a { --size: clamp(44px, 12vw, 56px); }   /* 44px tap floor */
  .bottom-bar { bottom: calc(12px + 4vh); gap: 6px; }
}

@media (max-height: 640px) {
  .alien-wrap { width: clamp(120px, 19vh, 170px); }
  body[data-alien="ufo"] .alien-wrap { width: clamp(170px, 27vh, 240px); }
  .cta { padding: 12px 24px; }
  .bottom-bar .locus { display: none; }
  .socials a { --size: 44px; }                      /* 44px tap floor */
}

/* landscape phones / short-wide windows: unstack the CTAs so the
   stage fits the shorter viewport (must come after the ≤720w block) */
@media (max-height: 640px) and (min-width: 540px) {
  .cta-row { flex-direction: row; width: auto; gap: 14px; }
  .cta { padding: 12px 22px; }
}

/* very short viewports: shrink the scene hard and drop the bottom
   bar — at this height the icons can only sit on top of the CTAs,
   and the conversion actions win */
@media (max-height: 450px) {
  .alien-wrap { width: clamp(96px, 17vh, 130px); }
  body[data-alien="ufo"] .alien-wrap { width: clamp(135px, 23vh, 185px); }
  .wordmark-wrap { width: min(70vw, 560px); }
  .bottom-bar { display: none; }
}

/* ── transmission console (Acid Souljah radio) ────────────── */

.console {
  position: fixed;
  top: 14px;
  right: 14px;
  z-index: 6;
  width: 240px;
  display: flex;
  justify-content: flex-end;
  opacity: 0;
  animation: fade-in 0.9s ease 2.35s forwards;
  /* scaled footprint (client 2026-08-25: −30%, then +10% and tucked
     snug into the top-right corner); uniform scale keeps every
     internal proportion, tap targets shrink with it */
  transform: scale(0.77);
  transform-origin: top right;
}

/* collapsed chip */
.console-pill {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  gap: 3px;
  width: 40px;
  height: 40px;
  padding: 11px 10px;
  background: rgba(11, 10, 24, 0.72);
  border: 1px solid rgba(166, 255, 77, 0.28);
  cursor: pointer;
  transition: border-color 0.25s ease, box-shadow 0.25s ease;
}
.console-pill:hover { border-color: var(--beam); box-shadow: 0 0 18px rgba(166, 255, 77, 0.18); }
.console-pill:focus-visible { outline: 2px solid var(--beam); outline-offset: 3px; }
.console.open .console-pill { display: none; }

/* open panel */
.console-panel { display: none; }
/* no fill, no border: the controls float straight on the starfield */
.console.open .console-panel {
  display: flex;
  flex-direction: column;
  gap: 9px;
  width: 100%;
  padding: 12px 14px;
}

.console-head { display: flex; align-items: center; gap: 8px; }

.console-live {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: #5b5870;
  transition: background 0.3s ease;
}
.console.playing .console-live {
  background: var(--beam);
  box-shadow: 0 0 8px rgba(166, 255, 77, 0.8);
  animation: live-blink 1.6s ease-in-out infinite;
}
@keyframes live-blink { 50% { opacity: 0.35; } }

.console-label {
  flex: 1;
  font-size: 9px;
  letter-spacing: 0.3em;
  color: var(--violet);
}
.console.playing .console-label { color: var(--beam); }
.console.offline .console-label { color: #ff8a5c; }

.console-min {
  background: none;
  border: 0;
  cursor: pointer;
  color: var(--faint);
  font: inherit;
  font-size: 12px;
  line-height: 1;
  padding: 2px 4px;
}
.console-min:hover { color: var(--bone); }
.console-min:focus-visible { outline: 2px solid var(--beam); outline-offset: 2px; }

/* track name — marquees only when it overflows */
.console-track { display: block; overflow: hidden; text-decoration: none; }
.console-title {
  display: inline-block;
  white-space: nowrap;
  font-size: 11px;
  letter-spacing: 0.08em;
  color: var(--bone);
}
.console-track:hover .console-title { color: var(--beam-soft); }
.console-track:focus-visible { outline: 2px solid var(--beam); outline-offset: 2px; }
.console-title.scroll { animation: marquee 8s linear 1.2s infinite alternate; }
@keyframes marquee {
  0%, 10%   { transform: translateX(0); }
  90%, 100% { transform: translateX(var(--marq, 0px)); }
}

/* EQ readout */
.console-eq { display: flex; align-items: flex-end; gap: 3px; height: 15px; }
.console-eq .eq-bar,
.console-pill .eq-bar {
  flex: 1;
  width: 3px;
  height: 100%;
  background: linear-gradient(180deg, var(--beam-soft), var(--beam));
  opacity: 0.45;
  transform: scaleY(0.18);
  transform-origin: bottom;
}
.console-pill .eq-bar { flex: none; height: 16px; }
.console.playing .eq-bar { opacity: 0.9; }
/* only the collapsed pill keeps the CSS-animated fake — the panel's
   EQ bars are driven per-frame by player.js from the track's real
   loudness waveform */
.console.playing .console-pill .eq-bar { animation: eq 0.52s ease-in-out infinite alternate; }
.console.playing .console-pill .eq-bar:nth-child(2n) { animation-duration: 0.44s; animation-delay: 0.12s; }
.console.playing .console-pill .eq-bar:nth-child(3n) { animation-duration: 0.62s; animation-delay: 0.05s; }
.console.playing .console-pill .eq-bar:nth-child(5n) { animation-duration: 0.38s; animation-delay: 0.2s; }
@keyframes eq { from { transform: scaleY(0.18); } to { transform: scaleY(1); } }

/* progress + times */
.console-progress { padding: 4px 0; cursor: pointer; }
.console-progress:focus-visible { outline: 2px solid var(--beam); outline-offset: 2px; }
.console-progress-track { height: 3px; background: rgba(255, 255, 255, 0.14); }
.console-progress-fill {
  display: block;
  width: 0;
  height: 100%;
  background: var(--beam);
  box-shadow: 0 0 10px rgba(166, 255, 77, 0.55);
  transition: width 0.25s linear;
}

.console-times {
  display: flex;
  justify-content: space-between;
  margin-top: -5px;
  font-size: 9px;
  letter-spacing: 0.14em;
  color: var(--faint);
}

/* transport row */
.console-controls { display: flex; align-items: center; gap: 7px; }

.console-btn {
  display: grid;
  place-items: center;
  width: 30px;
  height: 28px;
  background: none;
  border: 0;
  color: var(--beam);
  cursor: pointer;
  transition: color 0.25s ease, filter 0.25s ease;
}
.console-btn svg { width: 11px; height: 11px; fill: currentColor; }
.console-btn:hover { color: var(--beam-soft); filter: drop-shadow(0 0 6px rgba(166, 255, 77, 0.55)); }
.console-btn:focus-visible { outline: 2px solid var(--beam); outline-offset: 2px; }
.console-btn .ic-pause { display: none; }
.console-btn.is-playing .ic-play { display: none; }
.console-btn.is-playing .ic-pause { display: block; }

.console-vol {
  flex: 1;
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
  color: var(--faint);
}
.console-vol svg { flex: none; width: 12px; height: 11px; fill: currentColor; }

/* speaker = quick-mute toggle (padding keeps the hit area ≥24px) */
.console-mute {
  flex: none;
  display: grid;
  place-items: center;
  padding: 7px 6px;
  margin: -5px 0;
  background: none;
  border: 0;
  color: var(--faint);
  cursor: pointer;
  transition: color 0.25s ease;
}
.console-mute:hover { color: var(--bone); }
.console-mute:focus-visible { outline: 2px solid var(--beam); outline-offset: 2px; }
.console-mute .vol-slash { display: none; }
.console-mute.muted { color: var(--amber); }
.console-mute.muted .vol-arc { display: none; }
.console-mute.muted .vol-slash { display: block; }

/* the bar fills beam-green up to the current level (--fill, set by JS) */
.console-vol input {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  min-width: 0;
  height: 2px;
  background: linear-gradient(90deg,
    var(--beam) var(--fill, 80%),
    rgba(255, 255, 255, 0.18) var(--fill, 80%));
  cursor: pointer;
}
.console-vol input::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--beam);
  box-shadow: 0 0 8px rgba(166, 255, 77, 0.6);
}
.console-vol input::-moz-range-track { height: 2px; background: rgba(255, 255, 255, 0.18); }
.console-vol input::-moz-range-progress { height: 2px; background: var(--beam); }
/* Firefox paints the element background AND the -moz pseudos — kill the
   element gradient there so the track doesn't double-composite */
@supports (-moz-appearance: none) {
  .console-vol input { background: transparent; }
}
.console-vol input::-moz-range-thumb {
  width: 9px;
  height: 9px;
  border: 0;
  border-radius: 50%;
  background: var(--beam);
  box-shadow: 0 0 8px rgba(166, 255, 77, 0.6);
}
.console-vol input:focus-visible { outline: 2px solid var(--beam); outline-offset: 4px; }

.console-cred {
  align-self: flex-end;
  font-size: 8px;
  letter-spacing: 0.26em;
  color: var(--violet);
  text-decoration: none;
  transition: color 0.25s ease;
}
.console-cred:hover { color: var(--amber-hi); }
.console-cred:focus-visible { outline: 2px solid var(--amber); outline-offset: 2px; }

/* signal lost (adblock / no SoundCloud) — the collapsed pill must show
   it too: phones boot collapsed and are the primary offline audience */
.console.offline .console-eq .eq-bar { background: #6b4a3a; }
.console.offline .console-pill { border-color: rgba(255, 138, 92, 0.4); }
.console.offline .console-pill .eq-bar { background: #6b4a3a; }

/* the engine — kept technically visible so SoundCloud keeps streaming */
.sc-frame {
  position: fixed;
  bottom: 0;
  right: 0;
  width: 2px;
  height: 2px;
  opacity: 0.01;
  border: 0;
  pointer-events: none;
  z-index: -1;
}

@media (max-width: 720px) {
  .console { top: 10px; right: 8px; width: 216px; }
}

/* ── 8-bit cursors (2026-08-25, replaced the sta shooting star) ─ */
/* Two pixel-art data-URI cursors (zero requests): grey 8-bit arrow
   everywhere, grey pixel alien head over interactive targets AND
   while orbit-dragging (client choice). The retired sta system
   (physics rotor, dust trail, click burst) lives in git history.
   Rule ORDER below is load-bearing (invariant 8): base → interactive
   → body.grabbing win by document order at equal specificity. */

html, body, .camera {
  cursor: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20width%3D%2724%27%20height%3D%2724%27%3E%3Cdefs%3E%3CradialGradient%20id%3D%27g%27%20cx%3D%270.5%27%20cy%3D%270.5%27%20r%3D%270.5%27%3E%3Cstop%20offset%3D%270%27%20stop-color%3D%27%23ffffff%27%20stop-opacity%3D%270.5%27%2F%3E%3Cstop%20offset%3D%270.45%27%20stop-color%3D%27%23ffffff%27%20stop-opacity%3D%270.18%27%2F%3E%3Cstop%20offset%3D%271%27%20stop-color%3D%27%23ffffff%27%20stop-opacity%3D%270%27%2F%3E%3C%2FradialGradient%3E%3C%2Fdefs%3E%3Ccircle%20cx%3D%2712%27%20cy%3D%2712%27%20r%3D%2712%27%20fill%3D%27url%28%23g%29%27%2F%3E%3Ccircle%20cx%3D%2712%27%20cy%3D%2712%27%20r%3D%273%27%20fill%3D%27%23ffffff%27%2F%3E%3C%2Fsvg%3E") 12 12, auto;
}

a, button, input[type='range'],
.console-progress, .console-btn, .console-min, .console-pill, .console-mute,
.alien-btn, .cta {
  cursor: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20width%3D%2724%27%20height%3D%2724%27%3E%3Cdefs%3E%3CradialGradient%20id%3D%27g%27%20cx%3D%270.5%27%20cy%3D%270.5%27%20r%3D%270.5%27%3E%3Cstop%20offset%3D%270%27%20stop-color%3D%27%23ffffff%27%20stop-opacity%3D%270.5%27%2F%3E%3Cstop%20offset%3D%270.45%27%20stop-color%3D%27%23ffffff%27%20stop-opacity%3D%270.18%27%2F%3E%3Cstop%20offset%3D%271%27%20stop-color%3D%27%23ffffff%27%20stop-opacity%3D%270%27%2F%3E%3C%2FradialGradient%3E%3C%2Fdefs%3E%3Ccircle%20cx%3D%2712%27%20cy%3D%2712%27%20r%3D%2712%27%20fill%3D%27url%28%23g%29%27%2F%3E%3Ccircle%20cx%3D%2712%27%20cy%3D%2712%27%20r%3D%273%27%20fill%3D%27%23ffffff%27%2F%3E%3C%2Fsvg%3E") 12 12, pointer;
}

/* click pulse for the star-dot cursor: a small white ring expands
   and fades at the click point (pooled spans, main.js). Sits after
   the cursor rules but carries no cursor: property — invariant 8's
   rule ordering is untouched. */
.click-pulse {
  position: fixed;
  left: 0;
  top: 0;
  width: 34px;
  height: 34px;
  margin: -17px 0 0 -17px;
  border: 1.5px solid rgba(255, 255, 255, 0.8);
  border-radius: 50%;
  opacity: 0;
  pointer-events: none;
  z-index: 60;
}
.click-pulse.live { animation: click-pulse 0.45s ease-out forwards; }

@keyframes click-pulse {
  0%   { opacity: 0.8; transform: scale(0.35); }
  100% { opacity: 0; transform: scale(1.6); }
}

body.grabbing, body.grabbing .camera,
body.grabbing .camera a, body.grabbing .camera button {
  cursor: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20width%3D%2724%27%20height%3D%2724%27%3E%3Cdefs%3E%3CradialGradient%20id%3D%27g%27%20cx%3D%270.5%27%20cy%3D%270.5%27%20r%3D%270.5%27%3E%3Cstop%20offset%3D%270%27%20stop-color%3D%27%23ffffff%27%20stop-opacity%3D%270.5%27%2F%3E%3Cstop%20offset%3D%270.45%27%20stop-color%3D%27%23ffffff%27%20stop-opacity%3D%270.18%27%2F%3E%3Cstop%20offset%3D%271%27%20stop-color%3D%27%23ffffff%27%20stop-opacity%3D%270%27%2F%3E%3C%2FradialGradient%3E%3C%2Fdefs%3E%3Ccircle%20cx%3D%2712%27%20cy%3D%2712%27%20r%3D%2712%27%20fill%3D%27url%28%23g%29%27%2F%3E%3Ccircle%20cx%3D%2712%27%20cy%3D%2712%27%20r%3D%273%27%20fill%3D%27%23ffffff%27%2F%3E%3C%2Fsvg%3E") 12 12, grabbing;
}

/* ── reduced motion ───────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-delay: 0s !important;
    transition-duration: 0.01ms !important;
  }
  .alien { animation: none; }
  /* the reduce-motion .alien override kills the glow-in animation too
     (same specificity, later in document) — keep the settled faint
     glow as a static filter instead */
  .alien--v2 {
    filter: drop-shadow(0 0 16px rgba(166, 255, 77, 0.3))
            drop-shadow(0 0 42px rgba(166, 255, 77, 0.14));
  }
  .sheen { display: none; }
  .meteor { display: none; }
  .s3d-stack { animation: none; }
  .console-title.scroll { animation: none; }
  .console.playing .eq-bar { animation: none; transform: scaleY(0.6); }
  /* must match the rescoped pill selector's specificity or it loses */
  .console.playing .console-pill .eq-bar { animation: none; transform: scaleY(0.6); }
  .console.playing .console-live { animation: none; }
}
