/* Eldritch Tricks — site stylesheet. Based on the Iron Tower Press static-site system, reskinned for the game. */

/* ==========================================================================
   1  Tokens
   ========================================================================== */

:root {
  --abyss:       #0A1214;  /* page ground (blue-black) */
  --deep:        #162326;  /* raised surfaces, alternate bands */
  --raised:      #1B2B2E;  /* hover surface */
  --ink:         #050809;  /* vignette / deepest shadow / text on brass */
  --bone:        #DCD6C4;  /* body text            13.03:1 on abyss, 11.10:1 on deep */
  --bone-bright: #EDE6D2;  /* headings, quote text 15.19:1 on abyss */
  --bone-dim:    #A9A493;  /* secondary text        7.59:1 on abyss,  6.46:1 on deep, 5.88:1 on raised */
  --brine:       #57B8AE;  /* links, focus ring, glows, the eye glow   8.00:1 on abyss, 6.81:1 on deep */
  --brass:       #C9A227;  /* primary CTA fill, emphasis               7.82:1 on abyss; ink on brass 8.31:1 */
  --brass-hover: #D9B23A;  /* primary CTA hover fill (ink on it ≥ 9:1) */
  --tideline:    #56818A;  /* UI borders, rules, control boundaries    4.42:1 on abyss, 3.76:1 on deep, 3.42:1 on raised (all ≥ 3:1 non-text) */
  --line:        rgba(86, 129, 138, 0.35); /* decorative hairlines only (never a control boundary) */
  --scrim:       rgba(10, 18, 20, 0.88);   /* header when scrolled, lightbox backdrop base */

  --font-display: 'IM Fell English', 'Iowan Old Style', 'Palatino Linotype', Georgia, serif;
  --font-body:    'Spectral', Georgia, 'Times New Roman', serif;

  /* fluid display sizes: min – preferred – max (px equivalents in comments) */
  --fs-display: clamp(2.5rem, 1.6rem + 3.2vw, 4rem);         /* 40–64px  hero quote (IM Fell, lh 1.1) */
  --fs-h2:      clamp(2rem, 1.35rem + 2.2vw, 2.875rem);       /* 32–46px  section titles (IM Fell, lh 1.15) */
  --fs-h3:      1.5rem;                                       /* 24px     beat titles, suit names (IM Fell, lh 1.2) */
  --fs-quote:   clamp(1.5rem, 1.2rem + 1.2vw, 2.125rem);      /* 24–34px  pull quotes (IM Fell italic, lh 1.3) */
  --fs-lede:    1.25rem;                                      /* 20px     hero lede, section intros (Spectral 400, lh 1.55) */
  --fs-body:    1.125rem;                                     /* 18px     paragraphs, FAQ answers (Spectral 400, lh 1.62) */
  --fs-ui:      1.0625rem;                                    /* 17px     nav links (500), buttons (600), roster names (600); also the short reading copy */
  --fs-small:   0.9375rem;                                    /* 15px     labels only, never running copy */

  --lh-tight: 1.1; --lh-heading: 1.15; --lh-body: 1.62;
  --measure: 66ch;                                            /* max line length for prose */

  --space-1: 0.25rem; --space-2: 0.5rem; --space-3: 0.75rem; --space-4: 1rem;
  --space-5: 1.5rem;  --space-6: 2rem;   --space-7: 3rem;    --space-8: 4rem;
  --space-9: 6rem;    --space-10: 9rem;
  --section-pad: clamp(6rem, 10vw, 10rem);   /* vertical padding per section, desktop 96–160px */
  --container: 1120px;
  --gutter: clamp(1.25rem, 4vw, 2.5rem);
  --header-h: 72px;

  --z-mist: 0;       /* #mist-canvas, fixed */
  --z-page: 1;       /* main, footer (position: relative) */
  --z-header: 100;   /* .site-header, fixed */
  --z-nav: 110;      /* .nav drawer on mobile */
  --z-vignette: 200; /* body::before, fixed, pointer-events none */
  --z-lightbox: 300; /* #lightbox */
  --z-grain: 400;    /* body::after, fixed, pointer-events none */
  --z-skip: 500;     /* .skip-link when focused */

  --r-1: 2px;   /* buttons, screenshot tiles, video frame, the rank plaque: near-square, letterpress */
  --r-2: 4px;   /* the still, the lightbox image, the threshold figure box */
  --shadow-lift: 0 18px 40px -20px rgba(5, 8, 9, 0.9);          /* lightbox dialog only */
  --ring-brass:  0 0 0 1px rgba(201, 162, 39, 0.45);             /* primary button rest */
  --ease-out:    cubic-bezier(0.2, 0.7, 0.2, 1);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
  --dur-fast: 160ms; --dur-base: 320ms; --dur-slow: 700ms;
}

/* ==========================================================================
   2  Reset
   ========================================================================== */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--header-h) + 1rem);
}

/* both declarations, in this order: clip is what actually stops iOS Safari and
   Android Chrome panning sideways to the eye and its glow; hidden stays only as
   the fallback for engines without clip. */
html, body { overflow-x: hidden; overflow-x: clip; }

body {
  margin: 0;
  background: var(--abyss);
  color: var(--bone);
  font: 400 var(--fs-body)/var(--lh-body) var(--font-body);
  -webkit-font-smoothing: antialiased;
}

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

.defs { position: absolute; width: 0; height: 0; overflow: hidden; }

/* ==========================================================================
   3  Base
   ========================================================================== */

h1, h2, h3 { font-family: var(--font-display); font-weight: 400; color: var(--bone-bright); margin: 0; }
h2 { font-size: var(--fs-h2); line-height: var(--lh-heading); }
h3 { font-size: var(--fs-h3); line-height: 1.2; }

p { margin: 0 0 var(--space-5); max-width: var(--measure); }
p:last-child { margin-bottom: 0; }

a {
  color: var(--brine);
  text-decoration: underline;
  text-underline-offset: 0.15em;
  text-decoration-thickness: 1px;
}
a:hover { color: var(--bone-bright); }

ul, ol { margin: 0; padding-left: var(--space-5); }

::selection { background: var(--brine); color: var(--ink); }

.visually-hidden {
  position: absolute; width: 1px; height: 1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
}

.skip-link {
  position: absolute; top: -100%; left: var(--space-4);
  z-index: var(--z-skip);
  padding: var(--space-3) var(--space-4);
  background: var(--brass); color: var(--ink);
  border-radius: var(--r-1); text-decoration: none;
}
.skip-link:focus { top: var(--space-4); }

main, .site-footer { position: relative; z-index: var(--z-page); }

/* ==========================================================================
   4  Overlays
   ========================================================================== */

#mist-canvas, .mist {
  position: fixed; inset: 0; width: 100%; height: 100%;
  z-index: var(--z-mist); pointer-events: none;
}

body::before { /* vignette */
  content: ""; position: fixed; inset: 0; z-index: var(--z-vignette); pointer-events: none;
  background: radial-gradient(ellipse 80% 70% at 50% 45%, transparent 55%, rgba(5, 8, 9, 0.55) 100%);
}

body::after { /* static grain, ~400 bytes, no animation, no blend mode */
  content: ""; position: fixed; inset: 0; z-index: var(--z-grain); pointer-events: none; opacity: 0.045;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='256' height='256'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 256px 256px;
}

/* ==========================================================================
   5  Layout
   ========================================================================== */

.container { width: min(var(--container), 100% - 2 * var(--gutter)); margin-inline: auto; }
.container--narrow { max-width: 880px; }

.section { padding-block: var(--section-pad); }

/* soft-edged bands so the mist shows through; never a hard-edged stripe */
.section--band {
  background: linear-gradient(180deg,
    rgba(22, 35, 38, 0) 0%,
    rgba(22, 35, 38, 0.62) 10%,
    rgba(22, 35, 38, 0.62) 90%,
    rgba(22, 35, 38, 0) 100%);
}

.section__title { max-width: 22ch; margin-bottom: var(--space-5); text-wrap: balance; }
.section__intro {
  font-size: var(--fs-lede); line-height: 1.55; color: var(--bone);
  max-width: var(--measure); margin-bottom: var(--space-7);
}

.prose > * + * { margin-top: var(--space-5); }
/* margin-bottom only: the `margin` shorthand here (0,1,1) would zero the top margin the
   sibling rule above is meant to supply, and the section's three paragraphs would run together. */
.prose p { margin-bottom: 0; }

/* ==========================================================================
   6  Header + nav (desktop)
   ========================================================================== */

.site-header {
  position: fixed; inset: 0 0 auto 0; height: var(--header-h); z-index: var(--z-header);
  background: transparent;
  transition: background-color var(--dur-base), border-color var(--dur-base);
  border-bottom: 1px solid transparent;
}
.site-header.is-scrolled {
  background: var(--scrim);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border-bottom-color: var(--line);
}

.site-header__inner {
  height: 100%; display: flex; align-items: center; justify-content: space-between; gap: var(--space-4);
}

.brand {
  display: inline-flex; align-items: center; gap: var(--space-3);
  color: var(--bone-bright); text-decoration: none;
  font: 500 var(--fs-ui)/1 var(--font-body);
}
.brand__mark { width: 40px; height: 40px; }
.brand__name { font-family: var(--font-display); font-size: 1.5rem; white-space: nowrap; }

.nav__list {
  display: flex; align-items: center; gap: var(--space-5);
  list-style: none; margin: 0; padding: 0;
}
.nav__link {
  color: var(--bone); text-decoration: none;
  font: 500 var(--fs-ui)/1 var(--font-body);
  padding: var(--space-2) 0;
  border-bottom: 1px solid transparent;
  white-space: nowrap;
}
.nav__link:hover { color: var(--bone-bright); border-bottom-color: var(--brine); }
.nav__cta { display: flex; }

.nav-toggle {
  display: none;
  width: 44px; height: 44px;
  flex-direction: column; align-items: center; justify-content: center; gap: 4px;
  padding: 0; border: 0; background: none; color: var(--bone); cursor: pointer;
}
.nav-toggle__bar {
  display: block; width: 24px; height: 2px; background: var(--bone);
  transition: transform var(--dur-fast) var(--ease-out), opacity var(--dur-fast) var(--ease-out);
}
.nav-toggle.is-open .nav-toggle__bar:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.nav-toggle.is-open .nav-toggle__bar:nth-child(2) { opacity: 0; }
.nav-toggle.is-open .nav-toggle__bar:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

/* ==========================================================================
   7  Buttons + warp
   ========================================================================== */

.btn {
  position: relative; isolation: isolate;
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 52px; padding: 0 var(--space-6);
  border: 0; background: transparent; border-radius: var(--r-1);
  font: 600 var(--fs-ui)/1 var(--font-body);
  text-decoration: none; cursor: pointer; white-space: nowrap;
}
.btn__warp {
  position: absolute; inset: 0; z-index: -1; border-radius: inherit;
  border: 1px solid var(--tideline); background: rgba(22, 35, 38, 0.7);
  transition: border-color var(--dur-fast), background-color var(--dur-fast);
}
.btn__label { position: relative; }

.btn--primary { color: var(--ink); }
/* the base a:hover rule (0,1,1) outranks .btn--primary (0,1,0); without this guard the label
   turns bone-bright on brass (~1.9:1) the moment the pointer or focus arrives. */
.btn--primary:hover,
.btn--primary:focus-visible { color: var(--ink); }
.btn--primary .btn__warp { background: var(--brass); border-color: var(--brass); box-shadow: var(--ring-brass); }
.btn--primary:hover .btn__warp,
.btn--primary:focus-visible .btn__warp { background: var(--brass-hover); border-color: var(--brass-hover); }
.btn--primary:active .btn__warp { background: var(--brass); }

.btn--secondary { color: var(--bone); }
.btn--secondary:hover, .btn--secondary:focus-visible { color: var(--bone-bright); }
/* the ripple is the hover signal; no glow on top of it */
.btn--secondary:hover .btn__warp,
.btn--secondary:focus-visible .btn__warp { border-color: var(--brine); }
.btn--secondary:active .btn__warp { background: var(--raised); }

.btn--small { min-height: 40px; padding: 0 var(--space-4); font-size: 1rem; }

/* The filter is applied ONLY while the JS controller flags the layer; at rest there is no filter cost. */
.btn__warp.is-warping { filter: url(#warp-ui); will-change: filter; }
.section__title.is-warping, .hero__quote.is-warping { filter: url(#warp-text); will-change: filter; }

/* ==========================================================================
   8  Hero + eye
   ========================================================================== */

.hero {
  min-height: calc(100vh - var(--header-h));
  padding-top: calc(var(--header-h) + var(--space-9));
  padding-bottom: var(--space-9);
  display: flex; align-items: center;
}
.hero__inner {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(280px, 0.8fr);
  gap: var(--space-8);
  align-items: end;
}
.hero__copy { min-width: 0; }
.hero__title { margin: 0; }
.hero__wordmark { width: min(440px, 100%); height: auto; margin-bottom: var(--space-7); }

.hero__quote { margin: 0 0 var(--space-6); }
.hero__quote-text {
  font: italic 400 var(--fs-display)/var(--lh-tight) var(--font-display);
  color: var(--bone-bright); max-width: 16ch; margin: 0 0 var(--space-3);
}
.hero__cite { font: 500 var(--fs-ui)/1.3 var(--font-body); color: var(--bone-dim); }

.hero__lede { font-size: var(--fs-lede); line-height: 1.55; max-width: 44ch; margin-bottom: var(--space-6); }
.hero__actions { display: flex; flex-wrap: wrap; gap: var(--space-4); margin-bottom: var(--space-5); }
/* 17px: this line carries every platform claim on the page and is read, not glanced at */
.hero__platform { font-size: var(--fs-ui); line-height: 1.5; color: var(--bone-dim); max-width: 48ch; margin: 0; }

/* the eye sits low-right and slightly below the copy's baseline */
.hero__eye { justify-self: end; align-self: end; width: clamp(220px, 28vw, 360px); transform: translateY(6%); }

/* --- load-moment states (CSS side) --- */

html.js:not(.is-ready) .hero__quote,
html.js:not(.is-ready) .hero__lede,
html.js:not(.is-ready) .hero__actions,
html.js:not(.is-ready) .hero__platform {
  opacity: 0; transform: translateY(8px);
  animation: hero-fallback 0.01s linear 2.5s forwards;   /* CSS-only backstop: if main.js dies before initLoadMoment() runs, the copy appears anyway at 2.5 s */
}
@keyframes hero-fallback { to { opacity: 1; transform: none; } }

.hero__quote, .hero__lede, .hero__actions, .hero__platform {
  transition: opacity var(--dur-slow) var(--ease-out), transform var(--dur-slow) var(--ease-out);
}
html.is-ready .hero__lede     { transition-delay: 120ms; }
html.is-ready .hero__actions  { transition-delay: 240ms; }
html.is-ready .hero__platform { transition-delay: 360ms; }

html.js .eye { --lid: 0; }   /* held shut until JS opens it; JS then drives --lid inline */

/* --- the eye component --- */

.eye {
  position: relative; width: 100%; aspect-ratio: 720 / 656;
  --lid: 1; --px: 0px; --py: 0px; --ox: 0px; --oy: 0px;
}
.eye__glow {
  position: absolute; inset: -22%; pointer-events: none;
  background: radial-gradient(closest-side at 54% 58%,
    rgba(87, 184, 174, 0.40), rgba(87, 184, 174, 0.14) 45%, transparent 72%);
  opacity: calc(0.15 + 0.85 * var(--lid));
}
.eye__lens {
  position: absolute; inset: 0;
  transform: translate(var(--ox), var(--oy));
  clip-path: ellipse(36.9% calc(34% * var(--lid)) at 54.4% calc(58.1% + 6% * (1 - var(--lid))));
}
.eye__orb, .eye__pupil, .eye__socket { position: absolute; inset: 0; width: 100%; height: 100%; }
.eye__pupil { transform: translate(var(--px), var(--py)); }
.eye__socket { pointer-events: none; }

/* ==========================================================================
   9  The game
   ========================================================================== */

.game {
  display: grid; grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
  gap: var(--space-8); align-items: start;
}
.game__text { min-width: 0; }

.game__still { margin: 0; align-self: center; }
.game__still img { width: 100%; border-radius: var(--r-2); border: 1px solid var(--line); }
.game__still figcaption { margin-top: var(--space-3); font-size: var(--fs-small); color: var(--bone-dim); }

.pull-quote {
  display: grid; grid-template-columns: 80px 1fr; gap: var(--space-4) var(--space-5);
  align-items: start; margin: var(--space-7) 0 0; padding: var(--space-5) 0 0;
  border-top: 1px solid var(--line);
}
/* Dagon is a transparent cutout of his bust: no box, no border, no background */
.pull-quote__portrait { display: block; width: 80px; height: 80px; grid-row: 1 / span 2; }
.pull-quote__text {
  font: italic 400 var(--fs-quote)/1.3 var(--font-display);
  color: var(--bone-bright); margin: 0;
}
.pull-quote__cite { font-size: var(--fs-small); color: var(--bone-dim); }

/* ==========================================================================
   10  How it plays
   ========================================================================== */

.howplay {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--space-8); align-items: start;
}

.beats { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-6); }
.beat { display: grid; grid-template-columns: 2.5rem 1fr; gap: var(--space-4); }
.beat__num { font: italic 400 var(--fs-h3)/1 var(--font-display); color: var(--brine); padding-top: 0.15em; }
.beat__title { grid-column: 2; }
.beat__text { grid-column: 2; margin: var(--space-2) 0 0; }

.threshold-fig {
  margin: 0; padding: var(--space-6);
  border: 1px solid var(--line); border-radius: var(--r-2);
  background: rgba(10, 18, 20, 0.5);
  display: grid; gap: var(--space-5); justify-items: center;
}
.threshold-fig__dagon, .threshold-fig__trick {
  display: flex; flex-wrap: wrap; justify-content: center; align-items: flex-end; gap: var(--space-3);
}

/* no border, no overflow clip, no background: the WebP is a card with its own frame
   and rounded corners on transparent; the 5px radius exists only so the winner
   outline follows those corners. */
.tcard { position: relative; width: 96px; aspect-ratio: 5 / 7; border-radius: 5px; }
.tcard img { display: block; width: 100%; height: 100%; }
/* a corner index plaque, as on a real card: bone-bright on ink is 16.1:1, where the
   same numeral set straight on the art measured 1.8:1 on Tomes */
.tcard__rank {
  position: absolute; top: 4px; left: 4px;
  min-width: 1.6em; padding: 0.15em 0.35em;
  background: var(--ink); color: var(--bone-bright); border-radius: var(--r-1);
  font: 600 1.25rem/1 var(--font-body); text-align: center;
}
.tcard--winner { outline: 2px solid var(--brass); outline-offset: 2px; }
/* suit hooks on the diagram cards: the art carries the suit, so they add no paint */
.tcard--tides, .tcard--steel { background: none; }
.threshold-fig__dagon .tcard { width: 120px; border-radius: 6px; }
.tcard__label {
  flex-basis: 100%; text-align: center;
  font-size: var(--fs-small); color: var(--bone-dim); margin: var(--space-2) 0 0;
}
/* this caption teaches the core rule; it is body copy, so 17px and left-aligned */
.threshold-fig__caption {
  justify-self: start; font-size: var(--fs-ui); line-height: 1.5;
  color: var(--bone); max-width: 44ch; text-align: left; margin: 0;
}

/* ==========================================================================
   11  Suits
   ========================================================================== */

.suits {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: var(--space-6) var(--space-7);
}
/* column-gap only: a row gap here would be added to .suit__name's own 8px bottom margin,
   and the brass name would read as a detached heading instead of the head of its caption. */
.suit { display: grid; grid-template-columns: 112px 1fr; grid-template-rows: min-content 1fr;
        column-gap: var(--space-4); row-gap: 0; align-items: start; }
/* no border, no radius, no background: the WebP is the card itself, matte knocked out */
.suit__art { display: block; width: 112px; height: auto; grid-row: 1 / span 2; }
.suit__name { grid-column: 2; font-size: var(--fs-h3); color: var(--brass); margin: 0 0 var(--space-2); }
.suit__line { grid-column: 2; font-size: var(--fs-ui); line-height: 1.5; color: var(--bone); margin: 0; }

/* ==========================================================================
   12  Investigators
   ========================================================================== */

.roster-wrap { position: relative; }

/* A centred carousel: --n investigators in full, with the previous and the next one
   peeking in at either edge (--peek px of each), faded. The <ul> is the track. Card
   width is derived from the viewport width in CSS, so the script only ever moves the
   track by whole cards (--shift, in px) and re-orders <li>s for a seamless wrap.
   Without JS the viewport scrolls sideways and the arrows stay hidden. */
.roster-viewport {
  --n: 3; --peek: 112px; --gap: var(--space-5); --ground: 300px;
  position: relative; overflow-x: auto; overflow-y: hidden;
  padding-bottom: var(--space-4);
  scrollbar-width: thin; scrollbar-color: var(--tideline) transparent;
}
html.js .roster-viewport { overflow: hidden; touch-action: pan-y; }
html:not(.js) .roster__btn { display: none; }

.roster {
  --card: calc((100% - 2 * (var(--peek) + var(--gap)) - (var(--n) - 1) * var(--gap)) / var(--n));
  list-style: none; margin: 0; padding: 0;
  display: flex; gap: var(--gap); align-items: flex-start;
  transform: translateX(calc(var(--peek) - var(--card) + var(--shift, 0px)));
  transition: transform 560ms cubic-bezier(0.22, 0.61, 0.36, 1);
}
html:not(.js) .roster { transform: none; }
.roster.is-static { transition: none; }

.roster__card { flex: 0 0 var(--card); transition: opacity 560ms ease; }
.roster__card.is-edge { opacity: 0.3; }
/* each figure stands on its own 1px ledge; the WebP is a transparent cutout with a
   straight bottom edge that meets it. No border, radius, background or glow. */
.roster__figure { display: block; width: 100%; aspect-ratio: 5 / 7; margin: 0; border-bottom: 1px solid var(--tideline); }
.roster__portrait { display: block; width: 100%; height: 100%; object-fit: contain; object-position: bottom; }
.roster__name { font: 600 var(--fs-ui)/1.3 var(--font-body); color: var(--bone-bright); margin: var(--space-4) 0 0; }
.roster__title { font: italic 400 var(--fs-small)/1.3 var(--font-body); color: var(--bone-dim); margin: 0 0 var(--space-2); }
.roster__bio { font-size: var(--fs-ui); line-height: 1.5; margin: 0; }

/* arrows sit over the faded edge cards, centred on the figures */
.roster__btn {
  position: absolute; z-index: 2; top: calc(var(--ground) / 2 - 22px);
  width: 44px; height: 44px; display: grid; place-items: center;
  border: 1px solid var(--tideline); border-radius: var(--r-1);
  background: rgba(22, 35, 38, 0.85); color: var(--bone); cursor: pointer;
}
.roster__btn--prev { left: max(4px, calc(var(--peek) / 2 - 22px)); }
.roster__btn--next { right: max(4px, calc(var(--peek) / 2 - 22px)); }
.roster__btn:hover { border-color: var(--brine); color: var(--bone-bright); }

@media (max-width: 1024px) {
  .roster-viewport { --peek: 64px; --gap: var(--space-4); }
}

/* ==========================================================================
   13  Trailer
   ========================================================================== */

.trailer {
  position: relative; aspect-ratio: 16 / 9;
  border-radius: var(--r-1); overflow: hidden;
  border: 1px solid var(--tideline); background: var(--ink);
}
.trailer__video { width: 100%; height: 100%; object-fit: cover; }
.trailer__play {
  position: absolute; inset: 0; margin: auto;
  width: 96px; height: 96px; border-radius: 50%;
  border: 1px solid var(--bone); background: rgba(10, 18, 20, 0.72);
  color: var(--bone-bright); display: grid; place-items: center; cursor: pointer;
  transition: background-color var(--dur-fast), border-color var(--dur-fast);
}
.trailer__play:hover, .trailer__play:focus-visible {
  background: rgba(10, 18, 20, 0.9); border-color: var(--brine); color: var(--brine);
}
.trailer__play.is-hidden { display: none; }
.trailer__note { font-size: var(--fs-small); color: var(--bone-dim); margin: var(--space-3) 0 0; }

/* ==========================================================================
   14  Screenshots
   ========================================================================== */

.shots {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-4);
}
.shot {
  display: block; width: 100%; padding: 0;
  /* --tideline, not --line: this is the boundary of a control, and §7.3 reserves --line
     (1.56:1) for decorative hairlines. tideline is 4.42:1 on abyss, 4.03:1 on the band. */
  border: 1px solid var(--tideline); border-radius: var(--r-1);
  overflow: hidden; background: var(--ink); cursor: zoom-in;
}
.shot__img { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; transition: opacity var(--dur-fast); }
.shot:hover .shot__img, .shot:focus-visible .shot__img { opacity: 0.85; }
.shot:hover { border-color: var(--brine); }

/* ==========================================================================
   15  Lightbox
   ========================================================================== */

.lightbox { position: fixed; inset: 0; z-index: var(--z-lightbox); display: grid; place-items: center; }
.lightbox[hidden] { display: none; }
.lightbox__backdrop { position: absolute; inset: 0; background: rgba(5, 8, 9, 0.9); }
.lightbox__dialog {
  position: relative; width: min(1200px, 94vw); max-height: 92vh;
  display: grid; grid-template-columns: 56px 1fr 56px; align-items: center; gap: var(--space-3);
}
.lightbox__figure { margin: 0; text-align: center; }
.lightbox__img {
  width: 100%; max-height: 78vh; object-fit: contain;
  border-radius: var(--r-2); box-shadow: var(--shadow-lift);
}
.lightbox__caption { margin-top: var(--space-3); font-size: var(--fs-small); color: var(--bone); }
.lightbox__count {
  position: absolute; top: -2.5rem; left: 56px;
  font-size: var(--fs-small); color: var(--bone-dim); margin: 0;
}

/* prev / next / close share the .roster__btn visual recipe */
.lightbox__close, .lightbox__prev, .lightbox__next {
  width: 44px; height: 44px; display: grid; place-items: center;
  border: 1px solid var(--tideline); border-radius: var(--r-1);
  background: rgba(22, 35, 38, 0.7); color: var(--bone);
  font: 400 1.5rem/1 var(--font-body); cursor: pointer;
}
.lightbox__close:hover, .lightbox__prev:hover, .lightbox__next:hover {
  border-color: var(--brine); color: var(--bone-bright);
}
.lightbox__close { position: absolute; top: -3rem; right: 0; }
.lightbox__prev { justify-self: start; }
.lightbox__next { justify-self: end; }

body.lightbox-open { overflow: hidden; }

/* ==========================================================================
   16  FAQ
   ========================================================================== */

.faq { border-top: 1px solid var(--line); }
.faq__item { border-bottom: 1px solid var(--line); }
.faq__q { margin: 0; font-family: var(--font-body); }
.faq__btn {
  width: 100%; display: flex; justify-content: space-between; align-items: center; gap: var(--space-4);
  padding: var(--space-5) 0; background: none; border: 0; color: var(--bone-bright);
  font: 500 1.25rem/1.35 var(--font-body); text-align: left; cursor: pointer;
}
.faq__btn:hover { color: var(--brine); }
.faq__icon { flex: 0 0 auto; width: 14px; height: 14px; position: relative; }
.faq__icon::before, .faq__icon::after { content: ""; position: absolute; background: currentColor; inset: 6px 0; }   /* horizontal bar */
.faq__icon::after { inset: 0 6px; transition: transform var(--dur-fast); }                                          /* vertical bar */
.faq__item.is-open .faq__icon::after { transform: scaleY(0); }
.faq__panel {
  display: grid; grid-template-rows: 0fr;
  transition: grid-template-rows var(--dur-base) var(--ease-out);
}
.faq__item.is-open .faq__panel { grid-template-rows: 1fr; }
.faq__inner { min-height: 0; overflow: hidden; visibility: hidden; transition: visibility 0s linear var(--dur-base); }
.faq__item.is-open .faq__inner, html:not(.js) .faq__inner { visibility: visible; transition-delay: 0s; }
.faq__inner p { padding-bottom: var(--space-5); max-width: var(--measure); }
html:not(.js) .faq__panel { grid-template-rows: 1fr; }   /* no JS: every answer visible */

/* ==========================================================================
   17  Closing + footer
   ========================================================================== */

.closing { padding-block: var(--section-pad); text-align: left; border-top: 1px solid var(--line); }
.closing__quote { margin: 0 0 var(--space-7); }
.closing__quote-text {
  font: italic 400 var(--fs-quote)/1.3 var(--font-display);
  color: var(--bone-bright); max-width: 26ch; margin: 0 0 var(--space-3);
}
.closing__cite { font-size: var(--fs-small); color: var(--bone-dim); }
.closing__title { color: var(--brass); margin-bottom: var(--space-4); }
.closing__text { font-size: var(--fs-lede); margin-bottom: var(--space-6); }
.closing__actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-5); }
.closing__discord { display: inline-flex; align-items: center; min-height: 44px; font: 500 var(--fs-ui)/1 var(--font-body); }

.site-footer {
  border-top: 1px solid var(--line);
  padding-block: var(--space-8) var(--space-6);
  font-size: var(--fs-small); color: var(--bone-dim);
  background: rgba(5, 8, 9, 0.5);
}
.site-footer__inner { display: grid; grid-template-columns: 2fr 1fr 1fr; gap: var(--space-7); }
.site-footer__brand { min-width: 0; }
.site-footer__name {
  font-family: var(--font-display); font-size: 1.5rem; color: var(--bone-bright);
  margin: var(--space-3) 0 var(--space-2);
}
.site-footer__blurb { margin: 0; max-width: 34ch; }
.site-footer__col { min-width: 0; }
.site-footer__heading { color: var(--bone); font-weight: 600; margin: 0 0 var(--space-3); }
.site-footer__links { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-2); }
.site-footer__links a { color: var(--bone-dim); text-decoration: none; }
.site-footer__links a:hover { color: var(--brine); text-decoration: underline; }
.site-footer__bottom { margin-top: var(--space-7); padding-top: var(--space-5); border-top: 1px solid var(--line); }

/* ==========================================================================
   18  Focus
   ========================================================================== */

/* no border-radius here: at equal specificity it would override .trailer__play's 50%
   the moment the round button takes focus; outlines follow each element's own radius */
*:focus-visible { outline: 2px solid var(--brine); outline-offset: 3px; }
*:focus:not(:focus-visible) { outline: none; }

a:focus-visible,
.btn:focus-visible,
.nav__link:focus-visible,
.nav-toggle:focus-visible,
.faq__btn:focus-visible,
.trailer__play:focus-visible,
.roster-viewport:focus-visible,
.roster__btn:focus-visible,
.shot:focus-visible,
.skip-link:focus-visible,
.lightbox__close:focus-visible,
.lightbox__prev:focus-visible,
.lightbox__next:focus-visible {
  outline: 2px solid var(--brine); outline-offset: 3px;
}

/* ==========================================================================
   19  Reduced motion
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  html { scroll-behavior: auto; }
  html.js .eye { --lid: 1; }                     /* eye open, static */
  .btn__warp.is-warping, .section__title.is-warping, .hero__quote.is-warping { filter: none; }
  html.js:not(.is-ready) .hero__quote, html.js:not(.is-ready) .hero__lede,
  html.js:not(.is-ready) .hero__actions, html.js:not(.is-ready) .hero__platform { opacity: 1; transform: none; }
}

/* ==========================================================================
   20  Touch
   ========================================================================== */

@media (hover: none) {
  .btn__warp.is-warping { filter: url(#warp-ui); }   /* taps still ripple; nothing else changes */
}

/* ==========================================================================
   21  Responsive
   ========================================================================== */

@media (max-width: 1024px) {
  /* The drawer takes over here, not at 768: five nav links plus the brand and the Wishlist
     button need ~1040px of container, so below that the desktop row wraps and spills out of
     the 72px header band. --header-h is still 72px here and the drawer reads it. */
  .nav-toggle { display: flex; }
  /* an explicit height, never bottom: 0: once the header carries .is-scrolled its
     backdrop-filter makes it the containing block for this fixed drawer, and
     bottom: 0 would resolve to the header's own bottom edge. */
  .nav {
    position: fixed; top: var(--header-h); left: 0; right: 0;
    height: calc(100vh - var(--header-h));
    height: calc(100dvh - var(--header-h));
    overflow-y: auto; z-index: var(--z-nav);
    /* --abyss is --scrim's own colour at full alpha. The plan's scrim + blur(16px) is inert here:
       an element with backdrop-filter is the BACKDROP ROOT for its descendants, so once
       .site-header carries .is-scrolled the drawer has nothing behind it to sample and the hero
       copy reads straight through the 0.88 scrim. An opaque ground renders identically whether or
       not the page has been scrolled (what §5.20 asserts) and drops a full-viewport blur pass. */
    background: var(--abyss);
    padding: var(--space-6) var(--gutter);
    transform: translateX(100%); visibility: hidden;
    transition: transform var(--dur-base) var(--ease-out), visibility 0s linear var(--dur-base);
  }
  .nav.is-open { transform: none; visibility: visible; transition: transform var(--dur-base) var(--ease-out); }
  .nav__list { flex-direction: column; align-items: flex-start; gap: var(--space-5); }
  .nav__link { font-size: 1.375rem; }
  .nav__cta { margin-top: var(--space-4); }
  body.nav-open { overflow: hidden; }
  /* the drawer's Wishlist button is a finger target, unlike the desktop header's */
  .nav__cta .btn--small { min-height: 44px; }

  .hero__inner { gap: var(--space-6); }
  .game, .howplay { gap: var(--space-6); }
  .shots { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .site-footer__inner { grid-template-columns: 1.5fr 1fr 1fr; }
}

@media (max-width: 768px) {
  :root { --section-pad: 4rem; --header-h: 64px; }

  /* hero: the eye follows the copy and bleeds off the right edge, like something looking in */
  .hero { min-height: 0; padding-top: calc(var(--header-h) + var(--space-8)); }
  .hero__inner { grid-template-columns: 1fr; }
  .hero__eye {
    justify-self: end; width: clamp(200px, 56vw, 300px);
    margin-right: -12%; margin-top: var(--space-4); transform: none;
  }
  .hero__quote-text { max-width: none; }

  .game, .howplay { grid-template-columns: 1fr; }
  .threshold-fig { width: 100%; }

  .roster-viewport { --n: 1; --peek: 56px; --gap: var(--space-4); }

  .shots { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .site-footer__inner { grid-template-columns: 1fr; }

  /* lightbox: columns collapse, prev/next sit over the image edges */
  .lightbox__dialog { grid-template-columns: 1fr; }
  .lightbox__prev, .lightbox__next {
    position: absolute; top: 50%; transform: translateY(-50%);
    width: 40px; height: 40px;
  }
  .lightbox__prev { left: var(--space-2); }
  .lightbox__next { right: var(--space-2); }
  .lightbox__count { left: 0; }
}

@media (max-width: 480px) {
  .btn { width: 100%; }
  /* 32px of padding leaves 239px inside a 305px container at 360 wide, one pixel short of the
     three 72px cards plus their two 12px gaps, and the winning card drops to a second row. */
  .threshold-fig { padding: var(--space-5); }
  .hero__actions { flex-direction: column; }
  .hero__eye { width: 62vw; }
  .shots { grid-template-columns: 1fr; }
  .pull-quote { grid-template-columns: 56px 1fr; }
  .pull-quote__portrait { width: 56px; height: 56px; }
  .tcard { width: 72px; border-radius: 4px; }
  .threshold-fig__dagon .tcard { width: 88px; border-radius: 4px; }
}
