/* big-shoulders-display-vietnamese-wght-normal */
@font-face {
  font-family: 'Big Shoulders Display Variable';
  font-style: normal;
  font-display: swap;
  font-weight: 100 900;
  src: url(/_astro/big-shoulders-display-vietnamese-wght-normal.B-JM5mJH.woff2) format('woff2-variations');
  unicode-range: U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB;
}

/* big-shoulders-display-latin-ext-wght-normal */
@font-face {
  font-family: 'Big Shoulders Display Variable';
  font-style: normal;
  font-display: swap;
  font-weight: 100 900;
  src: url(/_astro/big-shoulders-display-latin-ext-wght-normal.EP2r9iG4.woff2) format('woff2-variations');
  unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}

/* big-shoulders-display-latin-wght-normal */
@font-face {
  font-family: 'Big Shoulders Display Variable';
  font-style: normal;
  font-display: swap;
  font-weight: 100 900;
  src: url(/_astro/big-shoulders-display-latin-wght-normal.Bn_gnr7w.woff2) format('woff2-variations');
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}/* public-sans-vietnamese-wght-normal */
@font-face {
  font-family: 'Public Sans Variable';
  font-style: normal;
  font-display: swap;
  font-weight: 100 900;
  src: url(/_astro/public-sans-vietnamese-wght-normal.CtlIRbEm.woff2) format('woff2-variations');
  unicode-range: U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB;
}

/* public-sans-latin-ext-wght-normal */
@font-face {
  font-family: 'Public Sans Variable';
  font-style: normal;
  font-display: swap;
  font-weight: 100 900;
  src: url(/_astro/public-sans-latin-ext-wght-normal.MQgHevqp.woff2) format('woff2-variations');
  unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}

/* public-sans-latin-wght-normal */
@font-face {
  font-family: 'Public Sans Variable';
  font-style: normal;
  font-display: swap;
  font-weight: 100 900;
  src: url(/_astro/public-sans-latin-wght-normal.DdeTHZLK.woff2) format('woff2-variations');
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}*,
*::before,
*::after {
  box-sizing: border-box;
}

* {
  margin: 0;
}

html {
  -webkit-text-size-adjust: 100%;
  /* Lenis drives smooth scrolling on content pages; native smooth scrolling
     would fight it. Anchor jumps are handled in scroll.ts. */
  scroll-behavior: auto;
}

html {
  scrollbar-color: var(--surface-3) var(--night);
  caret-color: var(--vice-pink);
}

::selection {
  background: var(--surface-3);
  color: var(--text);
}

body {
  min-height: 100svh;
  background-color: var(--bg);
  color: var(--fg);
  font-family: var(--font-ui);
  font-size: var(--step-0);
  line-height: var(--leading-body);
  font-synthesis-weight: none;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
}

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

img,
video {
  height: auto;
}

input,
button,
textarea,
select {
  font: inherit;
  color: inherit;
}

button {
  background: none;
  border: none;
  cursor: pointer;
}

p,
h1,
h2,
h3,
h4,
li,
figcaption {
  overflow-wrap: break-word;
  text-wrap: pretty;
}

h1,
h2,
h3,
h4 {
  text-wrap: balance;
}

ul[role='list'],
ol[role='list'] {
  list-style: none;
  padding: 0;
}

a {
  color: var(--link);
  text-underline-offset: 0.18em;
  text-decoration-thickness: 1px;
}

a:hover {
  text-decoration-thickness: 2px;
}

/* One focus ring for the whole site. Visible on the dark background at AA. */
:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 3px;
}

:focus:not(:focus-visible) {
  outline: none;
}

table {
  border-collapse: collapse;
}

hr {
  border: none;
  border-top: 1px solid var(--hairline);
}

[hidden] {
  display: none !important;
}

.visually-hidden:not(:focus):not(:active) {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Off-screen until it takes focus, then it parks over the header. */
.skip-link {
  position: absolute;
  top: 0;
  left: var(--space-2xs);
  z-index: var(--z-toast);
  padding: var(--space-2xs) var(--space-s);
  background: var(--surface-2);
  color: var(--text);
  text-decoration: none;
  translate: 0 -120%;
  transition: translate var(--dur-fast) var(--ease-deco);
}

.skip-link:focus-visible {
  translate: 0 0;
}
/**
 * Design tokens — "Leonida at dusk".
 *
 * The concept is deliberately NOT a full-bleed sunset gradient (that is what
 * map.stateofleonida.net does). Here the night indigo dominates and the warm
 * sunset is compressed into a 1-3px horizon line, so warm colour is scarce
 * enough to mean something when it appears.
 */

:root {
  color-scheme: dark;

  /* ── Surfaces ───────────────────────────────────────────────────────── */
  --night: #0d0b1e;
  --surface: #16132b;
  --surface-2: #1f1b3a;
  --surface-3: #2a2550;
  --hairline: #2e2a4d;
  --scrim: rgb(13 11 30 / 0.72);

  /* ── Accents ────────────────────────────────────────────────────────── */
  --vice-pink: #ff4fa3; /* 6.4:1 on --night */
  --sunset: #ff8c42; /* 8.2:1 */
  --sand: #ffd27a; /* 12.6:1 */
  --lagoon: #29d3c9; /* 9.7:1 */
  --twilight: #9b6bff; /* 4.3:1 — DECORATIVE ONLY, never text or icons */

  /* ── Text ───────────────────────────────────────────────────────────── */
  --text: #f5f0ff; /* 16.8:1 */
  --text-muted: #a7a2c3; /* 7.1:1 */
  --text-dim: #6f6a8c; /* 3.8:1 — large text, disabled states, hairline labels */

  /* ── Semantic ───────────────────────────────────────────────────────── */
  --bg: var(--night);
  --fg: var(--text);
  --accent: var(--vice-pink);
  --link: var(--lagoon);
  --focus: var(--lagoon);
  --progress: var(--sunset);
  --missable: var(--sand);

  /* Content confidence labels. Colour is never the only signal — every badge
     also carries an icon and a word. */
  --status-confirmed: var(--lagoon);
  --status-reported: var(--sand);
  --status-rumor: var(--text-muted);

  /* Category group colours. Same rule: always paired with icon + label. */
  --group-collectibles: var(--vice-pink);
  --group-activities: var(--lagoon);
  --group-services: var(--twilight);
  --group-missions: var(--sunset);
  --group-events: var(--sand);
  --group-landmarks: #7fd4a0;
  --group-other: var(--text-muted);

  /* ── The horizon ────────────────────────────────────────────────────── */
  /* Used in exactly three places: the progress meter, the rule under the hero
     wordmark, and the top edge of an open marker panel. Nowhere else. */
  --horizon: linear-gradient(90deg, var(--twilight), var(--vice-pink), var(--sunset));
  --horizon-soft: linear-gradient(
    180deg,
    rgb(155 107 255 / 0.14) 0%,
    rgb(255 79 163 / 0.06) 40%,
    transparent 100%
  );

  /* ── Type ───────────────────────────────────────────────────────────── */
  --font-display: 'Big Shoulders Display Variable', 'Big Shoulders Display', 'Arial Narrow', system-ui, sans-serif;
  --font-ui: 'Public Sans Variable', 'Public Sans', system-ui, sans-serif;

  /* Fluid scale, 1.25 ratio at 360px widening to 1.333 at 1440px. */
  --step--1: clamp(0.833rem, 0.81rem + 0.1vw, 0.889rem);
  --step-0: clamp(1rem, 0.97rem + 0.15vw, 1.125rem);
  --step-1: clamp(1.25rem, 1.19rem + 0.28vw, 1.5rem);
  --step-2: clamp(1.563rem, 1.45rem + 0.5vw, 2rem);
  --step-3: clamp(1.953rem, 1.76rem + 0.86vw, 2.667rem);
  --step-4: clamp(2.441rem, 2.13rem + 1.39vw, 3.556rem);
  --step-5: clamp(3.052rem, 2.56rem + 2.19vw, 4.741rem);
  --step-6: clamp(3.815rem, 3.05rem + 3.4vw, 6.321rem);

  --leading-tight: 1.05;
  --leading-snug: 1.25;
  --leading-body: 1.65;
  --measure: 68ch;

  /* ── Space ──────────────────────────────────────────────────────────── */
  --space-3xs: 0.25rem;
  --space-2xs: 0.5rem;
  --space-xs: 0.75rem;
  --space-s: 1rem;
  --space-m: 1.5rem;
  --space-l: 2.25rem;
  --space-xl: 3.5rem;
  --space-2xl: 5.5rem;
  --space-3xl: 8rem;

  --width-content: 75rem;
  --width-prose: 42rem;
  --gutter: clamp(1rem, 4vw, 2.5rem);

  /* ── Shape ──────────────────────────────────────────────────────────── */
  /* Soft, continuous corners (owner decision 2026-09-19: the Art Deco
     chamfer read as a sci-fi HUD; the site now speaks Apple-like glass). */
  --radius-xs: 8px;
  --radius-s: 12px;
  --radius-m: 18px;
  --radius-l: 26px;
  --radius-xl: 34px;
  --radius-pill: 999px;
  --radius-sm: var(--radius-xs);

  /* ── Glass ──────────────────────────────────────────────────────────── */
  /* Liquid-glass panels: translucent night, the scene behind blurred and
     saturated, a bright hairline catching light on the top edge. */
  --glass-fill: color-mix(in srgb, var(--surface) 52%, transparent);
  --glass-fill-strong: color-mix(in srgb, var(--surface) 78%, transparent);
  --glass-sheen: linear-gradient(
    180deg,
    color-mix(in srgb, var(--text) 10%, transparent),
    color-mix(in srgb, var(--text) 2%, transparent) 40%,
    transparent
  );
  --glass-edge: color-mix(in srgb, var(--text) 14%, transparent);
  --glass-highlight: color-mix(in srgb, var(--text) 26%, transparent);
  --glass-blur: blur(22px) saturate(170%);

  /* ── Elevation ──────────────────────────────────────────────────────── */
  /* Panels are separated by hairlines and background steps, not by identical
     drop shadows on identical cards. Only floating layers get a shadow. */
  --shadow-float: 0 1.5rem 3rem rgb(5 4 14 / 0.55);
  --shadow-panel: 0 0.5rem 1.5rem rgb(5 4 14 / 0.4);

  /* ── Motion ─────────────────────────────────────────────────────────── */
  --ease-deco: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
  --dur-fast: 140ms;
  --dur-base: 260ms;
  --dur-slow: 520ms;
  --dur-scene: 900ms;

  /* ── Layers ─────────────────────────────────────────────────────────── */
  --z-map: 1;
  --z-map-ui: 10;
  --z-sheet: 20;
  --z-header: 30;
  --z-panel: 40;
  --z-modal: 50;
  --z-toast: 60;
}
/**
 * Two families, both self-hosted.
 *
 * Big Shoulders Display is a condensed Art Deco grotesque (drawn from 1920s
 * Chicago signage) — the same family of letterform as the Deco lettering of
 * GTA VI's marketing, without borrowing Rockstar's proprietary face. It is set
 * heavy and uppercase for headings, only at >=28px, never for running text. Public Sans carries the interface: commissioned for dense
 * legibility, with real tabular figures for counters and coordinates. It is
 * used instead of Inter on purpose; Inter is the default of every site and
 * says nothing.
 */

.display {
  font-family: var(--font-display);
  font-weight: 800;
  line-height: var(--leading-tight);
  letter-spacing: 0.01em;
  text-transform: uppercase;
}

h1,
.h1 {
  font-family: var(--font-display);
  font-weight: 800;
  text-transform: uppercase;
  font-size: var(--step-4);
  line-height: var(--leading-tight);
  letter-spacing: 0.005em;
}

h2,
.h2 {
  font-family: var(--font-display);
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.005em;
  font-size: var(--step-3);
  line-height: var(--leading-tight);
}

h3,
.h3 {
  font-family: var(--font-display);
  font-weight: 750;
  font-size: var(--step-2);
  line-height: var(--leading-snug);
}

/* Below ~28px a condensed display face loses legibility, so h4 and smaller switch to the UI
   family. This is a rule, not a preference. */
h4,
.h4 {
  font-family: var(--font-ui);
  font-weight: 650;
  font-size: var(--step-1);
  line-height: var(--leading-snug);
}

.lede {
  font-size: var(--step-1);
  line-height: 1.45;
  color: var(--text-muted);
  max-width: var(--measure);
}

.prose {
  max-width: var(--width-prose);
}

.prose > * + * {
  margin-block-start: var(--space-s);
}

.prose > * + :is(h2, h3) {
  margin-block-start: var(--space-l);
}

.prose :is(h2, h3) + * {
  margin-block-start: var(--space-xs);
}

.prose li + li {
  margin-block-start: var(--space-3xs);
}

/* Counters, coordinates, countdown digits: fixed-width figures so numbers
   never jitter as they tick. */
.tabular {
  font-variant-numeric: tabular-nums;
  font-feature-settings: 'tnum' 1;
}
/**
 * Surfaces: liquid glass and soft corners.
 *
 * `.glass` is the one panel treatment on the site — translucent, the scene
 * behind it blurred and saturated, a bright hairline catching light along the
 * top edge, a soft float shadow. Use it on anything that sits over imagery or
 * the map. `.glass--solid` for panels that sit on flat night, where there is
 * nothing to blur and legibility matters more than translucency.
 */

.glass {
  position: relative;
  border-radius: var(--radius-l);
  background: var(--glass-sheen), var(--glass-fill);
  border: 1px solid var(--glass-edge);
  box-shadow:
    inset 0 1px 0 var(--glass-highlight),
    0 1.25rem 3rem rgb(5 4 14 / 0.4);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
}

.glass--solid {
  background: var(--glass-sheen), var(--glass-fill-strong);
}

.glass--flat {
  box-shadow: inset 0 1px 0 var(--glass-highlight);
}

/* Browsers without backdrop-filter get a denser fill instead of see-through. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .glass {
    background: var(--glass-sheen), var(--glass-fill-strong);
  }
}

/* ── The horizon rule ─────────────────────────────────────────────────── */
/* One of the three places the sunset gradient is allowed to appear. */
.rule-horizon {
  height: 2px;
  border: none;
  border-radius: var(--radius-pill);
  background: var(--horizon);
}

/* Section separator for the rest of the site: a hairline, not a card shadow. */
.rule-hair {
  height: 1px;
  border: none;
  background: var(--hairline);
}

/* ── Buttons ──────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2xs);
  min-height: 2.75rem;
  padding: 0.7em 1.35em;
  border: 1px solid transparent;
  border-radius: var(--radius-pill);
  font-family: var(--font-ui);
  font-size: var(--step-0);
  font-weight: 600;
  line-height: 1.2;
  white-space: nowrap;
  color: var(--text);
  text-decoration: none;
  transition:
    background-color var(--dur-fast) var(--ease-deco),
    border-color var(--dur-fast) var(--ease-deco),
    scale var(--dur-fast) var(--ease-deco);
}

.btn:active {
  scale: 0.97;
}

.btn--primary {
  background: var(--vice-pink);
  color: var(--night);
  box-shadow: 0 0.6rem 1.6rem color-mix(in srgb, var(--vice-pink) 35%, transparent);
}

@media (hover: hover) and (pointer: fine) {
  .btn--primary:hover {
    background: color-mix(in oklab, var(--vice-pink) 82%, var(--text));
  }
}

/* Ghost: a small pane of glass. */
.btn--ghost {
  background: var(--glass-sheen), var(--glass-fill);
  border-color: var(--glass-edge);
  box-shadow: inset 0 1px 0 var(--glass-highlight);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
}

@media (hover: hover) and (pointer: fine) {
  .btn--ghost:hover {
    border-color: color-mix(in srgb, var(--text) 30%, transparent);
  }
}

.btn--lg {
  padding: 0.9em 1.9em;
  font-size: var(--step-1);
}

/* ── Status badge ─────────────────────────────────────────────────────── */
/* Confirmed / Reported / Rumor. Colour is never the only signal: the badge
   always carries a dot and the word. */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 0.45em;
  padding: 0.25em 0.75em;
  border-radius: var(--radius-pill);
  font-size: var(--step--1);
  font-weight: 650;
  letter-spacing: 0.02em;
  color: var(--badge-color, var(--text-muted));
  background: color-mix(in oklab, var(--badge-color, var(--text-muted)) 14%, transparent);
  border: 1px solid color-mix(in oklab, var(--badge-color, var(--text-muted)) 35%, transparent);
}

.badge::before {
  content: '';
  width: 0.45em;
  height: 0.45em;
  border-radius: 50%;
  background: currentColor;
}

.badge[data-status='confirmed'] {
  --badge-color: var(--status-confirmed);
}
.badge[data-status='reported'] {
  --badge-color: var(--status-reported);
}
.badge[data-status='rumor'] {
  --badge-color: var(--status-rumor);
}

/* ── Film grain ───────────────────────────────────────────────────────── */
/* Binds official screenshots and our own plates into one surface. Generated
   noise, not an image: a few hundred bytes, deterministic, no AI involved. */
.grain::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  opacity: 0.08;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.9 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ── Layout helpers ───────────────────────────────────────────────────── */
.wrap {
  width: min(100% - var(--gutter) * 2, var(--width-content));
  margin-inline: auto;
}

.stack > * + * {
  margin-block-start: var(--flow, var(--space-s));
}

/* Top padding only: stacking two sections with symmetric padding doubles the
   gap into a hole. */
.section {
  padding-block-start: var(--space-2xl);
}
/**
 * Scroll choreography.
 *
 * Rockstar's own page drives 25 canvases from scroll-scrubbed video. That costs
 * hundreds of megabytes per page; we have to keep Lighthouse mobile >= 90, so
 * the same *feel* is rebuilt from native CSS scroll-driven animations (0 KB of
 * JS, composited on the GPU) plus Lenis for inertial scrolling on content
 * pages only.
 *
 * Rules, enforced in review:
 *   - Never animate the map UI.
 *   - Never animate an article body below its hero.
 *   - Never animate anything within 200px of an <AdSlot> (CLS).
 */

@keyframes reveal-up {
  from {
    opacity: 0;
    translate: 0 2rem;
  }
  to {
    opacity: 1;
    translate: 0 0;
  }
}

@keyframes reveal-fade {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@keyframes reveal-scale {
  from {
    opacity: 0;
    scale: 1.06;
  }
  to {
    opacity: 1;
    scale: 1;
  }
}

/* Headings rise out of their own lower edge, like type lifted from a mask. */
@keyframes reveal-wipe {
  from {
    clip-path: inset(0 0 100% 0);
    translate: 0 0.5em;
  }
  to {
    clip-path: inset(0 0 -0.2em 0);
    translate: 0 0;
  }
}

/* The hero drifts back as it is scrolled away. */
@keyframes hero-exit {
  to {
    opacity: 0.35;
    scale: 1.06;
  }
}

/* Slow drift for a background image inside a sticky scene. */
@keyframes parallax-y {
  from {
    translate: 0 calc(var(--parallax, 8) * -1%);
  }
  to {
    translate: 0 calc(var(--parallax, 8) * 1%);
  }
}

/* The hero's own entrance — the single orchestrated animation on the site.
   Everything else is a response to the user scrolling or clicking. */
@keyframes horizon-draw {
  from {
    scale: 0 1;
  }
  to {
    scale: 1 1;
  }
}

/* ── Native path: scroll-driven animations ────────────────────────────── */
@supports (animation-timeline: view()) {
  [data-reveal] {
    animation: reveal-up linear both;
    animation-timeline: view();
    /* `--i` staggers siblings by shifting the range instead of using a delay,
       which has no meaning on a scroll timeline. */
    animation-range: entry calc(4% + var(--i, 0) * 5%) entry calc(65% + var(--i, 0) * 5%);
  }

  [data-reveal='fade'] {
    animation-name: reveal-fade;
  }

  [data-reveal='scale'] {
    animation-name: reveal-scale;
  }

  [data-reveal='wipe'] {
    animation-name: reveal-wipe;
  }

  [data-parallax] {
    animation: parallax-y linear both;
    animation-timeline: view();
    animation-range: cover 0% cover 100%;
    will-change: translate;
  }
}

/* ── Fallback: IntersectionObserver (Firefox today) ───────────────────── */
/* scroll.ts adds `.sda` to <html> when the native path is available. */
html:not(.sda) [data-reveal] {
  opacity: 0;
  translate: 0 2rem;
  transition:
    opacity var(--dur-slow) var(--ease-deco),
    translate var(--dur-slow) var(--ease-deco);
  transition-delay: calc(var(--i, 0) * 70ms);
}

html:not(.sda) [data-reveal].is-revealed {
  opacity: 1;
  translate: 0 0;
}

html:not(.sda) [data-reveal='fade'],
html:not(.sda) [data-reveal='scale'],
html:not(.sda) [data-reveal='wipe'] {
  translate: none;
}

/* ── Hero entrance ────────────────────────────────────────────────────── */
/* 600ms with a 60ms stagger: the home is a page people come back to, and the
   call to action is never part of the entrance — it is there from the start. */
.hero-enter {
  animation: reveal-up 600ms var(--ease-deco) both;
  animation-delay: calc(var(--i, 0) * 60ms);
}

.hero-rule {
  transform-origin: left center;
  animation: horizon-draw var(--dur-scene) var(--ease-deco) both;
  animation-delay: 240ms;
}

/* ── Reduced motion wins over everything above ────────────────────────── */
/* Gentler, not zero: movement goes, short opacity fades stay, so state
   changes still read as changes. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    transition-duration: 1ms !important;
    scroll-behavior: auto !important;
  }

  .hero-enter {
    animation: reveal-fade 200ms ease-out both !important;
  }

  .hero-rule {
    animation: none !important;
  }

  [data-reveal] {
    translate: none !important;
    scale: none !important;
    clip-path: none !important;
  }

  @supports (animation-timeline: view()) {
    [data-reveal] {
      animation-name: reveal-fade !important;
    }
  }

  html:not(.sda) [data-reveal] {
    transition: opacity 200ms ease-out !important;
  }

  [data-parallax] {
    animation: none !important;
    translate: none !important;
  }
}
/**
 * Parallax primitives.
 *
 * The reference is the kind of site collected on awwwards' parallax lists —
 * Totem's floating elements, Shape Studio's opening frames, Drink Cann's
 * scroll-linked colour, Peter Lindbergh's pinned galleries. What those have in
 * common is not "things move": it is *depth*, built from a few layers travelling
 * at different rates against one fixed element.
 *
 * All of it is native CSS scroll-driven animation, so it costs no JavaScript
 * and runs on the compositor. That matters here: every one of these effects
 * sits on a page we want Google to index and a phone to render at 60fps.
 *
 * The primitives are deliberately generic. The character pages use them one
 * way; regions and later sections should combine them differently rather than
 * copying a layout — the vocabulary is shared, the sentence is not.
 *
 * Vocabulary
 *   .px              a scene: establishes the timeline other pieces read from
 *   .px__bed         a full-bleed image bed that drifts and settles
 *   .px__layer       anything that should travel at its own rate (--depth)
 *   .px__veil        the scrim that keeps type legible over imagery
 *   [data-open]      a frame that opens as it enters (clip-path)
 *   .px-shift        an image larger than its frame, panning inside it
 *
 * `--depth` is a signed distance in rem: negative moves against the scroll
 * (further away), positive moves with it (nearer). Roughly -12..12 is the
 * useful range; past that layers start to slide rather than sit.
 */

/* ── Scene ───────────────────────────────────────────────────────────── */

.px {
  position: relative;
  isolation: isolate;
  /* Named so children can opt into the scene's progress rather than their own
     entry, which is what makes layers travel together. */
  view-timeline-name: --px-scene;
}

.px__bed {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
}

/* `<picture>` is inline by default, which silently drops every transform put
   on it — the bed looked static for exactly that reason. */
.px__bed > :is(img, picture) {
  display: block;
  width: 100%;
  height: 100%;
}

.px__bed :is(img) {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: var(--bed-focus, 50% 50%);
}

.px__veil {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
}

.px__content {
  position: relative;
  z-index: 2;
}

/* ── Motion ──────────────────────────────────────────────────────────── */

/* `--depth` is in rem, not per cent: a percentage resolves against the
   element's own size, so the same depth moved a tall column of portraits
   200px and a three-line heading six. Absolute units make depth mean the
   same thing wherever it is used. */
@keyframes px-drift {
  from {
    translate: 0 calc(var(--depth, -6) * -1rem);
  }
  to {
    translate: 0 calc(var(--depth, -6) * 1rem);
  }
}

/* The bed starts slightly oversized and settles: the frame feels like it is
   coming to rest rather than sliding past. */
@keyframes px-settle {
  from {
    scale: 1.16;
    translate: 0 -4%;
  }
  to {
    scale: 1;
    translate: 0 4%;
  }
}

/* A frame that opens from its own centre line. */
@keyframes px-open {
  from {
    clip-path: inset(14% 8% 14% 8% round var(--radius-l));
    opacity: 0.4;
  }
  to {
    clip-path: inset(0% 0% 0% 0% round var(--radius-l));
    opacity: 1;
  }
}

/* An oversized image panning inside a fixed frame. */
@keyframes px-shift {
  from {
    object-position: 50% calc(50% - var(--shift, 12%));
  }
  to {
    object-position: 50% calc(50% + var(--shift, 12%));
  }
}

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .px__bed > :is(img, picture) {
      animation: px-settle linear both;
      animation-timeline: --px-scene;
      animation-range: cover 0% cover 100%;
      will-change: transform;
    }

    .px__layer {
      animation: px-drift linear both;
      animation-timeline: --px-scene;
      animation-range: cover 0% cover 100%;
      will-change: transform;
    }

    [data-open] {
      animation: px-open linear both;
      animation-timeline: view();
      animation-range: entry 10% cover 40%;
    }

    .px-shift img {
      animation: px-shift linear both;
      animation-timeline: view();
      animation-range: cover 0% cover 100%;
    }
  }
}

/* ── Fallbacks ───────────────────────────────────────────────────────── */

/* No scroll-driven animations (Firefox today): scroll.ts marks <html>. The
   pieces still have to look composed standing still, so they simply sit at
   their resting state. */
html:not(.sda) .px__bed > :is(img, picture),
html:not(.sda) .px__layer {
  translate: none;
  scale: 1;
}

html:not(.sda) [data-open] {
  clip-path: none;
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  .px__bed > :is(img, picture),
  .px__layer,
  .px-shift img {
    animation: none !important;
    translate: none !important;
    scale: 1 !important;
    object-position: 50% 50% !important;
  }

  [data-open] {
    animation: none !important;
    clip-path: none !important;
    opacity: 1 !important;
  }
}
.wordmark[data-astro-cid-whnqjgv2] {
  display: inline-flex;
  align-items: center;
  gap: .6rem;
  color: var(--text);
  text-decoration: none;
}

.wordmark__text[data-astro-cid-whnqjgv2] {
  display: flex;
  flex-direction: column;
  font-size: 1.45rem;
  font-weight: 850;
  letter-spacing: .04em;
  line-height: 1;
}

.wordmark__sub[data-astro-cid-whnqjgv2] {
  font-family: var(--font-ui);
  font-size: .5rem;
  font-weight: 600;
  letter-spacing: .22em;
  color: var(--text-muted);
  margin-block-start: .28rem;
}

@media (width <= 22rem) {
  .wordmark__sub[data-astro-cid-whnqjgv2] {
    display: none;
  }
}
.lang[data-astro-cid-ecceicg2] {
  display: flex;
  align-items: center;
  font-size: var(--step--1);
  font-weight: 650;
  letter-spacing: .06em;
}

.lang__item[data-astro-cid-ecceicg2] {
  padding: .25rem .4rem;
  color: var(--text-muted);
  text-decoration: none;
  transition: color var(--dur-fast) var(--ease-deco);
}

.lang__item[data-astro-cid-ecceicg2]:hover {
  color: var(--text);
}

.lang__item[data-astro-cid-ecceicg2][aria-current="true"] {
  color: var(--text);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: .35em;
}

@media (pointer: coarse) {
  .lang__item[data-astro-cid-ecceicg2] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 2.75rem;
    min-height: 2.75rem;
  }
}

.lang__item[data-astro-cid-ecceicg2] + .lang__item[data-astro-cid-ecceicg2] {
  border-inline-start: 1px solid var(--hairline);
}
.site-header[data-astro-cid-isef26zo] {
  position: sticky;
  top: 0;
  z-index: var(--z-header);
  padding-block: .6rem;
  pointer-events: none;
}

.site-header__inner[data-astro-cid-isef26zo] {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--space-m);
  min-height: 3.5rem;
  padding-inline: var(--space-s) var(--space-xs);
  border-radius: var(--radius-pill);
  background: var(--glass-sheen), color-mix(in srgb, var(--night) 58%, transparent);
  border: 1px solid var(--glass-edge);
  box-shadow: inset 0 1px 0 var(--glass-highlight),
      0 .75rem 2rem #05040e59;
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  pointer-events: auto;
}

.site-header__brand[data-astro-cid-isef26zo] {
  margin-inline-end: auto;
  text-decoration: none;
}

.site-header__toggle[data-astro-cid-isef26zo] {
  display: none;
  width: 2.75rem;
  height: 2.75rem;
  align-items: center;
  justify-content: center;
}

.site-header__bars[data-astro-cid-isef26zo], .site-header__bars[data-astro-cid-isef26zo]:before, .site-header__bars[data-astro-cid-isef26zo]:after {
  display: block;
  width: 1.25rem;
  height: 2px;
  background: var(--text);
}

.site-header__bars[data-astro-cid-isef26zo] {
  position: relative;
}

.site-header__bars[data-astro-cid-isef26zo]:before, .site-header__bars[data-astro-cid-isef26zo]:after {
  content: "";
  position: absolute;
  left: 0;
}

.site-header__bars[data-astro-cid-isef26zo]:before {
  top: -6px;
}

.site-header__bars[data-astro-cid-isef26zo]:after {
  top: 6px;
}

.site-nav[data-astro-cid-isef26zo] {
  display: flex;
  align-items: center;
  gap: var(--space-m);
}

.site-nav__list[data-astro-cid-isef26zo] {
  display: flex;
  align-items: center;
  gap: var(--space-s);
  margin: 0;
}

.site-nav__link[data-astro-cid-isef26zo] {
  position: relative;
  display: block;
  padding: .4rem 0;
  font-size: var(--step--1);
  font-weight: 600;
  color: var(--text-muted);
  text-decoration: none;
  transition: color var(--dur-fast) var(--ease-deco);
}

.site-nav__link[data-astro-cid-isef26zo]:hover {
  color: var(--text);
}

.site-nav__link[data-astro-cid-isef26zo][aria-current="page"] {
  color: var(--text);
}

.site-nav__link[data-astro-cid-isef26zo][aria-current="page"]:after {
  content: "";
  position: absolute;
  inset-inline: 0;
  bottom: -.15rem;
  height: 2px;
  background: var(--vice-pink);
  border-radius: var(--radius-pill);
}

@media (width <= 52rem) {
  .site-header__toggle[data-astro-cid-isef26zo] {
    display: inline-flex;
  }

  .site-nav[data-astro-cid-isef26zo] {
    position: absolute;
    inset-inline: 0;
    top: calc(100% + .5rem);
    display: none;
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-s);
    padding: var(--space-m) var(--space-l) var(--space-l);
    border-radius: var(--radius-l);
    background: var(--glass-sheen), color-mix(in srgb, var(--night) 82%, transparent);
    border: 1px solid var(--glass-edge);
    box-shadow: inset 0 1px 0 var(--glass-highlight),
        0 1.25rem 3rem #05040e80;
    backdrop-filter: var(--glass-blur);
    -webkit-backdrop-filter: var(--glass-blur);
  }

  .site-nav[data-astro-cid-isef26zo].is-open {
    display: flex;
  }

  .site-nav__list[data-astro-cid-isef26zo] {
    flex-direction: column;
    align-items: stretch;
    gap: 0;
  }

  .site-nav__link[data-astro-cid-isef26zo] {
    padding: .75rem 0;
    font-size: var(--step-0);
    border-block-end: 1px solid var(--hairline);
  }

  .site-nav__link[data-astro-cid-isef26zo][aria-current="page"]:after {
    display: none;
  }
}
.site-footer[data-astro-cid-oenwriqq] {
  margin-block-start: var(--space-3xl);
  padding-block-end: var(--space-xl);
  font-size: var(--step--1);
  color: var(--text-muted);
}

.site-footer__inner[data-astro-cid-oenwriqq] {
  display: grid;
  gap: var(--space-l);
  padding-block-start: var(--space-xl);
  grid-template-columns: 1fr;
}

@media (width >= 46rem) {
  .site-footer__inner[data-astro-cid-oenwriqq] {
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: start;
  }

  .site-footer__legal[data-astro-cid-oenwriqq] {
    grid-column: 1 / -1;
  }
}

.site-footer__tagline[data-astro-cid-oenwriqq] {
  margin-block-start: var(--space-2xs);
  color: var(--text-muted);
}

.site-footer__nav[data-astro-cid-oenwriqq] ul[data-astro-cid-oenwriqq] {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-s);
  margin: 0;
  padding: 0;
}

.site-footer__nav[data-astro-cid-oenwriqq] a[data-astro-cid-oenwriqq] {
  color: var(--text-muted);
  text-decoration: none;
}

@media (pointer: coarse) {
  .site-footer__nav[data-astro-cid-oenwriqq] a[data-astro-cid-oenwriqq] {
    display: inline-flex;
    align-items: center;
    min-height: 2.75rem;
  }

  .site-footer__nav[data-astro-cid-oenwriqq] ul[data-astro-cid-oenwriqq] {
    column-gap: var(--space-m);
    row-gap: 0;
  }
}

.site-footer__nav[data-astro-cid-oenwriqq] a[data-astro-cid-oenwriqq]:hover {
  color: var(--text);
  text-decoration: underline;
}

.site-footer__legal[data-astro-cid-oenwriqq] {
  max-width: var(--measure);
  color: var(--text-muted);
}

.site-footer__legal[data-astro-cid-oenwriqq] > [data-astro-cid-oenwriqq] + [data-astro-cid-oenwriqq] {
  margin-block-start: var(--space-2xs);
}

.site-footer__legal[data-astro-cid-oenwriqq] strong[data-astro-cid-oenwriqq] {
  color: var(--text-muted);
}
