:root {
  --navy: #00003c;
  --navy-2: #0a0a52;
  --navy-3: #14146a;
  --ink: #ffffff;
  --muted: #a9acd6;
  --accent: #ffc83d;
  --accent-ink: #00003c;
  --line: rgba(255, 255, 255, 0.1);
  /* Card surface, near-opaque so it reads the same on either section color. */
  --card-bg: rgba(16, 16, 84, 0.92);
  /* Node network color: the violet of the magic glow in the key art. */
  --net-rgb: 165, 120, 255;
  --radius: 16px;
  --header-h: 72px;
  --gutter: clamp(16px, 4vw, 48px);
}

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

html { scroll-behavior: smooth; scroll-padding-top: var(--header-h); }

body {
  margin: 0;
  background: var(--navy);
  color: var(--ink);
  font-family: "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

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

.container {
  width: 100%;
  max-width: 1120px;
  margin: 0 auto;
}

.section {
  padding: clamp(64px, 10vw, 120px) var(--gutter);
}
.section.alt { background: var(--navy-2); }
/* The hero's fade already separates the video from the page, so the first
   section doesn't need the full top padding. */
.hero + .section { padding-top: clamp(32px, 5vw, 56px); }

.eyebrow {
  margin: 0 0 8px;
  color: var(--accent);
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.section-title {
  font-family: "Lilita One", "Inter", sans-serif;
  font-weight: 400;
  font-size: clamp(2.25rem, 5vw, 3.25rem);
  line-height: 1.1;
  letter-spacing: 0.02em;
  margin: 0 0 16px;
}

.lead {
  font-size: clamp(1.05rem, 1.6vw, 1.2rem);
  color: var(--muted);
  margin: 0 0 24px;
}

.lead a { color: var(--accent); }

.center { text-align: center; }
.center .lead { max-width: 680px; margin-left: auto; margin-right: auto; }

/* ---------- Buttons ---------- */
.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}
.center .btn-row { justify-content: center; }

.btn {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 12px 22px;
  border: 2px solid transparent;
  border-radius: 999px;
  font: inherit;
  font-weight: 600;
  font-size: 1rem;
  text-decoration: none;
  cursor: pointer;
  transition: transform 0.15s ease, background-color 0.2s ease, border-color 0.2s ease;
}
.btn:hover { transform: translateY(-2px); }
.btn:focus-visible { outline: 3px solid var(--accent); outline-offset: 3px; }
.btn svg { width: 18px; height: 18px; flex: none; fill: currentColor; }

.btn-primary { background: var(--accent); color: var(--accent-ink); }
.btn-primary:hover { background: #ffd666; }

.btn-ghost {
  background: rgba(255, 255, 255, 0.06);
  border-color: rgba(255, 255, 255, 0.35);
  color: var(--ink);
}
.btn-ghost:hover { border-color: var(--ink); background: rgba(255, 255, 255, 0.12); }

/* ---------- Header ---------- */
.site-header {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 20;
  height: var(--header-h);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 var(--gutter);
  background: linear-gradient(to bottom, rgba(0, 0, 30, 0.7), rgba(0, 0, 30, 0));
  transition: background-color 0.3s ease;
}
/* Frosted glass: little tint, heavy blur, and a hairline to catch the edge. */
.site-header.scrolled,
.site-header.solid {
  background-color: rgba(0, 0, 60, 0.55);
  backdrop-filter: blur(18px) saturate(140%);
  -webkit-backdrop-filter: blur(18px) saturate(140%);
  border-bottom: 1px solid rgba(255, 255, 255, 0.1);
  box-shadow: 0 8px 24px rgba(0, 0, 20, 0.25);
}
/* Without blur support the tint has to carry the contrast on its own. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .site-header.scrolled,
  .site-header.solid { background-color: rgba(0, 0, 60, 0.92); }
}
.brand img { height: 40px; width: auto; }

.site-nav ul {
  display: flex;
  gap: clamp(16px, 2.5vw, 32px);
  margin: 0;
  padding: 0;
  list-style: none;
}
.site-nav a {
  font-weight: 600;
  font-size: 0.95rem;
  text-decoration: none;
  white-space: nowrap;
  opacity: 0.85;
}
.site-nav a:hover,
.site-nav a[aria-current="page"] { opacity: 1; color: var(--accent); }

.nav-toggle {
  display: none;
  width: 44px;
  height: 44px;
  padding: 10px;
  border: 0;
  background: none;
  color: var(--ink);
  cursor: pointer;
}
.nav-toggle svg { width: 24px; height: 24px; fill: currentColor; }

@media (max-width: 760px) {
  :root { --header-h: 60px; }
  .brand img { height: 32px; }
  .nav-toggle { display: block; }
  .site-nav {
    position: absolute;
    top: var(--header-h);
    left: 0;
    right: 0;
    display: none;
    background: rgba(0, 0, 60, 0.98);
    border-top: 1px solid var(--line);
  }
  .site-nav.open { display: block; }
  .site-nav ul { flex-direction: column; gap: 0; padding: 8px var(--gutter) 16px; }
  .site-nav a { display: block; padding: 12px 0; font-size: 1.05rem; }
  .site-header:has(.site-nav.open) { background-color: rgba(0, 0, 60, 0.98); }
}

/* ---------- Hero ---------- */
.hero {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  max-height: 100vh;
  min-height: 300px;
  overflow: hidden;
  background: #000 url("../video/loop-poster.jpg") center / cover no-repeat;
}
.hero video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  pointer-events: none;
}
.hero::after {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  height: 45%;
  /* Smoothstep, not a straight ramp. A linear gradient turns a corner where
     it starts, and the eye reads that corner as a line across the hero. */
  background: linear-gradient(
    to bottom,
    rgba(0, 0, 60, 0) 0%,
    rgba(0, 0, 60, 0.043) 12.5%,
    rgba(0, 0, 60, 0.156) 25%,
    rgba(0, 0, 60, 0.316) 37.5%,
    rgba(0, 0, 60, 0.5) 50%,
    rgba(0, 0, 60, 0.684) 62.5%,
    rgba(0, 0, 60, 0.844) 75%,
    rgba(0, 0, 60, 0.957) 87.5%,
    var(--navy) 100%
  );
  pointer-events: none;
}

/* ---------- Hero copy ---------- */
/* The scrim is this element's own background, nothing more exotic than that.
   It was a ::before with a negative z-index and its own compositing layer,
   and in that shape the browser kept not painting it: invisible until the
   header's backdrop-filter forced a composite, missing from screen capture,
   missing on phones. A plain background on a plain element always paints. */
.hero-copy {
  position: absolute;
  z-index: 1;
  inset: auto 0 0 0;
  /* The top padding is the room the fade needs above the title. */
  padding: 200px var(--gutter) 0;
  pointer-events: none;
  background: linear-gradient(
    to bottom,
    rgba(0, 0, 60, 0) 0,
    rgba(0, 0, 60, 0.028) 25px,
    rgba(0, 0, 60, 0.103) 50px,
    rgba(0, 0, 60, 0.209) 75px,
    rgba(0, 0, 60, 0.33) 100px,
    rgba(0, 0, 60, 0.451) 125px,
    rgba(0, 0, 60, 0.557) 150px,
    rgba(0, 0, 60, 0.632) 175px,
    rgba(0, 0, 60, 0.66) 200px,
    rgba(0, 0, 60, 0.66) 100%
  );
}
/* Aligns the title with the section content further down the page, and lifts
   it clear of the scroll cue, which keeps the bottom centre. */
.hero-copy-inner {
  width: 100%;
  max-width: 1120px;
  margin: 0 auto;
  padding-bottom: 128px;
}
.hero-copy h1 {
  font-family: "Lilita One", "Inter", sans-serif;
  font-weight: 400;
  font-size: clamp(2.1rem, 7vw, 4.75rem);
  line-height: 1.05;
  letter-spacing: 0.02em;
  margin: 0 0 clamp(4px, 1vw, 12px);
  text-shadow: 0 2px 24px rgba(0, 0, 40, 0.55);
}
.hero-copy p {
  margin: 0;
  max-width: 46ch;
  /* Keeps "time." off a line of its own when the tagline does wrap. */
  text-wrap: balance;
  font-size: clamp(0.95rem, 2.1vw, 1.4rem);
  font-weight: 500;
  color: #e7e8fb;
  text-shadow: 0 1px 12px rgba(0, 0, 40, 0.75);
}
@media (max-width: 640px) {
  /* The hero falls back to its 300px min-height here, so the copy sits closer
     to the bottom; it still has to clear the scroll cue's 48px plus its gap. */
  .hero-copy { padding-top: 160px; }
  .hero-copy-inner { padding-bottom: 88px; }
}
/* Under about 420px tall the hero is all copy and no video, so the tagline
   steps aside and the title carries it alone. */
@media (max-height: 420px) and (orientation: landscape) {
  .hero-copy p { display: none; }
}

/* Down arrow over the video, hinting that the page continues below. */
.scroll-cue {
  position: absolute;
  z-index: 1;
  left: 50%;
  bottom: clamp(12px, 3vw, 32px);
  display: grid;
  place-items: center;
  width: 48px;
  height: 48px;
  margin-left: -24px;
  color: var(--ink);
  opacity: 0.9;
  animation: scroll-cue-bob 2s ease-in-out infinite;
}
.scroll-cue svg { width: 32px; height: 32px; fill: none; stroke: currentColor; stroke-width: 2.5; stroke-linecap: round; stroke-linejoin: round; filter: drop-shadow(0 2px 6px rgba(0, 0, 0, 0.5)); }
.scroll-cue:hover { color: var(--accent); opacity: 1; }
.scroll-cue:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; border-radius: 50%; }
@keyframes scroll-cue-bob {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(8px); }
}

/* ---------- Game ---------- */
.game-intro {
  display: grid;
  grid-template-columns: 1.25fr 1fr;
  gap: clamp(32px, 5vw, 64px);
  align-items: center;
}
.key-art {
  /* Centered against the whole column so neither side finishes early. */
  margin-bottom: 0;
  border-radius: var(--radius);
  box-shadow: 0 30px 60px rgba(0, 0, 0, 0.45);
  width: 100%;
  height: auto;
}
.tagline {
  font-family: "Lilita One", sans-serif;
  font-size: 1.35rem;
  letter-spacing: 0.03em;
  margin: 0 0 12px;
}
.platforms {
  margin: 20px 0 0;
  color: var(--muted);
  font-size: 0.9rem;
}
/* Rides along at the end of the platforms line rather than sitting alone. */
.press-link {
  display: inline-block;
  margin-left: 4px;
  white-space: nowrap;
  color: var(--ink);
  font-weight: 600;
  font-size: 0.9rem;
  text-decoration: none;
  opacity: 0.85;
}
.press-link:hover { color: var(--accent); opacity: 1; }

/* Publisher credit and store rating share one row under the description,
   split by a hairline. The column is a container so they can stack, rule and
   all, whenever it is too narrow for one row. */
.game-intro > div { container-type: inline-size; }
.credits {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 14px;
  margin: -4px 0 24px;
}
.credits .publisher,
.credits .rating { margin: 0; }
.credits .rating {
  padding-left: 14px;
  border-left: 1px solid rgba(255, 255, 255, 0.18);
}
@container (max-width: 460px) {
  .credits {
    flex-direction: column;
    align-items: flex-start;
    gap: 14px;
  }
  .credits .rating { padding-left: 0; border-left: 0; }
}
.publisher {
  margin: -12px 0 20px;
  font-size: 0.9rem;
}
/* The whole credit is the link, so it lights up as one piece like the rating. */
.publisher a {
  display: flex;
  align-items: center;
  gap: 10px;
  color: var(--muted);
  text-decoration: none;
  transition: color 0.2s ease;
}
.publisher img {
  height: 56px;
  width: auto;
  opacity: 0.88;
  transition: opacity 0.2s ease;
}
.publisher a:hover { color: var(--ink); }
.publisher a:hover img { opacity: 1; }
.publisher a:focus-visible { outline: 3px solid var(--accent); outline-offset: 4px; border-radius: 8px; }

/* Star ratings: chunky outlined stars like the game's own icons. A dim row
   with a gold row clipped to the score on top; --star sets the size. */
.stars {
  --star: 1.35rem;
  position: relative;
  display: inline-block;
  width: calc(var(--star) * 5);
  height: var(--star);
  vertical-align: middle;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 2.6l2.9 5.85 6.45.94-4.67 4.55 1.1 6.43L12 17.33l-5.78 3.04 1.1-6.43L2.65 9.39l6.45-.94z' fill='rgba(255,255,255,0.16)' stroke='%23000028' stroke-width='1.6' stroke-linejoin='round' stroke-linecap='round'/%3E%3C/svg%3E") repeat-x left center / var(--star) var(--star);
}
.stars-fill {
  position: absolute;
  inset: 0 auto 0 0;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 2.6l2.9 5.85 6.45.94-4.67 4.55 1.1 6.43L12 17.33l-5.78 3.04 1.1-6.43L2.65 9.39l6.45-.94z' fill='%23ffc83d' stroke='%23000028' stroke-width='1.6' stroke-linejoin='round' stroke-linecap='round'/%3E%3C/svg%3E") repeat-x left center / var(--star) var(--star);
}
.stars.small { --star: 1.1rem; }

/* Store rating badge: the score reads as a score, not as a line of text. */
.rating {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin: 0 0 24px;
  color: var(--muted);
  text-decoration: none;
  transition: color 0.2s ease;
}
.rating[hidden] { display: none; }
.rating strong {
  transition: color 0.2s ease;
  font-family: "Lilita One", sans-serif;
  font-weight: 400;
  font-size: 2rem;
  line-height: 1;
  color: var(--accent);
  /* Outlined like the stars and the game's own card numbers. */
  -webkit-text-stroke: 3px #000028;
  paint-order: stroke fill;
}
.rating-stack { display: grid; gap: 4px; }
.rating .stars { --star: 1.2rem; }
.rating-meta { font-size: 0.85rem; }
.rating-arrow {
  transition: opacity 0.2s ease;
  width: 12px;
  height: 12px;
  margin-left: 2px;
  vertical-align: -1px;
  fill: currentColor;
  opacity: 0.6;
}
.rating:hover strong { color: #ffd666; }
.rating:hover { color: var(--ink); }
.rating:hover .rating-arrow { opacity: 1; }
.rating:focus-visible { outline: 3px solid var(--accent); outline-offset: 4px; border-radius: 8px; }

/* ---------- Praise carousel ---------- */
#praise { padding-block: clamp(48px, 7vw, 84px); }
.carousel {
  position: relative;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 16px;
  margin-top: clamp(20px, 3vw, 32px);
}
.carousel-track {
  --per-view: 3;
  --gap: 20px;
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: calc((100% - (var(--per-view) - 1) * var(--gap)) / var(--per-view));
  gap: var(--gap);
  margin: 0;
  padding: 4px 0;
  list-style: none;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  scrollbar-width: none;
  overscroll-behavior-x: contain;
}
.carousel-track::-webkit-scrollbar { display: none; }
.carousel-track:focus-visible { outline: 3px solid var(--accent); outline-offset: 4px; border-radius: var(--radius); }

.quote-card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 12px;
  padding: 22px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--card-bg);
  scroll-snap-align: start;
}
.quote-card blockquote {
  flex: 1;
  margin: 0;
  font-size: 1.02rem;
  line-height: 1.45;
}
/* Press cards outrank player reviews, so they get the gold treatment. */
.quote-card.press {
  position: relative;
  border-color: rgba(255, 200, 61, 0.35);
  background:
    linear-gradient(155deg, rgba(255, 200, 61, 0.12), rgba(255, 200, 61, 0) 55%),
    var(--card-bg);
}
.quote-card.press::before {
  content: "\201C";
  position: absolute;
  top: 2px;
  right: 18px;
  font-family: "Lilita One", sans-serif;
  font-size: 3.5rem;
  line-height: 1;
  color: var(--accent);
  opacity: 0.35;
}
.quote-card.press blockquote { font-size: 1.08rem; }
.quote-card.player blockquote { color: #d7d9f0; }
.quote-card cite {
  font-style: normal;
  font-weight: 600;
  color: var(--accent);
  letter-spacing: 0.02em;
  /* Player names run long and have no spaces to break at. */
  max-width: 100%;
  overflow-wrap: anywhere;
}
.quote-card.player cite { color: var(--ink); font-weight: 500; }
.quote-card cite small {
  display: block;
  color: var(--muted);
  font-size: 0.8rem;
  font-weight: 400;
  letter-spacing: 0;
}
.quote-card cite a { text-decoration: none; }
.quote-card cite a:hover { text-decoration: underline; }
/* Outlets with a recognizable logo show it; the rest keep their name. */
.press-logo {
  display: block;
  width: auto;
  height: 26px;
  /* Wide wordmarks would otherwise dwarf the compact ones. */
  max-width: 150px;
  object-fit: contain;
  object-position: left center;
  opacity: 0.9;
}
.quote-card cite a:hover .press-logo { opacity: 1; }
/* A logo drawn for light backgrounds keeps its own white card. */
.press-logo.on-white {
  height: 34px;
  max-width: 170px;
  padding: 5px 9px;
  border-radius: 8px;
  background: #fff;
}
.quote-card cite:has(.press-logo) a:hover { text-decoration: none; }
.carousel-heading {
  margin: clamp(24px, 3.5vw, 36px) 0 0;
  text-align: center;
  font-size: 0.95rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
}
.carousel-heading + .carousel { margin-top: 14px; }

.carousel-arrow {
  display: grid;
  place-items: center;
  width: 48px;
  height: 48px;
  padding: 0;
  border: 1px solid rgba(255, 255, 255, 0.35);
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.06);
  color: var(--ink);
  cursor: pointer;
  transition: background-color 0.2s ease, color 0.2s ease, opacity 0.2s ease;
}
.carousel-arrow svg { width: 26px; height: 26px; fill: currentColor; }
.carousel-arrow:hover:not(:disabled) { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.carousel-arrow:focus-visible { outline: 3px solid var(--accent); outline-offset: 3px; }
.carousel-arrow:disabled { opacity: 0.3; cursor: default; }

@media (max-width: 960px) {
  .carousel-track { --per-view: 2; }
}
@media (max-width: 640px) {
  .carousel { gap: 8px; }
  .carousel-track { --per-view: 1; --gap: 12px; }
  .carousel-arrow { width: 40px; height: 40px; }
  .quote-card { padding: 22px; }
}

.gallery {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
  margin: clamp(48px, 7vw, 80px) 0 0;
  padding: 0;
  list-style: none;
}
.gallery button {
  position: relative;
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  border-radius: 12px;
  overflow: hidden;
  /* overflow alone lets the scaled blur layer escape the rounded corners;
     clip the shape explicitly so it cannot. */
  clip-path: inset(0 round 12px);
  background: var(--navy-3);
  cursor: zoom-in;
  transition: transform 0.3s ease;
}
.gallery button:hover,
.gallery button:focus-visible { transform: scale(0.972); }
.gallery img {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
}
/* Hover softens the shot's edges, as if it sat deeper than its frame: a
   blurred copy of the picture (added in site.js) fades in over the rim while
   the centre stays sharp. A copy beats backdrop-filter, which some browsers
   skip entirely when hardware acceleration is off. */
.gallery-soft {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  filter: blur(22px);
  /* Oversized, or the blur would fade to nothing at the tile's edge. */
  transform: scale(1.14);
  pointer-events: none;
  transition: opacity 0.3s ease;
  -webkit-mask-image: radial-gradient(115% 115% at 50% 50%, transparent 22%, #000 80%);
  mask-image: radial-gradient(115% 115% at 50% 50%, transparent 22%, #000 80%);
}
/* The opening's edge: one hairline and a soft shadow from the top, nothing
   more. The depth comes from the recede and the blur, not from painted
   highlights. */
.gallery button::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  opacity: 0;
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.07),
    inset 0 12px 28px rgba(0, 0, 15, 0.3),
    inset 0 -6px 18px rgba(0, 0, 15, 0.2);
  transition: opacity 0.3s ease;
}
.gallery button:hover .gallery-soft,
.gallery button:focus-visible .gallery-soft,
.gallery button:hover::after,
.gallery button:focus-visible::after { opacity: 1; }
.gallery button:focus-visible { outline: 3px solid var(--accent); outline-offset: 3px; }

@media (prefers-reduced-motion: reduce) {
  .gallery button,
  .gallery-soft,
  .gallery button::after { transition: none; }
  .gallery button:hover,
  .gallery button:focus-visible { transform: none; }
}

@media (max-width: 960px) {
  .game-intro { grid-template-columns: 1fr; }
  .key-art { margin-bottom: 0; }
}
@media (max-width: 560px) {
  .gallery { grid-template-columns: repeat(2, 1fr); gap: 10px; }
}

/* ---------- Team ---------- */
.team-grid {
  list-style: none;
  margin: clamp(40px, 6vw, 64px) auto 0;
  padding: 0;
  max-width: 960px;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 48px 32px;
}
.member a {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-decoration: none;
}
/* Team portraits: the cut-out person zooms and shifts against the photo
   behind them, all inside the circle. The zoom is what hides the original
   person in the background, so the photo only needs a light blur. */
.avatar {
  position: relative;
  width: 240px;
  height: 240px;
  /* How far the person may travel from centre. Keep it under the margin the
     6% zoom buys, or the original person shows at the edges. */
  --shift: 2px;
  /* Flat at rest; hovering tilts the disc toward the pointer, up to this
     angle. Steeper than about 12deg starts to squash the face. */
  --tilt: 10deg;
  /* Both layers sit at the same rest scale, so the cut-out person lines up
     exactly with the person in the photo until the hover pulls them apart. */
  --base: 1.03;
  perspective: 700px;
}
.avatar-3d {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  overflow: hidden;
  transform:
    rotateX(calc(-1 * var(--py, 0) * var(--tilt)))
    rotateY(calc(var(--px, 0) * var(--tilt)))
    scale(var(--scale, 1));
  /* An element's own ring survives its overflow clip; a child's would not. */
  box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.15);
  transition: transform 0.35s ease, box-shadow 0.3s ease;
}
.member a:hover .avatar-3d { transition: transform 0.1s linear, box-shadow 0.3s ease; }
.avatar-frame {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  overflow: hidden;
  background: var(--navy-3);
}
.avatar-frame img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transform: scale(var(--base));
  transition: filter 0.35s ease, transform 0.35s ease;
}
.avatar-pop {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Grow from near the bottom edge: the shoulders stay put and the head
     rises, instead of the cut-off body sliding down into view. */
  transform-origin: 50% 92%;
  transform: scale(var(--base));
  transition: transform 0.35s ease, filter 0.35s ease;
  pointer-events: none;
}
.member a:hover .avatar-pop { transition: transform 0.1s linear, filter 0.35s ease; }
.member { position: relative; }
.member a:hover,
.member a:focus-visible { z-index: 2; }
.member a:hover .avatar-3d,
.member a:focus-visible .avatar-3d {
  --scale: 1.03;
  box-shadow: 0 0 0 3px var(--accent), 0 18px 32px rgba(0, 0, 20, 0.45);
}
/* The circle grows 3%, the person another 6%, and the room pulls back 3%:
   small moves in different directions read as depth. */
.member a:hover .avatar-frame img,
.member a:focus-visible .avatar-frame img {
  filter: brightness(0.85);
  transform: scale(1);
}
.member a:hover .avatar-pop,
.member a:focus-visible .avatar-pop {
  transform:
    translate(calc(var(--px, 0) * var(--shift)), calc(var(--py, 0) * var(--shift) - 2px))
    scale(calc(var(--base) + 0.06));
  filter: drop-shadow(0 10px 14px rgba(0, 0, 20, 0.5));
}

.member h3 { margin: 20px 0 4px; font-size: 1.25rem; font-weight: 600; }
.member p { margin: 0; color: var(--muted); font-size: 0.95rem; }

@media (max-width: 600px) {
  .avatar { width: 200px; height: 200px; }
}
/* Touch screens never hover, so the portraits simply sit still. */
@media (hover: none) {
  .avatar-pop { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .avatar { --tilt: 0deg; }
  .avatar-3d { transform: none; }
  .member a:hover .avatar-pop,
  .member a:focus-visible .avatar-pop { transform: none; filter: none; }
  .member a:hover .avatar-frame img,
  .member a:focus-visible .avatar-frame img { filter: none; transform: none; }
}

/* ---------- Contact ---------- */
.email-link {
  display: inline-block;
  margin: 8px 0 32px;
  font-family: "Lilita One", sans-serif;
  font-size: clamp(1.6rem, 4.5vw, 2.6rem);
  letter-spacing: 0.02em;
  text-decoration: none;
  color: var(--accent);
  overflow-wrap: anywhere;
}
.email-link:hover { text-decoration: underline; text-underline-offset: 6px; }

.socials {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 12px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.socials a {
  display: grid;
  place-items: center;
  width: 52px;
  height: 52px;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: rgba(255, 255, 255, 0.05);
  transition: background-color 0.2s ease, color 0.2s ease, transform 0.15s ease;
}
.socials a:hover { background: var(--accent); color: var(--accent-ink); transform: translateY(-2px); }
.socials svg { width: 22px; height: 22px; fill: currentColor; }

/* ---------- Footer ---------- */
.site-footer {
  padding: 40px var(--gutter);
  border-top: 1px solid var(--line);
  color: var(--muted);
  font-size: 0.875rem;
}
.site-footer .container {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}
.site-footer img { height: 32px; width: auto; }
.site-footer nav { display: flex; gap: 20px; }
.site-footer a { text-decoration: none; }
.site-footer a:hover { color: var(--ink); }

/* ---------- Dialogs (trailer + screenshots) ---------- */
.media-dialog {
  width: min(1200px, 94vw);
  max-width: none;
  padding: 0;
  border: 0;
  border-radius: 12px;
  background: #000;
  overflow: visible;
}
.media-dialog::backdrop { background: rgba(0, 0, 20, 0.88); }
.media-dialog video,
.media-dialog img {
  width: 100%;
  height: auto;
  max-height: 86vh;
  object-fit: contain;
  border-radius: 12px;
}
.dialog-close {
  position: absolute;
  top: -48px;
  right: 0;
  width: 40px;
  height: 40px;
  border: 0;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.12);
  color: #fff;
  font-size: 1.5rem;
  line-height: 1;
  cursor: pointer;
}
.dialog-close:hover { background: rgba(255, 255, 255, 0.25); }

/* ---------- Press kit ---------- */
.page-hero {
  position: relative;
  padding: calc(var(--header-h) + clamp(56px, 9vw, 110px)) var(--gutter) clamp(56px, 9vw, 110px);
  overflow: hidden;
  isolation: isolate;
}
/* Art on its own layer so site.js can shift it down at 25% of scroll speed
   (parallax). It only needs to overhang the bottom, by that same 25%. */
.page-hero::before,
.page-hero::after {
  content: "";
  position: absolute;
  z-index: -1;
}
.page-hero::before {
  inset: 0 0 -25%;
  background: url("../game/key-art-clean.jpg") center 35% / cover no-repeat;
  transform: translate3d(0, var(--parallax, 0px), 0);
  will-change: transform;
}
.page-hero::after {
  inset: 0;
  background: linear-gradient(to right, rgba(0, 0, 60, 0.92) 30%, rgba(0, 0, 60, 0.35));
}
.page-hero h1 {
  font-family: "Lilita One", sans-serif;
  font-weight: 400;
  font-size: clamp(2.75rem, 7vw, 4.5rem);
  line-height: 1.05;
  margin: 0 0 12px;
}
.page-hero p { max-width: 560px; margin: 0; color: var(--muted); font-size: 1.1rem; }

.kit-layout {
  display: grid;
  grid-template-columns: 320px 1fr;
  gap: clamp(32px, 5vw, 64px);
  align-items: start;
}
.fact-sheet {
  position: sticky;
  top: calc(var(--header-h) + 24px);
  margin: 0;
  padding: 24px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--card-bg);
}
.fact-sheet h2 { margin: 0 0 16px; font-size: 1.1rem; }
.fact-sheet dl { margin: 0; }
.fact-sheet dt {
  margin-top: 14px;
  color: var(--muted);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
.fact-sheet dd { margin: 2px 0 0; font-size: 0.95rem; }
.fact-sheet a { color: var(--accent); overflow-wrap: anywhere; }

.kit-content > section + section { margin-top: clamp(48px, 7vw, 72px); }
.kit-content h2 {
  font-family: "Lilita One", sans-serif;
  font-weight: 400;
  font-size: clamp(1.75rem, 3.5vw, 2.25rem);
  letter-spacing: 0.02em;
  margin: 0 0 16px;
}
.kit-content p,
.kit-content li { color: #d7d9f0; }
.kit-content ul.bullets { padding-left: 20px; }
.kit-content ul.bullets li + li { margin-top: 6px; }

.kit-video { border-radius: 12px; width: 100%; background: #000; }

.downloads {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 16px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.downloads a {
  display: flex;
  flex-direction: column;
  height: 100%;
  text-decoration: none;
  border: 1px solid var(--line);
  border-radius: 12px;
  overflow: hidden;
  background: var(--card-bg);
  transition: border-color 0.2s ease;
}
.downloads a:hover { border-color: var(--accent); }
.downloads img { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; }
.downloads .logo-tile img { object-fit: contain; background: var(--navy); padding: 16px; }
.downloads span {
  display: flex;
  flex: 1;
  justify-content: space-between;
  gap: 8px;
  padding: 10px 14px;
  font-size: 0.875rem;
  font-weight: 500;
}
.downloads small { color: var(--muted); font-weight: 400; }

.kit-team {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 16px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.kit-team li { display: flex; align-items: center; gap: 14px; }
.kit-team img { width: 56px; height: 56px; border-radius: 50%; object-fit: cover; }
.kit-team strong { display: block; }
.kit-team span { color: var(--muted); font-size: 0.9rem; }

@media (max-width: 860px) {
  .kit-layout { grid-template-columns: 1fr; }
  .fact-sheet { position: static; }
}

/* ---------- 404 ---------- */
.not-found {
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: var(--header-h) var(--gutter);
  text-align: center;
}
.not-found h1 {
  font-family: "Lilita One", sans-serif;
  font-weight: 400;
  font-size: clamp(4rem, 14vw, 8rem);
  line-height: 1;
  margin: 0;
  color: var(--accent);
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { transition: none !important; }
  .scroll-cue { animation: none; }
}

.kit-quotes {
  margin: 0;
  padding: 0;
  list-style: none;
}
.kit-quotes li {
  padding: 4px 0 4px 20px;
  border-left: 3px solid var(--accent);
}
.kit-quotes li + li { margin-top: 20px; }
.kit-quotes blockquote { margin: 0 0 6px; font-size: 1.05rem; color: var(--ink); }
.kit-quotes cite { font-style: normal; color: var(--muted); font-size: 0.9rem; }
.kit-quotes cite a { color: var(--accent); }
.kit-content ul.bullets a { color: var(--accent); }
[data-rating][hidden] { display: none !important; }

/* ---------- Node network background ---------- */
/* The layer covers the studio, team and contact sections, above their
   backgrounds and below their content. Its canvas is one screen tall and
   sticky, so the browser scrolls it natively and the script only draws. */
.net-band { position: relative; }
.net-layer {
  position: absolute;
  inset: 0;
  z-index: 1;
  overflow: clip;
  pointer-events: none;
}
.net-layer canvas {
  position: sticky;
  top: 0;
  display: block;
  width: 100%;
  height: 100vh;
}
.section > .container { position: relative; z-index: 2; }

/* ---------- Meet your army ---------- */
/* Shares the game section's background, so skip the doubled section padding. */
.army { overflow: clip; padding-top: 0; scroll-margin-top: clamp(24px, 4vw, 48px); }
.army-filters {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
  margin-top: 8px;
}
.army-filter {
  padding: 8px 18px;
  border: 1px solid rgba(255, 255, 255, 0.3);
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.05);
  color: var(--ink);
  font: 600 0.95rem/1 "Inter", sans-serif;
  cursor: pointer;
  transition: background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease;
}
.army-filter:hover { border-color: var(--ink); }
.army-filter[aria-pressed="true"] { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.army-filter:focus-visible { outline: 3px solid var(--accent); outline-offset: 3px; }

.army-stage {
  --card-w: clamp(190px, 22vw, 260px);
  position: relative;
  height: calc(var(--card-w) * 1209 / 700 + 110px);
  margin-top: clamp(24px, 4vw, 40px);
}
.army-viewport {
  position: absolute;
  inset: 0;
  perspective: 1600px;
  perspective-origin: 50% 50%;
  touch-action: pan-y;
  cursor: grab;
  user-select: none;
  -webkit-user-select: none;
}
.army-stage.is-dragging .army-viewport { cursor: grabbing; }
.army-viewport:focus-visible { outline: 3px solid var(--accent); outline-offset: -3px; border-radius: var(--radius); }
.army-ring {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 0;
  height: 0;
  transform-style: preserve-3d;
}
.army-nav {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  margin-top: 4px;
}
.army-status {
  margin: 0;
  min-width: 12em;
  text-align: center;
  color: var(--ink);
  font-weight: 600;
}

.army-card {
  position: absolute;
  width: var(--card-w);
  left: calc(var(--card-w) / -2);
  top: calc(var(--card-w) * 1209 / 700 / -2);
  transform-style: preserve-3d;
  container-type: inline-size;
}
.army-card__tilt {
  position: relative;
  aspect-ratio: 700 / 1209;
  transform-style: preserve-3d;
}
.army-card__front {
  position: absolute;
  inset: 0;
  border-radius: 3.2cqw;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  overflow: hidden;
  font-family: "Nunito Sans", "Inter", sans-serif;
  font-weight: 900;
  color: #3c1f1e;
  user-select: none;
  box-shadow: 0 0 0 0.9cqw #3a1f24, 0 18px 40px rgba(0, 0, 0, 0.4);
}
.army-card__face {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}
.army-card__window {
  position: absolute;
  left: 10.96%;
  top: 12.99%;
  width: 78.16%;
  height: 51.32%;
  border-radius: 1.6cqw;
  background: linear-gradient(#7d6a8c, #4a3766 62%, #8f9a55 62%, #5d4f73);
}
/* Distant cards blend into the section background instead of just darkening. */
.army-card__shade {
  position: absolute;
  inset: 0;
  background: var(--navy);
  opacity: 0;
  pointer-events: none;
}
.army-card__title {
  position: absolute;
  left: 7.9%;
  top: calc(11.9% - 42.1cqw);
  width: 84.2%;
  aspect-ratio: 1;
  display: grid;
  place-items: center;
  background: url("../army/ui/ribbon.webp") center / contain no-repeat;
}
.is-hero .army-card__title { background-image: url("../army/ui/ribbon-hero.webp"); }
.army-card__title span {
  /* The banner band sits at 46% of the ribbon image height, not 50%. */
  margin-top: -6.3cqw; /* a touch above the band center */
  font-size: calc(9cqw * var(--title-fit, 1));
  line-height: 1;
  white-space: nowrap;
  color: #fff;
  -webkit-text-stroke: 1.8cqw #3b1e1d;
  paint-order: stroke fill;
}
.is-hero .army-card__title span { -webkit-text-stroke-color: #b8741f; }
.army-card__coin {
  position: absolute;
  left: 0.3%;
  top: 1.24%;
  width: 23%;
  aspect-ratio: 1;
  display: grid;
  place-items: center;
  background: url("../army/ui/coin.webp") center / contain no-repeat;
}
.army-card__coin span {
  font-size: 11cqw;
  line-height: 1;
  color: #48271f;
  -webkit-text-stroke: 1.2cqw #f3c96b;
  paint-order: stroke fill;
}
.army-card__stats {
  position: absolute;
  inset: 0;
  margin: 0;
  padding: 0;
  list-style: none;
}
.army-card__stats li {
  position: absolute;
  top: calc(71.9% - 10.35cqw);
  left: calc(50% - 10.35% + var(--slot) * 23.3%);
  width: 20.7%;
  aspect-ratio: 1;
  display: grid;
  place-items: center;
  background: url("../army/ui/stat-bg.webp") center / contain no-repeat;
}
.is-hero .army-card__stats li { background-image: url("../army/ui/stat-bg-hero.webp"); }
.army-card__stats li::before {
  content: "";
  position: absolute;
  inset: 7%;
  background: var(--icon) center / contain no-repeat;
}
.army-card__stats .attack { --icon: url("../army/ui/icon-attack.webp"); --under: #d8f2f5; }
.army-card__stats .health { --icon: url("../army/ui/icon-health.webp"); --under: #ef7c90; }
.army-card__stats .number { --icon: url("../army/ui/icon-number.webp"); --under: #efc4b3; }
.army-card__stats b {
  position: relative;
  font-size: 8.5cqw;
  line-height: 1;
  color: #3c1f1e;
  -webkit-text-stroke: 1.4cqw var(--under);
  paint-order: stroke fill;
}
.army-card__desc {
  position: absolute;
  left: 10.96%;
  top: 79.74%;
  width: 78.16%;
  height: 13.8%;
  margin: 0;
  padding: 0 5cqw;
  display: flex;
  align-items: center;
  font-size: 6.4cqw;
  line-height: 1.15;
  color: #3c1e1e;
  text-align: left;
}
@media (max-width: 640px) {
  /* Smaller cards so the neighbours on the ring still peek in from the sides. */
  .army-stage { --card-w: 46vw; }
}
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* ---------- Autoplay countdown ---------- */
/* A ring closing around the next arrow, so the ring turning on its own reads
   as something about to happen rather than something random. Driven entirely
   by army.js: the class is only on while the timer is actually running. */
@property --army-p {
  syntax: "<percentage>";
  inherits: false;
  initial-value: 0%;
}
.army-arrow.next { position: relative; }
.army-arrow.next::after {
  content: "";
  position: absolute;
  inset: -5px;
  border-radius: 50%;
  background: conic-gradient(var(--accent) var(--army-p), rgba(255, 255, 255, 0) 0);
  /* Hollow it out, so it is a ring around the button and not a filled disc. */
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 2.5px), #000 calc(100% - 2.5px));
  mask: radial-gradient(farthest-side, transparent calc(100% - 2.5px), #000 calc(100% - 2.5px));
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.25s ease;
}
.army-arrow.next.is-counting::after {
  opacity: 0.85;
  animation: army-countdown var(--army-countdown, 8000ms) linear forwards;
}
@keyframes army-countdown {
  from { --army-p: 0%; }
  to { --army-p: 100%; }
}
/* No countdown where there is no autoplay to count down to. */
@media (prefers-reduced-motion: reduce) {
  .army-arrow.next::after { display: none; }
}
