/* ==========================================================================
   Dualshade — dualshade.xyz — v5

   The label's claim is that two shades is all a screen needs. v5 stops
   asserting that in copy and makes the page do it: it opens in marble light,
   inverts mid-scroll, and ends in the void. Colour is spent exactly once, on
   the one product you can actually install.

   Nothing here is loaded from anyone else. The privacy page makes that claim
   on behalf of this file, so it has to stay true: fonts are local, the noise
   is an inline data URI, and there is no third-party anything.
   ========================================================================== */

/* ---------------------------------------------------------------- fonts */
@font-face {
  font-family: 'Schibsted Grotesk';
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url('/assets/fonts/schibsted-latin.woff2') format('woff2');
  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;
}
@font-face {
  font-family: 'Schibsted Grotesk';
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url('/assets/fonts/schibsted-latin-ext.woff2') format('woff2');
  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;
}

/* The voice face. Only ever italic, only ever on <em>: it takes the human
   half of a line while the grotesk states the fact. */
@font-face {
  font-family: 'Instrument Serif';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('/assets/fonts/instrument-serif-italic-latin.woff2') format('woff2');
  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;
}
@font-face {
  font-family: 'Instrument Serif';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('/assets/fonts/instrument-serif-italic-latin-ext.woff2') format('woff2');
  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;
}

/* --------------------------------------------------------------- tokens */
/* Everything that differs between the shades is a token, and both shades are
   declared as scopes rather than as a root plus overrides. A section says
   which shade it is in and inherits a complete, self-consistent palette —
   which is what makes a single component work on either side of the wipe. */
:root {
  --pad: clamp(20px, 5vw, 72px);
  --maxw: 1180px;
  --maxw-wide: 1440px;
  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);

  --step-eyebrow: 12px;
  --step-body: clamp(15.5px, 1.55vw, 17px);
  --step-lede: clamp(17.5px, 2vw, 22px);
  --step-h3: clamp(20px, 2.4vw, 27px);
  --step-h2: clamp(30px, 4.4vw, 54px);
  /* Large, but sized against the measure it is actually set to. An earlier
     pass ran this to 132px, which put one word on each line and pushed the
     lede out of the hero entirely. */
  --step-h1: clamp(38px, 5.6vw, 86px);
  --step-display: clamp(34px, 6.2vw, 88px);

  --grotesk: 'Schibsted Grotesk', -apple-system, BlinkMacSystemFont, 'Segoe UI',
    Helvetica, Arial, sans-serif;
  --serif: 'Instrument Serif', 'Iowan Old Style', Palatino, Georgia, serif;
}

[data-shade='light'] {
  /* Paper white, not #fff. Marble has to read as brighter than the page it
     sits on, or the statue looks like a hole rather than a lit object. */
  --bg: #f4f3f1;
  --bg-lift: #eceae7;
  --ink: #111114;
  --muted: rgba(17, 17, 20, 0.66);
  --faint: rgba(17, 17, 20, 0.44);
  --ghost: rgba(17, 17, 20, 0.12);
  --hair: rgba(17, 17, 20, 0.13);
  --hair-strong: rgba(17, 17, 20, 0.28);
  /* Text-weight accent is darkened to clear AA on paper white. The bright
     value would be about 2.1:1 here, which is a decorative orange, not a
     legible one. */
  --accent: #a8490b;
  --accent-mark: #d2570a;
  --shadow: 0 30px 80px rgba(17, 17, 20, 0.1);
  --sel-bg: #111114;
  --sel-ink: #f4f3f1;
}

[data-shade='dark'] {
  --bg: #0a0a0c;
  --bg-lift: #121215;
  --ink: #f6f6f7;
  --muted: rgba(246, 246, 247, 0.64);
  --faint: rgba(246, 246, 247, 0.42);
  --ghost: rgba(246, 246, 247, 0.14);
  --hair: rgba(246, 246, 247, 0.13);
  --hair-strong: rgba(246, 246, 247, 0.26);
  --accent: #ff7a18;
  --accent-mark: #ff7a18;
  --shadow: 0 30px 80px rgba(0, 0, 0, 0.6);
  --sel-bg: #ff7a18;
  --sel-ink: #0a0a0c;
}

/* ------------------------------------------------------------- baseline */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--grotesk);
  font-size: var(--step-body);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: clip;
  font-synthesis-weight: none;
}

/* Sections paint their own shade, so the wipe never reveals a mismatched
   body colour underneath. */
[data-shade] { background: var(--bg); color: var(--ink); }

a { color: inherit; text-decoration: none; }
img, video, svg, canvas { max-width: 100%; display: block; }
h1, h2, h3, h4, p, ul, ol, figure, blockquote { margin: 0; }
ul, ol { padding: 0; list-style: none; }
strong, b { font-weight: 700; }

/* The voice face, everywhere <em> appears. Optical size is a notch larger
   than the grotesk beside it, because a serif italic at the same nominal
   size reads noticeably smaller. */
em {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: 1.1em;
  letter-spacing: -0.005em;
}

::selection { background: var(--sel-bg); color: var(--sel-ink); }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 2px; }

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 999;
  padding: 12px 18px; background: var(--ink); color: var(--bg); font-weight: 700;
}
.skip:focus { left: 12px; top: 12px; }

.sr-only {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.wrap { max-width: var(--maxw); margin-inline: auto; padding-inline: var(--pad); }
.wrap-narrow { max-width: 760px; margin-inline: auto; padding-inline: var(--pad); }

.eyebrow {
  font-size: var(--step-eyebrow); font-weight: 700; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--faint);
}

h1, h2 { letter-spacing: -0.03em; line-height: 1.02; font-weight: 700; }
h1 { font-size: var(--step-h1); }
h2 { font-size: var(--step-h2); }
h1 em, h2 em { letter-spacing: -0.015em; }

.lede {
  font-size: var(--step-lede); line-height: 1.5; color: var(--muted);
  max-width: 46ch; margin-top: 22px;
}

/* --------------------------------------------------- the marble mask */
/* The source photographs are white marble on near-black. That is the dark
   shade already finished — and, run through a luminance mask, it is also the
   light shade: the black plate drops to transparent and the statue is left
   floating on paper white. One asset, both shades, no second grade.

   Chrome shipped mask-mode in 120 and Safari in 15.4. Where it is missing
   the figure simply keeps its plate: a duller composition, not a broken one. */

/* ---------------------------------------------------------------- header */
.head {
  position: sticky; top: 0; z-index: 40;
  background: color-mix(in srgb, var(--bg) 72%, transparent);
  backdrop-filter: blur(18px) saturate(118%);
  -webkit-backdrop-filter: blur(18px) saturate(118%);
  border-bottom: 1px solid transparent;
  transition: border-color 0.35s var(--ease), background-color 0.5s var(--ease),
    color 0.5s var(--ease);
}
.head.stuck { border-bottom-color: var(--hair); }
.head-in {
  display: flex; align-items: center; justify-content: space-between;
  gap: 18px; padding-block: 15px;
}
.brand { display: flex; align-items: center; gap: 11px; }
.wordmark { font-size: 15px; font-weight: 600; letter-spacing: -0.012em; }
.head-right { display: flex; align-items: center; gap: clamp(12px, 2.4vw, 26px); }
.nav { display: flex; gap: clamp(14px, 2.4vw, 26px); font-size: 14px; color: var(--muted); }
.nav a { transition: color 0.18s var(--ease); }
.nav a:hover, .nav a[aria-current='page'] { color: var(--ink); }

/* ---------- the mark: a filled circle and an outlined one, offset ---------- */
.mark { position: relative; flex: 0 0 auto; display: block; }
.mark i { position: absolute; inset: 0; border-radius: 50%; display: block; }
.mark .solid { background: currentColor; }
.mark .ring { border: 1.5px solid currentColor; transform: translate(var(--sx), var(--sy)); }
.mark.sm { --d: 20px; --sx: 5.4px; --sy: 5.4px; width: 26px; height: 26px; }
.mark.sm i { width: var(--d); height: var(--d); inset: 0 auto auto 0; }
.mark.sm .ring { border-width: 1.25px; }
.mark:not(.sm) { --d: 92px; --sx: 26px; --sy: 26px; width: 118px; height: 118px; }
.mark:not(.sm) i { width: var(--d); height: var(--d); inset: 0 auto auto 0; }

/* ---------------------------------------------------- language switcher */
.lang { position: relative; }
.lang-btn {
  display: inline-flex; align-items: center; gap: 7px;
  min-height: 34px; padding: 0 10px;
  background: transparent; border: 1px solid var(--hair-strong); border-radius: 2px;
  color: var(--muted); font: inherit; font-size: 13px; cursor: pointer;
  transition: color 0.18s var(--ease), border-color 0.18s var(--ease);
}
.lang-btn:hover { color: var(--ink); border-color: var(--ink); }
.lang-btn svg { transition: transform 0.2s var(--ease); }
.lang-btn[aria-expanded='true'] svg:last-child { transform: rotate(180deg); }
.lang-menu {
  position: absolute; right: 0; top: calc(100% + 8px); z-index: 50;
  min-width: 190px; padding: 6px;
  background: var(--bg-lift); border: 1px solid var(--hair-strong); border-radius: 4px;
  box-shadow: var(--shadow);
  display: grid; gap: 1px;
}
/* `display:grid` above outranks the UA's [hidden] rule, so say it again. */
.lang-menu[hidden] { display: none; }
.lang-menu a {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 8px 10px; font-size: 14px; color: var(--muted); border-radius: 2px;
  transition: background 0.14s var(--ease), color 0.14s var(--ease);
}
.lang-menu a:hover { background: var(--ghost); color: var(--ink); }
.lang-menu a[aria-current='true'] { color: var(--ink); }
.lang-menu a[aria-current='true']::after {
  content: ''; width: 6px; height: 6px; border-radius: 50%; background: var(--accent-mark);
}
.lang-menu .code {
  font-size: 11px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--faint);
}

/* ================================================================== 1 hero */
.hero {
  position: relative; isolation: isolate;
  min-height: min(100svh, 1000px);
  display: flex; align-items: center;
  padding-block: clamp(80px, 14vh, 150px) clamp(90px, 16vh, 170px);
  overflow: hidden;
}

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

/* The canvas is the real hero image when WebGL is available. It draws the
   statue and the fog; a DOM glass card sits over the face and samples that
   canvas as its backdrop. */
.hero-canvas {
  position: absolute; inset: 0; width: 100%; height: 100%;
  opacity: 0; transition: opacity 1.1s var(--ease-out);
}
.hero-canvas.on { opacity: 1; }

/* The DOM fallback, and the same file the canvas samples. It is visible until
   the canvas reports ready, so the hero is never empty and never waits on
   JavaScript to show a picture. */
.hero-plate {
  position: absolute; inset: 0;
  -webkit-mask-image: url('/assets/img/hero-sculpture.jpg');
  mask-image: url('/assets/img/hero-sculpture.jpg');
  -webkit-mask-size: cover; mask-size: cover;
  -webkit-mask-position: 16% 46%; mask-position: 16% 46%;
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
  mask-mode: luminance;
  transition: opacity 0.8s var(--ease);
  animation: plate-drift 32s var(--ease) infinite alternate;
}
.hero-plate img {
  width: 100%; height: 100%; object-fit: cover; object-position: 16% 46%;
  /* Lit for a bright page. The source is graded for a black background, so
     without the lift the marble lands as mid-grey on paper. */
  filter: grayscale(1) brightness(1.24) contrast(1.06);
}
.hero-canvas.on ~ .hero-plate { opacity: 0; animation: none; }

@keyframes plate-drift {
  from { transform: scale(1.03); }
  to { transform: scale(1.07) translate3d(-1.4%, 1.1%, 0); }
}

/* Fog. The canvas has its own domain-warped mist; these sprites are the
   fallback when WebGL is off, and they are the live mist on every beat that
   has no canvas. Mix-blend-screen: black in the crop drops out. */
.haze {
  position: absolute;
  pointer-events: none;
  z-index: 1;
  -webkit-mask-image: radial-gradient(closest-side, #000 38%, transparent 74%);
  mask-image: radial-gradient(closest-side, #000 38%, transparent 74%);
}
[data-shade='light'] .haze {
  mix-blend-mode: multiply;
  filter: invert(1);
  opacity: 0.32;
}
[data-shade='dark'] .haze,
.haze-void {
  mix-blend-mode: screen;
  filter: brightness(2.1) contrast(1.15);
  opacity: 0.9;
}
.haze picture, .haze img {
  width: 100%; height: 100%;
  max-width: none;
  object-fit: contain;
}
.haze-paper {
  width: min(96vw, 1040px);
  height: min(54vw, 580px);
  right: -14%;
  bottom: -10%;
  animation: haze-drift-a 44s var(--ease) infinite alternate;
}
.haze-void {
  width: min(90vw, 980px);
  height: min(50vw, 540px);
  left: -16%;
  bottom: -12%;
  opacity: 0.85;
  animation: haze-drift-b 52s var(--ease) infinite alternate;
}
.hero-stage .haze:nth-child(4) {
  left: -18%;
  right: auto;
  bottom: 4%;
  transform: scaleX(-1);
  animation-name: haze-drift-b;
  animation-duration: 56s;
  opacity: 0.55;
}
.hero-canvas.on ~ .haze { opacity: 0; }
.hero-stage .hero-canvas.on ~ .haze { opacity: 0; }

@keyframes haze-drift-a {
  from { translate: 0 0; }
  to { translate: -5vw 3vh; }
}
@keyframes haze-drift-b {
  from { translate: 0 0; }
  to { translate: 6vw -4vh; }
}
@keyframes pane-drift {
  from { translate: 0 0; }
  to { translate: 10px -8px; }
}

.hero-grain {
  position: absolute; inset: -20% -10%; pointer-events: none;
  opacity: 0.3; mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)' opacity='0.42'/%3E%3C/svg%3E");
}

.hero-in {
  position: relative; width: 100%;
  display: flex; justify-content: flex-end;
}
/* Not `ch`: this element inherits the body font size, so a ch measure here
   would be computed against 17px while the h1 inside it is set at 80px —
   which collapses the column to about one word per line. Anywhere a wrapper
   constrains display type, the measure has to be absolute. */
.hero-copy { max-width: min(640px, 48vw); }
.hero .lede { max-width: 42ch; }

.hero-cta { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 34px; }

.scrollcue {
  position: absolute; left: 50%; bottom: clamp(24px, 5vh, 46px);
  transform: translateX(-50%);
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 11px; font-weight: 700; letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--faint);
}
.scrollcue svg { animation: nudge 2.6s var(--ease) infinite; }
@keyframes nudge {
  0%, 62%, 100% { transform: translateY(0); opacity: 0.6; }
  80% { transform: translateY(4px); opacity: 1; }
}

/* ---------------------------------------------------------------- buttons */
.btn {
  display: inline-flex; align-items: center; gap: 9px;
  min-height: 46px; padding: 0 20px;
  border-radius: 2px; border: 1px solid transparent;
  background: var(--ink); color: var(--bg);
  font-size: 14px; font-weight: 600; letter-spacing: -0.005em;
  position: relative; overflow: hidden;
  transition: transform 0.3s var(--ease-out), box-shadow 0.3s var(--ease);
}
.btn:hover { transform: translateY(-2px); box-shadow: var(--shadow); }
.btn:active { transform: translateY(0); }
/* The refraction sweep: a soft highlight that follows the cursor across the
   face of the button. Position arrives from JS as two custom properties. */
.btn::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(
    120px circle at var(--mx, 50%) var(--my, 50%),
    color-mix(in srgb, var(--bg) 34%, transparent),
    transparent 62%
  );
  opacity: 0; transition: opacity 0.3s var(--ease);
}
.btn:hover::after { opacity: 1; }

.btn-ghost {
  background: transparent; color: var(--ink); border-color: var(--hair-strong);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
}
.btn-ghost:hover { border-color: var(--ink); }
.btn-ghost::after {
  background: radial-gradient(
    120px circle at var(--mx, 50%) var(--my, 50%),
    color-mix(in srgb, var(--ink) 10%, transparent),
    transparent 62%
  );
}

.textlink {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 14px; font-weight: 600; color: var(--ink);
  border-bottom: 1px solid var(--hair-strong); padding-bottom: 2px;
  transition: border-color 0.2s var(--ease), gap 0.2s var(--ease);
}
.textlink:hover { border-color: var(--ink); gap: 11px; }

/* ================================================================ ticker */
.ticker {
  position: relative; overflow: hidden;
  border-block: 1px solid var(--hair);
  padding-block: 13px;
}
.ticker-track {
  display: flex; align-items: center; gap: 26px; width: max-content;
  animation: ticker 54s linear infinite;
}
.ticker:hover .ticker-track { animation-play-state: paused; }
@keyframes ticker { to { transform: translate3d(-50%, 0, 0); } }
.tick-item {
  font-size: 11.5px; font-weight: 700; letter-spacing: 0.2em;
  text-transform: uppercase; color: var(--faint); white-space: nowrap;
}
.tick-sep {
  width: 5px; height: 5px; border-radius: 50%;
  background: var(--ghost); flex: 0 0 auto;
}

/* ---------------------------------------------------------- glass tiles */
/* Frost, a rim and a hairline. Empty shards (the card on the hero face, the
   inversion chip) get an SVG displacement map as backdrop-filter so Chromium
   actually bends the marble; everyone else keeps the frost. Copy tiles never
   get the lens — type stays readable. */
.glass-svg {
  position: absolute; width: 0; height: 0; overflow: hidden;
}
.glass {
  position: relative; overflow: hidden;
  border-radius: 12px;
  background: rgba(244, 243, 241, 0.22);
  backdrop-filter: blur(18px) saturate(140%);
  -webkit-backdrop-filter: blur(18px) saturate(140%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.62),
    inset 0 0 0 1px rgba(17, 17, 20, 0.12),
    0 12px 40px rgba(17, 17, 20, 0.07);
}
.glass.glass-svg-on {
  background: rgba(244, 243, 241, 0.05);
  backdrop-filter: var(--glass-filter) saturate(1.22);
  -webkit-backdrop-filter: var(--glass-filter) saturate(1.22);
}
.glass::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(
    140px circle at var(--mx, 18%) var(--my, 12%),
    rgba(255, 255, 255, 0.28),
    transparent 58%
  );
  opacity: 0.55;
}
[data-shade='dark'] .glass {
  background: rgba(10, 10, 12, 0.28);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.16),
    inset 0 0 0 1px rgba(246, 246, 247, 0.14),
    0 12px 40px rgba(0, 0, 0, 0.35);
}
[data-shade='dark'] .glass.glass-svg-on {
  background: rgba(10, 10, 12, 0.06);
}

/* One tilted card over the bust's face — the Yunicorn move, on Dualshade's
   statue, kept off the headline. */
.glass.hero-face-glass {
  left: 10%;
  top: 14%;
  width: min(300px, 30vw);
  height: min(360px, 40vw);
  rotate: 8deg;
  z-index: 2;
  border-radius: 6px;
  background: rgba(244, 243, 241, 0.08);
  backdrop-filter: blur(10px) saturate(160%);
  -webkit-backdrop-filter: blur(10px) saturate(160%);
}
.glass.hero-face-glass.glass-svg-on {
  background: rgba(244, 243, 241, 0.04);
  backdrop-filter: var(--glass-filter) saturate(1.22);
  -webkit-backdrop-filter: var(--glass-filter) saturate(1.22);
}

/* ================================================================== bands */
.band { position: relative; padding-block: clamp(88px, 14vw, 190px); }
.band-work { padding-top: clamp(70px, 10vw, 130px); }

/* Absolute for the same reason as .hero-copy: the h2 inside is far larger
   than the font size a ch measure would be resolved against. */
.sec-head { max-width: min(660px, 62vw); margin-bottom: clamp(34px, 5vw, 60px); }
.sec-head .eyebrow { margin-bottom: 18px; }
.sec-body { max-width: 62ch; color: var(--muted); display: grid; gap: 20px; }

/* ================================================================= 2 about */
.about { position: relative; }
.about-intro { padding-top: clamp(64px, 10vw, 130px); padding-bottom: clamp(8px, 2vw, 24px); }
.about-intro .sec-head { margin-bottom: 18px; max-width: min(660px, 100%); }
.about-intro .lede { margin-top: 0; }

.about-stage {
  position: relative;
  min-height: min(88svh, 920px);
  overflow: hidden;
}

/* Fade lives on the parent so it does not travel with the figure. The figure
   itself is the same luminance key as the hero: black plate drops out. */
.about-fade {
  position: absolute; inset: 0;
  -webkit-mask-image: linear-gradient(to right, #000 46%, transparent 88%);
  mask-image: linear-gradient(to right, #000 46%, transparent 88%);
}
.about-fig {
  position: absolute; inset: 0;
  -webkit-mask-image: url('/assets/img/sculpture-hand.jpg');
  mask-image: url('/assets/img/sculpture-hand.jpg');
  -webkit-mask-size: cover; mask-size: cover;
  -webkit-mask-position: 50% 38%; mask-position: 50% 38%;
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
  mask-mode: luminance;
}
.about-fig img {
  width: 100%; height: 100%; object-fit: cover; object-position: 50% 38%;
  filter: grayscale(1) brightness(1.18) contrast(1.08);
}

.about-stage .haze-paper {
  left: 8%;
  right: auto;
  bottom: -6%;
  z-index: 1;
}

.tiles {
  position: absolute;
  left: 12%;
  right: auto;
  width: min(440px, 48vw);
  max-width: 460px;
  top: 44%;
  transform: translateY(-50%);
  z-index: 2;
  display: grid;
  gap: 16px;
}
.tile {
  --tile-rot: 0deg;
  display: flex; align-items: flex-start; gap: 14px;
  padding: 18px 22px 18px 18px;
  opacity: var(--tile-fade, 1);
  transition: opacity 0.45s var(--ease);
  animation: pane-drift 28s var(--ease) infinite alternate;
}
.tile .dot, .tile p { position: relative; z-index: 1; }
.tile .dot { margin-top: 9px; }
.tile p {
  font-size: clamp(18px, 2.1vw, 26px);
  font-weight: 600;
  letter-spacing: -0.025em;
  line-height: 1.22;
}
.tile em { font-size: 1.12em; }
.tile:nth-child(1) { --tile-fade: 1; --tile-rot: -8deg; }
.tile:nth-child(2) { --tile-fade: 0.78; --tile-rot: 5deg; margin-left: 36px; animation-duration: 34s; }
.tile:nth-child(3) { --tile-fade: 0.5; --tile-rot: -3.5deg; margin-left: 14px; animation-duration: 40s; }
.tile.rev {
  transform: translate3d(0, 18px, 0) rotate(var(--tile-rot));
}
.tile.rev.in { opacity: var(--tile-fade, 1); transform: rotate(var(--tile-rot)); }
.tile:hover, .tile:focus-within,
.tile.rev.in:hover, .tile.rev.in:focus-within { opacity: 1; }

/* ============================================================ 3 inversion */
/* The hinge of the page. Two complete copies of the same scene, one in each
   shade, stacked. The dark copy is clipped by a scroll-driven inset, so the
   edge travels up through the statue and the sentence together and both turn
   over as it passes. Clipping a composited layer is cheap; repainting the
   colour of two hundred glyphs every frame would not be. */
.shade {
  position: relative;
  height: 260vh; /* the travel the wipe plays out over */
}
.shade-stage {
  position: sticky; top: 0; height: 100svh; overflow: hidden;
}
.shade-face {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; justify-content: center;
  background: var(--bg); color: var(--ink);
  /* Each face is its own stacking context so the light copy cannot paint
     over the dark one. Without this, z-index on .shade-copy escapes and the
     ink stays black after the wipe has already turned the plate to void. */
  isolation: isolate;
  z-index: 0;
}
/* --wipe runs 100% → 0% across the section. At 100% the dark face is clipped
   away entirely; at 0% it has covered the light one. */
.shade-dark {
  z-index: 1;
  clip-path: inset(var(--wipe, 100%) 0 0 0);
  will-change: clip-path;
}
.shade-edge {
  position: absolute; left: 0; right: 0; top: var(--wipe, 100%);
  height: 1px;
  background: linear-gradient(
    to right, transparent, rgba(255, 122, 24, 0.5) 18%, rgba(255, 122, 24, 0.9) 50%,
    rgba(255, 122, 24, 0.5) 82%, transparent
  );
  box-shadow: 0 0 24px 2px rgba(255, 122, 24, 0.26);
  opacity: var(--edge-on, 0);
  transition: opacity 0.4s var(--ease);
}

/* The light face opens against the paper the study faded into, so its figure
   is eased in from the top rather than starting at full strength on the
   section boundary. Sits above the figure and below the copy. */
.shade-light::before {
  content: ''; position: absolute; inset: 0 0 auto 0; height: 24%;
  background: linear-gradient(to bottom, var(--bg), transparent);
  z-index: 1; pointer-events: none;
}
.shade-copy {
  position: relative;
  z-index: 2;
  text-align: center;
}

.shade-fig { position: absolute; inset: 0; pointer-events: none; opacity: 0.92; }
.shade-fig img {
  width: 100%; height: 100%; object-fit: cover; object-position: 22% 48%;
  filter: grayscale(1) contrast(1.16);
  transform: scale(var(--shade-scale, 1.06));
}
/* Light face: mask the plate away so the head floats on paper. */
.shade-light .shade-fig {
  -webkit-mask-image: url('/assets/img/sculpture-face.jpg');
  mask-image: url('/assets/img/sculpture-face.jpg');
  -webkit-mask-size: cover; mask-size: cover;
  -webkit-mask-position: 22% 48%; mask-position: 22% 48%;
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
  mask-mode: luminance;
}
/* Dark face: the photograph as shot, which is already the dark shade. */
.shade-dark .shade-fig img { filter: grayscale(1) contrast(1.05) brightness(0.92); }
.shade-dark .haze { z-index: 1; }

/* Empty chrome shard on the sticky stage so it survives the wipe. */
.shard {
  position: absolute;
  display: block;
  pointer-events: none;
  z-index: 3;
  animation: pane-drift 32s var(--ease) infinite alternate;
}
.shade-shard {
  left: 16%;
  top: 30%;
  width: min(250px, 28vw);
  height: min(168px, 20vw);
  rotate: 11deg;
  z-index: 4;
}

.shade-copy .eyebrow { margin-bottom: 20px; }
.shade-h {
  font-size: var(--step-display);
  line-height: 0.96; letter-spacing: -0.04em; font-weight: 700;
  text-wrap: balance;
  color: var(--ink);
}
.shade-body {
  margin: 28px auto 0; max-width: 48ch; color: var(--muted);
  font-size: var(--step-lede); line-height: 1.5;
}

/* =================================================================== rows */
.rows { display: grid; gap: 0; border-top: 1px solid var(--hair); }
.row {
  display: grid; grid-template-columns: auto 1fr; gap: clamp(16px, 3vw, 34px);
  padding-block: clamp(34px, 5vw, 58px);
  border-bottom: 1px solid var(--hair);
  transition: background-color 0.4s var(--ease);
}
.row:hover { background: color-mix(in srgb, var(--ink) 3%, transparent); }
.dot { width: 13px; height: 13px; border-radius: 50%; margin-top: 12px; flex: 0 0 auto; }
.dot.filled { background: var(--accent-mark); }
.dot.outline { border: 1.5px solid var(--hair-strong); }
.row-head { display: flex; align-items: baseline; flex-wrap: wrap; gap: 6px 16px; }
.row-name { font-size: var(--step-h3); font-weight: 700; letter-spacing: -0.02em; }
.row-kicker { font-size: 13.5px; color: var(--faint); }
.row-desc { margin-top: 14px; max-width: 58ch; color: var(--muted); }
.row-foot { display: flex; flex-wrap: wrap; align-items: center; gap: 16px; margin-top: 26px; }
.tag {
  font-size: 11.5px; font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--faint); border: 1px solid var(--hair); border-radius: 2px; padding: 5px 10px;
}
.note { margin-top: 30px; max-width: 62ch; font-size: 14px; color: var(--faint); }

/* ================================================================== rules */
.grid { display: grid; gap: 1px; background: var(--hair); border-block: 1px solid var(--hair); }
.grid-2 { grid-template-columns: repeat(2, 1fr); }
.rule { background: var(--bg); padding: clamp(26px, 3.4vw, 44px); }
.card-num {
  display: block; font-size: 11.5px; font-weight: 700; letter-spacing: 0.18em;
  color: var(--faint); margin-bottom: 20px;
}
.card-h { font-size: var(--step-h3); font-weight: 700; letter-spacing: -0.02em; }
.card-p { margin-top: 12px; color: var(--muted); max-width: 44ch; }

/* ================================================================ closing */
.closing {
  position: relative; overflow: hidden;
  padding-block: clamp(120px, 20vw, 240px);
  text-align: center;
}
.closing-fig { position: absolute; inset: -10% 0 -10% 0; z-index: 0; }
.closing-fig img {
  width: 100%; height: 100%; object-fit: cover; object-position: 78% 48%;
  filter: grayscale(1) contrast(1.08) brightness(0.78);
}
.closing-veil {
  position: absolute; inset: 0;
  background:
    radial-gradient(70% 62% at 74% 48%, rgba(10, 10, 12, 0.12) 0%, rgba(10, 10, 12, 0.62) 58%, #0a0a0c 100%),
    linear-gradient(to right, #0a0a0c 0%, rgba(10, 10, 12, 0.22) 38%, rgba(10, 10, 12, 0.5) 100%);
}
.closing .haze { z-index: 1; }
.closing-shard-a {
  right: 16%;
  top: 26%;
  width: min(210px, 24vw);
  height: min(148px, 17vw);
  rotate: -9deg;
}
.closing-shard-b {
  right: 30%;
  bottom: 20%;
  width: min(168px, 18vw);
  height: min(112px, 13vw);
  rotate: 13deg;
  animation-duration: 40s;
}
.closing-in { position: relative; z-index: 2; display: grid; justify-items: center; }
.closing-mark { color: var(--ghost); margin-bottom: clamp(34px, 6vw, 70px); }
.closing .eyebrow { margin-bottom: 18px; }
.closing .sec-body { margin-top: 22px; justify-items: center; text-align: center; }
.contact-mail {
  margin-top: clamp(34px, 5vw, 58px);
  display: inline-flex; align-items: center; gap: 10px;
  font-size: clamp(19px, 3vw, 34px); font-weight: 700; letter-spacing: -0.025em;
  border-bottom: 1px solid var(--hair-strong); padding-bottom: 6px;
  transition: border-color 0.25s var(--ease), gap 0.25s var(--ease), color 0.25s var(--ease);
}
.contact-mail:hover { border-color: var(--accent); color: var(--accent); gap: 16px; }

/* =========================================== inner pages (carried from v4) */
.page-hero { position: relative; padding-block: clamp(80px, 13vw, 150px) clamp(40px, 6vw, 70px); }
.page-motif, .motif { position: absolute; pointer-events: none; color: var(--ghost); }
.page-motif { right: clamp(-30px, 2vw, 40px); top: 16%; }
.motif-right { right: clamp(-40px, 1vw, 30px); top: 12%; }
.band-top { border-top: 1px solid var(--hair); }
.band-lift { background: var(--bg-lift); }
.status {
  display: inline-flex; align-items: center; gap: 12px; margin-top: 30px;
  padding: 13px 18px; border: 1px solid var(--hair); border-radius: 2px;
  color: var(--muted); font-size: 14.5px; max-width: 62ch;
}
.checks { display: grid; gap: 12px; margin-top: 26px; }
.checks li {
  display: flex; gap: 12px; align-items: flex-start; color: var(--muted); font-size: 15px;
}
.checks li::before {
  content: ''; flex: 0 0 auto; width: 7px; height: 7px; margin-top: 9px;
  border-radius: 50%; background: var(--hair-strong);
}

/* privacy documents */
.doc { padding-bottom: clamp(80px, 12vw, 150px); }
.doc-head { max-width: 820px; }
.doc-lead { margin-top: 24px; font-size: var(--step-lede); line-height: 1.5; color: var(--muted); }
.doc-lead strong { color: var(--ink); }
.doc-meta {
  display: flex; flex-wrap: wrap; gap: 8px 26px; margin-top: 30px;
  font-size: 13px; color: var(--faint);
}
.doc-layout { display: grid; grid-template-columns: 220px 1fr; gap: clamp(30px, 6vw, 80px); }
.toc { position: sticky; top: 90px; align-self: start; }
.toc-label { margin-bottom: 16px; }
.toc ol { display: grid; gap: 9px; }
.toc a { font-size: 13px; color: var(--faint); transition: color 0.18s var(--ease); }
.toc a:hover, .toc a.on { color: var(--ink); }
.clause { padding-block: clamp(28px, 4vw, 46px); border-top: 1px solid var(--hair); }
.clause:first-child { border-top: 0; padding-top: 0; }
.clause h2 {
  font-size: var(--step-h3); font-weight: 700; letter-spacing: -0.02em;
  display: flex; gap: 14px; align-items: baseline;
}
.clause h2 .n { font-size: 12px; color: var(--faint); letter-spacing: 0.16em; }
.clause p { margin-top: 14px; color: var(--muted); max-width: 68ch; }
.clause p.plain strong { color: var(--ink); }
.clause ul { margin-top: 16px; display: grid; gap: 10px; }
.clause li { display: flex; gap: 12px; color: var(--muted); max-width: 68ch; }
.clause li::before {
  content: ''; flex: 0 0 auto; width: 6px; height: 6px; margin-top: 10px;
  border-radius: 50%; background: var(--hair-strong);
}
.clause a { border-bottom: 1px solid var(--hair-strong); }

/* ================================================================= footer */
.foot { border-top: 1px solid var(--hair); padding-block: clamp(48px, 7vw, 82px); }
.foot-home { overflow: hidden; padding-top: 0; }
.foot-word {
  position: relative;
  overflow: hidden;
  margin: 0 0 clamp(8px, 1.5vw, 20px);
  line-height: 0.72;
  pointer-events: none;
}
.foot-word-in {
  display: block;
  font-size: clamp(64px, 17.5vw, 268px);
  font-weight: 800;
  letter-spacing: -0.07em;
  text-align: center;
  color: var(--ink);
  transform: scale(1.06);
  filter: url(#word-distort);
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 20%, #000 72%, transparent 100%);
  mask-image: linear-gradient(to bottom, transparent 0%, #000 20%, #000 72%, transparent 100%);
  opacity: 0.9;
}
.foot-cols { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(26px, 4vw, 50px); }
.foot h3 {
  font-size: var(--step-eyebrow); font-weight: 700; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--faint); margin-bottom: 16px;
}
.foot ul { display: grid; gap: 10px; }
.foot a { font-size: 14.5px; color: var(--muted); transition: color 0.18s var(--ease); }
.foot a:hover { color: var(--ink); }
.foot-base {
  display: flex; flex-wrap: wrap; justify-content: space-between; gap: 12px 30px;
  margin-top: clamp(40px, 6vw, 70px); padding-top: 26px; border-top: 1px solid var(--hair);
  font-size: 12.5px; color: var(--faint);
}

/* ================================================================ reveals */
.rev { opacity: 0; transform: translate3d(0, 18px, 0); }
.rev.in {
  opacity: 1; transform: none;
  transition: opacity 0.85s var(--ease-out), transform 0.85s var(--ease-out);
}

/* Word-level clip reveal on display type. JS wraps each word in .w > .wi;
   with no JS the heading is simply visible, which is the correct failure. */
.split .w { display: inline-block; overflow: hidden; vertical-align: top; }
.split .wi {
  display: inline-block;
  transform: translate3d(0, 105%, 0);
  transition: transform 0.9s var(--ease-out);
  transition-delay: calc(var(--i, 0) * 42ms);
}
.split.in .wi { transform: none; }

/* Tiles keep their tilt after the reveal, which would otherwise zero transform. */
.tile.rev.in {
  opacity: var(--tile-fade, 1);
  transform: rotate(var(--tile-rot, 0deg));
}

/* ====================================================== light resources */
/* `lite` is chosen in the head before this stylesheet paints. It is not a
   separate visual design: it is the same two-shade composition with one
   raster layer at a time and no continuously composited surfaces. */
html.lite .head {
  --bg: #0a0a0c;
  --bg-lift: #121215;
  --ink: #f6f6f7;
  --muted: rgba(246, 246, 247, 0.68);
  --faint: rgba(246, 246, 247, 0.46);
  --ghost: rgba(246, 246, 247, 0.14);
  --hair: rgba(246, 246, 247, 0.14);
  --hair-strong: rgba(246, 246, 247, 0.28);
  --accent: #ff7a18;
  --accent-mark: #ff7a18;
  background: rgba(10, 10, 12, 0.96);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}

html.lite .hero-canvas,
html.lite .hero-face-glass,
html.lite .hero-grain,
html.lite .haze,
html.lite .shard,
html.lite .shade-edge { display: none; }

html.lite .hero-plate,
html.lite .ticker-track,
html.lite .tile,
html.lite .scrollcue svg { animation: none; }

html.lite .hero {
  --bg: #0a0a0c;
  --bg-lift: #121215;
  --ink: #f6f6f7;
  --muted: rgba(246, 246, 247, 0.72);
  --faint: rgba(246, 246, 247, 0.5);
  --ghost: rgba(246, 246, 247, 0.14);
  --hair: rgba(246, 246, 247, 0.14);
  --hair-strong: rgba(246, 246, 247, 0.3);
  --accent: #ff7a18;
  --accent-mark: #ff7a18;
  background: var(--bg);
}
html.lite .hero-plate {
  transform: none;
  -webkit-mask-image: none;
  mask-image: none;
}
html.lite .hero-plate img {
  filter: grayscale(1) contrast(1.06) brightness(0.78);
}
html.lite .ticker-track { transform: none; }
html.lite .about-stage { min-height: auto; padding-block: clamp(24px, 6vw, 56px); }
html.lite .about-fade { display: none; }
html.lite .tiles {
  position: relative;
  inset: auto;
  width: auto;
  max-width: var(--maxw);
  margin: 0 auto;
  padding-inline: var(--pad);
  transform: none;
}
html.lite .tile,
html.lite .glass {
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  background: rgba(17, 17, 20, 0.055);
  box-shadow: inset 0 0 0 1px var(--hair);
}
html.lite .tile { opacity: var(--tile-fade, 1); }
html.lite .btn-ghost {
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  background: color-mix(in srgb, var(--bg) 90%, transparent);
}

/* Use the accessible face as the one static dark scene. The decorative dark
   duplicate stays unloaded, and the mask is unnecessary because the source
   photograph already carries its black plate. */
html.lite .shade { height: auto; }
html.lite .shade-stage { position: static; height: auto; }
html.lite .shade-face {
  position: relative;
  inset: auto;
  min-height: min(78svh, 760px);
}
html.lite .shade-light {
  --bg: #0a0a0c;
  --bg-lift: #121215;
  --ink: #f6f6f7;
  --muted: rgba(246, 246, 247, 0.68);
  --faint: rgba(246, 246, 247, 0.46);
  --ghost: rgba(246, 246, 247, 0.14);
  --hair: rgba(246, 246, 247, 0.14);
  --hair-strong: rgba(246, 246, 247, 0.28);
  --accent: #ff7a18;
  --accent-mark: #ff7a18;
  --shadow: 0 16px 40px rgba(0, 0, 0, 0.35);
}
html.lite .shade-dark { display: none; }
html.lite .shade-light .shade-fig {
  -webkit-mask-image: none;
  mask-image: none;
}
html.lite .shade-fig img { transform: none; }
html.lite .shade-dark { will-change: auto; }

html.lite .rev,
html.lite .rev.in { opacity: 1; transform: none; transition: none; }
html.lite .split .wi { transform: none; transition: none; }
html.lite [data-px] { transform: none !important; }
html.lite .foot-word-in { filter: none; }

/* Skip layout and paint work for the large sections until they approach the
   viewport. Intrinsic sizes keep the scrollbar stable while they are skipped. */
html.lite .band,
html.lite .closing,
html.lite .foot {
  content-visibility: auto;
  contain-intrinsic-size: auto 760px;
}

/* ============================================================ responsive */
@media (max-width: 900px) {
  .doc-layout { grid-template-columns: 1fr; }
  .toc { position: static; }
  .grid-2 { grid-template-columns: 1fr; }
  .foot-cols { grid-template-columns: 1fr 1fr; }
  .about-stage { min-height: auto; }
  .about-fade {
    position: relative; height: 62vw; min-height: 320px;
    -webkit-mask-image: linear-gradient(to bottom, #000 52%, transparent 100%);
    mask-image: linear-gradient(to bottom, #000 52%, transparent 100%);
  }
  .tiles {
    position: relative; left: auto; right: auto; top: auto; transform: none;
    width: auto; max-width: none; margin: -132px var(--pad) 40px;
  }
  .tile:nth-child(2), .tile:nth-child(3) { margin-left: 0; }
  .tile:nth-child(3) { --tile-fade: 0.62; }
  .shade-shard { left: 8%; top: 22%; width: min(180px, 42vw); height: min(120px, 28vw); }
  .closing-shard-a, .closing-shard-b { display: none; }
}

@media (max-width: 720px) {
  /* Mobile opens on the photograph as shot: a black plate with white type.
     Safari does not consistently honour mask-mode:luminance, so this is a
     deliberate fallback rather than a failed imitation of the paper scene.
     Once WebGL draws a frame, .glass-ready restores the light palette. */
  .page-home .head {
    --bg: #0a0a0c;
    --bg-lift: #121215;
    --ink: #f6f6f7;
    --muted: rgba(246, 246, 247, 0.68);
    --faint: rgba(246, 246, 247, 0.46);
    --ghost: rgba(246, 246, 247, 0.14);
    --hair: rgba(246, 246, 247, 0.14);
    --hair-strong: rgba(246, 246, 247, 0.28);
    --accent: #ff7a18;
    --accent-mark: #ff7a18;
    background: rgba(10, 10, 12, 0.96);
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
  .hero {
    --bg: #0a0a0c;
    --bg-lift: #121215;
    --ink: #f6f6f7;
    --muted: rgba(246, 246, 247, 0.72);
    --faint: rgba(246, 246, 247, 0.5);
    --ghost: rgba(246, 246, 247, 0.14);
    --hair: rgba(246, 246, 247, 0.14);
    --hair-strong: rgba(246, 246, 247, 0.3);
    --accent: #ff7a18;
    --accent-mark: #ff7a18;
    background: var(--bg);
  }
  .hero-stage::after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 3;
    background: linear-gradient(
      to bottom,
      rgba(10, 10, 12, 0.04) 4%,
      rgba(10, 10, 12, 0.28) 34%,
      rgba(10, 10, 12, 0.74) 68%,
      rgba(10, 10, 12, 0.94) 100%
    );
    pointer-events: none;
  }
  .hero-canvas { transition: none; }
  .hero-plate {
    -webkit-mask-image: none;
    mask-image: none;
    animation: none;
  }
  .hero-plate img { filter: grayscale(1) contrast(1.06) brightness(0.78); }
  .hero-stage > .haze,
  .hero-grain { display: none; }
  html.glass-ready .hero {
    --bg: #f4f3f1;
    --bg-lift: #eceae7;
    --ink: #111114;
    --muted: rgba(17, 17, 20, 0.66);
    --faint: rgba(17, 17, 20, 0.44);
    --ghost: rgba(17, 17, 20, 0.12);
    --hair: rgba(17, 17, 20, 0.13);
    --hair-strong: rgba(17, 17, 20, 0.28);
    --accent: #a8490b;
    --accent-mark: #d2570a;
    background: var(--bg);
  }
  html.glass-ready .hero-stage::after { display: none; }
  .head-in { flex-wrap: wrap; padding-block: 10px; }
  .head-right { display: contents; }
  .brand { order: 1; }
  .lang { order: 2; margin-inline-start: auto; }
  .nav {
    order: 3;
    width: 100%;
    justify-content: space-between;
    gap: 10px;
    padding-top: 8px;
    border-top: 1px solid var(--hair);
  }
  .nav a {
    min-height: 36px;
    display: inline-flex;
    align-items: center;
    padding-inline: 4px;
  }
  .lang-btn { min-height: 40px; }
  .hero { min-height: auto; padding-block: clamp(70px, 16vh, 120px) clamp(90px, 18vh, 140px); }
  .hero-in { justify-content: flex-start; }
  .hero-copy { max-width: none; }
  .hero-plate { -webkit-mask-position: 12% 42%; mask-position: 12% 42%; }
  .hero-plate img { object-position: 12% 42%; }
  /* Copy sits on the statue here; the card would run through the headline. */
  .hero-face-glass { display: none; }
  .about-fade { height: 58vw; min-height: 280px; }
  .about-fig { -webkit-mask-position: 50% 32%; mask-position: 50% 32%; }
  .about-fig img { object-position: 50% 32%; }
  .tiles { margin: -108px var(--pad) 28px; }
  /* The wipe needs less travel on a short viewport, or it reads as the page
     having stopped responding to the scroll. */
  .shade { height: 200vh; }
  .row { grid-template-columns: 1fr; }
  .row .dot { margin-top: 0; }
  .foot-cols { grid-template-columns: 1fr; }
  .ticker-track { animation-duration: 38s; }
}

@media (max-width: 420px) {
  .hero-cta { display: grid; grid-template-columns: 1fr; }
  .hero-cta .btn { width: 100%; justify-content: center; }
  .lang-menu { position: fixed; left: var(--pad); right: var(--pad); top: 98px; }
  .shade-body { margin-top: 20px; }
}

/* ===================================================== reduced motion */
/* Everything scroll-driven resolves to its settled state: the wipe is fully
   open, so the section reads as the dark shade, and the page becomes two
   statically themed halves with no canvas and no drift. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
  .rev { opacity: 1; transform: none; }
  .split .wi { transform: none; }
  .hero-canvas { display: none; }
  .hero-plate { animation: none; }
  .shade { height: auto; }
  .shade-stage { position: static; height: auto; }
  .shade-face { position: relative; inset: auto; min-height: 78svh; }
  .shade-dark { clip-path: none; }
  .shade-light { display: none; }
  .shade-edge { display: none; }
  .scrollcue svg { animation: none; }
  .tile { opacity: 1; margin-left: 0; transform: rotate(var(--tile-rot, 0deg)); animation: none; }
  .haze, .shard { animation: none; }
  .foot-word-in { filter: none; }
}

/* ================================================================ impressum */
/* § 5 DDG wants this readable and easy to find, so it is set as the page's own
   content rather than as small print: label faint and small, value in ink. */
.impressum { display: grid; gap: clamp(20px, 3vw, 30px); margin: 0; max-width: 52ch; }
.impressum dt {
  font-size: var(--step-eyebrow); font-weight: 700; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--faint); margin-bottom: 8px;
}
.impressum dd { margin: 0; color: var(--ink); line-height: 1.5; }
.impressum dd a { border-bottom: 1px solid var(--hair-strong); }
@media (min-width: 720px) {
  .impressum { grid-template-columns: 200px 1fr; gap: 22px clamp(24px, 4vw, 48px); align-items: baseline; }
  .impressum dt { margin-bottom: 0; }
}
