/* KILLSCRIPT — Specialist Selection Portal */

:root {
  --bg-0: #04070b;
  --bg-1: #07101a;
  --bg-2: #0c1824;
  --line: rgba(120, 200, 255, 0.12);
  --line-strong: rgba(120, 200, 255, 0.28);
  --fg: #cfe6ff;
  --fg-dim: #6f8aa6;
  --fg-mute: #3d556e;
  --accent: #6cc6ff;
  --accent-2: #9ee7ff;
  --accent-glow: oklch(0.78 0.16 230);
  --warn: #ffb247;
  --danger: #ff5b6e;
  --ok: #5be38d;
  --mono: "JetBrains Mono", "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
  --display: "Space Grotesk", "Inter", system-ui, sans-serif;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg-0);
  color: var(--fg);
  font-family: var(--mono);
  font-size: 14px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

/* Reserve scrollbar gutter on the root so it ALWAYS occupies width,
   even when the page doesn't overflow OR when a modal locks scroll
   via `overflow: hidden` on <html>. Without this the layout (and the
   fixed header) shifts horizontally by ~15px every time a modal
   opens/closes — visible as a jitter on the logo and nav.

   Only applied >=800px: below that the modal goes full-bleed and the
   reserved gutter would show as an empty stripe on the right edge of
   the modal. Mobile browsers also typically use overlay scrollbars
   that don't take layout width, so there's nothing to compensate. */
@media (min-width: 800px) {
  html {
    scrollbar-gutter: stable;
  }
}

body {
  background:
    radial-gradient(1200px 600px at 80% -10%, rgba(60,140,210,0.18), transparent 60%),
    radial-gradient(900px 500px at 10% 110%, rgba(40,90,160,0.12), transparent 70%),
    var(--bg-0);
  min-height: 100vh;
  padding-top: 64px;
}

/* Subtle scanline overlay */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  background-image: repeating-linear-gradient(
    0deg,
    rgba(108, 198, 255, 0.025) 0px,
    rgba(108, 198, 255, 0.025) 1px,
    transparent 1px,
    transparent 3px
  );
  z-index: 9990;
  mix-blend-mode: screen;
}

/* Vignette */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(ellipse at center, transparent 50%, rgba(0,0,0,0.55) 100%);
  z-index: 9991;
}

::selection { background: var(--accent); color: #000; }

a { color: var(--accent); text-decoration: none; }

button, input, textarea {
  font-family: inherit;
  font-size: inherit;
  color: inherit;
}

/* ---------- Layout primitives ---------- */
.shell {
  position: relative;
  max-width: 1440px;
  margin: 0 auto;
  padding: 0 40px;
}

.row { display: flex; align-items: center; }
.col { display: flex; flex-direction: column; }
.gap-2 { gap: 8px; }
.gap-3 { gap: 12px; }
.gap-4 { gap: 16px; }
.gap-6 { gap: 24px; }
.gap-8 { gap: 32px; }
.spacer { flex: 1; }

/* ---------- Top nav ---------- */
.nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 9992;
  background: rgba(4, 7, 11, 0.6);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--line);
}
.nav-inner {
  display: flex;
  align-items: center;
  height: 64px;
  padding: 0 40px;
  gap: 32px;
}
.nav-logo {
  display: flex; align-items: center; gap: 10px;
  font-family: var(--display);
  font-weight: 700;
  font-size: 18px;
  letter-spacing: 0.18em;
  color: var(--fg);
  background: none;
  border: 0;
  padding: 0;
  margin: 0;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}
.nav-logo:focus-visible {
  outline: 1px solid var(--accent);
  outline-offset: 4px;
}
.nav-logo-img {
  /* Default (desktop, with portal-tag + nav-links visible): pinned 200. */
  width: 200px;
  max-width: 100%;
  height: auto;
  display: block;
  filter: drop-shadow(0 0 10px rgba(108,198,255,0.18));
}
/* The compact "K" mark variant is roughly square — size by height so it
   sits cleanly inside the 64px-tall nav instead of stretching wide. */
.nav-logo-img--mark {
  width: auto;
  /* Matches the APPLY CTA's outer box height (~28px = 11px label +
     16px vertical padding + ~1px line-height fudge). */
  height: 24px;
  max-width: none;
}
.nav-portal-tag {
  /* Stay at 11px regardless of viewport. Let the text overflow its box
     visually if it can't fit \u2014 it can encroach on the APPLY area but
     will never overlap the logo (which sits on the left). */
  font-size: 11px;
  white-space: nowrap;
  flex-shrink: 1;
  min-width: 0;
  overflow: visible;
}
/* Below the desktop breakpoint, portal-tag + nav-links are hidden.
   Let the logo flex-grow into that freed space, capped at the same
   nominal 200px it has on desktop. The spacer is removed and the
   CTA pulled to the right edge via margin-left: auto, so any slack
   after the logo caps sits as auto-margin in front of the CTA. */
@media (max-width: 1000px) {
  .nav .spacer { display: none; }
  .nav-logo {
    flex: 1 1 0;
    min-width: 0;
    max-width: 200px;
  }
  /* When the compact mark is used, don't flex-grow — let the logo sit
     at its intrinsic width so the portal-tag has room to fit. */
  .nav-logo:has(.nav-logo-img--mark) {
    flex: 0 0 auto;
    max-width: none;
  }
  .nav-logo-img {
    width: 100%;
    max-width: 200px;
  }
  .nav-logo-img--mark {
    width: auto;
    height: 22px;
    max-width: none;
  }
  /* Tighten the nav gap so the tag + mark + cta fit on one row. */
  .nav-inner { gap: 14px; padding: 0 20px; }
  .nav-cta { margin-left: auto; }
}
.nav-logo { flex-shrink: 1; min-width: 0; }
.nav-logo .glyph {
  width: 22px; height: 22px;
  border: 1.5px solid var(--accent);
  position: relative;
  transform: rotate(45deg);
}
.nav-logo .glyph::before {
  content: "";
  position: absolute; inset: 3px;
  border: 1px solid var(--accent);
  opacity: 0.5;
}
.nav-links {
  display: flex; gap: 28px;
  font-size: 12px; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--fg-dim);
}
.nav-links a {
  position: relative;
  color: var(--fg-dim);
  padding: 6px 2px;
  transition: color 0.18s;
}
.nav-links a::after {
  content: "";
  position: absolute;
  left: 0;
  right: 100%;
  bottom: 0;
  height: 1px;
  background: var(--accent);
  box-shadow: 0 0 8px var(--accent);
  transition: right 0.22s ease;
}
.nav-links a:hover { color: var(--accent); }
.nav-links a:hover::after { right: 0; }
.nav-cta {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 8px 16px;
  border: 0;
  color: #04070b;
  background: var(--accent);
  font-family: var(--mono);
  font-size: 11px; letter-spacing: 0.16em; text-transform: uppercase;
  font-weight: 600;
  cursor: pointer;
  clip-path: polygon(0 0, calc(100% - 10px) 0, 100% 10px, 100% 100%, 10px 100%, 0 calc(100% - 10px));
  transition: background 0.15s ease, box-shadow 0.15s ease;
}
.nav-cta:hover {
  background: var(--accent-2);
  box-shadow: 0 0 24px rgba(108,198,255,0.55);
}

/* Secondary (ghost) variant — applied while the hero's own Apply CTA is
   still in the viewport, so the two don't compete. Same diagonal-cut
   polygon shape as the primary nav-cta but rendered as an accent-color
   outline on transparent, like the hero's Join Discord button. Falls
   back to the primary filled style as soon as the user scrolls past
   the hero (handled by the IntersectionObserver in <Nav>). */
.nav-cta-ghost {
  --ncol: var(--line-strong);
  background-color: transparent;
  background-image:
    linear-gradient(45deg, transparent calc(50% - 0.7px), var(--ncol) calc(50% - 0.7px), var(--ncol) calc(50% + 0.7px), transparent calc(50% + 0.7px)),
    linear-gradient(45deg, transparent calc(50% - 0.7px), var(--ncol) calc(50% - 0.7px), var(--ncol) calc(50% + 0.7px), transparent calc(50% + 0.7px)),
    linear-gradient(var(--ncol), var(--ncol)),
    linear-gradient(var(--ncol), var(--ncol)),
    linear-gradient(var(--ncol), var(--ncol)),
    linear-gradient(var(--ncol), var(--ncol));
  background-position:
    right top, left bottom,
    0 0, 100% 100%, 100% 100%, 0 0;
  background-size:
    10px 10px, 10px 10px,
    calc(100% - 10px) 1px,
    1px calc(100% - 10px),
    calc(100% - 10px) 1px,
    1px calc(100% - 10px);
  background-repeat: no-repeat;
  color: var(--fg);
  transition: color 0.18s ease, background-color 0.18s ease, box-shadow 0.18s ease;
}
.nav-cta-ghost:hover {
  /* Hover state matches the primary nav-cta: filled accent with dark
     text — same affordance as the hero's Apply CTA. */
  --ncol: var(--accent);
  background-color: var(--accent);
  color: #04070b;
  box-shadow: 0 0 24px rgba(108,198,255,0.55);
}

/* ---------- Hero ---------- */
.hero {
  position: relative;
  min-height: calc(100vh - 100px);
  padding: 64px 40px 80px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.hero-keyart-wrap {
  position: absolute;
  top: 0;
  left: 50%;
  width: 1600px;
  height: 900px;
  transform: translateX(-50%);
  opacity: 0;
  transition: opacity 0.6s ease-out;
  pointer-events: none;
  mask-image: linear-gradient(180deg, black 50%, transparent 100%),
              linear-gradient(90deg, transparent 0%, black 30%, black 70%, transparent 100%);
  -webkit-mask-image: linear-gradient(180deg, black 50%, transparent 100%),
                      linear-gradient(90deg, transparent 0%, black 30%, black 70%, transparent 100%);
  mask-composite: intersect;
  -webkit-mask-composite: source-in;
}
.hero-keyart-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}
.hero-grid {
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(var(--line) 1px, transparent 1px),
    linear-gradient(90deg, var(--line) 1px, transparent 1px);
  background-size: 80px 80px;
  opacity: 0.4;
  mask-image: radial-gradient(ellipse at 30% 50%, black 0%, transparent 70%);
  -webkit-mask-image: radial-gradient(ellipse at 30% 50%, black 0%, transparent 70%);
}

.hero-inner {
  position: relative;
  max-width: 1440px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 48px;
  align-items: stretch;
}

.hero-meta {
  display: flex;
  align-items: center;
  gap: 14px;
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--fg-dim);
  margin-bottom: 28px;
}
.hero-meta .pip {
  width: 8px; height: 8px;
  background: var(--accent);
  box-shadow: 0 0 12px var(--accent);
}
.term-card-clickable { cursor: pointer; }
.term-card.term-card-booting { cursor: pointer; }
.term-card-clickable:hover {
  /* 2px inset stroke matches the 2px corner brackets exactly — both are
     measured from the same outer edge, so no fractional-pixel/DPI drift. */
  box-shadow: inset 0 0 0 2px var(--accent);
}
.signup-cue { opacity: 0.65; }
.signup-cue strong { color: var(--accent); font-weight: 500; }
.hero-meta .badge {
  border: 1px solid var(--line-strong);
  padding: 4px 10px;
  color: var(--accent-2);
}

.hero-logo {
  margin-bottom: 28px;
}
.hero-logo img,
.hero-logo-img {
  width: min(560px, 100%);
  height: auto;
  display: block;
  /* Soft halo only — keeps the wordmark legible against the keyart
     without painting a hard outline. */
  filter: drop-shadow(0 0 14px rgba(0, 0, 0, 0.55));
}
@media (prefers-reduced-motion: reduce) {
  .hero-logo-img { animation: none; }
}

.hero-tag {
  font-family: var(--display);
  font-size: clamp(22px, 2.8vw, 34px);
  line-height: 1.2;
  letter-spacing: 0;
  color: var(--fg);
  margin: 0 0 24px;
  font-weight: 500;
  max-width: 620px;
  text-wrap: balance;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.85), 0 0 18px rgba(0, 0, 0, 0.7);
}
.hero-tag em {
  font-style: normal;
  color: var(--accent);
}

.hero-sub {
  color: var(--fg-dim);
  font-size: 14px;
  line-height: 1.6;
  max-width: 476px;
  margin-bottom: 36px;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.9), 0 0 14px rgba(0, 0, 0, 0.85);
}
.hero-sub strong { color: var(--fg); font-weight: 500; }

/* ---------- CTA buttons ---------- */
.cta-row {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 36px;
}
/* Buttons. Polygon corners come from clip-path on the button itself.
   Outlined variants (ghost/disco) keep a single-layer construction by
   filling the button with the border color and using a ::before that
   "punches a hole" via mix-blend-mode: destination-out, leaving a 1px
   ring of border-colored fill. This avoids the previous bug where a
   real CSS border + clip-path left the diagonal corners unstroked. */
.btn {
  position: relative;
  isolation: isolate;
  display: inline-flex;
  align-items: center;
  gap: 12px;
  padding: 14px 22px;
  border: 0;
  color: #04070b;
  background: var(--accent);
  font-family: var(--mono);
  font-size: 12px;
  /* Pin line-height + min-height so every .btn variant — button OR span,
     with OR without SVG — renders the SAME outer height. Without this,
     <span> placeholders inherit body line-height (1.55) and end up
     ~4px taller than <button> peers (which use UA `line-height: normal`),
     and buttons with vs without an SVG icon disagree on cross-axis
     baseline. The pin keeps the CTA row at a fixed height so the
     terminal below doesn't shift when post-submit content swaps in. */
  line-height: 1.2;
  min-height: 48px;
  box-sizing: border-box;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  font-weight: 600;
  cursor: pointer;
  clip-path: polygon(0 0, calc(100% - 12px) 0, 100% 12px, 100% 100%, 12px 100%, 0 calc(100% - 12px));
  transition: color 0.18s ease, box-shadow 0.18s ease, background 0.18s ease;
}
.btn:hover {
  background: var(--accent-2);
  box-shadow: 0 0 32px rgba(108,198,255,0.6);
}
.btn .arrow { font-size: 16px; transition: transform 0.18s; }
.btn:hover .arrow { transform: translateX(4px); }

.btn-ghost,
.btn-disco {
  /* Diagonal-cut 1px outline on a transparent button. Drawing this
     correctly is finicky in CSS: clip-path on a real border erases the
     diagonal segments; mix-blend punches need an opaque page surface
     beneath the button; mask-composite still leaves clipped corners
     unstroked. The robust answer is to draw the outline ourselves as
     six background-image layers — four straight edge strips and two
     45° gradient strokes for the corner cuts — and skip clip-path
     entirely on the outlined variants. The stroke colour is exposed as
     --bcol so it can change on hover with the rest of the colours. */
  --bcol: var(--line-strong);
  background-color: transparent;
  background-image:
    /* Top-right diagonal: 12x12 box at top-right, "\" stroke */
    linear-gradient(45deg, transparent calc(50% - 0.7px), var(--bcol) calc(50% - 0.7px), var(--bcol) calc(50% + 0.7px), transparent calc(50% + 0.7px)),
    /* Bottom-left diagonal */
    linear-gradient(45deg, transparent calc(50% - 0.7px), var(--bcol) calc(50% - 0.7px), var(--bcol) calc(50% + 0.7px), transparent calc(50% + 0.7px)),
    /* Top edge */
    linear-gradient(var(--bcol), var(--bcol)),
    /* Right edge */
    linear-gradient(var(--bcol), var(--bcol)),
    /* Bottom edge */
    linear-gradient(var(--bcol), var(--bcol)),
    /* Left edge */
    linear-gradient(var(--bcol), var(--bcol));
  background-position:
    right top, left bottom,
    0 0, 100% 100%, 100% 100%, 0 0;
  background-size:
    12px 12px, 12px 12px,
    calc(100% - 12px) 1px,
    1px calc(100% - 12px),
    calc(100% - 12px) 1px,
    1px calc(100% - 12px);
  background-repeat: no-repeat;
  border: 0;
  /* Reuse the same polygon clip as .btn so the hover bg-color also has
     the diagonal cuts. The outlines drawn above sit on the polygon
     edges, so clipping doesn't visually erase them. */
  color: var(--accent);
  transition: color 0.18s ease, background-color 0.18s ease, box-shadow 0.18s ease;
}
.btn-disco { color: var(--fg); }
.btn-ghost:hover {
  --bcol: var(--accent);
  background-color: rgba(108, 198, 255, 0.08);
  color: var(--accent-2);
  box-shadow: none;
}
.btn-disco:hover {
  --bcol: #6f7bff;
  background-color: #6f7bff;
  color: #fff;
  box-shadow: 0 0 24px rgba(88, 101, 242, 0.45);
}

/* Awaiting-invite placeholder — sits in the Apply slot after the funnel
   completes. Matches .btn dimensions (so the layout doesn't shift on
   mobile when the apply button is retired) but is pure text — no
   border, no hover, no scramble animation. */
.btn-awaiting {
  display: inline-flex;
  align-items: center;
  padding: 14px 22px;
  min-height: 48px;
  box-sizing: border-box;
  font-family: var(--mono);
  font-size: 12px;
  line-height: 1.2;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  font-weight: 600;
  color: var(--fg-dim);
  cursor: default;
  user-select: none;
}

/* ---------- Right column terminal ---------- */
.term-card {
  position: relative;
  background: rgba(7, 16, 26, 0.78);
  backdrop-filter: blur(8px);
  /* Inset shadow instead of a real border — absolute-positioned corner
     brackets at top/left:0 then sit on the same outer edge as the stroke,
     so they line up cleanly at any DPI without pixel nudges. */
  box-shadow: inset 0 0 0 1px var(--line-strong);
  font-size: 12px;
  line-height: 1.7;
  max-width: 540px;
  justify-self: end;
  align-self: center;
  width: 100%;
  /* Fixed-height card. Sized to fit the typical console + tallest tail
     (signup form / pills) without leaving a big empty area in the idle
     state — earlier 540 left ~200px of top whitespace that pushed the
     hero-left column down via `align-items: stretch`. The console
     script clips its oldest lines off the top during the funnel so
     all phases still display correctly at this height. */
  height: 440px;
  display: flex;
  flex-direction: column;
}
.term-card > * { flex-shrink: 0; }
.term-card::before {
  content: "";
  position: absolute;
  top: 0; left: 0; width: 14px; height: 14px;
  border-top: 2px solid var(--accent);
  border-left: 2px solid var(--accent);
}
.term-card::after {
  content: "";
  position: absolute;
  bottom: 0; right: 0; width: 14px; height: 14px;
  border-bottom: 2px solid var(--accent);
  border-right: 2px solid var(--accent);
}
.term-head {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 14px;
  position: relative;
  border-bottom: 1px solid var(--line);
  color: var(--fg-dim);
  font-size: 10px; letter-spacing: 0.18em; text-transform: uppercase;
}
.term-head .dots { display: flex; gap: 6px; }
.term-head .dots span {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--fg-mute);
}
.term-head .title {
  color: var(--fg);
  text-transform: none;
  letter-spacing: 0;
  line-height: 1;
  flex: 1 1 auto;
  min-width: 0;
  text-align: center;
  pointer-events: none;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Phantom spacer mirrors the dots width so the centered title stays
   visually centered between the two sides instead of drifting right. */
.term-head::after {
  content: "";
  display: block;
  width: 36px; /* 3 × 8px dot + 2 × 6px gap */
  flex: 0 0 auto;
}
.term-body {
  padding: 18px 18px 14px;
  /* Flex column: console-script flexes to fill, console-tail keeps its
     natural size at the bottom. With the card height fixed above, the
     script area shrinks when the tail (form / steam button / final
     pills) grows, instead of letting the whole card pulse. */
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
.console-script {
  /* Flex:1 inside .term-body — shrinks/grows inversely to the tail.
     Newest lines bottom-align; older lines fall off the top via
     overflow:hidden so the card never grows past its fixed height. */
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
}
.console-script .term-line {
  flex: 0 0 auto;
  min-height: 1.7em;
}
.console-tail {
  flex: 0 0 auto;
  /* Reserve the height of the tallest tail variant (full signup form /
     steam-btn / stacked confirmation pills) so console-script doesn't
     flex up and down as phases swap a one-line comment for an 8-line
     form — that would shift the older console history up/down too. */
  min-height: 150px;
  opacity: 0;
  transform: translateY(4px);
  pointer-events: none;
  transition: opacity 0.4s ease, transform 0.4s ease;
}
.console-tail.show {
  opacity: 1;
  transform: none;
  pointer-events: auto;
}
.term-line { color: var(--fg); }
/* Long emails / commands wrap inside the terminal at every viewport
   instead of pushing the card past its container. */
.term-line {
  overflow-wrap: anywhere;
  word-break: break-word;
}
/* Progress lines with an animated `.dots-anim` must NEVER wrap, even
   when the dots content peaks at "..." — a wrap would briefly double
   the line's height, and the bottom-aligned console-script would jump
   every animation cycle. The text itself ("signing confirmation with
   DKIM", "opening steam community handshake") is short enough to fit
   on a single line at every viewport width we support. */
.term-line .line-progress {
  white-space: nowrap;
  /* Override .term-line's overflow-wrap:anywhere / word-break:break-word
     (set for long emails / commands) — those win over an inner nowrap
     once the content exceeds container width, and let the browser
     break mid-word. Resetting to normal here is what actually keeps
     the progress line at a single row. */
  overflow-wrap: normal;
  word-break: normal;
}
.term-line.cursor::after {
  content: "_";
  margin-left: 2px;
  color: var(--fg);
  animation: term-cursor-blink 1.06s infinite;
}
@keyframes term-cursor-blink {
  0%, 49.99% { opacity: 1; }
  50%, 100%  { opacity: 0; }
}
.term-line .prompt { color: var(--accent); margin-right: 8px; }
.term-line .dim { color: var(--fg-dim); }
.term-line .ok { color: var(--ok); }
.term-line .warn { color: var(--warn); }
.term-line .err { color: var(--danger); }

/* Signup form */
.signup {
  display: flex;
  flex-direction: column;
  justify-content: center;
  margin-top: 14px;
  padding: 12px 14px;
  border-top: 1px dashed var(--line-strong);
  min-height: 140px;
  box-sizing: border-box;
}
.signup-comment {
  display: flex;
  align-items: center;
  justify-content: center;
}
.signup-comment .signup-label { margin-bottom: 0; }
.signup-row-placeholder {
  border-color: var(--line);
  background: rgba(0,0,0,0.25);
  padding: 12px 14px;
  min-height: 44px;
  align-items: center;
  pointer-events: none;
}
.signup-label {
  font-size: 10px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--fg-dim);
  margin-bottom: 10px;
}
.signup-row {
  display: flex;
  align-items: stretch;
  gap: 0;
  border: 1px solid var(--line-strong);
  background: rgba(0,0,0,0.4);
  /* Hard-pinned outer row height — same value used for .steam-btn and
     .signup-row-inline so the action area's top/bottom edges sit at
     the same Y across all phases. min-height alone would let the row
     grow if inner content (e.g. font-size 14 pills) needed more. */
  height: 52px;
  min-height: 52px;
  box-sizing: border-box;
}
.signup-row:focus-within {
  border-color: var(--accent);
  box-shadow:
    0 0 0 2px var(--accent),
    0 0 28px 0 color-mix(in oklab, var(--accent) 45%, transparent);
}
.cta-dim {
  opacity: 0.35;
  filter: saturate(0.6);
  transition: opacity 0.4s ease, filter 0.4s ease;
}
.cta-dim:hover {
  opacity: 1;
  filter: none;
}
.signup-row .prefix {
  padding: 12px 14px;
  color: var(--accent);
  border-right: 1px solid var(--line);
  font-weight: 600;
}
.signup-row input {
  flex: 1;
  border: 0;
  background: transparent;
  outline: none;
  padding: 0 14px;
  font-family: var(--mono);
  font-size: 13px;
  color: var(--fg);
  /* Match the parent row's pinned 52px height exactly — without this
     Chrome shaves ~1px off the input when it goes from empty
     placeholder to filled value (different default min-block-size
     between the two states). align-self: stretch is the flex
     default but spelled out so the contract is explicit. */
  height: 100%;
  align-self: stretch;
  line-height: 1;
  min-height: 0;
  box-sizing: border-box;
}
.signup-row input::placeholder { color: var(--fg-mute); }

/* Override browser autofill chrome to match the terminal palette.
   IMPORTANT: each engine's prefix lives in its own rule block — a
   comma-separated list with even one engine-foreign selector is treated
   as invalid by the parser and the entire rule is discarded. */

/* Chrome / Safari / Edge / Opera (Blink + WebKit).
   Note: the *preview* state (suggestion hovered in the popup but not yet
   committed) is rendered by Chrome's UA layer using `:-internal-autofill-
   previewed` — that pseudo is UA-only and cannot be reached from author
   CSS. Our styling kicks in once the user actually accepts a suggestion. */
.signup-row input:-webkit-autofill,
.signup-row input:-webkit-autofill:hover,
.signup-row input:-webkit-autofill:focus,
.signup-row input:-webkit-autofill:active,
.signup-row input:autofill {
  /* Inset shadow paints over the engine's yellow autofill background */
  -webkit-box-shadow: 0 0 0 1000px rgba(0,0,0,0.4) inset !important;
          box-shadow: 0 0 0 1000px rgba(0,0,0,0.4) inset !important;
  -webkit-text-fill-color: var(--fg) !important;
  caret-color: var(--accent) !important;
  /* Pin a hard-coded mono stack here (instead of var(--mono)) — some
     Chrome versions snapshot the input's font at first paint and
     ignore later variable resolution on the autofill state. The
     explicit stack also gives a usable mono fallback if JetBrains
     Mono hasn't finished loading yet. */
  font-family: "JetBrains Mono", "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace !important;
  font-size: 13px !important;
  /* Long delay keeps the engine's yellow flash from ever paint-landing */
  transition:
    background-color 9999s ease 0s,
    color 9999s ease 0s,
    -webkit-text-fill-color 9999s ease 0s !important;
}
.signup-row button {
  border: 0;
  background: var(--accent);
  color: #04070b;
  padding: 0 18px;
  cursor: pointer;
  font-weight: 600;
  letter-spacing: 0.12em;
  font-size: 11px;
  text-transform: uppercase;
}
.signup-row button:hover { background: var(--accent-2); }
.signup-row-done .confirmed-email {
  flex: 1;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 14px;
  font-family: var(--font-mono);
  font-size: 14px;
  color: var(--fg);
  min-width: 0;
}
.signup-row-done .ok-mark {
  color: var(--ok);
  font-weight: 700;
}
.signup-row-done .confirmed-addr {
  color: var(--accent);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.signup-row-done {
  border-color: var(--ok);
}
.signup-row-done button {
  background: transparent;
  color: var(--fg);
  border-left: 1px solid var(--line-strong);
}
.signup-row-done button:hover { background: var(--line); color: var(--accent); }
.signup-meta {
  margin-top: 10px;
  font-size: 10px;
  color: var(--fg-mute);
  letter-spacing: 0.04em;
  line-height: 1.5;
  text-transform: none;
}
.signup-meta a {
  color: var(--fg-dim);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.signup-meta a:hover { color: var(--accent); }

/* ---- Step header with go-back (post-idle steps only) ---- */
.signup-label-row {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 12px;
  margin-bottom: 10px;
  /* Lock the row height to the BACK chip's natural height so phases
     with no BACK button (email, key-ready) reserve the same vertical
     space \u2014 keeps the label baseline, the action element below, and
     the meta line below that, at the same Y across every phase. */
  min-height: 26px;
}
.signup-label-row .signup-label { margin-bottom: 0; text-align: left; }
.signup-back {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 9px;
  background: transparent;
  border: 1px solid var(--line-strong);
  color: var(--fg-dim);
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  cursor: pointer;
  transition: color 0.15s, border-color 0.15s, background 0.15s;
}
.signup-back:hover {
  color: var(--accent);
  border-color: var(--accent);
  background: rgba(108, 198, 255, 0.06);
}

/* Hidden variant — used in the `key-ready` phase where there's no
   meaningful "back" action (going back would drop the applicant out of
   the issued-key state, which would be a UX regression). Collapses to
   zero horizontal width so the label-row layout stays identical to the
   other phases. */
/* Hidden BACK button kept in the DOM purely for layout: takes its
   natural width (same as the real button in other phases) but is
   visually and interactively inert, so the label that follows sits
   at the same x-coordinate across every phase. */
.signup-back--hidden {
  visibility: hidden;
  pointer-events: none;
}

/* Switch-account variant — used in `claim-blocked` to give the
   left-of-label slot a useful action ("switch steam account"). Slightly
   wider than the default back chip + amber-on-hover to match the
   warning palette of the claim-blocked CTA below it. */
.signup-back--switch {
  color: var(--accent);
  border-color: var(--accent);
  background: rgba(108, 198, 255, 0.05);
}
.signup-back--switch:hover {
  color: #fff;
  border-color: var(--accent);
  background: rgba(108, 198, 255, 0.14);
}

/* Strong dim — used inside .signup-label for inline data that should
   read brighter than the surrounding `// comment` text. */
.signup-label .dim-strong {
  color: var(--fg);
}

/* Long/short label variants — wide phrasing with the persona inline on
   roomy terminals, shorter "// playtest key ready" on narrow widths so
   the label-row doesn't wrap. */
.signup-label-narrow { display: none; }
@media (max-width: 640px) {
  .signup-label-wide { display: none; }
  .signup-label-narrow { display: inline; }
}

/* Invisible BACK in the email-form phase — reserves the same VERTICAL
   space as a real BACK button (so the meta line below stays put across
   phases), but consumes no horizontal width on the desktop label-row
   layout so the label sits at the same X position too. width:0 +
   overflow:hidden clips the rendered "← back" away; padding-top/bottom
   + border are preserved so the box still has its natural ~22px
   height in column-stacked layouts at ≤1000. */
.signup-back-placeholder {
  visibility: hidden;
  pointer-events: none;
  width: 0;
  min-width: 0;
  padding-left: 0;
  padding-right: 0;
  margin: 0;
  overflow: hidden;
  white-space: nowrap;
}
/* Stacked layout (≤1000): the email-form's invisible BACK was reserving
   ~22px of vertical space, pushing the label / input / submit down.
   The tail min-height (220/260px) already absorbs phase-to-phase tail
   size differences, so we can safely collapse the placeholder to zero
   here. The meta line still anchors to the bottom of the centered
   signup block, so phase-to-phase drift is minimal. */
@media (max-width: 1000px) {
  .signup-back-placeholder {
    height: 0;
    min-height: 0;
    padding-top: 0;
    padding-bottom: 0;
    border: 0;
  }
}

/* ---- Step 2: Sign in through Steam ---- */
.signup-row-email-done {
  border-color: var(--ok);
}
.steam-btn {
  /* Margin handled by parent .signup-label-row (margin-bottom: 10px),
     same as the email-form's input row sits 10px below its label. */
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 0 16px;
  /* Same locked height as .signup-row / .signup-row-inline so the
     meta line below sits at the same Y position across all phases. */
  min-height: 52px;
  box-sizing: border-box;
  border: 1px solid var(--line-strong);
  background: linear-gradient(180deg, #1b2838 0%, #0f1b27 100%);
  color: #c7d5e0;
  font-family: var(--mono);
  font-size: 12px;
  line-height: 1.2;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  font-weight: 600;
  cursor: pointer;
  transition: border-color 0.15s, box-shadow 0.15s, background 0.15s, color 0.15s;
}
.steam-btn:hover {
  border-color: var(--accent);
  color: #fff;
  background: linear-gradient(180deg, #243949 0%, #14222f 100%);
  box-shadow: 0 0 24px rgba(108, 198, 255, 0.25);
}
.steam-btn .steam-logo {
  width: 22px;
  height: 22px;
  flex-shrink: 0;
  color: #c7d5e0;
}
.steam-btn:hover .steam-logo { color: #fff; }
.steam-btn .steam-btn-label {
  flex: 1;
  text-align: left;
}
.steam-btn .arrow {
  color: var(--accent);
  font-size: 14px;
  transition: transform 0.15s;
}
.steam-btn:hover .arrow { transform: translateX(3px); }
/* Two text variants for the Steam button — long phrasing on roomy
   viewports, shorter "Sign in via Steam" on ≤640 so it wraps to two
   lines max inside the 100px mobile pill. The toggle lives next to
   the button definition because both versions ship in the DOM and
   only display differs across the breakpoint. */
.steam-btn-text-short { display: none; }

/* ---- Final confirmation: inline email + steam pills ---- */
.signup-row-inline {
  flex-direction: row;
  align-items: stretch;
  border-color: var(--ok);
  /* .signup-row already has min-height: 52px — this variant inherits it.
     Confirmed-email / confirmed-steam children also stretch to fill,
     so the row reads as a single block at the same height as the
     email-input row and the steam button. */
}
.signup-row-inline .confirmed-email,
.signup-row-inline .confirmed-steam {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 11px 14px;
  min-width: 0;
}
.signup-row-inline .confirmed-email {
  flex: 1 1 auto;
  min-width: 0;
}
.signup-row-inline .confirmed-steam {
  border-left: 1px dashed var(--line-strong);
  color: var(--fg);
  font-size: 11px;
  letter-spacing: 0.18em;
  flex: 0 0 auto;
}
.confirmed-steam .steam-logo {
  width: 16px;
  height: 16px;
  color: var(--fg);
}
.confirmed-steam-label {
  color: var(--fg);
}

/* ---------- Section frame ---------- */
.section {
  position: relative;
  /* Asymmetric vertical: pb > pt so the gap above a divider reads larger
     than the gap below it (optical compensation for the heavier text
     content that follows the divider). */
  padding: clamp(32px, 8vw, 80px) 40px clamp(48px, 12vw, 120px);
  border-top: 1px solid var(--line);
}
.section-inner {
  max-width: 1440px;
  margin: 0 auto;
}
.section-tag {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-size: 11px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 18px;
}
.section-tag .num {
  color: var(--fg-mute);
  font-variant-numeric: tabular-nums;
}
.section-tag::before {
  content: "";
  width: 28px; height: 1px;
  background: var(--accent);
}
.section-title {
  font-family: var(--display);
  font-weight: 500;
  font-size: clamp(22px, 2.8vw, 34px);
  line-height: 1.2;
  letter-spacing: 0;
  margin: 0 0 28px;
  max-width: 900px;
  text-wrap: balance;
}
.section-title em {
  font-style: normal;
  color: var(--accent);
}
.section-lead {
  color: var(--fg-dim);
  font-size: 15px;
  line-height: 1.7;
  max-width: 680px;
  margin: 0 0 56px;
}

/* ---------- Briefing ---------- */
.briefing-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0;
  border: 1px solid var(--line);
  background: rgba(7,16,26,0.4);
}
.briefing-cell {
  padding: 28px 32px;
  border-right: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  position: relative;
}
.briefing-cell:nth-child(2n) { border-right: 0; }
.briefing-cell:nth-last-child(-n+2) { border-bottom: 0; }
.briefing-cell .key {
  display: flex;
  justify-content: space-between;
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--fg-mute);
  margin-bottom: 14px;
}
.briefing-cell .key .id { color: var(--accent); }
.briefing-cell .val {
  color: var(--fg);
  font-size: 16px;
  line-height: 1.55;
}
.briefing-cell .val strong { color: var(--accent-2); font-weight: 500; }

/* ---------- Features ---------- */
.feat-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
}
.feat {
  background: var(--bg-1);
  padding: 36px 32px;
  position: relative;
  min-height: 280px;
  display: flex;
  flex-direction: column;
  cursor: default;
  transition: background 0.2s;
}
.feat:hover {
  background: var(--bg-2);
}
.feat-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  margin-bottom: 24px;
}
.feat-num {
  font-size: 11px;
  letter-spacing: 0.2em;
  color: var(--fg-mute);
  text-transform: uppercase;
}
.feat-tag {
  font-size: 10px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  padding: 3px 8px;
  border: 1px solid var(--line-strong);
  color: var(--accent);
}
.feat-icon {
  width: 40px;
  height: 40px;
  background-color: var(--accent);
  margin-bottom: 18px;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: left center;
  mask-position: left center;
  -webkit-mask-size: contain;
  mask-size: contain;
  transition: background-color 0.2s;
}
.feat:hover .feat-icon { background-color: var(--accent-2); }
.feat-title {
  font-family: var(--display);
  font-size: 17px;
  font-weight: 500;
  line-height: 1.3;
  margin: 0 0 12px;
  color: var(--fg);
}
.feat-desc {
  color: var(--fg-dim);
  font-size: 13px;
  line-height: 1.65;
  margin: 0;
}

/* ---------- Module devs ---------- */
.modules {
  background:
    linear-gradient(135deg, rgba(255,178,71,0.06) 0%, transparent 60%),
    rgba(7, 16, 26, 0.6);
  border: 1px solid rgba(255, 178, 71, 0.25);
  padding: 56px;
  display: grid;
  grid-template-columns: 1.2fr 1fr;
  gap: 56px;
  align-items: center;
  position: relative;
}
.modules::before {
  content: "";
  position: absolute;
  top: -1px; left: -1px; width: 18px; height: 18px;
  border-top: 2px solid var(--warn);
  border-left: 2px solid var(--warn);
}
.modules::after {
  content: "";
  position: absolute;
  bottom: -1px; right: -1px; width: 18px; height: 18px;
  border-bottom: 2px solid var(--warn);
  border-right: 2px solid var(--warn);
}
.modules-tag {
  color: var(--warn);
  font-size: 11px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  margin-bottom: 16px;
}
.modules h3 {
  font-family: var(--display);
  font-size: 38px;
  font-weight: 500;
  line-height: 1.1;
  margin: 0 0 20px;
  letter-spacing: -0.01em;
}
.modules h3 em {
  font-style: normal;
  color: var(--warn);
}
.modules p {
  color: var(--fg-dim);
  margin: 0 0 24px;
  font-size: 14px;
  line-height: 1.7;
}
.modules-amt {
  font-family: var(--display);
  font-size: 96px;
  line-height: 1;
  font-weight: 500;
  color: var(--warn);
  letter-spacing: -0.04em;
  text-shadow: 0 0 40px rgba(255,178,71,0.3);
}
.modules-amt-label {
  font-size: 11px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--fg-dim);
  margin-top: 4px;
}
.modules-amt-meta {
  margin-top: 28px;
  border-top: 1px dashed rgba(255,178,71,0.3);
  padding-top: 16px;
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--fg-mute);
  display: flex;
  justify-content: space-between;
}
.modules-amt-meta .v { color: var(--warn); }

.btn-warn {
  background: var(--warn);
  color: #04070b;
}
.btn-warn:hover {
  background: #ffc56b;
  box-shadow: 0 0 32px rgba(255,178,71,0.5);
}

/* ---------- FAQ ---------- */
.faq-list {
  border-top: 1px solid var(--line);
}
.faq-item {
  border-bottom: 1px solid var(--line);
}
.faq-q {
  display: flex;
  align-items: center;
  gap: 24px;
  width: 100%;
  padding: 24px 0;
  background: transparent;
  border: 0;
  text-align: left;
  cursor: pointer;
  color: var(--fg);
  transition: color 0.15s;
}
.faq-q:hover { color: var(--accent); }
.faq-q .num {
  font-size: 11px;
  color: var(--fg-mute);
  letter-spacing: 0.18em;
  font-variant-numeric: tabular-nums;
  width: 36px;
  flex-shrink: 0;
}
/* Hide the leading question number on narrow viewports — the wide left
   gutter eats space the wrapped question text needs more. Mirror the
   1000px breakpoint that stacks the hero / nav. */
@media (max-width: 1000px) {
  .faq-q .num { display: none; }
}
.faq-q .label {
  font-family: var(--display);
  /* Softer scaling: never below 18px so questions stay readable on phones,
     ramp up to 22px on roomy viewports. */
  font-size: clamp(18px, 2vw, 22px);
  font-weight: 500;
  flex: 1;
}
.faq-q .chev {
  color: var(--accent);
  font-size: 18px;
  transition: transform 0.2s;
}
.faq-item.open .faq-q .chev { transform: rotate(45deg); }
.faq-a {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.25s ease;
}
.faq-item.open .faq-a { grid-template-rows: 1fr; }
.faq-a-inner {
  overflow: hidden;
  color: var(--fg-dim);
  font-size: 14px;
  line-height: 1.7;
  padding-left: 60px;
  padding-right: 80px;
  max-width: 900px;
}
.faq-item.open .faq-a-inner {
  padding-bottom: 28px;
}
/* On narrow viewports the desktop padding (60 + 80) eats most of the row.
   The number gutter is hidden below 1000px, so drop the left indent and
   keep only a token right inset so the answer still reads as nested. */
@media (max-width: 1000px) {
  .faq-a-inner {
    padding-left: 0;
    padding-right: 16px;
  }
}

/* ---------- Final CTA ---------- */
.cta-morph {
  transition: background 0.5s ease, color 0.5s ease, border-color 0.5s ease, box-shadow 0.5s ease;
}
.cta-morph--discord {
  background: #5865F2;
  color: #fff;
  border-color: #5865F2;
  box-shadow: 0 0 32px rgba(88, 101, 242, 0.45);
  animation: ctaMorphIn 0.5s ease both;
}
.cta-morph--discord:hover {
  background: #6f7bff;
  box-shadow: 0 0 40px rgba(88, 101, 242, 0.7);
}
@keyframes ctaMorphIn {
  0%   { transform: scale(0.98); filter: hue-rotate(-30deg) brightness(1.4); }
  60%  { transform: scale(1.02); filter: hue-rotate(0deg) brightness(1.1); }
  100% { transform: scale(1);    filter: none; }
}

.final {
  text-align: center;
  /* pt < pb to mirror the optical compensation used on .section. */
  padding: clamp(48px, 11vw, 100px) 40px clamp(56px, 12vw, 120px);
  border-top: 1px solid var(--line);
  background:
    radial-gradient(600px 300px at 50% 0%, rgba(108,198,255,0.1), transparent 70%);
}
.final h2 {
  font-family: var(--display);
  font-size: clamp(28px, 4vw, 48px);
  line-height: 1.1;
  font-weight: 500;
  margin: 0 0 24px;
  letter-spacing: 0;
}
.final h2 em { font-style: normal; color: var(--accent); }
.final p {
  color: var(--fg-dim);
  font-size: 15px;
  max-width: 540px;
  margin: 0 auto 36px;
  line-height: 1.7;
}
.final .cta-row { justify-content: center; }

/* ---------- Footer ---------- */
.footer {
  border-top: 1px solid var(--line);
  padding: 28px 40px 32px;
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--fg-mute);
}
.footer-links-row {
  max-width: 1440px;
  margin: 0 auto 22px;
  padding-bottom: 22px;
  border-bottom: 1px solid var(--line);
}
.footer-links {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 18px;
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}
.footer-links a {
  position: relative;
  color: var(--fg-dim);
  padding: 6px 2px;
  transition: color 0.18s;
  cursor: pointer;
  text-decoration: none;
}
.footer-links a::after {
  content: "";
  position: absolute;
  left: 0;
  right: 100%;
  bottom: 0;
  height: 1px;
  background: var(--accent);
  box-shadow: 0 0 8px var(--accent);
  transition: right 0.22s ease;
}
.footer-links a:hover { color: var(--accent); }
.footer-links a:hover::after { right: 0; }
.footer-links-sep {
  color: var(--fg-mute);
  opacity: 0.45;
  user-select: none;
}
.footer-inner {
  max-width: 1440px;
  margin: 0 auto;
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 24px;
}
.footer-block-lead { min-width: 0; max-width: 540px; }
.footer-co {
  color: var(--fg);
  letter-spacing: 0.18em;
  margin-bottom: 6px;
}
.footer-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 16px 32px;
}
.footer-meta-item { min-width: 0; }
.footer-meta-key { color: var(--fg-dim); margin-bottom: 4px; }
.footer-meta-val { color: var(--fg); }
.footer-meta-val.accent { color: var(--accent); }
.footer .lore {
  font-style: italic;
  text-transform: none;
  letter-spacing: normal;
  color: var(--fg-mute);
  opacity: 0.65;
  font-size: 11px;
  max-width: 520px;
  line-height: 1.6;
}

@media (max-width: 640px) {
  .footer { padding: 24px 20px 28px; }
  .footer-inner {
    flex-direction: column;
    align-items: stretch;
    gap: 20px;
  }
  .footer-meta {
    flex-direction: column;
    align-items: flex-start;
    gap: 14px;
  }
  .footer-block-lead { max-width: 100%; }
}

/* ---------- Legal modal ---------- */
.legal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(2, 5, 9, 0.78);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  /* Above .nav (z-index: 9992) so the nav doesn't hover over the modal. */
  z-index: 10000;
  display: flex;
  align-items: stretch;
  justify-content: center;
  animation: legal-fade 0.18s ease-out;
}
@keyframes legal-fade {
  from { opacity: 0; }
  to { opacity: 1; }
}
.legal-modal {
  position: relative;
  flex: 1 1 auto;
  min-width: 0;
  background:
    linear-gradient(180deg, rgba(12, 24, 36, 0.96), rgba(7, 14, 22, 0.98));
  border: 1px solid var(--line-strong);
  box-shadow:
    0 0 0 1px rgba(108, 198, 255, 0.04),
    0 40px 120px rgba(0, 0, 0, 0.6),
    0 0 60px rgba(108, 198, 255, 0.08);
  display: flex;
  flex-direction: column;
  min-height: 0;
  font-family: var(--mono);
  animation: legal-slide 0.22s cubic-bezier(.16,1,.3,1);
}
@keyframes legal-slide {
  from { transform: translateY(8px); opacity: 0; }
  to { transform: translateY(0); opacity: 1; }
}
.legal-modal::before {
  content: "";
  position: absolute;
  inset: 4px;
  border: 1px solid rgba(108, 198, 255, 0.06);
  pointer-events: none;
  z-index: 0;
}
.legal-head {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 18px 22px;
  border-bottom: 1px solid var(--line);
  background: rgba(7, 14, 22, 0.7);
  position: relative;
  z-index: 2;
}
.legal-head-left {
  display: flex;
  align-items: baseline;
  gap: 10px;
  min-width: 0;
}
.legal-prompt {
  color: var(--accent);
  font-family: var(--mono);
  font-size: 14px;
  letter-spacing: 0;
}
.legal-title {
  margin: 0;
  font-family: var(--mono);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--fg);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.legal-close {
  flex-shrink: 0;
  background: transparent;
  border: 1px solid transparent;
  color: var(--fg-dim);
  font-size: 22px;
  font-family: var(--mono);
  line-height: 1;
  width: 36px;
  height: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: color 0.15s, background 0.15s, border-color 0.15s;
}
.legal-close:hover {
  color: var(--accent);
  background: rgba(108, 198, 255, 0.06);
  border-color: var(--line-strong);
}
.legal-body {
  flex: 1 1 auto;
  overflow-y: auto;
  overflow-x: hidden;
  /* Stop wheel/touch scroll from bubbling out into the page once the
     internal scrollable region hits its top/bottom edge. */
  overscroll-behavior: contain;
  position: relative;
  z-index: 1;
  scrollbar-width: thin;
  scrollbar-color: var(--line-strong) transparent;
}
.legal-body::-webkit-scrollbar { width: 10px; }
.legal-body::-webkit-scrollbar-track { background: transparent; }
.legal-body::-webkit-scrollbar-thumb {
  background: var(--line-strong);
  border: 3px solid transparent;
  background-clip: padding-box;
  border-radius: 10px;
}
.legal-body-inner {
  max-width: 720px;
  margin: 0 auto;
  padding: 28px 24px 48px;
  /* Body prose in JetBrains Mono to match the terminal/CLI tone of the
     rest of the site. Headings, tags, pills etc. already use --mono via
     their own rules — this just swaps the previous Space Grotesk default
     used for the paragraph copy. */
  font-family: var(--mono);
  font-size: 13.5px;
  line-height: 1.65;
  color: var(--fg-dim);
  letter-spacing: 0;
  text-transform: none;
  text-wrap: pretty;
}
.legal-body-inner h3 {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 32px 0 12px;
  font-weight: 600;
}
.legal-body-inner h3:first-of-type { margin-top: 8px; }
.legal-body-inner p { margin: 0 0 16px; }
.legal-body-inner strong { color: var(--fg); font-weight: 600; }
.legal-body-inner ul {
  margin: 0 0 16px;
  padding-left: 22px;
}
.legal-body-inner li { margin-bottom: 6px; }
.legal-body-inner a {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-thickness: 1px;
  transition: color 0.15s;
}
.legal-body-inner a:hover {
  color: #fff;
}
.legal-body-inner code,
.legal-body-inner .legal-mono {
  font-family: var(--mono);
  font-size: 12.5px;
  color: var(--fg);
  background: rgba(108, 198, 255, 0.06);
  padding: 1px 6px;
  border-radius: 2px;
  letter-spacing: 0.02em;
}
.legal-body-inner .legal-meta {
  color: var(--fg-mute);
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  margin-bottom: 22px;
  padding-bottom: 16px;
  border-bottom: 1px solid var(--line);
}

/* Modal sizing tiers per spec:
   <800px: full-bleed (no padding on backdrop, modal stretches to fill)
   >=800px: 40px gutter on every side, locked at 800px max width AND
           sized to content height — centered vertically when short.
           Capped at 100% available height so overflow scrolls inside
           the body instead of pushing the modal off-screen. */
@media (min-width: 800px) {
  .legal-backdrop {
    padding: 40px;
    align-items: center;
  }
  .legal-modal {
    flex: 0 1 800px;
    max-width: 100%;
    max-height: 100%;
  }
  .legal-head { padding: 22px 28px; }
  .legal-body-inner { padding: 36px 40px 56px; }
}

/* ---------- Activation modal (Key Activation) ---------- */
.activation-body h3 {
  margin-top: 36px;
}
/* The first h3 sits below the intro paragraph (which already adds
   16px margin-bottom). 20px on top totals 36px — same as every
   other h3-to-h3 gap in the doc. */
.activation-body h3:first-of-type { margin-top: 20px; }
.activation-pill {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 14px 16px;
  margin: 0 0 16px;
  background:
    linear-gradient(135deg, rgba(42, 71, 94, 0.55), rgba(23, 38, 54, 0.85));
  border: 1px solid rgba(108, 198, 255, 0.18);
  border-left: 2px solid var(--accent);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03);
  position: relative;
}
.activation-pill-left {
  display: flex;
  align-items: center;
  gap: 14px;
  min-width: 0;
}
.activation-avatar {
  flex: 0 0 auto;
  width: 56px;
  height: 56px;
  border: 1px solid rgba(108, 198, 255, 0.25);
  background: #0a141f;
  position: relative;
}
.activation-avatar svg { display: block; width: 100%; height: 100%; }
.activation-pill-meta {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.activation-pill-state {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: #7ad17a;
  display: flex;
  align-items: center;
  gap: 8px;
}
.activation-pill-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: #7ad17a;
  box-shadow: 0 0 6px rgba(122, 209, 122, 0.65);
}
.activation-pill-persona {
  font-family: var(--mono);
  font-size: 15px;
  color: var(--fg);
  letter-spacing: 0.02em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.activation-pill-id {
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--fg-mute);
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
.activation-pill-mark {
  flex: 0 0 auto;
  width: 24px;
  height: 24px;
  color: rgba(207, 231, 255, 0.55);
}
.activation-no-steam {
  display: flex;
  gap: 14px;
  align-items: flex-start;
  padding: 16px 16px 18px;
  margin: 0 0 16px;
  background: rgba(255, 176, 89, 0.04);
  border: 1px solid rgba(255, 176, 89, 0.25);
  border-left: 2px solid #ffb059;
}
.activation-no-steam-glyph {
  flex: 0 0 auto;
  width: 28px;
  height: 28px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--mono);
  font-weight: 700;
  font-size: 16px;
  color: #ffb059;
  border: 1px solid rgba(255, 176, 89, 0.45);
  background: rgba(255, 176, 89, 0.08);
}
.activation-no-steam-body { min-width: 0; flex: 1 1 auto; }
.activation-no-steam-title {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: #ffb059;
  margin-bottom: 8px;
}
.activation-no-steam-body p {
  margin: 0 0 12px;
}
.activation-no-steam-cta {
  background: transparent;
  border: 1px solid rgba(255, 176, 89, 0.45);
  color: #ffb059;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  padding: 8px 12px;
  cursor: pointer;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.activation-no-steam-cta:hover {
  background: rgba(255, 176, 89, 0.1);
  border-color: #ffb059;
  color: #ffd9a8;
}
.activation-warn {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 12px 14px;
  margin: 0;
  border: 1px dashed var(--line-strong);
  background: rgba(108, 198, 255, 0.03);
}
.activation-warn-tag {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: #ffb059;
}
.activation-warn p { margin: 0; }
.activation-steps {
  list-style: none;
  margin: 0 0 16px;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.activation-steps > li {
  display: flex;
  gap: 14px;
  align-items: flex-start;
}
.activation-step-num {
  flex: 0 0 auto;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.2em;
  color: var(--accent);
  border: 1px solid rgba(108, 198, 255, 0.25);
  padding: 4px 8px;
  margin-top: 2px;
  min-width: 36px;
  text-align: center;
}
.activation-step-body { flex: 1 1 auto; min-width: 0; }
.activation-step-body p { margin: 0 0 8px; }
.activation-screenshot {
  margin: 10px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.activation-screenshot img {
  width: 100%;
  height: auto;
}
/* Wide variant: authored at 454x200, with transparency. Shown at native
   size when there is at least 454px of content area; gracefully scales
   below that until the container-query swap kicks in. */
.activation-screenshot img.activation-screenshot-wide {
  display: block;
  max-width: 454px;
  aspect-ratio: 454 / 200;
}
/* Narrow variant: a tighter crop of the Steam menu (276x200) for small
   modal widths. Hidden by default; revealed by the container query
   below. Inside its own band it also caps at native size and soft-scales
   when the container is narrower than 276px. */
.activation-screenshot img.activation-screenshot-narrow {
  display: none;
  max-width: 276px;
  aspect-ratio: 276 / 200;
}
/* Swap source based on the actual modal content width rather than the
   viewport — the modal can be wide on a narrow viewport (it's locked at
   800px from 800px viewport up) and vice versa. The legal body inner is
   declared as a size container so we can switch the screenshot when it
   no longer has room for the 454-wide variant. */
.legal-body-inner { container-type: inline-size; }
@container (max-width: 454px) {
  .activation-screenshot img.activation-screenshot-wide { display: none; }
  .activation-screenshot img.activation-screenshot-narrow { display: block; }
}
.activation-screenshot figcaption {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--fg-mute);
}

/* ---------- Claim CTA (post-Steam-link bottom-block button) ----------
   Single full-width primary action used in the `key-ready` and
   `claim-blocked` phases of the terminal. Visually it's a louder,
   accent-filled sibling of .steam-btn — same 52px locked height so the
   meta line beneath it lands at the same Y as the email/steam pills. */
.claim-cta {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 0 18px;
  min-height: 52px;
  box-sizing: border-box;
  border: 1px solid var(--accent);
  background: linear-gradient(180deg, rgba(108, 198, 255, 0.18), rgba(108, 198, 255, 0.08));
  color: var(--accent);
  font-family: var(--mono);
  font-size: 13px;
  line-height: 1.2;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  font-weight: 600;
  cursor: pointer;
  transition: border-color 0.15s, box-shadow 0.15s, background 0.15s, color 0.15s;
  box-shadow:
    0 0 24px rgba(108, 198, 255, 0.15),
    inset 0 0 0 1px rgba(108, 198, 255, 0.08);
}
.claim-cta:hover {
  background: linear-gradient(180deg, rgba(108, 198, 255, 0.32), rgba(108, 198, 255, 0.14));
  color: #fff;
  box-shadow:
    0 0 32px rgba(108, 198, 255, 0.35),
    inset 0 0 0 1px rgba(108, 198, 255, 0.18);
}
.claim-cta .claim-cta-label { flex: 1; text-align: left; }
.claim-cta .arrow {
  color: inherit;
  font-size: 14px;
  transition: transform 0.15s;
}
.claim-cta:hover .arrow { transform: translateX(3px); }
/* Mobile/narrow viewport: match the 100px action-row contract used by
   .steam-btn and .signup-row so the bottom-block layout is the same
   total height as the email-form / steam-link phases — keeps the
   label row and meta line at the same Y across all phases. */
@media (max-width: 640px) {
  .claim-cta {
    height: 84px;
    min-height: 84px;
    font-size: 14px;
    letter-spacing: 0.18em;
    line-height: 1.3;
  }
  .claim-cta .claim-cta-label { line-height: 1.3; }
  .claim-cta .arrow { font-size: 20px; }
}
/* Warn variant — used for "Resolve Steam Account" in the claim-blocked
   phase. Same chrome, amber palette. */
.claim-cta--warn {
  border-color: var(--warn);
  background: linear-gradient(180deg, rgba(255, 178, 71, 0.16), rgba(255, 178, 71, 0.06));
  color: var(--warn);
  box-shadow:
    0 0 24px rgba(255, 178, 71, 0.15),
    inset 0 0 0 1px rgba(255, 178, 71, 0.08);
}
.claim-cta--warn:hover {
  background: linear-gradient(180deg, rgba(255, 178, 71, 0.28), rgba(255, 178, 71, 0.12));
  color: #ffd9a8;
  box-shadow:
    0 0 32px rgba(255, 178, 71, 0.35),
    inset 0 0 0 1px rgba(255, 178, 71, 0.2);
}

/* ---------- Debug navigation links in .signup-meta ----------
   Step the prototype forward through the post-link states. Visually
   muted (mono, mute-coloured) so they read as developer affordances
   rather than primary UI. */
.signup-meta .debug-sep {
  color: var(--fg-mute);
  margin: 0 2px;
}
.signup-meta .debug-tag {
  font-family: var(--mono);
  color: var(--fg-mute);
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
.signup-meta a.debug-link {
  font-family: var(--mono);
  color: var(--fg-mute);
  text-decoration: underline dotted;
  text-underline-offset: 2px;
  letter-spacing: 0.04em;
}
.signup-meta a.debug-link:hover {
  color: var(--warn);
}

/* ---------- Key block (inside activation modal when key is issued) ----
   This is the focal point of the "your access is ready" view, so it
   gets accent treatment: brighter border, larger mono key, and a
   clearly clickable copy button. */
.key-block {
  margin: 0;
  /* Anchor for the absolutely-positioned `.key-block-feedback` —
     the feedback line floats below the row without claiming layout
     space, so the rhythm above section 3 stays the same whether the
     "copied" toast is visible or not. */
  position: relative;
}
.key-block-row {
  display: flex;
  align-items: stretch;
  gap: 0;
  /* Lock a consistent overall height on wider layouts so the value cell
     can't grow taller than the copy button on the right. */
  min-height: 56px;
  border: 1px solid var(--accent);
  background:
    linear-gradient(180deg, rgba(108, 198, 255, 0.10), rgba(108, 198, 255, 0.04));
  box-shadow:
    0 0 28px rgba(108, 198, 255, 0.18),
    inset 0 0 0 1px rgba(108, 198, 255, 0.08);
}
.legal-body-inner .key-block-value {
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  padding: 14px 22px;
  font-family: var(--mono);
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0.18em;
  color: var(--accent);
  background: transparent;
  user-select: all;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.key-block-copy {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 0 20px;
  background: transparent;
  border: 0;
  border-left: 1px solid var(--accent);
  color: var(--accent);
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  cursor: pointer;
  transition: color 0.15s, background 0.15s;
}
.key-block-copy:hover {
  color: #fff;
  background: rgba(108, 198, 255, 0.18);
}
.key-block-copy.is-copied {
  color: var(--ok);
  border-left-color: var(--ok);
}
.key-block-copy svg { display: block; }
.key-block-feedback {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ok);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.18s ease;
}
.key-block-feedback.is-visible { opacity: 1; }
/* On narrow modal widths, the key may not fit on one line — let it
   shrink and break the copy button to a row below rather than ellipsing
   the key itself. */
@container (max-width: 454px) {
  .key-block-row { flex-direction: column; min-height: 0; }
  .legal-body-inner .key-block-value {
    font-size: 13px;
    padding: 10px 16px;
    justify-content: center;
    text-align: center;
    min-height: 40px;
  }
  .key-block-copy {
    border-left: 0;
    border-top: 1px solid var(--accent);
    padding: 10px 18px;
    justify-content: center;
    min-height: 40px;
  }
  /* Drop the "Locked · " prefix in the already-claimed pill state on
     narrow modal widths — the line wraps otherwise and reads worse than
     just "Already claimed" with the ⊘ glyph carrying the lock meaning. */
  .activation-pill-state-locked-word { display: none; }
}

/* ---------- Locked Steam pill (claim-blocked modal) ---------- */
.activation-pill--locked {
  filter: grayscale(0.4);
  opacity: 0.85;
}
.activation-pill--locked .activation-pill-state--locked {
  color: var(--warn);
}
.activation-pill-state--locked .activation-pill-lock {
  width: 12px;
  height: 12px;
  display: inline-block;
  color: var(--warn);
}

/* ---------- Primary CTA inside claim-blocked / error modals ---------- */
.activation-primary-cta {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 14px 18px;
  margin-top: 8px;
  box-sizing: border-box;
  border: 1px solid var(--accent);
  background: linear-gradient(180deg, rgba(108, 198, 255, 0.18), rgba(108, 198, 255, 0.08));
  color: var(--accent);
  font-family: var(--mono);
  font-size: 13px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s, color 0.15s, box-shadow 0.15s;
}
.activation-primary-cta:hover {
  background: linear-gradient(180deg, rgba(108, 198, 255, 0.32), rgba(108, 198, 255, 0.14));
  color: #fff;
  box-shadow: 0 0 28px rgba(108, 198, 255, 0.3);
}
.activation-primary-cta .steam-logo {
  width: 18px;
  height: 18px;
  color: inherit;
}
.activation-primary-cta > span:not(.arrow) { flex: 1; text-align: left; }
.activation-primary-cta .arrow {
  font-size: 14px;
  transition: transform 0.15s;
}
.activation-primary-cta:hover .arrow { transform: translateX(3px); }

/* Tighten the modal layout for these two flows — they're short and
   shouldn't pad like the long privacy/terms documents. */
.claim-blocked-body ul,
.error-body ul { padding-left: 18px; }


/* ---------- Page-load reveal ---------- */
.loader-line {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  font-family: var(--mono);
  font-size: 13px;
  color: var(--fg-dim);
  letter-spacing: 0.08em;
  z-index: 100;
  opacity: 1;
  transition: opacity 0.3s ease;
  pointer-events: none;
  white-space: nowrap;
}
.loader-line.is-hidden { opacity: 0; }

/* Each hero element starts invisible; .hero.is-revealed staggers their fade-in. */
.hero .hero-logo,
.hero .hero-tag,
.hero .hero-sub,
.hero .cta-row,
.hero .term-card {
  opacity: 0;
  transition: opacity 0.3s ease-out;
}
.hero.is-revealed .hero-logo     { opacity: 1; transition-delay: 0.25s; }
.hero.is-revealed .hero-tag      { opacity: 1; transition-delay: 0.45s; }
.hero.is-revealed .hero-sub      { opacity: 1; transition-delay: 0.65s; }
.hero.is-revealed .cta-row       { opacity: 1; transition-delay: 0.85s; }
.hero.is-revealed .hero-keyart-wrap {
  opacity: 0.9;
  pointer-events: auto;
  transition: opacity 0.6s ease-out 1.05s;
}
.hero.is-revealed .term-card     { opacity: 1; transition-delay: 1.3s; }

/* ---------- Boot overlay (removed: page opens immediately) ---------- */
.boot-backdrop { display: none; }

/* Hero left column stays visible from the start. */
.hero-left {
  opacity: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
}
.hero-left .hero-logo { margin: 0 0 40px; }
.hero-left .hero-tag { margin: 0 0 24px; }
.hero-left .hero-sub { margin: 0 0 44px; }
.hero-left .cta-row { margin: auto 0 0; }

/* Term card sits in its hero-grid slot from the start — no boot centering. */

/* Animated trailing ellipsis for in-progress console lines.
   Note: do NOT add `overflow: hidden` to this ::after — Chrome treats an
   inline-block with overflow:hidden as an atomic box whose intrinsic
   content width counts for line-wrap decisions, which defeats the
   parent's `white-space: nowrap`. Keep overflow visible; the ::after's
   fixed 1.4em width plus the parent's nowrap is what actually keeps
   the line at a single row. */
.dots-anim::after {
  content: "";
  display: inline-block;
  width: 1.4em;
  vertical-align: baseline;
  text-align: left;
  animation: dots 1.2s steps(4, end) infinite;
}
@keyframes dots {
  0%   { content: ""; }
  25%  { content: "."; }
  50%  { content: ".."; }
  75%  { content: "..."; }
  100% { content: ""; }
}
/* ---------- Glitch text utility ---------- */
.glitch {
  position: relative;
  display: inline-block;
}
.glitch:hover::before, .glitch:hover::after {
  content: attr(data-text);
  position: absolute;
  inset: 0;
  pointer-events: none;
}
.glitch:hover::before {
  color: var(--accent);
  transform: translate(-2px, 0);
  clip-path: polygon(0 0, 100% 0, 100% 33%, 0 33%);
  animation: gl 0.4s steps(2) infinite;
}
.glitch:hover::after {
  color: var(--danger);
  transform: translate(2px, 0);
  clip-path: polygon(0 66%, 100% 66%, 100% 100%, 0 100%);
  animation: gl 0.4s steps(2) infinite reverse;
}
@keyframes gl {
  0% { transform: translate(-2px, 0); }
  50% { transform: translate(2px, -1px); }
  100% { transform: translate(-1px, 1px); }
}

/* Headings — JetBrains Mono Bold, uppercase */
.hero-tag,
.section-title,
.feat-title,
.faq-q .label,
.final h2,
.modules h3 {
  font-family: var(--mono);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0;
}

/* ---------- Logo lockup style for inline H1 ---------- */
.h-logo-fallback {
  font-family: var(--display);
  font-weight: 500;
  font-size: clamp(56px, 9vw, 120px);
  letter-spacing: 0.04em;
  line-height: 0.9;
  color: transparent;
  -webkit-text-stroke: 1.5px var(--fg);
  margin: 0;
}

/* responsive */
@media (max-width: 1000px) {
  /* Match the .signup block height to the .console-tail at this
     breakpoint so comment text centers visually instead of being
     anchored to top of the tail with empty space below. Tightened
     to ~160 so the action variants pack closer (tallest content
     is ~144) — mobile override below bumps to 260. */
  .signup,
  .signup-comment {
    min-height: 160px;
    justify-content: center;
  }

  /* === Stop scaling vertical padding between 641 and 1000 ===
     The base clamp()s (.section, .hero, .final) ramp from ~48/~77
     at 641 up to 80/120 at 1000. The 641-end values already feel
     generous, so lock vertical padding to fixed smaller numbers in
     this range. */
  .section {
    padding-top: 48px;
    padding-bottom: 72px;
  }
  .final {
    padding-top: 48px;
    padding-bottom: 72px;
  }

  /* === Unified content column ===
     Every major page block caps at the same max-width — anchored to
     the terminal modal's max-width (540) so hero content, sections,
     final CTA, and footer share a single centered column instead of
     reading as a mix of column widths. */
  .hero-inner,
  .section-inner,
  .footer-links-row,
  .footer-inner {
    max-width: 540px;
  }
  /* .final has no inner wrapper — cap each direct child individually
     instead. The section already has text-align: center, so the
     CTAs and copy stay horizontally centered within the column. */
  .final > .section-tag,
  .final > h2,
  .final > p,
  .final > .cta-row {
    max-width: 540px;
    margin-left: auto;
    margin-right: auto;
  }
  .hero-inner, .modules, .briefing-grid, .feat-grid {
    grid-template-columns: 1fr;
  }
  .briefing-cell { border-right: 0; }
  .term-card {
    justify-self: stretch;
    /* Taller card on stacked layouts: text wraps to more lines, more
       vertical breathing room, and the (now larger) bottom tail block
       has enough room to host the pills without crowding the console
       history above it. */
    height: 580px;
  }

  /* Lock the bottom tail to the height of its tallest variant (the
     pills + meta + back-row stack in steam-done) so it never resizes
     as the user moves between funnel phases. At 641–1000 pills stay
     between phases. At 641–1000 pills stay inline, so 160 covers; at
     ≤640 they stack and the form-row grows column too, bumped to 260
     below. */
  .console-tail { min-height: 140px; }

  /* signup-label-row layout (column + centered label + back at left)
     is set only at ≤640 below. At 641-1000 we keep the base inline
     row (BACK + label on the same line, left-aligned) so it matches
     the desktop look. */
  .modules { padding: 36px 24px; }
  .modules-amt { font-size: 64px; }
  .nav-links { display: none; }
  /* portal-tag stays visible now that the header logo is a compact mark
     instead of the full wordmark \u2014 there's plenty of room. */
  body { padding-top: 0; }
  .nav {
    transform: translateY(-100%);
    transition: transform 0.3s ease;
    pointer-events: none;
  }
  .nav.nav-past-hero {
    transform: translateY(0);
    pointer-events: auto;
  }

  /* Keyart stays fixed 1458x820 anchored to the top — only the hero content
     shifts. Padding-top pushes the logo below the keyart's fade edge. */
  .hero {
    /* Cap so hero-left stays anchored near the top as the viewport widens —
       below ~400px we keep the proportional 70vw, beyond that the value
       freezes so the logo doesn't drift further down on wider stacked
       layouts (up to the 1000px breakpoint). */
    padding-top: min(70vw, 280px);
    /* Lock the gap below the hero (clamp would scale up to 100 at 1000;
       user wants the 641-end value held constant across the range). */
    padding-bottom: 72px;
    justify-content: flex-start;
  }
}

.nav-cta-label-short { display: none; }
.nav-cta { flex-shrink: 0; }
@media (max-width: 1000px) {
  .nav-cta-label-full { display: none; }
  .nav-cta-label-short { display: inline; }
}

/* No special narrow-viewport nav padding/gap overrides — keep the
   default 40px / 32px chrome at every width. The logo image scales via
   its own clamp() and the CTA stays full-size with flex-shrink: 0. */

/* ---------- Cursor trail ---------- */
.cursor-fx {
  position: fixed;
  width: 8px;
  height: 8px;
  border: 1px solid var(--accent);
  pointer-events: none;
  z-index: 9999;
  transform: translate(-50%, -50%);
  mix-blend-mode: screen;
  transition: opacity 0.4s;
  opacity: 0;
}

/* Ticker */
.ticker {
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  background: rgba(7,16,26,0.5);
  overflow: hidden;
  height: 44px;
  display: flex;
  align-items: center;
  white-space: nowrap;
  font-size: 11px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--fg-dim);
}
.ticker-track {
  display: inline-flex;
  gap: 48px;
  animation: scroll 60s linear infinite;
  padding-left: 48px;
}
.ticker-track span { display: inline-flex; align-items: center; gap: 10px; }
.ticker-track .pip {
  width: 4px; height: 4px; background: var(--accent);
}
@keyframes scroll {
  to { transform: translateX(-50%); }
}

/* ---------- Mobile terminal layout ---------- */
@media (max-width: 640px) {
  /* Title ellipsizes via the base flex rules; just tighten the chrome. */
  .term-head { padding: 9px 12px; }

  /* Tighter body padding gives the form more room. */
  .term-body { padding: 14px; }

  /* Long emails / commands wrap inside the terminal instead of pushing the
     card past the viewport. Mono content stays mono, but words can break. */
  .term-card { max-width: 100%; }
  .term-card,
  .term-body,
  .console-script,
  .term-line {
    min-width: 0;
  }
  /* Bump tail min-height for the stacked-pills variant — pills go
     column at ≤640 so the tail is taller than the 220px floor set in
     the wider 1000px breakpoint. The email-form's stacked input +
     submit (~99px row + label-row + meta + padding) sets the high-
     water mark — pin to cover it so all phases match. */
  .console-tail { min-height: 200px; }

  /* signup-label-row layout (column + centered label + back at left)
     is set in the 1000px breakpoint and carries through here. */
  .term-line {
    overflow-wrap: anywhere;
    word-break: break-word;
  }

  /* Step header (back button + label): keep both on a single row. */
  .signup-label-row {
    flex-wrap: nowrap;
    gap: 10px;
  }
  .signup-label-row .signup-label {
    flex: 1 1 auto;
    min-width: 0;
    line-height: 1.5;
  }

  /* === Mobile bottom-block contract ===
     All three "action" variants (email-form input+submit, steam-btn,
     stacked pills) render at the SAME 100px height so the row above
     (label + BACK) and the row below (meta) stay at the same Y in
     every phase. Comment-only phases (// transmitting..., // verifying...)
     pin the .signup block to a matching min-height and center their
     single line of text inside it.

     BACK in the email-form phase is rendered as a real button at this
     width (overriding the .signup-back-placeholder rules that hide it
     on desktop / tablet); clicking it dismisses the relay form, the
     same effect as clicking outside the terminal. */

  /* Make the placeholder BACK visible + clickable on mobile. The
     desktop / tablet rules earlier in this file pin it to zero size
     so the label sits where the other phases place it; here we
     unset those pins so the button reads as a normal control. */
  .signup-back-placeholder {
    visibility: visible;
    pointer-events: auto;
    width: auto;
    min-width: 0;
    padding: 4px 9px;
    margin: 0;
    overflow: visible;
    white-space: normal;
    height: auto;
    min-height: 0;
    border: 1px solid var(--line-strong);
  }

  /* Match the .signup block height to the .console-tail so action and
     comment content can center within it visually. */
  .signup,
  .signup-comment {
    min-height: 200px;
    justify-content: center;
  }

  /* Labels above and below the action element (signup-label in the
     label-row, and signup-meta at the bottom) align LEFT on mobile;
     only the comment-phase placeholder text stays centered. Overrides
     the center-align rules in the 1000px breakpoint above. */
  .signup-label-row .signup-label,
  .signup .signup-label,
  .signup .signup-meta {
    text-align: left;
  }
  .signup-comment .signup-label {
    text-align: center;
  }

  /* Email-form: input + submit stacked inside a 100px row, each
     half-height via flex split — placeholder vs filled renders
     identically thanks to UA appearance:none + flex sizing. */
  .signup-row {
    flex-direction: column;
    align-items: stretch;
    height: 84px;
    min-height: 84px;
    max-height: 84px;
    box-sizing: border-box;
  }
  .signup-row input {
    flex: 1 1 0;
    width: 100%;
    min-width: 0;
    padding: 0 14px;
    font-size: 14px; /* prevents iOS Safari zoom-on-focus */
    height: auto;
    min-height: 0;
    max-height: none;
    line-height: 1;
    -webkit-appearance: none;
    appearance: none;
    box-sizing: border-box;
  }
  .signup-row button {
    flex: 1 1 0;
    width: 100%;
    padding: 0 14px;
    height: auto;
    min-height: 0;
    box-sizing: border-box;
    border-top: 1px solid var(--line-strong);
  }

  /* Steam button: same 100px pill as the email-form action area.
     Scale internal elements up so the button's visual mass feels
     proportional to its height — a tiny 18px logo on a 100px-tall
     button reads "debug placeholder", a 36px logo with bigger text
     reads "primary auth CTA". */
  .steam-btn {
    height: 84px;
    min-height: 84px;
    max-height: 84px;
    padding: 0 22px;
    gap: 16px;
    font-size: 13px;
    letter-spacing: 0.08em;
    /* Subtle inner top-highlight + bottom-shadow gives the button a
       chunky, raised feel that matches its visual weight. */
    box-shadow:
      inset 0 1px 0 rgba(255, 255, 255, 0.06),
      inset 0 -1px 0 rgba(0, 0, 0, 0.4);
  }
  .steam-btn .steam-logo {
    width: 36px;
    height: 36px;
  }
  .steam-btn .arrow {
    font-size: 20px;
  }
  .steam-btn .steam-btn-label {
    line-height: 1.35;
  }
  .steam-btn-text-long { display: none; }
  .steam-btn-text-short { display: inline; }

  /* Final state: two pills stacked inside a 100px row, each half-height
     via flex split. */
  .signup-row-inline {
    flex-direction: column;
    align-items: stretch;
    height: 84px;
    min-height: 84px;
    max-height: 84px;
  }
  .signup-row-inline .confirmed-email,
  .signup-row-inline .confirmed-steam {
    flex: 1 1 0;
    min-height: 0;
    min-width: 0;
    padding: 0 14px;
    /* Existing rule already sets display:flex + align-items:center */
  }
  .signup-row-inline .confirmed-steam {
    border-left: 0;
    border-top: 1px dashed var(--line-strong);
    justify-content: flex-start;
  }
  /* Move the green ok-mark to the LEFT of the Steam logo + label on
     mobile to mirror the email pill's "✓ <value>" pattern. CSS-only
     reorder via flex `order` — no JSX change. */
  .signup-row-inline .confirmed-steam .ok-mark {
    order: -1;
  }
  .signup-row-inline .confirmed-addr {
    overflow: hidden;
    text-overflow: ellipsis;
  }
}

/* Very narrow phones: just tighten chrome; title keeps its size and
   ellipsizes through the flex rules above. */
@media (max-width: 360px) {
  .term-head { padding: 9px 10px; gap: 8px; }
  .term-head::after { width: 28px; }
}

/* ---- Stacked CTA rows go full-width on narrow viewports ----
   At wider widths the buttons sit side-by-side at their natural
   content widths. Below 580px there isn't reliably room for both,
   so we stack them vertically and stretch each to fill the column \u2014
   targets stay tappable and the row reads as one unified block. */
@media (max-width: 580px) {
  .cta-row {
    flex-direction: column;
    align-items: stretch;
    gap: 6px;
  }
  .cta-row .btn,
  .cta-row .btn-awaiting {
    display: flex;
    width: 100%;
    justify-content: center;
  }
}
