/* ==========================================================================
   INVASIA - rocat.games
   Dark cinematic horror. Station-records design system.
   Fonts are declared in fonts.css (Anton / Space Grotesk / IBM Plex Mono).
   NOTE: .reveal elements get their initial animation state from JS only -
   this stylesheet never hides content. With JS disabled the page reads
   top-to-bottom (see the @media (scripting: none) blocks).
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Tokens
   -------------------------------------------------------------------------- */

:root {
  color-scheme: dark;

  --bg: #060708;
  --surface: #0d0f11;
  --text: #d6d3cd;
  --dim: #858179;
  --blood: #c22d1e;
  --blood-dark: #8f1d14;
  --line: rgba(214, 211, 205, 0.12);

  --text-bright: #e8e5df;
  --text-body: rgba(214, 211, 205, 0.78);
  --field-bg: #090b0c;

  --font-display: "Anton", "Arial Narrow", sans-serif;
  --font-body: "Space Grotesk", "Helvetica Neue", sans-serif;
  --font-mono: "IBM Plex Mono", "Courier New", monospace;

  --gutter: clamp(20px, 6vw, 96px);
  --pad-y: clamp(104px, 15vh, 176px);
  --measure: 720px;
  --content-max: 1200px;

  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
  --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);

  /* z scale */
  --z-vignette: 80;
  --z-grain: 90;
  --z-scanlines: 91;
  --z-header: 120;
  --z-flash: 300;
  --z-preloader: 400;
  --z-cursor: 500;
}

/* --------------------------------------------------------------------------
   2. Reset & base
   -------------------------------------------------------------------------- */

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

html {
  scroll-behavior: smooth;
  /* Sideways overflow is clipped here, on the root, not on <body>.
     On <body> it turns the body into a clip container, and scrollIntoView()
     then stops at that container instead of reaching the viewport: every menu
     link becomes a link that highlights and goes nowhere. Verified: with the
     rule on <body>, scrollIntoView moved the page by 0px. */
  overflow-x: clip;
}

body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-weight: 300;
  font-size: 16px;
  line-height: 1.7;
  -webkit-font-smoothing: antialiased;
}

body.locked {
  overflow: hidden;
}

::selection {
  background: var(--blood);
  color: #f4efe9;
}

img {
  max-width: 100%;
  height: auto;
}

a {
  color: inherit;
  text-decoration: none;
}

button {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
}

ul,
ol {
  list-style: none;
}

:focus-visible {
  outline: 2px solid var(--blood);
  outline-offset: 3px;
}

/* thin dark scrollbars */
::-webkit-scrollbar {
  width: 10px;
  height: 10px;
}
::-webkit-scrollbar-track {
  background: var(--bg);
}
::-webkit-scrollbar-thumb {
  background: #1c1f22;
  border: 2px solid var(--bg);
}

/* Content links inside copy */
p a,
dd a,
.faq-a a,
.privacy-note a {
  color: var(--text-bright);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: rgba(194, 45, 30, 0.55);
  transition: text-decoration-color 200ms ease, color 200ms ease;
}

p a:hover,
dd a:hover,
.faq-a a:hover,
.privacy-note a:hover {
  text-decoration-color: var(--blood);
}

/* --------------------------------------------------------------------------
   3. Typography
   -------------------------------------------------------------------------- */

h1,
h2,
h3,
h4 {
  font-weight: 400;
}

h2 {
  font-family: var(--font-display);
  font-size: clamp(38px, 5.4vw, 72px);
  line-height: 1.02;
  letter-spacing: 0.01em;
  text-transform: uppercase;
  color: var(--text-bright);
  text-align: center;
  margin-bottom: clamp(52px, 8vh, 84px);
}

/* Section eyebrow - every archive section is a numbered station log. */
main {
  counter-reset: sec;
}

.section.bg {
  counter-increment: sec;
}

.section.bg > h2::before {
  content: "LOG // " counter(sec, decimal-leading-zero);
  display: block;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.34em;
  color: var(--blood);
  margin-bottom: 18px;
}

.kicker {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--blood);
  margin-bottom: 20px;
}

.center-txt {
  text-align: center;
}

.narrow {
  max-width: var(--measure);
  margin-inline: auto;
}

.center-txt.narrow {
  color: var(--text-body);
  line-height: 1.8;
  margin-bottom: 40px;
}

.link-accent {
  color: var(--blood);
  text-decoration: underline;
  text-underline-offset: 4px;
  text-decoration-color: rgba(194, 45, 30, 0.55);
  transition: color 200ms ease, text-decoration-color 200ms ease;
}

.link-accent:hover {
  color: #d84730;
  text-decoration-color: currentColor;
}

/* --------------------------------------------------------------------------
   4. Utilities
   -------------------------------------------------------------------------- */

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: fixed;
  top: 16px;
  left: 16px;
  z-index: calc(var(--z-cursor) + 10);
  transform: translateY(-300%);
  background: var(--surface);
  border: 1px solid var(--blood);
  color: var(--text-bright);
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 12px 18px;
}

.skip-link:focus {
  transform: none;
}

/* .reveal - intentionally no initial state here.
   JS owns opacity/transform so the page is readable without it. */
.reveal {
  will-change: auto;
}

/* --------------------------------------------------------------------------
   5. Overlays: preloader, grain, scanlines, vignette, flash, cursor
   -------------------------------------------------------------------------- */

.preloader {
  position: fixed;
  inset: 0;
  z-index: var(--z-preloader);
  background: #030404;
  display: flex;
  justify-content: center;
  align-items: center;
}

.pre-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  text-align: center;
}

.pre-inner .pre-logo {
  margin-bottom: 12px;
}

.pre-label,
.pre-sysline {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 400;
  letter-spacing: 0.25em;
  text-transform: uppercase;
  color: var(--dim);
}

/* The logo carries this screen; the readout is a caption to it. Left at its
   old clamp(56px, 10vw, 84px) the number fought the mark for attention and the
   two large elements stacked badly. */
.pre-logo {
  width: min(240px, 56vw);
  height: auto;
  display: block;
}

.pre-count {
  font-family: var(--font-display);
  font-size: clamp(30px, 4.6vw, 44px);
  line-height: 1;
  letter-spacing: 0.02em;
  color: var(--text-bright);
}

.pre-pct {
  color: var(--blood);
}

.grain {
  position: fixed;
  inset: -50%;
  width: 200%;
  height: 200%;
  pointer-events: none;
  z-index: var(--z-grain);
  opacity: 0.055;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 300 300' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.7' numOctaves='3'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  animation: grain-shift 0.8s steps(4) infinite;
}

@keyframes grain-shift {
  0% { transform: translate(0, 0); }
  25% { transform: translate(-2%, 1%); }
  50% { transform: translate(1%, -2%); }
  75% { transform: translate(-1%, -1%); }
  100% { transform: translate(0, 0); }
}

.scanlines {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: var(--z-scanlines);
  opacity: 0.3;
  background: repeating-linear-gradient(
    0deg,
    transparent 0 3px,
    rgba(0, 0, 0, 0.22) 3px 4px
  );
}

/* JS drives #vignette / #flash opacity - decorative overlays, not content */
#vignette {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: var(--z-vignette);
  opacity: 0;
  background:
    radial-gradient(ellipse at 50% 120%, rgba(143, 29, 20, 0.4), transparent 55%),
    radial-gradient(ellipse at 100% 0%, rgba(143, 29, 20, 0.2), transparent 40%);
  box-shadow: inset 0 0 220px rgba(60, 8, 4, 0.85);
}

#flash {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: var(--z-flash);
  opacity: 0;
  background: rgba(194, 45, 30, 0.16);
}

/* Custom cursor - desktop pointers with scripting only */
#cursorDot,
#cursorRing {
  display: none;
}

@media (pointer: fine) and (scripting: enabled) and (prefers-reduced-motion: no-preference) {
  * {
    cursor: none !important;
  }

  /* A <dialog> opened with showModal() is painted in the browser's top layer,
     which sits above every z-index on the page. The custom cursor is a pair of
     ordinary divs, so it ends up underneath the dialog and invisible, while the
     real cursor is still switched off: over any modal there is no pointer at
     all. Hand the native cursor back for the whole top layer.

     Was scoped to .lightbox only, which left the trailer modal and the 18+ age
     gate with no cursor. Matching `dialog` covers those two and anything added
     later. */
  dialog,
  dialog * {
    cursor: auto !important;
  }

  /* ...but a control inside a dialog still has to look clickable. */
  dialog button,
  dialog a,
  dialog [role="button"],
  dialog summary {
    cursor: pointer !important;
  }

  #cursorDot,
  #cursorRing {
    display: block;
    position: fixed;
    top: 0;
    left: 0;
    pointer-events: none;
    z-index: var(--z-cursor);
  }

  /* Visibility: the pointer has to survive both the near-black page and the
     bright gallery and creature images. The brand red alone does not manage
     that (--blood on --bg is a ~3:1 contrast ratio at 6px), so the dot gets a
     light collar and a dark halo: one of the two always contrasts with
     whatever is underneath. */
  #cursorDot {
    width: 9px;
    height: 9px;
    margin: -4.5px 0 0 -4.5px;
    background: #ff3b2c;
    border-radius: 50%;
    box-shadow:
      0 0 0 1.5px rgba(255, 255, 255, 0.92),
      0 0 0 3px rgba(0, 0, 0, 0.4),
      0 0 10px rgba(255, 59, 44, 0.55);
  }

  #cursorRing {
    width: 32px;
    height: 32px;
    margin: -16px 0 0 -16px;
    border: 2px solid rgba(255, 90, 74, 0.9);
    border-radius: 50%;
    box-shadow:
      0 0 0 1px rgba(0, 0, 0, 0.45),
      inset 0 0 0 1px rgba(0, 0, 0, 0.35),
      0 0 14px rgba(255, 59, 44, 0.3);
  }
}

/* Kill switch: uncomment to drop the custom cursor and hand the pointer back
   to the operating system. Nothing else depends on it. */
/*
@media (pointer: fine) and (scripting: enabled) {
  * { cursor: auto !important; }
  #cursorDot,
  #cursorRing { display: none !important; }
}
*/

/* --------------------------------------------------------------------------
   6. Buttons & icons
   -------------------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  padding: 15px 26px;
  border: 1px solid transparent;
  white-space: nowrap;
  transition:
    transform 160ms var(--ease-out),
    background-color 200ms ease,
    border-color 200ms ease,
    box-shadow 200ms ease,
    color 200ms ease;
}

.btn:active {
  transform: scale(0.97);
}

.btn--accent {
  background: var(--blood);
  border-color: var(--blood);
  color: #f4efe9;
}

.btn--accent:hover {
  background: #e23b22;
  border-color: #ff6a4d;
  transform: translateY(-2px);
  box-shadow:
    0 6px 22px rgba(194, 45, 30, 0.45),
    0 0 0 1px rgba(255, 106, 77, 0.35);
}

.btn--neutral {
  background: transparent;
  border-color: var(--line);
  color: var(--text);
}

.btn--neutral:hover {
  border-color: rgba(214, 211, 205, 0.42);
  background: rgba(214, 211, 205, 0.04);
  color: var(--text-bright);
}

.btn--sm {
  padding: 10px 18px;
  font-size: 11px;
}

.btn--xs {
  padding: 8px 14px;
  font-size: 10px;
  letter-spacing: 0.12em;
}

/* Icons: monochrome SVG masks tinted by currentColor */
.icon-wrap {
  display: inline-block;
  flex: none;
  width: 15px;
  height: 15px;
  background-color: currentColor;
  -webkit-mask-repeat: no-repeat;
  -webkit-mask-position: center;
  -webkit-mask-size: contain;
  mask-repeat: no-repeat;
  mask-position: center;
  mask-size: contain;
}

.icon-lg {
  width: 22px;
  height: 22px;
}

.icon-wrap[data-icon="steam"] { -webkit-mask-image: url("../icons/steam.svg"); mask-image: url("../icons/steam.svg"); }
.icon-wrap[data-icon="download"] { -webkit-mask-image: url("../icons/download.svg"); mask-image: url("../icons/download.svg"); }
.icon-wrap[data-icon="close"] { -webkit-mask-image: url("../icons/close.svg"); mask-image: url("../icons/close.svg"); }
.icon-wrap[data-icon="arrow-left"] { -webkit-mask-image: url("../icons/arrow-left.svg"); mask-image: url("../icons/arrow-left.svg"); }
.icon-wrap[data-icon="arrow-right"] { -webkit-mask-image: url("../icons/arrow-right.svg"); mask-image: url("../icons/arrow-right.svg"); }
.icon-wrap[data-icon="expand"] { -webkit-mask-image: url("../icons/expand.svg"); mask-image: url("../icons/expand.svg"); }
.icon-wrap[data-icon="contact"] { -webkit-mask-image: url("../icons/contact.svg"); mask-image: url("../icons/contact.svg"); }
.icon-wrap[data-icon="submit"] { -webkit-mask-image: url("../icons/submit.svg"); mask-image: url("../icons/submit.svg"); }
.icon-wrap[data-icon="x"] { -webkit-mask-image: url("../icons/x.svg"); mask-image: url("../icons/x.svg"); }
.icon-wrap[data-icon="youtube"] { -webkit-mask-image: url("../icons/youtube.svg"); mask-image: url("../icons/youtube.svg"); }
.icon-wrap[data-icon="sound-on"] { -webkit-mask-image: url("../icons/sound-on.svg"); mask-image: url("../icons/sound-on.svg"); }
.icon-wrap[data-icon="sound-off"] { -webkit-mask-image: url("../icons/sound-off.svg"); mask-image: url("../icons/sound-off.svg"); }

/* --------------------------------------------------------------------------
   7. Header / nav
   -------------------------------------------------------------------------- */

.site-header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: var(--z-header);
  display: flex;
  align-items: center;
  gap: 24px;
  /* Own horizontal padding rather than the page gutter: --gutter tops out at
     96px, which is generous for a text column and pure waste in a row that has
     to fit a 206px logo, twelve links and a button on one line. */
  padding: 18px clamp(16px, 3vw, 44px);
}

.site-header::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(rgba(6, 7, 8, 0.92), rgba(6, 7, 8, 0.75));
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  opacity: 0;
  transition: opacity 200ms ease-out;
  pointer-events: none;
}

.site-header.scrolled::before {
  opacity: 1;
}

.logo-wrap {
  flex: none;
  display: block;
  line-height: 0;
}

.logo-wrap img {
  height: 76px;
  width: auto;
}

.primary-nav {
  margin-left: auto;
}

.nav-list {
  display: flex;
  align-items: center;
  gap: clamp(10px, 1.2vw, 18px);
}

/* Readability: 11px uppercase mono at 0.13em tracking is small type made
   smaller by the tracking, sitting next to a 76px logo. Bigger glyphs, tighter
   tracking: the extra width from the size is paid for by the letter-spacing,
   so the row still fits on one line. Vertical padding grows too, because a
   23px-tall link is a poor click target. */
.nav-list a {
  display: inline-block;
  position: relative;
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #f6f4f0;
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.55);
  padding: 10px 0;
  transition: color 200ms ease;
}

.nav-list a::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 1px;
  background: var(--blood);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 200ms var(--ease-out);
}

.nav-list a:hover {
  color: var(--text-bright);
}

/* The section being read. Same underline the hover state uses, so the two
   read as one language rather than two different signals, plus a brighter
   label because this one has to be findable without moving the mouse. */
.nav-list a[aria-current] {
  color: #fff;
}

.nav-list a[aria-current]::after {
  transform: scaleX(1);
  height: 2px;
  background: var(--blood);
  box-shadow: 0 0 8px rgba(194, 45, 30, 0.6);
}

/* Hover on the active item must not read as "deactivated". */
.nav-list a[aria-current]:hover::after {
  transform: scaleX(1);
}

@media (prefers-reduced-motion: reduce) {
  .nav-list a::after {
    transition: none;
  }
}

/* Transform-based hover reveal - gated so a touch tap can't leave the
   underline "stuck" drawn until the next tap (no hover-off event on touch). */
@media (hover: hover) and (pointer: fine) {
  .nav-list a:hover::after {
    transform: scaleX(1);
  }
}

.nav-cta {
  flex: none;
}

.menu-toggle {
  display: none;
}

/* --------------------------------------------------------------------------
   8. Hero
   -------------------------------------------------------------------------- */

.hero {
  position: relative;
  height: 100vh;
  height: 100svh;
  min-height: 620px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.hero-bg {
  position: absolute;
  inset: -8%;
  background: url("../assets/hero/hero-1920.jpg") center 30% / cover no-repeat;
  background-image: image-set(
    url("../assets/hero/hero-1920.webp") type("image/webp"),
    url("../assets/hero/hero-1920.jpg") type("image/jpeg")
  );
  filter: brightness(0.5) saturate(0.82);
  will-change: transform;
}

@media (min-width: 1921px) {
  .hero-bg {
    background-image: image-set(
      url("../assets/hero/hero-2560.webp") type("image/webp"),
      url("../assets/hero/hero-2560.jpg") type("image/jpeg")
    );
  }
}

/* Background loop video - sits in the DOM right after .hero-bg and before
   .hero-mid/.hero::after, and deliberately carries NO z-index. Every layer
   here (.hero-bg, .hero-mid, .hero::after) is also z-index:auto, so they
   paint in tree order within the same stacking level; .hero-content alone
   has z-index:2, which is what actually keeps it above all of them. Adding
   an explicit z-index to .hero-video (even something like 1) would pull it
   into its own stacking context ABOVE that whole auto/0 group - including
   .hero-mid and the .hero::after fog gradient - breaking the readability
   darkening main.js relies on. Leave it as auto and keep the markup order.
   JS (initHero, main.js) only ever toggles opacity/play state here; it
   never reorders these elements. */
.hero-video {
  position: absolute;
  inset: -8%;
  /* <video> is a replaced element: inset alone does NOT stretch it (it falls
     back to the file's intrinsic size). Explicit width/height are required
     so it fills the hero with the same 8% overscan as .hero-bg/.hero-mid. */
  width: 116%;
  height: 116%;
  object-fit: cover;
  opacity: 0;
  pointer-events: none;
  will-change: opacity, transform;
}

.hero-mid {
  position: absolute;
  inset: -8%;
  background: radial-gradient(
    ellipse 80% 60% at 50% 80%,
    rgba(120, 130, 145, 0.14),
    transparent 65%
  );
  will-change: transform;
}

/* floor gradient so copy sits on darkness, not on the render */
.hero::after {
  content: "";
  position: absolute;
  inset: 55% 0 0 0;
  background: linear-gradient(to bottom, transparent, rgba(6, 7, 8, 0.82));
  pointer-events: none;
}

.hero-content {
  position: relative;
  z-index: 2;
  /* auto margins = safe centering: when content is taller than the viewport
     it pins below the fixed header instead of sliding under it */
  margin: auto;
  text-align: center;
  padding: clamp(88px, 11vh, 128px) 24px 0;
  max-width: 880px;
  will-change: transform;
}

.glitch {
  position: relative;
  display: block;
  width: min(560px, 78vw);
  margin: 0 auto;
}

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

/* glitch ghosts: decorative aria-hidden duplicates, flashed by JS */
.glitch .g {
  position: absolute;
  inset: 0;
  opacity: 0;
  pointer-events: none;
}

.glitch .g.r {
  filter: hue-rotate(-40deg) saturate(2);
}

.glitch .g.c {
  filter: hue-rotate(140deg);
}

.hero-tag {
  margin: 30px auto 0;
  max-width: 700px;
  font-size: 15px;
  line-height: 1.75;
  color: var(--text-body);
}

/* Hero action buttons - Wishlist + Watch Trailer side by side. The trailer
   opens in the #trailer-modal dialog (no second video embedded in the hero,
   so it doesn't compete with the background loop). */
.hero-actions {
  margin-top: 34px;
  display: flex;
  gap: 14px;
  justify-content: center;
  flex-wrap: wrap;
}

.hero-cta {
  margin-top: 0;
}

.hero-trailer-btn .icon-wrap {
  width: 13px;
  height: 13px;
}

/* Fullscreen trailer modal (native <dialog>) */
.trailer-modal {
  width: min(1100px, 92vw);
  max-width: 92vw;
  margin: auto;
  padding: 0;
  border: 1px solid var(--line);
  background: #000;
  color: var(--text);
  overflow: visible;
}

.trailer-modal::backdrop {
  background: rgba(4, 5, 6, 0.86);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

.trailer-frame {
  position: relative;
  aspect-ratio: 16 / 9;
  width: 100%;
  background: #000;
}

.trailer-frame iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

/* Sits just outside the top-right corner when there's room, but never
   off-screen: on short viewports it tucks back inside the frame. */
.trailer-close {
  position: absolute;
  top: -48px;
  right: 0;
  width: 40px;
  height: 40px;
  display: grid;
  place-items: center;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--text);
  cursor: pointer;
  transition: border-color 200ms ease, background-color 200ms ease;
}

.trailer-close .icon-wrap {
  width: 16px;
  height: 16px;
}

@media (hover: hover) and (pointer: fine) {
  .trailer-close:hover {
    border-color: rgba(194, 45, 30, 0.7);
    background: var(--bg);
  }
}

/* When the modal is tall enough to reach the top edge, keep the close
   button inside the frame so it can't be clipped by the viewport. */
@media (max-height: 720px), (max-width: 600px) {
  .trailer-close {
    top: 8px;
    right: 8px;
    background: rgba(6, 7, 8, 0.7);
  }
}

.hero-scroll {
  position: absolute;
  bottom: 26px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 2;
  display: block;
  padding: 10px 16px;
}

.hero-scroll-line {
  display: block;
  width: 1px;
  height: 64px;
  background: linear-gradient(to bottom, transparent, var(--text));
  animation: scroll-drop 2.4s var(--ease-in-out) infinite;
}

@keyframes scroll-drop {
  0% { transform: scaleY(0); transform-origin: top; }
  45% { transform: scaleY(1); transform-origin: top; }
  55% { transform: scaleY(1); transform-origin: bottom; }
  100% { transform: scaleY(0); transform-origin: bottom; }
}

/* --------------------------------------------------------------------------
   9. Story - pinned chapters (JS scrub) + static fallback
   -------------------------------------------------------------------------- */

.story {
  position: relative;
  height: 100vh;
  height: 100svh;
  overflow: hidden;
  background: var(--bg);
}

.chapter-bg {
  position: absolute;
  inset: -5%;
  background-size: cover;
  background-position: center;
  filter: brightness(0.42) saturate(0.85);
  will-change: transform, opacity;
}

.chapter-bg.b1 {
  background-image: url("../assets/story/story-1-1920.jpg");
  background-image: image-set(
    url("../assets/story/story-1-1920.webp") type("image/webp"),
    url("../assets/story/story-1-1920.jpg") type("image/jpeg")
  );
}

.chapter-bg.b2 {
  background-image: url("../assets/story/story-2-1920.jpg");
  background-image: image-set(
    url("../assets/story/story-2-1920.webp") type("image/webp"),
    url("../assets/story/story-2-1920.jpg") type("image/jpeg")
  );
}

.chapter-bg.b3 {
  background-image: url("../assets/story/story-3-1920.jpg");
  background-image: image-set(
    url("../assets/story/story-3-1920.webp") type("image/webp"),
    url("../assets/story/story-3-1920.jpg") type("image/jpeg")
  );
}

.chapter-text {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  text-align: center;
  padding: 0 8vw;
}

.chapter-text h3 {
  font-family: var(--font-display);
  font-size: clamp(40px, 6vw, 96px);
  line-height: 1;
  text-transform: uppercase;
  color: var(--text-bright);
  text-shadow: 0 2px 28px rgba(3, 4, 4, 0.7);
}

.chapter-text p {
  margin-top: 24px;
  max-width: 520px;
  font-size: 15px;
  line-height: 1.75;
  color: var(--text);
  text-shadow: 0 1px 14px rgba(3, 4, 4, 0.8);
}

/* .chapter-text p would override .kicker (same element) - re-assert the label */
.chapter-text p.kicker {
  margin-top: 0;
  max-width: none;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.3em;
  color: var(--blood);
}

/* Static story: normal vertical flow, one background per chapter.
   JS adds .story--static on touch / reduced-motion. */
.story--static {
  height: auto;
  min-height: 0;
  overflow: visible;
}

.story--static .chapter-bg {
  inset: auto 0 auto 0;
  height: calc(100% / 3);
  opacity: 1;
  transform: none;
}

.story--static .chapter-bg.b1 { top: 0; }
.story--static .chapter-bg.b2 { top: calc(100% / 3); }
.story--static .chapter-bg.b3 { top: calc(200% / 3); }

.story--static .chapter-text {
  position: relative;
  inset: auto;
  min-height: 100vh;
  min-height: 100svh;
  padding: 18vh 8vw;
  opacity: 1;
  transform: none;
}

/* --------------------------------------------------------------------------
   10. Sections shared
   -------------------------------------------------------------------------- */

.section {
  position: relative;
}

.section[id] {
  scroll-margin-top: 32px;
}

.section.bg {
  padding: var(--pad-y) var(--gutter);
}

.card {
  background: var(--surface);
  border: 1px solid var(--line);
}

.cta-row {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 16px;
  margin-top: clamp(40px, 6vh, 64px);
}

/* --------------------------------------------------------------------------
   11. Features - one etched hairline panel
   -------------------------------------------------------------------------- */

.feature-list {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1px;
  max-width: var(--content-max);
  margin-inline: auto;
  background: var(--line);
  border: 1px solid var(--line);
}

.feature-card {
  background: var(--bg);
  border: 0;
  padding: clamp(24px, 3vw, 36px) clamp(22px, 2.6vw, 32px);
  min-height: 190px;
  display: flex;
  flex-direction: column;
  transition: background-color 200ms ease;
}

@media (hover: hover) and (pointer: fine) {
  .feature-card:hover {
    background: var(--surface);
  }
}

.feature-card .num {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.22em;
  color: var(--blood);
}

.feature-card .card__title {
  margin-top: auto;
  padding-top: 36px;
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 16px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text-bright);
  line-height: 1.35;
}

.feature-card p {
  margin-top: 10px;
  font-size: 14px;
  line-height: 1.6;
  color: var(--text-body);
}

/* --------------------------------------------------------------------------
   12. Gallery - horizontal track (JS pin) + native scroll fallback
   -------------------------------------------------------------------------- */

#art.section.bg {
  padding-inline: 0;
}

#art > h2 {
  padding-inline: var(--gutter);
}

.gallery-pin {
  overflow: hidden;
}

/* While pinned (same context as the ScrollTrigger pin in main.js), the bare
   strip would sit flush under the fixed header with a viewport-sized void
   beneath it for the whole 2400px of pinned scroll. Full viewport height +
   vertical centering composes the shots mid-screen instead; native-scroll
   fallbacks keep normal flow. */
@media (pointer: fine) and (prefers-reduced-motion: no-preference) and (min-width: 901px) {
  .gallery-pin {
    display: flex;
    align-items: center;
    height: 100vh;
    height: 100svh;
  }
}

#track {
  display: flex;
  gap: 3vw;
  width: max-content;
  padding: 2vh var(--gutter);
  will-change: transform;
}

.shot {
  position: relative;
  flex: none;
  width: 46vw;
  min-width: 420px;
  overflow: hidden;
  border: 1px solid var(--line);
}

.shot img {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  /* 0.94, not the 0.76 this used to be. That figure was set against the old
     gallery, which was a good deal brighter to begin with; the August 2026
     captures are graded to a fixed target by tools/import-screenshots.sh, so
     dimming them a further quarter took frames that had just been made
     readable and put them back under. Enough of a step is left for the hover
     to still register as the tile waking up. */
  filter: brightness(0.94) saturate(0.96);
  transition: filter 200ms ease;
}

@media (hover: hover) and (pointer: fine) {
  .shot:hover img {
    filter: brightness(1.06) saturate(1.04);
  }
}

.shot .tag {
  position: absolute;
  bottom: 14px;
  left: 16px;
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.2em;
  color: var(--text);
  background: rgba(6, 7, 8, 0.72);
  padding: 6px 10px;
}

/* camera REC dot */
.shot .tag::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--blood);
}

/* Native-scroll fallback: JS adds .gallery--native on touch/reduced-motion.
   Selectors cover the class landing on .gallery-pin or on the section. */
.gallery--native,
.gallery--native .gallery-pin {
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
}

.gallery--native #track {
  will-change: auto;
}

.gallery--native .shot {
  scroll-snap-align: start;
  scroll-margin-left: var(--gutter);
}

/* Lightbox - native <dialog>, top layer */
.lightbox {
  position: fixed;
  inset: 0;
  width: 100vw;
  height: 100vh;
  max-width: none;
  max-height: none;
  padding: 0;
  border: 0;
  background: rgba(4, 5, 6, 0.92);
  color: var(--text);
}

.lightbox[open] {
  display: flex;
  justify-content: center;
  align-items: center;
}

.lightbox::backdrop {
  background: rgba(4, 5, 6, 0.8);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
}

.lightbox-img {
  max-width: min(90vw, 1440px);
  max-height: 80vh;
  width: auto;
  height: auto;
  border: 1px solid var(--line);
}

.lightbox-close,
.lightbox-prev,
.lightbox-next {
  position: absolute;
  z-index: 2;
  display: flex;
  justify-content: center;
  align-items: center;
  width: 48px;
  height: 48px;
  border: 1px solid var(--line);
  background: rgba(6, 7, 8, 0.65);
  color: var(--text-bright);
  cursor: pointer;
  transition: border-color 200ms ease, background-color 200ms ease, transform 160ms var(--ease-out);
}

.lightbox-close:hover,
.lightbox-prev:hover,
.lightbox-next:hover {
  border-color: rgba(194, 45, 30, 0.7);
  background: rgba(13, 15, 17, 0.9);
}

.lightbox-close:active,
.lightbox-prev:active,
.lightbox-next:active {
  transform: scale(0.94);
}

.lightbox-close {
  top: 22px;
  right: 22px;
}

.lightbox-prev {
  left: 22px;
  top: 50%;
  margin-top: -24px;
}

.lightbox-next {
  right: 22px;
  top: 50%;
  margin-top: -24px;
}

.lightbox-close .icon-wrap,
.lightbox-prev .icon-wrap,
.lightbox-next .icon-wrap {
  width: 18px;
  height: 18px;
}

/* injected by main.js - "N / 16" position readout */
.lightbox-counter {
  position: absolute;
  top: 22px;
  left: 22px;
  z-index: 2;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.14em;
  color: var(--text);
  background: rgba(6, 7, 8, 0.72);
  padding: 6px 10px;
  border: 1px solid var(--line);
}

.lightbox-tag {
  position: absolute;
  bottom: 26px;
  left: 50%;
  transform: translateX(-50%);
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.24em;
  color: var(--dim);
  text-transform: uppercase;
}

/* --------------------------------------------------------------------------
   12A. Creatures - Bestiary grid
   Cards use the plain .card look (surface bg, hairline border) rather than
   the hairline-grid technique from Features/Team (shared background as the
   border) because each card needs its OWN border to blood-tint on hover.
   No opacity:0 here - reveal state is JS-only (initReveals), same rule as
   every other .reveal element on the page.
   -------------------------------------------------------------------------- */


/* --------------------------------------------------------------------------
   13. Factsheet - terminal readout
   -------------------------------------------------------------------------- */

#factsheet h2::after {
  content: "_";
  color: var(--blood);
  animation: caret-blink 1.1s steps(1) infinite;
}

@keyframes caret-blink {
  0%, 100% { opacity: 1; }
  50% { opacity: 0; }
}

.facts-term {
  max-width: 760px;
  margin-inline: auto;
  font-family: var(--font-mono);
  border-top: 1px solid var(--line);
}

.fact-row {
  display: flex;
  align-items: baseline;
  padding: 14px 2px;
  border-bottom: 1px solid var(--line);
}

.fact-row dt {
  flex: 1 1 auto;
  display: flex;
  align-items: baseline;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--dim);
}

/* dotted leader */
.fact-row dt::after {
  content: "";
  flex: 1;
  min-width: 32px;
  margin: 0 14px;
  border-bottom: 1px dotted rgba(214, 211, 205, 0.28);
  transform: translateY(-3px);
}

.fact-row dd {
  flex: none;
  max-width: 62%;
  text-align: right;
  font-size: 13px;
  font-weight: 400;
  color: var(--text-bright);
}

.fact-row .sub {
  margin-left: 8px;
  font-size: 11px;
  color: var(--dim);
}

.badge {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text);
  border: 1px solid var(--line);
  padding: 2px 8px;
  margin-left: 4px;
}

/* --------------------------------------------------------------------------
   14. Roadmap - left rail timeline
   -------------------------------------------------------------------------- */

/* Grid overlap keeps the rail exactly as tall as the milestone list. */
#roadmap.section.bg {
  display: grid;
  grid-template-columns: minmax(0, var(--measure));
  justify-content: center;
}

#roadmap > h2 {
  grid-column: 1;
}

.timeline {
  grid-column: 1;
  grid-row: 2;
  position: relative;
  z-index: 1;
  padding-left: 56px;
}

.timeline-line {
  grid-column: 1;
  grid-row: 2;
  position: relative;
  z-index: 0;
  width: 1px;
  margin-left: 8px;
  background: var(--line);
}

.timeline-line-progress {
  position: absolute;
  inset: 0;
  background: var(--blood);
  box-shadow: 0 0 14px rgba(194, 45, 30, 0.55);
  transform: scaleY(0);
  transform-origin: top;
  will-change: transform;
}

.milestone {
  position: relative;
  padding: 26px 0;
}

/* node dot on the rail */
.milestone::before {
  content: "";
  position: absolute;
  left: -52px;
  top: 34px;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--bg);
  border: 1px solid var(--dim);
  transition: background-color 200ms ease, border-color 200ms ease, box-shadow 200ms ease;
}

.milestone .q {
  display: block;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--dim);
  margin-bottom: 8px;
}

.milestone h3 {
  display: inline-block;
  font-family: var(--font-display);
  font-size: clamp(22px, 2.6vw, 30px);
  line-height: 1.05;
  text-transform: uppercase;
  letter-spacing: 0.015em;
  color: rgba(214, 211, 205, 0.55);
  margin-right: 16px;
  transition: color 200ms ease;
}

.status {
  display: inline-block;
  vertical-align: 4px;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--dim);
  border: 1px solid var(--line);
  padding: 4px 10px;
  white-space: nowrap;
}

.status:empty {
  display: none;
}

.status--done {
  color: var(--text);
  border-color: rgba(214, 211, 205, 0.3);
}

.status--inprogress {
  color: #e0492f;
  border-color: rgba(194, 45, 30, 0.55);
}

.status--inprogress::before {
  content: "";
  display: inline-block;
  width: 6px;
  height: 6px;
  margin-right: 8px;
  border-radius: 50%;
  background: var(--blood);
  animation: status-pulse 1.6s var(--ease-in-out) infinite;
}

@keyframes status-pulse {
  0%, 100% { opacity: 1; box-shadow: 0 0 0 0 rgba(194, 45, 30, 0.5); }
  50% { opacity: 0.55; box-shadow: 0 0 0 5px rgba(194, 45, 30, 0); }
}

.status--planned {
  border-style: dashed;
}

/* passed milestones - JS adds .lit as the progress line crosses them */
.milestone.lit h3 {
  color: var(--text-bright);
}

.milestone.lit::before {
  background: var(--blood);
  border-color: var(--blood);
  box-shadow: 0 0 12px rgba(194, 45, 30, 0.6);
}

/* --------------------------------------------------------------------------
   15. Team
   -------------------------------------------------------------------------- */

.team-grid {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 1px;
  max-width: var(--content-max);
  margin-inline: auto;
  background: var(--line);
  border: 1px solid var(--line);
}

.team-member {
  background: var(--bg);
  border: 0;
  padding: 0 0 22px;
  text-align: center;
  overflow: hidden;
  transition: background-color 200ms ease;
}

@media (hover: hover) and (pointer: fine) {
  .team-member:hover {
    background: var(--surface);
  }
}

.team-member picture {
  display: block;
  overflow: hidden;
}

.avatar {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 285 / 369;
  object-fit: cover;
  object-position: center 22%;
  border: 0;
  filter: grayscale(0.5) contrast(1.05) brightness(0.82);
  transition:
    filter 300ms ease,
    transform 400ms var(--ease-out);
}

@media (hover: hover) and (pointer: fine) {
  .team-member:hover .avatar {
    filter: grayscale(0) contrast(1) brightness(1);
    transform: scale(1.03);
  }
}

.team-member h3 {
  margin-top: 16px;
  padding-inline: 12px;
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 15px;
  letter-spacing: 0.03em;
  color: var(--text-bright);
}

.team-member .role {
  margin-top: 6px;
  padding-inline: 12px;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 400;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--dim);
}

/* --------------------------------------------------------------------------
   16. Press kit
   -------------------------------------------------------------------------- */

.press-assets {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1px;
  max-width: 960px;
  margin-inline: auto;
  background: var(--line);
  border: 1px solid var(--line);
}

.press-card {
  background: var(--bg);
  border: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
  padding: 30px 28px;
  transition: background-color 200ms ease;
}

@media (hover: hover) and (pointer: fine) {
  .press-card:hover {
    background: var(--surface);
  }
}

.press-card strong {
  font-weight: 500;
  font-size: 15px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text-bright);
}

.press-card span {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.12em;
  color: var(--dim);
  text-transform: uppercase;
}

.press-card .btn {
  margin-top: 22px;
}

/* --------------------------------------------------------------------------
   17. Publisher
   -------------------------------------------------------------------------- */

.publisher-list {
  max-width: 680px;
  margin-inline: auto;
}

.publisher-list > li {
  padding: 16px 2px;
  border-bottom: 1px solid var(--line);
  font-size: 15px;
  color: var(--text-body);
}

.publisher-list > li:first-child {
  border-top: 1px solid var(--line);
}

.publisher-list strong {
  font-weight: 500;
  color: var(--text-bright);
}

.publisher-list ul {
  margin-top: 10px;
}

.publisher-list ul li {
  position: relative;
  padding: 5px 0 5px 20px;
  font-size: 14px;
}

.publisher-list ul li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 15px;
  width: 8px;
  height: 1px;
  background: var(--blood);
}

/* --------------------------------------------------------------------------
   18. FAQ
   -------------------------------------------------------------------------- */

.faq-list {
  max-width: 760px;
  margin-inline: auto;
  border-top: 1px solid var(--line);
}

.faq-item {
  border-bottom: 1px solid var(--line);
}

.faq-q {
  position: relative;
  display: block;
  width: 100%;
  text-align: left;
  padding: 22px 48px 22px 2px;
  font-family: var(--font-body);
  font-weight: 400;
  font-size: 17px;
  color: var(--text-bright);
  cursor: pointer;
  transition: color 200ms ease;
}

.faq-q:hover {
  color: #fff;
}

.faq-q .icon-wrap {
  position: absolute;
  right: 6px;
  top: 50%;
  margin-top: -8px;
  width: 16px;
  height: 16px;
  color: var(--dim);
  transition: transform 200ms var(--ease-out), color 200ms ease;
}

.faq-q[aria-expanded="true"] .icon-wrap {
  transform: rotate(45deg); /* + becomes × */
  color: var(--blood);
}

.faq-a {
  overflow: hidden; /* JS animates height */
  max-width: 660px;
  padding: 0 2px 26px;
  font-size: 15px;
  line-height: 1.75;
  color: var(--text-body);
}

/* --------------------------------------------------------------------------
   19. Careers
   -------------------------------------------------------------------------- */

#careers .center-txt h3 {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 14px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-bright);
  margin-bottom: 26px;
}

.carrier-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px clamp(24px, 4vw, 56px);
  text-align: left;
  max-width: 960px;
  margin-inline: auto;
}

.carrier-list li {
  position: relative;
  padding: 8px 0 8px 20px;
  font-size: 14px;
  line-height: 1.65;
  color: var(--text-body);
}

.carrier-list li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 19px;
  width: 8px;
  height: 1px;
  background: var(--blood);
}

.carrier-list strong {
  font-weight: 500;
  color: var(--text-bright);
}

.careers-wrap {
  max-width: 1000px;
  margin-inline: auto;
}

.form-card {
  padding: clamp(26px, 4.5vw, 52px);
}

.form-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0 clamp(28px, 4vw, 48px);
}

.form-row {
  margin-bottom: 22px;
}

.form-row > label {
  display: block;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--dim);
  margin-bottom: 9px;
}

.req {
  color: var(--blood);
}

.form-row input[type="text"],
.form-row input[type="email"],
.form-row input[type="url"],
.form-row select,
.form-row textarea {
  width: 100%;
  background: var(--field-bg);
  border: 1px solid var(--line);
  border-radius: 0;
  color: var(--text);
  font-family: var(--font-body);
  font-weight: 300;
  font-size: 15px;
  padding: 13px 14px;
  transition: border-color 200ms ease, box-shadow 200ms ease;
}

.form-row input::placeholder,
.form-row textarea::placeholder {
  color: rgba(119, 115, 108, 0.65);
}

.form-row input:focus-visible,
.form-row select:focus-visible,
.form-row textarea:focus-visible {
  outline: none;
  border-color: var(--blood);
  box-shadow: 0 0 0 3px rgba(194, 45, 30, 0.18);
}

.form-row select {
  appearance: none;
  -webkit-appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' fill='none' stroke='%2377736c' stroke-width='1.5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 14px center;
  padding-right: 40px;
}

.form-row textarea {
  min-height: 128px;
  resize: vertical;
}

/* chips - bordered toggle labels over visually-hidden inputs */
.chips {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

.chip {
  position: relative;
}

.chip input {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
}

.chip label {
  display: block;
  border: 1px solid var(--line);
  padding: 9px 16px;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--dim);
  cursor: pointer;
  transition: color 200ms ease, border-color 200ms ease, background-color 200ms ease;
}

.chip label:hover {
  color: var(--text);
  border-color: rgba(214, 211, 205, 0.32);
}

.chip input:checked + label {
  color: var(--text-bright);
  border-color: var(--blood);
  background: rgba(194, 45, 30, 0.12);
}

.chip input:focus-visible + label {
  outline: 2px solid var(--blood);
  outline-offset: 2px;
}

.form-row.inline-checkbox {
  display: flex;
  align-items: flex-start;
  gap: 12px;
}

.form-row.inline-checkbox input {
  flex: none;
  width: 16px;
  height: 16px;
  margin-top: 3px;
  accent-color: var(--blood);
}

.form-row.inline-checkbox label {
  margin: 0;
  font-family: var(--font-body);
  font-size: 13px;
  font-weight: 300;
  letter-spacing: 0;
  text-transform: none;
  color: var(--text-body);
  line-height: 1.6;
}

.privacy-note {
  font-size: 12px;
  color: var(--dim);
  margin-bottom: 22px;
}

.form-row.honeypot {
  position: absolute;
  left: -9999px;
}

.alert {
  margin-top: 24px;
  padding: 15px 18px;
  border: 1px solid var(--line);
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.06em;
  line-height: 1.6;
}

.alert.success {
  border-color: rgba(125, 168, 125, 0.5);
  color: #a7c4a7;
}

.alert.error {
  border-color: rgba(194, 45, 30, 0.6);
  color: #dd8a7d;
}

/* --------------------------------------------------------------------------
   20. Contact
   -------------------------------------------------------------------------- */

#contact {
  text-align: center;
}

#contact > p {
  font-size: 17px;
}

.socials {
  display: flex;
  justify-content: center;
  gap: 18px;
  margin-top: 40px;
}

.social-link {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 54px;
  height: 54px;
  border: 1px solid var(--line);
  color: var(--text);
  transition: border-color 200ms ease, color 200ms ease, transform 160ms var(--ease-out);
}

.social-link:hover {
  border-color: rgba(194, 45, 30, 0.7);
  color: var(--text-bright);
}

.social-link:active {
  transform: scale(0.95);
}

/* --------------------------------------------------------------------------
   21. Footer
   -------------------------------------------------------------------------- */

.site-footer {
  border-top: 1px solid var(--line);
  padding: clamp(56px, 8vh, 88px) var(--gutter) 44px;
}

.footer-inner {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 40px;
  max-width: var(--content-max);
  margin-inline: auto;
}

.footer-col h3 {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--dim);
  margin-bottom: 18px;
}

.footer-col li {
  margin-bottom: 10px;
}

.footer-col a {
  font-size: 14px;
  color: var(--text);
  transition: color 200ms ease;
}

.footer-col a:hover {
  color: var(--blood);
}

.legal-note {
  margin-top: clamp(48px, 7vh, 72px);
  text-align: center;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.12em;
  color: var(--dim);
}

.disclaimer-footer {
  margin: 14px auto 0;
  max-width: 760px;
  text-align: center;
  font-size: 11px;
  line-height: 1.7;
  color: var(--dim);
}

/* --------------------------------------------------------------------------
   22. Responsive
   -------------------------------------------------------------------------- */

/* Measured widths of the whole header row (logo + links + button + padding):
     13px / 0.06em / 18px gap  ->  1345px
     12px / 0.04em / 12px gap  ->  1208px
   Hence the steps below. Under 1200 the overlay menu takes over instead of
   shrinking the type further. */
@media (max-width: 1360px) {
  .nav-list {
    gap: 12px;
  }

  .nav-list a {
    font-size: 12px;
    letter-spacing: 0.04em;
  }
}

@media (max-width: 1100px) {

  .team-grid {
    grid-template-columns: repeat(4, 1fr);
  }

  .shot {
    width: 56vw;
    min-width: 380px;
  }

}

/* The overlay menu now starts at 1200px, not 900px: between those widths the
   horizontal row could only fit by shrinking the type to 10px, which is the
   problem this change is meant to fix. */
@media (max-width: 1200px) {
  .site-header {
    padding: 14px clamp(20px, 4vw, 32px);
    background: linear-gradient(to bottom, rgba(6, 7, 8, 0.85), transparent);
  }

  /* full-screen overlay menu, opened via .nav-open on the header */
  .primary-nav {
    position: fixed;
    inset: 0;
    z-index: -1; /* under the header bar so logo/burger stay clickable */
    margin: 0;
    display: flex;
    justify-content: center;
    align-items: center;
    background: #040506; /* opaque: translucency ghosts bright text through */
    visibility: hidden; /* menu overlay - revealed by .nav-open */
    clip-path: inset(0 0 100% 0);
    transition: clip-path 360ms var(--ease-in-out), visibility 0s 360ms;
  }

  .nav-open .primary-nav {
    visibility: visible;
    clip-path: inset(0 0 0 0);
    /* Entering uses ease-out (fast start, settle at the end) - the
       symmetric ease-in-out used for closing delays the very first frame
       the user watches, reading as a hesitation before the reveal commits. */
    transition: clip-path 360ms var(--ease-out), visibility 0s;
  }

  .nav-list {
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
    max-height: 100vh;
    max-height: 100svh;
    overflow-y: auto;
    padding: 96px 12vw 48px;
    width: 100%;
    counter-reset: navitem;
  }

  .nav-list li {
    counter-increment: navitem;
    width: 100%;
  }

  .nav-list a {
    display: block;
    font-family: var(--font-display);
    font-size: min(6.2vh, 42px);
    line-height: 1.18;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    color: var(--text-bright);
    padding: 2px 0;
  }

  .nav-list a::before {
    content: counter(navitem, decimal-leading-zero);
    font-family: var(--font-mono);
    font-size: 10px;
    font-weight: 500;
    letter-spacing: 0.2em;
    color: var(--blood);
    margin-right: 16px;
    vertical-align: 0.9em;
  }

  .nav-list a::after {
    content: none;
  }

  /* The overlay drops the underline, so the current section is signalled by
     contrast instead: it stays at full strength while the rest step back.
     Works at a glance on a phone, where a 2px rule would not. */
  .nav-list a {
    opacity: 0.5;
    transition: opacity 180ms var(--ease-out);
  }

  .nav-list a[aria-current],
  .nav-list a:hover,
  .nav-list a:focus-visible {
    opacity: 1;
  }

  .nav-list a[aria-current]::before {
    color: #fff;
  }

  .menu-toggle {
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 5px;
    width: 44px;
    height: 44px;
    padding: 10px;
    cursor: pointer;
  }

  .menu-toggle .bar {
    display: block;
    width: 24px;
    height: 2px;
    background: var(--text);
    transition: transform 200ms var(--ease-out);
  }

  .nav-open .menu-toggle .bar:nth-child(1) {
    transform: translateY(7px) rotate(45deg);
  }

  .nav-open .menu-toggle .bar:nth-child(2) {
    transform: scaleX(0);
  }

  .nav-open .menu-toggle .bar:nth-child(3) {
    transform: translateY(-7px) rotate(-45deg);
  }

  .nav-cta {
    margin-left: auto;
  }

  .feature-list {
    grid-template-columns: 1fr;
  }

  .feature-card {
    min-height: 0;
  }

  .feature-card .card__title {
    padding-top: 20px;
  }

  .shot {
    width: 78vw;
    min-width: 300px;
  }

  .team-grid {
    grid-template-columns: repeat(3, 1fr);
  }

  .press-assets {
    grid-template-columns: 1fr;
  }

  .carrier-row {
    grid-template-columns: 1fr;
  }

  .form-grid {
    grid-template-columns: 1fr;
  }

  .footer-inner {
    grid-template-columns: repeat(2, 1fr);
  }

  .lightbox-prev {
    left: 10px;
  }

  .lightbox-next {
    right: 10px;
  }
}

@media (max-width: 600px) {
  :root {
    --pad-y: clamp(80px, 12vh, 110px);
  }

  .team-grid {
    grid-template-columns: repeat(2, 1fr);
  }

  body {
    font-size: 15px;
  }

  .logo-wrap img {
    height: 64px;
  }

  .nav-cta {
    padding: 8px 12px;
    font-size: 10px;
  }

  .hero-content {
    padding-top: 72px;
  }

  .hero-tag {
    font-size: 14px;
  }

  .chapter-text p {
    font-size: 14px;
  }

  .fact-row dd {
    max-width: 58%;
    font-size: 12px;
  }

  .timeline {
    padding-left: 40px;
  }

  .timeline-line {
    margin-left: 4px;
  }

  .milestone::before {
    left: -40px;
  }

  .milestone h3 {
    display: block;
    margin: 0 0 10px;
  }

  .status {
    vertical-align: baseline;
  }


  .lightbox-img {
    max-width: 100vw;
    border-left: 0;
    border-right: 0;
  }

  .lightbox-prev,
  .lightbox-next {
    top: auto;
    bottom: 70px;
    margin-top: 0;
  }


}

/* --------------------------------------------------------------------------
   23. No-JS readability - @media (scripting: none)
   The page must read top-to-bottom on styles.css alone.
   -------------------------------------------------------------------------- */

@media (scripting: none) {
  .preloader {
    display: none;
  }

  /* story falls back to static vertical flow */
  #story.story {
    height: auto;
    min-height: 0;
    overflow: visible;
  }

  #story .chapter-bg {
    inset: auto 0 auto 0;
    height: calc(100% / 3);
  }

  #story .chapter-bg.b1 { top: 0; }
  #story .chapter-bg.b2 { top: calc(100% / 3); }
  #story .chapter-bg.b3 { top: calc(200% / 3); }

  #story .chapter-text {
    position: relative;
    inset: auto;
    min-height: 100vh;
    min-height: 100svh;
    padding: 18vh 8vw;
  }

  /* gallery becomes a native scroller */
  .gallery-pin {
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
  }

  .shot {
    scroll-snap-align: start;
    scroll-margin-left: var(--gutter);
  }

  /* FAQ answers are readable without the accordion */
  .faq-a[hidden] {
    display: block;
  }

  .faq-q .icon-wrap {
    display: none;
  }
}

/* --------------------------------------------------------------------------
   24. Reduced motion
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  .grain,
  .hero-scroll-line,
  #factsheet h2::after,
  .status--inprogress::before {
    animation: none;
  }

  .glitch .g {
    display: none;
  }

  .nav-open .primary-nav,
  .primary-nav {
    transition: none;
  }

  /* Static infection mood - the scroll-linked vignette growth is JS/motionOk
     only (see initInfection in main.js); reduced-motion readers get a fixed,
     non-animated 0.25 vignette so the page keeps its atmosphere without any
     scroll-driven change. */
  #vignette {
    opacity: 0.25;
  }
}

/* --------------------------------------------------------------------------
   24. Legal Pages - privacy.html, terms.html
   -------------------------------------------------------------------------- */

.legal-page {
  max-width: 820px;
  margin: clamp(64px, 10vh, 120px) auto clamp(48px, 8vh, 88px);
  padding: 0 var(--gutter);
}

.legal-page h1 {
  font-family: var(--font-display);
  font-size: clamp(36px, 5vw, 56px);
  line-height: 1.1;
  letter-spacing: 0.01em;
  text-transform: uppercase;
  color: var(--text-bright);
  margin-bottom: 18px;
}

.legal-page h2 {
  font-family: var(--font-body);
  font-size: clamp(18px, 2.5vw, 24px);
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: 0;
  text-transform: none;
  text-align: left;
  color: var(--text-bright);
  margin: 40px 0 20px 0;
}

.legal-page h2:first-of-type {
  margin-top: 32px;
}

.legal-page p {
  margin-bottom: 18px;
  line-height: 1.8;
  color: var(--text-body);
}

.legal-page ul,
.legal-page ol {
  margin: 20px 0 20px 1.6em;
  padding: 0;
  list-style-position: outside;
  list-style-type: disc;
}

.legal-page li {
  margin-bottom: 12px;
  line-height: 1.8;
  color: var(--text-body);
}

.legal-page ol {
  list-style-type: decimal;
}

.legal-page strong {
  color: var(--text-bright);
}

.legal-page em {
  color: var(--text);
}

.updated-date {
  opacity: 0.7;
  font-size: 0.875rem;
  margin-bottom: 32px;
  color: var(--dim);
}

@media (max-width: 600px) {
  .legal-page {
    margin-top: clamp(80px, 12vh, 100px);
  }

  .legal-page h1 {
    font-size: 28px;
  }

  .legal-page h2 {
    font-size: 18px;
    margin-top: 32px;
  }
}

/* --------------------------------------------------------------------------
   25. Print - nothing fancy, just no overlays
   -------------------------------------------------------------------------- */

@media print {
  .grain,
  .scanlines,
  #vignette,
  #flash,
  #cursorDot,
  #cursorRing,
  .preloader,
  .site-header,
  .hero-scroll {
    display: none;
  }
}

/* --------------------------------------------------------------------------
   26. Cookie consent banner (GDPR)
   -------------------------------------------------------------------------- */

.cookie-banner {
  position: fixed;
  z-index: 350;
  left: 16px;
  right: 16px;
  bottom: 16px;
  max-width: 720px;
  margin-inline: auto;
  display: flex;
  gap: 18px;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  padding: 16px 20px;
  background: rgba(13, 15, 17, 0.96);
  border: 1px solid var(--line);
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  transform: translateY(140%);
  transition: transform 320ms var(--ease-out);
}

.cookie-banner[hidden] {
  display: none;
}

.cookie-banner.is-visible {
  transform: translateY(0);
}

.cookie-text {
  flex: 1 1 300px;
  margin: 0;
  font-size: 13px;
  line-height: 1.6;
  color: var(--text);
}

.cookie-text a {
  color: var(--blood);
}

.cookie-actions {
  display: flex;
  gap: 10px;
  flex: none;
}

@media (prefers-reduced-motion: reduce) {
  .cookie-banner {
    transition: none;
  }
}

@media (max-width: 600px) {
  .cookie-banner {
    flex-direction: column;
    align-items: stretch;
  }

  .cookie-actions {
    justify-content: flex-end;
  }
}

/* --------------------------------------------------------------------------
   27. Content warning + age gate (mature content)
   -------------------------------------------------------------------------- */

.content-note {
  margin-top: 18px;
  text-align: center;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--dim);
}

.content-note__badge {
  display: inline-block;
  margin-right: 7px;
  padding: 1px 6px;
  border: 1px solid rgba(194, 45, 30, 0.6);
  border-radius: 2px;
  color: var(--blood);
  font-weight: 500;
}

.age-gate {
  width: min(440px, 92vw);
  margin: auto;
  padding: 30px 28px 24px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--text);
  text-align: center;
}

.age-gate::backdrop {
  background: rgba(4, 5, 6, 0.86);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

.age-gate-title {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--blood);
  margin-bottom: 12px;
}

.age-gate-text {
  font-size: 14px;
  line-height: 1.6;
  margin-bottom: 22px;
}

.age-gate-actions {
  display: flex;
  gap: 10px;
  justify-content: center;
  flex-wrap: wrap;
}

/* ---------------------------------------------------------------------------
   #about - the short "What is INVASIA?" answer under the hero.
   Kept out of `.section.bg` so it doesn't take a number in the LOG counter.
   --------------------------------------------------------------------------- */
.about-lede {
  padding: clamp(56px, 8vh, 96px) var(--gutter);
  border-bottom: 1px solid var(--line);
}

.about-lede h2 {
  margin: 0 0 18px;
  text-align: left;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--blood);
}

.about-lede p {
  max-width: 68ch;
  margin: 0;
  font-size: clamp(16px, 1.5vw, 20px);
  line-height: 1.6;
  color: var(--text-bright);
}

/* ---------------------------------------------------------------------------
   Rescue state, set by the inline script in index.html when gsap or main.js
   never arrived. Everything JavaScript would have revealed is forced visible,
   so a dropped request costs the animation, not the page.
   --------------------------------------------------------------------------- */
.js-rescued .reveal,
.js-rescued .hero-tag,
.js-rescued .hero-actions,
.js-rescued .hero-content,
.js-rescued .hero-scroll,
.js-rescued #glitch,
.js-rescued .chapter-text {
  opacity: 1 !important;
  transform: none !important;
  visibility: visible !important;
}

.js-rescued .preloader {
  display: none !important;
}

/* ---------------------------------------------------------------------------
   Reading progress + back to top

   Both exist because the page is roughly twenty-two screens tall. Neither is
   an effect: one answers "how much is left", the other "how do I get back".
   --------------------------------------------------------------------------- */

.read-progress {
  position: absolute;
  left: 0;
  bottom: 0;
  height: 2px;
  width: 100%;
  background: var(--blood);
  transform: scaleX(0);
  transform-origin: left;
  /* Driven by transform only, so it never triggers layout while scrolling. */
  will-change: transform;
  pointer-events: none;
}

.to-top {
  position: fixed;
  right: clamp(16px, 3vw, 34px);
  bottom: clamp(16px, 3vw, 34px);
  z-index: calc(var(--z-header) - 10);
  width: 46px;
  height: 46px;
  display: grid;
  place-items: center;
  border: 1px solid var(--line);
  background: rgba(6, 7, 8, 0.82);
  backdrop-filter: blur(8px);
  color: var(--text-bright);
  cursor: pointer;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 220ms var(--ease-out), transform 220ms var(--ease-out),
    border-color 220ms var(--ease-out);
}

.to-top[hidden] {
  display: none;
}

.to-top.is-visible {
  opacity: 1;
  transform: none;
}

.to-top:hover {
  border-color: var(--blood);
}

.to-top:active {
  transform: translateY(1px);
}

/* The icon set has no "up" arrow, so the left one is turned. */
.to-top .icon-wrap {
  transform: rotate(90deg);
}

@media (prefers-reduced-motion: reduce) {
  .to-top {
    transition: none;
  }
}

/* ---------------------------------------------------------------------------
   Threshold cut into #creatures

   One splice, in one place. Everything before the creature section is the ship
   and the story; everything after is what is left of the crew, behind an 18+
   notice. That change of register is the only point on the page that earns a
   hard cut, and it earns it precisely because it happens once.

   Reuses the #flash layer with a modifier: black instead of the ambient red
   blink, so the two never read as the same event.
   --------------------------------------------------------------------------- */

#flash.is-cut {
  background: #040505;
}

/* ---------------------------------------------------------------------------
   Ambient sound toggle

   Off by default and never autoplayed. A horror site that starts making noise
   before you asked is a site people close. The button sits next to the Wishlist
   CTA because that is where the eye already goes.
   --------------------------------------------------------------------------- */

.sound-toggle {
  flex: none;
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  margin-left: 4px;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--dim);
  cursor: pointer;
  transition: color 200ms ease, border-color 200ms ease;
}

.sound-toggle:hover {
  color: var(--text-bright);
  border-color: rgba(214, 211, 205, 0.3);
}

.sound-toggle[aria-pressed="true"] {
  color: var(--blood);
  border-color: rgba(194, 45, 30, 0.55);
}

.sound-toggle .icon-wrap {
  width: 17px;
  height: 17px;
}

.sound-toggle:active {
  transform: scale(0.96);
}

@media (max-width: 1200px) {
  /* The overlay menu owns the header at these widths; the toggle would crowd
     the burger. It comes back with the horizontal nav. */
  .sound-toggle {
    display: none;
  }
}

/* ---------------------------------------------------------------------------
   Ambient volume slider

   Lives beside the toggle and only exists while the sound is on. It is not
   hidden but collapsed to zero width, so opening it slides the header apart
   instead of jolting it.
   --------------------------------------------------------------------------- */

.sound-control {
  flex: none;
  display: flex;
  align-items: center;
  gap: 0;
}

.sound-level {
  width: 0;
  opacity: 0;
  margin: 0;
  pointer-events: none;
  appearance: none;
  -webkit-appearance: none;
  background: transparent;
  height: 18px;
  transition: width 260ms var(--ease-out), opacity 200ms ease,
    margin 260ms var(--ease-out);
}

.sound-control.is-open .sound-level {
  width: 74px;
  opacity: 1;
  margin-left: 10px;
  pointer-events: auto;
}

/* Track and thumb have to be styled per engine; there is no shared shorthand. */
.sound-level::-webkit-slider-runnable-track {
  height: 2px;
  background: rgba(214, 211, 205, 0.24);
}

.sound-level::-moz-range-track {
  height: 2px;
  background: rgba(214, 211, 205, 0.24);
}

.sound-level::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 10px;
  height: 10px;
  margin-top: -4px;
  border-radius: 50%;
  background: var(--blood);
  border: 0;
  cursor: pointer;
}

.sound-level::-moz-range-thumb {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--blood);
  border: 0;
  cursor: pointer;
}

.sound-level:focus-visible {
  outline: 2px solid var(--blood);
  outline-offset: 3px;
}

@media (prefers-reduced-motion: reduce) {
  .sound-level {
    transition: none;
  }
}

/* ---------------------------------------------------------------------------
   Diegetic-interface proof

   Split rather than centred: the claim and the evidence for it should sit side
   by side so the eye can check one against the other, which a stacked layout
   makes you scroll to do.
   --------------------------------------------------------------------------- */

.proof {
  border-top: 1px solid var(--line);
  /* No padding on top, because #features above already ends with its own
     --pad-y and two paddings in a row stack into one long nothing. That stack
     is what the gap above the video was: 135px from the section above, plus
     another 61px of dead space this section made on its own by centring a
     390px video against what was then a 512px column of text. The heading is
     two lines now instead of four, so that second part is gone; dropping the
     top padding removes the doubling and leaves the same gap every other
     section transition on this page has.

     Bottom padding stays: #art below opens with a heading rather than its own
     full-width padding, and without it the gallery crowds the paragraph. */
  padding: 0 var(--gutter) clamp(52px, 7vh, 88px);
}

.proof-inner {
  display: grid;
  grid-template-columns: 1.35fr 1fr;
  gap: clamp(28px, 5vw, 72px);
  align-items: center;
  max-width: 1280px;
  margin-inline: auto;
}

.proof-media {
  position: relative;
  overflow: hidden;
  border: 1px solid var(--line);
  /* Reserve the box before the video loads. preload="none" means the file is
     not fetched until it is nearly in view, so without this the section would
     collapse and then shove the gallery down the page as it arrives. */
  aspect-ratio: 16 / 9;
  background: var(--surface);
}

.proof-video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.proof-media .tag {
  position: absolute;
  left: 16px;
  bottom: 14px;
  padding: 6px 10px;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-2, #b9b5ae);
  background: rgba(6, 7, 8, 0.72);
}

/* Sized for a column, not for a section.
   The global h2 runs to 72px, which is right for a heading that owns the full
   width of the page and wrong for one sharing a 514px column with a video: at
   72px this wrapped to three lines and stranded the word YOU alone on the
   middle one. Capping it at 40px lets the line break where the sentence does. */
.proof-copy h2 {
  font-size: clamp(26px, 2.6vw, 40px);
  line-height: 1.08;
  margin: 0 0 18px;
  /* Left, against the global h2's centring. Section headings on this site are
     centred because they sit over the full width; here the heading shares an
     edge with the paragraph under it, and a centred line above a ragged-right
     one looks like neither was decided on. */
  text-align: left;
}

.proof-copy p:last-child {
  color: var(--ink-2, #b9b5ae);
  max-width: 46ch;
}

@media (max-width: 900px) {
  .proof-inner {
    grid-template-columns: 1fr;
    gap: 24px;
  }
}

/* Reduced motion: the poster is already on the element, so hiding the video
   frame leaves the still in place and the section keeps making its point. */
@media (prefers-reduced-motion: reduce) {
  .proof-video::-webkit-media-controls { display: none; }
}

/* ---------------------------------------------------------------------------
   Production turntables above the creature cards

   Same three columns and the same card width as the creature grid below, so
   the two blocks read as one section. What differs is the height: these clips
   were captured at five different aspect ratios and are shown at every one of
   them. An earlier pass forced them into the cards' 4/5 box with object-fit:
   cover, which cut a 320x192 landscape down to a portrait and hid half of each
   model - the whole point of showing a turntable is that you can see the model.
   align-items: start is what lets each card keep its own height.
   --------------------------------------------------------------------------- */

.pipe-band {
  max-width: var(--content-max);
  margin: 0 auto clamp(28px, 4vw, 48px);
}

.pipe-band .kicker {
  margin-bottom: 14px;
}

.pipe-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(16px, 2vw, 24px);
  align-items: start;
}

.pipe-card {
  position: relative;
  overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--line);
  transition: border-color 200ms ease, transform 200ms var(--ease-out, ease);
}

.pipe-card:hover {
  border-color: rgba(194, 45, 30, 0.6);
  transform: translateY(-4px);
}

.pipe-card video {
  display: block;
  width: 100%;
  height: auto;
}

.pipe-card .tag {
  position: absolute;
  bottom: 12px;
  left: 14px;
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-2, #b9b5ae);
  text-shadow: 0 1px 6px rgba(6, 7, 8, 0.9);
}

.pipe-card .tag::before {
  content: "";
  flex: none;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--blood);
}

@media (max-width: 900px) {
  .pipe-grid { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 600px) {
  .pipe-grid { grid-template-columns: 1fr; }
}

/* A thirteenth menu item (Story) pushed the row over its width and PRESS KIT
   broke across two lines mid-label. Labels are two words at most, so keeping
   them whole costs nothing and stops the header changing height. */
.primary-nav .nav-list > li > a {
  white-space: nowrap;
}

