/* ==========================================================================
   peterprestrud.com: main stylesheet
   1. Tokens · 2. Fonts · 3. Base · 4. Nav · 5. Hero   (critical, inlined)
   6. Layout · 7. Components · 8. Sections · 9. Legal/404 · 10. Motion/print

   The block between critical:start and critical:end is copied verbatim into
   an inline <style> in index.html by dev/scripts/sync_critical.py, which also
   updates the CSP hash in vercel.json. Edit it here, then run the script.
   ========================================================================== */

/* critical:start */
:root {
  /* Color */
  --c-bg: #000;
  --c-text: #fff;
  --c-accent: #ff8c00;
  --c-accent-hover: #ffa640;
  --c-accent-dim: rgb(255 140 0 / 0.55);
  --c-muted: rgb(255 255 255 / 0.7);
  --c-faint: rgb(255 255 255 / 0.5);
  --c-line: rgb(255 255 255 / 0.12);
  --c-surface: #0b0b0b;
  --c-media: #141414;
  --c-error: #ff6b6b;
  --c-success: #5ee08a;

  /* Type */
  --font-display: "Archivo", "Archivo Fallback", "Arial Black", Arial, sans-serif;
  --font-body: "Inter", "Inter Fallback", system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
  --fs-xs: clamp(0.75rem, 0.72rem + 0.15vw, 0.8125rem);
  --fs-sm: clamp(0.875rem, 0.85rem + 0.15vw, 0.9375rem);
  --fs-base: clamp(1rem, 0.96rem + 0.2vw, 1.125rem);
  --fs-lg: clamp(1.125rem, 1.05rem + 0.4vw, 1.375rem);
  --fs-xl: clamp(1.375rem, 1.2rem + 0.9vw, 2rem);
  --fs-2xl: clamp(1.75rem, 1.4rem + 1.8vw, 3rem);
  --fs-3xl: clamp(2.25rem, 1.6rem + 3.2vw, 4.5rem);
  --fs-hero: min(10.5vw, (100vw - 2 * var(--gutter)) / 7.4, 16rem); /* "Peter Prestrud" is ~7em: always one line */

  /* Space */
  --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-section: clamp(5rem, 3rem + 8vw, 10rem);
  --gutter: max(1rem, 4vw);
  --wrap: 80rem;
  --nav-h: 5rem;

  /* Shape, depth, motion */
  --radius-sm: 0.5rem;
  --radius-md: 0.75rem;
  --radius-full: 999px;
  --z-nav: 100;
  --z-modal: 200;
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
  --dur-fast: 0.2s;
  --dur: 0.3s;
  --dur-slow: 0.6s;
}

/* Metric-matched fallbacks keep text from shifting when the web fonts swap
   in. Computed from the font files (average glyph width + vertical metrics,
   Capsize method) against Arial / Arial Bold. */
@font-face {
  font-family: "Archivo Fallback";
  src: local("Arial Bold"), local("Arial-BoldMT");
  font-weight: 800;
  size-adjust: 103.18%;
  ascent-override: 85.09%;
  descent-override: 20.35%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "Inter Fallback";
  src: local("Arial"), local("ArialMT");
  font-weight: 400;
  size-adjust: 107.48%;
  ascent-override: 90.14%;
  descent-override: 22.44%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "Inter Fallback";
  src: local("Arial Bold"), local("Arial-BoldMT");
  font-weight: 600;
  size-adjust: 101.32%;
  ascent-override: 95.61%;
  descent-override: 23.81%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "Archivo";
  src: url("/fonts/archivo-800-latin-v1.woff2") format("woff2");
  font-weight: 800;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Inter";
  src: url("/fonts/inter-400-latin-v1.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Inter";
  src: url("/fonts/inter-600-latin-v1.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

*, *::before, *::after { box-sizing: border-box; }
html {
  color-scheme: dark;
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  scroll-padding-top: var(--nav-h);
}
body {
  margin: 0;
  min-height: 100svh;
  background: var(--c-bg);
  color: var(--c-text);
  font-family: var(--font-body);
  font-size: var(--fs-base);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;
}
img, video, canvas, svg { display: block; max-width: 100%; }
a { color: inherit; }
h1, h2, h3, p, ul, ol, dl, dd, figure { margin: 0; }
button, input, textarea { font: inherit; color: inherit; }
:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 3px; }
/* No transitions until the async stylesheet has applied (main.js removes the
   class after load), so elements don't animate in from browser defaults. */
.no-transitions *, .no-transitions *::before, .no-transitions *::after { transition: none !important; }
[tabindex="-1"]:focus { outline: none; }

.skip-link {
  position: fixed;
  top: var(--space-3);
  left: var(--space-3);
  z-index: calc(var(--z-modal) + 1);
  padding: var(--space-3) var(--space-5);
  border-radius: var(--radius-full);
  background: var(--c-accent);
  color: #000;
  font-weight: 600;
  text-decoration: none;
  transform: translateY(-200%);
}
.skip-link:focus-visible { transform: none; }

/* ---------- Nav ---------- */
.site-header {
  position: fixed;
  inset: 0 0 auto;
  z-index: var(--z-nav);
  display: flex;
  justify-content: center;
  padding: max(var(--space-3), env(safe-area-inset-top)) var(--gutter) 0;
  pointer-events: none;
}
.nav {
  position: relative;
  isolation: isolate;
  display: flex;
  align-items: center;
  gap: var(--space-5);
  min-height: 4rem; /* room for the home page name and its wave (nav.js) */
  padding: var(--space-2) var(--space-6);
  pointer-events: auto;
  transform-origin: 50% 0;
  transition: transform var(--dur-slow) var(--ease-out);
}
.nav::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border: 1px solid var(--c-line);
  border-radius: var(--radius-full);
  background: rgb(0 0 0 / 0.85);
  opacity: 0;
  transform: scale(0.94, 0.8);
  transition: opacity var(--dur-slow) var(--ease-out), transform var(--dur-slow) var(--ease-out);
}
@supports ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
  .nav::before {
    background: rgb(0 0 0 / 0.5);
    -webkit-backdrop-filter: blur(12px) saturate(140%);
    backdrop-filter: blur(12px) saturate(140%);
  }
}
.nav--compact:not(.is-open) { transform: scale(0.92); }
/* An open menu's fixed overlay must not be contained by a transformed nav */
.nav.is-open { transform: none; transition: none; }
.nav--compact::before { opacity: 1; transform: none; }
.nav__brand {
  display: none;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: var(--fs-sm);
  letter-spacing: 0.02em;
  text-decoration: none;
}
.nav__links {
  display: flex;
  gap: clamp(1.5rem, 4vw, 3rem);
  padding: 0;
  list-style: none;
}
.nav__link {
  display: inline-block;
  padding: var(--space-2) 0;
  font-size: var(--fs-sm);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--c-text);
  transition: color var(--dur) ease;
}
.nav__link:hover, .nav__link:focus-visible { color: var(--c-accent); }
.nav__toggle { display: none; }

@media (max-width: 47.99rem) {
  .nav { width: 100%; min-height: 3.75rem; justify-content: center; padding-inline: var(--space-5); } /* same box before/after nav.js */
  .nav__links { gap: var(--space-5); }
  .nav--enhanced { width: 100%; justify-content: space-between; }
  .nav--enhanced .nav__brand { display: block; transition: opacity var(--dur) ease, visibility var(--dur); }
  /* visibility too, so the hidden name isn't an invisible Tab stop (the hero H1 already says it) */
  .nav--enhanced:not(.nav--compact):not(.is-open) .nav__brand { opacity: 0; visibility: hidden; pointer-events: none; }
  .nav--enhanced .nav__links { display: none; }
  .nav--enhanced .nav__toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.75rem;
    height: 2.75rem;
    margin-right: calc(var(--space-3) * -1);
    border: 0;
    border-radius: var(--radius-full);
    background: transparent;
    cursor: pointer;
  }
}

/* ---------- Hero ---------- */
.hero {
  position: relative;
  display: grid;
  grid-template-rows: 1fr auto; /* name centered, client logos along the bottom */
  place-items: center;
  min-height: 100svh;
  overflow: clip;
  background: radial-gradient(ellipse at 50% 45%, #1c1c1c 0%, var(--c-media) 45%, #000 100%);
}
.hero__media, .hero__overlay, .hero__wave { position: absolute; inset: 0; }
.hero__poster, .hero__video { width: 100%; height: 100%; object-fit: cover; }
.hero__video {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 0.8s var(--ease-out);
}
.hero__video.is-playing { opacity: 1; }
.hero__overlay {
  background:
    /* Fade to the page background into the about section: eased stops, no seam */
    linear-gradient(to bottom, rgb(0 0 0 / 0) 60%, rgb(0 0 0 / 0.12) 68%, rgb(0 0 0 / 0.35) 77%, rgb(0 0 0 / 0.65) 86%, rgb(0 0 0 / 0.88) 94%, var(--c-bg) 100%),
    linear-gradient(to bottom, rgb(0 0 0 / 0.55) 0%, rgb(0 0 0 / 0.65) 30%, rgb(0 0 0 / 0.65) 100%);
}
.hero__wave { inset: auto; pointer-events: none; visibility: hidden; } /* shown once positioned (hero.js) */
.hero__content {
  position: relative;
  z-index: 2;
  padding: calc(var(--nav-h) + var(--space-4)) var(--gutter) var(--space-8);
  text-align: center;
}
.hero__title { margin: 0; font-weight: 400; }
.hero__name {
  display: block;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: var(--fs-hero);
  line-height: 0.92;
  letter-spacing: -0.02em;
  white-space: nowrap;
  color: rgb(255 255 255 / 0.7);
  text-shadow: 0 0 40px rgb(0 0 0 / 0.35);
}
.hero__role {
  display: block;
  margin-top: var(--space-5);
  font-family: var(--font-body);
  font-weight: 600;
  font-size: var(--fs-lg);
  line-height: 1.3;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--c-text);
  text-shadow: 0 0 0.75rem rgb(0 0 0 / 0.9), 0 0 0.25rem rgb(0 0 0 / 0.8); /* legible over wave spikes + video */
}
/* Client logos along the bottom of the hero. Styled here (critical) so the
   row has its final size in the first paint: no layout shift when marquee.js
   starts it moving. */
.hero__clients {
  position: relative;
  z-index: 2;
  justify-self: stretch;
  min-width: 0;
  padding-bottom: max(var(--space-5), env(safe-area-inset-bottom));
}
.marquee__title {
  margin-bottom: var(--space-4);
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  text-align: center;
  color: var(--c-muted);
}
.marquee__row {
  --logo-gap: clamp(1.75rem, 4vw, 4rem);
  display: flex;
  min-width: 0;
  overflow: clip;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
/* Hidden until main.js sees every logo loaded or swapped for its name (no
   swap or width jumps), then shown at once. Failsafe without JS: after 3 s. */
.marquee__row { opacity: 0; animation: marquee-failsafe 0s 3s forwards; }
.marquee.is-ready .marquee__row { opacity: 1; animation: none; }
@keyframes marquee-failsafe { to { opacity: 1; } }
.marquee__track {
  display: flex;
  flex-shrink: 0;
  align-items: center;
  gap: var(--logo-gap);
  margin: 0;
  padding: 0 var(--logo-gap) 0 0;
  list-style: none;
}
.marquee__logo {
  display: block;
  width: auto;
  height: clamp(2.5rem, 1.8rem + 2vw, 4rem);
  max-width: 16rem;
  object-fit: contain;
  opacity: 0.85;
}
/* Reduced motion (marquee.js doesn't run): a static, wrapped, centered set.
   Critical: the wrapped row is taller, so applying it late shifted the hero. */
@media (prefers-reduced-motion: reduce) {
  .marquee__row { justify-content: center; -webkit-mask-image: none; mask-image: none; }
  .marquee__track { flex-wrap: wrap; justify-content: center; flex-shrink: 1; padding: 0 var(--gutter); row-gap: var(--space-4); }
  .marquee__track[aria-hidden="true"] { display: none; }
}
@media (max-width: 24rem) {
  .hero__role { font-size: 1rem; letter-spacing: 0.12em; }
}
/* critical:end */

/* ==========================================================================
   6. Layout
   ========================================================================== */
html:focus-within { scroll-behavior: smooth; }

.wrap {
  width: 100%;
  max-width: calc(var(--wrap) + 2 * var(--gutter));
  margin-inline: auto;
  padding-inline: max(var(--gutter), env(safe-area-inset-left)) max(var(--gutter), env(safe-area-inset-right));
}
.section { position: relative; padding-block: var(--space-section); }
.section-title {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: var(--fs-3xl);
  line-height: 1.02;
  letter-spacing: -0.02em;
  text-wrap: balance;
}
.eyebrow {
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--c-muted);
}
/* Offscreen sections skip layout/paint until near the viewport. `auto` makes
   the browser remember the real size once rendered, so no scrollbar jumps. */
.cv { content-visibility: auto; contain-intrinsic-size: auto 60rem; }

/* Missing media never breaks layout: neutral fill under every image/video. */
.media-fill { background: var(--ph, var(--c-media)); }
img[data-broken] { visibility: hidden; }
/* Text stand-in for a client logo that failed to load (see main.js) */
.logo-fallback {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(0.95rem, 0.8rem + 0.6vw, 1.5rem);
  line-height: 1;
  letter-spacing: -0.01em;
  white-space: nowrap;
  color: rgb(255 255 255 / 0.85);
}
.marquee__logo.logo-fallback { width: auto; max-width: none; font-size: clamp(1.9rem, 1.6rem + 1.2vw, 3rem); }
.tile__logo.logo-fallback { width: max-content; max-width: calc(100% - 2rem); font-size: var(--fs-lg); white-space: normal; text-align: center; }
/* Posters cross-fade in over the fill once loaded (only when JS is running) */
.stage__item img { transition: opacity var(--dur-slow) ease; }
.js :is(.tile__poster, .stage__item img):not(.is-loaded) { opacity: 0; }

/* ==========================================================================
   7. Components
   ========================================================================== */
.btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  min-height: 3.25rem;
  padding: var(--space-3) var(--space-6);
  border: 0;
  border-radius: var(--radius-full);
  background: var(--c-accent);
  color: #000;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--dur) ease, transform var(--dur) var(--ease-out);
}
.btn:hover { background: var(--c-accent-hover); }
.btn:active { transform: scale(0.98); }
.btn[disabled] { cursor: progress; opacity: 0.65; }
.btn__spinner {
  display: none;
  width: 1rem;
  height: 1rem;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}
.btn.is-loading .btn__spinner { display: inline-block; }
@keyframes spin { to { transform: rotate(360deg); } }

.text-link {
  color: var(--c-text);
  text-decoration: underline;
  text-decoration-color: var(--c-accent-dim);
  text-underline-offset: 0.25em;
  transition: color var(--dur) ease, text-decoration-color var(--dur) ease;
}
.text-link:hover, .text-link:focus-visible { color: var(--c-accent); text-decoration-color: var(--c-accent); }

/* Mobile menu overlay (nav.js) */
@media (max-width: 47.99rem) {
  .nav--enhanced.is-open .nav__links {
    position: fixed;
    inset: 0;
    z-index: -1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--space-6);
    background: var(--c-bg);
  }
  .nav--enhanced.is-open .nav__link { font-size: var(--fs-2xl); font-family: var(--font-display); font-weight: 800; letter-spacing: 0; text-transform: none; }
}
.nav__toggle-bars, .nav__toggle-bars::before, .nav__toggle-bars::after {
  display: block;
  width: 1.25rem;
  height: 2px;
  border-radius: 2px;
  background: currentColor;
  transition: transform var(--dur) var(--ease-out), opacity var(--dur) ease;
}
.nav__toggle-bars { position: relative; }
.nav__toggle-bars::before, .nav__toggle-bars::after { content: ""; position: absolute; left: 0; }
.nav__toggle-bars::before { transform: translateY(-6px); }
.nav__toggle-bars::after { transform: translateY(6px); }
.is-open .nav__toggle-bars { background: transparent; }
.is-open .nav__toggle-bars::before { transform: rotate(45deg); }
.is-open .nav__toggle-bars::after { transform: rotate(-45deg); }

/* The name in the pill (one line) with a small live wave behind "Prestrud"
   (nav.js), on every page. Home: it snaps in once the pill forms, left of
   About. Legal/404 pages: the pill is formed from the start. */
.nav__brand { position: relative; font-size: 1.25rem; letter-spacing: -0.01em; white-space: nowrap; }
.nav__brand-name { position: relative; } /* above the wave */
.nav__wave { position: absolute; pointer-events: none; }
@media (min-width: 48rem) {
  .nav--enhanced.nav--compact .nav__brand { display: block; }
}
@media (max-width: 47.99rem) {
  .nav__brand { font-size: 1.125rem; }
}
.nav--enhanced.nav--compact:not(.is-open) .nav__brand { animation: brand-snap 0.35s 0.15s var(--ease-out) both; }
@keyframes brand-snap {
  from { opacity: 0; transform: scale(0.85); }
  to { opacity: 1; transform: none; }
}

/* Fixed nav on legal/404 pages starts compact, with the name as a home link */
.page-simple .nav::before { opacity: 1; transform: none; }
@media (min-width: 48rem) { .page-simple .nav__brand { display: block; margin-right: var(--space-4); } }
.page-simple .nav--enhanced.nav--compact .nav__brand { animation: none; } /* already in place on load: no snap-in */

/* ==========================================================================
   8. Sections
   ========================================================================== */

/* ---------- Marquee ---------- */
.marquee.is-enhanced .marquee__track { will-change: transform; }

/* ---------- About ----------
   All copy centered. With motion, about.js pins the stage: the headline +
   lead hold centered (headline filling orange) while the client logos
   scatter around them, then the rest of the copy scrolls up through the
   middle while the photos fly in from depth around and behind it. No bottom
   padding: the Work section's own top padding is the gap between them. */
.about { padding-bottom: 0; }
.about__header { margin-bottom: var(--space-7); text-align: center; }
.about__header .section-title { max-width: 22ch; margin-inline: auto; }
.about__lead {
  max-width: 34ch;
  margin: var(--space-6) auto 0;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: var(--fs-xl);
  line-height: 1.3;
  letter-spacing: -0.01em;
  /* Not balance: about.js splits the lead into lines for its reveal, then
     puts the original text back. Firefox balances the original differently
     from the split lines, so words jumped to another line at the swap.
     `pretty` (Chrome, Safari) wraps the same both ways; Firefox ignores it
     and uses plain wrapping. */
  text-wrap: wrap;
  text-wrap: pretty;
}
.about__more { text-align: center; }
.about__body {
  display: grid;
  gap: var(--space-5);
  max-width: 46rem;
  margin-inline: auto;
  color: var(--c-muted);
}
.about__body em { color: var(--c-text); font-style: italic; }
.about__press { margin-top: var(--space-6); font-size: var(--fs-sm); }
/* Depth stage: centered text then a static grid until about.js pins it
   (also the reduced-motion look) */
.stage { margin-bottom: var(--space-8); }
.stage__items {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
  gap: var(--space-4);
  width: 100%;
  max-width: calc(var(--wrap) + 2 * var(--gutter));
  margin: 0 auto;
  padding: 0 var(--gutter);
  list-style: none;
}
.stage:not(.is-pinned) .stage__items { margin-top: var(--space-8); }
.stage__item { position: relative; overflow: hidden; aspect-ratio: 3 / 2; border-radius: var(--radius-md); }
.stage__item--portrait { aspect-ratio: 4 / 5; }
.stage__item img, .stage__item video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.stage__item video { opacity: 0; transition: opacity var(--dur-slow) ease; }
.stage__item video.is-playing { opacity: 1; }

/* Pinned stage (about.js): the copy column on top (placed and scrolled by
   GSAP), items flown behind it */
/* Held in place by sticky over the spacer about.js adds after it (as tall as
   the scrubbed range). Sticky is handled on the browser's scroll thread, so
   the text can't stutter, and it never counts as a layout shift. */
.stage.is-pinned {
  position: sticky;
  top: 0;
  z-index: 2; /* above the flying logos (.logo-scatter, z-index 1) */
  height: 100svh;
  margin-bottom: 0;
  overflow: hidden;
}
.stage.is-pinned .about__copy {
  position: absolute;
  top: var(--copy-top, 0px);
  left: 0;
  right: 0;
  z-index: 3;
  text-shadow: 0 0 1rem rgb(0 0 0 / 0.9), 0 0 0.25rem rgb(0 0 0 / 0.8); /* legible over photos where the band fades */
}
/* Dark band behind the text column, so photos passing behind it stay readable.
   Its top and bottom fade out too, so no hard edge cuts across the logos as
   the stage scrolls in. */
.stage.is-pinned::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background: linear-gradient(90deg, transparent calc(50% - 32rem), rgb(0 0 0 / 0.7) calc(50% - 24rem), rgb(0 0 0 / 0.7) calc(50% + 24rem), transparent calc(50% + 32rem));
  -webkit-mask-image: linear-gradient(transparent, #000 20%, #000 80%, transparent);
  mask-image: linear-gradient(transparent, #000 20%, #000 80%, transparent);
}
.stage.is-pinned .stage__items { position: absolute; inset: 0; z-index: 1; display: block; max-width: none; padding: 0; perspective: 1200px; }
.stage.is-pinned .stage__item {
  position: absolute;
  top: 50%;
  left: 50%;
  width: min(24vw, 21rem);
  box-shadow: 0 2rem 5rem rgb(0 0 0 / 0.6);
  will-change: transform, opacity;
}
.stage.is-pinned .stage__item--portrait { width: min(16vw, 14rem); }
@media (max-width: 47.99rem) {
  .stage.is-pinned::after { background: rgb(0 0 0 / 0.65); } /* the text spans the screen */
  .stage.is-pinned .stage__item { width: 46vw; }
  .stage.is-pinned .stage__item--portrait { width: 34vw; }
}

/* Client logos flying from the hero row to around the about text (about-logos.js) */
.logo-scatter { position: fixed; inset: 0; z-index: 1; pointer-events: none; }
.logo-scatter > * { position: absolute; top: 0; left: 0; margin: 0; transform-origin: 50% 50%; }
.hero__clients.is-scattered .marquee__row { visibility: hidden; }

/* ---------- Work grid ----------
   Full-width rows (about 4 per row on desktop, stacked bands on phones). At rest
   every tile plays its clip in black and white with its logo centered and
   its title along the bottom. The open tile (hover, keyboard focus or tap)
   takes half the row's width and its row grows to about half the screen; it
   turns to color, the logo slides to the top, and the rest of the info and
   the play button reveal. Tiles use min-height so a row is as tall as
   its open tile. Tiles touch (no gap, no rounded corners): a gap left the
   pointer over no tile between two, so the open row collapsed and jumped
   before the next tile opened. */
.work__header { margin-bottom: var(--space-7); }
.work__grid {
  --tile-gap: 0px;
  container: work / inline-size;
  display: flex;
  flex-wrap: wrap;
  column-gap: var(--tile-gap);
  row-gap: 0;
  padding-inline: max(var(--tile-gap), env(safe-area-inset-left)) max(var(--tile-gap), env(safe-area-inset-right));
}
/* Breaks force rows. Phones show every break (one tile per row); wider grids
   show only the breaks whose data-cols lists their column count. The data-cols
   values are written by dev/scripts/build_grid.py so rows stay balanced for
   any number of tiles (never a lone tile on the last row). */
.work__break { display: block; flex-basis: 100%; height: 0; }
.tile {
  --cols: 1;
  --ratio: 0.5; /* phones: short full-width bands (room for the logo and title) */
  --tile-h: calc((100cqi - (var(--cols) - 1) * var(--tile-gap)) / var(--cols) * var(--ratio));
  --open-h: max(var(--tile-h), 50svh);       /* the open tile's row: about half the screen */
  --open-grow: max(2, calc(var(--cols) - 1)); /* the open tile: about half the row */
  position: relative;
  flex: 1 1 1px; /* not 0: with no gap, 0-wide tiles plus a 100% break fit one line and the tiles collapse to nothing */
  min-width: 0;
  min-height: var(--tile-h);
  margin-block-end: var(--tile-gap);
  overflow: hidden;
  background: var(--ph, var(--c-media));
  content-visibility: auto;
  contain-intrinsic-size: auto var(--tile-h);
  transition: flex-grow var(--dur-slow) var(--ease-out), min-height var(--dur-slow) var(--ease-out);
}
/* A row is as tall as its tallest tile, so when the open tile moves to a
   neighbour, one shrinking while the other grows would dip the row (and jump
   the page) halfway through. So a closing tile in the same row as the open
   tile (no visible break between them: one rule per column count) keeps its
   height until the new one has finished growing. A tile in another row
   closes at once, in step with the new row opening, so the two rows trade
   height and nothing above or below them moves. Leaving the grid closes at
   once. Pure CSS on purpose: a class set from a hover event lands after
   Chrome has already started the transitions. */
@container work (min-width: 36rem) and (max-width: 63.99rem) {
  .tile:not(:hover, :focus-within, .is-active):has(~ .tile:is(:hover, :focus-within, .is-active)):not(:has(~ .work__break[data-cols~="2"] ~ .tile:is(:hover, :focus-within, .is-active))),
  .tile:is(:hover, :focus-within, .is-active) ~ .tile:not(:hover, :focus-within, .is-active):not(.tile:is(:hover, :focus-within, .is-active) ~ .work__break[data-cols~="2"] ~ .tile) {
    transition-delay: 0s, var(--dur-slow);
  }
}
@container work (min-width: 64rem) and (max-width: 149.99rem) {
  .tile:not(:hover, :focus-within, .is-active):has(~ .tile:is(:hover, :focus-within, .is-active)):not(:has(~ .work__break[data-cols~="4"] ~ .tile:is(:hover, :focus-within, .is-active))),
  .tile:is(:hover, :focus-within, .is-active) ~ .tile:not(:hover, :focus-within, .is-active):not(.tile:is(:hover, :focus-within, .is-active) ~ .work__break[data-cols~="4"] ~ .tile) {
    transition-delay: 0s, var(--dur-slow);
  }
}
@container work (min-width: 150rem) {
  .tile:not(:hover, :focus-within, .is-active):has(~ .tile:is(:hover, :focus-within, .is-active)):not(:has(~ .work__break[data-cols~="8"] ~ .tile:is(:hover, :focus-within, .is-active))),
  .tile:is(:hover, :focus-within, .is-active) ~ .tile:not(:hover, :focus-within, .is-active):not(.tile:is(:hover, :focus-within, .is-active) ~ .work__break[data-cols~="8"] ~ .tile) {
    transition-delay: 0s, var(--dur-slow);
  }
}
@container work (min-width: 36rem) {
  .tile { --cols: 2; --ratio: 0.75; }
  .work__break { display: none; }
  .work__break[data-cols~="2"] { display: block; }
}
@container work (min-width: 64rem) {
  .tile { --cols: 4; }
  .work__break[data-cols] { display: none; } /* same weight as the rule above, so order decides */
  .work__break[data-cols~="4"] { display: block; }
}
@container work (min-width: 150rem) {
  .tile { --cols: 8; }
  .work__break[data-cols] { display: none; } /* same weight as the rule above, so order decides */
  .work__break[data-cols~="8"] { display: block; }
}
.tile__poster, .tile__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: grayscale(1);
  transition: filter var(--dur-slow) ease, opacity var(--dur-slow) ease, transform 1.2s var(--ease-out);
}
.tile__video { opacity: 0; }
.tile__video.is-playing { opacity: 1; }
.tile::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgb(0 0 0 / 0.85), rgb(0 0 0 / 0.35) 55%, rgb(0 0 0 / 0.25));
  opacity: 0.6; /* at rest: enough for the logo and title; full when open */
  transition: opacity var(--dur-slow) ease;
}
/* Centered in the tile at rest, whatever the row's height (siblings of an
   open tile are taller); slides to the top when open. `top` only moves the
   logo itself, nothing else in the layout. */
.tile__logo {
  position: absolute;
  top: 50%;
  left: 50%;
  z-index: 2;
  width: clamp(5rem, 52%, 11.7rem);
  height: min(3.575rem, 40%); /* 40%: room for the title under it on short phone bands */
  object-fit: contain;
  transform: translate(-50%, -50%);
  transition: top var(--dur-slow) var(--ease-out), transform var(--dur-slow) var(--ease-out);
}
.tile__play {
  position: absolute;
  top: 50%;
  left: 50%;
  z-index: 3;
  display: grid;
  place-items: center;
  width: 3.5rem;
  height: 3.5rem;
  padding: 0;
  border: 1px solid rgb(255 255 255 / 0.6);
  border-radius: 50%;
  background: rgb(0 0 0 / 0.35);
  color: #fff;
  cursor: pointer;
  opacity: 0;
  transform: translate(-50%, -60%) scale(0.8);
  transition: opacity var(--dur) ease, transform var(--dur-slow) var(--ease-out), background-color var(--dur) ease, border-color var(--dur) ease;
}
.tile__play svg { width: 1.1rem; height: 1.1rem; margin-left: 0.15rem; }
.tile__play:hover, .tile__play:focus-visible { background: var(--c-accent); border-color: var(--c-accent); color: #000; }
.tile__play[aria-disabled="true"] { cursor: not-allowed; }
.tile.has-video { cursor: pointer; } /* whole tile opens the video (work-grid.js) */
/* Title along the bottom at rest; meta + description rows are collapsed
   (0fr) so the title sits at the bottom, and open to their height (1fr). */
.tile__info {
  position: absolute;
  inset: auto var(--space-4) var(--space-4);
  z-index: 2;
  display: grid;
  grid-template-rows: auto 0fr 0fr;
  gap: var(--space-1);
  transition: grid-template-rows var(--dur-slow) var(--ease-out);
}
.tile__info > :not(.tile__title) { min-height: 0; overflow: hidden; }
.tile__info > * {
  opacity: 0;
  transform: translateY(0.75rem);
  transition: opacity var(--dur) ease, transform var(--dur-slow) var(--ease-out);
}
.tile__info > .tile__title { opacity: 1; transform: none; } /* the title shows at rest */
.tile__title { font-family: var(--font-display); font-weight: 800; font-size: var(--fs-lg); line-height: 1.2; }
.tile__meta { display: flex; flex-wrap: wrap; gap: 0 var(--space-4); font-size: var(--fs-xs); letter-spacing: 0.08em; text-transform: uppercase; }
.tile__meta div { display: flex; gap: var(--space-2); }
.tile__meta dt { color: var(--c-faint); }
.tile__meta dd { color: var(--c-accent); }
.tile__desc {
  display: -webkit-box;
  overflow: hidden;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  font-size: var(--fs-xs);
  line-height: 1.5;
  color: var(--c-muted);
}

/* Open state: hover (fine pointers), keyboard focus, or tap (.is-active) */
.tile:focus-within, .tile.is-active { flex-grow: var(--open-grow); min-height: var(--open-h); }
@media (hover: hover) { .tile:hover { flex-grow: var(--open-grow); min-height: var(--open-h); } }
@container work (max-width: 35.99rem) {
  .tile:focus-within, .tile.is-active, .tile:hover { flex-grow: 1; } /* bands: open in height only */
}
.tile:is(:focus-within, .is-active)::after { opacity: 1; }
.tile:is(:focus-within, .is-active) :is(.tile__poster, .tile__video) { filter: grayscale(0); }
.tile:is(:focus-within, .is-active) .tile__logo { top: var(--space-4); transform: translate(-50%, 0) scale(0.85); }
.tile:is(:focus-within, .is-active) .tile__info { grid-template-rows: auto 1fr 1fr; }
.tile:is(:focus-within, .is-active) .tile__play { opacity: 1; transform: translate(-50%, -60%); }
.tile:is(:focus-within, .is-active) .tile__info > * { opacity: 1; transform: none; }
.tile:is(:focus-within, .is-active) .tile__info > :nth-child(2) { transition-delay: 0.06s; }
.tile:is(:focus-within, .is-active) .tile__info > :nth-child(3) { transition-delay: 0.12s; }
@media (hover: hover) {
  .tile:hover::after { opacity: 1; }
  .tile:hover :is(.tile__poster, .tile__video) { filter: grayscale(0); }
  .tile:hover .tile__logo { top: var(--space-4); transform: translate(-50%, 0) scale(0.85); }
  .tile:hover .tile__info { grid-template-rows: auto 1fr 1fr; }
  .tile:hover .tile__play { opacity: 1; transform: translate(-50%, -60%); }
  .tile:hover .tile__info > * { opacity: 1; transform: none; }
  .tile:hover .tile__info > :nth-child(2) { transition-delay: 0.06s; }
  .tile:hover .tile__info > :nth-child(3) { transition-delay: 0.12s; }
}

/* ---------- Video overlay (video-modal.js) ---------- */
.vmodal {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  max-height: none;
  margin: 0;
  padding: max(4.5rem, env(safe-area-inset-top)) max(var(--space-4), env(safe-area-inset-right)) max(var(--space-4), env(safe-area-inset-bottom)) max(var(--space-4), env(safe-area-inset-left));
  border: 0;
  background: #000;
  color: var(--c-text);
}
.vmodal[open] { display: grid; place-items: center; animation: vmodal-in 0.35s var(--ease-out); }
.vmodal:focus { outline: none; } /* focus sits here after a click in the player (video-modal.js) */
.vmodal::backdrop { background: #000; }
@keyframes vmodal-in { from { opacity: 0; } }
.vmodal__frame {
  width: min(100%, calc((100dvh - 6rem) * 16 / 9));
  aspect-ratio: 16 / 9;
  background: #000;
}
.vmodal__frame iframe { display: block; width: 100%; height: 100%; border: 0; }
.vmodal__close {
  position: absolute;
  top: max(var(--space-3), env(safe-area-inset-top));
  right: max(var(--space-3), env(safe-area-inset-right));
  display: grid;
  place-items: center;
  width: 3rem;
  height: 3rem;
  padding: 0;
  border: 1px solid var(--c-line);
  border-radius: 50%;
  background: rgb(255 255 255 / 0.06);
  color: var(--c-text);
  cursor: pointer;
  transition: background-color var(--dur) ease, color var(--dur) ease, border-color var(--dur) ease;
}
.vmodal__close svg { width: 1.25rem; height: 1.25rem; }
.vmodal__close:hover, .vmodal__close:focus-visible { background: var(--c-accent); border-color: var(--c-accent); color: #000; }
@media (orientation: landscape) and (max-height: 32rem) {
  .vmodal { padding-top: max(var(--space-4), env(safe-area-inset-top)); }
  .vmodal__frame { width: min(100% - 4rem, calc((100dvh - 2rem) * 16 / 9)); }
}

/* ---------- Contact ----------
   Layers, back to front: background video, dark overlay, orange wave,
   content. */
.contact { overflow: clip; }
.contact__media { position: absolute; inset: 0; overflow: hidden; }
.contact__poster, .contact__video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.contact__video { opacity: 0; transition: opacity var(--dur-slow) ease; }
.contact__video.is-playing { opacity: 1; }
/* About 70% black so the form reads first; fades to the page background at
   the top and bottom so the section blends into its neighbours. */
.contact__overlay {
  position: absolute;
  inset: 0;
  background: linear-gradient(to bottom, var(--c-bg) 0%, rgb(0 0 0 / 0.7) 14%, rgb(0 0 0 / 0.7) 86%, var(--c-bg) 100%);
}
.contact__wave { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0.45; pointer-events: none; }
.contact__inner { position: relative; z-index: 1; }
.contact__intro { max-width: 46ch; margin-top: var(--space-5); color: var(--c-muted); font-size: var(--fs-lg); }
.contact__layout { display: grid; gap: var(--space-8); margin-top: var(--space-7); }
@media (min-width: 64rem) {
  .contact__layout { grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr); align-items: start; }
}
.contact__area { margin-top: var(--space-6); font-size: var(--fs-sm); color: var(--c-muted); }

.form { display: grid; gap: var(--space-5); }
.form__row { display: grid; gap: var(--space-5); }
@media (min-width: 40rem) { .form__row { grid-template-columns: 1fr 1fr; } }
.field { position: relative; display: grid; }
.field__input {
  width: 100%;
  min-height: 3.5rem;
  padding: 1.5rem var(--space-4) 0.5rem;
  border: 0;
  border-bottom: 1px solid rgb(255 255 255 / 0.3);
  border-radius: var(--radius-sm) var(--radius-sm) 0 0;
  background: rgb(255 255 255 / 0.05);
  transition: border-color var(--dur) ease, background-color var(--dur) ease, box-shadow var(--dur) ease;
}
textarea.field__input { min-height: 10rem; resize: vertical; line-height: 1.5; }
.field__input:hover { background: rgb(255 255 255 / 0.08); }
.field__input:focus { outline: none; border-bottom-color: var(--c-accent); box-shadow: 0 1px 0 var(--c-accent); }
.field__input:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 2px; }
.field__label {
  position: absolute;
  top: 1.05rem;
  left: var(--space-4);
  color: var(--c-muted);
  pointer-events: none;
  transform-origin: 0 0;
  transition: transform var(--dur) var(--ease-out), color var(--dur) ease;
}
.field__input:focus + .field__label,
.field__input:not(:placeholder-shown) + .field__label { transform: translateY(-0.65rem) scale(0.75); }
.field__input:focus + .field__label { color: var(--c-accent); }
.field__input[aria-invalid="true"] { border-bottom-color: var(--c-error); }
.field__hint, .field__error { margin-top: var(--space-2); font-size: var(--fs-xs); }
.field__hint { color: var(--c-faint); }
.field__error { color: var(--c-error); }
.field__error:empty { display: none; }
.field__counter { justify-self: end; margin-top: var(--space-2); font-size: var(--fs-xs); color: var(--c-faint); font-variant-numeric: tabular-nums; }
.field__req { color: var(--c-accent); }
.form__note { font-size: var(--fs-xs); color: var(--c-faint); }
.form__hp { display: none; }
.form__captcha:empty { display: none; } /* no JS: nothing to show */
/* With JS (contact-form.js sets data-ready), the widget's 78px are reserved so it appears without moving the button. */
.form[data-ready] .form__captcha { display: block; min-height: 78px; }
.form__captcha iframe { display: block; } /* no inline baseline gap: stays at the reserved 78px */
.form__actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-4) var(--space-6); }
.form__consent { font-size: var(--fs-xs); color: var(--c-faint); }
.form__status { font-size: var(--fs-sm); }
.form__status:empty { display: none; }
.form__status[data-state="success"] { color: var(--c-success); }
.form__status[data-state="error"] { color: var(--c-error); }

.socials { display: grid; gap: var(--space-4); }
.socials__title { margin-bottom: var(--space-2); }
.socials__list { display: flex; flex-wrap: wrap; gap: var(--space-3); padding: 0; list-style: none; }
.social {
  position: relative;
  isolation: isolate;
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  min-height: 3rem;
  padding: var(--space-2) var(--space-5) var(--space-2) var(--space-3);
  overflow: hidden;
  border: 1px solid var(--c-line);
  border-radius: var(--radius-full);
  font-size: var(--fs-sm);
  font-weight: 600;
  text-decoration: none;
  transition: color var(--dur) ease, border-color var(--dur) ease;
}
.social::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--c-accent);
  clip-path: inset(100% 0 0 0);
  transition: clip-path var(--dur-slow) var(--ease-out);
}
.social svg { width: 1.75rem; height: 1.75rem; flex-shrink: 0; }
.social:hover, .social:focus-visible { color: #000; border-color: var(--c-accent); }
.social:hover::before, .social:focus-visible::before { clip-path: inset(0 0 0 0); }

/* ---------- Footer ---------- */
.footer {
  padding-block: var(--space-7) max(var(--space-7), env(safe-area-inset-bottom));
  border-top: 1px solid var(--c-line);
  font-size: var(--fs-sm);
  color: var(--c-muted);
}
.footer__inner { display: grid; gap: var(--space-4); }
@media (min-width: 48rem) {
  .footer__inner { grid-template-columns: 1fr auto; align-items: end; }
}
.footer__links { display: flex; gap: var(--space-5); padding: 0; list-style: none; }

/* ==========================================================================
   9. Legal + 404
   ========================================================================== */
.page-simple main { padding-top: calc(var(--nav-h) + var(--space-7)); }
.legal { max-width: 46rem; padding-bottom: var(--space-section); }
.legal h1 { font-family: var(--font-display); font-weight: 800; font-size: var(--fs-3xl); line-height: 1.05; }
.legal__updated { margin-top: var(--space-3); color: var(--c-faint); font-size: var(--fs-sm); }
.legal h2 { margin-top: var(--space-7); font-family: var(--font-display); font-weight: 800; font-size: var(--fs-xl); line-height: 1.2; }
.legal h3 { margin-top: var(--space-5); font-size: var(--fs-base); font-weight: 600; }
.legal p, .legal ul, .legal ol { margin-top: var(--space-4); color: var(--c-muted); }
.legal ul, .legal ol { padding-left: 1.25rem; }
.legal strong { color: var(--c-text); }
.legal li + li { margin-top: var(--space-2); }

.notfound { display: grid; place-items: center; min-height: 70svh; text-align: center; }
/* "404" with the hero's orange wave behind the digits (notfound.js). The
   wave sits behind all the text (z-index -1 inside the isolated block). */
.notfound__inner { position: relative; isolation: isolate; }
.notfound__wave { position: absolute; z-index: -1; max-width: none; pointer-events: none; visibility: hidden; } /* shown once placed; may be wider than the block (padX) */
.notfound .notfound__code { font-family: var(--font-display); font-weight: 800; font-size: clamp(5rem, 25vw, 14rem); line-height: 1; color: rgb(255 255 255 / 0.7); text-shadow: 0 0 40px rgb(0 0 0 / 0.35); }
/* Thank-you page: same block, wider text, so smaller and always one line. */
.notfound--thanks .notfound__code { font-size: clamp(3rem, 15vw, 11rem); white-space: nowrap; }
.notfound h1 { font-family: var(--font-display); font-weight: 800; font-size: var(--fs-2xl); }
.notfound p { margin-block: var(--space-4) var(--space-6); color: var(--c-muted); }

/* Digital business card (/vcard, vcard.js) */
.vcard { display: flex; flex-direction: column; align-items: center; max-width: calc(28rem + 2 * var(--gutter)); margin-bottom: var(--space-8); text-align: center; }
/* The about portrait (4:5) scaled up and offset inside the circle, so it
   shows the head and shoulders. Margins in % are of the circle's width. */
.vcard__photo {
  width: clamp(8rem, 30vw, 10rem);
  aspect-ratio: 1;
  overflow: hidden;
  border-radius: 50%;
  box-shadow: 0 0 0 3px var(--c-bg), 0 0 0 5px var(--c-accent);
}
.vcard__photo img { width: 172%; max-width: none; height: auto; margin: -9% 0 0 -36%; }
.vcard__name { margin-top: var(--space-5); font-family: var(--font-display); font-weight: 800; font-size: var(--fs-2xl); line-height: 1.05; letter-spacing: -0.01em; white-space: nowrap; }
/* The wave canvas sits behind the name inside its own stacking context;
   flow-root keeps the name's top margin inside the box it's placed against. */
.vcard__title { position: relative; isolation: isolate; display: flow-root; }
.vcard__wave { position: absolute; z-index: -1; max-width: none; pointer-events: none; visibility: hidden; } /* shown once placed (vcard.js) */
.vcard__role { margin-top: var(--space-3); font-size: var(--fs-xs); font-weight: 600; letter-spacing: 0.3em; text-transform: uppercase; color: var(--c-accent); }
.vcard__save { width: 100%; margin-top: var(--space-6); }
.vcard__save svg { width: 1.25rem; height: 1.25rem; }
.vcard__actions { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--space-3); width: 100%; margin-top: var(--space-6); padding: 0; list-style: none; }
.vcard__action {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.06em;
  color: var(--c-muted);
  text-decoration: none;
  transition: color var(--dur) ease;
}
.vcard__icon {
  display: grid;
  place-items: center;
  width: 3.5rem;
  height: 3.5rem;
  border: 1px solid var(--c-line);
  border-radius: 50%;
  background: rgb(255 255 255 / 0.06);
  color: var(--c-accent);
  transition: background-color var(--dur) ease, color var(--dur) ease, border-color var(--dur) ease;
}
.vcard__icon svg { width: 1.5rem; height: 1.5rem; }
.vcard__action:hover, .vcard__action:focus-visible { color: var(--c-text); }
.vcard__action:hover .vcard__icon, .vcard__action:focus-visible .vcard__icon { background: var(--c-accent); border-color: var(--c-accent); color: #000; }
.vcard__socials { justify-content: center; margin-top: var(--space-6); }
.vcard__share { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--space-3); margin-top: var(--space-3); visibility: hidden; }
.vcard__share.is-ready { visibility: visible; }
.vcard__share .social { background: none; cursor: pointer; }
.vcard__share .social svg { width: 1.25rem; height: 1.25rem; margin-inline: 0.25rem; }
/* Logo row under the name and title, as wide as the card. */
.vcard__clients { width: 100%; margin-top: var(--space-6); }
.vcard__clients .marquee__row { --logo-gap: 2rem; }
.vcard__clients .marquee__logo { height: 2.5rem; max-width: 10rem; }
/* QR code: black on white for scanners, in a native modal <dialog> */
.vcard__qr {
  width: min(22rem, calc(100% - 2 * var(--gutter)));
  padding: var(--space-6);
  border: 0;
  border-radius: var(--radius-md);
  background: #fff;
  color: #000;
  text-align: center;
}
.vcard__qr[open] { animation: vmodal-in 0.35s var(--ease-out); }
.vcard__qr::backdrop { background: rgb(0 0 0 / 0.85); }
.vcard__qr-code { width: 100%; height: auto; }
.vcard__qr-title { margin-top: var(--space-5); font-family: var(--font-display); font-weight: 800; font-size: var(--fs-lg); }
.vcard__qr-url { margin-top: var(--space-1); font-size: var(--fs-sm); color: rgb(0 0 0 / 0.6); }
.vcard__qr-close { margin-top: var(--space-5); }

/* ==========================================================================
   10. Motion preferences + print
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  html:focus-within { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    transition-delay: 0s !important;
  }
}

@media print {
  .site-header, .hero__media, .hero__overlay, .contact__media, .contact__overlay, canvas, video, .hero__clients, .form, .skip-link { display: none !important; }
  body { background: #fff; color: #000; }
  .hero__name { color: #000; text-shadow: none; }
  .cv, .tile { content-visibility: visible; }
}
