/* ==========================================================================
   Suss — splash page styles
   Standalone, zero build step. Tokens mirror the live app's real design
   system (see plan doc / globals.css + tailwind.config.ts) — not invented.
   ========================================================================== */

:root {
  --ink: #0a0a0b;
  --stone: #151619;
  --stone-hover: #1b1c20;
  --blood: #e12528;
  --blood-dim: #8a1518;
  --bone: #e0e0e0;
  --ash: #a0a0a0;

  --font-league: 'League Gothic', sans-serif;
  --font-cinzel: 'Cinzel', serif;
  --font-inter: 'Inter', sans-serif;
  --font-body: 'Spectral', serif;

  --glow-red: 0 0 10px rgba(225, 37, 40, 0.8), 0 0 20px rgba(225, 37, 40, 0.4);
  --section-max: 920px;
}

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

html { scroll-behavior: smooth; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}

body {
  margin: 0;
  background: var(--ink);
  color: var(--bone);
  font-family: var(--font-inter);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

h1, h2, h3 {
  font-family: var(--font-cinzel);
  font-weight: 700;
  margin: 0;
  color: var(--bone);
  letter-spacing: 0.02em;
}

/* Secondary titles ("No Prep, No Rules" etc.) match the primary headline's
   display face — same family as h1/h2's League Gothic override, without
   their heavy red glow (reserved for primary titles only, see #133). */
h3 {
  font-family: var(--font-league);
  font-weight: 400;
  text-transform: uppercase;
}

p { margin: 0; }

a { color: inherit; }

img { max-width: 100%; display: block; }

button { font-family: inherit; }

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

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

/* ---------- rune texture backdrop ---------- */

.rune-texture {
  position: fixed;
  inset: 0;
  z-index: 0;
  background-image: url('assets/images/texture.jpg');
  background-size: cover;
  background-position: center;
  opacity: 0.16;
  pointer-events: none;
}

.rune-texture::after {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(ellipse at center, transparent 0%, var(--ink) 78%);
}

/* Rune glyph backdrop — ported from RuneBackground.tsx (see script.js's
   initRuneGlyphs), same pulsing/floating grid effect used app-wide. See
   issue #121. */
.rune-glyphs {
  position: fixed;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}

.rune-grid {
  height: 200%;
  width: 100%;
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 3rem;
  padding: 3rem;
  opacity: 0.27;
  animation: runeFloatUp 120s linear infinite;
}

.rune-grid.is-paused,
.rune-grid.is-paused .rune-grid__glyph {
  animation-play-state: paused;
}

@keyframes runeFloatUp {
  0%   { transform: translateY(0); }
  100% { transform: translateY(-50%); }
}

.rune-grid__glyph {
  font-family: var(--font-cinzel);
  font-size: 2.25rem;
  color: var(--blood);
  display: flex;
  align-items: center;
  justify-content: center;
  animation: runePulse ease-in-out infinite;
}

@keyframes runePulse {
  0%, 100% { opacity: 0.27; filter: drop-shadow(0 0 0px var(--blood-dim)); }
  50%      { opacity: 0.85; filter: drop-shadow(0 0 15px var(--blood-dim)); color: var(--blood); }
}

@media (min-width: 768px) {
  .rune-grid { grid-template-columns: repeat(10, 1fr); }
}

@media (min-width: 1024px) {
  .rune-grid { grid-template-columns: repeat(12, 1fr); }
}

@media (prefers-reduced-motion: reduce) {
  .rune-grid, .rune-grid__glyph { animation: none; opacity: 0.27; }
}

main, .site-footer { position: relative; z-index: 1; }

/* ---------- site nav ---------- */

/* Fixed (not sticky) so it never occupies document flow space above the
   hero — the hero photo now renders full-bleed behind it from the true
   top of the page instead of starting below a solid nav-colored bar. A
   soft downward gradient (rather than a flat translucent fill) keeps the
   nav readable without reading as an opaque black strip. See #140. */
.site-nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 20;
  padding: 1.25rem 1.5rem;
  background: linear-gradient(180deg, rgba(10, 10, 11, 0.6) 0%, rgba(10, 10, 11, 0) 100%);
  /* Reduced from 8px — read as too frosted/opaque. See issue #145. */
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
}

/* Grid (not flex) so the center links are pinned to the true page/inner
   center regardless of how wide the logo vs. CTA button are, and the logo
   + CTA stay fixed to the left/right edges at every viewport width. A flex
   layout with an auto-width center item drifts off-center whenever its
   flanking items are unequal width — which they are here. See #140. */
.site-nav__inner {
  max-width: var(--section-max);
  margin: 0 auto;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 1.5rem;
}

.site-nav__mark {
  display: flex;
  justify-self: start;
  filter: drop-shadow(0 0 6px rgba(225, 37, 40, 0.6));
}

.site-nav__links {
  display: none;
  justify-self: center;
  gap: 2rem;
}

.site-nav__links a {
  font-family: var(--font-cinzel);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--ash);
  transition: color 0.2s ease;
}

.site-nav__links a:hover,
.site-nav__links a:focus-visible {
  color: var(--bone);
}

.site-nav__cta {
  justify-self: end;
  background: var(--blood);
  color: #fff;
  font-family: var(--font-league);
  font-weight: 400;
  font-size: 0.9rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-decoration: none;
  padding: 0.6rem 1.1rem;
  border-radius: 0.55rem;
  transition: background-color 0.15s ease;
}

.site-nav__cta:hover { background: #c91e21; }

@media (min-width: 900px) {
  .site-nav__links { display: flex; }
}

/* ---------- eyebrow / shared type ---------- */

.eyebrow {
  font-family: var(--font-cinzel);
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.25em;
  text-transform: uppercase;
  color: var(--blood);
  margin: 0 0 1.25rem;
}

/* Hero's own eyebrow line — same headline face as "NO ONE TO TRUST" below
   it, not the shared Cinzel caption style. See issue #140. */
.hero__eyebrow--display {
  font-family: var(--font-league);
  font-weight: 400;
  font-size: clamp(1rem, 2.6vw, 1.3rem);
  letter-spacing: 0.06em;
}

/* ---------- hero ---------- */

/* justify-content: flex-start (not center) + a top padding sized to clear
   the fixed nav — content sits nearer the top of the viewport instead of
   dead-center. See issues #140 and #145 (nudged up further). */
.hero {
  position: relative;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  text-align: center;
  padding: 6rem 1.5rem 4rem;
  overflow: hidden;
}

/* Real game-night photo as the hero backdrop — duotone (grayscale + red
   wash) so it reads as one system with the rune/glow palette, with a slow
   drift so it feels like a memory replaying rather than a static banner.
   See issue #121. */
.hero__photo {
  position: absolute;
  inset: 0;
  z-index: -2;
  overflow: hidden;
}

.hero__photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Shifted up from 30% — was showing too much ceiling/wall at the top
     of the frame instead of the people. See issue #136. */
  object-position: center 15%;
  filter: grayscale(0.55) contrast(1.1) brightness(0.62);
  animation: heroPhotoDrift 40s ease-in-out infinite alternate;
}

@keyframes heroPhotoDrift {
  0%   { transform: scale(1.06) translate(0, 0); }
  100% { transform: scale(1.14) translate(-1.5%, -1.5%); }
}

.hero__photo::after {
  content: '';
  position: absolute;
  inset: 0;
  background:
    linear-gradient(180deg, rgba(10, 10, 11, 0.22) 0%, rgba(10, 10, 11, 0.62) 55%, var(--ink) 96%),
    radial-gradient(ellipse at center, rgba(225, 37, 40, 0.22) 0%, transparent 62%);
}

@media (prefers-reduced-motion: reduce) {
  .hero__photo img { animation: none; transform: scale(1.06); }
}

.hero__glow {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 900px;
  height: 900px;
  transform: translate(-50%, -50%);
  background: radial-gradient(circle at center, rgba(225, 37, 40, 0.16) 0%, rgba(225, 37, 40, 0.07) 40%, transparent 70%);
  animation: pulseSlow 4.5s ease-in-out infinite;
  pointer-events: none;
  z-index: -1;
}

@keyframes pulseSlow {
  0%, 100% { opacity: 0.7; transform: translate(-50%, -50%) scale(1); }
  50%      { opacity: 1;   transform: translate(-50%, -50%) scale(1.06); }
}

.hero__content {
  display: flex;
  flex-direction: column;
  align-items: center;
  max-width: 640px;
}

.hero-reveal {
  opacity: 0;
  animation: elasticIn 0.6s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}

.hero-reveal[data-reveal-order="1"] { animation-delay: 0.1s; }
.hero-reveal[data-reveal-order="2"] { animation-delay: 0.35s; }
.hero-reveal[data-reveal-order="3"] { animation-delay: 0.95s; }
.hero-reveal[data-reveal-order="4"] { animation-delay: 1.2s; }
.hero-reveal[data-reveal-order="5"] { animation-delay: 1.4s; }
.hero-reveal[data-reveal-order="6"] { animation-delay: 1.6s; }
.hero-reveal[data-reveal-order="7"] { animation-delay: 1.8s; }

@keyframes elasticIn {
  0%   { opacity: 0; transform: scale(0.9) translateY(14px); }
  60%  { opacity: 1; transform: scale(1.03) translateY(-2px); }
  100% { opacity: 1; transform: scale(1) translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
  .hero-reveal { opacity: 1; animation: none; }
}

/* ---------- logo ---------- */

/* Sized down 20% from clamp(140px, 26vw, 220px) — read as too dominant,
   leaving too little room for the rest of the hero content. See #149. */
.sigil-wrap {
  width: clamp(112px, 20.8vw, 176px);
  margin: 0 0 1.75rem;
  filter: drop-shadow(0 0 12px rgba(225, 37, 40, 0.9));
  animation: pulseGlow 5s cubic-bezier(0.4, 0, 0.6, 1) infinite;
  animation-delay: 1.4s;
}

@keyframes pulseGlow {
  0%, 100% { filter: drop-shadow(0 0 12px rgba(225, 37, 40, 0.9)); }
  50%      { filter: drop-shadow(0 0 3px rgba(225, 37, 40, 0.3)); }
}

.sigil-logo { width: 100%; height: auto; }

@media (prefers-reduced-motion: reduce) {
  .sigil-wrap { animation: none; filter: drop-shadow(0 0 8px rgba(225, 37, 40, 0.6)); }
}

/* ---------- hero headline / sub ---------- */

/* Wraps the headline in a radial vignette so it stays legible over the
   busiest part of the background photo — the hero photo itself is
   unchanged, this only darkens the small region directly behind the
   text. See issue #133. */
.hero__headline-wrap {
  position: relative;
}

/* Extends well beyond the headline itself so the same soft backdrop
   covers the eyebrow above and tagline below too — issue #136 asked for
   the vignette behind "the primary text" as a group, not just the
   headline. */
.hero__headline-vignette {
  position: absolute;
  inset: -6rem -4rem;
  z-index: -1;
  background: radial-gradient(ellipse at center, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.32) 45%, transparent 75%);
}

.hero__headline {
  position: relative;
  font-family: var(--font-league);
  font-weight: 400;
  font-size: clamp(2.4rem, 8vw, 4.5rem);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  line-height: 1.08;
  text-shadow: var(--glow-red);
  margin-bottom: 1.25rem;
}

.hero__sub {
  font-size: clamp(0.95rem, 2vw, 1.1rem);
  color: var(--ash);
  max-width: 460px;
  margin-bottom: 3rem;
}

/* Tagline as icon+label pairs instead of "|"-separated text — same League
   Gothic voice as the headline. See issue #133. */
.hero__tagline {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.75rem 1.25rem;
  max-width: 720px;
  margin-bottom: 3rem;
}

@media (min-width: 900px) {
  /* All four items share one row at desktop widths — was wrapping to a
     lonely second line there. Left wrapping below this breakpoint since
     four unwrapped items won't fit a tablet/mobile viewport without
     overflowing. See issue #136. */
  .hero__tagline { flex-wrap: nowrap; max-width: none; }
  .hero__tagline-item { white-space: nowrap; }
}

.hero__tagline-item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-family: var(--font-league);
  font-size: clamp(0.85rem, 1.8vw, 1rem);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--bone);
  opacity: 0.85;
}

.hero__tagline-icon {
  width: 1.15em;
  height: 1.15em;
  flex: 0 0 auto;
  color: var(--blood);
}

/* ---------- countdown ---------- */

.countdown { margin-bottom: 3rem; }

.countdown__label {
  font-family: var(--font-cinzel);
  font-size: 0.8rem;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--ash);
  margin-bottom: 0.75rem;
}

.countdown__digits {
  display: flex;
  align-items: baseline;
  justify-content: center;
  flex-wrap: wrap;
  row-gap: 0.5rem;
  gap: 0.4rem;
}

.countdown__unit {
  display: flex;
  flex-direction: column;
  align-items: center;
  min-width: 4.7rem;
}

/* Another 30% on top of the already-30%-bumped clamp(2.86rem, 7.8vw, 4.16rem)
   from issue #121 — see issue #129. */
.countdown__num {
  font-family: var(--font-league);
  font-size: clamp(3.72rem, 10.14vw, 5.41rem);
  color: var(--blood);
  text-shadow: var(--glow-red);
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

.countdown__unit-label {
  font-family: var(--font-cinzel);
  font-size: 0.65rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--ash);
  margin-top: 0.35rem;
}

.countdown__sep {
  font-family: var(--font-league);
  font-size: clamp(1.6rem, 4vw, 2.2rem);
  color: var(--blood-dim);
  transform: translateY(-0.4rem);
}

/* ---------- hero social spotlight ---------- */

.hero-social {
  width: 100%;
  max-width: 440px;
  /* Clears the waitlist box's pulsing glow below it — was sitting close
     enough to visually overlap. See issue #136. */
  margin-top: 2rem;
  margin-bottom: 1.75rem;
  text-align: center;
}

.hero-social__eyebrow {
  margin-bottom: 1rem;
}

.hero-social__links {
  display: flex;
  justify-content: center;
  gap: 1.75rem;
}

.hero-social .social-link__icon {
  width: 72px;
  height: 72px;
  border-width: 2px;
  box-shadow: var(--glow-red);
}

.hero-social .social-link__icon svg { width: 30px; height: 30px; }

.hero-social .social-link__label {
  font-size: 0.78rem;
}

.hero-social .social-link:hover .social-link__icon,
.hero-social .social-link:focus-visible .social-link__icon {
  box-shadow: 0 0 22px rgba(225, 37, 40, 0.65), 0 0 40px rgba(225, 37, 40, 0.3);
}

/* ---------- waitlist form ---------- */

.waitlist-form {
  position: relative;
  width: 100%;
  max-width: 480px;
  background: rgba(21, 22, 25, 0.6);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border: 1px solid rgba(225, 37, 40, 0.5);
  border-radius: 1.25rem;
  padding: 1.75rem 1.5rem;
}

/* Pulsing red glow so the signup box stands out from the rest of the
   hero. On a ::before rather than the form itself — the form already has
   its own `animation` (the .hero-reveal fade-in via [data-reveal-order]),
   and a second `animation` declaration on the same element would replace
   rather than combine with it, silently killing the reveal (this actually
   happened — the box stayed at opacity:0 forever until caught live). See
   issue #136. */
.waitlist-form::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  animation: waitlistPulse 3.5s ease-in-out infinite;
}

@keyframes waitlistPulse {
  0%, 100% { box-shadow: 0 0 20px 2px rgba(225, 37, 40, 0.2); }
  50%      { box-shadow: 0 0 32px 6px rgba(225, 37, 40, 0.4); }
}

@media (prefers-reduced-motion: reduce) {
  .waitlist-form::before { animation: none; box-shadow: 0 0 20px 2px rgba(225, 37, 40, 0.25); }
}

/* "Genesis Release..." headline + a smaller supporting line — sits above
   the eyebrow, so it reads as the reason to sign up before the CTA
   itself. Two-tier per issue #133 (previously a single sentence). */
.waitlist-form__limited {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  margin-bottom: 1.1rem;
}

/* "Genesis Release" — the big header. */
.waitlist-form__limited-headline {
  font-family: var(--font-league);
  font-weight: 400;
  font-size: clamp(1.5rem, 4vw, 1.9rem);
  letter-spacing: 0.03em;
  text-transform: uppercase;
  line-height: 1.15;
  color: var(--blood);
  text-shadow: var(--glow-red);
}

/* "Only 100 First Edition Boxes Will Be Made" — a step down from the
   headline, still in the display face so it reads as one unit with it. */
.waitlist-form__limited-sub {
  font-family: var(--font-league);
  font-weight: 400;
  font-size: clamp(0.95rem, 2.4vw, 1.1rem);
  letter-spacing: 0.03em;
  text-transform: uppercase;
  line-height: 1.25;
  color: var(--bone);
}

/* One line at typical widths (issue #140) — wraps back to normal below
   400px so it never overflows the box on small phones. */
.waitlist-form__limited-note {
  font-family: var(--font-inter);
  font-size: clamp(0.72rem, 2.1vw, 0.85rem);
  color: var(--ash);
  line-height: 1.5;
}

@media (min-width: 400px) {
  .waitlist-form__limited-note { white-space: nowrap; }
}

.waitlist-form__eyebrow {
  font-family: var(--font-cinzel);
  font-size: 0.7rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--ash);
  margin-bottom: 0.9rem;
}

/* justify-content: center — the input's flex:1 fills all free space when
   the row fits on one line (so this has no visible effect there), but
   when the button wraps to its own line on narrow screens it otherwise
   sits flush-left instead of centered. See issue #149. */
.waitlist-form__row {
  display: flex;
  justify-content: center;
  gap: 0.6rem;
  flex-wrap: wrap;
}

.waitlist-form input[type="email"] {
  flex: 1 1 200px;
  min-width: 0;
  background: rgba(0, 0, 0, 0.4);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 0.65rem;
  padding: 0.8rem 1rem;
  color: var(--bone);
  font-family: var(--font-inter);
  font-size: 0.95rem;
}

.waitlist-form input[type="email"]::placeholder { color: var(--ash); opacity: 0.7; }

.waitlist-form input[type="email"]:focus {
  outline: none;
  border-color: var(--blood);
  box-shadow: 0 0 0 3px rgba(225, 37, 40, 0.2);
}

/* Same headline face as the nav's "Join The Waitlist" button, instead of
   the shared Cinzel caption style — consistent across every waitlist
   button on the page. See issue #149. */
.waitlist-form button {
  flex: 0 0 auto;
  background: var(--blood);
  color: #fff;
  border: none;
  border-radius: 0.65rem;
  padding: 0.8rem 1.4rem;
  font-family: var(--font-league);
  font-weight: 400;
  font-size: 0.95rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background-color 0.15s ease, transform 0.15s ease;
}

.waitlist-form button:hover { background: #c91e21; }
.waitlist-form button:active { transform: scale(0.97); }

.waitlist-form button:disabled {
  opacity: 0.6;
  cursor: default;
}

.waitlist-form__status {
  font-size: 0.85rem;
  margin-top: 0.75rem;
  min-height: 1.2em;
}

.waitlist-form__status[data-state="success"] { color: #4ade80; }
.waitlist-form__status[data-state="already"] { color: var(--ash); }
.waitlist-form__status[data-state="error"]   { color: var(--blood); }

/* ---------- scroll cue ---------- */

.scroll-cue {
  position: absolute;
  bottom: 2rem;
  left: 50%;
  transform: translateX(-50%);
}

.scroll-cue span {
  display: block;
  width: 1px;
  height: 44px;
  background: linear-gradient(to bottom, transparent, var(--blood-dim));
  animation: scrollCue 2.2s ease-in-out infinite;
}

@keyframes scrollCue {
  0%   { transform: scaleY(0); transform-origin: top; opacity: 0; }
  40%  { transform: scaleY(1); transform-origin: top; opacity: 1; }
  60%  { transform: scaleY(1); transform-origin: bottom; opacity: 1; }
  100% { transform: scaleY(0); transform-origin: bottom; opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .scroll-cue { display: none; }
}

/* ---------- hero divider ---------- */

/* Marks the boundary between the hero "act" (countdown + signup + socials)
   and the rest of the page — solid and glowing, distinct from the faint
   per-section hairlines below it. */
.hero-divider {
  position: relative;
  z-index: 1;
  height: 2px;
  margin: 0 auto;
  width: min(70%, 640px);
  background: var(--blood);
  border-radius: 2px;
  box-shadow: 0 0 12px 2px rgba(225, 37, 40, 0.75), 0 0 32px 6px rgba(225, 37, 40, 0.35);
}

/* ---------- generic sections ---------- */

.section {
  position: relative;
  padding: 6rem 1.5rem;
}

/* Fading red hairline — replaces the near-invisible white border-top.
   A radial gradient reads as a ritual boundary rather than a hard UI rule. */
.section::before {
  content: '';
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  width: min(700px, 80%);
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--blood-dim) 50%, transparent);
}

/* The hero already ends on its own dedicated glowing divider (.hero-divider)
   — a second hairline immediately after it would be redundant. */
#gathering::before {
  content: none;
}

.section__inner {
  max-width: var(--section-max);
  margin: 0 auto;
  text-align: center;
}

.section h2 {
  font-family: var(--font-league);
  font-weight: 400;
  font-size: clamp(2rem, 5vw, 3rem);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  text-shadow: var(--glow-red);
  margin-bottom: 1.5rem;
  line-height: 1.2;
}

.section__body {
  font-family: var(--font-body);
  color: var(--ash);
  font-size: clamp(0.95rem, 1.6vw, 1.05rem);
  max-width: 620px;
  margin: 0 auto;
  line-height: 1.7;
}

.section__body + .section__body { margin-top: 1rem; }

/* "Be The First To Play" — same display face/red glow as the hero
   headline, on its own line above the rest of the closing CTA copy. See
   issue #140. */
.section__body--callout {
  display: block;
  font-family: var(--font-league);
  font-size: clamp(1.15rem, 2.6vw, 1.5rem);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--blood);
  text-shadow: var(--glow-red);
  margin-bottom: 0.5rem;
}

/* "The Experience" / "The Truth" mid-section labels. Bolder/bigger via the
   headline face rather than the small Cinzel caption style — these are act
   titles, not captions (issue #136) — and red to match the section eyebrow,
   overriding the earlier not-red rationale per an explicit request to make
   them red (issue #140). */
.section__subheading {
  font-family: var(--font-league);
  font-weight: 400;
  font-size: clamp(1.3rem, 3vw, 1.6rem);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--blood);
  margin: 0 0 1.1rem;
}

.experience-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}

.experience-list h3 {
  font-family: var(--font-cinzel);
  font-size: 1rem;
  letter-spacing: 0.06em;
  margin-bottom: 0.35rem;
}

.experience-list p {
  font-family: var(--font-body);
  color: var(--ash);
  font-size: 0.92rem;
  line-height: 1.6;
}

/* ---------- alternating text/image split rows ---------- */

.split-row {
  display: flex;
  flex-direction: column;
  gap: 2rem;
  max-width: var(--section-max);
  margin: 3.5rem auto 0;
  padding: 0 1.5rem;
  align-items: center;
}

.split-row__media {
  width: 100%;
  border-radius: 1.25rem;
  overflow: hidden;
  border: 1px solid rgba(255, 255, 255, 0.08);
  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.45);
}

.split-row__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  aspect-ratio: 4 / 3;
  filter: grayscale(0.4) contrast(1.08) brightness(0.85);
}

.split-row__content {
  width: 100%;
  text-align: left;
}

.split-row .section__subheading { margin-top: 0; }

/* Groups the whole row (image + list) inside one red glowing lined box,
   matching the journey list's alert-style treatment. See #133. */
.split-row--boxed {
  border: 1px solid rgba(225, 37, 40, 0.4);
  border-radius: 1.5rem;
  box-shadow: 0 0 30px rgba(225, 37, 40, 0.18), inset 0 0 20px rgba(225, 37, 40, 0.06);
  padding: 1.75rem;
}

@media (min-width: 900px) {
  .split-row {
    flex-direction: row;
    align-items: center;
    gap: 3.5rem;
    padding: 0 2rem;
    margin-top: 5rem;
  }

  .split-row__media,
  .split-row__content { flex: 1 1 0%; min-width: 0; }

  .split-row--reverse { flex-direction: row-reverse; }

  /* .split-row's own padding above (same specificity, later in the
     cascade) was zeroing out top/bottom padding here, leaving text
     flush against the box border on desktop — read as "clipping" in
     issue #136. Re-asserting it after that rule restores the box's own
     padding on every side. */
  .split-row--boxed { padding: 2rem; }
}

[data-reveal] {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity 0.7s ease-out, transform 0.7s ease-out;
}

[data-reveal].is-in {
  opacity: 1;
  transform: translateY(0);
}

@media (prefers-reduced-motion: reduce) {
  [data-reveal] { opacity: 1; transform: none; transition: none; }
}

/* ---------- roles ---------- */

.roles-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 1.25rem;
  margin-top: 2.5rem;
  text-align: center;
}

/* Angels get a white lined glow, demons a red one (below) — visually
   separates the two roles at a glance. See issue #136. */
.role-card {
  background: var(--stone);
  border: 1px solid rgba(255, 255, 255, 0.35);
  border-radius: 1rem;
  padding: 1.75rem 1.5rem;
  box-shadow: 0 0 24px rgba(255, 255, 255, 0.12);
}

.role-card--demon {
  border-color: rgba(225, 37, 40, 0.5);
  box-shadow: 0 0 24px rgba(225, 37, 40, 0.25);
}

.role-card h3 {
  font-family: var(--font-cinzel);
  font-size: 1.1rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  margin-bottom: 0.75rem;
  color: var(--bone);
}

.role-card--demon h3 { color: var(--blood); text-shadow: var(--glow-red); }

.role-card__subtitle {
  font-family: var(--font-cinzel);
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--blood-dim);
  margin-bottom: 0.9rem;
}

.role-card p {
  font-family: var(--font-body);
  color: var(--ash);
  font-size: 0.92rem;
  line-height: 1.6;
}

/* ---------- role card photo (image-top / text-below) ---------- */

.role-card {
  padding: 0;
  overflow: hidden;
}

.role-card__photo {
  aspect-ratio: 16 / 9;
  overflow: hidden;
}

.role-card__photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* A wide crop box against this tall (3:4) source shows well under half its
     height — positioning at the very top keeps it to just the illustrated
     figure, cropping out the baked-in "ANGEL"/"DEMON" title card further
     down in the source (this page has its own heading/copy for that). */
  object-position: center top;
}

.role-card__body { padding: 1.75rem 1.5rem; }

/* ---------- gallery ---------- */

.section--gallery .section__inner { margin-bottom: 2.5rem; }

.gallery-track {
  display: flex;
  gap: 1.25rem;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  padding: 0 1.5rem 1rem;
  scrollbar-width: thin;
  scrollbar-color: var(--blood-dim) transparent;
}

.gallery-card {
  flex: 0 0 auto;
  scroll-snap-align: center;
  width: min(78vw, 380px);
  aspect-ratio: 4 / 3;
  margin: 0;
  border-radius: 1.25rem;
  overflow: hidden;
  border: 1px solid rgba(255, 255, 255, 0.08);
  box-shadow: 0 16px 40px rgba(0, 0, 0, 0.4);
}

.gallery-card--tall { aspect-ratio: 3 / 4; }

.gallery-card img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: grayscale(0.4) contrast(1.08) brightness(0.85);
}

/* Looping opening-scene clip, framed like a phone screen rather than a
   plain rectangular photo. See issue #133. */
.gallery-card--phone {
  border: 3px solid var(--stone-hover);
  box-shadow: 0 0 24px rgba(225, 37, 40, 0.25), 0 16px 40px rgba(0, 0, 0, 0.4);
}

.gallery-card--phone video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.gallery-card--placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  background: repeating-linear-gradient(
    135deg,
    var(--stone),
    var(--stone) 10px,
    var(--stone-hover) 10px,
    var(--stone-hover) 20px
  );
  border-style: dashed;
  border-color: rgba(255, 255, 255, 0.15);
}

.gallery-card--placeholder span {
  font-family: var(--font-cinzel);
  font-size: 0.7rem;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--ash);
}

@media (min-width: 900px) {
  .gallery-track { padding: 0 2rem 1rem; }
  .gallery-card { width: min(32vw, 340px); }
}

/* ---------- CTA banner ---------- */

.cta-banner {
  position: relative;
  padding: 4rem 1.5rem;
  text-align: center;
  background: linear-gradient(135deg, var(--blood-dim) 0%, var(--blood) 100%);
}

.cta-banner__inner { max-width: 560px; margin: 0 auto; }

.cta-banner h2 {
  font-family: var(--font-league);
  font-weight: 400;
  font-size: clamp(1.8rem, 4.5vw, 2.6rem);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: #fff;
  margin-bottom: 0.75rem;
}

.cta-banner p {
  font-family: var(--font-body);
  color: rgba(255, 255, 255, 0.85);
  font-size: 1rem;
  margin-bottom: 1.75rem;
}

.cta-banner__button {
  display: inline-block;
  background: var(--ink);
  color: #fff;
  font-family: var(--font-cinzel);
  font-weight: 700;
  font-size: 0.8rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  text-decoration: none;
  padding: 0.9rem 1.75rem;
  border-radius: 0.65rem;
  transition: transform 0.15s ease;
}

.cta-banner__button:hover { transform: translateY(-2px); }

/* ---------- what's in the box ---------- */

.box-flatlay {
  max-width: 900px;
  margin: 3rem auto 0;
  border-radius: 1.25rem;
  overflow: hidden;
  border: 1px solid rgba(255, 255, 255, 0.08);
  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.45);
}

.box-flatlay img {
  width: 100%;
  height: auto;
}

/* ---------- journey ---------- */

/* Named specifically in issue #136 — scoped to this one eyebrow rather
   than changing the shared .eyebrow style used by every other section. */
.journey-eyebrow {
  font-family: var(--font-league);
  font-weight: 400;
  font-size: clamp(1.1rem, 2.4vw, 1.35rem);
  letter-spacing: 0.08em;
  text-shadow: var(--glow-red);
}

.journey-list {
  list-style: none;
  margin: 2.5rem 0 0;
  padding: 0;
  text-align: left;
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}

/* Boxes styled to match the in-game "Archangel claimed" alert (dark glass +
   amber glow border) — see src/app/rooms/[roomCode]/tv/page.tsx's
   archangelClaimed overlay, translated from Tailwind arbitrary values into
   plain CSS since this page has no Tailwind. See issue #121. Content
   stacked above image on mobile; alternating left/right split at desktop
   widths (below) instead of a centered column with dead space either
   side. See issue #136. */
.journey-list li {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  padding: 1.75rem 2rem;
  background: rgba(0, 0, 0, 0.95);
  backdrop-filter: blur(40px);
  -webkit-backdrop-filter: blur(40px);
  border: 1px solid rgba(251, 191, 36, 0.5);
  border-radius: 1.5rem;
  box-shadow: 0 0 40px rgba(251, 191, 36, 0.35), inset 0 0 20px rgba(251, 191, 36, 0.1);
}

.journey-list__content {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  text-align: left;
}

.journey-list__num {
  font-family: var(--font-cinzel);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.25em;
  text-transform: uppercase;
  color: var(--blood-dim);
}

.journey-list__image {
  width: 100%;
  aspect-ratio: 4 / 3;
  border-radius: 1rem;
  overflow: hidden;
}

@media (min-width: 900px) {
  .journey-list li {
    flex-direction: row;
    align-items: center;
    gap: 3rem;
  }

  .journey-list__content,
  .journey-list__image { flex: 1 1 0%; min-width: 0; }

  /* Act 2, Act 4 — image on the left, content on the right. */
  .journey-list li:nth-child(even) { flex-direction: row-reverse; }
}

/* No color grading — issue #140 flagged the desaturated look and asked
   for the real journey photos to render as-shot. */
.journey-list__image img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.journey-list h3 {
  font-size: 1.3rem;
  margin-bottom: 0.1rem;
}

.journey-list p {
  font-family: var(--font-body);
  color: var(--ash);
  font-size: 0.9rem;
  line-height: 1.6;
  max-width: 480px;
}

/* The section default's 6rem bottom padding, stacked on top of
   .section--call's own top padding right after it, read as too much dead
   space between the Act 5 box and "The Realm Opens". See issue #145. */
.section--journey {
  padding-bottom: 2rem;
}

/* ---------- final call ---------- */

.section--call {
  position: relative;
  overflow: hidden;
  /* Tighter than the section default (6rem/6rem) on both edges — the
     headline/signup form read as floating with too much dead space
     above and below otherwise. Tightened further in #145: less gap
     above the headline, and less gap after the social links below
     before the closing photo section. See issues #133, #140, #145. */
  padding-top: 2rem;
  padding-bottom: 1.25rem;
}

/* Same photo as the hero, quieter — a bookend echo rather than a third
   distinct treatment. See issue #121. */
.section--call__photo {
  position: absolute;
  inset: 0;
  z-index: 0;
}

.section--call__photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 30%;
  filter: grayscale(0.7) contrast(1.1) brightness(0.3);
}

.section--call__photo::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, var(--ink) 0%, rgba(10, 10, 11, 0.8) 30%, rgba(10, 10, 11, 0.8) 70%, var(--ink) 100%);
}

.section--call .section__inner {
  position: relative;
  z-index: 1;
}

.section--call .waitlist-form {
  margin: 2.5rem auto 0;
}

/* "Stay Connected" — moved up from the closing photo section so that
   section's image isn't obscured by text. See issue #136. */
.section--call__social {
  position: relative;
  z-index: 1;
  margin: 2.5rem auto 0;
  text-align: center;
}

/* ---------- closing photo ---------- */

.section--social-photo {
  position: relative;
  overflow: hidden;
  min-height: clamp(280px, 40vw, 480px);
}

/* Same photo motif as the hero/call sections, at its quietest treatment —
   closes out the page instead of ending on flat black. */
.section--social__photo {
  position: absolute;
  inset: 0;
  z-index: 0;
}

/* This image (LANDING_v07.png, see issue #147) is a fully composed promo
   graphic with its own baked-in text and box render, not an ambient
   lifestyle photo — kept in color and much brighter than the hero/call
   treatment so it actually reads. No text sits on top of it now (see
   .section--call__social above), so the fade only needs to blend the
   top/bottom edges into the page.
   object-fit: contain (not cover) — this box container is much shorter
   than the image's own aspect ratio, and cover cropped a real chunk off
   the graphic no matter which edge the crop was biased toward (#149
   biased it toward showing the top, which then clipped the bottom
   instead — see #151). contain guarantees the whole image is always
   visible; bottom-anchored so it sits close to the footer below it
   rather than "floating" mid-section. See issue #151. */
.section--social__photo img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: center 100%;
}

.section--social__photo::after {
  content: '';
  position: absolute;
  inset: 0;
  /* Top fade shortened from 20% -> 10% so more of the actual image is
     visible before it starts darkening. See issue #149. */
  background: linear-gradient(180deg, var(--ink) 0%, transparent 10%, transparent 80%, var(--ink) 100%);
}

.social-links {
  display: flex;
  justify-content: center;
  gap: 1.5rem;
  margin-top: 2rem;
}

.social-link {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.6rem;
  text-decoration: none;
  color: var(--ash);
  transition: color 0.2s ease, transform 0.2s ease;
}

.social-link:hover,
.social-link:focus-visible {
  color: var(--bone);
  transform: translateY(-3px);
}

.social-link__icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  border: 1.5px solid var(--blood-dim);
  color: var(--blood);
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

.social-link__icon svg { width: 24px; height: 24px; }

.social-link:hover .social-link__icon,
.social-link:focus-visible .social-link__icon {
  border-color: var(--blood);
  box-shadow: 0 0 16px rgba(225, 37, 40, 0.45);
}

.social-link__label {
  font-family: var(--font-cinzel);
  font-size: 0.7rem;
  letter-spacing: 0.15em;
  text-transform: uppercase;
}

/* ---------- footer ---------- */

.site-footer {
  padding: 3.5rem 1.5rem 2.5rem;
  border-top: 1px solid rgba(255, 255, 255, 0.06);
}

/* Grid (not a fully stacked flex column) below 640px — all three blocks
   (brand, "The Game", "Community") sit side by side in one row instead of
   each getting a full-width row. The old fully-stacked layout (#149's
   first pass only got this to two rows, brand still on its own above the
   other two) still read as too tall on mobile. See issue #151. */
.site-footer__inner {
  max-width: var(--section-max);
  margin: 0 auto;
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 1.5rem 1rem;
  text-align: center;
}

.site-footer__brand {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.6rem;
}

.site-footer__mark { opacity: 0.7; }

.site-footer__wordmark {
  font-family: var(--font-league);
  font-size: 1.4rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--bone);
}

.site-footer__col {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.site-footer__heading {
  font-family: var(--font-cinzel);
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--ash);
  opacity: 0.6;
  margin-bottom: 0.25rem;
}

.site-footer__col a {
  font-family: var(--font-inter);
  font-size: 0.9rem;
  color: var(--ash);
  text-decoration: none;
  transition: color 0.2s ease;
}

.site-footer__col a:hover,
.site-footer__col a:focus-visible { color: var(--bone); }

.site-footer__copyright {
  font-family: var(--font-cinzel);
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  color: var(--ash);
  opacity: 0.6;
  text-align: center;
  max-width: var(--section-max);
  margin: 2.5rem auto 0;
}

/* Version/build line — deliberately quieter than the copyright line above
   it, with an extra gap standing in for a line break. Empty (not just
   visually hidden) until script.js's initBuildInfo() populates it, so it
   never renders a bare gap if JS fails to run. See issue #143. */
.site-footer__build-info {
  font-family: var(--font-cinzel);
  font-size: 0.65rem;
  letter-spacing: 0.08em;
  color: var(--ash);
  opacity: 0.4;
  text-align: center;
  max-width: var(--section-max);
  margin: 1.25rem auto 0;
}

.site-footer__build-info:empty {
  margin: 0;
}

@media (min-width: 640px) {
  .site-footer__inner {
    display: flex;
    flex-direction: row;
    justify-content: space-between;
    text-align: left;
  }

  .site-footer__brand { align-items: flex-start; }
  .site-footer__copyright { text-align: left; }
}

/* ---------- responsive ---------- */

@media (max-width: 420px) {
  /* Prevents the 4th digit pair wrapping to its own row at narrow widths —
     a sizing fix only, the countdown's desktop scale (issues #121/#129) is
     untouched above this breakpoint. */
  .countdown__digits { gap: 0.2rem; }
  .countdown__unit { min-width: 3.5rem; }
  .countdown__num { font-size: clamp(2.3rem, 9.5vw, 3rem); }
  .countdown__sep { font-size: 1.3rem; }
}

@media (min-width: 640px) {
  .waitlist-form__row { flex-wrap: nowrap; }
}

@media (min-width: 900px) {
  .section { padding: 8rem 2rem; }
  .roles-grid { gap: 1.75rem; }

  /* .section's own desktop-only padding bump above (same specificity,
     later in the cascade) was silently overriding these two sections'
     deliberately tighter padding at >=900px — meaning the #140 dead-space
     fix for .section--call never actually took effect at desktop widths.
     Same pitfall already fixed once for .split-row--boxed elsewhere in
     this file; re-asserting here too. See issue #145. */
  .section--journey { padding-bottom: 2rem; }
  .section--call { padding-top: 2rem; padding-bottom: 1.25rem; }
}
