/* ============================================================
   Base, reset, Apple typography, primitives, utilities (v2)
   ============================================================ */

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

html {
  /* Vangrail tegen horizontaal wiebelen op de telefoon: body clipt al, maar
     absolute gloeden (founder-halo, ep-stage::before) lekten in WebKit toch
     door naar de scrollbreedte van het document (12-16px). clip op html
     maakt geen scrollcontainer, dus sticky en fixed blijven werken. */
  overflow-x: clip;
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  scroll-behavior: auto;
  /* geen systeem-tik-flits over grote kaart-links/knoppen op Android/oudere iOS;
     :active-feedback op knoppen hieronder vervangt het netjes */
  -webkit-tap-highlight-color: transparent;
}

body {
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  font-weight: 400;
  letter-spacing: -0.011em;
  color: var(--ink);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  overflow-x: clip;
  transition: background-color 0.5s var(--ease-out), color 0.5s var(--ease-out);
}

/* Rich aurora mesh: subtle on light, luminous on dark. The "expensive" depth.
   Sinds 13 sep 2026 zit de mesh op body::before en de vulling op body::after
   (was andersom). Reden: het hero-achtergrondbeeld (.hero--beeld::before,
   z-index -1) moet bóven de mesh tekenen. Bij gelijke z-index wint de DOM-
   volgorde, en body::after is altijd het laatste kind van body, dus die
   tekende over het beeld heen (lichte vlek rechtsboven). body::before komt
   vóór alles, dus elke laag op z-index -1 in de pagina ligt nu boven de mesh;
   de vulling staat op -2 en ligt onder alles. De gloedbollen (.hero__glow,
   ook -1) liggen daardoor ook boven de mesh in plaats van eronder; twee
   doorschijnende lagen, het verschil is niet te zien. */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -2;
  background: var(--bg);
  transition: background-color 0.5s var(--ease-out);
}
body::before {
  content: "";
  position: fixed;
  inset: -25%;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(50% 48% at 84% 0%, var(--mesh-1), transparent 66%),
    radial-gradient(54% 52% at 6% 98%, var(--mesh-2), transparent 68%);
  opacity: var(--mesh-alpha);
  filter: blur(70px) saturate(1.05);
  transition: opacity 0.5s var(--ease-out);
}

img,
svg,
video {
  display: block;
  max-width: 100%;
}
/* <picture> is alleen een keuzemechanisme (telefoon krijgt een kleinere
   YouTube-thumbnail); de img gedraagt zich alsof hij direct in de kaart staat */
picture {
  display: contents;
}
a {
  color: inherit;
  text-decoration: none;
}
button {
  font: inherit;
  color: inherit;
  background: none;
  border: none;
  cursor: pointer;
}
::selection {
  background: var(--accent);
  color: var(--accent-ink);
}
:focus-visible {
  outline: 2px solid var(--accent-2);
  outline-offset: 3px;
  border-radius: 4px;
}

/* ---------- Typography ---------- */
.display,
h1,
h2,
h3 {
  font-family: var(--font-display);
  font-weight: 600;
  line-height: var(--lh-snug);
  letter-spacing: var(--tracking-tight);
  color: var(--ink);
  text-wrap: balance;
}
.display {
  font-size: var(--fs-display);
  line-height: var(--lh-tight);
  font-weight: 640;
}
.display--mega {
  font-size: var(--fs-mega);
}
h2,
.h2 {
  font-size: var(--fs-h2);
  line-height: 1.04;
  font-weight: 640;
}
h3,
.h3 {
  font-size: var(--fs-h3);
  letter-spacing: -0.025em;
}

/* Emphasis = brand gradient text (replaces the old serif italic) */
em,
.it,
.grad,
.swash {
  font-style: normal;
  font-weight: inherit;
  background: var(--grad-text);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
  /* graceful fallback if background-clip:text unsupported */
}
@supports not ((-webkit-background-clip: text) or (background-clip: text)) {
  em,
  .it,
  .grad,
  .swash {
    -webkit-text-fill-color: currentColor;
    color: var(--accent-deep);
  }
}

/* ---------- Woord-spans (gezet door lux.js én grad-words.js) ----------
   .lw is een niet-brekende woordwrapper; .lw__in is het bewegende deel.
   Hier (en niet in lux.css) zodat de per-woord gradient op élke pagina
   werkt, ook zonder de scroll-choreografielaag. */
.lw {
  display: inline-block;
  white-space: nowrap;
}
.lw__in {
  display: inline-block;
  /* clip-to-text verft glyfen alleen binnen de padding-box; bij de krappe
     kop-line-heights (1.02–1.05) vallen staarten (j/g/p) en accenten (é)
     daarbuiten en lijken letters deels te verdwijnen. Extra padding met
     gelijke negatieve marge verft het volledige glyf zonder de layout of
     de baseline te verschuiven. */
  padding: 0.24em 0.12em;
  margin: -0.24em -0.12em;
}
/* woorden die uit een <em>/.grad komen: gradient per woord her-toegepast
   (background-clip:text overleeft geen inline-block kinderen betrouwbaar) */
.lw__in--grad {
  background: var(--grad-text);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
}
@supports not ((-webkit-background-clip: text) or (background-clip: text)) {
  .lw__in--grad {
    -webkit-text-fill-color: currentColor;
    color: var(--accent-deep);
  }
}

/* gradient-element dat in de HTML al in woorddelen is opgeknipt (koppelwoorden
   als "stap-voor-stap": elk deel verft zijn eigen gradient). Het element zelf
   moet dan niet meeverven, anders trekt Chrome er alsnog één sweep doorheen. */
em.lw,
.grad.lw,
.it.lw,
.swash.lw {
  background: none;
}
/* Zelfde verhaal voor een gradient-element dat in de HTML al per woord is
   opgeknipt: de woorden verven zelf, dus het element eromheen moet zijn eigen
   clip-to-text achtergrond loslaten. Zonder dit trekt de browser er alsnog
   één sweep over de hele zin doorheen en is de gradient niet per woord.
   grad-words.js doet dit voor de spans die hij zelf zet; deze regel dekt de
   spans die al in de HTML staan. */
em:has(> .lw),
.grad:has(> .lw),
.it:has(> .lw),
.swash:has(> .lw) {
  background: none;
}

.eyebrow {
  font-family: var(--font-mono);
  font-size: var(--fs-eyebrow);
  font-weight: 500;
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  color: var(--ink-faint);
  display: inline-flex;
  align-items: center;
  gap: 0.6em;
}
.eyebrow::before {
  content: "";
  width: 1.6em;
  height: 1px;
  background: var(--accent-2);
  opacity: 0.9;
}
.eyebrow--plain::before {
  display: none;
}

.lead {
  font-size: var(--fs-lead);
  line-height: 1.36;
  color: var(--ink-soft);
  font-weight: 400;
  letter-spacing: -0.018em;
  max-width: 32ch;
}
p {
  max-width: var(--measure);
  color: var(--ink-soft);
}
.prose p + p {
  margin-top: 1.1em;
}
/* eerste alinea direct na een eyebrow: zelfde compacte ruimte als in de subhero
   (eyebrow -> kop), niet de ruimere alinea-tussenruimte */
.prose .eyebrow + p {
  margin-top: 1rem;
}
.accent-text {
  color: var(--accent-deep);
}

/* ---------- Layout helpers ---------- */
.container {
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
.container--text {
  max-width: var(--maxw-text);
}
.section {
  position: relative;
  padding-block: var(--section-pad);
}
/* Uniform sectie-ritme: twee opeenvolgende secties zouden anders allebei hun
   volle padding optellen (= dubbele tussenruimte). Door de top-padding van een
   sectie die direct op een andere sectie volgt te nullen, is de afstand tussen
   ELKE twee secties exact één --section-pad. Gepinde scroll-scenes (reframe,
   journey-scene, square-scene) zijn geen .section, dus de sectie eronder houdt
   netjes zijn top-padding en ook dáár blijft de afstand één --section-pad. */
main > .section + .section {
  padding-top: 0;
}
.stack > * + * {
  margin-top: var(--space-3);
}
.stack-lg > * + * {
  margin-top: var(--space-4);
}
.grid {
  display: grid;
  gap: clamp(1.5rem, 1rem + 3vw, 4rem);
}
@media (min-width: 860px) {
  .grid-2 {
    grid-template-columns: repeat(2, 1fr);
  }
  .grid-3 {
    grid-template-columns: repeat(3, 1fr);
  }
}
.muted {
  color: var(--ink-faint);
}
.center {
  text-align: center;
  margin-inline: auto;
}

/* ---------- Buttons ---------- */
.btn {
  --bg-btn: var(--ink);
  --fg-btn: var(--ink-invert);
  display: inline-flex;
  align-items: center;
  gap: 0.55em;
  padding: 0.95em 1.55em;
  border-radius: var(--r-pill);
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: var(--fs-small);
  letter-spacing: -0.01em;
  background: var(--bg-btn);
  color: var(--fg-btn);
  line-height: 1;
  transition: transform var(--dur-1) var(--ease-out),
    box-shadow var(--dur-1) var(--ease-out), filter var(--dur-1) var(--ease-out);
  will-change: transform;
}
.btn:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-soft);
}
.btn:active {
  transform: translateY(0) scale(0.97);
}
.btn .arrow {
  transition: transform var(--dur-1) var(--ease-out);
}
.btn:hover .arrow {
  transform: translateX(4px);
}
.btn--ghost {
  --bg-btn: transparent;
  --fg-btn: var(--ink);
  border: 1px solid var(--line-strong);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
}
.btn--ghost:hover {
  box-shadow: none;
  border-color: var(--ink);
}
/* Er is geen .btn--accent meer. De merk-gradient stond op de gidspagina's en
   de campagne, en nergens anders op de site: dezelfde knop kreeg daardoor een
   andere kleur zodra je van de homepage naar een weggever liep. Eén knopkleur,
   overal: zwart op licht, gebroken wit op donker. Zit een knop op een vlak dat
   in beide thema's donker blijft, zet daar .on-dark of een eigen --bg-btn op
   (zie .channel__subscribe en .ik-cover__cta) in plaats van een accentklasse. */

.link-arrow {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  font-weight: 600;
  font-size: var(--fs-small);
  color: var(--ink);
  border-bottom: 1px solid transparent;
  padding-bottom: 2px;
  transition: color var(--dur-1), border-color var(--dur-1);
}
.link-arrow .arrow {
  color: var(--accent-deep);
  transition: transform var(--dur-1) var(--ease-out);
}
.link-arrow:hover {
  color: var(--accent-deep);
}
.link-arrow:hover .arrow {
  transform: translateX(4px);
}

/* ---------- Scroll-reveal (with no-blank failsafe) ---------- */
[data-motion="on"] .reveal {
  opacity: 0;
  transform: translateY(26px);
  filter: blur(8px);
  transition: opacity 0.9s var(--ease-out), transform 0.9s var(--ease-out),
    filter 0.9s var(--ease-out);
  transition-delay: var(--reveal-delay, 0s);
  animation: revealFailsafe 0.6s var(--ease-out) 1.6s forwards;
}
[data-motion="on"] .reveal.is-in {
  opacity: 1;
  transform: none;
  filter: blur(0);
}
[data-motion="on"] .reveal-line {
  display: block;
  opacity: 0;
  transform: translateY(0.4em);
  filter: blur(8px);
  transition: opacity 0.85s var(--ease-out), transform 0.85s var(--ease-out),
    filter 0.85s var(--ease-out);
  animation: revealFailsafe 0.6s var(--ease-out) 1.6s forwards;
}
[data-motion="on"] .reveal-line.is-in {
  opacity: 1;
  transform: none;
  filter: blur(0);
}
[data-motion="on"].reveal-js .reveal,
[data-motion="on"].reveal-js .reveal-line {
  animation: none;
}
/* Telefoon: dezelfde reveal, maar zonder de blur. Een filter-overgang van
   0,9s is op de iPhone het duurste wat er is: WebKit blurt het hele blok
   elk frame opnieuw. Dat ging mis op twee plekken (Mika, 8 sep 2026): de
   logoband, waar de marquee al loopt terwijl zijn container nog ont-blurt,
   en de glaskaarten van de reviews, waar filter en backdrop-filter elkaar
   in WebKit bijten en de kaart zonder overgang op zijn plek valt. Opkomen
   en omhoogschuiven blijven staan, dat leest nog steeds als een reveal. */
@media (max-width: 767px) {
  [data-motion="on"] .reveal {
    filter: none;
    transition: opacity 0.9s var(--ease-out), transform 0.9s var(--ease-out);
    transition-delay: var(--reveal-delay, 0s);
  }
  [data-motion="on"] .reveal-line {
    filter: none;
    transition: opacity 0.85s var(--ease-out), transform 0.85s var(--ease-out);
  }
}
@keyframes revealFailsafe {
  to {
    opacity: 1;
    transform: none;
    filter: blur(0);
  }
}

/* ---------- Accessibility ---------- */
.visually-hidden {
  position: absolute !important;
  width: 1px;
  height: 1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}
.skip-link {
  position: fixed;
  top: -100px;
  left: 1rem;
  z-index: var(--z-overlay);
  padding: 0.7em 1.2em;
  background: var(--ink);
  color: var(--ink-invert);
  border-radius: var(--r-pill);
  transition: top 0.2s var(--ease-out);
}
.skip-link:focus {
  top: 1rem;
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

