/* ------------------------------------------------------------------- */
/* ------------------ TITANS OF FIRE — ERA SKIN (2026) ----------------- */
/* Palette + artwork + hero FX for the Titans of Fire release.          */
/* Mirror-image of the DTL scheme: DTL was cool petrol blue with a      */
/* yellow accent — ToF is hot fire with a portal-teal accent.           */
/* ------------------------------------------------------------------- */

/* CAT Eckmann (Peter Wiegel, SIL OFL — license next to the font file).
   Single-weight Jugendstil display face; the 100-900 range maps every
   requested weight onto it so browsers never synthesize a faux bold. */
@font-face {
  font-family: 'CAT Eckmann';
  src: url(../fonts/CAT-Eckmann.woff2) format('woff2');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

:root {
  --accent: #ffb400;
  --accent-hot: #ff5a00;
  --accent-deep: #6b0f00;
  --accent-2: #59e2f0; /* the portal teal — links / special highlights */
  --bg: #0a0006;
  --text: #ffffff;
  --text-soft: #ece7df;
  --hero-art: url(../images/DEFENDER_titans_cover.png);
  --footer-art: url(../images/DEFENDER_titans_cover.png);
}

/* ------------------------------------------------------------------- */
/* HERO — sticky scroll story: artwork parallax, fog, embers, ignition  */
/* ------------------------------------------------------------------- */

/* Extra height beyond 100vh drives the scroll story while the hero
   stays pinned. --ignite (0..1) is written by js/parallax.js as the
   visitor scrolls through it. */
/* v3: no manual vh height here — GSAP's ScrollTrigger `pin: true`
   (js/parallax.js) pins .hero-scroll directly and inserts its own
   spacer sized from the `end` scroll distance. Under reduced motion no
   ScrollTrigger is created at all, so this just block-flows to its
   child's height (100vh) — no override needed either. */
.hero-scroll {
  position: relative;
}

.hero {
  --ignite: 0;
  /* own positioned box: .hero-art's inset:0 must anchor here, NOT skip
     up to .hero-scroll — that's the element GSAP's pin transforms
     directly, including a compensating translate3d it applies once the
     pin hands off to normal scroll. Without this, .hero-art layers
     could visibly shift right at that handoff. */
  position: relative;
  height: 100vh;
  height: 100svh; /* match the small viewport under a collapsed mobile URL bar */
  overflow: hidden;
  display: flex;
  flex-direction: column;
  align-items: center;
  /* positioning during the ride comes entirely from GSAP's pin now,
     not CSS position:sticky */
}

.hero-art {
  position: absolute;
  inset: 0;
  z-index: 0;
}

/* The "off" fallback (reduced motion OR the manual toggle): a plain
   flat-cover background, NOT the layered stack at transform:none. Two
   reasons. (1) GSAP writes transforms as inline styles, which always
   beat a class rule — if motion is switched off mid-ride, a "reset via
   CSS" approach leaves the last inline transform stuck, visibly
   zoomed in. (2) Even at a clean transform:none, the layered stack's
   object-fit/position was only ever an approximation of the JS-computed
   pan/crop, and crops wrong on aspect ratios far from what it was tuned
   against. One full-bleed image sidesteps both: nothing to get stuck,
   nothing to approximate. */
.hero-art_static {
  display: none;
  position: absolute;
  inset: 0;
  background-image: url(../images/DEFENDER_titans_cover.png);
  background-size: cover;
  background-position: center 30%;
  background-repeat: no-repeat;
}

/* v5: three planes, gapless & doubling-free by construction (full
   rationale in js/parallax.js). Transform origins live here as
   percentages ON PURPOSE: they resolve against each element's own box
   at render time, so they keep tracking the boxes parallax.js resizes —
   a JS-written px origin would go stale on resize. The static
   transforms below are only the pre-JS start-frame approximation so
   there is no flash of the composed cover before GSAP takes over.
   No will-change anywhere: three permanently-promoted 16MP textures
   would be a GPU-memory disaster; GSAP promotes layers while animating. */

/* L0 — the free parallax plane: a NEW fully opaque full-bleed painting.
   Every hole in the planes above can only ever expose this, never the
   page background. */
.hero-art_mountains {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 35%;
  transform-origin: 50% 45%; /* mountains rise slightly as they settle */
  transform: scale(1.5);
}

/* the gate group: carries the sized cover-fit box (parallax.js) and the
   big dolly transform; the two cutouts inside share its box exactly, so
   no independent rounding can ever misalign them */
.hero-art_gate {
  position: absolute;
  inset: 0;
  transform-origin: 50% 52%; /* portal-opening center (measured from alpha) */
  transform: scale(5.5);     /* pre-JS: land deep inside the portal */
}

/* the cutouts fill the group box; their box AR equals the source AR
   after parallax.js sizes the group, so object-fit is identity */
.hero-art_portal,
.hero-art_world,
.hero-art_titans {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 30%; /* only matters pre-JS / reduced motion */
}

/* residual start states (pre-JS approximation; parallax.js drives the
   real values). The invariants that keep these safe live as proofs in
   js/parallax.js — change the numbers there, not here. */
.hero-art_portal {
  transform-origin: 50% 52%;
  transform: scale(1.45);
}
.hero-art_world {
  transform-origin: 50% 52%;
  transform: scale(1.25);
}
.hero-art_titans {
  transform-origin: 50% 52%;
  transform: scale(1.35);
}

.hero-fog {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(ellipse at 50% 42%, rgba(89, 226, 240, 0.10) 0%, rgba(0, 0, 0, 0) 40%),
    linear-gradient(to bottom, rgba(0, 0, 0, 0.35) 0%, rgba(0, 0, 0, 0) 25%, rgba(0, 0, 0, 0) 80%, var(--bg) 100%);
}

/* portrait: pull the bottom fade up so the artwork's dark middle
   corridor melts into embers instead of gaping between the stairs
   and the flames */
@media (max-width: 576px) {
  .hero-fog {
    background:
      radial-gradient(ellipse at 50% 42%, rgba(89, 226, 240, 0.10) 0%, rgba(0, 0, 0, 0) 40%),
      linear-gradient(to bottom, rgba(0, 0, 0, 0.35) 0%, rgba(0, 0, 0, 0) 25%, rgba(0, 0, 0, 0) 66%, var(--bg) 96%);
  }
}

#embers {
  position: absolute;
  inset: 0;
  /* canvas is a replaced element — inset alone doesn't stretch it */
  width: 100%;
  height: 100%;
  z-index: 1;
  pointer-events: none;
}

.hero-content {
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  height: 100%;
  width: 100%;
  padding: 0 1rem;
}

.hero-content .logo {
  width: min(500px, 92vw);
  padding-top: 20px;
}

.hero-title {
  margin-top: auto;
}

/* Display headings wear the era's Jugendstil face; Crimson Text stays
   as the fallback while the woff2 loads. */
h2 {
  font-family: 'CAT Eckmann', 'Crimson Text', serif;
}

.hero-title h1 {
  font-family: 'CAT Eckmann', 'Crimson Text', serif;
  /* CAT Eckmann swaps mid-word H/I/T for their Jugendstil alternate
     glyphs via 'calt' (e.g. TITANS -> T + I.001 + T.001). Explicit so
     letter-spacing can't switch the feature off. */
  font-feature-settings: 'calt' 1;
  font-size: clamp(2rem, 9vw, 7.5rem);
  font-weight: 800;
  text-align: center;
  margin: 0;
  letter-spacing: 0.02em;
  background: linear-gradient(180deg, #ffe89a 0%, var(--accent) 38%, var(--accent-hot) 72%, #a11a00 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  filter: drop-shadow(0 0.2rem 0.3rem rgba(0, 0, 0, 0.9))
          drop-shadow(0 0 calc(var(--ignite) * 1.5rem) rgba(255, 90, 0, 0.7));
}

.release_date {
  margin-bottom: 1rem;
  font-size: 32px;
  color: var(--text);
  text-shadow: 0 0 0.6rem rgba(0, 0, 0, 0.95), 0 0 1.4rem rgba(0, 0, 0, 0.9);
}

.release_date .title {
  margin: 0;
  font-family: 'Crimson Text', serif;
  font-weight: 600;
}

@media (max-width: 576px) {
  .release_date {
    text-align: center;
    font-size: 1.2rem;
  }
}

.cta_buttons {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 0 1rem;
  margin-bottom: 3rem;
}

@media (max-width: 576px) {
  .cta_buttons {
    margin-bottom: 5rem;
  }
}

.color-fire {
  background: linear-gradient(180deg, #ffe89a 0%, var(--accent) 45%, var(--accent-hot) 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* ------------------------------------------------------------------- */
/* MOBILE NAVIGATION — artwork behind the overlay                       */
/* ------------------------------------------------------------------- */

#navigation {
  background-image: linear-gradient(rgba(5, 0, 3, 0.78), rgba(5, 0, 3, 0.78)), var(--hero-art);
  background-size: cover;
  background-position: center center;
}

/* the link back to the old era glows portal-teal in the navigation */
.mobile-navigation a.era-link {
  color: var(--accent-2) !important;
  text-shadow: -1px -1px 1rem #0b3c44,
    1px -1px 1rem #0b3c44,
    -1px 1px 1rem #0b3c44,
    1px 1px 1rem #0b3c44;
}

/* ------------------------------------------------------------------- */
/* FOOTER — the lava edge of the artwork closes the page                */
/* ------------------------------------------------------------------- */

.footer-background {
  background-image: linear-gradient(to top, rgba(0, 0, 0, 0) 70%, var(--bg) 95%), var(--footer-art);
  background-position: center bottom;
  background-size: cover;
  background-repeat: no-repeat;
  width: 100%;
  height: 110vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
}

@media (max-width: 766px) {
  .footer-background {
    background-image: linear-gradient(to top, rgba(0, 0, 0, 0) 40%, var(--bg) 60%), var(--footer-art);
    background-position: center bottom;
    height: 80vh;
    margin-top: -10vh;
  }
}

/* ------------------------------------------------------------------- */
/* REAPER PORTAL — the kneeling DTL reaper in the artwork links back    */
/* to the old era. Desktop only: on mobile the crop shifts the reaper   */
/* off-frame, so the visible .era-switch link carries that duty.        */
/* ------------------------------------------------------------------- */

.reaper-portal {
  position: absolute;
  /* the reaper kneels at ~75% x / ~11-22% up from the artwork's bottom
     edge; with a square image covering a full-width footer these vw
     offsets track it across desktop viewports */
  right: 20vw;
  bottom: 9vw;
  width: 10vw;
  height: 14vw;
  z-index: 2;
  border-radius: 50%;
  cursor: pointer;
}

.reaper-portal:hover,
.reaper-portal:focus {
  background: radial-gradient(ellipse at center, rgba(89, 226, 240, 0.22) 0%, rgba(89, 226, 240, 0) 70%);
  outline: none;
}

.reaper-portal::after {
  content: attr(data-tooltip);
  position: absolute;
  bottom: 105%;
  left: 50%;
  transform: translateX(-50%);
  white-space: nowrap;
  font-family: 'Crimson Text', serif;
  font-size: 1.2rem;
  letter-spacing: 0.2rem;
  text-transform: uppercase;
  color: var(--accent-2);
  text-shadow: 0 0 1rem rgba(0, 0, 0, 1);
  opacity: 0;
  transition: opacity 0.3s ease-out;
  pointer-events: none;
}

.reaper-portal:hover::after,
.reaper-portal:focus::after {
  opacity: 1;
}

@media (max-width: 767px) {
  .reaper-portal {
    display: none;
  }
}

/* ------------------------------------------------------------------- */
/* ERA BRIDGE — cross-document view transition between eras             */
/* (same animation lives in dying-to-live/css/style.css)                */
/* ------------------------------------------------------------------- */

@view-transition {
  navigation: auto;
}

@keyframes era-burn-out {
  to {
    opacity: 0;
    transform: scale(1.04);
    filter: brightness(2.5) saturate(2);
  }
}

@keyframes era-burn-in {
  from {
    opacity: 0;
    transform: scale(0.98);
    filter: brightness(2.5) saturate(2);
  }
}

::view-transition-old(root) {
  animation: era-burn-out 0.45s ease-in both;
}

::view-transition-new(root) {
  animation: era-burn-in 0.6s ease-out both;
}

/* ------------------------------------------------------------------- */
/* REDUCED MOTION — hero settles, effects off, page fully usable        */
/* ------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  /* no override needed: with no ScrollTrigger created at all, .hero-scroll
     already block-flows to .hero's 100vh — see the base rule above */
  .hero-art_mountains,
  .hero-art_gate {
    display: none;
  }
  .hero-art_static {
    display: block;
  }
  .hero-fog {
    opacity: 1;
  }
  #embers {
    display: none;
  }
  .hero-title h1 {
    filter: drop-shadow(0 0.2rem 0.3rem rgba(0, 0, 0, 0.9));
  }
  ::view-transition-old(root),
  ::view-transition-new(root) {
    animation: none;
  }
}

/* Desktop only: rather than crop the (near-square) artwork to fit a
   fixed 100vh box — which fades to black partway down and hides the
   lava/reaper below entirely — let .hero grow to the image's own
   aspect ratio and reveal the rest via ordinary scrolling. There's no
   pin to protect here, so plain document flow does the job. Mobile
   viewports are already close to the image's own aspect ratio, so
   the fixed-height crop there already shows most/all of it.
   .hero-content is pulled OUT of that taller flow and pinned to the
   first screen's worth — its flex layout (title anchored via
   margin-top:auto) assumes a 100vh-tall box, and would otherwise get
   dragged down with the taller .hero and end up scrolled out of view. */
@media (prefers-reduced-motion: reduce) and (min-width: 577px) {
  .hero {
    height: auto;
    min-height: 100vh;
    aspect-ratio: 4075 / 4013;
  }
  .hero-content {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100vh;
  }
}

/* ------------------------------------------------------------------- */
/* MANUAL MOTION TOGGLE — a visitor-controlled override on top of the   */
/* OS setting above; js/parallax.js adds/removes this class and drives  */
/* the "seen it once" default via localStorage. Same static frame.      */
/* ------------------------------------------------------------------- */

@media (min-width: 577px) {
  :root.motion-off .hero {
    height: auto;
    min-height: 100vh;
    /* aspect-ratio: 4075 / 4013; */
  }
  :root.motion-off .hero-content {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100vh;
  }
}

:root.motion-off .hero-art_mountains,
:root.motion-off .hero-art_gate {
  display: none;
}
:root.motion-off .hero-art_static {
  display: block;
}
:root.motion-off .hero-fog {
  /* !important: defeats a leftover inline opacity GSAP may have written
     if motion was switched off mid-ride, not before it ever started */
  opacity: 1 !important;
}
:root.motion-off #embers {
  display: none;
}
:root.motion-off .hero-title h1 {
  filter: drop-shadow(0 0.2rem 0.3rem rgba(0, 0, 0, 0.9));
}

.hero-motion-toggle {
  position: fixed;
  top: 1rem;
  left: 1rem;
  z-index: 6;
  font-family: 'Crimson Text', serif;
  font-size: 0.85rem;
  letter-spacing: 0.05rem;
  color: var(--text-soft);
  background: rgba(10, 0, 6, 0.55);
  border: 1px solid rgba(255, 180, 0, 0.35);
  border-radius: 999px;
  padding: 0.4rem 0.9rem;
  cursor: pointer;
  backdrop-filter: blur(2px);
  transition: border-color 0.2s ease-out, color 0.2s ease-out;
}

.hero-motion-toggle:hover,
.hero-motion-toggle:focus {
  border-color: var(--accent);
  color: var(--accent);
}

@media (max-width: 576px) {
  .hero-motion-toggle {
    /* the DEFENDER logo is ~92vw wide and centered — top:1rem sits
       right underneath/behind it on narrow screens; drop below it */
    top: 10rem;
    font-size: 0.5rem;
    padding: 0.35rem 0.7rem;
  }
}
