/* ============================================================================
   LUDEO — styles-v3.css
   Design system for the 2026 site redesign.

   One committed world: near-black ground, a single amber accent, heavy
   condensed display type over Sora reading type, zero-radius structure,
   hairline rules instead of cards. Two warm-paper bands carry the pacing.

   Token values are Ludeo's own (studios-landing v2 system), not invented.
   ============================================================================ */

/* ---------------------------------------------------------------- 1. TOKENS */
:root {
  /* Brand accent. Amber is the only accent in the system. */
  --amber: #eca746;
  --amber-hi: #efb667;
  --amber-lo: #c8862f;
  --gold: #ffbb00;
  --amber-ink: #151007;   /* label color on an amber fill */
  /* Ludeo's own brand gradient. Amber fields carry it; controls stay flat so
     their labels keep full contrast. */
  --grad-amber: linear-gradient(92deg, #eca746 0%, #ffbb00 100%);
  /* The pentagon from the Ludeo mark, used as this system's dot and bullet. */
  --mark: url("/media/brand/Ludeo pentagon logo.svg");

  /* Dark ground */
  --ink-0: #0b0b0e;       /* page */
  --ink-1: #0c0c0f;       /* deeper wells */
  --ink-2: #131317;       /* chrome, nav, footer */
  --ink-3: #17171b;       /* raised */

  --text: #f4f4f6;
  --muted: #b6b8c4;
  --faint: #7e8290;

  --line: rgba(255, 255, 255, 0.09);
  --line-2: rgba(255, 255, 255, 0.16);
  --fill: rgba(255, 255, 255, 0.04);
  --fill-2: rgba(255, 255, 255, 0.07);

  /* Warm paper band */
  --paper: #f6f3ec;
  --paper-2: #efece2;
  --paper-line: #ddd8c9;
  --paper-ink: #17181c;
  --paper-muted: #55534a;
  --paper-faint: #6a6759;   /* 5.1:1 on --paper; the old #8b887b failed at label sizes */
  --paper-kick: #96601b;  /* amber that passes contrast on paper */

  --ok: #1f7a4d;
  --bad: #c62323;
  --bad-dark: #ff8080;   /* --bad fails contrast on the ink ramp; this is its dark-surface twin */

  /* Type */
  --display: "Barlow Condensed", "Arial Narrow", system-ui, sans-serif;
  --sans: "Sora", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;

  /* Metrics */
  --wrap: 1240px;
  --pad: clamp(20px, 5vw, 56px);
  --nav-h: 68px;
  --banner-h: 46px;

  /* Motion */
  --ease: cubic-bezier(0.16, 1, 0.3, 1);
  --fast: 180ms;
  --mid: 300ms;
  --slow: 460ms;
}

/* ------------------------------------------------------------- 2. RESET/BASE */
*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scrollbar-color: var(--line-2) var(--ink-0);
}

body {
  margin: 0;
  background: var(--ink-0);
  color: var(--text);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.65;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

body.modal-open { overflow: hidden; }

img, svg, video { display: block; max-width: 100%; }
img, video { height: auto; }

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

button { font: inherit; color: inherit; }

h1, h2, h3, h4 { margin: 0; font-weight: 700; }
p { margin: 0; }

/* Browser surfaces belong to the design system too. */
::selection { background: var(--amber); color: var(--amber-ink); }

:focus-visible {
  outline: 2px solid var(--amber);
  outline-offset: 3px;
  border-radius: 1px;
}

::-webkit-scrollbar { width: 11px; height: 11px; }
::-webkit-scrollbar-track { background: var(--ink-0); }
::-webkit-scrollbar-thumb { background: #2c2c33; border: 3px solid var(--ink-0); }
::-webkit-scrollbar-thumb:hover { background: #3d3d46; }

input, textarea { caret-color: var(--amber); }

/* ---------------------------------------------------------- 3. TYPE PRIMITIVES */
.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--pad);
}

/* Display voice: heavy condensed, uppercase, tight. */
.d1, .d2, .d3 {
  font-family: var(--display);
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: -0.015em;
  line-height: 0.9;
  text-wrap: balance;
}
.d1 { font-size: clamp(44px, 8.4vw, 96px); }
.d2 { font-size: clamp(36px, 5.6vw, 72px); }
.d3 { font-size: clamp(26px, 3.2vw, 42px); letter-spacing: -0.01em; line-height: 0.95; }

/* Long statements stay in the display face but drop the uppercase, which is
   unreadable past about two lines. Short headings keep the caps. */
.d-state {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(25px, 3.1vw, 40px);
  line-height: 1.12;
  letter-spacing: -0.008em;
  text-wrap: pretty;
  max-width: 34ch;
}

/* No section labels exist in this system. Each band opens on its h2, which is
   the largest type in the band; any supporting sentence sits beside or beneath
   it at a smaller size. */

.lede {
  font-size: clamp(16px, 1.4vw, 20px);
  line-height: 1.6;
  color: var(--muted);
  max-width: 62ch;
}

.tnum { font-variant-numeric: tabular-nums; }

/* Band head: the h2 leads at display scale, its supporting sentence sits in the
   second column at reading scale. Stacking on small screens gives heading then
   body, never a label above a heading. */
.bandhead {
  display: grid;
  grid-template-columns: 1fr 1.05fr;
  gap: clamp(22px, 5vw, 72px);
  align-items: end;
}
@media (max-width: 860px) {
  .bandhead { grid-template-columns: 1fr; gap: 20px; align-items: start; }
}

/* --------------------------------------------------------------- 4. BANDS */
.band { padding-block: clamp(72px, 9vw, 132px); position: relative; }
.band--tight { padding-block: clamp(52px, 6vw, 84px); }

.band--paper {
  background: var(--paper);
  color: var(--paper-ink);
}
.band--paper .lede { color: var(--paper-muted); }

/* --------------------------------------------------------------- 5. BUTTONS */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  border: 1px solid transparent;
  border-radius: 0;
  padding: 15px 26px;
  font-family: var(--sans);
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0.02em;
  cursor: pointer;
  transition: background var(--fast) var(--ease), color var(--fast) var(--ease),
              border-color var(--fast) var(--ease), transform var(--fast) var(--ease);
  text-align: center;
}
.btn:active { transform: translateY(1px); }

.btn--amber { background: var(--amber); color: var(--amber-ink); }
.btn--amber:hover { background: var(--amber-hi); }

.btn--ghost { background: transparent; color: var(--text); border-color: var(--line-2); }
.btn--ghost:hover { border-color: var(--text); background: var(--fill); }

.btn--solid { background: var(--text); color: var(--ink-0); }
.btn--solid:hover { background: #fff; }

.band--paper .btn--ghost { color: var(--paper-ink); border-color: var(--paper-line); }
.band--paper .btn--ghost:hover { border-color: var(--paper-ink); background: rgba(0,0,0,0.03); }

/* Small chevron used on primary links */
.btn-chev {
  width: 7px; height: 7px;
  border-right: 2px solid currentColor;
  border-top: 2px solid currentColor;
  transform: rotate(45deg);
  transition: transform var(--fast) var(--ease);
}
.btn:hover .btn-chev { transform: rotate(45deg) translate(2px, -2px); }

/* Text link with an underline that grows from the left. */
.tlink {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-size: 14px;
  font-weight: 600;
  color: var(--amber);
  padding-bottom: 3px;
  background-image: linear-gradient(currentColor, currentColor);
  background-size: 0% 1px;
  background-position: 0 100%;
  background-repeat: no-repeat;
  transition: background-size var(--mid) var(--ease);
}
.tlink:hover { background-size: 100% 1px; }
.band--paper .tlink { color: var(--paper-kick); }

/* --------------------------------------------------------------- 6. BANNER */
.banner {
  position: relative;
  background: var(--amber);
  color: var(--amber-ink);
  min-height: var(--banner-h);
  display: flex;
  align-items: center;
}
.banner[hidden], .banner.is-hidden { display: none; }
.banner__link { position: absolute; inset: 0; z-index: 1; }
.banner__inner {
  position: relative;
  z-index: 2;
  pointer-events: none;
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding: 10px var(--pad);
  display: flex;
  /* Five type sizes sit on this one line. Centring each box put every item on
     its own vertical position; the shared baseline is what makes it read as
     one sentence. */
  align-items: baseline;
  justify-content: space-between;
  gap: 10px 18px;
  flex-wrap: wrap;
}
.banner__left, .banner__right { display: flex; align-items: baseline; gap: 14px; }
.banner__title { font-size: 13px; font-weight: 700; letter-spacing: 0.01em; }
.banner__grant { display: inline-flex; align-items: baseline; gap: 7px; }
.banner__upto { font-size: 11px; text-transform: uppercase; letter-spacing: 0.14em; opacity: 0.72; }
.banner__amount {
  font-family: var(--display);
  font-weight: 800;
  font-size: 21px;
  line-height: 1;
  letter-spacing: 0.01em;
}
.banner__grant-label { font-size: 12px; opacity: 0.8; }
.banner__deadline { font-size: 12px; font-weight: 600; opacity: 0.85; }
.banner__close {
  pointer-events: auto;
  background: none;
  border: 0;
  cursor: pointer;
  width: 28px; height: 28px;
  display: grid; place-items: center;
  color: var(--amber-ink);
  opacity: 0.62;
  transition: opacity var(--fast) var(--ease);
  /* An icon target centres; it has no baseline worth aligning to. */
  align-self: center;
  margin-block: -6px;
}
.banner__close:hover { opacity: 1; }
.banner__x { font-size: 20px; line-height: 1; }

@media (max-width: 720px) {
  .banner__grant-label, .banner__deadline { display: none; }
  .banner__title { font-size: 12px; }
}

/* ------------------------------------------------------------------ 7. NAV */
.nav {
  position: sticky;
  top: 0;
  z-index: 60;
  background: rgba(11, 11, 14, 0.82);
  backdrop-filter: saturate(150%) blur(14px);
  -webkit-backdrop-filter: saturate(150%) blur(14px);
  border-bottom: 1px solid var(--line);
}
.nav__inner {
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--pad);
  height: var(--nav-h);
  display: flex;
  align-items: center;
  gap: 34px;
}
.nav__logo { display: flex; align-items: center; flex: none; }
.nav__logo img {
  height: 26px; width: auto;
  filter: brightness(0) invert(1);
}
.nav__tabs { display: flex; align-items: center; gap: 30px; }
.nav__tab {
  font-size: 14px;
  font-weight: 500;
  color: var(--muted);
  position: relative;
  padding: 6px 0;
  transition: color var(--fast) var(--ease);
}
.nav__tab::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 1px;
  background: var(--amber);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--mid) var(--ease);
}
.nav__tab:hover { color: var(--text); }
.nav__tab:hover::after, .nav__tab[aria-current="page"]::after { transform: scaleX(1); }
.nav__tab[aria-current="page"] { color: var(--text); }

.nav__right { margin-left: auto; display: flex; align-items: center; gap: 14px; }

.nav-btn {
  display: inline-flex;
  align-items: center;
  padding: 11px 20px;
  border-radius: 0;
  font-size: 13px;
  font-weight: 600;
  transition: background var(--fast) var(--ease), color var(--fast) var(--ease);
}
.nav-btn--dark { background: var(--amber); color: var(--amber-ink); }
.nav-btn--dark:hover { background: var(--amber-hi); }

.nav__toggle {
  display: none;
  width: 40px; height: 40px;
  background: none; border: 0;
  cursor: pointer;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  padding: 0 8px;
}
.nav__toggle span {
  display: block; height: 1.5px; width: 100%;
  background: var(--text);
  transition: transform var(--mid) var(--ease), opacity var(--fast) var(--ease);
}
.nav__toggle[aria-expanded="true"] span:nth-child(1) { transform: translateY(6.5px) rotate(45deg); }
.nav__toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.nav__toggle[aria-expanded="true"] span:nth-child(3) { transform: translateY(-6.5px) rotate(-45deg); }

@media (max-width: 880px) {
  .nav__inner { gap: 16px; }
  .nav__toggle { display: flex; }
  .nav__tabs {
    position: absolute;
    top: 100%; left: 0; right: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    background: var(--ink-2);
    border-bottom: 1px solid var(--line);
    padding: 6px var(--pad) 16px;
    transform: translateY(-8px);
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--fast) var(--ease), transform var(--mid) var(--ease);
  }
  /* Two selectors, deliberately. /script.js module 10 owns the burger on every
     route that loads it and puts `is-open` on `.nav`, the PARENT; /creators does
     not load that file and its own toggle puts `is-open` on `.nav__tabs` itself.
     Keying only on the tabs element left the mobile menu dead on all 13 routes
     that load script.js: the burger animated and aria-expanded flipped to true,
     but the panel stayed at opacity 0 with pointer-events none, so no nav link
     could be tapped. Found on live 2026-08-25. Match their contract here rather
     than override their module: `.nav.is-open` is a class name we do not own. */
  .nav__tabs.is-open,
  .nav.is-open .nav__tabs { opacity: 1; transform: none; pointer-events: auto; }
  .nav__tab { padding: 15px 0; border-bottom: 1px solid var(--line); font-size: 16px; }
  .nav__tab::after { display: none; }
}
@media (max-width: 480px) {
  .nav-btn--dark { padding: 10px 14px; font-size: 12px; }
}

/* ----------------------------------------------------------------- 8. HERO */
.hero {
  position: relative;
  background: var(--ink-0);
}
.hero__frame { position: relative; }
.hero__media {
  position: relative;
  /* Short enough that the proof rail below is never clipped at 1440x900. */
  min-height: clamp(468px, 64vh, 640px);
  display: flex;
  align-items: flex-end;
  overflow: hidden;
}
.hero__video {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  z-index: 0;
}
.hero__scrim {
  position: absolute;
  inset: 0;
  z-index: 1;
  /* Light enough that the gameplay clearly ships; the headline gets its
     contrast from a local text shadow rather than from drowning the asset. */
  background:
    linear-gradient(180deg, rgba(11,11,14,0.34) 0%, rgba(11,11,14,0.06) 30%, rgba(11,11,14,0.6) 86%, var(--ink-0) 100%),
    linear-gradient(90deg, rgba(11,11,14,0.55) 0%, rgba(11,11,14,0.26) 46%, rgba(11,11,14,0) 100%);
}
.hero__overlay {
  position: relative;
  z-index: 2;
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding: clamp(52px, 9vh, 96px) var(--pad) clamp(40px, 6vh, 64px);
}
.hero__title {
  font-family: var(--display);
  font-weight: 800;
  text-transform: uppercase;
  font-size: clamp(44px, 8.4vw, 96px);
  line-height: 0.88;
  letter-spacing: -0.015em;
  max-width: 15ch;
  margin: 0;
  color: var(--text);
  text-shadow: 0 3px 12px rgba(6, 6, 8, 0.72);
}
.hero__nowrap { display: inline; }

.hero__sub {
  margin-top: 20px;
  max-width: 40ch;
  font-size: clamp(16px, 1.4vw, 20px);
  line-height: 1.55;
  color: #e8e9ef;
  text-shadow: 0 2px 9px rgba(6, 6, 8, 0.8);
}

/* Rotating word: JS translates the list by --ws-step per index. */
.word-switch {
  display: inline-block;
  vertical-align: baseline;
  color: var(--amber);
  --ws-step: 1em;
}
.word-switch__viewport {
  display: inline-block;
  height: 1em;
  overflow: hidden;
  vertical-align: bottom;
}
/* The list is a vertical stack; script.js translates it by --ws-step per index
   and sizes the viewport to the visible word. Without the column stack every
   word lands on one line and the viewport shows the neighbour's first letter. */
.word-switch__list {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  transition: transform 0.5s var(--ease);
}
.word-switch__item {
  height: 1em;
  line-height: 1em;
  margin-bottom: calc(var(--ws-step) - 1em);
  white-space: nowrap;
}
.hero__title .word-switch,
.hero__title .word-switch__item { color: var(--amber); }

.hero__cta-row {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: clamp(26px, 4vh, 40px);
}
.hero__btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 16px 30px;
  border: 1px solid transparent;
  border-radius: 0;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  transition: background var(--fast) var(--ease), border-color var(--fast) var(--ease),
              color var(--fast) var(--ease), transform var(--fast) var(--ease);
}
.hero__btn:active { transform: translateY(1px); }
.hero__btn--primary { background: var(--amber); color: var(--amber-ink); }
.hero__btn--primary:hover { background: var(--amber-hi); }
.hero__btn--play {
  background: rgba(12, 12, 16, 0.42);
  color: var(--text);
  border-color: rgba(255, 255, 255, 0.42);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
.hero__btn--play:hover { background: rgba(255,255,255,0.15); border-color: #fff; }
/* Marks the button as the control that plays the moment on screen. */
.btn-play-mark {
  width: 15px; height: 15px; flex: none;
  background: var(--amber);
  -webkit-mask: url("/media/brand/Ludeo pentagon logo.svg") center / contain no-repeat;
  mask: url("/media/brand/Ludeo pentagon logo.svg") center / contain no-repeat;
}

/* Proof rail: the three verified numbers, on a hairline under the hero. */
.proof {
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  background: var(--ink-1);
}
.proof__grid {
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--pad);
  display: grid;
  grid-template-columns: repeat(3, 1fr);
}
.proof__cell {
  padding: clamp(22px, 3vw, 34px) clamp(14px, 2.5vw, 34px);
  border-left: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.proof__cell:first-child { border-left: 0; padding-left: 0; }
.proof__cell:last-child { padding-right: 0; }
.proof__n {
  font-family: var(--display);
  font-weight: 800;
  font-size: clamp(32px, 4.4vw, 54px);
  line-height: 0.95;
  letter-spacing: -0.01em;
  color: var(--amber);
  font-variant-numeric: tabular-nums;
}
.proof__n small {
  font-size: 0.44em;
  font-weight: 700;
  color: var(--muted);
  letter-spacing: 0.06em;
  margin-right: 4px;
}
.proof__l { font-size: 13px; color: var(--muted); line-height: 1.4; }

@media (max-width: 720px) {
  .proof__grid { grid-template-columns: 1fr; }
  .proof__cell { border-left: 0; border-top: 1px solid var(--line); padding-inline: 0; }
  .proof__cell:first-child { border-top: 0; }
}

/* ------------------------------------------------------------- 10. LOGO WALL */
.logos {
  background: var(--ink-0);
  padding-block: clamp(46px, 6vw, 72px);
  border-bottom: 1px solid var(--line);
}
.logos__wrap { max-width: var(--wrap); margin-inline: auto; padding-inline: var(--pad); }
.logos__inner { display: flex; flex-direction: column; gap: 30px; }
.logos__title {
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--faint);
  text-align: center;
  max-width: 56ch;
  margin-inline: auto;
  line-height: 1.6;
}
.logos__marquee { position: relative; overflow: hidden; }
.logos__fade {
  position: absolute;
  top: 0; bottom: 0;
  width: clamp(64px, 12vw, 168px);
  z-index: 2;
  pointer-events: none;
}
.logos__fade--left { left: 0; background: linear-gradient(90deg, var(--ink-0), transparent); }
.logos__fade--right { right: 0; background: linear-gradient(270deg, var(--ink-0), transparent); }
.logos__scale { overflow: hidden; }
.logos__track { display: flex; width: max-content; will-change: transform; align-items: center; }
.logos__group { display: flex; align-items: center; }
.logos__item {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 40px;
  padding-inline: clamp(22px, 3.6vw, 50px);
  flex: none;
}
.logos__item img {
  display: block;
  width: auto;
  height: 100%;
  max-width: clamp(104px, 14vw, 158px);
  object-fit: contain;
  /* Light-mode marks flattened to a white silhouette for the dark ground.
     Kept legible rather than decorative: these are the page's social proof. */
  filter: brightness(0) invert(1);
  opacity: 0.94;
  transition: opacity var(--mid) var(--ease);
}
.logos__marquee:hover .logos__item img { opacity: 1; }
/* Red Storm and Relic ship real dark-ground artwork; show it unflattened. */
.logos__group .logo-themed--light { display: none; }
.logos__group .logo-themed--dark { display: block; filter: none; opacity: 0.95; }
.logos__item img.logo-relic { filter: none; opacity: 0.95; }
/* Playtika only ships a light asset, so it stays a silhouette. */
.logos__item img.logo-playtika { filter: brightness(0) invert(1); opacity: 0.94; }

/* ------------------------------------------------------- 11. DEFINITION BAND */
.def__grid {
  display: grid;
  grid-template-columns: 1fr 1.05fr;
  gap: clamp(22px, 5vw, 72px);
  align-items: end;
}
.def__lede {
  font-family: var(--display);
  font-weight: 700;
  text-transform: none;
  font-size: clamp(21px, 2.5vw, 32px);
  line-height: 1.14;
  letter-spacing: -0.008em;
  max-width: 34ch;
  color: var(--paper-ink);
}
.def__lede em { font-style: normal; color: var(--paper-kick); }
.def__sub { margin-top: 22px; max-width: 58ch; color: var(--paper-muted); font-size: 17px; line-height: 1.68; }
.def__rows { margin-top: clamp(34px, 4vw, 52px); border-top: 1px solid var(--paper-line); }
.def__row {
  display: grid;
  grid-template-columns: minmax(120px, 210px) 1fr;
  gap: clamp(14px, 3vw, 44px);
  padding-block: 24px;
  border-bottom: 1px solid var(--paper-line);
  align-items: baseline;
}
.def__k {
  font-family: var(--display);
  font-weight: 700;
  text-transform: uppercase;
  font-size: 21px;
  letter-spacing: 0.01em;
  line-height: 1.1;
  color: var(--paper-ink);
}
.def__v { color: var(--paper-muted); font-size: 16px; line-height: 1.62; max-width: 62ch; }

@media (max-width: 860px) {
  .def__grid { grid-template-columns: 1fr; gap: 20px; align-items: start; }
  .def__row { grid-template-columns: 1fr; gap: 6px; padding-block: 20px; }
}

/* ------------------------------------------------------------ 12. FLOW BAND */
.flow__grid {
  margin-top: clamp(38px, 5vw, 62px);
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  border-top: 1px solid var(--line);
}
.flow__step {
  padding: clamp(26px, 3vw, 40px) clamp(18px, 2.6vw, 36px) clamp(30px, 4vw, 48px);
  border-left: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  position: relative;
  overflow: hidden;
}
.flow__step:first-child { border-left: 0; padding-left: 0; }
.flow__step:last-child { padding-right: 0; }
.flow__step::before {
  content: "";
  position: absolute;
  left: 0; right: 0; top: 0;
  height: 2px;
  background: var(--amber);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--slow) var(--ease);
}
.flow__step:hover::before { transform: scaleX(1); }
.flow__n {
  font-family: var(--display);
  font-weight: 800;
  font-size: 17px;
  letter-spacing: 0.06em;
  color: var(--amber);
  font-variant-numeric: tabular-nums;
  display: block;
  margin-bottom: 16px;
}
.flow__h {
  font-family: var(--display);
  font-weight: 800;
  text-transform: uppercase;
  font-size: clamp(26px, 3.2vw, 42px);
  line-height: 0.95;
  letter-spacing: -0.01em;
  margin-bottom: 12px;
}
.flow__p { color: var(--muted); font-size: 16px; line-height: 1.62; max-width: 38ch; }

@media (max-width: 860px) {
  .flow__grid { grid-template-columns: 1fr; }
  .flow__step { border-left: 0; padding-inline: 0; }
}

/* --------------------------------------------------- 13. LUDEO CARD CAROUSEL */
.tryl { padding-block: clamp(72px, 9vw, 132px); background: var(--ink-0); }
.tryl > .wrap { display: block; }
.tryl__body { margin-top: clamp(38px, 5vw, 60px); }

.ludeo-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: clamp(14px, 1.8vw, 22px);
}
.lcard {
  position: relative;
  display: flex;
  flex-direction: column;
  background: var(--ink-2);
  border: 1px solid var(--line);
  overflow: hidden;
  transition: border-color var(--mid) var(--ease), transform var(--mid) var(--ease);
}
.lcard:hover { border-color: var(--line-2); transform: translateY(-3px); }
.lcard__stage {
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  padding: 0;
  border: 0;
  background: #000;
  cursor: pointer;
  overflow: hidden;
}
.lcard__stage video {
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform var(--slow) var(--ease), filter var(--mid) var(--ease);
}
.lcard:hover .lcard__stage video { transform: scale(1.045); filter: brightness(0.55); }
.lcard__hover {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  opacity: 0;
  transition: opacity var(--mid) var(--ease);
  pointer-events: none;
  padding: 18px;
}
.lcard:hover .lcard__hover { opacity: 1; }
.lcard__hover-logo {
  max-height: 40px;
  max-width: 40%;
  width: auto;
  object-fit: contain;
  filter: brightness(0) invert(1);
}
.lcard__hover-logo--raw { filter: none; }
.lcard__hover-dot {
  width: 4px; height: 4px;
  background: rgba(255,255,255,0.5);
  flex: none;
}
.lcard__play {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  width: 100%;
  padding: 15px 16px;
  background: transparent;
  border: 0;
  border-top: 1px solid var(--line);
  cursor: pointer;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--text);
  transition: background var(--fast) var(--ease), color var(--fast) var(--ease);
}
.lcard__play:hover { background: var(--amber); color: var(--amber-ink); }
.lcard__play-logo {
  width: 14px; height: 14px; flex: none;
  background: var(--amber);
  -webkit-mask: url("/media/brand/Ludeo pentagon logo.svg") center / contain no-repeat;
  mask: url("/media/brand/Ludeo pentagon logo.svg") center / contain no-repeat;
  transition: background var(--fast) var(--ease);
}
.lcard__play:hover .lcard__play-logo { background: var(--amber-ink); }

/* Fullscreen playable overlay (created by script.js) */
.ludeo-overlay {
  position: fixed;
  inset: 0;
  z-index: 200;
  background: rgba(6, 6, 8, 0.94);
  display: flex;
  align-items: center;
  justify-content: center;
}
.ludeo-overlay iframe { width: 100%; height: 100%; border: 0; }

/* --------------------------------------------- 14. SECOND-AUDIENCE CTA LINE */
/* ludeo.com reads as the studio door, so its primary action is a studio signup.
   Creators arrive here too. Their path is named as a line of type under the
   button row, at a weight that answers them without competing with the one
   action the page is built to get. */
.cta-alt {
  margin-top: 16px;
  font-size: 14px;
  line-height: 1.5;
  color: rgba(255, 255, 255, 0.6);
}
.cta-alt a {
  color: var(--text);
  border-bottom: 1px solid rgba(236, 167, 70, 0.55);
  padding-bottom: 1px;
  transition: color var(--fast) var(--ease), border-color var(--fast) var(--ease);
}
.cta-alt a:hover { color: var(--amber); border-bottom-color: var(--amber); }
/* On the amber close the same line inverts: ink on amber, not white on black. */
.endcta .cta-alt { color: rgba(21, 16, 7, 0.66); }
.endcta .cta-alt a { color: var(--amber-ink); border-bottom-color: rgba(21, 16, 7, 0.45); }
.endcta .cta-alt a:hover { color: var(--amber-ink); border-bottom-color: var(--amber-ink); }

/* -------------------------------------------------------------- 15. FAQ */
.faq__grid { margin-top: clamp(30px, 4vw, 48px); border-top: 1px solid var(--paper-line); }
.faq-item { border-bottom: 1px solid var(--paper-line); }
.faq-q {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  padding: 22px 0;
  background: none;
  border: 0;
  cursor: pointer;
  text-align: left;
  font-family: var(--display);
  font-weight: 700;
  text-transform: uppercase;
  font-size: clamp(22px, 2.4vw, 30px);
  line-height: 1.15;
  letter-spacing: 0.005em;
  color: var(--paper-ink);
  transition: color var(--fast) var(--ease);
}
.faq-q:hover { color: var(--paper-kick); }
.faq-chev {
  width: 19px; height: 19px;
  flex: none;
  stroke-width: 2.4;
  transition: transform var(--mid) var(--ease);
  color: var(--paper-muted);
}
.faq-item.is-open .faq-chev { transform: rotate(180deg); color: var(--paper-kick); }
.faq-a-wrap {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--mid) var(--ease);
}
.faq-item.is-open .faq-a-wrap { grid-template-rows: 1fr; }
.faq-a { overflow: hidden; }
.faq-a p {
  padding-bottom: 24px;
  max-width: 72ch;
  color: var(--paper-muted);
  font-size: 16px;
  line-height: 1.68;
}

/* Dark-band FAQ variant (used on dark pages) */
.band:not(.band--paper) .faq__grid { border-top-color: var(--line); }
.band:not(.band--paper) .faq-item { border-bottom-color: var(--line); }
.band:not(.band--paper) .faq-q { color: var(--text); }
.band:not(.band--paper) .faq-q:hover { color: var(--amber); }
.band:not(.band--paper) .faq-chev { color: var(--faint); }
.band:not(.band--paper) .faq-item.is-open .faq-chev { color: var(--amber); }
.band:not(.band--paper) .faq-a p { color: var(--muted); }

/* ------------------------------------------------------------ 16. END CTA */
/* The close is the page's second amber field. Together with the kinetic strip
   it brackets the dark middle, and it gives the closer real material instead of
   two buttons floating on black. */
.endcta {
  background: var(--grad-amber);
  color: var(--amber-ink);
  padding-block: clamp(66px, 9vw, 120px);
  position: relative;
  overflow: hidden;
}
.endcta__mark {
  position: absolute;
  right: -6%;
  bottom: -46%;
  width: min(560px, 46vw);
  aspect-ratio: 1;
  background: var(--amber-ink);
  opacity: 0.085;
  -webkit-mask: url("/media/brand/Ludeo pentagon logo.svg") center / contain no-repeat;
  mask: url("/media/brand/Ludeo pentagon logo.svg") center / contain no-repeat;
  pointer-events: none;
}
.endcta__inner {
  position: relative;
  z-index: 1;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--pad);
}
.endcta__h {
  font-family: var(--display);
  font-weight: 800;
  text-transform: uppercase;
  font-size: clamp(40px, 7vw, 88px);
  line-height: 0.9;
  letter-spacing: -0.015em;
  max-width: 17ch;
}
.endcta__actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: clamp(26px, 3.4vw, 40px); }
.endcta .btn--amber { background: var(--ink-0); color: var(--text); }
.endcta .btn--amber:hover { background: var(--ink-2); }
.endcta .btn--ghost { color: var(--amber-ink); border-color: rgba(21, 16, 7, 0.4); }
.endcta .btn--ghost:hover { border-color: var(--amber-ink); background: rgba(21, 16, 7, 0.07); }

/* -------------------------------------------------------------- 17. FOOTER */
.footer { background: var(--ink-2); border-top: 1px solid var(--line); }
.footer__top {
  max-width: var(--wrap);
  margin-inline: auto;
  padding: clamp(52px, 6vw, 78px) var(--pad) clamp(34px, 4vw, 52px);
  display: grid;
  grid-template-columns: 1.6fr repeat(4, 1fr);
  gap: clamp(26px, 3.4vw, 48px);
}
.footer__brandcol { display: flex; flex-direction: column; align-items: flex-start; gap: 16px; max-width: 34ch; }
.footer__logo { height: 26px; width: auto; align-self: flex-start; filter: brightness(0) invert(1); }
.footer__tagline { font-size: 14px; color: var(--faint); line-height: 1.6; }
.footer__socials { display: flex; gap: 12px; margin-top: 4px; }
.footer__socials a {
  width: 36px; height: 36px;
  display: grid; place-items: center;
  border: 1px solid var(--line);
  transition: border-color var(--fast) var(--ease), background var(--fast) var(--ease);
}
.footer__socials a:hover { border-color: var(--amber); background: var(--fill); }
.footer__socials img { width: 16px; height: 16px; filter: brightness(0) invert(1); opacity: 0.72; }

.footer__col { display: flex; flex-direction: column; gap: 11px; }
.footer__col h3 {
  font-family: var(--sans);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--faint);
  margin-bottom: 5px;
}
.footer__col a {
  font-size: 14px;
  color: var(--muted);
  cursor: pointer;
  transition: color var(--fast) var(--ease);
  width: fit-content;
}
.footer__col a:hover { color: var(--amber); }

/* Oversized wordmark closing the page. */
.footer__brand {
  border-top: 1px solid var(--line);
  padding: clamp(22px, 3vw, 34px) var(--pad) clamp(18px, 2.4vw, 26px);
  max-width: var(--wrap);
  margin-inline: auto;
}
.footer__brand-mark {
  font-family: var(--display);
  font-weight: 800;
  text-transform: uppercase;
  font-size: clamp(78px, 24vw, 340px);
  line-height: 0.8;
  letter-spacing: 0.02em;
  color: transparent;
  -webkit-text-stroke: 1px rgba(255, 255, 255, 0.19);
  display: block;
  text-align: center;
  user-select: none;
}
.footer__legal {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 12px;
  margin-top: clamp(14px, 2vw, 24px);
  font-size: 12px;
  color: var(--faint);
}

@media (max-width: 980px) {
  .footer__top { grid-template-columns: 1fr 1fr; }
  .footer__brandcol { grid-column: 1 / -1; }
}
@media (max-width: 560px) {
  .footer__top { grid-template-columns: 1fr; gap: 30px; }
}

/* -------------------------------------------------------------- 18. MODALS */
.modal {
  position: fixed;
  inset: 0;
  z-index: 120;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(14px, 4vw, 40px);
}
.modal[hidden] { display: none; }
.modal__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(6, 6, 8, 0.78);
  backdrop-filter: blur(5px);
  -webkit-backdrop-filter: blur(5px);
  animation: fade-in var(--fast) var(--ease) both;
}
@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes pop-in {
  from { opacity: 0; transform: translateY(10px) scale(0.985); }
  to { opacity: 1; transform: none; }
}

.gs-popup, .eula-popup, .book-popup, .share-popup {
  position: relative;
  z-index: 1;
  background: var(--ink-2);
  border: 1px solid var(--line-2);
  width: 100%;
  animation: pop-in var(--mid) var(--ease) both;
  max-height: calc(100dvh - 40px);
  display: flex;
  flex-direction: column;
}
.gs-popup { max-width: 440px; }
.eula-popup { max-width: 780px; }
.book-popup { max-width: 900px; height: min(760px, calc(100dvh - 40px)); }
.share-popup { max-width: 420px; }

.gs-box { padding: clamp(26px, 4vw, 38px); overflow-y: auto; }
.gs-title {
  font-family: var(--display);
  font-weight: 800;
  text-transform: uppercase;
  font-size: clamp(22px, 2.4vw, 30px);
  line-height: 1;
  letter-spacing: -0.01em;
}
.gs-eyebrow { margin-top: 8px; font-size: 14px; color: var(--muted); line-height: 1.6; }

.gs-agree { display: flex; gap: 11px; margin-top: 24px; cursor: pointer; align-items: flex-start; }
.gs-agree__check {
  appearance: none;
  -webkit-appearance: none;
  width: 18px; height: 18px;
  flex: none;
  margin-top: 2px;
  border: 1px solid var(--line-2);
  background: transparent;
  cursor: pointer;
  display: grid;
  place-items: center;
  transition: background var(--fast) var(--ease), border-color var(--fast) var(--ease);
}
.gs-agree__check:checked { background: var(--amber); border-color: var(--amber); }
.gs-agree__check:checked::after {
  content: "";
  width: 5px; height: 9px;
  border-right: 2px solid var(--amber-ink);
  border-bottom: 2px solid var(--amber-ink);
  transform: rotate(45deg) translate(-1px, -1px);
}
.gs-agree__text { font-size: 13px; color: var(--muted); line-height: 1.55; }
.gs-eula-link { color: var(--amber); cursor: pointer; text-decoration: underline; text-underline-offset: 3px; }
.gs-agree--nudge { animation: nudge 420ms var(--ease); }
.gs-agree--nudge .gs-agree__check { border-color: var(--bad); }
@keyframes nudge {
  0%, 100% { transform: translateX(0); }
  25% { transform: translateX(-5px); }
  75% { transform: translateX(5px); }
}

.gs-google {
  margin-top: 22px;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 11px;
  padding: 15px 20px;
  background: var(--text);
  color: var(--ink-0);
  border: 0;
  cursor: pointer;
  font-size: 14px;
  font-weight: 600;
  transition: background var(--fast) var(--ease), opacity var(--fast) var(--ease);
}
.gs-google:hover { background: #fff; }
.gs-google[aria-disabled="true"] { opacity: 0.45; }
.gs-google__logo { width: 18px; height: 18px; }

.gs-field { margin-bottom: 12px; }
.gs-input {
  width: 100%;
  padding: 14px 15px;
  background: var(--ink-0);
  border: 1px solid var(--line-2);
  border-radius: 0;
  color: var(--text);
  font-family: var(--sans);
  font-size: 15px;
  transition: border-color var(--fast) var(--ease), background var(--fast) var(--ease);
}
.gs-input::placeholder { color: var(--faint); }
.gs-input:focus { outline: none; border-color: var(--amber); background: #0e0e12; }
.gs-input:disabled { opacity: 0.5; cursor: not-allowed; }
.gs-textarea { resize: vertical; min-height: 118px; line-height: 1.6; }
.gs-error {
  display: block;
  min-height: 18px;
  font-size: 13px;
  color: var(--bad-dark);
  margin-bottom: 6px;
}
.btn-cta {
  width: 100%;
  padding: 15px 22px;
  background: var(--amber);
  color: var(--amber-ink);
  border: 0;
  border-radius: 0;
  font-family: var(--sans);
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  transition: background var(--fast) var(--ease), opacity var(--fast) var(--ease);
}
.btn-cta:hover { background: var(--amber-hi); }
.btn-cta:disabled { opacity: 0.5; cursor: not-allowed; }

.eula-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 24px clamp(22px, 4vw, 34px);
  border-bottom: 1px solid var(--line);
  flex: none;
}
.eula-title {
  font-family: var(--display);
  font-weight: 800;
  text-transform: uppercase;
  font-size: 25px;
  line-height: 1.05;
  letter-spacing: -0.005em;
}
.eula-close {
  width: 36px; height: 36px;
  flex: none;
  display: grid; place-items: center;
  background: none;
  border: 1px solid var(--line);
  color: var(--muted);
  cursor: pointer;
  font-size: 16px;
  line-height: 1;
  transition: border-color var(--fast) var(--ease), color var(--fast) var(--ease);
}
.eula-close:hover { border-color: var(--text); color: var(--text); }
.eula-body {
  padding: clamp(20px, 3.4vw, 32px);
  overflow-y: auto;
  font-size: 14px;
  line-height: 1.72;
  color: var(--muted);
}
.eula-body h3 {
  font-family: var(--display);
  font-weight: 800;
  text-transform: uppercase;
  font-size: 21px;
  color: var(--text);
  margin: 26px 0 10px;
  letter-spacing: 0.005em;
}
.eula-body h3:first-child { margin-top: 0; }
.eula-body h4 {
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
  margin: 20px 0 7px;
}
.eula-body p { margin-bottom: 12px; }
.eula-body ul, .eula-body ol { margin: 0 0 14px; padding-left: 20px; }
.eula-body li { margin-bottom: 6px; }
.eula-body a { color: var(--amber); text-decoration: underline; text-underline-offset: 3px; }
.eula-body strong { color: var(--text); }

.brush-frame { display: none; }

.contact-popup, .share-popup, .book-popup { position: relative; }
.contact-popup__close, .share-popup__close, .book-popup__close {
  position: absolute;
  top: 12px; right: 12px;
  z-index: 3;
}
.book-iframe { flex: 1; width: 100%; border: 0; background: #fff; }
.book-fallback {
  display: block;
  padding: 13px 18px;
  border-top: 1px solid var(--line);
  font-size: 13px;
  color: var(--amber);
  text-align: center;
  flex: none;
}

.share-popup { padding: clamp(26px, 4vw, 34px); }
.share-popup__title {
  font-family: var(--display);
  font-weight: 800;
  text-transform: uppercase;
  font-size: 25px;
  margin-bottom: 20px;
  letter-spacing: -0.005em;
}
.share-socials { display: flex; gap: 10px; margin-bottom: 18px; flex-wrap: wrap; }
.share-social {
  width: 44px; height: 44px;
  display: grid; place-items: center;
  border: 1px solid var(--line-2);
  color: var(--muted);
  transition: border-color var(--fast) var(--ease), color var(--fast) var(--ease), background var(--fast) var(--ease);
  cursor: pointer;
}
.share-social:hover { border-color: var(--amber); color: var(--amber); background: var(--fill); }
.share-social svg { width: 18px; height: 18px; }
.share-link { display: flex; border: 1px solid var(--line-2); }
.share-link__input {
  flex: 1;
  min-width: 0;
  padding: 12px 14px;
  background: var(--ink-0);
  border: 0;
  color: var(--muted);
  font-family: var(--sans);
  font-size: 13px;
}
.share-link__input:focus { outline: none; }
.share-link__copy {
  padding: 12px 18px;
  background: var(--amber);
  color: var(--amber-ink);
  border: 0;
  cursor: pointer;
  font-size: 13px;
  font-weight: 600;
  flex: none;
}
.share-link__copy:hover { background: var(--amber-hi); }

/* Thank-you modal built by script.js */
.ty-popup {
  position: relative;
  z-index: 1;
  background: var(--ink-2);
  border: 1px solid var(--line-2);
  padding: clamp(30px, 4vw, 44px);
  max-width: 440px;
  width: 100%;
  text-align: center;
  animation: pop-in var(--mid) var(--ease) both;
}

/* ------------------------------------------------------ 19. REVEAL MOTION */
/* One authored moment: bands rise into place once, from a visible default. */
@media (prefers-reduced-motion: no-preference) {
  .reveal {
    opacity: 0;
    transform: translateY(18px);
    transition: opacity var(--slow) var(--ease), transform var(--slow) var(--ease);
  }
  .reveal.is-in { opacity: 1; transform: none; }
  .reveal--d1 { transition-delay: 70ms; }
  .reveal--d2 { transition-delay: 140ms; }
  .reveal--d3 { transition-delay: 210ms; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  .reveal { opacity: 1; transform: none; }
}

/* --------------------------------------------------------------- 20. UTIL */
.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}
.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 200;
  background: var(--amber);
  color: var(--amber-ink);
  padding: 12px 20px;
  font-size: 14px;
  font-weight: 600;
}
.skip-link:focus { left: 0; }

/* ==========================================================================
   21. INTERIOR PAGES
   News, blog, careers, legal and the creators stub. Class names match the
   production markup so those content blocks are spliced in verbatim rather
   than retyped, which keeps every link, date and asset path intact.
   ========================================================================== */

/* Page header. The h1 is the largest type on the page; there is no label
   above it, here or anywhere else in this system. */
.phead {
  border-bottom: 1px solid var(--line);
  background: var(--ink-1);
  padding-block: clamp(52px, 8vw, 104px);
  position: relative;
  overflow: hidden;
}
/* Every interior route opens on the mark, so the brand is carried by form
   rather than by repeating the logo. */
.phead::before {
  content: "";
  position: absolute;
  right: -7%;
  top: -40%;
  width: min(520px, 46vw);
  aspect-ratio: 1;
  background: var(--amber);
  opacity: 0.05;
  -webkit-mask: var(--mark) center / contain no-repeat;
  mask: var(--mark) center / contain no-repeat;
  pointer-events: none;
}
.phead__inner { position: relative; z-index: 1; max-width: var(--wrap); margin-inline: auto; padding-inline: var(--pad); }
.phead__title {
  font-family: var(--display);
  font-weight: 800;
  text-transform: uppercase;
  font-size: clamp(40px, 7vw, 88px);
  line-height: 0.9;
  letter-spacing: -0.015em;
  max-width: 18ch;
}
.phead__tagline {
  margin-top: 20px;
  max-width: 62ch;
  font-size: clamp(16px, 1.4vw, 20px);
  line-height: 1.6;
  color: var(--muted);
}

.news-wrap {
  max-width: var(--wrap);
  margin-inline: auto;
  padding: clamp(52px, 7vw, 96px) var(--pad) clamp(64px, 9vw, 120px);
}

/* Featured item: asymmetric, media left, text right. */
.news-featured {
  display: grid;
  grid-template-columns: 1.15fr 1fr;
  gap: clamp(20px, 3vw, 44px);
  align-items: center;
  border: 1px solid var(--line);
  padding: clamp(18px, 2.2vw, 26px);
  margin-bottom: clamp(34px, 4vw, 56px);
  transition: border-color var(--mid) var(--ease), background var(--mid) var(--ease);
}
.news-featured:hover { border-color: var(--line-2); background: var(--fill); }
.news-featured__media { overflow: hidden; aspect-ratio: 16 / 9; background: var(--ink-2); }
.news-featured__title {
  font-family: var(--display);
  font-weight: 800;
  text-transform: uppercase;
  font-size: clamp(26px, 3.2vw, 42px);
  line-height: 0.98;
  letter-spacing: -0.01em;
  margin: 12px 0;
}
.news-featured__excerpt { color: var(--muted); font-size: 16px; line-height: 1.62; max-width: 54ch; }
/* Labels above headings are not part of this system. */
.news-featured__kicker, .news-hero__eyebrow, .blog-soon__eyebrow { display: none; }

.news-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(290px, 1fr));
  gap: clamp(16px, 2vw, 26px);
}
.news-card {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--line);
  transition: border-color var(--mid) var(--ease), transform var(--mid) var(--ease), background var(--mid) var(--ease);
}
.news-card:hover { border-color: var(--line-2); background: var(--fill); transform: translateY(-3px); }
.news-card__media { aspect-ratio: 16 / 9; overflow: hidden; background: var(--ink-2); border-bottom: 1px solid var(--line); }
.news-img { width: 100%; height: 100%; object-fit: cover; }
.news-card__media--brand { display: grid; place-items: center; }
.news-brand { display: grid; place-items: center; }
.news-brandmark { width: 46px; height: 46px; opacity: 0.45; filter: brightness(0) invert(1); }
.news-card__body { padding: clamp(18px, 2vw, 24px); display: flex; flex-direction: column; gap: 10px; flex: 1; }
.news-card__title {
  font-family: var(--display);
  font-weight: 700;
  text-transform: uppercase;
  font-size: 21px;
  line-height: 1.06;
}
.news-card__excerpt { color: var(--muted); font-size: 15px; line-height: 1.6; flex: 1; }

.news-meta {
  display: flex;
  align-items: center;
  gap: 9px;
  font-size: 12px;
  color: var(--faint);
  letter-spacing: 0.02em;
}
.news-tag { color: var(--amber); font-weight: 600; }
.news-dot { width: 3px; height: 3px; background: currentColor; flex: none; }
.news-readmore { font-size: 13px; font-weight: 600; color: var(--amber); margin-top: 2px; }

@media (max-width: 780px) {
  .news-featured { grid-template-columns: 1fr; }
}

/* Blog empty state */
.blog-soon {
  border: 1px solid var(--line);
  padding: clamp(44px, 7vw, 96px) clamp(24px, 4vw, 56px);
  text-align: center;
}
.blog-soon__title {
  font-family: var(--display);
  font-weight: 800;
  text-transform: uppercase;
  font-size: clamp(26px, 4vw, 48px);
  line-height: 0.96;
  letter-spacing: -0.01em;
}
.blog-soon__text { margin-top: 14px; color: var(--muted); max-width: 52ch; margin-inline: auto; }
.blog-soon__actions { margin-top: 26px; display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; }

/* Careers */
.crs-photos { max-width: var(--wrap); margin-inline: auto; padding: clamp(40px, 5vw, 68px) var(--pad) 0; }
.crs-photos__grid {
  display: grid;
  grid-template-columns: 1.3fr 1fr 1fr;
  gap: clamp(12px, 1.6vw, 20px);
}
/* One row height across all three so the strip reads as a single band. */
.crs-photo { overflow: hidden; height: clamp(190px, 24vw, 320px); border: 1px solid var(--line); }
.crs-photo img { width: 100%; height: 100%; object-fit: cover; }
@media (max-width: 780px) {
  .crs-photos__grid { grid-template-columns: 1fr 1fr; }
  .crs-photo:first-child { grid-column: 1 / -1; }
}

.crs-roles { max-width: var(--wrap); margin-inline: auto; padding: clamp(52px, 7vw, 96px) var(--pad) clamp(64px, 9vw, 120px); }
.crs-offices { color: var(--faint); font-size: 15px; margin-bottom: 30px; }
.crs-roles__card, .crs-open { border: 1px solid var(--line); padding: clamp(24px, 3.4vw, 44px); }
.crs-open { margin-top: clamp(20px, 2.6vw, 32px); }
.crs-roles__title, .crs-open__title {
  font-family: var(--display);
  font-weight: 800;
  text-transform: uppercase;
  font-size: clamp(26px, 3.2vw, 42px);
  line-height: 0.96;
  letter-spacing: -0.01em;
  margin-bottom: 20px;
}
.crs-open__title { margin-bottom: 10px; }
.crs-open__text { color: var(--muted); max-width: 52ch; margin-bottom: 22px; }
.crs-open__btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 15px 26px;
  background: var(--amber);
  color: var(--amber-ink);
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  transition: background var(--fast) var(--ease);
}
.crs-open__btn:hover { background: var(--amber-hi); }

/* Legacy decorative frame from the old visual world; this system uses hairlines. */
.brush-frame { display: none; }
.crs-roles__status { color: var(--muted); font-size: 15px; }
.crs-roles__status a { color: var(--amber); text-decoration: underline; text-underline-offset: 3px; }

/* Comeet renders these groups and rows into #crsRoles at runtime. The class
   names below are its output, not ours, so they must not be renamed. */
.crs-group { border-top: 1px solid var(--line); padding-top: 22px; margin-top: 30px; }
.crs-group:first-child { border-top: 0; margin-top: 0; padding-top: 0; }
.crs-group__name {
  font-family: var(--display);
  font-weight: 700;
  text-transform: uppercase;
  font-size: 15px;
  letter-spacing: 0.14em;
  color: var(--amber);
  margin-bottom: 6px;
}
.crs-role {
  display: grid;
  grid-template-columns: 1fr auto auto;
  align-items: baseline;
  column-gap: clamp(14px, 2.4vw, 30px);
  row-gap: 4px;
  padding: 18px 0;
  border-bottom: 1px solid var(--line);
  transition: color var(--fast) var(--ease), transform var(--mid) var(--ease);
}
.crs-role:hover { color: var(--amber); transform: translateX(8px); }
.crs-role__title { font-size: 17px; font-weight: 500; min-width: 0; }
/* The department already labels the group above, so the per-row copy is noise. */
.crs-role__dept { display: none; }
.crs-role__loc { font-size: 13px; color: var(--faint); white-space: nowrap; }
.crs-role:hover .crs-role__loc { color: inherit; }
.crs-role__apply {
  font-size: 13px;
  font-weight: 600;
  color: var(--amber);
  white-space: nowrap;
}
@media (max-width: 560px) {
  .crs-role { grid-template-columns: 1fr auto; }
  .crs-role__title { grid-column: 1 / -1; }
}

/* Legal documents. Long-form reading on the warm paper band. */
.legal { background: var(--paper); color: var(--paper-ink); }
.legal .news-wrap { max-width: 900px; }
.eula-body.legal-doc {
  padding: 0;
  overflow: visible;
  font-size: 16px;
  line-height: 1.75;
  color: var(--paper-muted);
}
.eula-body.legal-doc h3 {
  font-family: var(--display);
  font-weight: 800;
  text-transform: uppercase;
  font-size: clamp(22px, 2.4vw, 30px);
  line-height: 1.02;
  color: var(--paper-ink);
  margin: 44px 0 14px;
  padding-top: 16px;
  border-top: 1px solid var(--paper-line);
}
.eula-body.legal-doc h3:first-child { margin-top: 0; border-top: 0; padding-top: 0; }
.eula-body.legal-doc h4 { font-size: 16px; font-weight: 600; color: var(--paper-ink); margin: 26px 0 8px; }
.eula-body.legal-doc p { margin-bottom: 14px; max-width: 74ch; }
.eula-body.legal-doc ul, .eula-body.legal-doc ol { margin: 0 0 16px; padding-left: 22px; max-width: 74ch; }
.eula-body.legal-doc li { margin-bottom: 8px; }
.eula-body.legal-doc a { color: var(--paper-kick); text-decoration: underline; text-underline-offset: 3px; }
.eula-body.legal-doc strong { color: var(--paper-ink); }

/* --------------------------------------------------- for-studios hero ----- */
.shero { border-bottom: 1px solid var(--line); background: var(--ink-1); position: relative; overflow: hidden; }
/* An oversized Ludeo mark bleeding off the top-right corner, so the brand is
   present in the first viewport as form rather than as another logo. */
.shero::before {
  content: "";
  position: absolute;
  right: -9%;
  top: -34%;
  width: min(620px, 52vw);
  aspect-ratio: 1;
  background: var(--amber);
  opacity: 0.045;
  -webkit-mask: var(--mark) center / contain no-repeat;
  mask: var(--mark) center / contain no-repeat;
  pointer-events: none;
}
.shero__inner { position: relative; z-index: 1; max-width: var(--wrap); margin-inline: auto; padding: clamp(48px, 7vw, 92px) var(--pad) clamp(52px, 7vw, 92px); }
/* Both columns start on the same line. Centring floated the player against the
   copy stack, so nothing in the hero aligned to anything. */
.shero__grid { display: grid; grid-template-columns: 1fr 0.94fr; gap: clamp(30px, 5vw, 72px); align-items: start; }
.shero__title {
  font-family: var(--display);
  font-weight: 800;
  text-transform: uppercase;
  font-size: clamp(40px, 7vw, 88px);
  line-height: 0.9;
  letter-spacing: -0.015em;
  max-width: 16ch;
}
.shero__sub { margin-top: 20px; max-width: 46ch; color: var(--muted); font-size: clamp(16px, 1.4vw, 20px); line-height: 1.6; }
/* A fixed three-column rack. As a wrapping flex row the third stat dropped to
   its own line and read as a mistake; the hairline ties the rack to the column. */
.shero__stats {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(16px, 2.2vw, 30px);
  margin-top: clamp(28px, 3.6vw, 40px);
  padding-top: clamp(20px, 2.6vw, 28px);
  border-top: 1px solid var(--line);
}
.sstat { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
@media (max-width: 620px) {
  .shero__stats { grid-template-columns: 1fr; gap: 0; }
  .sstat { padding-block: 15px; border-top: 1px solid var(--line); }
  .sstat:first-child { border-top: 0; padding-top: 0; }
}
/* The figure owns the numeral size so the unit suffix can scale from it. */
.sstat__fig { display: flex; align-items: baseline; gap: 5px; font-size: clamp(32px, 4.4vw, 54px); }
.sstat__fig--col { flex-direction: row; }
.sstat__pre { font-size: 13px; font-weight: 600; color: var(--muted); letter-spacing: 0.06em; text-transform: uppercase; }
.sstat__num, .sstat__unit {
  font-family: var(--display);
  font-weight: 800;
  font-size: 1em;
  line-height: 0.95;
  color: var(--amber);
  font-variant-numeric: tabular-nums;
}
.sstat__unit { font-size: 0.62em; }
.sstat__cap { font-size: 13px; color: var(--muted); line-height: 1.4; text-wrap: pretty; }

/* The media column is shorter than the copy column, so its closing proof is
   pinned to the bottom and lands on the same line as the primary CTA. */
/* Stretch keeps the top edge on the row line while giving the column the height
   its bottom-pinned proof needs to reach the CTA. */
.shero__right { display: flex; flex-direction: column; gap: 14px; align-self: stretch; }
.shero__ticks { margin-top: auto; padding-top: clamp(18px, 2.4vw, 28px); border-top: 1px solid var(--line); display: flex; flex-direction: column; }
.shero__tick { display: flex; align-items: baseline; gap: 12px; padding: 10px 0; font-size: 15px; color: var(--muted); border-bottom: 1px solid var(--line); }
.shero__tick:last-child { border-bottom: 0; }
.shero__tick b { color: var(--text); font-weight: 600; flex: none; }
@media (max-width: 900px) { .shero__ticks { margin-top: 0; } }
.shero__cta-row { margin-top: clamp(26px, 3.4vw, 38px); display: flex; gap: 12px; flex-wrap: wrap; }
.shero__btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  padding: 16px 30px; background: var(--amber); color: var(--amber-ink);
  font-size: 14px; font-weight: 600; transition: background var(--fast) var(--ease);
}
.shero__btn:hover { background: var(--amber-hi); }
@media (max-width: 900px) { .shero__grid { grid-template-columns: 1fr; } }

/* The moment card: a real Ludeo, playing, beside the pitch. */
.splayer { border: 1px solid var(--line); background: var(--ink-2); }
.splayer__head { display: flex; align-items: center; gap: 12px; padding: 15px 16px; border-bottom: 1px solid var(--line); }
.splayer__avatar { width: 38px; height: 38px; object-fit: cover; flex: none; border-radius: 50%; }
.splayer__meta { min-width: 0; }
.splayer__title { font-size: 15px; font-weight: 600; line-height: 1.3; }
.splayer__byline { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; font-size: 12px; color: var(--faint); margin-top: 3px; }
/* Narrow cards break the byline mid-phrase, so it stacks instead of wrapping. */
@media (max-width: 560px) {
  .splayer__byline { flex-direction: column; align-items: flex-start; gap: 2px; }
  .splayer__dot { display: none; }
}
.splayer__dot { width: 3px; height: 3px; background: currentColor; flex: none; }
.splayer__video { aspect-ratio: 16 / 9; background: #000; overflow: hidden; }
.splayer__video video { width: 100%; height: 100%; object-fit: cover; }
.splayer__actions { display: flex; border-top: 1px solid var(--line); }
.splayer__play, .splayer__share {
  flex: 1; display: inline-flex; align-items: center; justify-content: center; gap: 9px;
  padding: 15px 14px; background: none; border: 0; cursor: pointer;
  font-family: var(--sans); font-size: 13px; font-weight: 600; color: var(--text);
  transition: background var(--fast) var(--ease), color var(--fast) var(--ease);
}
.splayer__share { border-left: 1px solid var(--line); flex: 0 0 auto; padding-inline: 22px; color: var(--muted); }
.splayer__play:hover { background: var(--amber); color: var(--amber-ink); }
.splayer__share:hover { color: var(--text); background: var(--fill); }
.splayer__play-logo {
  width: 14px; height: 14px; flex: none; background: var(--amber);
  -webkit-mask: url("/media/brand/Ludeo pentagon logo.svg") center / contain no-repeat;
  mask: url("/media/brand/Ludeo pentagon logo.svg") center / contain no-repeat;
  transition: background var(--fast) var(--ease);
}
.splayer__play:hover .splayer__play-logo { background: var(--amber-ink); }
.splayer__share-icon {
  width: 13px; height: 13px; flex: none; background: currentColor;
  -webkit-mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><circle cx='18' cy='5' r='3'/><circle cx='6' cy='12' r='3'/><circle cx='18' cy='19' r='3'/><line x1='8.6' y1='10.5' x2='15.4' y2='6.5'/><line x1='8.6' y1='13.5' x2='15.4' y2='17.5'/></svg>") center / contain no-repeat;
  mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><circle cx='18' cy='5' r='3'/><circle cx='6' cy='12' r='3'/><circle cx='18' cy='19' r='3'/><line x1='8.6' y1='10.5' x2='15.4' y2='6.5'/><line x1='8.6' y1='13.5' x2='15.4' y2='17.5'/></svg>") center / contain no-repeat;
}

/* Six integration steps: two rows of the same hairline grid the homepage uses. */
.steps { margin-top: clamp(38px, 5vw, 62px); display: grid; grid-template-columns: repeat(3, 1fr); border-top: 1px solid var(--line); }
.step {
  padding: clamp(24px, 2.8vw, 36px) clamp(18px, 2.4vw, 32px) clamp(28px, 3.4vw, 42px);
  border-left: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  display: flex; flex-direction: column; gap: 10px;
}
.step:nth-child(3n + 1) { border-left: 0; padding-left: 0; }
.step:nth-child(3n) { padding-right: 0; }
.step__head { display: flex; align-items: center; gap: 12px; }
.step__num {
  font-family: var(--display); font-weight: 800; font-size: 15px;
  letter-spacing: 0.1em; color: var(--amber); font-variant-numeric: tabular-nums;
}
.step__hr { flex: 1; height: 1px; background: var(--line); }
.step__tag { font-size: 12px; color: var(--faint); letter-spacing: 0.04em; white-space: nowrap; }
.step__title {
  font-family: var(--display); font-weight: 800; text-transform: uppercase;
  font-size: clamp(22px, 2.4vw, 30px); line-height: 0.98; letter-spacing: -0.005em;
}
.step__text { color: var(--muted); font-size: 15px; line-height: 1.6; flex: 1; }
.step__foot { margin-top: 6px; }
.step__btn { font-size: 13px; font-weight: 600; color: var(--amber); display: inline-flex; align-items: center; gap: 8px; }
.step__btn:hover { text-decoration: underline; text-underline-offset: 3px; }
@media (max-width: 900px) { .steps { grid-template-columns: 1fr 1fr; } .step:nth-child(3n+1) { border-left: 1px solid var(--line); padding-left: clamp(18px, 2.4vw, 32px); } .step:nth-child(odd) { border-left: 0; padding-left: 0; } }
@media (max-width: 620px) { .steps { grid-template-columns: 1fr; } .step { border-left: 0; padding-inline: 0; } }

/* Developer-friendly rows: the definition-row component on the dark ground. */
.dfrows { margin-top: clamp(34px, 4vw, 52px); border-top: 1px solid var(--line); }
.dfrow {
  display: grid; grid-template-columns: minmax(140px, 230px) 1fr;
  gap: clamp(14px, 3vw, 44px); padding-block: 26px;
  border-bottom: 1px solid var(--line); align-items: baseline;
}
.dfrow h3 {
  font-family: var(--display); font-weight: 700; text-transform: uppercase;
  font-size: 22px; line-height: 1.06; letter-spacing: 0.005em;
}
.dfrow p { color: var(--muted); font-size: 16px; line-height: 1.62; max-width: 64ch; }
.dfrow a { color: var(--amber); font-size: 14px; font-weight: 600; display: inline-block; margin-top: 8px; }
.dfrow a:hover { text-decoration: underline; text-underline-offset: 3px; }
@media (max-width: 860px) { .dfrow { grid-template-columns: 1fr; gap: 6px; } }

/* =========================================================================
   22. LANDING PAGES (studios + creators)
   ========================================================================= */

/* Two paths: the product's whole argument in one glance. Three steps to play
   against six to maybe-play. Step count is the message, so nothing decorative
   competes with it. */
.paths { margin-top: clamp(34px, 4.4vw, 56px); display: grid; grid-template-columns: 1fr 1fr; gap: clamp(20px, 3vw, 44px); }
.path { border-top: 2px solid var(--line-2); padding-top: 20px; }
.path--win { border-top-color: var(--amber); }
.path__head {
  font-family: var(--display); font-weight: 800; text-transform: uppercase;
  font-size: 21px; line-height: 1.06; margin-bottom: 16px;
}
.path--win .path__head { color: var(--amber); }
.path__chain { display: flex; flex-direction: column; gap: 0; }
.path__node {
  display: flex; align-items: center; gap: 12px;
  padding: 11px 0; font-size: 15px; line-height: 1.4;
}
/* The Ludeo pentagon is this system's dot, so the winning path is literally
   marked in the brand and the store path is not. */
.path__dot {
  width: 12px; height: 12px; flex: none; background: var(--faint);
  -webkit-mask: var(--mark) center / contain no-repeat;
  mask: var(--mark) center / contain no-repeat;
}
.path--win .path__dot { background: var(--amber); }
.path__rule { width: 1px; height: 12px; margin-left: 4px; background: var(--line-2); }
.path--lose .path__node { color: var(--muted); }
.path__end { font-family: var(--display); font-weight: 800; text-transform: uppercase; font-size: 17px; letter-spacing: 0.04em; padding-top: 12px; }
.path--win .path__end { color: var(--amber); }
.path--lose .path__end { color: var(--faint); }
.paths__punch { margin-top: clamp(24px, 3vw, 36px); font-size: 17px; color: var(--muted); max-width: 60ch; }
.band--paper .path { border-top-color: var(--paper-line); }
.band--paper .path--win { border-top-color: var(--paper-kick); }
.band--paper .path--win .path__head, .band--paper .path--win .path__end { color: var(--paper-kick); }
.band--paper .path--win .path__dot { background: var(--paper-kick); }
.band--paper .path__dot { background: var(--paper-faint); }
.band--paper .path--lose .path__node, .band--paper .paths__punch { color: var(--paper-muted); }
.band--paper .path--lose .path__end { color: var(--paper-faint); }
@media (max-width: 720px) { .paths { grid-template-columns: 1fr; } }

/* The sponsor DM thread: the objection in the sponsor's own words. */
.dm { border: 1px solid var(--line); background: var(--ink-2); padding: clamp(18px, 2.4vw, 28px); max-width: 46ch; }
.dm__head { display: flex; align-items: center; gap: 10px; padding-bottom: 14px; border-bottom: 1px solid var(--line); margin-bottom: 16px; }
.dm__who { font-size: 13px; font-weight: 600; }
.dm__meta { font-size: 12px; color: var(--faint); }
/* Bubbles size to their own text, so the creator's short reply reads as the
   weak answer it is next to the sponsor's question. */
.dm__msg { width: fit-content; max-width: 28ch; padding: 11px 14px; margin-bottom: 10px; font-size: 15px; line-height: 1.45; background: var(--fill-2); border: 1px solid var(--line); }
.dm__msg--you { margin-left: auto; background: rgba(236, 167, 70, 0.12); border-color: rgba(236, 167, 70, 0.3); }
.dm__msg--sting { border-color: var(--amber); color: var(--text); }

/* The creator's own surfaces, rendered as the real thing. */
.surfaces { margin-top: clamp(34px, 4.4vw, 56px); display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(16px, 2vw, 24px); }
.surf { border: 1px solid var(--line); background: var(--ink-2); display: flex; flex-direction: column; }
.surf__bar { padding: 10px 14px; border-bottom: 1px solid var(--line); font-size: 11px; letter-spacing: 0.16em; text-transform: uppercase; color: var(--faint); }
.surf__body { padding: 16px; display: flex; flex-direction: column; gap: 9px; font-size: 14px; line-height: 1.5; flex: 1; }
.surf__who { display: flex; align-items: center; gap: 9px; }
.surf__av { width: 26px; height: 26px; flex: none; background: var(--fill-2); border: 1px solid var(--line-2); }
.surf__name { font-size: 13px; font-weight: 600; }
.surf__sub { font-size: 12px; color: var(--faint); }
.surf__text { color: var(--muted); }
.surf__link { color: var(--amber); word-break: break-all; font-size: 13px; }
@media (max-width: 780px) { .surfaces { grid-template-columns: 1fr; } }

/* The stream chat is the one surface that is not a still. A fixed body height
   plus overflow:hidden means an appended line is clipped out of the top instead
   of resizing the hero beside it, and only opacity and transform animate, never
   a layout property. */
.surf--chat .surf__text b { color: var(--text); }
.surf__body--live {
  flex: none; height: 186px; justify-content: flex-end; overflow: hidden;
  /* the oldest line leaves through the top edge, so it fades out rather than
     being cut mid-glyph, which reads as a clipping bug instead of as scroll */
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 30px);
  mask-image: linear-gradient(to bottom, transparent 0, #000 30px);
}
/* The column, not the row, is what moves. A new line is appended, the whole
   stack is offset down by exactly its height so nothing appears to have moved,
   then released to 0 — so chat glides up and the new line rises in from under
   the bottom edge, instead of every line jumping a row at a time. Bottom
   anchored, so trimming lines off the top never disturbs the visible region. */
.surf__stream { flex: none; display: flex; flex-direction: column; gap: 9px; will-change: transform; }
.surf__stream > * { animation: surf-msg 200ms var(--ease) both; }
@keyframes surf-msg { from { opacity: 0; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .surf__stream { transform: none !important; transition: none !important; }
  .surf__stream > * { animation: none; }
}

/* Quest brief: what a paid campaign actually looks like. No invented figures. */
.quest { border: 1px solid var(--line-2); background: var(--ink-2); padding: clamp(20px, 2.6vw, 30px); }
.quest__head { display: flex; align-items: baseline; justify-content: space-between; gap: 14px; padding-bottom: 14px; border-bottom: 1px solid var(--line); }
.quest__title { font-family: var(--display); font-weight: 800; text-transform: uppercase; font-size: 21px; }
.quest__flag { font-size: 12px; color: var(--amber); font-weight: 600; white-space: nowrap; }
.quest__body { padding-top: 16px; font-size: 15px; color: var(--muted); line-height: 1.6; }
.quest__facts { display: flex; flex-wrap: wrap; gap: 10px 22px; margin-top: 16px; }
.quest__fact { font-size: 13px; color: var(--text); display: flex; align-items: center; gap: 8px; }
.quest__fact::before {
  content: ""; width: 11px; height: 11px; background: var(--amber); flex: none;
  -webkit-mask: var(--mark) center / contain no-repeat;
  mask: var(--mark) center / contain no-repeat;
}
.quest__toast { margin-top: 16px; display: flex; align-items: center; gap: 11px; padding: 13px 15px; border: 1px solid var(--amber); background: rgba(236, 167, 70, 0.1); font-size: 14px; }
.quest__tick { width: 20px; height: 20px; flex: none; display: grid; place-items: center; background: var(--amber); color: var(--amber-ink); }
.quest__tick svg { width: 12px; height: 12px; }

/* Deadline: the one honest piece of urgency on the page. */
.deadline { border: 1px solid var(--amber); background: rgba(236, 167, 70, 0.07); padding: clamp(20px, 2.6vw, 30px); display: flex; flex-wrap: wrap; align-items: center; gap: clamp(16px, 3vw, 34px); }
.deadline__count { font-family: var(--display); font-weight: 800; font-size: clamp(32px, 4.4vw, 54px); line-height: 0.95; color: var(--amber); font-variant-numeric: tabular-nums; }
.deadline__text { font-size: 16px; color: var(--muted); line-height: 1.55; max-width: 52ch; flex: 1 1 26ch; }
.deadline__text b { color: var(--text); font-weight: 600; }

/* Anchor menu with scrollspy */
.anchors { display: flex; gap: 26px; margin-left: 34px; }
.anchors a { font-size: 13px; color: var(--muted); padding: 6px 0; position: relative; transition: color var(--fast) var(--ease); }
.anchors a::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 1px; background: var(--amber); transform: scaleX(0); transform-origin: left; transition: transform var(--mid) var(--ease); }
.anchors a:hover { color: var(--text); }
.anchors a.is-active { color: var(--text); }
.anchors a.is-active::after, .anchors a:hover::after { transform: scaleX(1); }
@media (max-width: 1100px) { .anchors { display: none; } }

/* ------------------------------------------------- landing: application ---- */
.apply { border: 1px solid var(--line-2); background: var(--ink-2); padding: clamp(24px, 3.4vw, 40px); }
.apply__title {
  font-family: var(--display); font-weight: 800; text-transform: uppercase;
  font-size: clamp(22px, 2.4vw, 30px); line-height: 1.02; letter-spacing: -0.005em;
}
.apply__title em { font-style: normal; color: var(--amber); }
.apply__note { margin-top: 10px; font-size: 13px; color: var(--faint); }
.apply__form { margin-top: 22px; display: flex; flex-direction: column; gap: 10px; }
.apply__form input {
  width: 100%; padding: 14px 15px;
  background: var(--ink-0); border: 1px solid var(--line-2); border-radius: 0;
  color: var(--text); font-family: var(--sans); font-size: 15px;
  transition: border-color var(--fast) var(--ease);
}
.apply__form input::placeholder { color: var(--faint); }
.apply__form input:focus { outline: none; border-color: var(--amber); }
.apply__submit {
  margin-top: 6px; width: 100%; padding: 16px 24px;
  background: var(--amber); color: var(--amber-ink); border: 0; border-radius: 0;
  font-family: var(--sans); font-size: 15px; font-weight: 600; cursor: pointer;
  transition: background var(--fast) var(--ease), opacity var(--fast) var(--ease);
}
.apply__submit:hover { background: var(--amber-hi); }
.apply__submit:disabled { opacity: 0.6; cursor: not-allowed; }
.apply__benefits { margin: 22px 0 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 12px; }
.apply__benefits li { display: flex; gap: 11px; align-items: flex-start; font-size: 15px; color: var(--muted); line-height: 1.5; }
.apply__tick {
  width: 18px; height: 18px; flex: none; margin-top: 2px;
  display: grid; place-items: center; background: var(--amber); color: var(--amber-ink);
}
.apply__tick svg { width: 11px; height: 11px; }
.apply__benefits b { color: var(--amber); font-weight: 700; }
.js-err { margin-top: 10px; font-size: 14px; color: var(--bad-dark); }

/* The form is replaced by this block on success. */
.sent { text-align: center; padding: 26px 0; }
.sent__mark { width: 56px; height: 56px; margin: 0 auto 16px; display: grid; place-items: center; border: 1px solid var(--amber); background: rgba(236, 167, 70, 0.16); }
.sent__mark svg { width: 26px; height: 26px; color: var(--amber); }
.sent__title { font-family: var(--display); font-weight: 800; text-transform: uppercase; font-size: clamp(22px, 2.4vw, 30px); line-height: 1.02; }
.sent__text { margin-top: 10px; color: var(--muted); font-size: 15px; line-height: 1.6; }
.sent__cta { margin-top: 20px; display: inline-flex; align-items: center; gap: 10px; padding: 13px 22px; background: #5865f2; color: #fff; font-size: 14px; font-weight: 600; }
.sent__cta svg { width: 18px; height: 18px; }

/* Mobile desktop-handoff: moments need a PC, so mobile never navigates away. */
.handoff { display: none; margin-top: 14px; border: 1px solid var(--line-2); background: var(--ink-2); padding: 18px; }
.handoff.is-open { display: block; }
.handoff__title { font-family: var(--display); font-weight: 800; text-transform: uppercase; font-size: 21px; line-height: 1.05; }
.handoff__text { margin-top: 8px; font-size: 14px; color: var(--muted); line-height: 1.55; }
.handoff__link { display: block; margin-top: 12px; padding: 11px 12px; background: var(--ink-0); border: 1px solid var(--line); font-size: 12px; color: var(--muted); word-break: break-all; }
.handoff__copy { margin-top: 10px; width: 100%; padding: 12px 18px; background: var(--amber); color: var(--amber-ink); border: 0; font-family: var(--sans); font-size: 14px; font-weight: 600; cursor: pointer; }

/* Sticky mobile conversion bar */
.mcta {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 70;
  display: none; align-items: center; justify-content: space-between; gap: 14px;
  padding: 11px 16px; background: var(--ink-2); border-top: 1px solid var(--line-2);
}
.mcta__text { font-size: 13px; color: var(--muted); line-height: 1.3; }
.mcta__text b { color: var(--amber); }
.mcta__btn { flex: none; padding: 12px 18px; background: var(--amber); color: var(--amber-ink); font-size: 14px; font-weight: 600; }
@media (max-width: 860px) {
  .mcta { display: flex; }
  body.page-landing { padding-bottom: 72px; }
}

/* Creators stub */
.cs {
  min-height: calc(100dvh - var(--nav-h) - var(--banner-h));
  display: flex;
  align-items: center;
  padding: clamp(56px, 10vh, 120px) 0;
  position: relative;
  overflow: hidden;
}
.cs__mark {
  position: absolute;
  right: -8%;
  bottom: -34%;
  width: min(620px, 60vw);
  aspect-ratio: 1;
  background: var(--amber);
  opacity: 0.07;
  -webkit-mask: url("/media/brand/Ludeo pentagon logo.svg") center / contain no-repeat;
  mask: url("/media/brand/Ludeo pentagon logo.svg") center / contain no-repeat;
  pointer-events: none;
}
.cs__inner { position: relative; z-index: 1; max-width: var(--wrap); width: 100%; margin-inline: auto; padding-inline: var(--pad); }
.cs__title {
  font-family: var(--display);
  font-weight: 800;
  text-transform: uppercase;
  font-size: clamp(44px, 9vw, 112px);
  line-height: 0.88;
  letter-spacing: -0.02em;
  max-width: 14ch;
}
.cs__title em { font-style: normal; color: var(--amber); }
.cs__text { margin-top: 22px; max-width: 54ch; color: var(--muted); font-size: clamp(16px, 1.4vw, 20px); line-height: 1.6; }
.cs__actions { margin-top: 32px; display: flex; gap: 12px; flex-wrap: wrap; }

/* ==========================================================================
   21. FINISH LAYER — atmosphere, material and choreography

   The system above sets the world. This layer is the finish: the things that
   separate a page that is correct from a page that reads as made by hand.
   Three ideas only, applied everywhere rather than decorated onto one band.

   1. ATMOSPHERE. A flat #0b0b0e is a colour, not a room. A single fixed grain
      plate and one directional bloom per dark band give the ground depth, so
      large empty areas read as air instead of as missing content.
   2. MATERIAL. Rules stop being uniform 1px greys: they carry light, fading at
      their ends and warming where the eye enters the band.
   3. CHOREOGRAPHY. Reveals stagger from a shared index instead of firing as a
      block, headings wipe up under their own mask, and every rule draws itself
      in. Motion is authored once and never touches a layout property.
   ========================================================================== */

/* ---------------------------------------------------------- 21.1 ATMOSPHERE */
/* One grain plate over the whole document. Overlay blending means the same
   texture warms the near-black ground and tooths the warm-paper bands, so the
   two halves of the system share a surface instead of looking like two sites. */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 9000;
  pointer-events: none;
  opacity: 0.05;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='220' height='220' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 220px 220px;
}
@media print { body::after { display: none; } }

/* Directional bloom. The light enters every dark band from the same upper-left
   corner the reading eye enters from, at a strength that is felt and not seen:
   it lifts the ground by about 3/255, far under any contrast floor. */
.band:not(.band--paper),
.tryl { position: relative; isolation: isolate; }

.band:not(.band--paper)::after,
.tryl::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(58% 46% at 10% 0%, rgba(236, 167, 70, 0.055), transparent 68%),
    radial-gradient(42% 40% at 92% 100%, rgba(236, 167, 70, 0.03), transparent 72%);
}

/* The seam between two dark bands is where a page usually goes dead. A hairline
   that carries the accent at the entry point and fades out across the measure
   keeps the join deliberate. */
.band:not(.band--paper)::before,
.tryl::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 1px;
  pointer-events: none;
  background: linear-gradient(90deg, rgba(236, 167, 70, 0.5) 0%, rgba(255, 255, 255, 0.1) 22%, rgba(255, 255, 255, 0.05) 62%, transparent 100%);
}

/* ------------------------------------------------------------ 21.2 MATERIAL */
/* Gradient hairlines. A rule that fades at its far end reads as light falling
   on an edge; a flat rule reads as a border. Applied to the row systems that
   carry most of the page's structure. */
.def__rows,
.faq__grid { border-top: 1px solid; border-image: linear-gradient(90deg, rgba(0,0,0,0.22), rgba(0,0,0,0.16) 70%, rgba(0,0,0,0.02)) 1; }
.def__row,
.faq-item { border-bottom: 1px solid; border-image: linear-gradient(90deg, rgba(0,0,0,0.16), rgba(0,0,0,0.1) 74%, rgba(0,0,0,0.02)) 1; }
.band:not(.band--paper) .faq__grid { border-image: linear-gradient(90deg, rgba(255,255,255,0.22), rgba(255,255,255,0.1) 70%, rgba(255,255,255,0.02)) 1; }
.band:not(.band--paper) .faq-item { border-image: linear-gradient(90deg, rgba(255,255,255,0.14), rgba(255,255,255,0.07) 74%, rgba(255,255,255,0.02)) 1; }

/* The flow grid's top rule is the band's horizon: amber where the first step
   begins, dissolving before the right edge. */
.flow__grid { border-top: 1px solid; border-image: linear-gradient(90deg, var(--amber) 0%, rgba(255,255,255,0.16) 18%, rgba(255,255,255,0.07) 66%, rgba(255,255,255,0.02) 100%) 1; }

/* Ghosted step figures. The number is already spoken in amber at label size;
   repeating it at display scale behind the step gives the column a background
   plane and turns three text blocks into three composed panels. */
.flow__step { z-index: 0; }
.flow__step::after {
  content: attr(data-fig);
  position: absolute;
  right: clamp(6px, 1.4vw, 18px);
  bottom: -0.22em;
  font-family: var(--display);
  font-weight: 800;
  font-size: clamp(96px, 12vw, 168px);
  line-height: 0.8;
  letter-spacing: -0.03em;
  color: rgba(255, 255, 255, 0.05);
  pointer-events: none;
  z-index: -1;
  font-variant-numeric: tabular-nums;
  transition: color var(--slow) var(--ease);
}
.flow__step:hover::after { color: rgba(236, 167, 70, 0.1); }

/* ------------------------------------------------------------- 21.3 BUTTONS */
/* A light sweep across the fill on hover. Transform only, so nothing reflows,
   and the label sits above it at full contrast throughout. */
.btn, .hero__btn, .nav-btn { position: relative; overflow: hidden; isolation: isolate; }
.btn > *, .hero__btn > *, .nav-btn > * { position: relative; z-index: 1; }
.btn::after, .hero__btn::after, .nav-btn::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background: linear-gradient(100deg, transparent 18%, rgba(255, 255, 255, 0.4) 50%, transparent 82%);
  transform: translateX(-115%);
  transition: transform 640ms var(--ease);
}
.btn:hover::after, .hero__btn:hover::after, .nav-btn:hover::after { transform: translateX(115%); }
.btn--amber::after, .hero__btn--primary::after, .nav-btn--dark::after {
  background: linear-gradient(100deg, transparent 18%, rgba(255, 255, 255, 0.55) 50%, transparent 82%);
}

/* -------------------------------------------------------- 21.4 NAV PROGRESS */
/* The page's own length, drawn on the nav's bottom edge. It adds no chrome:
   the rule is already there, this only fills it. */
.nav { position: sticky; }
.nav__prog {
  position: absolute;
  left: 0;
  bottom: -1px;
  height: 1px;
  width: 100%;
  transform: scaleX(0);
  transform-origin: left;
  background: var(--grad-amber);
  pointer-events: none;
}

/* -------------------------------------------------------- 21.5 CHOREOGRAPHY */
@media (prefers-reduced-motion: no-preference) {
  /* Stagger from a shared index rather than three hard-coded delay classes, so
     a row of four steps arrives as a sequence instead of as two pairs. */
  .reveal,
  .reveal--d1,
  .reveal--d2,
  .reveal--d3 { transition-delay: calc(var(--i, 0) * 90ms); }

  /* Headings wipe up under their own edge. The mask is on the heading only, so
     the supporting sentence beside it is free to arrive on its own beat. */
  .reveal .d2 {
    clip-path: inset(0 0 108% 0);
    transform: translateY(6px);
    transition: clip-path 760ms var(--ease), transform 760ms var(--ease);
    transition-delay: calc(var(--i, 0) * 90ms + 60ms);
  }
  .reveal.is-in .d2 { clip-path: inset(0 0 -14% 0); transform: none; }

  /* Every structural rule draws itself in from the side the band is read from. */
  .rv-rule { transform: scaleX(0); transform-origin: left; transition: transform 900ms var(--ease); }
  .rv-rule.is-in { transform: scaleX(1); }
}

/* ==========================================================================
   22. COMPOSITION FIXES — the empty quadrants

   Three places on the homepage reserved space and never filled it: the top of
   the definition band's left column, the top of the thesis frame, and the whole
   right half of the closing field. Empty space is only air when something has
   been placed against it. These give each of them something to hold.
   ========================================================================== */

/* --------------------------------------------------- 22.1 DEFINITION BAND */
/* The h2 was bottom-aligned to the paragraph, which left roughly 380px of dead
   paper above it. Aligning the two columns at their tops puts the heading where
   the reader enters the band and hands the space below to the figure. The nudge
   is optical: Barlow Condensed carries its cap-height high, so the two columns
   only look aligned once the display side is pulled up a fraction of an em. */
.def__grid { align-items: start; }
.def__grid > .d2 { margin-top: -0.1em; }

/* ------------------------------------------------ 22.2 WATCH/PLAY FIGURE */
.swap {
  margin: clamp(38px, 5vw, 68px) 0 0;
}
.swap { --x: 50%; }
.swap__stage {
  position: relative;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: #06060a;
  border: 1px solid var(--paper-line);
}
.swap__stage:has(.swap__range:focus-visible) { outline: 2px solid var(--paper-kick); outline-offset: 3px; }

.swap__plate {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Each half clips against the same custom property, so the seam is a single
   number and the two sides can never disagree about where it is. */
.swap__side { position: absolute; inset: 0; }
.swap__side--watch { clip-path: inset(0 calc(100% - var(--x)) 0 0); }
.swap__side--play { clip-path: inset(0 0 0 var(--x)); }

/* Colour is the honest difference: a clip is a recording of a thing that
   already happened, so the watching half is drained and dimmed. */
.swap__grade--watch {
  position: absolute;
  inset: 0;
  background: rgba(9, 9, 12, 0.34);
  -webkit-backdrop-filter: grayscale(1) brightness(0.78) contrast(0.94);
  backdrop-filter: grayscale(1) brightness(0.78) contrast(0.94);
}

.swap__tag {
  position: absolute;
  top: clamp(12px, 1.6vw, 20px);
  left: clamp(14px, 1.8vw, 24px);
  font-family: var(--sans);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.86);
  text-shadow: 0 1px 14px rgba(0, 0, 0, 0.95);
  z-index: 3;
}
.swap__tag--live { left: auto; right: clamp(14px, 1.8vw, 24px); color: var(--amber); }

/* Player chrome. It sits on the bottom edge where a video player's controls
   sit, over its own scrim so it stays legible against whatever the frame is. */
.swap__scrim {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 42%;
  background: linear-gradient(180deg, transparent, rgba(6, 6, 10, 0.86));
  z-index: 2;
}
.swap__player {
  position: absolute;
  left: clamp(14px, 1.8vw, 24px);
  right: clamp(14px, 1.8vw, 24px);
  bottom: clamp(14px, 1.8vw, 22px);
  z-index: 3;
  display: block;
}
.swap__track {
  display: block;
  height: 2px;
  background: rgba(255, 255, 255, 0.28);
}
.swap__fill {
  display: block;
  height: 100%;
  width: 36%;
  background: rgba(255, 255, 255, 0.92);
  position: relative;
}
.swap__fill::after {
  content: "";
  position: absolute;
  right: -3px;
  top: -2px;
  width: 6px;
  height: 6px;
  background: #fff;
}
.swap__time {
  display: block;
  margin-top: 9px;
  font-size: 11px;
  letter-spacing: 0.06em;
  color: rgba(255, 255, 255, 0.66);
}

/* Input, shown as input. Four keycaps in the system's own zero-radius hairline
   language, lighting in sequence so the half that is playable is the half that
   moves. */
.swap__keys {
  position: absolute;
  right: clamp(14px, 1.8vw, 24px);
  bottom: clamp(14px, 1.8vw, 22px);
  z-index: 3;
  display: flex;
  gap: 5px;
}
.swap__key {
  width: clamp(22px, 2.4vw, 30px);
  height: clamp(22px, 2.4vw, 30px);
  display: grid;
  place-items: center;
  font-family: var(--sans);
  font-size: 11px;
  font-weight: 600;
  color: rgba(255, 255, 255, 0.9);
  border: 1px solid rgba(255, 255, 255, 0.34);
  background: rgba(6, 6, 10, 0.55);
}
@media (prefers-reduced-motion: no-preference) {
  .swap__key { animation: swapKey 2.6s var(--ease) infinite; }
  .swap__key:nth-child(2) { animation-delay: 0.18s; }
  .swap__key:nth-child(3) { animation-delay: 0.36s; }
  .swap__key:nth-child(4) { animation-delay: 0.54s; }
}
@keyframes swapKey {
  0%, 62%, 100% { border-color: rgba(255, 255, 255, 0.34); color: rgba(255, 255, 255, 0.9); background: rgba(6, 6, 10, 0.55); }
  70%, 82% { border-color: var(--amber); color: var(--amber-ink); background: var(--amber); }
}

/* The seam carries the only light in the figure. */
.swap__seam {
  position: absolute;
  top: 0;
  bottom: 0;
  left: var(--x);
  width: 1px;
  background: var(--amber);
  box-shadow: 0 0 26px rgba(236, 167, 70, 0.7);
  z-index: 4;
  pointer-events: none;
}
.swap__grip {
  position: absolute;
  top: 50%;
  left: 50%;
  width: clamp(34px, 3.4vw, 44px);
  height: clamp(34px, 3.4vw, 44px);
  transform: translate(-50%, -50%);
  background: var(--amber);
  display: grid;
  place-items: center;
}
.swap__grip::before,
.swap__grip::after {
  content: "";
  position: absolute;
  width: 7px;
  height: 7px;
  border-top: 2px solid var(--amber-ink);
  border-left: 2px solid var(--amber-ink);
}
.swap__grip::before { transform: rotate(-45deg) translate(0, 0); left: 26%; }
.swap__grip::after { transform: rotate(135deg); right: 26%; }

.swap__range {
  position: absolute;
  inset: 0;
  z-index: 5;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: col-resize;
  -webkit-appearance: none;
  appearance: none;
  background: transparent;
}
.swap__range::-webkit-slider-thumb { -webkit-appearance: none; width: 56px; height: 100vh; }
.swap__range::-moz-range-thumb { width: 56px; height: 100vh; border: 0; }

.swap__cap {
  margin-top: 16px;
  padding-top: 14px;
  border-top: 1px solid;
  border-image: linear-gradient(90deg, rgba(0,0,0,0.16), rgba(0,0,0,0.02)) 1;
  font-size: 15px;
  line-height: 1.6;
  color: var(--paper-muted);
  max-width: 68ch;
}

@media (max-width: 700px) {
  .swap__stage { aspect-ratio: 4 / 3; }
  .swap__time { display: none; }
}

/* --------------------------------------------------------- 22.4 END FIELD */
}

/* ==========================================================================
   23. SECOND PASS — what the first render showed

   Every rule here answers something visible in the render rather than
   something intended: labels landing on the game's own HUD, a desaturation too
   polite to read as a difference, ghost figures sliced by the row rule they
   were meant to sit behind, and three identical card widths where the moment
   grid wanted a lead.
   ========================================================================== */

/* ----------------------------------------------------- 23.1 THE COMPARATOR */
/* Drained hard enough to read at a glance. At the first setting the two halves
   differed by about 6% luminance, which is a rendering artefact, not an idea. */
.swap__grade--watch {
  background: rgba(9, 9, 12, 0.42);
  -webkit-backdrop-filter: grayscale(1) brightness(0.58) contrast(0.88);
  backdrop-filter: grayscale(1) brightness(0.58) contrast(0.88);
}

/* Both pieces of chrome hug the divider, so the comparison is a timeline on one
   side of a single line and a pair of hands on the other. */
.swap__keys {
  left: calc(var(--x) + 16px);
  right: auto;
  bottom: clamp(16px, 2vw, 26px);
}

.swap__grip {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
}
.swap__grip::before,
.swap__grip::after {
  content: "";
  position: static;
  width: 6px;
  height: 6px;
  border-top: 2px solid var(--amber-ink);
  border-right: 2px solid var(--amber-ink);
  border-left: 0;
  left: auto;
  right: auto;
}
.swap__grip::before { transform: rotate(-135deg); }
.swap__grip::after { transform: rotate(45deg); }

/* The legend is the divider's readout: each label owns exactly the width of
   the side it names, and its rule carries that side's colour. */
.swap__legend { display: flex; align-items: stretch; margin-top: 0; }
.swap__leg {
  padding-top: 11px;
  font-family: var(--sans);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  border-top: 2px solid;
  transition: width 120ms linear;
}
.swap__leg--watch {
  width: var(--x);
  padding-right: 14px;
  border-color: rgba(23, 24, 28, 0.34);
  color: var(--paper-faint);
}
.swap__leg--play {
  flex: 1;
  padding-left: 14px;
  border-color: var(--amber);
  color: var(--paper-kick);
}
.swap__cap { margin-top: 18px; }

/* --------------------------------------------------------- 23.2 FLOW BAND */
/* The ghost figure was cropped by the row rule at its widest point, which read
   as a clipping bug rather than as a device. Give the step the room to hold the
   whole glyph and let it sit under the paragraph as a plane. */
.flow__step { padding-bottom: clamp(74px, 8.5vw, 118px); }
.flow__step::after {
  bottom: clamp(10px, 1.2vw, 18px);
  font-size: clamp(92px, 11vw, 152px);
  color: rgba(255, 255, 255, 0.055);
}

/* ------------------------------------------------------ 23.3 MOMENT CARDS */
/* Three identical widths is the arrangement a grid produces, not one a person
   chooses. The first moment leads; the other two support it. */
@media (min-width: 980px) {
  .ludeo-grid { grid-template-columns: 1.3fr 1fr 1fr; }
}

/* Frames get a foot so they sit on the ground instead of floating as rectangles
   of someone else's artwork, and the accent arrives on the edge nearest the
   pointer rather than around the whole card. */
.lcard { border-color: rgba(255, 255, 255, 0.1); }
.lcard__stage::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 38%;
  background: linear-gradient(180deg, transparent, rgba(6, 6, 10, 0.6));
  pointer-events: none;
  z-index: 1;
  transition: opacity var(--mid) var(--ease);
}
.lcard:hover .lcard__stage::after { opacity: 0.35; }
.lcard__hover { z-index: 2; }
.lcard::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 2px;
  background: var(--amber);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--mid) var(--ease);
  z-index: 3;
  pointer-events: none;
}
.lcard:hover::after { transform: scaleX(1); }
.lcard__play { letter-spacing: 0.05em; text-transform: uppercase; font-size: 12px; }

/* ------------------------------------------------------------ 23.4 THE HERO */
/* The hero used to end on a hard cut into the proof rail. A short fall-off ties
   the two together and stops the join reading as two stacked components. */
.hero__media::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 120px;
  background: linear-gradient(180deg, transparent, var(--ink-1));
  pointer-events: none;
  z-index: 1;
}
.hero__overlay { z-index: 2; }

/* ==========================================================================
   24. THIRD PASS

   Three things the second render exposed: a rule doubled under the comparator,
   a card row whose lead was wider but whose furniture no longer lined up, and
   a thesis frame sitting in the one hue this system does not own.
   ========================================================================== */

/* The legend already draws the rule under the figure. A second one 30px below
   it is not a pair, it is a mistake. */
.swap__cap { border-top: 0; padding-top: 0; margin-top: 20px; }

/* The lead moment is wider, so at 16/9 it is also taller, and the two cards
   beside it were left hanging their play bars 60px high. Only the lead keeps a
   fixed ratio; the others fill the row it sets, which crops them a little
   squarer and reads as an arrangement rather than a division. */
@media (min-width: 980px) {
  .lcard { height: 100%; }
  .lcard:first-child .lcard__stage { aspect-ratio: 16 / 9; }
  .lcard:not(:first-child) .lcard__stage { aspect-ratio: auto; flex: 1 1 auto; min-height: 180px; }
}

/* Sections 24 (thesis colour blend) and 25 (thesis band, full bleed) are gone
   with the band itself. The Ludeo row now closes the dark middle and hands
   straight to the amber field. */

/* ==========================================================================
   26. FOURTH PASS — the two most templated surfaces

   A hero video that sits perfectly still while the page moves over it, and an
   accordion with no voice of its own, are the two places this page still looked
   like every other page. Both are fixed with what the system already owns:
   depth on the hero, and the numbering language the flow band established.
   ========================================================================== */

/* --------------------------------------------------------- 26.1 HERO PLATE */
/* The plate is 12% taller than the frame and hangs 6% above it, so it can
   travel 9% down without ever showing an edge. */
.hero__plate {
  position: absolute;
  left: 0;
  right: 0;
  top: -6%;
  height: 112%;
  will-change: transform;
}
.hero__plate .hero__video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
@media (prefers-reduced-motion: reduce) {
  .hero__plate { top: 0; height: 100%; transform: none !important; }
}

/* ------------------------------------------------------- 26.2 NUMBERED FAQ */
/* The flow band already taught the reader that this system counts in amber
   two-digit figures. The questions join that language, which also gives each
   row a fixed left edge for the eye to run down. */
.faq__grid { counter-reset: faq; }
.faq-q { counter-increment: faq; gap: 0; }
.faq-q::before {
  content: counter(faq, decimal-leading-zero);
  flex: none;
  width: clamp(44px, 5vw, 64px);
  font-family: var(--display);
  font-weight: 800;
  font-size: 15px;
  letter-spacing: 0.06em;
  line-height: 1.5;
  color: var(--paper-kick);
  font-variant-numeric: tabular-nums;
  opacity: 0.62;
  transition: opacity var(--fast) var(--ease);
}
.faq-q > span { flex: 1 1 auto; padding-right: 20px; }
.faq-q:hover::before,
.faq-item.is-open .faq-q::before { opacity: 1; }
.band:not(.band--paper) .faq-q::before { color: var(--amber); }
/* The answer lines up under the question, not under its number. */
.faq-a p { padding-left: clamp(44px, 5vw, 64px); }

@media (max-width: 560px) {
  .faq-q::before { width: 34px; font-size: 13px; }
  .faq-a p { padding-left: 34px; }
}

/* ==========================================================================
   27. CONTRAST AND ANNOUNCEMENT

   Two of the new marks were set with alpha for tone and landed under the AA
   floor once measured against their real backgrounds, and one decorative glyph
   was repeating a number a screen reader had already been given.
   ========================================================================== */

/* #96601b at 62% over #f6f3ec measures 2.43:1. At full strength it is 4.76:1,
   and emphasis moves to the ink instead of to more of the accent. */
.faq-q::before { opacity: 1; transition: color var(--fast) var(--ease); }
.faq-q:hover::before { color: var(--paper-ink); }
.faq-item.is-open .faq-q::before { color: var(--paper-ink); }
.band:not(.band--paper) .faq-q:hover::before,
.band:not(.band--paper) .faq-item.is-open .faq-q::before { color: var(--text); }


/* The ghost figure is the step's number drawn as a surface, and the step has
   already announced that number in its own element. The empty alternative text
   keeps it out of the accessibility tree so nobody hears "01" twice. */
.flow__step::after { content: attr(data-fig) / ""; }

/* ==========================================================================
   28. THE PROOF RAIL

   The three numbers directly under the hero are the page's first factual
   claim, and they were sitting between flat 1px dividers with no light of
   their own. Same rules, given the same treatment as the rest of the system:
   they fall off downward, and each cell answers the pointer.
   ========================================================================== */
.proof__cell { position: relative; transition: background var(--mid) var(--ease); }
.proof__cell + .proof__cell {
  border-left: 1px solid;
  border-image: linear-gradient(180deg, rgba(255,255,255,0.02), rgba(255,255,255,0.16) 40%, rgba(255,255,255,0.03)) 1;
}
.proof__cell::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 2px;
  background: var(--amber);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--slow) var(--ease);
}
.proof__cell:hover::before { transform: scaleX(1); }
.proof__cell:hover { background: rgba(255, 255, 255, 0.02); }

@media (max-width: 720px) {
  .proof__cell + .proof__cell {
    border-left: 0;
    border-top: 1px solid;
    border-image: linear-gradient(90deg, rgba(255,255,255,0.16), rgba(255,255,255,0.02)) 1;
  }
}

/* ==========================================================================
   29. THE HERO SCRIM, MADE STREAM-PROOF

   The hero cycles three Mux streams and the scrim was tuned against the two
   dark ones. The third is a daylight RTS frame of pale sand, and behind white
   condensed display type at 96px that is the one case where the existing
   left-to-right wash plus a text shadow is doing all the work. A soft pool
   under the copy block only deepens the ground where the type actually sits,
   which costs the frame nothing in the two thirds of the width the reader is
   looking at the gameplay in.
   ========================================================================== */
.hero__scrim {
  background:
    radial-gradient(64% 58% at 26% 52%, rgba(8, 8, 11, 0.5) 0%, rgba(8, 8, 11, 0.22) 46%, transparent 72%),
    linear-gradient(180deg, rgba(11,11,14,0.34) 0%, rgba(11,11,14,0.06) 30%, rgba(11,11,14,0.6) 86%, var(--ink-0) 100%),
    linear-gradient(90deg, rgba(11,11,14,0.62) 0%, rgba(11,11,14,0.3) 46%, rgba(11,11,14,0) 100%);
}

/* ==========================================================================
   30. RECONCILING WITH THE RECORDED SYSTEM

   Two things added in this finish broke rules DESIGN.md already carries. The
   rules win; the additions change.

   1. "Don't put a paper panel on the dark ground or a dark panel inside a
      paper surface." The comparator was a dark figure boxed inside the warm
      paper band. It is now its own full-bleed band on the dark ground, so it
      interrupts the paper rather than sitting on it, and it rhymes with the
      full-bleed thesis band further down. The definition band goes back to the
      bottom-aligned heading every other band head in this system uses.
   2. "Don't use gradient text, or any gradient outside the video scrims and
      the marquee edge fades." A white shine sweeping across a button fill was
      both a gradient inside a control and, on its own merits, the most
      generic thing in the build. It is replaced by the system's own documented
      hover gesture: a rule growing in from the left.

   The gradients that remain are all light on an edge or a scrim over media:
   band seams, hairlines that fall off across a measure, corner bloom, the hero
   and card scrims. None fills a surface, a control, or type.
   ========================================================================== */

/* ------------------------------------------------- 30.1 DEFINITION BAND BACK */
.def__grid { align-items: end; }
.def__grid > .d2 { margin-top: 0; }

/* --------------------------------------------------- 30.2 FULL-BLEED FIGURE */
.swapband {
  background: var(--ink-0);
  padding-block: 0;
  position: relative;
  isolation: isolate;
}
.swap { margin: 0; }
.swap__stage {
  aspect-ratio: 2.32 / 1;
  border: 0;
  border-top: 1px solid var(--line);
}
/* Edge to edge, the legend measures the seam exactly, because both are
   percentages of the same full width. */
.swap__legend { width: 100%; }
.swap__leg { padding-top: 13px; padding-bottom: 2px; }
.swap__leg--watch { padding-left: var(--pad); border-color: rgba(255, 255, 255, 0.22); color: var(--faint); }
.swap__leg--play { border-color: var(--amber); color: var(--amber); }
.swap__cap {
  color: var(--muted);
  margin: clamp(20px, 2.6vw, 30px) 0 clamp(64px, 8vw, 110px);
  border-top: 0;
  padding-top: 0;
}
@media (max-width: 700px) {
  .swap__stage { aspect-ratio: 4 / 3; }
  .swap__leg--watch { padding-left: var(--pad); }
}

/* ------------------------------------------------------ 30.3 BUTTON HOVER */
/* The sweep is gone. The gesture is the one this system already names: a rule
   that grows from the left on hover, in the ink the control carries. */
.btn::after, .hero__btn::after, .nav-btn::after {
  background: currentColor;
  inset: auto 0 0 0;
  height: 2px;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--mid) var(--ease);
  opacity: 0.85;
}
.btn:hover::after, .hero__btn:hover::after, .nav-btn:hover::after { transform: scaleX(1); }
.btn--amber::after, .hero__btn--primary::after, .nav-btn--dark::after { background: currentColor; }

/* ==========================================================================
   31. THE FIGURE BAND, SETTLED

   Edge to edge, the legend sits on the page's outer padding while the caption
   was still centred in the content wrap, so the two left edges missed each
   other by 100px. In a full-bleed band the outer padding is the measure.
   ========================================================================== */
.swap__cap {
  padding-inline: var(--pad);
  max-width: calc(70ch + var(--pad));
  margin: clamp(18px, 2.2vw, 26px) 0 clamp(44px, 5.5vw, 76px);
}

/* The drain has to carry across whatever the frame happens to show. On a dark
   interior a brightness cut alone is invisible; taking the colour out entirely
   and lifting the black point makes the left half read as footage in any
   crop. */
.swap__grade--watch {
  background: rgba(12, 12, 16, 0.3);
  -webkit-backdrop-filter: grayscale(1) brightness(0.72) contrast(0.8);
  backdrop-filter: grayscale(1) brightness(0.72) contrast(0.8);
}

/* ==========================================================================
   32. THE COMPARATOR, MADE PLAYABLE

   The first build of this figure argued by illustration: a still, drained on
   one side, with a picture of some keycaps on the other. It said the right
   half was playable. It did not behave that way, which on a page whose whole
   claim is "watching is not playing" is the wrong thing to be caught doing.

   Now the difference is enforced rather than depicted:

   - One live stream under both halves, so the seam never tears and the left
     half's timeline is the stream's real position, not a typed-in number.
   - Left of the seam the frame is inert. The cursor stays an arrow, nothing
     tracks, and the only thing moving is a clock you did not set.
   - Right of the seam the cursor is replaced by a reticle that follows the
     pointer, a soft focus falls where you point, the keycaps answer real
     W A S D presses, and the reticle leans the way you press.
   - Everything on the play side is clipped by the seam, so dragging the
     divider across a parked pointer turns the reader's own cursor into a
     reticle in front of them. That is the entire pitch, done as a gesture.
   - The way out is a real Ludeo, not a mock: the play side carries the
     PAYDAY 3 campaign link the moment cards below use.

   Desktop only for the link and the reticle. Moments do not run on phones, so
   under 700px the figure keeps the divider, the timeline and the keycaps and
   drops the parts that would strand a touch reader.
   ========================================================================== */

/* ------------------------------------------------------------ 32.1 STAGE */
.swap__plate {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  background: #06060a;
}

/* Both halves are hit-testable, because the cursor is half of the argument:
   it has to change as the reader crosses the seam. clip-path clips the hit
   region as well as the paint, so each side only answers on its own ground. */
.swap__side { pointer-events: auto; }
.swap__side--watch { cursor: default; }
.swap__side--play { cursor: none; }
.swap__side--watch > *, .swap__side--play > * { pointer-events: none; }
.swap__go { pointer-events: auto; }

/* --------------------------------------------------------- 32.2 THE RETICLE */
.swap__cross {
  position: absolute;
  left: var(--px, 50%);
  top: var(--py, 50%);
  width: 34px;
  height: 34px;
  margin: -17px 0 0 -17px;
  opacity: 0;
  transition: opacity var(--fast) var(--ease), transform var(--fast) var(--ease);
  z-index: 3;
}
.swap__stage.is-hot .swap__cross { opacity: 1; }
/* The two strokes are drawn as gaps in a cross, so the exact point stays
   readable against whatever the frame is showing. */
.swap__cross::before,
.swap__cross::after {
  content: "";
  position: absolute;
  background: var(--amber);
  box-shadow: 0 0 10px rgba(6, 6, 10, 0.9);
}
.swap__cross::before { left: 50%; top: 0; bottom: 0; width: 2px; margin-left: -1px; }
.swap__cross::after { top: 50%; left: 0; right: 0; height: 2px; margin-top: -1px; }
/* The centre stays clear. */
.swap__cross { -webkit-mask: radial-gradient(circle at 50% 50%, transparent 0 5px, #000 5px); mask: radial-gradient(circle at 50% 50%, transparent 0 5px, #000 5px); }

/* A press leans the reticle the way it was pressed. Small, and transform only. */
.swap[data-dir="KeyW"] .swap__cross { transform: translateY(-6px); }
.swap[data-dir="KeyS"] .swap__cross { transform: translateY(6px); }
.swap[data-dir="KeyA"] .swap__cross { transform: translateX(-6px); }
.swap[data-dir="KeyD"] .swap__cross { transform: translateX(6px); }

/* Where you point, the frame lifts. 7% is under the threshold of noticing it
   as an effect and over the threshold of feeling the side respond. */
.swap__focus {
  position: absolute;
  left: var(--px, 50%);
  top: var(--py, 50%);
  width: 420px;
  height: 420px;
  margin: -210px 0 0 -210px;
  background: radial-gradient(circle, rgba(255, 236, 205, 0.07), transparent 66%);
  opacity: 0;
  transition: opacity var(--mid) var(--ease);
  z-index: 2;
}
.swap__stage.is-hot .swap__focus { opacity: 1; }

/* ------------------------------------------------------------- 32.3 KEYCAPS */
/* The idle loop stops for good at the first real press: `is-live` is set by the
   keydown handler and never removed. */
.swap__keys.is-live .swap__key { animation: none; }
.swap__key { transition: background var(--fast) var(--ease), border-color var(--fast) var(--ease), color var(--fast) var(--ease), transform var(--fast) var(--ease); }
.swap__key.is-down {
  background: var(--amber);
  border-color: var(--amber);
  color: var(--amber-ink);
  transform: translateY(2px);
}

/* --------------------------------------------------------- 32.4 THE WAY OUT */
.swap__go {
  position: absolute;
  right: clamp(16px, 2vw, 28px);
  bottom: clamp(16px, 2vw, 26px);
  z-index: 4;
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 13px 20px;
  background: var(--amber);
  color: var(--amber-ink);
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0.01em;
  cursor: pointer;
  transition: background var(--fast) var(--ease);
}
.swap__go:hover { background: var(--amber-hi); }
/* Over a real control the reader gets a real cursor back. */
.swap__go:hover ~ .swap__cross,
.swap__side--play:has(.swap__go:hover) .swap__cross { opacity: 0; }

/* ------------------------------------------------------------- 32.5 SEAM */
/* The divider is the only pointer control on the frame. A transparent sheet
   over the whole stage would have swallowed every event the reticle and the
   link need, so the range input is keyboard-only and the drag lives here. */
.swap__seam { pointer-events: auto; cursor: col-resize; touch-action: none; }
.swap__seam::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: -24px;
  right: -24px;
}
.swap__stage.is-dragging { cursor: col-resize; }
.swap__stage.is-dragging .swap__side--play { cursor: col-resize; }
.swap__stage.is-dragging .swap__cross,
.swap__stage.is-dragging .swap__focus { opacity: 0; }

.swap__range {
  position: absolute;
  width: 1px;
  height: 1px;
  inset: auto auto 0 0;
  opacity: 0;
  pointer-events: none;
}
.swap__stage:has(.swap__range:focus-visible) .swap__grip {
  outline: 2px solid var(--text);
  outline-offset: 3px;
}

/* ------------------------------------------------------------ 32.6 TIMELINE */
/* Bound to the stream. With no duration it stays at zero with no timecode,
   which is what a paused player looks like and is the honest state. */
.swap__fill { width: 0; transition: none; }
.swap__time:empty { display: none; }

/* -------------------------------------------------------------- 32.7 TOUCH */
@media (max-width: 700px), (pointer: coarse) {
  .swap__cross, .swap__focus { display: none; }
  .swap__side--play { cursor: default; }
  .swap__seam::before { left: -30px; right: -30px; }
}

/* ==========================================================================
   33. THE STUDIO APPLICATION AND ITS THANK YOU  — the broken CTA

   This is the bug behind "the CTA is not working", and it was invisible to
   every check the build runs.

   /script.js intercepts every `a[href^="https://studio.ludeo.com"]` and builds
   a five-field studio application at runtime, posts a SHA-256-signed body to
   /api/notify-slack, and fires indie_submission + PostHog + Meta + LinkedIn.
   That is the only lead path the primary CTAs have. Production styles it with
   an `.apply-*` block; this stylesheet was written from scratch and never
   carried one. With no rules at all the popup was `position: static` with no
   width cap, so it rendered 863 x 1142 inside a 900px viewport, its submit
   button sat 87px below the fold, and because a static box cannot rise above
   an absolutely positioned sibling, the modal backdrop painted straight over
   it. Every click on Get Started opened a dialog that could not be filled in
   or submitted.

   The markup is generated by a file we do not own, so these selectors are a
   contract: keep the class names exactly, and re-check them whenever
   /script.js changes. Nothing here is styled like production; it is the same
   component redrawn in this system, which is why the `.apply-pill` below is
   plain tracked text and not a capsule.
   ========================================================================== */

.apply-popup,
.ty-popup {
  position: relative;              /* the whole bug: must rise above .modal__backdrop */
  z-index: 1;
  width: 100%;
  max-width: 460px;
  max-height: calc(100dvh - 40px);
  overflow-y: auto;
  padding: clamp(28px, 4vw, 40px);
  background: var(--ink-2);
  border: 1px solid var(--line-2);
  text-align: center;
  animation: pop-in var(--mid) var(--ease) both;
}

.apply-close {
  position: absolute;
  top: 12px;
  right: 12px;
  width: 34px;
  height: 34px;
  display: grid;
  place-items: center;
  background: transparent;
  border: 1px solid var(--line);
  color: var(--muted);
  font-size: 15px;
  line-height: 1;
  cursor: pointer;
  transition: color var(--fast) var(--ease), border-color var(--fast) var(--ease);
}
.apply-close:hover { color: var(--text); border-color: var(--line-2); }

/* Unsized, this SVG expanded to 863px and took the layout with it. */
.apply-icon { display: flex; justify-content: center; margin-bottom: 18px; }
.apply-icon svg { width: 34px; height: 34px; flex: none; color: var(--amber); }

.apply-title {
  font-family: var(--display);
  font-weight: 800;
  text-transform: uppercase;
  font-size: clamp(26px, 3vw, 34px);
  line-height: 0.98;
  letter-spacing: -0.01em;
  color: var(--text);
}
.apply-title b { font-weight: 800; color: var(--amber); }

/* Named "pill" by the markup, drawn as plain text: this system has no capsules. */
.apply-pill {
  margin-top: 12px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
  background: none;
  border: 0;
  padding: 0;
}

.apply-form { margin-top: 24px; text-align: left; display: grid; gap: 10px; }
.apply-field { display: block; }
.apply-input {
  width: 100%;
  height: 48px;
  padding: 0 14px;
  background: var(--ink-0);
  border: 1px solid var(--line-2);
  color: var(--text);
  font-family: var(--sans);
  font-size: 15px;
  transition: border-color var(--fast) var(--ease);
}
.apply-input::placeholder { color: var(--faint); }
.apply-input:hover { border-color: rgba(255, 255, 255, 0.28); }
.apply-input:focus { outline: none; border-color: var(--amber); }

.apply-error {
  display: none;
  margin-top: 6px;
  font-size: 13px;
  color: var(--bad-dark);
}
.apply-field.is-error .apply-error { display: block; }
.apply-field.is-error .apply-input { border-color: var(--bad-dark); }

.apply-submit {
  width: 100%;
  height: 52px;
  margin-top: 6px;
  background: var(--amber);
  color: var(--amber-ink);
  border: 0;
  font-family: var(--sans);
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 0.01em;
  cursor: pointer;
  transition: background var(--fast) var(--ease);
}
.apply-submit:hover { background: var(--amber-hi); }
.apply-submit:disabled { opacity: 0.6; cursor: not-allowed; }

.apply-form__error {
  display: none;
  margin-top: 12px;
  font-size: 14px;
  color: var(--bad-dark);
}
.apply-form__error.is-visible { display: block; }

/* ---- the thank you step, same chassis ---- */
.ty-check { display: flex; justify-content: center; margin-bottom: 18px; }
.ty-check svg { width: 30px; height: 30px; flex: none; color: var(--amber); }
.ty-title {
  font-family: var(--display);
  font-weight: 800;
  text-transform: uppercase;
  font-size: clamp(26px, 3vw, 34px);
  line-height: 0.98;
  letter-spacing: -0.01em;
}
.ty-body { margin-top: 14px; color: var(--muted); font-size: 15px; line-height: 1.6; }
.ty-actions { margin-top: 26px; display: grid; gap: 10px; }
.ty-actions__label {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--faint);
}
.ty-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  height: 50px;
  padding: 0 20px;
  font-size: 15px;
  font-weight: 600;
  border: 0;
  cursor: pointer;
  transition: background var(--fast) var(--ease);
}
.ty-btn--primary { background: var(--amber); color: var(--amber-ink); }
.ty-btn--primary:hover { background: var(--amber-hi); }
.ty-btn--discord { background: #5865f2; color: #fff; }
.ty-btn--discord:hover { background: #6b76f5; }
.ty-btn--discord svg { width: 20px; height: 20px; flex: none; }

@media (max-width: 560px) {
  .apply-popup, .ty-popup { padding: 24px 18px; }
  .apply-input { height: 46px; font-size: 14px; }
  .apply-submit { height: 50px; }
}

/* ==========================================================================
   34. RESPONSIVE FIXES AND THE COMPARATOR'S CALL TO ACTION

   Findings from a sweep of 12 routes across 14 widths from 320 to 2560. Only
   one route overflowed, but four things were wrong at phone sizes and the
   figure's own call to action was the smallest thing on a very loud frame.
   ========================================================================== */

/* --------------------------------------------------- 34.1 THE ONE OVERFLOW */
/* /creators at 320px pushed the page 29px wide. The paid-quest grid was two
   columns held open by a 190px minimum on its card, and it was written as an
   inline style attribute, so no media query could ever have reached it. It is
   a stylesheet rule now, and it collapses before it can overflow. */
.paid__grid {
  margin-top: clamp(30px, 4vw, 48px);
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(20px, 3vw, 44px);
  align-items: start;
}
@media (max-width: 760px) {
  .paid__grid { grid-template-columns: 1fr; }
}

/* ------------------------------------------------------- 34.2 TAP TARGETS */
/* Everything below was tall enough to read and too short to hit. The rule
   applies on coarse pointers only, so the desktop rhythm is untouched. */
@media (pointer: coarse), (max-width: 760px) {
  .banner__close { width: 44px; height: 44px; }
  .nav__logo { min-height: 44px; display: inline-flex; align-items: center; }
  .tlink, .step__btn, .dfrow a { padding-block: 10px; }
  .footer__col a { padding-block: 6px; }
  .footer__col { gap: 4px; }
  .footer__socials a { min-width: 44px; min-height: 44px; display: inline-grid; place-items: center; }
}

/* --------------------------------------------------------- 34.3 SMALL TEXT */
/* The legend under the comparator names the two states; at 11px with 0.18em
   tracking on a 320px screen that is a caption, not a label. The banner's
   "up to" sits against a 24px figure and only needs to clear the floor. */
.swap__leg { font-size: 12px; }
.banner__upto { font-size: 11.5px; }

/* ------------------------------------------- 34.4 THE COMPARATOR'S WAY OUT */
/* A single 14px button in the corner of a frame full of the game's own HUD is
   not a call to action, it is a detail. Three changes, in order of how much
   they do: the play side gets the same bottom scrim the watch side already
   had, so anything sitting there has a base to read against; the action gains
   a line of context above it, which roughly doubles its mass and answers the
   question the button raises; and the button itself goes up to 16px with the
   pentagon on it, so it reads as a play control rather than a link. */
.swap__side--play::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 46%;
  background: linear-gradient(180deg, transparent, rgba(6, 6, 10, 0.88));
  pointer-events: none;
  z-index: 1;
}

.swap__cue {
  position: absolute;
  right: clamp(16px, 2vw, 30px);
  bottom: clamp(16px, 2vw, 28px);
  z-index: 4;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 10px;
  text-align: right;
}
.swap__cue-line {
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.01em;
  color: rgba(255, 255, 255, 0.9);
  text-shadow: 0 1px 12px rgba(0, 0, 0, 0.95);
}

.swap__go {
  position: static;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 15px 24px;
  background: var(--amber);
  color: var(--amber-ink);
  font-size: 16px;
  font-weight: 600;
  letter-spacing: 0.01em;
  line-height: 1;
  cursor: pointer;
  pointer-events: auto;
  transition: background var(--fast) var(--ease), transform var(--fast) var(--ease);
}
.swap__go:hover { background: var(--amber-hi); transform: translateY(-1px); }
.swap__go:active { transform: translateY(0); }
.swap__go-mark {
  width: 17px;
  height: 17px;
  flex: none;
  background: var(--amber-ink);
  -webkit-mask: var(--mark) center / contain no-repeat;
  mask: var(--mark) center / contain no-repeat;
}
.swap__go .btn-chev { border-color: var(--amber-ink); }

/* A moment does not run on a phone, so the control stops promising one and
   says what is true instead. Set by the comparator script, which also stops it
   navigating. */
.swap__go.is-desktop-only {
  background: transparent;
  color: rgba(255, 255, 255, 0.92);
  border: 1px solid rgba(255, 255, 255, 0.34);
  cursor: default;
  padding: 12px 16px;
  font-size: 14px;
}
.swap__go.is-desktop-only:hover { background: transparent; transform: none; }
.swap__go.is-desktop-only .swap__go-mark { background: var(--amber); }
.swap__go.is-desktop-only .btn-chev { display: none; }

/* On touch the play side is a ~200px sliver of a small frame, which is no
   place for a control. The in-frame cue goes and the note under the caption
   carries the same fact where there is room to read it. */
.swap__note { display: none; }
@media (max-width: 700px), (pointer: coarse) {
  .swap__cue, .swap__keys { display: none; }
  .swap__note {
    display: block;
    margin: 0 0 clamp(44px, 5.5vw, 76px);
    padding: 12px var(--pad) 0;
    border-top: 1px solid var(--line);
    max-width: calc(60ch + var(--pad));
    font-size: 14px;
    line-height: 1.55;
    color: var(--faint);
  }
  .swap__cap { margin-bottom: 14px; }
}

/* ==========================================================================
   35. THE LAST TWO TAP TARGETS

   Both survived the first pass for the same reason the one page overflow did:
   an inline `style` attribute in the markup, which no stylesheet rule and no
   media query can reach. There is a lesson in that, recorded in the Don'ts.
   ========================================================================== */

/* A `<button>` styled as a text link. It carried
   `style="background:none;border:0;cursor:pointer;padding:0"` inline, so the
   coarse-pointer padding never applied. The reset is a class now. */
.tlink--btn {
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
}

/* The landing page's footer sets its legal row in a flex line; on a phone the
   Discord link in it was a 20px target. */
@media (pointer: coarse), (max-width: 760px) {
  .tlink--btn { padding-block: 10px; }
  .footer__legal a { display: inline-block; padding-block: 10px; }
}

/* ==========================================================================
   36. THE SMALLEST PHONE

   At 320 the nav's primary button wrapped to two lines inside a 68px bar and
   sat hard against the menu toggle. Nothing is dropped: the label holds on one
   line at a smaller size, and the logo gives up the width for it.
   ========================================================================== */
/* The promo banner stacked into three ragged rows here: a wrapped title, a
   two-line "UP TO", and the dismiss on a line of its own. It keeps the offer
   and the number and drops the connective words. */
@media (max-width: 420px) {
  .banner__upto { display: none; }
  /* The dismiss was dropping onto a line of its own. Pinned to the edge it
     stays a 44px target without taking a row. */
  .banner__right { position: absolute; right: 6px; top: 50%; transform: translateY(-50%); }
  .banner__inner { padding-right: 46px; }
  .banner__inner { gap: 10px; }
  .banner__left { gap: 10px; align-items: center; }
  .banner__title { font-size: 11.5px; line-height: 1.25; }
  .banner__amount { font-size: 19px; }
}

@media (max-width: 360px) {
  .nav__inner { gap: 12px; padding-inline: 16px; }
  .nav__logo img { height: 22px; }
  .nav-btn { white-space: nowrap; font-size: 12px; padding-inline: 12px; }
  .banner__inner { padding-inline: 16px; }
  .wrap { padding-inline: 16px; }
}

/* ==========================================================================
   37. OMRI'S CUT — the homepage speaks through the video

   Client direction (2026-08-07, Omri Gazit): as little text as possible; the
   main page talks only about what the video does and the value Ludeo brings,
   with no value-prop section and no indie-programme messaging (the indie
   banner above the header is explicitly allowed). The mechanism, the studio
   rows and the FAQ moved to /for-studios, which already carried all three,
   and the homepage went from 756 words to 230. The FAQPage schema went with
   the FAQ; schema without matching content on the page is a spam signal.

   Two bands had been composed around copy that is now gone.
   ========================================================================== */

/* The moments band opens on its h2 and stops. With no supporting sentence the
   two-column band head would strand the heading in a half-width column and
   wrap it for no reason, so the solo variant gives it the full measure. */
.bandhead--solo { grid-template-columns: 1fr; }
.bandhead--solo .d2 { max-width: 20ch; }

/* The closing field held a headline, two actions and a three-step list. With
   the list gone it was 652px of amber around fourteen words. The pentagon
   watermark still holds the right side; the band just stops being taller than
   what is in it. */
.endcta { padding-block: clamp(56px, 6.5vw, 92px); }
.endcta__h { max-width: 17ch; }

/* The docs link sits in the studios hero action row as a third, quieter step:
   a developer evaluating an SDK reaches for documentation before a sales call,
   and it should not have to compete with the two filled controls beside it. */
.shero__docs { margin-left: 4px; align-self: center; }
@media (max-width: 560px) { .shero__docs { margin-left: 0; } }

/* ==========================================================================
   38. PLAY IN PLACE, AND THE THREE DOORS

   Rob Schonfeld's direction of 2026-08-18, taken with Omri and Kuper: the
   landing page should show a Ludeo and let people play it, with three doors
   below it for Studios, Players and Creators.

   That amends section 37's rule, which admitted nothing to the homepage but
   the video doing something. Doors are navigation, not a value-prop block, and
   the amendment is recorded rather than assumed.
   ========================================================================== */

/* ---------------------------------- 38.1 THE OVERLAY THIS STYLESHEET MISSED */
/* /script.js has always shipped openLudeoOverlay(): a fullscreen iframe with a
   close button, Escape, and a body scroll lock. This stylesheet carried
   .ludeo-overlay and .ludeo-overlay iframe and NOTHING for the close button,
   because nothing in the redesign opened the overlay, so no check could see it.

   Wiring play in place makes it live. Unstyled, .ludeo-overlay__close is a flex
   sibling of an iframe sized 100% x 100% inside a centering flex container: it
   gets squeezed to nothing while body scroll is locked, leaving Escape as the
   only exit. This is the same failure the missing .apply-* rules caused, and
   these class names are the same kind of contract with a file we do not own.

   Redrawn in this system rather than copied from production: a square, not the
   production circle, because nothing here is a capsule. */
.ludeo-overlay.is-full { inset: 0; }
.ludeo-overlay__close {
  position: absolute;
  top: 16px;
  right: 16px;
  z-index: 2;
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  padding: 0;
  border: 1px solid var(--line-2);
  background: rgba(6, 6, 10, 0.72);
  color: var(--text);
  font-family: var(--display);
  font-weight: 700;
  font-size: 20px;
  line-height: 1;
  text-transform: uppercase;
  cursor: pointer;
  transition: background var(--fast) var(--ease), border-color var(--fast) var(--ease);
}
.ludeo-overlay__close:hover { background: var(--amber); border-color: var(--amber); color: var(--amber-ink); }
.ludeo-overlay__close:focus-visible { outline: 2px solid var(--amber); outline-offset: 2px; }

/* --------------------------------------------- 38.2 THE HERO'S PLAYING NOTE */
/* A moment streams a real PC build and refuses every phone. The constraint is
   stated under the action where it is read before the click, not discovered by
   a visitor whose page has just been destroyed by one. */
.hero__note {
  margin-top: 14px;
  font-size: 14px;
  line-height: 1.5;
  color: var(--muted);
  max-width: 42ch;
}
.hero__note.is-handoff { color: var(--amber); }

/* ------------------------------------------------------- 38.3 THREE DOORS */
/* Same skeleton as .flow__grid: hairline cells, the leading cell flush to the
   gutter, one growing amber rule on hover. No numeral, because these are not
   steps in a sequence; they are three equal ways in, and numbering them would
   rank them. */
.doors { padding-block: clamp(72px, 9vw, 132px); background: var(--ink-0); position: relative; isolation: isolate; }
.doors > .wrap { display: block; }
.doors__grid {
  margin-top: clamp(38px, 5vw, 62px);
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  border-top: 1px solid var(--line);
}
.door {
  display: flex;
  flex-direction: column;
  padding: clamp(26px, 3vw, 40px) clamp(18px, 2.6vw, 36px) clamp(30px, 4vw, 48px);
  border-left: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  position: relative;
  overflow: hidden;
}
.door:first-child { border-left: 0; padding-left: 0; }
.door:last-child { padding-right: 0; }
.door::before {
  content: "";
  position: absolute;
  left: 0; right: 0; top: 0;
  height: 2px;
  background: var(--amber);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--slow) var(--ease);
}
.door:hover::before { transform: scaleX(1); }
.door__h {
  font-family: var(--display);
  font-weight: 800;
  text-transform: uppercase;
  font-size: clamp(26px, 3.2vw, 42px);
  line-height: 0.95;
  letter-spacing: -0.01em;
  margin-bottom: 12px;
}
.door__p {
  color: var(--muted);
  font-size: 16px;
  line-height: 1.62;
  max-width: 34ch;
}
/* The action sits at the foot of every cell regardless of how long its sentence
   runs, so the three read as one row rather than three ragged columns.

   This did not work as written. `.door__p + .door__btn` is more specific than
   `.door__btn`, so the sibling rule won and `margin-top: auto` never applied:
   each button sat wherever its paragraph happened to stop, and the Studios cell
   carries a fourth line, so its action hung ~26px below the other two. The gap
   belongs to the paragraph's bottom, not the button's top, which leaves the
   auto margin free to do the one job it was there for. */
.door__p { margin-bottom: clamp(24px, 2.8vw, 34px); }
.door__btn {
  margin-top: auto;
  align-self: flex-start;
  /* A common width turns three actions into a set. Left-aligned labels with the
     chevrons stacked in one column reads as deliberate; three widths cut to the
     length of their own words reads as an accident. */
  min-width: min(100%, 15.5rem);
  justify-content: space-between;
  gap: 18px;
}

@media (max-width: 860px) {
  .doors__grid { grid-template-columns: 1fr; }
  .door { border-left: 0; padding-inline: 0; }
}

/* -------------------------------------------------- 38.4 THE PLAYER LIBRARY */
/* The three-card arrangement leads with a wider first moment, which is right
   when three cards are the whole set and wrong when six are: it would make the
   first of two rows lopsided against the second. The library variant returns to
   equal columns and gives every card the same ratio. */
.ludeo-grid--library { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
@media (min-width: 980px) {
  .ludeo-grid--library { grid-template-columns: repeat(3, 1fr); }
  .ludeo-grid--library .lcard:first-child .lcard__stage,
  .ludeo-grid--library .lcard:not(:first-child) .lcard__stage {
    aspect-ratio: 16 / 9;
    flex: 0 0 auto;
    min-height: 0;
  }
}
.tryl__note {
  margin-top: clamp(26px, 3vw, 38px);
  font-size: 14px;
  line-height: 1.6;
  color: var(--faint);
  max-width: 62ch;
}

/* ------------------------------------------------------ 38.5 MOBILE HANDOFF */
/* On a phone the library never navigates. campaign.ludeo.com refuses mobile,
   and inside an in-app browser a navigation destroys the page and leaves no way
   back, so the link is handed over here instead. */
.handoff {
  background: var(--ink-2);
  border-block: 1px solid var(--line);
}
.handoff[hidden] { display: none; }
.handoff__inner {
  max-width: var(--wrap);
  margin: 0 auto;
  padding: clamp(26px, 4vw, 40px) var(--pad);
}
.handoff__title {
  font-family: var(--display);
  font-weight: 800;
  text-transform: uppercase;
  font-size: clamp(22px, 2.6vw, 30px);
  line-height: 1;
  margin-bottom: 10px;
}
.handoff__body { color: var(--muted); font-size: 15px; line-height: 1.6; max-width: 48ch; }
.handoff__link {
  margin: 16px 0;
  padding: 12px 14px;
  border: 1px solid var(--line);
  background: var(--ink-0);
  color: var(--amber);
  font-size: 13px;
  line-height: 1.5;
  word-break: break-all;
}

/* ==========================================================================
   39. THE LUDEO ITSELF, AND THE DEPTH THAT CARRIES IT

   Correction to section 38. That pass put a play button over gameplay footage,
   which is a trailer with a door beside it, not "a place that shows a ludeo".
   The real campaign.ludeo.com moment is now embedded in the hero, in front of
   the footage, and the page's one authored motion is the panel standing up out
   of that footage to face the reader.
   ========================================================================== */

/* ------------------------------------------------------- 39.1 BUTTONS, AGAIN */
/* The old control spoke 14px Sora beneath a 72px condensed-uppercase headline:
   a foreign voice in its own page, and the only component on the site whose
   hover was a plain colour swap while every link, tab and grid cell used the
   growing amber rule. Both are fixed here. Box model is unchanged, so no
   layout on any route moves. */
.btn,
.hero__btn {
  font-family: var(--display);
  font-weight: 700;
  font-size: 17px;
  line-height: 1;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 17px 28px;
  position: relative;
  overflow: hidden;
}
/* Correction to an earlier note: buttons already carried the growing rule.
   Section 30.3 built it, in `currentColor`. What changes here is only the
   colour, because DESIGN.md names this gesture as an amber rule and on a ghost
   button currentColor resolves to white, which is the one place the system drew
   its own signature in the wrong ink. Geometry stays 30.3's. */
.btn::after,
.hero__btn::after { background: var(--amber); opacity: 1; }
/* On an amber fill an amber rule is invisible, so that variant darkens its own
   foot instead; inside the amber band the primary inverts to ink and the rule
   goes back to amber. */
.btn--amber::after { background: var(--amber-ink); }
.endcta .btn--amber::after { background: var(--amber); }
.btn--ghost:hover { border-color: var(--text); }
.btn .btn-play-mark,
.hero__btn .btn-play-mark { width: 14px; height: 14px; }
.btn--amber .btn-play-mark { background: var(--amber-ink); }

/* ------------------------------------------------------------- 39.2 THE STAGE */
/* Perspective lives on the host so the rotating plane never also carries the
   hairline: a border on a rotated element renders soft, and this system's
   hairlines are the structure. */
.stage {
  perspective: 1400px;
  perspective-origin: 50% 40%;
  margin-top: clamp(26px, 3.4vw, 40px);
  max-width: 720px;
}
.stage__deck {
  --p: 1; /* resting state is upright: no JS, no motion, no tilt */
  transform:
    translateY(calc((1 - var(--p)) * 26px))
    rotateX(calc((1 - var(--p)) * 13deg))
    scale(calc(0.965 + var(--p) * 0.035));
  transform-origin: 50% 100%;
  will-change: transform;
}
.stage__frame {
  position: relative;
  aspect-ratio: 16 / 9;
  background: #000;
  border: 1px solid var(--line-2);
  overflow: hidden;
}
.stage__art {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  transition: opacity var(--slow) var(--ease);
}
.stage__slot { position: absolute; inset: 0; }
.stage__live { width: 100%; height: 100%; border: 0; display: block; }
/* Once the moment answers, the still it was standing in for gets out of its way
   and the cue stops offering to start something already running. */
.stage.is-live .stage__art { opacity: 0; }
.stage.is-live .stage__cue { opacity: 0; pointer-events: none; }

/* The cue is the affordance while the frame is still arriving, and the whole
   frame is the target: a small button on a large panel reads as the only live
   part of it. */
.stage__cue {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  padding: 0;
  border: 0;
  background: linear-gradient(180deg, rgba(6, 6, 10, 0.15), rgba(6, 6, 10, 0.62));
  color: var(--text);
  cursor: pointer;
  font-family: var(--display);
  font-weight: 700;
  font-size: 17px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  transition: opacity var(--mid) var(--ease), background var(--mid) var(--ease);
}
.stage__cue:hover { background: linear-gradient(180deg, rgba(6, 6, 10, 0.05), rgba(6, 6, 10, 0.45)); }
.stage__cue-mark {
  width: 26px; height: 26px; flex: none;
  background: var(--amber);
  -webkit-mask: url("/media/brand/Ludeo pentagon logo.svg") center / contain no-repeat;
  mask: url("/media/brand/Ludeo pentagon logo.svg") center / contain no-repeat;
  transition: transform var(--mid) var(--ease);
}
.stage__cue:hover .stage__cue-mark { transform: scale(1.12); }
.stage__cue:focus-visible { outline: 2px solid var(--amber); outline-offset: -4px; }

/* The moment names itself under its own frame. Text, not a chip. */
.stage__meta {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 12px;
  font-size: 13px;
  color: var(--faint);
}
.stage__game { color: var(--text); font-weight: 600; }
.stage__dot { width: 3px; height: 3px; background: var(--faint); flex: none; }

/* ------------------------------------------------------- 39.3 THE MOMENT BAND
   The embed spent one build inside the hero. It cost the headline half its
   scale, put a queue timer in the first impression, and asked a cold visitor to
   read a game UI before they knew whose game it was. A hero states the claim;
   it cannot also be the proof. So the hero is back to full scale and untouched,
   and the moment has the room directly beneath it, which is still "below that,
   three boxes" in the right order: claim, proof, then the three ways in. */
.moment {
  padding-block: clamp(64px, 8vw, 116px);
  background: var(--ink-0);
  position: relative;
  isolation: isolate;
}
.moment > .wrap { display: block; }
.moment .stage {
  margin-top: clamp(30px, 4vw, 46px);
  max-width: 100%;
}
/* The frame gets the full measure here. In the hero it was capped at 920px to
   clear the fold; in its own band nothing is competing for the height. */
.moment .stage__frame { border-color: var(--line-2); }

/* Identity on the left, the way out on the right, on one baseline under the
   frame. */
.moment__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  flex-wrap: wrap;
  margin-top: 16px;
}
.moment__foot .stage__meta { margin-top: 0; }
.moment__actions { display: flex; gap: 12px; }
.moment__note {
  margin-top: 14px;
  font-size: 14px;
  line-height: 1.6;
  color: var(--faint);
  max-width: 62ch;
}
.moment__note.is-handoff { color: var(--amber); }

/* ------------------------------------------------------------- 39.4 THE DOORS
   take the same depth in a quieter register, so the page has one spatial idea
   rather than an effect in the hero and a different one below it. */
.has-depth .doors__grid { perspective: 1600px; perspective-origin: 50% 30%; }
.has-depth .door {
  --p: 1;
  transform:
    translateY(calc((1 - var(--p)) * 18px))
    rotateX(calc((1 - var(--p)) * 7deg));
  transform-origin: 50% 100%;
}

/* Depth is an enhancement, never a requirement. Anything that cannot or should
   not carry it simply sits flat, which is the resting state anyway. */
@media (prefers-reduced-motion: reduce) {
  .stage__deck, .has-depth .door { transform: none; }
}
@media (pointer: coarse) {
  .stage { perspective: none; }
  .stage__deck, .has-depth .door { transform: none; }
}


/* Depth is an enhancement, never a requirement. Anything that cannot or should
   not carry it simply sits flat, which is the resting state anyway. */
@media (prefers-reduced-motion: reduce) {
  .stage__deck, .has-depth .door { transform: none; }
}
@media (pointer: coarse) {
  .stage { perspective: none; }
  .stage__deck, .has-depth .door { transform: none; }
}

/* --------------------------------------------- 39.5 THE COMPARATOR'S HEADING
   The figure used to sit under the definition band and borrow its h2. That band
   went out in Omri's cut, so the band was left headless, which the system does
   not allow: every band opens on its own h2. It gets the room back, and only
   above the stage, so the figure stays edge to edge. */
.swapband { padding-block: clamp(64px, 8vw, 116px) 0; }
.swapband__head { margin-bottom: clamp(30px, 4vw, 46px); }

/* ==========================================================================
   40. SOCIAL PROOF MOVES INTO THE HERO

   Emily, 2026-08-18: "social proof should be in the hero above the fold."
   It was a standalone band four screens down, which is where proof goes to be
   missed. A hundred studios including KRAFTON, IO Interactive and Starbreeze is
   the strongest thing this page owns and it was arriving after the argument had
   already been made.
   ========================================================================== */

/* First attempt put the strip inside the headline's wrap, where it sat on bare
   gameplay: the marks were near invisible against a lit desert and the marquee
   clipped through a logo at the gutter. Marks are images, so the system's
   "try a text-shadow before darkening the video" rule has nothing to offer
   here. It gets a real ground instead, full width, which is a scrim over media
   and therefore inside the permitted gradient set. */
.hero__media { flex-direction: column; align-items: stretch; justify-content: flex-end; }
.hero__logos {
  position: relative;
  z-index: 2;
  padding: clamp(16px, 2vw, 24px) var(--pad) clamp(16px, 2vw, 22px);
  background: linear-gradient(180deg, rgba(6, 6, 10, 0) 0%, rgba(6, 6, 10, 0.74) 16%, rgba(6, 6, 10, 0.93) 44%, rgba(6, 6, 10, 0.97) 100%);
}
.hero__logos .logos__wrap {
  max-width: var(--wrap);
  margin-inline: auto;
  padding: 0;
}
.hero__logos .logos__inner { padding: 0; margin: 0; max-width: none; }
.hero__logos .logos__title {
  font-size: 12px;
  letter-spacing: 0.16em;
  text-align: left;
  margin: 0 0 clamp(10px, 1.4vw, 15px);
  max-width: 58ch;
  color: var(--muted);
}
.hero__logos .logos__item img { height: 24px; opacity: 0.95; }
.hero__logos .logos__group { gap: clamp(26px, 3.4vw, 46px); }
/* The fades work again now that the strip has ink behind it, and they are what
   stops the marquee cutting a mark in half at the gutter. */
.hero__logos .logos__fade { width: clamp(28px, 4vw, 56px); }

@media (max-width: 700px) {
  .hero__logos { padding-top: 14px; }
  .hero__logos .logos__item img { height: 19px; }
}

/* ----------------------------------------- 40.1 PROOF HAS TO CLEAR THE FOLD */
/* Moving the logos into the hero only counts if they are visible on arrival,
   and at 1440x900 they finished 10px under the fold, at 1366x768 a full 122px
   under it. Proof below the fold is proof nobody has.

   The headline gives up the difference, and only on short viewports: the full
   96px hero survives everywhere it fits. Height-based, not width-based, because
   this is a vertical budget and a wide short laptop is the case that breaks. */
@media (min-width: 1100px) and (max-height: 940px) {
  .hero__overlay { padding-block: clamp(28px, 3.4vh, 42px) clamp(18px, 2.4vh, 26px); }
  .hero__title { font-size: clamp(40px, 5.4vw, 70px); }
  .hero__sub { margin-top: 14px; }
}
@media (min-width: 1100px) and (max-height: 810px) {
  .hero__title { font-size: clamp(38px, 4.4vw, 56px); }
  .hero__sub { font-size: 16px; }
  .hero__logos .logos__title { margin-bottom: 9px; }
  .hero__logos .logos__item img { height: 21px; }
}

/* ------------------------------------------- 41. THE COMPARATOR'S TWO HANDS
   Emily, 2026-08-18: "there needs to be a button on the playable moment and a
   pause on the left as if its a real video when you hover."

   Right, and it is the sharpest thing on the figure. The comparison stops being
   a caption and becomes an experience: reach into the left half and the only
   control you are offered is the one a recording can honour, which is stop.
   Reach into the right and you are offered a way in, and it is real, opening
   the same moment the band below runs.

   Both controls live on the stage, not inside the clipped halves, and centre on
   their half with calc against the seam, so the divider can move anywhere
   without cutting a button in half. Above the range input, which owns the rest
   of the surface for dragging. */
.swap__act {
  position: absolute;
  top: 50%;
  z-index: 6;
  transform: translate(-50%, -50%) scale(0.94);
  opacity: 0;
  pointer-events: none;
  border-radius: 0;
  cursor: pointer;
  transition: opacity 200ms var(--ease), transform 200ms var(--ease),
              background 200ms var(--ease), border-color 200ms var(--ease);
}
.swap__act--pause { left: calc(var(--x) / 2); }
/* Appears when the pointer is anywhere over the watching half. The playing
   half's control is `.swap__go`, which the stylesheet already owned; only the
   pause is new. */
.swap__stage:hover .swap__act--pause,
.swap__act--pause:focus-visible {
  opacity: 1;
  pointer-events: auto;
  transform: translate(-50%, -50%) scale(1);
}
.swap__stage.is-hot .swap__act--pause { opacity: 0; pointer-events: none; }

/* The watching control is player chrome, so it takes a video player's language
   rather than the brand's: neutral, quiet, no amber. Amber on this side would
   promise something the left half cannot do. */
.swap__act--pause {
  width: clamp(52px, 5vw, 64px);
  height: clamp(52px, 5vw, 64px);
  display: grid;
  place-items: center;
  padding: 0;
  border: 1px solid rgba(255, 255, 255, 0.5);
  background: rgba(6, 6, 10, 0.55);
}
.swap__act--pause:hover { background: rgba(6, 6, 10, 0.78); border-color: #fff; }
.swap__act-bars {
  width: 15px; height: 19px;
  border-left: 5px solid rgba(255, 255, 255, 0.94);
  border-right: 5px solid rgba(255, 255, 255, 0.94);
}
/* Paused, it offers the way back, drawn as a triangle from one border. */
.swap__act--pause.is-paused .swap__act-bars {
  width: 0; height: 0;
  border-left: 17px solid rgba(255, 255, 255, 0.94);
  border-right: 0;
  border-top: 10px solid transparent;
  border-bottom: 10px solid transparent;
  margin-left: 4px;
}

/* The playing control is the brand's, because this half is the product. */
.swap__act--play {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 15px 24px;
  border: 1px solid transparent;
  background: var(--amber);
  color: var(--amber-ink);
  font-family: var(--display);
  font-weight: 700;
  font-size: 17px;
  line-height: 1;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
}
.swap__act--play:hover { background: var(--amber-hi); }
.swap__act--play .btn-play-mark { background: var(--amber-ink); width: 15px; height: 15px; }
.swap__act:focus-visible { outline: 2px solid var(--amber); outline-offset: 3px; opacity: 1; pointer-events: auto; transform: translate(-50%, -50%) scale(1); }

/* No hover on a touch screen, so the way in is simply always offered, and the
   pause is not: a control that only appears on a gesture the device does not
   have is a control that does not exist. */
@media (pointer: coarse) {
  .swap__act--play { opacity: 1; pointer-events: auto; transform: translate(-50%, -50%) scale(1); font-size: 15px; padding: 13px 18px; }
  .swap__act--pause { display: none; }
}
@media (max-width: 560px) {
  .swap__act--play { font-size: 13px; padding: 11px 14px; gap: 7px; }
}

/* -------------------------------------- 42. THE TWO WORDS HAVE TO CARRY IT
   Emily: "the watching and playing needs to be more clear." They were 11px
   tracked labels in the corners, which is player-chrome scale, and the whole
   figure turns on the reader registering those two words. They take the
   display face and the scale of a heading, one centred on each half so they
   move with the divider and always name the side you are looking at. */
.swap__tag {
  left: calc(var(--x) / 2);
  right: auto;
  top: clamp(20px, 4vw, 46px);
  transform: translateX(-50%);
  font-family: var(--display);
  font-weight: 800;
  font-size: clamp(24px, 3.4vw, 52px);
  line-height: 1;
  letter-spacing: 0.02em;
  color: rgba(255, 255, 255, 0.5);
  text-shadow: 0 2px 24px rgba(0, 0, 0, 0.95);
  transition: color var(--mid) var(--ease);
  white-space: nowrap;
}
.swap__tag--live {
  left: calc((100% + var(--x)) / 2);
  right: auto;
  color: var(--amber);
}
/* The side under the pointer says so. */
.swap__stage.is-hot .swap__tag--live { color: var(--amber-hi); }

/* The legend under the frame measures the seam, so it stays, but at a size that
   reads as a readout rather than competing with the words on the frame. */
.swap__leg { font-size: 12px; letter-spacing: 0.2em; }

/* ------------------------------------------------ 42.1 THE LOGOS WERE TINY */
/* At 24px the marks were smaller than the line of type above them, which
   inverts the point: the studios are the proof, the sentence is the caption. */
.hero__logos .logos__item img { height: 38px; }
.hero__logos .logos__group { gap: clamp(34px, 4.4vw, 62px); }
@media (max-width: 1100px) { .hero__logos .logos__item img { height: 32px; } }
@media (max-width: 700px)  { .hero__logos .logos__item img { height: 26px; } }
@media (min-width: 1100px) and (max-height: 810px) { .hero__logos .logos__item img { height: 30px; } }

/* ══════════════════════════════════════════════ 43. THE MOTION LAYER, RAISED */
/* Section 19 authored the reveal and 21.5 the choreography on top of it, but
   both were driven by a script that lived inline on the homepage. Six routes
   therefore shipped with the rules present and nothing to trigger them. The
   driver is now the shared _motion.html partial; these are the two things that
   needed changing once it actually ran everywhere. */

/* --------------------------------------------------- 43.1 A LONGER ARRIVAL */
/* 18px over 460ms reads as a settle, not an arrival, which is why even the one
   page that did carry the layer felt still. The curve and the duration are
   untouched; only the distance is. */
@media (prefers-reduced-motion: no-preference) {
  .reveal { transform: translateY(28px); }
}

/* ------------------------------------------ 43.2 THE WALL THAT NEVER MOVED */
/* /script.js module 12 drives the partner marquee from a rAF on every route
   that loads it. /creators does not load it, and its wall has been a static row
   inside a box named marquee since the page was authored. The partial clones a
   second group there only when nothing else has, then hands the travel to CSS.

   -50% is exactly one group because the clone doubles the track and the items
   carry their own symmetric padding-inline. The one wall that spaces its marks
   with a gap on the group instead (.hero__logos, section 42.1) is on a route
   that loads /script.js, so it never reaches this rule.

   Hover pauses. /script.js's version has no pause mechanism, which is a WCAG
   2.2.2 gap on moving content; not replicating it is deliberate, and pausing is
   the same gesture the marks already answer to, since the wall lifts to full
   opacity on hover so a reader can settle on one. */
@media (prefers-reduced-motion: no-preference) {
  .logos__track.is-looping {
    animation: logos-travel var(--logos-dur, 48s) linear infinite;
  }
  .logos__marquee:hover .logos__track.is-looping,
  .logos__marquee:focus-within .logos__track.is-looping { animation-play-state: paused; }
}

@keyframes logos-travel {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}

/* ═════════════════════════════════════════════ 44. THE DOORS GET SOMETHING TO SEE */
/* 38.3 built the doors as hairline cells of pure type, and at rest the whole
   band carried no accent at all: .door::before is scaleX(0) until hover, so a
   visitor who never moves the pointer reads three interchangeable grey columns.
   A door is media and an independently linked item, which is exactly the case
   DESIGN.md exempts from "no cards as page structure", so art is admissible
   here where it would not be in a feature grid.

   The art caps the cell above the heading rather than sitting behind the copy.
   Body text over key art would need a scrim heavy enough to be the thing you
   see, and the rule is to try a local text-shadow before darkening a scrim; a
   full-bleed art cell under copy would also be card-as-structure, which is the
   banned pattern rather than the exempt one.

   Each image is a game from a studio already named on the logo wall above
   (Relic, Payday, Bloober), so the band argues rather than dresses. */
.door__art {
  position: relative;
  aspect-ratio: 16 / 10;
  overflow: hidden;
  margin-bottom: clamp(20px, 2.4vw, 30px);
}
.door__art img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* The permitted kind of gradient: a scrim over media, resolving into the exact
   ground the band is painted on, so the frame fades out instead of ending on a
   hard edge above the heading. */
.door__art::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, var(--ink-0), transparent 46%);
  pointer-events: none;
}

/* The same gesture the moment cards already use for their stage video, at the
   same duration the system reserves for video scale. No new vocabulary, and the
   amber rule on .door::before stays the primary hover signal. */
@media (prefers-reduced-motion: no-preference) {
  .door__art img { transition: transform var(--slow) var(--ease); }
  .door:hover .door__art img { transform: scale(1.045); }
}

/* -------------------------------------- 44.1 THREE PANELS, ONE SIZE */
/* Caught on the first render: the art came out 340 / 303 / 339px wide at 1440.
   38.3 drops padding-left on the leading cell and padding-right on the trailing
   one so the type lines up with the page gutter, which means the three content
   boxes were never the same width. Invisible while every cell held a paragraph
   clamped to 34ch; obvious the moment something filled the box.

   So the art spans the grid cell rather than the content box: it bleeds back
   out through the padding on the sides that have it, and to the cell's top
   edge, which also gives the band the filmstrip it was missing. The type stays
   inset and keeps the gutter alignment 38.3 wanted. All three panels are now
   exactly one column wide. */
.door {
  --door-px: clamp(18px, 2.6vw, 36px);
  --door-pt: clamp(26px, 3vw, 40px);
}
.door__art {
  margin-top: calc(var(--door-pt) * -1);
  margin-inline: calc(var(--door-px) * -1);
}
.door:first-child .door__art { margin-left: 0; }
.door:last-child .door__art { margin-right: 0; }

/* The amber hover rule is a pseudo-element of the cell and the art is a child,
   so on source order alone the art paints over it and the primary hover signal
   disappears under a picture. Both are positioned, so one z-index settles it,
   and the rule now draws across the top of the art, which is a better gesture
   than a line hovering above empty padding. */
.door::before { z-index: 2; }

/* Stacked, the cells have no inline padding to bleed back out of. */
@media (max-width: 860px) {
  .door__art { margin-inline: 0; }
}

/* ══════════════════════════════════ 45. THE COMPARATOR IS A FRAME, NOT A BLEED */
/* Section 30 took the comparator full bleed: border dropped to a single top
   rule, stage re-cropped to 2.32/1, legend at 100vw, and the caption pushed out
   to the band's outer padding because "in a full-bleed band the outer padding is
   the measure". It made the figure the only element on the page that did not sit
   on the page's own grid: stage 1440px against 1128px for the band heads, the
   doors and every paragraph.

   Boxed, it sits in the wrap like everything else, and the caption problem
   solves itself. That caption was never misaligned on the left (156px, matching
   the doors exactly); it was set 1040px wide, roughly 130 characters a line,
   which is why the last two words fell off on their own. */
.swap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--pad);
}
/* The figcaption carries .wrap from the full-bleed layout. Nested inside a
   .swap that is now itself a wrap, it would indent the caption by a second
   --pad and miss the frame's left edge by 56px. */
.swap .wrap { max-width: none; padding-inline: 0; margin-inline: 0; }

.swap__stage {
  aspect-ratio: 16 / 9;
  border: 1px solid var(--line);
}
/* Restated after the ratio above, which is unmediated and would otherwise beat
   the narrow-viewport crop authored back in section 22. */
@media (max-width: 700px) {
  .swap__stage { aspect-ratio: 4 / 3; }
}

/* The legend measures the seam by sharing the stage's width, which still holds
   now that both are the box rather than the viewport. What does not survive is
   the leading label's --pad indent: that existed to meet the page gutter across
   a full-bleed band, and inside the frame it just pushes the word off the edge
   it is supposed to mark. */
.swap__leg--watch { padding-left: 0; }

/* A readable measure, and no outer-padding compensation now that the caption's
   container is the frame. */
.swap__cap {
  padding-inline: 0;
  max-width: 68ch;
  margin: clamp(18px, 2.2vw, 26px) 0 clamp(44px, 5.5vw, 76px);
}

/* -------------------------------- 45.1 THE CAPTION MEASURE WAS NEVER APPLIED */
/* `.swap__cap` is a <span>, and max-width does not apply to a non-replaced
   inline element. Section 22 set `max-width: 68ch` on it and section 30 set
   `calc(70ch + var(--pad))`; both have been inert since the day they were
   written, so the caption has always run the full width of whatever contained
   it, which is how it reached 1040px, about 130 characters a line, with the
   closing two words stranded on a line of their own.
   One declaration makes every max-width authored above it real. */
.swap__cap { display: block; }

/* ═══════════════════════════════════════ 46. THE ROTATING WORD, FASTER AND LIT */
/* The headline's swapping word was a plain vertical slide of a stacked list
   behind a 1em clip, over 500ms on the system's heavy ease-out. On that curve
   most of the travel happens up front and the last third crawls, which is what
   read as slow. The cadence itself (2000ms) lives in /script.js module 2 and
   exposes no timer id, so it is not ours to retime; the transition is. */
.word-switch__list { transition: transform 0.22s var(--ease); }

/* Each letter of the incoming word rises into place behind the same 1em clip
   that already masks the list, on a short stagger. Transform and opacity only,
   one curve, and the whole thing is an enhancement: without JS the words are
   plain text and without motion nothing animates at all.

   inline-block is required rather than stylistic. Transforms do not apply to
   non-replaced inline elements, which is the same rule that had .swap__cap's
   max-width doing nothing for two sections. */
@media (prefers-reduced-motion: no-preference) {
  .ws-ch { display: inline-block; }
  .word-switch__item.is-swap .ws-ch {
    animation: ws-rise 190ms var(--ease) both;
    animation-delay: calc(var(--c, 0) * 16ms);
  }
}

@keyframes ws-rise {
  from { transform: translateY(0.42em); opacity: 0; }
  to   { transform: none; opacity: 1; }
}


/* ══════════════════════════════════════ 46. THE PLAYERS HERO, SUPERSEDED

   Section 46 built /players its own full-bleed hero: the studio's footage as
   the ground, the headline at full scale on top, a credit band at the foot.
   It answered Emily's 2026-08-18 note, "the HERO is boring and uninviting",
   which was aimed at the shared `.phead` interior header the route used to run.

   Emily, later the same day: the players page should carry the same hero as the
   other inner pages. Section 47 is that hero, and /players now runs it, so the
   route no longer has a component of its own. Every rule this section held was
   scoped to `.hero--players`, `.hero__foot`, `.hero__ident`, `.hero__more` or
   `.hero__still`, none of which survive in any built page, so they are removed
   rather than left to read as live.

   What the original note was actually about is preserved: /players does not go
   back to two lines of type over bare black. Its masthead opens on a real
   moment, looping, with the play verb as its primary control. What it gives up
   is the full-bleed ground, and that was the trade the consistency request
   asked for. The homepage keeps `.hero`, and is now the only route that runs it.
   ========================================================================== */

/* ============================================================ 47. THE INNER-PAGE MASTHEAD
   What the studios hero actually shipped: the left column ran headline, sub,
   stat rack and controls, while the right ran a moment card that ends 270px
   earlier. `.shero__right` stretched and `.shero__ticks` took `margin-top:auto`
   to pin its proof to the column floor, which is a fine device when the two
   columns are close in height and a hole when they are not. Measured at
   1440x900 the hole was 109px of nothing, and the primary CTA sat at y=1200
   inside a 900px viewport: a conversion page whose action was below the fold.

   The fix is structural, not cosmetic. The numbers leave the left column and
   become a rail spanning the whole grid, so the composition is tied together by
   a horizontal beam instead of two columns drifting apart, and neither column
   has to stretch to meet the other. Section 47 is shared by /for-studios,
   /creators and /players, which is why /players stops running the homepage's
   full-bleed hero: one masthead, three payloads. */

/* ------------------------------------------------- 47.1 THE TYPE WAS TOO BIG */
/* 88px condensed over a 544px column set the studios headline in four lines,
   690px of it, which is most of the fold spent before a single claim. 66px
   breaks the same sentence in three and buys back ~180px for the things that
   actually convert. Tracking tightens with the size, per the display ramp. */
.shero__title {
  font-size: clamp(38px, 5vw, 66px);
  letter-spacing: -0.022em;
  max-width: 19ch;
}
.shero__sub { margin-top: 18px; max-width: 44ch; }

/* ------------------------------------------------------- 47.2 CLOSING THE HOLE */
/* Both fixes are removals. The right column no longer stretches to the left
   column's height, and its proof sits directly under the card it belongs to
   rather than being thrown at the floor. */
.shero__grid { align-items: start; row-gap: clamp(30px, 4vw, 54px); }
.shero__right { align-self: start; }
.shero__ticks { margin-top: clamp(16px, 2vw, 22px); padding-top: clamp(14px, 1.8vw, 18px); }
.shero__tick { padding: 11px 0; gap: 14px; }
.shero__tick b { min-width: 108px; }

/* ------------------------------------------------------------- 47.3 THE RAIL */
/* The stats, out of the left column and across the whole grid. Subgrid is what
   makes it hold: prefix, figure and caption each get a shared row track, so the
   numerals sit on one baseline and the captions start on one line even when
   only one cell carries a prefix and the captions run to different depths. */
.shero__rail {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  grid-template-rows: auto auto auto;
  border-top: 1px solid var(--line);
}
.shero__rail .sstat {
  display: grid;
  grid-row: 1 / -1;
  grid-template-rows: subgrid;
  row-gap: 0;
  align-content: start;
  padding: clamp(16px, 1.9vw, 22px) clamp(12px, 1.5vw, 20px) 0;
  border-left: 1px solid var(--line);
}
.shero__rail .sstat:first-child { border-left: 0; padding-left: 0; }
.shero__rail .sstat:last-child { padding-right: 0; }
/* The prefix is a line of its own now. Inline beside a 54px numeral it broke
   the optical left edge of the first cell, so the three figures never lined up
   with each other however carefully the rack was spaced. */
/* The three parts name their own row rather than taking the next free one.
   Left implicit, a cell with no prefix put its figure in the prefix's row, so
   the numerals sat on two different lines and the captions on two more: the
   exact misalignment the rack had before, rebuilt in a new mechanism. */
.shero__rail .sstat__pre { grid-row: 1; }
.shero__rail .sstat__fig { grid-row: 2; }
.shero__rail .sstat__cap { grid-row: 3; }
.shero__rail .sstat__pre {
  display: block;
  font-size: 12px;
  line-height: 1.1;
  padding-bottom: 7px;
  color: var(--faint);
}
.shero__rail .sstat__fig { align-items: baseline; font-size: clamp(27px, 2.9vw, 38px); }
.shero__rail .sstat__cap { padding-top: 8px; font-size: 12.5px; }

/* ------------------------------------------------- 47.3b THE COLUMN THAT ENDED
   With the headline down to three lines the copy column now finishes well above
   the media column on all three routes: measured at 1440x900 the shortfall ran
   from 190px on /for-studios to 460px on /players, all of it dead space in the
   bottom left of the fold. Rather than stretch either column to meet the other,
   the rail drops into exactly that gap and the media spans both rows. The hero
   becomes an L, the void becomes the numbers, and nothing has to be padded. */
@media (min-width: 901px) {
  .shero__grid { grid-template-rows: auto 1fr; }
  .shero__left  { grid-column: 1; grid-row: 1; }
  .shero__rail  { grid-column: 1; grid-row: 2; align-self: end; }
  .shero__right { grid-column: 2; grid-row: 1 / span 2; }
}

@media (max-width: 760px) {
  .shero__rail { grid-template-columns: 1fr; grid-template-rows: none; }
  .shero__rail .sstat {
    grid-row: auto;
    grid-template-rows: none;
    border-left: 0;
    border-top: 1px solid var(--line);
    padding: 15px 0;
  }
  .shero__rail .sstat__pre,
  .shero__rail .sstat__fig,
  .shero__rail .sstat__cap { grid-row: auto; }
  .shero__rail .sstat:first-child { border-top: 0; padding-top: 4px; }
  .shero__rail .sstat__cap { max-width: none; }
}

/* --------------------------------------------------------- 47.4 ONE CONTROL VOICE */
/* The row shipped three: a Sora sentence-case amber fill, a Barlow Condensed
   uppercase ghost, and a Sora text link, all at once. Section 39 already ruled
   that this site's control voice is the condensed uppercase one and migrated
   `.btn`; `.shero__btn` was simply never brought along. The templates now use
   `.btn` directly, so the rule below only has to hold the row itself. The text
   link stays a text link: three tiers of one voice is hierarchy, three voices
   is noise. */
.shero__cta-row { align-items: center; gap: 14px; margin-top: clamp(24px, 3vw, 34px); }
.shero__docs { margin-left: 6px; align-self: center; }

@media (max-width: 560px) {
  .shero__cta-row { gap: 12px; }
  .shero__cta-row .btn { width: 100%; }
  .shero__docs { margin-left: 0; }
}

/* ============================================================ 48. FOUR NOTES FROM OMRI
   2026-08-19. Four comments on the redesign, and between them they move where
   three arguments live rather than restyle any of them:

   1. /for-studios argues value and what a studio can actually do. The Indie
      Program leaves it entirely and keeps its header access through the banner.
   2. The numbers, results and testimonials get a room of their own at
      /use-cases, the way Sett splits case studies off its product page.
   3. /tech exists, marked Coming Soon, and carries the mechanism rather than
      the integration steps.
   4. The three doors on the homepage stay exactly as they are; only the
      Players door changes destination.

   Everything below is the type and the rules those rooms need. No new colour,
   no new font, no pill: sections 1 through 47 already settled all three. */

/* ---------------------------------------------------- 48.1 WHAT YOU CAN DO
   The playbook on /for-studios. This shipped first as seven bordered cards on
   paper-2, which is exactly the tray of floating tiles the overview forbids.
   Now it is one ruled sheet: a 1px-gap grid whose background is the hairline
   color, so the rulings are drawn by the grid itself, and the tier labels are
   full-width paper-2 strips inside the same sheet, like the group rows of a
   ledger. Six columns rather than three because the tiers hold 3, 2 and 2
   recipes: at span 2 / span 3 / span 3 every row fills the sheet exactly and
   no cell is ever a hairline-colored hole. */
.dogrid {
  margin-top: clamp(34px, 4vw, 52px);
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 1px;
  background: var(--paper-line);
  border: 1px solid var(--paper-line);
}
.dotier {
  grid-column: 1 / -1;
  display: flex;
  align-items: baseline;
  gap: 14px;
  padding: 13px clamp(18px, 2.2vw, 26px);
  background: var(--paper-2);
}
/* A label on a rule, not a chip. This site does not do badge pills. */
/* DESIGN.md calibrates `--paper-kick` against `--paper`, where it measures
   4.75:1. The tier strips introduced here are `--paper-2`, a step darker, and
   the same ochre lands at 4.46:1 there: under AA by four hundredths, on a
   label. Rather than move a brand token every legal page depends on, the strip
   gets an ochre calibrated for its own ground. 4.8:1 on `--paper-2`. */
.dotier__k {
  font-family: var(--display);
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: #8f5b19;
}
.dotier__v { font-size: 13px; color: var(--paper-faint); }

.doc {
  grid-column: span 2;
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: clamp(20px, 2.2vw, 28px);
  background: var(--paper);
}
/* Recipes four through seven sit two to a row under their tier strips. */
.dogrid .doc:nth-of-type(n + 4) { grid-column: span 3; }
.doc__n {
  font-family: var(--display);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.14em;
  color: var(--paper-faint);
}
.doc__h {
  font-family: var(--display);
  font-size: clamp(21px, 2.1vw, 26px);
  font-weight: 700;
  line-height: 1.1;
  letter-spacing: -0.005em;
  color: var(--paper-ink);
  text-wrap: balance;
}
.doc__p { font-size: 15px; line-height: 1.62; color: var(--paper-muted); }
/* The meta line sits on the card floor whatever the copy above runs to, so the
   seven effort figures read as a column instead of seven loose lines. */
.doc__m {
  margin-top: auto;
  padding-top: 14px;
  border-top: 1px solid var(--paper-line);
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 9px;
  font-size: 12.5px;
  color: var(--paper-faint);
}
.doc__dot { width: 3px; height: 3px; border-radius: 50%; background: currentColor; opacity: 0.55; }
.doc__free { color: var(--ok); font-weight: 600; }
.doc__paid { color: var(--paper-kick); font-weight: 600; }

.do__foot {
  margin-top: clamp(26px, 3vw, 38px);
  max-width: 78ch;
  font-size: 15.5px;
  line-height: 1.68;
  color: var(--paper-muted);
}
.band:not(.band--paper) .do__foot { color: var(--muted); }

/* Two per row on tablet. The third starter recipe takes the full row rather
   than leaving a hole in the sheet: with an odd count, something must. */
@media (max-width: 1000px) {
  .dogrid .doc { grid-column: span 3; }
  .dogrid .doc:nth-of-type(3) { grid-column: 1 / -1; }
}
@media (max-width: 680px) {
  .dogrid .doc, .dogrid .doc:nth-of-type(n) { grid-column: 1 / -1; }
}

/* --------------------------------------------------------- 48.2 THE CASES
   /use-cases. A case is a claim plus the honest expectation attached to it, so
   it is a row with the label left and both paragraphs right, the same shape
   `.def__row` uses for the technical facts. Sett runs one card per named
   customer; these are plays until Ludeo clears named results, and the "what to
   expect" line is exactly where a real one lands when it does. */
.cases { margin-top: clamp(34px, 4vw, 52px); border-top: 1px solid var(--paper-line); }
.case {
  display: grid;
  grid-template-columns: minmax(190px, 0.9fr) minmax(0, 2.1fr);
  gap: clamp(20px, 3vw, 48px);
  padding-block: clamp(26px, 3vw, 40px);
  border-bottom: 1px solid var(--paper-line);
}
.case__head { display: flex; align-items: baseline; gap: 12px; }
.case__n {
  font-family: var(--display);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.14em;
  color: var(--paper-faint);
  padding-top: 3px;
}
.case__h {
  font-family: var(--display);
  font-size: clamp(23px, 2.4vw, 31px);
  font-weight: 700;
  line-height: 1.06;
  letter-spacing: -0.008em;
  color: var(--paper-ink);
  text-wrap: balance;
}
.case__body { display: flex; flex-direction: column; gap: 14px; }
.case__p { font-size: 16px; line-height: 1.66; color: var(--paper-muted); max-width: 66ch; }
/* The expectation is set apart because it is the part allowed to be
   unflattering. A rule rather than a tinted box: the caveat should read as
   part of the argument, not as a warning label bolted onto it. */
.case__x {
  padding-left: clamp(14px, 1.6vw, 20px);
  border-left: 2px solid var(--paper-kick);
  font-size: 15px;
  line-height: 1.64;
  color: var(--paper-muted);
  max-width: 66ch;
}
.case__x b {
  display: block;
  margin-bottom: 4px;
  font-family: var(--display);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--paper-kick);
}
.case__m {
  grid-column: 2;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  font-size: 12.5px;
  color: var(--paper-faint);
}
.case__dot { width: 3px; height: 3px; border-radius: 50%; background: currentColor; opacity: 0.55; }
.case__paid { color: var(--paper-kick); font-weight: 600; }

@media (max-width: 860px) {
  .case { grid-template-columns: 1fr; gap: 16px; }
  .case__m { grid-column: 1; }
}

/* --------------------------------------------------------- 48.3 THE QUOTES
   Six real lines with the handles they were posted under. The first is given
   scale because it is the only one that reports an outcome rather than an
   opinion, and the source line is set as small as it is because a Twitch
   handle is provenance, not a testimonial byline. Quotation marks are drawn by
   the rule, so the copy in the HTML stays exactly what was typed. */
/* The same ruled-sheet construction as the do-grid, on the dark ground: 1px
   gaps over the hairline color, cells in page ink. Six quotes over six
   columns: the lead runs the full first row, three sit under it at span 2,
   and the last two close the sheet at span 3, so every row fills exactly. */
.quotes {
  margin-top: clamp(34px, 4vw, 52px);
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
}
.quote {
  grid-column: span 2;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 18px;
  margin: 0;
  padding: clamp(20px, 2.2vw, 28px);
  background: var(--ink-0);
}
.quotes .quote:nth-of-type(n + 5) { grid-column: span 3; }
.quote__t {
  margin: 0;
  font-size: 17px;
  line-height: 1.5;
  color: var(--text);
  text-wrap: pretty;
}
.quote__t::before { content: "\201C"; }
.quote__t::after { content: "\201D"; }
/* The lead is the only quote that reports an outcome, so it gets the full
   first row and the display face. Scale is its emphasis; the cell tone stays
   the page's own, because a raised surface is for interactive objects here. */
.quotes .quote--lead { grid-column: 1 / -1; }
.quote--lead .quote__t {
  font-family: var(--display);
  font-size: clamp(28px, 3.4vw, 44px);
  font-weight: 700;
  line-height: 1.08;
  letter-spacing: -0.012em;
}
.quote__c { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.quote__who { font-size: 13.5px; font-weight: 600; color: var(--amber); }
.quote__src { font-size: 12.5px; color: var(--faint); }

@media (max-width: 900px) {
  .quotes .quote { grid-column: span 3; }
  .quotes .quote--lead, .quotes .quote:nth-of-type(6) { grid-column: 1 / -1; }
}
@media (max-width: 620px) {
  .quotes .quote, .quotes .quote:nth-of-type(n) { grid-column: 1 / -1; }
}

/* ------------------------------------------------------------- 48.4 /tech
   The masthead with no media column. Section 47 builds an L around a moment
   card; this page has no moment to show yet, so the grid collapses to one
   column and the measure does the holding instead of the composition. */
.shero__grid--solo { grid-template-columns: minmax(0, 1fr); }
@media (min-width: 901px) {
  .shero__grid--solo { grid-template-rows: auto; }
  .shero__grid--solo .shero__left { grid-column: 1; grid-row: 1; max-width: 78ch; }
}
.shero--tech .shero__title { max-width: 22ch; }
.shero--tech .shero__sub { max-width: 68ch; font-size: 17px; line-height: 1.68; }
/* Coming Soon, said once, in a sentence after the actions. The first cut set
   this as an uppercase amber label above the h1, which is the label tier this
   system bans outright: every route opens on its heading. A plain line below
   the CTA row says the same thing without wearing a costume. */
.tech__soon {
  margin-top: 18px;
  font-size: 14px;
  line-height: 1.6;
  color: var(--faint);
}

.soon__grid {
  margin-top: clamp(34px, 4vw, 52px);
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
}
.soon__item { padding: clamp(22px, 2.4vw, 32px); background: var(--ink-0); }
.soon__h {
  font-family: var(--display);
  font-size: clamp(20px, 2vw, 25px);
  font-weight: 700;
  line-height: 1.1;
  color: var(--text);
}
.soon__p { margin-top: 10px; font-size: 15px; line-height: 1.64; color: var(--muted); max-width: 54ch; }
@media (max-width: 720px) { .soon__grid { grid-template-columns: 1fr; } }

/* --------------------------------------------------- 48.5 THE PLAYERS CLOSE
   The end CTA gained a sentence on /players, because "the platform opens
   shortly" is a claim that needs its qualifier beside it rather than in a
   footnote. `.endcta` centres its stack, so the paragraph inherits that. */
/* `--muted` is the grey for the ink ramp and this paragraph sits on the amber
   field, where it measured 1.05:1 and was effectively invisible. The field's
   own secondary voice is amber-ink at reduced alpha, which is what `.cta-alt`
   beside it already uses; 0.72 rather than its 0.66 because this is a full
   sentence rather than a short line. Measures 5.0:1 at the amber stop and
   5.6:1 at the gold end of the gradient. */
.endcta__p {
  /* `margin-inline: auto` centred this block inside a left-aligned composition,
     so it started roughly 220px right of the heading it belongs to and lined up
     with nothing. The heading, the paragraph and the buttons share one left
     edge. And the size was a hard 16px next to a heading that scales to 88px,
     which is why it read as fine print on a large monitor: it is fluid now,
     from 17px on a phone to 26px on the big glass. */
  margin-top: clamp(16px, 1.6vw, 26px);
  max-width: 46ch;
  font-size: clamp(17px, 1.5vw, 26px);
  line-height: 1.5;
  color: rgba(21, 16, 7, 0.72);
}

/* --------------------------------------------------------- 48.6 THE NAV ROW
   Four tabs became six. At a flat 30px the row started competing with the CTA
   for the same pixels between 1000px and 1180px, so the gap goes fluid and
   gives that range back. The Indie Program keeps its header access through the
   banner, which is where the deadline lives; the tab is the fallback for the
   drawer, where there is vertical room and the banner is compressed. */
.nav__tabs { gap: clamp(16px, 1.9vw, 30px); }
/* 880px is where `.nav__tabs` becomes the drawer, so that is exactly where the
   seventh item is allowed to exist. Shown any earlier it is a seventh inline
   tab racing the CTA for the same row. */
.nav__tab--indie { display: none; }
@media (max-width: 880px) {
  .nav__tab--indie { display: block; color: var(--amber); }
  .nav__tab--indie::after { display: none; }
}


/* ------------------------------------------------- 48.7 THE MASTHEAD ARRIVES
   The choreography ran everywhere except the first thing a visitor sees: the
   inner-page masthead sat finished while every band below it wiped and rose.
   Now the masthead runs the site's one entrance, in the site's own vocabulary:
   the title wipes up under its own edge exactly as every d2 does, the copy
   column and the moment card rise on successive beats, and the stat rail lands
   last as one beam. The wipe rules mirror 21.5 with the same durations, so the
   masthead is the same motion earlier, not a second motion language. The rail
   numerals are then counted up by _motion.html, because on these pages the
   numbers are the argument: a figure that visibly arrives at its value reads
   as measured, where a figure that pops in reads as typed. */
@media (prefers-reduced-motion: no-preference) {
  .reveal .shero__title,
  .reveal .phead__title {
    clip-path: inset(0 0 108% 0);
    transform: translateY(6px);
    transition: clip-path 760ms var(--ease), transform 760ms var(--ease);
    transition-delay: calc(var(--i, 0) * 90ms + 60ms);
  }
  .reveal.is-in .shero__title,
  .reveal.is-in .phead__title { clip-path: inset(0 0 -14% 0); transform: none; }
}

/* ============================================================ 49. THE READABILITY FLOOR AND THE LARGE FRAME
   Two audits, one layer. The first swept every text node the six main routes
   render and found a stratum of 11-15px Sora doing real reading work: stat
   captions, recipe copy, quote attributions, footer navigation, control
   labels. Small type was standing in for hierarchy. The rule now enforced:
   nothing that carries information sits under 13px, nothing that carries a
   sentence sits under 15px, and body copy that argues sits at 16px. Hierarchy
   comes from the display ramp above, not from shrinking the floor below.

   The second audit put the site on real glass: 1920, 2560 and 3440 wide. The
   1240px frame that composes at 1440 leaves 660-1100px of dead street on each
   side of the lit content, and the nav, banner, heroes and sheets all read as
   a 1440 screenshot pinned to a monitor. The frame now breathes in two steps.
   Type does not scale with it: the measure caps (19ch/44ch/66ch) hold, so the
   extra frame goes to the compositions, the sheets and the moment cards, not
   to longer lines. */

/* ------------------------------------------------------ 49.1 THE WIDE FRAME */
/* Every wrapped surface reads --wrap, so the whole street widens together:
   nav, banner, mastheads, bands, sheets, footer. Two steps, both conservative,
   because the point is a frame that fits the glass, not content inflated to
   chase it. */
@media (min-width: 1680px) { :root { --wrap: 1400px; } }
@media (min-width: 2200px) { :root { --wrap: 1560px; } }

/* Controls hold their optical weight on the big glass. A 14px button that
   reads as a button at 1440 reads as a crumb at 2560. */
@media (min-width: 1920px) {
  .btn { font-size: 15px; padding: 17px 30px; }
  .nav-btn { font-size: 14px; padding: 12px 22px; }
}

/* --------------------------------------------- 49.2 LABELS THAT DO REAL WORK */
/* The banner is the one lit field on the street and was setting its offer in
   11-12px. The sentence reads as one line; now it reads at arm's length. */
.banner__title { font-size: 14px; }
.banner__upto { font-size: 12px; }
.banner__grant-label { font-size: 13.5px; }
.banner__deadline { font-size: 13px; }

/* Navigation: six tabs of primary wayfinding and a footer that is the site's
   index. The footer column heads were 11px uppercase, which is a whisper
   doing a heading's job. */
.nav__tab { font-size: 15px; }
.nav-btn { font-size: 14px; }
.footer__col h3 { font-size: 13px; }
.footer__col a { font-size: 15px; }
.footer__tagline { font-size: 15px; }

/* The logo wall's claim line is the site's strongest social proof and was the
   smallest sentence on the page. */
.logos__title { font-size: 13.5px; }

/* ------------------------------------------------ 49.3 CONTROLS AND PLAYERS */
/* Anything a visitor is asked to click names its action at 14px minimum. */
.lcard__play { font-size: 14px; }
.splayer__play, .splayer__share { font-size: 14px; }
.step__btn { font-size: 14px; }
.tlink { font-size: 15px; }
.splayer__title { font-size: 16px; }
.splayer__byline { font-size: 13.5px; }
.stage__game { font-size: 14px; }

/* ------------------------------------------------- 49.4 METAS AND CAPTIONS */
/* Captions under the site's own numbers, effort/cost lines under the recipes,
   and the provenance under the quotes: all meaningful, all were 12-13px. */
.sstat__cap { font-size: 14px; }
.shero__rail .sstat__cap { font-size: 14px; }
.doc__m { font-size: 13.5px; }
.case__m { font-size: 13.5px; }
.quote__src { font-size: 13.5px; }
.quote__who { font-size: 14.5px; }
.dotier__v { font-size: 14px; }
.step__tag { font-size: 13.5px; }
.moment__note, .tryl__note, .tech__soon { font-size: 15px; }
.swap__leg { font-size: 13.5px; }
.swap__cue-line { font-size: 14px; }

/* --------------------------------------------------- 49.5 SENTENCES AT 16px */
/* Copy that argues is body copy, whatever container it sits in. */
.doc__p, .case__x, .soon__p, .step__text, .shero__tick, .swap__cap,
.dm__msg, .quest__body, .do__foot { font-size: 16px; }

/* The creators route mocks a channel surface; a mock still gets read. */
.surf__bar { font-size: 12.5px; }
.surf__sub { font-size: 13.5px; }
.surf__link { font-size: 14px; }
.surf__text { font-size: 15px; }
.surf__name { font-size: 14px; }
.dm__meta { font-size: 13.5px; }
.dm__who { font-size: 14px; }
.quest__flag { font-size: 13.5px; }
.quest__fact { font-size: 14px; }

/* Stragglers the first sweep missed: the homepage hero's compact logo line,
   the moment byline, the mock player's timestamp, the expectation label on
   the use-case rows, and the creators journey nodes, which are sentences. */
.hero__logos .logos__title { font-size: 13px; }
.footer__legal { font-size: 13.5px; }
/* "WANT THE DETAIL BEFORE THE PAGE HAS IT?" broke with "IT?" alone on the
   third line at 1920. Balance keeps the closing question from ragging into an
   orphan on any of the amber fields. */
.endcta__h { text-wrap: balance; }
.stage__meta { font-size: 14px; }
.swap__time { font-size: 12px; }
.case__x b { font-size: 13.5px; }
.path__node { font-size: 16px; }

/* --------------------------------------------------- 49.6 PRINT AND CAPTURE */
/* The choreography hides everything below the fold until it is approached.
   Print never approaches: every reveal must stand at rest on paper, or a
   printed page is a header and five feet of blank street. */
@media print {
  .reveal, .rv-rule {
    opacity: 1 !important;
    transform: none !important;
    clip-path: none !important;
  }
}

/* ============================================================ 50. THE MASTHEAD ON REAL GLASS
   Section 49 widened the frame. This fixes what widening exposed: the
   composition inside the frame was still sized for 1440.

   The L-void, measured. At 2560 the copy column ran 318px and the media
   column 709px, so grid row 2 inherited 337px of height that only a 106px
   stat rail had to fill, and the rail pins to the bottom to close the L. That
   is 285px of dead street between the CTA and the numbers, and it grows with
   every pixel of extra width, because the media column takes its share of the
   frame and converts it straight into height.

   Two causes, two fixes, both of which the large-screen brief asks for on
   their own terms. The display ramp stops at 66px, so a headline that
   commands a 1440 screen reads as a caption on a 2560 one: it grows. And the
   moment card kept scaling past the size at which a 16:9 video is useful: it
   is capped, and hugs the right edge so the L still closes. Together the void
   drops to roughly the air it holds at 1440, and neither fix adds a pixel of
   decoration to do it. */

/* --------------------------------------------------- 50.1 THE DISPLAY RAMP */
@media (min-width: 1680px) {
  .shero__title { font-size: 78px; }
  .shero__sub { font-size: 19px; max-width: 46ch; }
  .shero__tick { font-size: 16.5px; padding: 12px 0; }
  /* A 16:9 card past ~620px is an image scaled beyond its useful size, and
     every pixel of that scale lands in the column as height. */
  .shero__right { max-width: 620px; margin-left: auto; }
  .shero__rail .sstat__fig { font-size: 42px; }
}

@media (min-width: 2200px) {
  .shero__title { font-size: 86px; }
  .shero__right { max-width: 640px; }
  .shero__rail .sstat__fig { font-size: 46px; }
  .shero__rail .sstat__cap { font-size: 15px; }
}

/* Ultrawide gets one more step of frame. Past this the reading measure, not
   the monitor, is the constraint: the caps in 50.1 hold the line length while
   the frame keeps the composition off the far edges. */
@media (min-width: 2800px) { :root { --wrap: 1720px; } }

/* Band headings and ledes carry the same treatment, so a band below the fold
   is not visibly a smaller design than the masthead above it. */
@media (min-width: 1680px) {
  .lede { font-size: 20px; }
  .case__p, .doc__p, .soon__p, .step__text { font-size: 17px; }
  .case__x { font-size: 16.5px; }
}

/* --------------------------------------------------- 50.2 THE RAIL AS A BEAM
   The display ramp closed most of the L-void but not all of it, and on the
   two routes whose headline runs to two lines rather than three the copy
   column is short enough that 237px still sat between the CTA and the
   numbers. The remaining fix is not to shrink the gap but to enclose it.

   Section 47.3b's own words: "the rail drops into exactly that gap and the
   void becomes the numbers." It only half did, because a 106px rail pinned to
   the bottom of a 300px row leaves 194px above it outside any rule. The rail
   now stretches to own that row, draws its top hairline directly under the
   CTA, and hangs its figures at the foot of the beam. Identical geometry for
   the numbers, and the space above them is inside the composition instead of
   being a hole in it. */
@media (min-width: 901px) {
  .shero__rail { align-self: stretch; align-content: end; }
}

/* ------------------------------------------------- 50.3 THE TECH PIPELINE
   /tech had no media column, so above 1920 its masthead was a paragraph and
   575px of bare ink. The first attempt put a vertical schematic in the empty
   column and simply moved the problem: the stack ran 1080px against a 491px
   copy column, so the dead space changed sides.

   A pipeline is read along its length, so it is drawn along the width the
   large screens actually have. Three stages across the full frame, in the
   ruled-sheet construction section 48 already established: 1px gaps over the
   hairline colour, cells in page ink. Each cell names what the moment IS at
   that stage, and the same frame of the same game appears in the first cell
   and the last, which is the entire claim made visually: identical pixels,
   different container. It also gives /tech the one masthead on the site that
   is not the shared L, which is the right page to spend that on. */
.tdiag {
  margin-top: clamp(30px, 3.5vw, 46px);
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
}
.tdiag__stage {
  display: flex;
  flex-direction: column;
  gap: 9px;
  padding: clamp(18px, 1.8vw, 26px);
  background: var(--ink-0);
}
.tdiag__k {
  font-family: var(--display);
  font-size: 14px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--amber);
}
.tdiag__v { font-size: 16px; line-height: 1.55; color: var(--text); }
.tdiag__n { font-size: 14.5px; line-height: 1.6; color: var(--muted); }

/* The visual sits on the cell floor so the three line up whatever their copy
   runs to. */
.tdiag__art {
  margin-top: auto;
  padding-top: 14px;
  aspect-ratio: 16 / 9;
  overflow: hidden;
}
.tdiag__art img {
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
  border: 1px solid var(--line);
}

/* The middle stage has nothing to photograph: a moment between capture and
   restore is values, not a picture. Tabular figures, which is the one place
   this system aligns numerals in a column. */
.tdiag__state {
  margin-top: auto;
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 7px 16px;
  padding: 16px;
  border: 1px solid var(--line);
  background: var(--ink-1);
  font-size: 14px;
  font-variant-numeric: tabular-nums;
}
.tdiag__sk { color: var(--faint); }
.tdiag__sv { color: var(--amber); text-align: right; }

/* A browser frame in the system's own hairlines. A title bar carrying the real
   destination is information; three coloured dots would be a costume. */
.tdiag__browser { margin-top: auto; padding-top: 14px; }
/* The same frame appears in the first cell and the last, which only reads as
   the argument if the last one is unmistakably a browser. The bar carries a
   recessed address field rather than a row of coloured dots: the field is the
   part of browser chrome that actually says browser, and it stays inside this
   system (ink ground, hairline, no radius) where the dots would not. */
.tdiag__bar {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border: 1px solid var(--line-2);
  border-bottom: 0;
  background: var(--ink-2);
}
/* Named, not `.tdiag__bar span`: that selector outranks `.tdiag__dot` on
   specificity and handed the dot flex:1 plus the field's own border and
   padding, which drew it as a 180px ellipse. */
.tdiag__url {
  flex: 1;
  padding: 6px 11px;
  border: 1px solid var(--line);
  background: var(--ink-0);
  font-size: 13.5px;
  color: var(--muted);
}
.tdiag__dot { width: 6px; height: 6px; border-radius: 50%; background: var(--line-2); flex: none; }
.tdiag__frame { aspect-ratio: 16 / 9; overflow: hidden; border: 1px solid var(--line-2); }
.tdiag__frame img { width: 100%; height: 100%; object-fit: cover; display: block; }

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

/* ============================================================ 51. THE HERO LOCK
   Emily, 2026-08-20: "some kind of mouse effect in the homepage hero, a little
   gamified but with class."

   The comparator already owns a crosshair, so the hero does not get a second
   one: the same gesture twice on one page is a tic, not a language. What the
   hero gets is the other half of the same grammar. A crosshair says where you
   are pointing. Brackets say what has been acquired, and this hero has exactly
   one thing worth acquiring, which is the single control in it.

   So the reticle drifts with the pointer while it is over open ground, and the
   moment the pointer comes near "Play a moment" it snaps to the button's
   bounds, tightens and goes solid. It is a lock-on, which is unmistakably game
   UI, and it is doing a real job: on a full-bleed video with one call to
   action, it is the thing that finds the call to action for you.

   With class rather than costume, which here means four rules. Hairline arms
   in the one accent, no glow and no trail. It never covers the headline: it
   rides under the type and over the footage. It is transform-only on a single
   rAF, so it costs nothing. And it does not exist at all for a coarse pointer
   or under reduced motion, because a lock-on with no mouse is decoration. */

.hlock {
  position: absolute;
  left: 0;
  top: 0;
  width: 54px;
  height: 54px;
  /* Under .hero__overlay (z-index 2) so the headline always wins, over the
     scrim so the brackets read against the footage. */
  z-index: 1;
  pointer-events: none;
  opacity: 0;
  transition: opacity 220ms var(--ease);
  will-change: transform;
}
.hlock.is-live { opacity: 0.62; }
.hlock.is-locked { opacity: 1; }

/* Four corners, each two hairline arms. Drawn as borders on a bare span so the
   whole reticle is four elements and no pseudo-element gymnastics. */
.hlock span {
  position: absolute;
  width: 11px;
  height: 11px;
  border: 0 solid var(--amber);
  transition: width 180ms var(--ease), height 180ms var(--ease);
}
.hlock span:nth-child(1) { left: 0;  top: 0;    border-left-width: 2px; border-top-width: 2px; }
.hlock span:nth-child(2) { right: 0; top: 0;    border-right-width: 2px; border-top-width: 2px; }
.hlock span:nth-child(3) { left: 0;  bottom: 0; border-left-width: 2px; border-bottom-width: 2px; }
.hlock span:nth-child(4) { right: 0; bottom: 0; border-right-width: 2px; border-bottom-width: 2px; }

/* Acquired: the arms shorten, which is what tightening looks like on a bracket,
   and the target picks up the same amber at its own edge. */
.hlock.is-locked span { width: 8px; height: 8px; }

/* The button answers the lock rather than the reticle drawing a box around a
   button that ignores it. One hairline, the accent already on the control. */
#heroToMoment { transition: box-shadow 200ms var(--ease), transform 200ms var(--ease); }
.hero.is-locked #heroToMoment { box-shadow: 0 0 0 1px var(--amber-hi); }

/* No pointer, no lock. Touch gets the hero exactly as it was. */
@media (pointer: coarse), (prefers-reduced-motion: reduce) {
  .hlock { display: none; }
  .hero.is-locked #heroToMoment { box-shadow: none; }
}

/* ============================================================ 52. THE PRESS
   The site had no testimonial of any kind, so the strongest voice available is
   a named editor at a named outlet who tried the product and wrote down what
   happened. That deserves scale, and it deserves to be unmistakably somebody
   else talking: the quote runs in the display face at statement size, and the
   attribution carries a name, a role and a link to the source rather than a
   logo doing the vouching.

   The rows below are outlet and headline only. Two of the four are press
   release rewrites, so there is nothing honest to pull from them, and a row
   that says only where and when is worth more than a fabricated pull quote. */

.pquote {
  margin: clamp(34px, 4vw, 52px) 0 0;
  padding: clamp(28px, 3vw, 44px) 0 clamp(26px, 3vw, 38px);
  border-top: 1px solid var(--paper-line);
  border-bottom: 1px solid var(--paper-line);
}
.pquote__t {
  margin: 0;
  max-width: 24ch;
  font-family: var(--display);
  font-size: clamp(30px, 4.2vw, 58px);
  font-weight: 700;
  line-height: 1.04;
  letter-spacing: -0.012em;
  color: var(--paper-ink);
  text-wrap: balance;
}
/* Drawn by the rule, so the copy in the HTML stays exactly what he wrote. */
.pquote__t::before { content: "\201C"; }
.pquote__t::after { content: "\201D"; }

.pquote__c {
  margin-top: clamp(18px, 2vw, 26px);
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 8px 16px;
}
.pquote__who { font-size: 16px; font-weight: 600; color: var(--paper-ink); }
.pquote__role { font-size: 15px; color: var(--paper-muted); }
.pquote__src { margin-left: auto; }
@media (max-width: 640px) { .pquote__src { margin-left: 0; } }

/* ------------------------------------------------------------- 52.2 THE ROWS
   Outlet, headline, date. A whole-row link because the row is one destination,
   and the outlet is set in the display face so the four read as a masthead
   column down the left rather than four sentences that happen to start with a
   name. */
.press { margin-top: clamp(26px, 3vw, 40px); }
.press__row {
  display: grid;
  grid-template-columns: minmax(120px, 0.5fr) minmax(0, 2.4fr) auto;
  gap: clamp(16px, 2.4vw, 40px);
  align-items: baseline;
  padding-block: clamp(16px, 1.8vw, 22px);
  border-bottom: 1px solid var(--paper-line);
  color: inherit;
  text-decoration: none;
  transition: background var(--fast) var(--ease);
}
.press__row:first-child { border-top: 1px solid var(--paper-line); }
.press__row:hover { background: rgba(0, 0, 0, 0.03); }
.press__row:hover .press__h { color: var(--paper-kick); }
.press__out {
  font-family: var(--display);
  font-size: 19px;
  font-weight: 700;
  letter-spacing: 0.01em;
  color: var(--paper-ink);
}
.press__h {
  font-size: 16px;
  line-height: 1.55;
  color: var(--paper-muted);
  transition: color var(--fast) var(--ease);
}
.press__d { font-size: 14px; color: var(--paper-faint); white-space: nowrap; }

@media (max-width: 720px) {
  .press__row { grid-template-columns: 1fr auto; gap: 6px 14px; }
  .press__out { grid-column: 1; }
  .press__d { grid-column: 2; }
  .press__h { grid-column: 1 / -1; }
}

/* ============================================================ 53. THE CREATOR APPLICATION
   The production /creators page captures the creator before handing off to
   Lurkit; the redesign had dropped that form and linked straight out, which
   gave the lead away. This is that form in the v3 voice.

   It reuses the .apply-* field metrics (48px rows, 1px --line-2, amber focus)
   deliberately, so the two application forms on the site read as one control,
   but under its own prefix: .apply-* is a contract with markup /script.js
   generates and must not be widened to cover markup we own. */
.capp__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(32px, 5vw, 72px);
  align-items: start;
}
.capp__h {
  font-family: var(--display);
  font-weight: 800;
  text-transform: uppercase;
  font-size: clamp(32px, 4.2vw, 56px);
  line-height: 0.94;
  letter-spacing: -0.005em;
}
.capp__p { margin-top: 18px; color: var(--muted); font-size: 16px; line-height: 1.62; max-width: 46ch; }

/* Hairline rows rather than a bulleted list: the page has no other bullet and
   the rule is the system's own separator. */
.capp__list { margin-top: 28px; list-style: none; padding: 0; border-top: 1px solid var(--line); }
.capp__list li {
  padding: 14px 0 14px 26px;
  border-bottom: 1px solid var(--line);
  font-size: 15px;
  color: var(--muted);
  position: relative;
}
.capp__list li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 21px;
  width: 12px;
  height: 1px;
  background: var(--amber);
}

.capp__box { background: var(--ink-1); border: 1px solid var(--line); padding: clamp(22px, 3vw, 34px); }
.capp__form { display: grid; gap: 14px; }
.capp__field { display: block; }
.capp__label {
  display: block;
  margin-bottom: 7px;
  font-size: 13px;
  font-weight: 500;
  color: var(--muted);
}
.capp__input {
  width: 100%;
  height: 48px;
  padding: 0 14px;
  background: var(--ink-0);
  border: 1px solid var(--line-2);
  border-radius: 0;
  color: var(--text);
  font-family: var(--sans);
  font-size: 15px;
  transition: border-color var(--fast) var(--ease);
}
.capp__input::placeholder { color: var(--faint); }
.capp__input:hover { border-color: rgba(255, 255, 255, 0.28); }
.capp__input:focus { outline: none; border-color: var(--amber); }
/* The native arrow is drawn in the UA's own colour and reads as a light-mode
   artefact on this ground, so the control supplies its own. */
.capp__select {
  appearance: none;
  -webkit-appearance: none;
  padding-right: 38px;
  background-image: linear-gradient(45deg, transparent 50%, var(--muted) 50%),
                    linear-gradient(135deg, var(--muted) 50%, transparent 50%);
  background-position: calc(100% - 19px) 21px, calc(100% - 14px) 21px;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
}
.capp__select option { background: var(--ink-1); color: var(--text); }
.capp__field.is-error .capp__input { border-color: var(--bad-dark); }

.capp__submit {
  width: 100%;
  height: 52px;
  margin-top: 4px;
  background: var(--amber);
  color: var(--amber-ink);
  border: 0;
  border-radius: 0;
  font-family: var(--display);
  font-weight: 700;
  font-size: 17px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  cursor: pointer;
  transition: background var(--fast) var(--ease);
}
.capp__submit:hover { background: var(--amber-hi); }
.capp__submit:disabled { opacity: 0.6; cursor: not-allowed; }
.capp__micro { margin-top: 4px; font-size: 13px; color: var(--faint); }

.capp__done-h {
  font-family: var(--display);
  font-weight: 800;
  text-transform: uppercase;
  font-size: clamp(26px, 3vw, 38px);
  line-height: 0.96;
  color: var(--amber);
}
.capp__done .btn { margin-top: 22px; }

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