/* ============================================================
   JOHAN MEESKE — aquarellen
   Stijl afgeleid van de presentatiemockups (2026):
   wit, één grotesk, cursieve nummer-captions, kunst op papier.
   ============================================================ */

/* ---------- fonts ---------- */
@font-face {
  font-family: "Inter";
  src: url("../fonts/inter-latin-300-normal.woff2") format("woff2");
  font-weight: 300; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Inter";
  src: url("../fonts/inter-latin-400-normal.woff2") format("woff2");
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Inter";
  src: url("../fonts/inter-latin-400-italic.woff2") format("woff2");
  font-weight: 400; font-style: italic; font-display: swap;
}
@font-face {
  font-family: "Inter";
  src: url("../fonts/inter-latin-500-normal.woff2") format("woff2");
  font-weight: 500; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Inter";
  src: url("../fonts/inter-latin-700-normal.woff2") format("woff2");
  font-weight: 700; font-style: normal; font-display: swap;
}
/* La Belle Aurore (SIL OFL 1.1) — de 'geschreven' stem: bijschriften bij foto's
   en de quotes. Dun potloodhandschrift, dicht bij Johans eigen signatuur. */
@font-face {
  font-family: "La Belle Aurore";
  src: url("../fonts/labelleaurore-latin.woff2") format("woff2");
  font-weight: 400; font-style: normal; font-display: swap;
  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: "La Belle Aurore";
  src: url("../fonts/labelleaurore-latin-ext.woff2") format("woff2");
  font-weight: 400; font-style: normal; font-display: swap;
  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 ---------- */
:root {
  --paper: #ffffff;
  --mist: #f4f4f5;
  --page: #fcfcfd;
  --ink: #101013;
  --grey: #8a8a90;
  --grey-soft: #b9b9bf;
  --hairline: #e8e8ea;
  --shadow-card: 0 1px 2px rgba(16, 16, 19, .04), 0 22px 55px -22px rgba(16, 16, 19, .25);
  --shadow-frame: 0 34px 90px -22px rgba(0, 0, 0, .5), 0 8px 22px rgba(0, 0, 0, .18);
  --maxw: 1400px;
  --pad: clamp(20px, 4vw, 48px);
  /* De ruimte tussen de twee uitsnedes op een werkpagina. Dezelfde maat staat
     eronder en links en rechts, zodat die twee beelden plus de kamerfoto als
     één blok met een gelijke witrand rondom staan. */
  --duo-gap: clamp(14px, 1.6vw, 26px);
  --font: "Inter", "Helvetica Neue", Helvetica, Arial, sans-serif;
  --hand: "La Belle Aurore", "Snell Roundhand", "Segoe Script", cursive;
}

/* ---------- laadscherm ----------
   Eén keer per bezoek (per tabblad) begint de site met een zwart vlak waarop de
   naam van onder naar boven in beeld schuift; daarna trekt het vlak omhoog weg
   en komen de letters van de banner op. Het strikt noodzakelijke (zwart, over de
   hele pagina) staat inline in de <head>, want anders zie je eerst een flits van
   de witte pagina; alles hieronder mag wachten tot deze stylesheet er is. */
html.laadt .laadscherm {
  clip-path: inset(0 0 0 0);
  transition: clip-path .9s cubic-bezier(.72, 0, .16, 1);
}
html.laadt .laadscherm.weg { clip-path: inset(0 0 100% 0); }
/* Het merk staat linksboven op dezelfde plek als in de header, dus als het zwart
   wegtrekt staat de naam al waar hij hoort. De teller loopt linksonder mee: dat
   geeft het wachten een maat, in plaats van een groot vlak waar niets gebeurt. */
.laad-merk {
  position: absolute; left: var(--pad); top: 16px;
  display: flex; align-items: baseline; gap: .42em;
  color: #fff; line-height: 1.65;
  font-size: clamp(1.2rem, 1.05rem + .5vw, 1.34rem); letter-spacing: -.01em;
}
.laad-merk strong { font-weight: 700; letter-spacing: -.022em; }
.laad-merk .laad-regel + .laad-regel > * {
  font-weight: 300; color: rgba(255, 255, 255, .62); letter-spacing: 0;
}
.laad-teller {
  position: absolute; left: var(--pad); bottom: clamp(18px, 3.4vh, 44px);
  font-size: clamp(2.6rem, 7vw, 5.2rem); font-weight: 300; line-height: 1;
  letter-spacing: -.03em; color: rgba(255, 255, 255, .9);
  font-variant-numeric: tabular-nums;
}
/* elke regel is een venstertje waar de tekst vanonder in schuift */
.laad-regel { display: block; overflow: hidden; }
.laad-regel > * {
  display: block; transform: translateY(110%);
  animation: laadRegel .8s cubic-bezier(.2, .75, .2, 1) both;
}
.laad-merk .laad-regel:first-child > * { animation-delay: .05s; }
.laad-merk .laad-regel + .laad-regel > * { animation-delay: .13s; }
@keyframes laadRegel { from { transform: translateY(110%) } to { transform: none } }
/* naam en teller schuiven met het zwart mee omhoog weg */
html.laadt .laadscherm.weg .laad-merk,
html.laadt .laadscherm.weg .laad-teller {
  transform: translateY(-40px); opacity: 0;
  transition: transform .8s cubic-bezier(.72, 0, .16, 1), opacity .5s ease;
}
html.laadt .laadscherm.weg .laad-regel > * { animation: none; transform: none; }
/* De letters van de banner wachten op het zwart: zonder dit zouden ze hun
   entree er al achter hebben gehad. Op een pagina zonder laadscherm (elke klik
   na de eerste) staat `intro-klaar` al vanaf het begin op <html>, dus dan
   verandert er niets. */
@keyframes introRijs { from { opacity: 0; transform: translateY(18px) } to { opacity: 1; transform: none } }
@keyframes introOp { from { opacity: 0 } to { opacity: 1 } }
.hero-foot .cap { animation: introRijs .95s cubic-bezier(.2, .7, .2, 1) .3s both paused; }
/* op een werkpagina hangt het bijschrift onder de titel, dus die wacht mee */
.hc-cap { animation: introRijs .95s cubic-bezier(.2, .7, .2, 1) 1s both paused; }
.hero-page-hint { animation: introOp 1s ease 1.3s both paused; }
.bigname { animation: introOp 1.1s ease .14s both paused; }
html.intro-klaar .hc-cap, html.intro-klaar .hero-foot .cap,
html.intro-klaar .hero-page-hint, html.intro-klaar .bigname { animation-play-state: running; }
/* De banner-titel komt per regel van onder een rand tevoorschijn, zoals bij
   Goodman: het buitenste vakje is het venster, het binnenste schuift omhoog. De
   ondertitel volgt een tel later. Het venster staat iets ruimer dan de regel
   (padding + negatieve marge), anders knipt hij de staartletters af. */
.hc-title .ln { display: block; overflow: hidden; padding-bottom: .14em; margin-bottom: -.14em; }
/* De animatie staat er meteen op maar op pauze, dus de regel wacht onder de rand
   tot `intro-klaar` op <html> staat. Die klasse komt van het laadscherm (zodra het
   zwart wegtrekt) of, als dat uit staat, meteen bij het laden — zo werkt het
   opkomen in beide gevallen. */
.hc-title .ln > span {
  display: block;
  /* een tel wachten: eerst het beeld laten landen, dan pas de letters */
  animation: lnRijs 1s cubic-bezier(.16, .8, .2, 1) .7s both paused;
}
.hc-title .hc-sub .ln > span { animation-delay: .83s; }
html.intro-klaar .hc-title .ln > span { animation-play-state: running; }
@keyframes lnRijs { from { transform: translateY(115%) } to { transform: none } }
/* de grote naam op de home rijst niet maar komt alleen op: die zit met een eigen
   transform aan de scroll vast (de morph naar de header) */
@media (prefers-reduced-motion: reduce) {
  html.laadt .laadscherm { transition: none; }
  .laad-regel > *, .hc-title .ln > span, .hc-cap, .hero-foot .cap,
  .hero-page-hint, .bigname { animation: none; transform: none; opacity: 1; }
}

/* ---------- basis ---------- */
*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
a, button { -webkit-tap-highlight-color: transparent; }
body {
  margin: 0;
  background: var(--page);
  color: var(--ink);
  font-family: var(--font);
  font-size: 1rem;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
img { max-width: 100%; height: auto; display: block; }
a { color: inherit; text-decoration: none; }
p { margin: 0 0 1.2em; }
:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; border-radius: 1px; }
::selection { background: var(--ink); color: var(--paper); }

main { position: relative; }
.wrap { max-width: var(--maxw); margin: 0 auto; padding-left: var(--pad); padding-right: var(--pad); }

/* ---------- wordmark ---------- */
.wordmark { display: inline-flex; align-items: baseline; gap: .45em; white-space: nowrap; }
.wordmark strong { font-weight: 700; letter-spacing: -.015em; }
.wordmark span { font-weight: 300; color: var(--grey); letter-spacing: .01em; }

/* ---------- header ---------- */
.site-head {
  position: fixed; inset: 0 0 auto 0; z-index: 50;
  background: rgba(252, 252, 253, 0);
  transition: background .35s ease, box-shadow .35s ease;
}
.site-head.scrolled {
  background: rgba(252, 252, 253, .86);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  box-shadow: 0 1px 0 var(--hairline);
}
.site-head .bar {
  /* de header loopt door tot de randen, net als de beelden — dus geen
     inhoudskolom van 1280px maar alleen --pad aan weerszijden */
  max-width: none;
  /* grotere letters binnen exact dezelfde headerhoogte: de ruimte eromheen
     krimpt mee met wat de regel extra nodig heeft */
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 16px; padding-top: 17px; padding-bottom: 14px;
}
/* staat bovenaan de pagina groot en krimpt bij scroll naar deze maat (site.js).
   Transform i.p.v. font-size, zodat de headerhoogte niet meebeweegt. */
.site-head .wordmark {
  font-size: clamp(1.2rem, 1.05rem + .5vw, 1.34rem);
  transform-origin: left center;
  /* GEEN will-change hier. Daarmee zet Chrome de wordmark op een eigen laag die
     één keer op de kleine maat wordt getekend en daarna door de GPU wordt
     opgeblazen — en dan staat er bovenaan de pagina onscherpe tekst terwijl de
     rest scherp is. Zonder will-change wordt de tekst opnieuw getekend op de
     maat die je ziet. Het is één regel tekst, dus dat kost niets. */
}
.site-nav { display: flex; gap: clamp(16px, 3vw, 34px); }
.site-nav a {
  font-size: .9rem; letter-spacing: .17em; text-transform: uppercase;
  color: #6d6d74; padding: 4px 0;
  border-bottom: 1px solid transparent;
  transition: color .2s ease;
}
.site-nav a:hover { color: var(--ink); }
.site-nav a[aria-current="page"] { color: var(--ink); border-bottom-color: var(--ink); }
/* DE en EN: de teksten van de oude site in het Duits en Engels */
.site-nav .taal {
  display: inline-flex; align-items: baseline; gap: clamp(10px, 1.2vw, 16px);
  padding-left: clamp(14px, 1.8vw, 26px); border-left: 1px solid var(--hairline);
}
.site-nav .taal a { font-size: .8rem; letter-spacing: .14em; }
.site-head.over-hero .site-nav .taal,
.site-head.over-hero-licht .site-nav .taal { border-left-color: rgba(255, 255, 255, .35); }
/* menuknop: alleen op smal scherm, daar staat het menu in een paneel */
.menu-knop {
  display: none; position: relative; z-index: 71;
  width: 30px; height: 22px; padding: 0; margin: -2px -4px 0 0;
  background: none; border: 0; cursor: pointer;
  flex-direction: column; justify-content: center; gap: 6px; align-items: flex-end;
}
.menu-knop span {
  display: block; height: 1px; background: var(--ink);
  transition: transform .3s cubic-bezier(.2, .7, .2, 1), width .3s ease, background .3s ease;
}
.menu-knop span:nth-child(1) { width: 24px; }
.menu-knop span:nth-child(2) { width: 16px; }
body.menu-open .menu-knop span:nth-child(1) { width: 22px; transform: translateY(3.5px) rotate(45deg); }
body.menu-open .menu-knop span:nth-child(2) { width: 22px; transform: translateY(-3.5px) rotate(-45deg); }
.site-head.over-hero .menu-knop span { background: #fff; }
body.menu-open .site-head.over-hero .menu-knop span { background: var(--ink); }
/* met het paneel open staat de knop op wit, dus ook boven een lichte hero inkt
   en zonder het schaduwtje dat hij op de zaalwand nodig heeft */
body.menu-open .site-head.over-hero-licht .menu-knop span { background: var(--ink); box-shadow: none; }

/* ---------- captions (mockup-stijl) ---------- */
.cap {
  font-size: .9rem; font-style: italic; color: var(--grey);
  letter-spacing: .01em; line-height: 1.5;
}
.cap .sep { margin: 0 .55em; color: var(--grey-soft); font-style: normal; }
figure { margin: 0; }
figure .cap { display: block; text-align: right; padding-top: 14px; }

/* ---------- met de hand geschreven ---------- */
.hand {
  font-family: var(--hand);
  font-weight: 400; font-style: normal;
  color: var(--ink);
}

/* ---------- papier-kaart ---------- */
.paper {
  display: block;
  background: var(--paper);
  border: 1px solid #ececee;
  padding: clamp(10px, 1.6vw, 22px);
  box-shadow: var(--shadow-card);
}
.paper img { width: 100%; display: block; }

/* Foto op wit karton: de onderrand loopt door en daar staat het bijschrift
   met de hand op geschreven — zoals Johan onder een blad signeert. */
.paper > .hand {
  display: block;
  font-size: clamp(1.3rem, .62rem + 1vw, 1.68rem);
  line-height: 1.35;
  padding: clamp(15px, 1.8vw, 24px) 1px clamp(2px, .7vw, 8px);
}

/* ============================================================
   HOME — full-bleed hero met naam die naar de header morpht
   ============================================================ */
.hero-full {
  position: relative;
  height: 100svh;
  min-height: 480px;
  overflow: hidden;
  background: #0c0f12;
}
.hero-full .hero-bg {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  /* wacht op intro-klaar (letters en beeld binnen), anders zoomt hij al in
     voordat het schilderij er is en ploft het er halverwege in */
  animation: heroSettle 1.8s cubic-bezier(.16, .7, .2, 1) both paused;
}
html.intro-klaar .hero-full .hero-bg { animation-play-state: running; }
/* De parallax-laag om een bannerbeeld. Het beeld zelf houdt zijn eigen
   inzoom-animatie bij het laden; deze laag doet alleen het verschuiven bij
   scroll (site.js).

   De laag is een kwart HOGER dan de banner en hangt met de helft daarvan boven
   en de helft onder de rand. Dat achtste boven en onder is precies de ruimte om
   te schuiven: over de hele banner loopt het beeld dus een kwart van de
   bannerhoogte achter op de pagina — een paar honderd pixels, zo sterk als bij
   Goodman. Hoger maken dan dit kan, maar dan zoomt de uitsnede verder in: een
   dekkende foto in een hogere bak wordt vanzelf groter. */
.hc-plx {
  --plx: .25;                       /* hoeveel van de bannerhoogte het beeld achterloopt */
  position: absolute; left: 0; right: 0;
  top: calc(-50% * var(--plx)); height: calc(100% + 100% * var(--plx));
  display: block; will-change: transform;
}
/* Op de biografie is het beeld een portret en is de kop het onderwerp: daar mag
   er niet zo veel van boven en onder af, dus is de sprong kleiner. Op de home en
   de werkpagina's hangt er een panorama waar dat niets kost. */
.hero-page .hc-plx { --plx: .1; }
.hc-plx img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
@media (prefers-reduced-motion: reduce) {
  .hc-plx { --plx: 0; transform: none; }
}
@keyframes heroSettle { from { transform: scale(1.055); } to { transform: scale(1); } }
.hero-scrim {
  position: absolute; inset: 0;
  background:
    linear-gradient(to bottom, rgba(8, 10, 13, .38) 0%, rgba(8, 10, 13, .10) 40%, rgba(8, 10, 13, .55) 100%);
}
.hero-foot {
  position: absolute; left: 0; right: 0; bottom: clamp(20px, 4vh, 46px);
  padding-left: var(--pad); padding-right: var(--pad);
  text-align: center;
}
/* wit op een aquarel: een zachte schaduw houdt het leesbaar, ook als het werk
   op die plek juist licht is — beter dan het hele beeld donkerder maken */
.hero-foot .cap { color: rgba(255, 255, 255, .9); text-shadow: 0 1px 16px rgba(0, 0, 0, .6); }
.hero-foot .cap .sep { color: rgba(255, 255, 255, .5); }
/* pijltje dat rustig ademt in plaats van het woord 'Scroll' */
.scrollhint {
  display: block; margin-top: 18px; line-height: 0;
  color: rgba(255, 255, 255, .72);
}
.scrollhint svg {
  animation: ademen 3.4s cubic-bezier(.4, 0, .3, 1) infinite;
  filter: drop-shadow(0 1px 8px rgba(0, 0, 0, .55));
}
@keyframes ademen {
  0%, 100% { transform: translateY(-2px) scale(.94); opacity: .45; }
  50%      { transform: translateY(4px) scale(1.06); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) { .scrollhint svg { animation: none; opacity: .8; } }

/* de naam zelf: fixed, schaalt bij scroll naar de headerpositie */
.namestage {
  /* Vaste hoogte, gelijk aan de hero (100svh, minstens 480px) — niet `inset: 0`.
     Op een iPhone klapt de adresbalk in en uit tijdens het scrollen; met inset: 0
     groeide het podium dan mee en schoof de naam, die in het midden staat, een
     halve balkhoogte op. Zie site.js (de vlucht naar de header). */
  position: fixed; top: 0; left: 0; right: 0; z-index: 60;
  height: max(100vh, 480px);
  height: max(100svh, 480px);
  display: grid; place-items: center;
  pointer-events: none;
}
/* zonder morph (telefoon of reduced motion): naam blijft in de hero staan en
   scrolt gewoon mee omhoog. Dan moet hij ONDER de header door. De morph heeft
   z-index 60 nodig om over de header (50) heen naar zijn plek te vliegen; bleef
   die hier ook staan, dan schoof de stilstaande naam bij het scrollen bovenop
   de headertekst (Ruben, 24 oktober 2026). De header is al ondoorzichtig voor
   de naam hem bereikt, dus hij verdwijnt er netjes achter. */
.namestage.is-static { position: absolute; top: 0; left: 0; right: 0; bottom: auto; height: 100svh; z-index: 40; }
body.static-name .site-head .wordmark.ghost { pointer-events: auto; }
body.static-name .site-head .wordmark.ghost strong,
body.static-name .site-head .wordmark.ghost span { opacity: 1; }

/* ---------- telefoon: de naam vliegt in één beweging naar de header ----------
   Zie isMobiel() in site.js. Dat script zet alleen body.morph-mobiel en, zodra
   je begint te scrollen, body.naam-in-kop; de vlucht zelf is deze overgang. Hij
   loopt op de grafische chip, dus niet meer achter op het schilderij aan.
   Een overgang gebruikt de timing van de stand waar hij NAARTOE gaat.
   Heen: de naam vliegt in 0,46s naar zijn plek. Vanaf 0,24s — dan hangt hij al
   bij de header en niet meer boven het schilderij — kleurt hij donker en gaat
   zijn schaduw weg. Pas als hij helemaal geland is wisselt hij met de header-
   wordmark: donker op donker, op exact dezelfde plek, dus die wissel zie je
   niet. Begon de wissel eerder, dan stonden er even twee namen net verschoven
   over elkaar (gezien in de frames, 24 oktober 2026).
   Terug: de header-wordmark gaat meteen weg en de naam is er meteen. */
body.morph-mobiel .bigname strong {
  transition: transform .46s cubic-bezier(.2, .75, .25, 1), opacity .16s ease,
              color .2s ease, text-shadow .2s ease;
}
body.morph-mobiel.naam-in-kop .bigname strong {
  transform: translate3d(var(--vlieg-x, 0), var(--vlieg-y, 0), 0) scale(var(--vlieg-s, 1));
  opacity: 0;
  color: var(--ink);
  text-shadow: 0 1px 2px rgba(10, 11, 13, 0), 0 0 9px rgba(10, 11, 13, 0), 0 2px 30px rgba(10, 11, 13, 0);
  transition: transform .46s cubic-bezier(.2, .75, .25, 1), color .2s ease .24s,
              text-shadow .2s ease .2s, opacity .12s linear .46s;
}
/* 'aquarellen' vliegt niet mee: staand zou hij dwars door de naam kruisen.
   Hij verdwijnt meteen en komt in de header op terwijl de naam aankomt. */
body.morph-mobiel .bigname .wordmark > span { transition: opacity .2s ease .34s; }
body.morph-mobiel.naam-in-kop .bigname .wordmark > span { opacity: 0; transition: opacity .14s ease; }
body.morph-mobiel .site-head .wordmark.ghost strong,
body.morph-mobiel .site-head .wordmark.ghost span { transition: opacity .18s ease; }
body.morph-mobiel.naam-in-kop .site-head .wordmark.ghost strong { opacity: 1; transition: opacity .1s linear .44s; }
body.morph-mobiel.naam-in-kop .site-head .wordmark.ghost span { opacity: 1; transition: opacity .22s ease .34s; }
body.morph-mobiel.naam-in-kop .site-head .wordmark.ghost { pointer-events: auto; }
/* De naam begint midden op een lichte aquarel; daar hoort dezelfde strakke
   schaduw bij als bij de stilstaande naam, ook liggend (breder dan 559px). */
body.morph-mobiel .bigname strong,
body.morph-mobiel .bigname .wordmark span {
  text-shadow:
    0 1px 2px rgba(10, 11, 13, .5),
    0 0 9px rgba(10, 11, 13, .45),
    0 2px 30px rgba(10, 11, 13, .5);
}
/* Zolang de naam nog in de hero staat blijft de header doorzichtig, ook na de
   eerste paar pixels (.scrolled gaat al aan bij 8px). Anders zat daar even een
   lichte balk met een witte menuknop erop. */
body.morph-mobiel:not(.naam-in-kop) .site-head.scrolled {
  background: transparent; box-shadow: none;
  -webkit-backdrop-filter: none; backdrop-filter: none;
}
.bigname {
  margin: 0;
  font-size: min(7.4vw, 6.6rem);
  line-height: 1;
  white-space: nowrap;
  transform-origin: left top;
  color: #fff;
  text-shadow: 0 2px 34px rgba(0, 0, 0, .55);
}
/* Alleen de letters zelf zijn aanklikbaar, niet de link eromheen. Die link blijft
   namelijk op zijn plek midden op het scherm staan terwijl de letters naar de
   header vliegen, en ving daar onzichtbaar elke klik op: wie op een schilderij
   klikte, kwam weer op de home (Ruben, 30 september 2026). */
.bigname .wordmark { pointer-events: none; gap: .42em; }
.bigname .wordmark > strong, .bigname .wordmark > span { pointer-events: auto; }
body.menu-open .bigname .wordmark > strong, body.menu-open .bigname .wordmark > span { pointer-events: none; }
.bigname strong { font-weight: 700; letter-spacing: -.022em; }
.bigname span { font-weight: 300; font-size: .72em; color: rgba(255, 255, 255, .82); letter-spacing: 0; }
/* naam én ondertitel vliegen elk apart naar hun eigen plek in de header
   (site.js), zodat het woordmerk als één geheel beweegt */
/* will-change zet site.js aan en uit: alleen aan zolang de naam vliegt, want
   anders blijft de tekst als plaatje op de grote maat hangen en ziet hij
   verkleind wazig uit */
.bigname strong, .bigname .wordmark span { transform-origin: left top; }
/* de ghost is het landingspunt van de grote naam: JOHAN MEESKE blijft hier
   onzichtbaar (de gelande naam ligt eroverheen), 'aquarellen' komt aan het eind
   van de morph op zijn eigen plek tevoorschijn — site.js stuurt die opacity */
.site-head .wordmark.ghost { pointer-events: none; }
.site-head .wordmark.ghost strong { opacity: 0; }
.site-head .wordmark.ghost span { opacity: 0; }
/* menu en wordmark wit zolang ze boven een hero-afbeelding staan */
.site-head.over-hero .site-nav a { color: rgba(255, 255, 255, .82); text-shadow: 0 1px 18px rgba(0, 0, 0, .45); }
.site-head.over-hero .site-nav a:hover { color: #fff; }
.site-head.over-hero .site-nav a[aria-current="page"] { color: #fff; border-bottom-color: #fff; }
.site-head.over-hero .wordmark:not(.ghost) { text-shadow: 0 1px 18px rgba(0, 0, 0, .45); }
.site-head.over-hero .wordmark:not(.ghost) strong { color: #fff; }
.site-head.over-hero .wordmark:not(.ghost) span { color: rgba(255, 255, 255, .78); }

@media (max-width: 559px) {
  .bigname { font-size: clamp(2.2rem, 11.5vw, 3.4rem); text-align: center; }
  .bigname .wordmark { flex-direction: column; align-items: center; gap: .12em; }
  .bigname span { font-size: .42em; letter-spacing: .06em; }
  /* Op een telefoon staat de naam midden op de aquarel en die is licht van
     zichzelf — wit op wit. De schaduw van de brede versie is met 34px te wijd
     om daar iets te doen. Hier dus drie lagen die dichter op de letter zitten:
     1px voor de rand, een halo van 9px die de kleur er direct achter dempt, en
     een brede pool die het geheel losmaakt van de achtergrond. Alleen op de
     letters, dus geen vlak over het schilderij.
     Deze regel geldt alleen als de naam blijft staan waar hij staat. Vliegt hij
     naar de header, dan zet site.js dezelfde schaduw als inline stijl en laat
     hem onderweg uitlopen — want in een witte header hoort er niets omheen. */
  body.static-name .bigname strong,
  body.static-name .bigname .wordmark span {
    text-shadow:
      0 1px 2px rgba(10, 11, 13, .5),
      0 0 9px rgba(10, 11, 13, .45),
      0 2px 30px rgba(10, 11, 13, .5);
  }
  .site-head.over-hero .wordmark { text-shadow: 0 1px 18px rgba(0, 0, 0, .45); }
  .site-head.over-hero .wordmark strong { color: #fff; }
  .site-head.over-hero .wordmark span { color: rgba(255, 255, 255, .78); }
}

/* home-secties */
.home-intro { padding-top: clamp(64px, 11vw, 150px); padding-bottom: clamp(56px, 9vw, 120px); }
.intro-grid { display: grid; gap: clamp(28px, 5vw, 72px); align-items: center; }
@media (min-width: 860px) { .intro-grid { grid-template-columns: 5fr 6fr; } }
.intro-portrait { position: relative; }
.intro-portrait img { width: 100%; aspect-ratio: 4 / 5; object-fit: cover; }
.intro-body .eyebrow { margin-bottom: clamp(16px, 2vw, 26px); }
.intro-lead {
  font-size: clamp(1.3rem, 2.5vw, 1.95rem); font-weight: 300;
  letter-spacing: -.015em; line-height: 1.4; margin: 0 0 1em;
}
.intro-body p { color: #4a4a50; max-width: 46ch; }

.home-sel { padding-bottom: clamp(56px, 9vw, 120px); }
.more-works { padding-top: clamp(40px, 6vw, 72px); padding-bottom: clamp(56px, 8vw, 100px); }

.home-expo { border-top: 1px solid var(--hairline); padding-top: clamp(48px, 7vw, 90px); padding-bottom: clamp(56px, 9vw, 120px); }
.expo-teaser { display: grid; gap: 0; max-width: 860px; }
.expo-teaser .expo:first-child { border-top: 1px solid var(--hairline); }

.eyebrow {
  font-size: .8rem; letter-spacing: .24em; text-transform: uppercase;
  color: var(--grey); margin: 0 0 clamp(28px, 4vw, 52px);
}

/* pijl-links */
.arrowlink {
  font-size: .86rem; letter-spacing: .17em; text-transform: uppercase;
  color: #6d6d74; display: inline-flex; align-items: center; gap: .7em;
  transition: color .2s ease;
}
.arrowlink::after { content: "\2192"; font-size: 1.05em; transition: transform .25s ease; }
.arrowlink:hover { color: var(--ink); }
.arrowlink:hover::after { transform: translateX(5px); }

/* ---------- sectiekoppen ---------- */
.sec-head { display: flex; align-items: baseline; justify-content: space-between; gap: 24px; margin-bottom: clamp(32px, 5vw, 64px); }
.sec-title {
  font-size: clamp(1.9rem, 4vw, 3.1rem); font-weight: 300;
  letter-spacing: -.02em; line-height: 1.1; margin: 0;
}
.sec-note { font-size: .9rem; font-style: italic; color: var(--grey); }
/* Op een telefoon krijgt de kop de hele regel; een notitie of link ernaast zakt
   eronder in plaats van de kop in twee regels te knijpen. */
@media (max-width: 599px) {
  .sec-head { flex-wrap: wrap; gap: 8px 24px; }
  .sec-head .sec-title { flex: 1 1 100%; }
}

/* ---------- werkoverzicht ---------- */
.period { padding-top: clamp(40px, 7vw, 90px); padding-bottom: clamp(28px, 4vw, 56px); }
.period + .period { border-top: 1px solid var(--hairline); }
.period-head { display: flex; align-items: baseline; gap: 20px; justify-content: space-between; flex-wrap: wrap; margin-bottom: 10px; }
.period-title { font-size: clamp(1.6rem, 3vw, 2.4rem); font-weight: 300; letter-spacing: -.02em; margin: 0; }
.period-count { font-size: .9rem; font-style: italic; color: var(--grey); }
.period-intro { max-width: 640px; color: #4a4a50; margin: 6px 0 clamp(28px, 4vw, 48px); }
/* een serie zonder inleiding: dan geen lege ruimte (in het beheer kan Johan
   er alsnog een schrijven; daar maakt bewerk.js het lege vak zichtbaar) */
.period-intro:empty { display: none; }
.period-head:has(+ .period-intro:empty) { margin-bottom: clamp(24px, 3.4vw, 40px); }
/* ---------- kunstraster: redactioneel, rijen vullen exact 12 ----------
   build.py verdeelt elke serie in rijen die samen 12 kolommen vullen:
   6+6, 4+4+4, 8+4, en de grote 160 × 95 cm-werken op volle breedte.
   Een allerlaatste eenling wordt gecentreerd (ctr-klassen).           */
.art-grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  align-items: start;
  column-gap: clamp(18px, 2.2vw, 34px);
  row-gap: clamp(24px, 2.8vw, 44px);
}
.art-grid--lead { row-gap: clamp(30px, 3.4vw, 54px); }
.sp4  { grid-column: span 4; }
.sp6  { grid-column: span 6; }
.sp8  { grid-column: span 8; }
.sp12 { grid-column: 1 / -1; }
.ctr6 { grid-column: 4 / 10; }
.ctr8 { grid-column: 3 / 11; }

/* Geen hoogteverspringing meer tussen de kaarten: Johan wilde de werken
   bovenaan gelijk uitgelijnd (september 2026). */
@media (max-width: 1023px) {
  .sp4, .sp6, .sp8 { grid-column: span 6; }
  .ctr6, .ctr8 { grid-column: 4 / 10; }
}
@media (max-width: 599px) {
  .art-grid { grid-template-columns: 1fr; row-gap: clamp(28px, 6vw, 44px); }
  .sp4, .sp6, .sp8, .sp12, .ctr6, .ctr8 { grid-column: 1 / -1; }
}

/* ---------- uitzoomen op de werkpagina ----------
   Stand 2 is het redactionele raster hierboven (standaard). De andere standen
   zetten de serie in kolommen in plaats van rijen: kaarten verschillen in
   hoogte, dus alleen zo haken ze verticaal in elkaar zonder witte gaten. */
:root[data-zoom="1"] .period .art-grid { display: block; }
:root[data-zoom="1"] .period .art-card { width: 100%; margin: 0 0 clamp(28px, 3vw, 52px); }
:root[data-zoom="3"] .period .art-grid,
:root[data-zoom="5"] .period .art-grid {
  column-gap: clamp(16px, 2vw, 30px);
  row-gap: clamp(16px, 2vw, 30px);
  /* brede werken passen niet altijd in de resterende kolommen; met dense
     schuift een volgend smal werk het gat op in plaats van het te laten staan */
  grid-auto-flow: row dense;
}
:root[data-zoom="3"] .period .art-grid { grid-template-columns: repeat(3, 1fr); }
:root[data-zoom="5"] .period .art-grid { grid-template-columns: repeat(5, 1fr); }
:root[data-zoom="3"] .period .art-card,
:root[data-zoom="5"] .period .art-card { grid-column: span 1; margin: 0; }
/* contrast in maten: de grote werken en elk derde panorama krijgen dubbele
   breedte (data-wide uit build.py) — alles breed maken pakt slecht in kolommen
   en levert juist geen contrast op */
:root[data-zoom="5"] .period .art-card[data-wide],
:root[data-zoom="3"] .period .art-card[data-lead] { grid-column: span 2; }
/* met JS: fijnmazige rijen + berekende rijspanne, zodat kaarten van
   verschillende hoogte verticaal in elkaar haken (metselwerk) */
:root[data-metsel="1"][data-zoom="3"] .period .art-grid,
:root[data-metsel="1"][data-zoom="5"] .period .art-grid {
  grid-auto-rows: 4px; row-gap: 0;
}
/* Eén per rij: bewust niet de volle 1300px. De meeste scans zijn ±650px breed,
   dus een smallere kolom houdt ze scherp terwijl het werk toch groot in beeld
   staat. Een staand werk wordt op hoogte begrensd en krijgt wit ernaast. */
:root[data-zoom="1"] .period .art-card { max-width: min(100%, 1000px); margin-inline: auto; }
/* Nooit witte randen naast het werk: in plaats van het beeld in een breder vak
   te passen (dan houd je wit over), krimpt het vák mee. --ar is de verhouding
   van dit werk, dus de breedte die bij 76vh hoogte hoort. */
:root[data-zoom="1"] .period .art-card { max-width: min(100%, 1000px); }
:root[data-zoom="1"] .period .art-card .mount {
  width: min(100%, calc(var(--fit-h) * var(--ar, 1.5) + 2 * clamp(14px, 1.8vw, 30px) + 2px));
  margin-inline: auto;
}
:root[data-zoom="1"] .period .art-card .mount img { width: 100%; height: auto; }
:root[data-zoom="1"] .period .art-card .mount { padding: clamp(14px, 1.8vw, 30px); }
:root[data-zoom="1"] .period .card-name { margin-top: 18px; font-size: 1.1rem; }
/* hoe kleiner de kaart, hoe smaller de witrand en het bijschrift — anders
   neemt het passe-partout meer plaats in dan het werk zelf */
:root[data-zoom="3"] .period .art-card .mount { padding: clamp(7px, .9vw, 13px); }
:root[data-zoom="3"] .period .card-name { margin-top: 11px; font-size: 1rem; }
:root[data-zoom="3"] .period .card-desc { font-size: .86rem; }
:root[data-zoom="5"] .period .art-card .mount { padding: 6px; }
:root[data-zoom="5"] .period .card-name { margin-top: 8px; font-size: .9rem; }
:root[data-zoom="5"] .period .card-desc { font-size: .8rem; }
:root[data-zoom="5"] .period .card-cta { display: none; }   /* past niet meer */
:root[data-zoom="3"] .period .card-cta,
:root[data-zoom="5"] .period .card-cta { left: 7px; bottom: 7px; }
@media (max-width: 1200px) { :root[data-zoom="5"] .period .art-grid { grid-template-columns: repeat(4, 1fr); } }
@media (max-width: 860px) {
  :root[data-zoom="5"] .period .art-grid { grid-template-columns: repeat(3, 1fr); }
  :root[data-zoom="3"] .period .art-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 560px) {
  :root[data-zoom="5"] .period .art-grid { grid-template-columns: repeat(2, 1fr); }
  :root[data-zoom="3"] .period .art-grid { grid-template-columns: 1fr; }
  :root[data-zoom="3"] .period .art-card { grid-column: 1 / -1; }
}

/* De formaatkiezer staat middenonder in beeld, niet in een hoek: daar leest
   hij als een kijkknop bij de werken in plaats van als een los widget, en hij
   loopt de jaartallenbalk niet in de weg. Zo onopvallend als het kan — een
   dun schijfje dat oplicht zodra je in de buurt komt. */
.zoomer {
  position: fixed; left: 50%; transform: translateX(-50%);
  bottom: clamp(16px, 2.6vh, 28px); z-index: 48;
  display: flex; gap: 2px; padding: 5px 7px;
  background: rgba(252, 252, 253, .8);
  -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
  border: 1px solid var(--hairline); border-radius: 999px;
  box-shadow: 0 1px 2px rgba(16, 16, 19, .04), 0 10px 24px -14px rgba(16, 16, 19, .22);
  /* Hij komt pas tevoorschijn als de periode-lijst voorbij is: daarvoor zou hij
     er dwars door die regels heen staan, en er is dan ook nog niets om groter of
     kleiner te maken. site.js zet `zicht` zodra de lijst boven hem uit is. */
  opacity: 0; pointer-events: none;
  transform: translate(-50%, 14px);
  transition: opacity .35s ease, transform .35s cubic-bezier(.2, .7, .2, 1), background .25s ease;
}
.zoomer.zicht { opacity: .72; pointer-events: auto; transform: translate(-50%, 0); }
.zoomer.zicht:hover, .zoomer.zicht:focus-within { opacity: 1; background: rgba(252, 252, 253, .94); }
@media (prefers-reduced-motion: reduce) { .zoomer { transition: opacity .2s ease; } }
.zoomer button {
  display: grid; place-items: center;
  width: 34px; height: 28px; padding: 0;
  background: none; border: 0; border-radius: 999px; cursor: pointer;
  color: var(--grey-soft);
  transition: color .2s ease, background .2s ease;
}
.zoomer button svg { fill: currentColor; }
.zoomer button:hover { color: var(--grey); }
.zoomer button[aria-pressed="true"] { color: var(--ink); background: rgba(16, 16, 19, .06); }
@media (max-width: 767px) { .zoomer { display: none; } }

/* nette drie-op-een-rij voor de selectie op home en onder een werk */
.art-grid--three { grid-template-columns: repeat(3, 1fr); }
.art-grid--three > .art-card { grid-column: auto; margin-top: 0; }
.dots { display: none; }
@media (max-width: 767px) {
  /* op een telefoon een carrousel: het volgende werk piept er half in, dus
     je ziet meteen dat er meer naast staat, en de bolletjes zeggen hoeveel */
  .carousel {
    display: flex; gap: 14px;
    /* Alleen opzij. Met overflow-x: auto wordt de andere richting vanzelf ook
       scrollbaar, en de kaarten die nog moesten infaden stonden 14px lager en
       staken er dus onderuit: bij de eerste veeg zakten ze op een iPhone mee
       naar beneden en veerden ze terug (Ruben, 30 september 2026). */
    overflow-x: auto; overflow-y: hidden; overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory;
    scroll-padding-left: var(--pad);
    margin-inline: calc(var(--pad) * -1);
    padding-inline: var(--pad);
    scrollbar-width: none; -webkit-overflow-scrolling: touch;
  }
  .carousel::-webkit-scrollbar { display: none; }
  /* de kaarten in een carrousel staan er meteen: infaden terwijl je opzij veegt
     leest als haperen */
  .carousel > .art-card.rv { opacity: 1; transform: none; transition: none; }
  .carousel > .art-card { flex: 0 0 78%; margin-top: 0; scroll-snap-align: start; }
  /* in de carrousel telt alleen het werk: de interesse-knop staat verderop
     al bij de specificaties en maakt het hier alleen maar druk */
  .carousel .card-cta { display: none; }
  .dots { display: flex; gap: 8px; justify-content: center; padding-top: 20px; }
  .dots span {
    width: 8px; height: 8px; border-radius: 50%; background: var(--grey-soft);
    transition: background .25s ease, transform .25s ease;
  }
  .dots span.on { background: var(--ink); transform: scale(1.3); }
  .art-grid--three:not(.carousel) { grid-template-columns: 1fr; }
}

.art-card { position: relative; }
/* Een staand werk in een brede kolom werd hoger dan het scherm ("past niet in
   beeld", Johan). De kaart mag daarom niet breder worden dan wat bij een beeld
   van schermhoogte min de balken hoort; --ar is de verhouding van het werk. Hij
   blijft bovenaan staan en schuift naar het midden van zijn kolom. */
.art-card {
  --fit-h: calc(100vh - 260px);
  max-width: calc(var(--fit-h) * var(--ar, 1.5) + 2 * clamp(8px, 1.1vw, 18px) + 2px);
  justify-self: center; width: 100%;
}
@supports (height: 100svh) { .art-card { --fit-h: calc(100svh - 260px); } }
.art-card .mount {
  display: block;
  position: relative;
  background: var(--paper);
  border: 1px solid #ececee;
  padding: clamp(8px, 1.1vw, 18px);
  box-shadow: var(--shadow-card);
  transition: box-shadow .45s cubic-bezier(.2, .6, .2, 1);
}
.art-card:hover .mount {
  box-shadow: 0 1px 2px rgba(16, 16, 19, .05), 0 32px 68px -24px rgba(16, 16, 19, .36);
}
.art-card .mount img { width: 100%; display: block; }
.card-hit { position: absolute; inset: 0; z-index: 2; }
.card-name { margin-top: 14px; font-size: 1.05rem; letter-spacing: -.005em; }
.card-desc { margin-top: 2px; font-size: .9rem; font-style: italic; color: var(--grey); }
/* knop zweeft over het werk, zodat hij geen ruimte onder de kaart kost */
.card-cta {
  position: absolute; z-index: 3;
  left: clamp(8px, 1.1vw, 18px); bottom: clamp(8px, 1.1vw, 18px);
  padding: 7px 13px;
  background: rgba(255, 255, 255, .93);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  box-shadow: 0 1px 2px rgba(16, 16, 19, .12), 0 8px 20px -8px rgba(16, 16, 19, .35);
  font-size: .76rem; letter-spacing: .18em; text-transform: uppercase; color: #2c2c31;
  opacity: 0; transform: translateY(4px);
  transition: opacity .3s cubic-bezier(.5, 0, .15, 1), transform .3s cubic-bezier(.5, 0, .15, 1);
}
.art-card:hover .card-cta, .card-cta:focus-visible { opacity: 1; transform: translateY(0); }
.card-cta:hover { color: var(--ink); background: #fff; }
@media (hover: none) { .card-cta { opacity: 1; transform: none; } }

/* jaartallen-balk onder de header (werk-pagina) */
.yearbar {
  position: fixed; left: 0; right: 0; z-index: 49;
  pointer-events: none;              /* JS zet alleen gedokte links weer aan */
}
/* het balkvlak is een eigen laag: de jaartallen zelf zijn ook zichtbaar terwijl
   ze nog beneden in de index staan, het vlak verschijnt pas bij het eerste dok */
.yearbar::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: rgba(252, 252, 253, .9);
  -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px);
  box-shadow: 0 1px 0 var(--hairline);
  opacity: 0; transition: opacity .3s ease;
}
.yearbar.show::before { opacity: 1; }
.yb-inner {
  /* loopt net als de header van rand tot rand, zodat de twee balken uitlijnen */
  max-width: none; margin: 0 auto;
  /* verticale ruimte zit op de container, niet op de links: zo valt de bovenkant
     van een balklink samen met de bovenkant van het label in de lijst */
  padding: 13px var(--pad) 12px;
  display: flex; gap: var(--yb-gap, clamp(16px, 2.6vw, 32px));
  overflow: visible;                 /* de jaartallen vliegen buiten de balk */
  scrollbar-width: none;
}
.yb-inner::-webkit-scrollbar { display: none; }
.yearbar a {
  flex: 0 0 auto;
  padding: 0 0 3px;
  /* zelfde gewicht en spatiëring als het label in de lijst, zodat de
     geschaalde kopie bij vertrek exact op het origineel past.
     --yb-size wordt door site.js berekend: de jaartallen vullen de balk
     precies uit terwijl de tussenruimte onveranderd blijft */
  font-size: var(--yb-size, .9rem); font-weight: 300; letter-spacing: -.01em;
  color: #6d6d74; white-space: nowrap;
  border-bottom: 1px solid transparent;
  opacity: 0;                       /* JS stuurt transform + opacity per frame */
  transform-origin: left top;
  will-change: transform, opacity;
  transition: color .2s ease, border-color .2s ease;
}
.yearbar a:hover { color: var(--ink); }
.yearbar a.act { color: var(--ink); border-bottom-color: var(--ink); }
@media (max-width: 767px) {
  /* smal scherm: geen vliegende jaartallen maar een keuzewiel — het jaartal in
     het midden is geselecteerd, je veegt van periode naar periode */
  .yb-inner {
    padding: 10px 50vw 9px;          /* elk jaartal kan tot in het midden staan */
    gap: clamp(22px, 7vw, 34px);
    overflow-x: auto; overflow-y: hidden; overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory; -webkit-overflow-scrolling: touch;
    opacity: 0; transition: opacity .3s ease;
    -webkit-mask-image: linear-gradient(to right, transparent, #000 16%, #000 84%, transparent);
            mask-image: linear-gradient(to right, transparent, #000 16%, #000 84%, transparent);
  }
  .yearbar.show .yb-inner { opacity: 1; pointer-events: auto; }
  .yearbar a {
    /* geen scroll-snap-stop: één veeg mag meerdere jaren doorschieten, als een wiel */
    font-size: 1.02rem; scroll-snap-align: center;
    transform-origin: 50% 50%; padding: 0; will-change: transform, opacity;
    transition: color .2s ease;
  }
  .yearbar a.act { border-bottom-color: transparent; }
  /* het pilletje in het midden, zoals de keuzelijst van de wekker */
  .yearbar::after {
    content: ""; position: absolute; z-index: -1;
    left: 50%; top: 50%; transform: translate(-50%, -50%);
    width: var(--pil-w, 92px); height: 34px; border-radius: 999px;
    background: rgba(16, 16, 19, .055);
    opacity: 0; transition: width .24s cubic-bezier(.2, .7, .2, 1), opacity .3s ease;
  }
  .yearbar.show::after { opacity: 1; }
}
.period { scroll-margin-top: var(--anchor-off, 150px); }
/* een kaart is ook een ankerpunt (het submenu onder een jaartal linkt erheen),
   dus die moet net als een periode onder de twee balken landen */
.art-card { scroll-margin-top: var(--anchor-off, 150px); }

/* ---------- submenu onder een jaartal: de werken uit die periode ---------- */
/* Het paneel staat `fixed` en site.js zet het onder het jaartal waar je op
   staat. Waarom niet gewoon in de balk hangen: elk jaartal is een <a> die per
   scrollframe een eigen transform krijgt (de vlucht uit de index), en een
   paneel dáárin zou meeschalen — plus een link mag geen links bevatten. */
.yb-menu {
  position: fixed; left: 0; right: 0; z-index: 48;
  padding: 16px var(--pad) 20px;
  background: rgba(17, 17, 20, .95);
  -webkit-backdrop-filter: blur(16px); backdrop-filter: blur(16px);
  box-shadow: 0 1px 0 rgba(255, 255, 255, .06), 0 34px 60px -26px rgba(10, 10, 12, .55);
  animation: ybMenuIn .22s cubic-bezier(.2, .7, .2, 1) both;
}
.yb-menu[hidden] { display: none; }
@keyframes ybMenuIn { from { opacity: 0; transform: translateY(-8px) } to { opacity: 1; transform: none } }
.yb-kop {
  display: block; margin-bottom: 12px;
  font-size: .74rem; letter-spacing: .16em; text-transform: uppercase;
  color: rgba(255, 255, 255, .5);
}
/* Uitgevulde rijen: elk werk houdt zijn eigen verhouding (`--ar`) en krijgt
   ruimte naar zijn aard (`--w` — de grote werken meer dan een kleine studie).
   Doordat zowel de basis als de rek proportioneel aan ar x w zijn, komen alle
   werken in één rij op dezelfde hoogte uit zolang hun gewicht gelijk is, en is
   een staand werk dus smal en even hoog — geen witte randen ernaast. De rijen
   vullen zichzelf uit tot de volle breedte en wisselen daardoor van hoogte. */
.yb-rij {
  display: flex; flex-wrap: wrap; align-items: flex-end;
  gap: 10px; max-height: 54vh; overflow-y: auto;
}
/* De laatste rij is meestal niet vol. Zonder deze onzichtbare vuller zouden de
   paar werken die er staan alle overgebleven ruimte opeten en twee keer zo groot
   worden als de rest; nu slokt de vuller die ruimte op en houden ze hun maat. */
.yb-rij::after { content: ""; flex: 1000000 0 0; height: 0; }
.yb-thumb {
  position: relative; display: block; overflow: hidden;
  flex-grow: calc(var(--ar, 1.5) * var(--w, 1));
  flex-shrink: 1;
  flex-basis: calc(var(--ar, 1.5) * var(--w, 1) * 62px);
  aspect-ratio: var(--ar, 1.5);
  background: rgba(255, 255, 255, .06);
  outline: 1px solid rgba(255, 255, 255, .12); outline-offset: -1px;
}
.yb-thumb img {
  width: 100%; height: 100%; display: block; object-fit: cover;
  transition: transform .35s cubic-bezier(.2, .6, .2, 1), opacity .25s ease;
  opacity: .88;
}
.yb-thumb:hover img, .yb-thumb:focus-visible img { opacity: 1; transform: scale(1.04); }
.yb-thumb:focus-visible { outline: 2px solid #fff; outline-offset: 1px; }
/* het nummer ligt in het beeld en komt alleen op bij hover: zo blijft de rij
   een rij beelden en niet een tabel met labels */
.yb-nr {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: 14px 8px 6px;
  background: linear-gradient(to top, rgba(10, 10, 12, .8), rgba(10, 10, 12, 0));
  font-size: .74rem; color: #fff; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
  opacity: 0; transition: opacity .2s ease;
}
.yb-thumb:hover .yb-nr, .yb-thumb:focus-visible .yb-nr { opacity: 1; }
/* op een aanraakscherm is er geen hover, en daar is de balk een keuzewiel */
@media (hover: none), (max-width: 767px) { .yb-menu { display: none; } }

/* Aangekomen bij een werk: even een ring eromheen, dan weer weg. Zonder dat
   weet je na een sprong van een halve pagina niet wélk werk je zocht. */
@keyframes kaartGevonden {
  0%   { opacity: 0; box-shadow: 0 0 0 2px rgba(16, 16, 19, .9), 0 0 0 14px rgba(16, 16, 19, 0); }
  14%  { opacity: 1; box-shadow: 0 0 0 2px rgba(16, 16, 19, .9), 0 0 0 12px rgba(16, 16, 19, .10); }
  62%  { opacity: 1; box-shadow: 0 0 0 2px rgba(16, 16, 19, .85), 0 0 0 12px rgba(16, 16, 19, .07); }
  100% { opacity: 0; box-shadow: 0 0 0 2px rgba(16, 16, 19, 0), 0 0 0 22px rgba(16, 16, 19, 0); }
}
.art-card.gevonden .mount::after {
  content: ""; position: absolute; inset: -5px; z-index: 3; pointer-events: none;
  animation: kaartGevonden 2.4s cubic-bezier(.2, .6, .2, 1) both;
}
@media (prefers-reduced-motion: reduce) {
  .yb-menu { animation: none; }
  .art-card.gevonden .mount::after { animation: kaartGevonden 2.4s steps(1, end) both; }
}
@media (prefers-reduced-motion: reduce) {
  .yearbar::before, .yearbar a { transition: none; transform: none; }
}

/* periode-index (home + werk) */
.period-index { border-top: 1px solid var(--hairline); }
.period-index a {
  display: flex; align-items: baseline; justify-content: space-between; gap: 16px;
  padding: 15px 2px; border-bottom: 1px solid var(--hairline);
  transition: padding .25s ease;
}
.period-index a:hover { padding-left: 10px; }
/* ruim groter dan de balkmaat: het jaartal moet onderweg zichtbaar krimpen */
.period-index .p-label { font-size: clamp(1.5rem, 3.1vw, 2.9rem); font-weight: 300; letter-spacing: -.01em; }
.period-index .p-count { font-size: .9rem; font-style: italic; color: var(--grey); }

/* ---------- detailpagina ---------- */
.work-hero { padding-top: clamp(110px, 14vh, 160px); }
.backlink { margin-bottom: clamp(20px, 3vw, 36px); display: inline-flex; }
.backlink::before { content: "\2190"; margin-right: .7em; transition: transform .25s ease; }
.backlink:hover::before { transform: translateX(-5px); }
.back-arrowless::after { content: none; }
.work-stage { max-width: 1160px; margin: 0 auto; }
.work-stage img { margin: 0 auto; max-height: 82vh; width: auto; max-width: 100%; }
.work-title-row {
  display: flex; align-items: baseline; justify-content: space-between; gap: 20px; flex-wrap: wrap;
  padding: clamp(40px, 6vw, 72px) 0 0;
}
.work-title { font-size: clamp(2rem, 4.6vw, 3.6rem); font-weight: 300; letter-spacing: -.02em; margin: 0; }
.work-sub { font-size: 1rem; font-style: italic; color: var(--grey); }

.story { max-width: 660px; padding-top: clamp(28px, 4vw, 48px); padding-bottom: clamp(48px, 7vw, 88px); }
.story p { font-size: 1.12rem; line-height: 1.8; color: #2c2c31; }
.story p:first-of-type::first-letter { }

/* pull-quote */
.pull {
  padding-top: clamp(64px, 11vw, 150px);
  padding-bottom: clamp(64px, 11vw, 150px);
  text-align: center;
}
.pull blockquote {
  margin: 0 auto; max-width: 1000px;
  font-family: var(--hand);
  font-size: clamp(1.85rem, 4.2vw, 3.3rem);
  font-weight: 400; font-style: normal; letter-spacing: 0; line-height: 1.34;
  color: var(--ink);
  text-wrap: balance;
}
.pull .who {
  display: block; margin-top: 1.1em;
  font-family: var(--font); font-size: .8rem; font-weight: 400; font-style: normal;
  letter-spacing: .24em; text-transform: uppercase; color: var(--grey);
}

/* ---------- aan de muur: een echte kamer uit de presentatie-PDF's ---------- */
.wall { display: block; }
.wall .scene-crop { aspect-ratio: 16 / 9; }
/* De kamerfoto is een werk uit de catalogus, geen decoratie: daarom hetzelfde
   bijschrift eronder als onder een kaart in het raster. Zonder dat leest
   niemand het als iets waar je op kunt klikken. */
.wall-hit { display: block; position: relative; }
.wall-cap {
  display: flex; align-items: baseline; gap: .9em 1.4em; flex-wrap: wrap;
  padding-top: 16px;
}
.wall-cap .card-name { margin-top: 0; }
.wall-cap .card-desc { margin-top: 0; }
.wall-note {
  margin-left: auto;
  font-size: .8rem; letter-spacing: .16em; text-transform: uppercase;
  color: var(--grey-soft);
}
@media (max-width: 559px) {
  .wall-cap { gap: 2px; }
  .wall-cap .card-desc { flex: 1 0 100%; }
  .wall-note { margin-left: 0; flex: 1 0 100%; padding-top: 6px; }
}
.install { margin: clamp(40px, 6vw, 90px) 0; }
/* de kamerbeelden tussen de series zijn op een telefoon een lange omweg
   tussen het werk door; op een groot scherm geven ze juist rust */
@media (max-width: 767px) { .install-serie { display: none; } }
/* Op een werkpagina staat de kamerfoto precies zo breed als de twee uitsnedes
   erboven, met dezelfde witrand ernaast als ertussen (`--duo-gap`). Dus niet
   van rand tot rand: die drie beelden horen als één blok te lezen. */
.wall-werk { margin: 0 var(--duo-gap) clamp(40px, 6vw, 90px); }

/* De lijst uit 'Lijst 160 x 95 cm.svg'. Buiten naar binnen: het profiel
   (1,5 cm van de 160 = 0,94% van de breedte, grijs verloop uit de tekening),
   dan de passe-partout in #f6f6f3, dan pas het werk. De maten van de
   passe-partout staan in procenten van de binnenmaat, dus ze kloppen op elk
   formaat. build.py zet de profielbreedte inline (procenten rekenen anders
   tegen de ouder in plaats van tegen de lijst zelf). */
.frame {
  display: block;
  background: linear-gradient(150deg, #e9e9e9 0%, #d3d3d3 38%, #acacac 58%, #e4e4e4 100%);
  box-shadow:
    0 0 0 1px rgba(0, 0, 0, .16),
    0 1px 2px rgba(22, 22, 28, .12),
    0 10px 18px -8px rgba(22, 22, 28, .2),
    0 40px 60px -28px rgba(22, 22, 28, .36);
}
.mat {
  display: block;
  background: #f6f6f3;
  /* boven 286, opzij 241, onder 507 eenheden van de 4450 binnenbreedte */
  padding: 6.43% 5.42% 11.4%;
}
.mat img { width: 100%; display: block; box-shadow: 0 0 0 1px rgba(0, 0, 0, .1); }

/* ---------- detail-hero: het werk beeldvullend, titel eroverheen ---------- */
.hero-cover {
  position: relative;
  height: 100svh; min-height: 460px;
  overflow: hidden;
  background: #101013;
}
.hero-cover .hc-img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  animation: heroSettle 1.8s cubic-bezier(.16, .7, .2, 1) both paused;
}
html.intro-klaar .hero-cover .hc-img { animation-play-state: running; }
.hc-scrim {
  position: absolute; inset: 0;
  background: linear-gradient(to bottom, rgba(8, 10, 13, .34) 0%, rgba(8, 10, 13, .06) 34%, rgba(8, 10, 13, .52) 100%);
}
/* De terugweg staat op een willekeurig stuk aquarel, licht of donker. Daarom
   geen witte letters met een schaduwtje maar een echt wit knopje: leesbaar
   op elk werk, en meteen herkenbaar als iets waar je op kunt klikken. */
.hc-back {
  position: absolute; top: clamp(76px, 11vh, 110px); left: var(--pad);
  display: inline-flex; align-items: center; gap: .7em;
  padding: 11px 20px;
  background: rgba(255, 255, 255, .94);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  box-shadow: 0 1px 2px rgba(16, 16, 19, .14), 0 10px 26px -10px rgba(16, 16, 19, .45);
  font-size: .84rem; letter-spacing: .16em; text-transform: uppercase;
  color: var(--ink);
  transition: background .25s ease, transform .25s ease;
}
.hc-back:hover { background: #fff; transform: translateX(-3px); }
.hc-foot {
  position: absolute; left: var(--pad); right: var(--pad); bottom: clamp(24px, 5vh, 56px);
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 20px; flex-wrap: wrap;
}
.hc-title {
  margin: 0;
  font-size: clamp(2.2rem, 5.4vw, 4.4rem);
  font-weight: 700; letter-spacing: -.02em; line-height: 1;
  color: #fff; text-shadow: 0 2px 34px rgba(0, 0, 0, .45);
}
.hc-sub {
  display: block; margin-top: .35em;
  font-size: .34em; font-weight: 300; font-style: italic; letter-spacing: 0;
  color: rgba(255, 255, 255, .85);
}
.hc-cap { color: rgba(255, 255, 255, .85); }
/* Zelfde hero als op een werkpagina, maar voor een pagina-opening. Het
   geschilderde portret is liggend (±1,76:1) en het hoofd zit rechts van het
   midden en in de bovenhelft — vandaar de object-position, zodat het gezicht
   ook op een telefoon (waar hard wordt bijgesneden) in beeld blijft. */
.hero-page { height: min(88svh, 860px); }
/* het hoofd zit in het schilderij (1672 x 941) rond 62% breed en 38% hoog */
.hero-page .hc-img { object-position: 62% 38%; animation-duration: 2.2s; }
/* de paginatitel mag groter dan die op een werkpagina: daar staat een nummer,
   hier het woord waar de pagina over gaat */
.hero-page .hc-title { font-size: clamp(2.7rem, 6.8vw, 5.6rem); }
/* de ondertitel niet in em van de titel: met een grotere titel werd hij op een
   telefoon 11px, en dat is te klein voor dit publiek. Dus een eigen maat. */
.hero-page .hc-sub { font-size: clamp(1rem, .85rem + .6vw, 1.36rem); }
/* De opening van Exposities is een montage: de zaalfoto met het werk in zijn
   lijst eroverheen. De uitsnede rekent site.js uit (heroZaal), want die moet
   per schermformaat anders vallen — de lijst moet altijd heel in beeld staan.
   Tot dat gerekend is dekt de foto de bak op de gewone manier. */
.hero-zaal .hero-scene {
  position: absolute; inset: 0; aspect-ratio: auto;
  background: var(--paper); overflow: hidden;
}
.hero-zaal .scene-photo { width: 100%; left: 0; top: 0; }
.hero-zaal .scene-room { width: 100%; }
/* De salie zit nu in de foto zelf (de zaal is zo gegenereerd), dus geen
   tintlaag meer. Het wandje blijft staan als haakje: wil je de kleur ooit
   bijsturen, dan komt hier weer een multiply-laag met isolation: isolate —
   dat sluit het blenden op in de foto, zodat de aquarel eronder niet meekleurt. */
.hero-zaal .zaal-wand { display: block; position: relative; }
/* Deze hero is exact even hoog als die van Biografie: hij erft `.hero-page`
   (88svh, max 860px) en krijgt hier bewust geen eigen hoogte meer. Op een breed,
   plat scherm gaat er dus hoogte van de foto af — welk stuk dat is, kiest
   `heroZaal()` in site.js: de lijsten blijven daar verticaal in het midden. */
/* Op de brede wand hangen meerdere werken, op een telefoon één — daar is de
   wand simpelweg te smal. De <picture> wisselt de foto, deze regels wisselen
   welke lijsten je ziet. Houd de grens gelijk aan die van de <source> én aan
   de matchMedia in site.js. */
.hero-zaal .hero-kunst--mobiel { display: none; }
@media (max-width: 640px) {
  .hero-zaal .hero-kunst { display: none; }
  .hero-zaal .hero-kunst--mobiel { display: block; }
}
/* Diepte. Een lijst hangt niet plat op een wand: er zit lucht achter, en het
   licht komt hier van linksboven (zie de helderheidsval naar rechts in de
   foto). Vier lagen doen het werk:
     1. een haarlijn rondom, zodat de rand zich aftekent;
     2. een contactschaduw pal onder de lijst — dat 'plakt' hem aan de wand;
     3. een korte slagschaduw naar rechtsonder: de dikte van de lijst;
     4. een brede, zachte schaduw die de wand eronder laat inzakken.
   Plus een lichtlijntje bovenop het profiel, want daar valt het licht op. */
.hero-zaal .scene-frame .frame {
  box-shadow:
    0 0 0 1px rgba(30, 34, 24, .20),
    0 3px 3px -2px rgba(30, 34, 24, .46),
    7px 11px 11px -6px rgba(30, 34, 24, .30),
    22px 36px 48px -18px rgba(30, 34, 24, .40),
    inset 0 1px 0 rgba(255, 255, 255, .60),
    inset -1px 0 0 rgba(0, 0, 0, .07);
}
/* De onderrand loopt weg in het donker, zodat de witte titel daar iets achter
   zich heeft. Boven de 60% blijft de laag volledig transparant: de lijsten
   houden hier op ±56% op, en over een aquarel mag geen sluier — die moet
   kleurecht blijven. Onderaan staat alleen vloer, en een zaal die onderin
   inzakt is precies wat een zaal doet. */
.hero-licht .hc-scrim {
  background: linear-gradient(to bottom,
    rgba(20, 23, 16, 0) 60%, rgba(20, 23, 16, .52) 100%);
}
/* Boven de saliegroene zaal staat de header in het WIT. Op kleur alleen zou dat
   niet lukken: die wand (#afb3a3) zit qua helderheid precies tussen zwart en
   wit in, dus wit haalt er maar ~1,6:1 — te weinig om te lezen. De schaduw doet
   hier dus het werk, niet de kleur: een harde van 1px die de letterrand
   aftekent en een zachte pool eronder. Zo staat er lokaal een donkere wand
   achter elke letter en blijft het wit rustig; over de schilderijen komt géén
   sluier, want die moeten kleurecht blijven. */
.site-head.over-hero-licht .site-nav a {
  color: rgba(255, 255, 255, .88);
  text-shadow: 0 1px 2px rgba(20, 23, 16, .55), 0 1px 14px rgba(20, 23, 16, .5);
}
.site-head.over-hero-licht .site-nav a:hover { color: #fff; }
.site-head.over-hero-licht .site-nav a[aria-current="page"] {
  color: #fff; border-bottom-color: rgba(255, 255, 255, .8);
}
.site-head.over-hero-licht .wordmark {
  text-shadow: 0 1px 2px rgba(20, 23, 16, .5), 0 2px 18px rgba(20, 23, 16, .55);
}
.site-head.over-hero-licht .wordmark strong { color: rgba(255, 255, 255, .95); }
.site-head.over-hero-licht .wordmark span { color: rgba(255, 255, 255, .78); }
.site-head.over-hero-licht .menu-knop span {
  background: #fff; box-shadow: 0 1px 3px rgba(20, 23, 16, .5);
}
/* Titel en ondertitel ook in het wit. Ze staan onderaan, deels op de lichte
   vloer, dus ze leunen op dezelfde twee schaduwen als de header plus de
   verdonkerde onderrand van de scrim hierboven. */
.hero-licht .hc-title {
  color: #fff;
  text-shadow: 0 1px 3px rgba(20, 23, 16, .45), 0 3px 30px rgba(20, 23, 16, .6);
}
.hero-licht .hc-sub { color: rgba(255, 255, 255, .86); }
.hero-licht .scrollhint { color: rgba(255, 255, 255, .8); }
.hero-page-hint {
  position: absolute; left: 50%; transform: translateX(-50%);
  bottom: clamp(12px, 2vh, 22px); margin-top: 0;
}
@media (max-width: 640px) {
  .hero-page { height: min(72svh, 620px); }
  /* de zaalfoto is 4:3; op een telefoon minder hoog, anders knijpt de uitsnede
     zo hard dat de lijst tot de rand komt en er geen wand meer naast staat */
  .hero-zaal { height: min(60svh, 500px); }
  /* Op een telefoon komt de vierkante versie binnen (zie <picture>). Het hoofd
     zit daar rond 58% van de breedte; met object-position 58% landt het dus
     ook op 58% van het scherm, en dat staat scheef. Er wordt ruim 200px
     afgesneden, dus met 71% schuift het beeldvenster net genoeg op om het
     hoofd midden in beeld te zetten. */
  .hero-page .hc-img { object-position: 71% 38%; }
}
.hc-cap .sep { color: rgba(255, 255, 255, .45); }
@media (prefers-reduced-motion: reduce) {
  .hero-full .hero-bg, .hero-cover .hc-img { animation: none; }
}

/* ---------- wt: het werk aan een gekleurde wand + verhaal ernaast ---------- */
.wt { padding: clamp(56px, 8vw, 110px) var(--pad); }
.wt-inner {
  max-width: var(--maxw); margin: 0 auto;
  display: grid; gap: clamp(36px, 5vw, 88px);
  align-items: center;
}
@media (min-width: 960px) {
  .wt-inner { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); }
}
.wt-fig { margin: 0; }
/* geen kleurvlak: de lijst hangt op wit en dankt zijn diepte aan de schaduw —
   een contactschaduw vlak onder de lijst plus een brede, zachte slagschaduw */
.wt-tile {
  position: relative;
  display: grid; place-items: center;
  padding: clamp(20px, 3.5vw, 56px) clamp(4px, 1.5vw, 24px);
}
.wt-tile .frame {
  position: relative; z-index: 1;
  /* nooit hoger dan het scherm: --far (uit build.py) is breedte/hoogte van de lijst */
  max-width: calc((100vh - 170px) * var(--far, 1.4));
}
@supports (height: 100svh) { .wt-tile .frame { max-width: calc((100svh - 170px) * var(--far, 1.4)); } }
/* Op een telefoon krijgt de lijst bijna de hele breedte: de breedtes uit
   build.py (88/76/56%) zijn voor een kolom naast de tekst bedoeld, en daar
   bleef een staand werk op een telefoon te klein. De schermhoogte begrenst hem
   nog steeds (max-width hierboven). */
@media (max-width: 767px) { .wt-tile .frame { width: 92% !important; } }
/* geen tekst bij dit werk: dan hangt het alleen, in het midden */
.wt--solo .wt-inner { grid-template-columns: minmax(0, 1fr); max-width: 1100px; }
.wt--solo .wt-text { display: none; }

/* Alles wat je kunt vergroten is een knop zonder knop-uiterlijk: de lijst op de
   werkpagina, de twee detailvakken en de kamerfoto eronder. */
.loep {
  display: block; width: 100%; position: relative;
  margin: 0; padding: 0; border: 0; background: none;
  font: inherit; color: inherit; cursor: zoom-in;
}
.wt-tile .loep .frame { margin-inline: auto; }
.loep-hint {
  /* de lijst zelf staat op z-index 1, dus het hintje moet daar overheen */
  position: absolute; z-index: 2; left: 50%; bottom: clamp(-8px, -.6vw, -2px);
  transform: translate(-50%, 6px);
  padding: 10px 20px; background: rgba(16, 16, 19, .9);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  box-shadow: 0 10px 26px -10px rgba(16, 16, 19, .5);
  font-size: .78rem; letter-spacing: .16em; text-transform: uppercase; color: #fff;
  white-space: nowrap; pointer-events: none;
  opacity: 0; transition: opacity .28s ease, transform .28s ease;
}
.loep:hover .loep-hint, .loep:focus-visible .loep-hint { opacity: 1; transform: translate(-50%, 0); }
@media (hover: none) { .loep-hint { display: none; } }

/* ---------- loep: het werk schermvullend ---------- */
.loepbak {
  --loep-rand: clamp(14px, 2.4vw, 46px);
  position: fixed; inset: 0; z-index: 90;
  /* flex en niet grid: in een grid is de rij automatisch hoog, en dan valt
     max-height: 100% op de plaat weg — precies waardoor het werk op een breed,
     laag scherm onderaan werd afgesneden. In flex rekent die procent tegen de
     vaste hoogte van deze laag, dus past het altijd. */
  display: flex; align-items: center; justify-content: center;
  padding: var(--loep-rand);
  background: rgba(252, 252, 253, .97);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  cursor: zoom-out;
  animation: loepIn .2s ease both;
}
.loepbak[hidden] { display: none; }
.loep-plaat {
  /* Zo groot als er past, ook als het bestand kleiner is. Eerst gold hier
     'nooit boven de eigen resolutie', maar dan stond een scan van 650px als een
     postzegel midden op een leeg scherm — en dat is erger dan een beetje korrel.
     De maat zet site.js (`pasLoep`) in pixels: puur met CSS lukt het niet, want
     `width: 100%` schaalt wél op maar dan klemt max-height de hoogte zonder de
     breedte terug te rekenen — een staand werk werd zo een breed wit vlak met
     het schilderij klein in het midden. Deze max-regels blijven als vangnet. */
  width: auto; height: auto; flex: 0 0 auto; min-width: 0;
  max-width: min(100%, calc(100vw - 2 * var(--loep-rand)));
  max-height: min(100%, calc(100svh - 2 * var(--loep-rand)));
  object-fit: contain; background: #fff;
  box-shadow: 0 2px 4px rgba(16, 16, 19, .08), 0 40px 90px -30px rgba(16, 16, 19, .45);
  animation: loepUit .3s cubic-bezier(.2, .7, .2, 1) both;
}
/* Uitgelicht: klik je op een detailvak, dan komt het HELE schilderij in beeld —
   groot genoeg dat het meestal buiten het scherm doorloopt — met alleen dat ene
   stuk in het licht. De rest blijft donker zichtbaar, zodat je ziet waar je
   naar kijkt. Alles staat hier absoluut (site.js rekent de plek uit), dus de
   flexbox en de padding van de gewone loep gaan eraf. */
.loepbak--spot {
  display: block; padding: 0; overflow: hidden;
  background: rgba(14, 14, 17, .55);
}
.loepbak--spot .loep-plaat {
  position: absolute; max-width: none; max-height: none;
  background: none; box-shadow: none; animation: none;
}
/* het lichte vak zelf: de schaduw eromheen dempt de hele rest in één keer */
.loep-spot {
  position: absolute; pointer-events: none;
  box-shadow:
    0 0 0 1px rgba(255, 255, 255, .5),
    0 0 0 100vmax rgba(10, 10, 12, .66);
}
.loepbak:not(.loepbak--spot) .loep-spot { display: none; }
.loep-sluit {
  position: fixed; top: clamp(12px, 2vw, 26px); right: clamp(12px, 2vw, 26px);
  width: 56px; height: 56px; border-radius: 50%;
  display: grid; place-items: center; cursor: pointer;
  border: 1px solid var(--hairline); background: #fff; color: var(--ink);
  box-shadow: var(--shadow-card);
  transition: transform .2s ease, background .2s ease;
}
.loep-sluit svg { width: 20px; height: 20px; }
.loep-sluit:hover { transform: rotate(90deg); background: var(--mist); }
@keyframes loepIn { from { opacity: 0 } to { opacity: 1 } }
@keyframes loepUit { from { opacity: 0; transform: scale(.965) } to { opacity: 1; transform: none } }
@media (prefers-reduced-motion: reduce) {
  .loepbak, .loep-plaat { animation: none; }
  .loep-sluit:hover { transform: none; }
}
.wt-text p { font-size: 1.1rem; line-height: 1.75; color: #2c2c31; }

/* de belangrijkste knop van de site: iets steviger dan de rest, met een
   pijl die meeschuift zodat duidelijk is dat er iets achter zit */
.enquire {
  display: inline-flex; align-items: center; gap: .9em; margin-top: 26px;
  padding: 17px 34px;
  background: var(--ink); color: var(--paper);
  font-size: .86rem; letter-spacing: .2em; text-transform: uppercase;
  box-shadow: 0 2px 4px rgba(16, 16, 19, .12), 0 16px 30px -14px rgba(16, 16, 19, .5);
  transition: background .25s ease, box-shadow .25s ease, transform .25s ease;
  border: 0; cursor: pointer; font-family: var(--font);
}
.enquire::after {
  content: "\2192"; font-size: 1.15em; line-height: 0;
  transition: transform .25s cubic-bezier(.2, .7, .2, 1);
}
.enquire:hover {
  background: #26262c;
  box-shadow: 0 2px 4px rgba(16, 16, 19, .14), 0 22px 40px -16px rgba(16, 16, 19, .55);
  transform: translateY(-1px);
}
.enquire:hover::after { transform: translateX(5px); }

/* ---------- duo: woonkamer-impressie + detail, naast elkaar ---------- */
/* twee even grote beelden, van rand tot rand — de kamerfoto en de uitsnede
   worden allebei op hetzelfde vierkant bijgesneden (Goodman-formaat) */
.duo-sec {
  padding: clamp(20px, 3vw, 44px) var(--duo-gap) var(--duo-gap);
}
.duo { display: grid; gap: var(--duo-gap); align-items: start; }
@media (min-width: 800px) { .duo { grid-template-columns: 1fr 1fr; } }
.duo figure { margin: 0; }
.duo .cap { display: block; text-align: right; padding-top: 12px; }
.scene { position: relative; }
.scene-crop, .crop-box {
  display: block; position: relative; overflow: hidden;
  aspect-ratio: 1 / 1; background: var(--mist);
}
.scene-photo { position: absolute; display: block; }
.crop-box img { position: absolute; max-width: none; }
/* een los fragment (webbeelden.py) is precies dit vak: gewoon vullen */
.crop-box img.frag { inset: 0; width: 100%; height: 100%; object-fit: cover; }
.scene-room { width: 100%; display: block; }
/* Interieurfoto's van Ruben waar het werk al in hangt: geen montage, dus geen
   lagen om te verschuiven — de foto vult de bak en de uitsnede is gecentreerd.
   Dat kan omdat de lijst op alle elf rond het midden hangt: in de 16:9-band
   gaat er alleen boven en onder iets af, in het vierkant links en rechts. */
.scene-vol {
  position: absolute; inset: 0; display: block;
  width: 100%; height: 100%; object-fit: cover; object-position: center;
}
/* alleen positioneren — de lijst zelf komt uit .frame */
.scene-frame { position: absolute; transform: translate(-50%, -50%); }
.scene-frame .frame {
  box-shadow:
    0 0 0 1px rgba(0, 0, 0, .2),
    0 1px 2px rgba(0, 0, 0, .22),
    0 14px 26px -10px rgba(0, 0, 0, .5);
}

/* ---------- contactformulier ---------- */
/* Geen uitleg eromheen: een formulier met een naam, een adres en een bericht
   spreekt voor zich. Alleen een kop erboven, en het kiezen van een werk gebeurt
   met beelden in plaats van met woorden. */
.cform-sec { padding-bottom: clamp(56px, 9vw, 120px); }
.cform-sec .sec-title { margin: 0 0 clamp(22px, 3vw, 34px); }
.cform { max-width: 720px; }
/* de valstrik voor spam: onzichtbaar, maar niet met display:none — dan vullen
   sommige robots hem juist niet in */
.cf-val { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
/* de stand van het versturen, meteen onder de knop */
.cform-stand {
  margin: 1em 0 0; max-width: 46ch; line-height: 1.6; font-size: .95rem; color: #4a4a50;
}
.cform-stand:empty { display: none; }
.cform-stand.is-ok { color: var(--ink); }
.cform-stand.is-fout { color: #8a2b2b; }
.cform-stand .arrowlink { margin-top: .5em; }
.cform .enquire[disabled] { opacity: .55; cursor: default; transform: none; }

.cform label {
  display: block; margin-bottom: 18px;
  font-size: .8rem; letter-spacing: .2em; text-transform: uppercase; color: var(--grey);
}
.cform input, .cform textarea {
  display: block; width: 100%; margin-top: 8px;
  padding: 11px 14px;
  font: inherit; font-size: 1.05rem; color: var(--ink);
  background: var(--paper);
  border: 1px solid var(--hairline); border-radius: 0;
  letter-spacing: normal; text-transform: none;
}
.cform input:focus, .cform textarea:focus { outline: none; border-color: var(--ink); }
.cf-two { display: grid; gap: 0 20px; }
@media (min-width: 640px) { .cf-two { grid-template-columns: 1fr 1fr; } }
.cf-works { margin-bottom: 18px; }
.chips { display: flex; flex-wrap: wrap; gap: 8px; margin: 8px 0; }
.chips:empty { margin: 4px 0 0; }
.chip {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 6px 10px 6px 12px;
  border: 1px solid #d6d6db; background: var(--mist);
  font-size: .9rem; letter-spacing: normal; text-transform: none; color: var(--ink);
}
.chip button {
  border: 0; background: none; cursor: pointer; padding: 0;
  font-size: 1rem; line-height: 1; color: var(--grey); font-family: inherit;
}
.chip button:hover { color: var(--ink); }
/* Werk kiezen doe je door het aan te klikken. Het zoekveld erboven filtert dit
   raster — het is dus geen tweede manier van kiezen, alleen een kortere weg naar
   het juiste werk. De beelden zijn uitsnedes (cover): in een vakje van 90px
   leest een hele panorama-aquarel toch niet, en zo staan er geen witte randen
   naast een staand werk. */
.cf-kop {
  display: block; margin-bottom: 10px;
  font-size: .8rem; letter-spacing: .16em; text-transform: uppercase; color: var(--grey);
}
.cf-kop em { font-style: normal; letter-spacing: .1em; color: var(--grey-soft); }
.werkraster {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(84px, 1fr));
  gap: 6px; margin-top: 10px;
  max-height: 262px; overflow-y: auto;
  padding: 8px; border: 1px solid var(--hairline); background: var(--mist);
}
.wk {
  position: relative; display: block; padding: 0; border: 0; background: none;
  cursor: pointer; font: inherit; line-height: 0;
}
.wk img {
  width: 100%; aspect-ratio: 3 / 2; object-fit: cover; display: block;
  background: var(--paper); transition: opacity .2s ease;
}
.wk > span {          /* het nummer, alleen bij hover of als hij aan staat */
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: 10px 4px 3px; background: linear-gradient(to top, rgba(10,10,12,.78), rgba(10,10,12,0));
  font-size: .68rem; line-height: 1.2; color: #fff; letter-spacing: normal;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  opacity: 0; transition: opacity .2s ease;
}
.wk:hover > span, .wk:focus-visible > span, .wk.is-uit > span { opacity: 1; }
.wk:hover img { opacity: .82; }
.wk:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
/* gekozen: een duidelijke rand plus een vinkje in de hoek */
.wk.is-uit img { outline: 2px solid var(--ink); outline-offset: -2px; }
.wk.is-uit::after {
  content: "✓"; position: absolute; top: 4px; right: 4px;
  width: 20px; height: 20px; border-radius: 50%;
  background: var(--ink); color: #fff;
  font-size: .72rem; line-height: 20px; text-align: center;
}
.wk[hidden] { display: none; }

/* Installatiebeeld: brede band met de lijst erin. GEEN min-height meer — de
   16:9-verhouding op .scene-crop bepaalt de hoogte. Die min-height stamde uit
   de tijd van de schermhoge gekleurde wand en liet op een telefoon een half
   scherm wit onder de kamerfoto staan (band 211px, min-height 88vh = 715px). */


/* ---------- specificaties ---------- */
/* de gegevens lopen als één regel van marge tot marge, met de knop rechts —
   als het kaartje naast een werk in een zaal, niet als een blok in het midden */
.specs {
  padding-top: clamp(26px, 3.4vw, 46px);
  padding-bottom: clamp(56px, 8vw, 100px);
  display: grid; gap: clamp(22px, 3vw, 44px);
  align-items: end;
}
.specs dl {
  margin: 0; display: grid; gap: clamp(16px, 2vw, 34px);
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  border-top: 1px solid var(--hairline);
  padding-top: clamp(18px, 2.2vw, 30px);
}
.specs .row { min-width: 0; }
.specs dt {
  font-size: .8rem; letter-spacing: .2em; text-transform: uppercase;
  color: var(--grey); margin-bottom: 7px;
}
.specs dd { margin: 0; font-size: 1.05rem; }
@media (min-width: 900px) {
  .specs { grid-template-columns: minmax(0, 1fr) auto; }
}
.specs dd a { border-bottom: 1px solid var(--grey-soft); transition: border-color .2s ease; }
.specs dd a:hover { border-bottom-color: var(--ink); }

/* ---------- vorige / volgende ---------- */
.prevnext {
  display: grid; grid-template-columns: 1fr 1fr; gap: 1px;
  background: var(--hairline); border-top: 1px solid var(--hairline); border-bottom: 1px solid var(--hairline);
}
.prevnext a {
  background: var(--page); padding: clamp(24px, 4vw, 44px) var(--pad);
  display: flex; flex-direction: column; gap: 6px;
  transition: background .25s ease;
}
.prevnext a:hover { background: var(--mist); }
.prevnext .dir { font-size: .78rem; letter-spacing: .22em; text-transform: uppercase; color: var(--grey); }
.prevnext .name { font-size: 1.1rem; font-weight: 300; letter-spacing: -.01em; }
.prevnext a.next { text-align: right; align-items: flex-end; }
.prevnext a.empty { pointer-events: none; opacity: .35; }

/* ---------- over / lijsten ---------- */
.page-head { padding-top: clamp(120px, 16vh, 190px); padding-bottom: clamp(20px, 4vw, 44px); }
.page-title { font-size: clamp(2.4rem, 6vw, 4.6rem); font-weight: 300; letter-spacing: -.025em; line-height: 1.04; margin: 0 0 .3em; }
.page-intro { max-width: 640px; font-size: 1.14rem; color: #4a4a50; }

.prose { max-width: 660px; }
.prose p { font-size: 1.12rem; line-height: 1.8; color: #2c2c31; }
.prose h2 { font-size: 1.5rem; font-weight: 500; letter-spacing: -.01em; margin: 2.2em 0 .7em; }

/* ---------- tijdlijn ----------
   Was een tabelletje van jaartal + regel; dat las als een spoorboekje. Nu een
   ruggengraat met per regel een waterverf-vlek, een lijnicoon en het jaartal
   als anker. De vlek is een zachte grijze wash (radial-gradient), dus geen
   accentkleur — de aquarellen blijven de kleur van de site. */
/* na een hero begint de tekst direct; de kop zit al in het beeld */
.hero-page + .page-head { padding-top: clamp(40px, 6vw, 76px); }
.tijdlijn { max-width: 820px; position: relative; }
.tl-rij {
  position: relative;
  display: grid; grid-template-columns: 46px 1fr; gap: 0 20px;
  padding: 0 0 clamp(26px, 3.4vw, 40px);
}
.tl-rij:last-child { padding-bottom: 0; }
/* de ruggengraat loopt van vlek tot vlek, niet door de laatste heen */
.tl-rij::before {
  content: ""; position: absolute; left: 22px; top: 40px; bottom: 0;
  border-left: 1px solid var(--hairline);
}
.tl-rij:last-child::before { display: none; }
/* de vlek: een harde witte schijf met haarlijn, met een zachte wash eronder */
.tl-merk {
  grid-row: span 2; align-self: start;
  position: relative; z-index: 1;
  width: 44px; height: 44px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--paper); border: 1px solid var(--hairline);
  color: #33333b;
}
.tl-merk::before {
  content: ""; position: absolute; inset: -9px; border-radius: 50%; z-index: -1;
  background: radial-gradient(circle at 42% 38%,
    rgba(16, 16, 19, .13) 0%, rgba(16, 16, 19, .07) 46%, rgba(16, 16, 19, 0) 72%);
}
.tl-jaar {
  align-self: center;
  font-size: clamp(1.35rem, 2.4vw, 1.9rem); font-weight: 300;
  letter-spacing: -.02em; line-height: 1.1;
  min-height: 44px; display: flex; align-items: center;
}
.tl-wat {
  grid-column: 2; padding-top: 6px;
  font-size: 1.08rem; line-height: 1.65; color: #2c2c31; max-width: 62ch;
}
.tl-wat small { display: block; color: #6d6d74; }
/* optionele foto bij een regel; verschijnt zodra er een in TIJDLIJN_BEELD staat */
.tl-foto {
  grid-column: 2; display: block; margin-top: 14px;
  max-width: 320px; background: var(--paper);
  border: 1px solid #ececee; padding: 8px; box-shadow: var(--shadow-card);
}
.tl-foto img { width: 100%; display: block; }
/* de regels komen na elkaar in beeld, dat geeft het leven dat de lijst miste */
.rv .tl-rij { opacity: 0; }
.rv.in .tl-rij {
  opacity: 1;
  transition: opacity .55s cubic-bezier(.2, .6, .2, 1) calc(var(--n, 0) * 90ms);
}
@media (prefers-reduced-motion: reduce) {
  .rv .tl-rij { opacity: 1; transform: none; }
  .rv.in .tl-rij { transition: none; }
}

/* exposities */
.expo-year { padding-top: clamp(28px, 4vw, 44px); padding-bottom: 6px; }
.expo-year h2 { font-size: clamp(1.7rem, 3.4vw, 2.6rem); font-weight: 300; letter-spacing: -.02em; margin: 0 0 .6em; }
.expo {
  display: grid; grid-template-columns: 1fr; gap: 2px;
  padding: 16px 2px; border-top: 1px solid var(--hairline);
}
.expo:last-child { border-bottom: 1px solid var(--hairline); }
.expo .e-title { font-size: 1.14rem; font-weight: 500; }
.expo .e-where { font-size: 1.02rem; color: #4a4a50; }
.expo .e-when { font-size: .9rem; font-style: italic; color: var(--grey); }

/* publicaties */
.pubs { display: grid; gap: 1px; background: var(--hairline); border-top: 1px solid var(--hairline); border-bottom: 1px solid var(--hairline); max-width: 780px; }
.pub { background: var(--page); padding: 20px 2px; display: grid; grid-template-columns: 130px 1fr auto; gap: 18px; align-items: baseline; }
.pub .yr { font-size: .9rem; font-style: italic; color: var(--grey); }
.pub .t { font-weight: 500; }
.pub .t small { display: block; font-weight: 400; color: #6d6d74; }
.pub .pr { font-size: 1.02rem; white-space: nowrap; }

/* contact */
/* de biografie: tekst links, portret rechts (heette eerder contact-grid, maar
   dat is hij niet — de contactpagina heeft nu zijn eigen opzet) */
.bio-grid { display: grid; gap: clamp(32px, 6vw, 80px); grid-template-columns: 1fr; padding-bottom: clamp(56px, 9vw, 120px); }
@media (min-width: 860px) { .bio-grid { grid-template-columns: 1.2fr 1fr; } }

/* ---------- contact ----------
   Twee wegen naar Johan, naast elkaar en even zwaar: een mail of een telefoontje.
   Geen kaartjes met een randje eromheen — een haarlijn erboven, het gegeven groot
   en één regel uitleg eronder. Zo is in één oogopslag duidelijk wat de bedoeling
   van de pagina is, en waarvoor je welke weg neemt. */
.wegen { display: grid; gap: clamp(26px, 4vw, 56px); padding-bottom: clamp(44px, 7vw, 92px); }
@media (min-width: 760px) { .wegen { grid-template-columns: 1fr 1fr; } }
.weg {
  display: block; color: inherit;
  border-top: 1px solid var(--ink); padding-top: clamp(13px, 1.5vw, 20px);
}
.weg .eyebrow { margin-bottom: clamp(16px, 2.4vw, 30px); }
.weg-groot {
  display: block;
  font-size: clamp(1.5rem, .95rem + 1.9vw, 2.5rem);
  font-weight: 300; letter-spacing: -.022em; line-height: 1.12;
  overflow-wrap: break-word;
}
.weg:hover .weg-groot, .weg:focus-visible .weg-groot {
  text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: .18em;
}
.weg-bij {
  display: block; margin-top: 1em; max-width: 36ch;
  color: #4a4a50; font-size: .96rem; line-height: 1.7;
}
/* het atelier met een gezicht erbij: dezelfde foto als op de home, maar liggend
   en met een bijschrift dat hier past */
.atelier { display: grid; gap: clamp(28px, 5vw, 72px); align-items: start; padding-bottom: clamp(56px, 9vw, 120px); }
@media (min-width: 860px) { .atelier { grid-template-columns: 5fr 6fr; } }
.atelier-beeld img { width: 100%; aspect-ratio: 5 / 4; object-fit: cover; }
.atelier-adres {
  margin: 0 0 .75em;
  font-size: clamp(1.45rem, 1rem + 1.5vw, 2.1rem);
  font-weight: 300; letter-spacing: -.02em; line-height: 1.25;
}
.atelier-tekst p { color: #4a4a50; max-width: 46ch; line-height: 1.75; }
.atelier-extra {
  margin-top: clamp(26px, 3.2vw, 42px); padding-top: clamp(15px, 1.8vw, 22px);
  border-top: 1px solid var(--hairline);
}
.atelier-extra .eyebrow { margin-bottom: .8em; }


.over-portrait { max-width: 460px; }
.over-portrait img { width: 100%; aspect-ratio: 4 / 5; object-fit: cover; }

/* portret-placeholder */
.portret-ph {
  aspect-ratio: 4 / 5; display: flex; align-items: center; justify-content: center;
  text-align: center; padding: 24px;
  border: 1px dashed #cdcdd3; background: #fafafb; color: #6d6d74;
  font-size: .9rem; font-style: italic; max-width: 420px;
}

/* ---------- footer ---------- */
.site-foot { margin-top: clamp(64px, 10vw, 140px); border-top: 1px solid var(--hairline); background: var(--mist); }
.site-foot .cols {
  display: flex; flex-wrap: wrap; gap: 28px; justify-content: space-between; align-items: baseline;
  padding-top: clamp(36px, 6vw, 64px); padding-bottom: 20px;
}
.site-foot .wordmark { font-size: clamp(1.25rem, 2.6vw, 1.8rem); }
.foot-contact { text-align: right; font-size: 1rem; color: #4a4a50; line-height: 1.9; }
.foot-contact a:hover { color: var(--ink); }
.site-foot .base {
  display: flex; flex-wrap: wrap; gap: 12px 28px; justify-content: space-between;
  padding-bottom: 34px; font-size: .86rem; color: var(--grey);
}
.site-foot .base a:hover { color: var(--ink); }

/* ---------- reveal & parallax ---------- */
/* Alles wat bij binnenkomst verschijnt, komt alleen op: het schuift niet meer
   omhoog. Ruben wil geen tekst die meebeweegt met het scrollen (september 2026). */
.rv { opacity: 0; transition: opacity .55s cubic-bezier(.2, .6, .2, 1); }
.rv.in { opacity: 1; }
[data-plx] { will-change: transform; }

/* ---------- responsive ---------- */
/* Tot 1024px breed staat het menu achter de knop rechtsboven, in een paneel.
   Breder past het in de kop, ook in het Duits en Engels waar de woorden langer
   zijn (gemeten: Nederlands vanaf 920px, Duits 970px, Engels 990px). Eerst lag
   deze grens op 640px en liep het menu op een tablet rechts uit beeld. De grens
   staat ook in site.js (menu dicht bij breder worden). */
@media (max-width: 1023px) {
  /* smal scherm: wordmark links, menuknop rechts, menu in een paneel */
  .site-head .bar { align-items: center; padding-top: 15px; padding-bottom: 14px; position: relative; z-index: 71; }
  /* het paneel hangt binnen .bar, dus wordmark en knop moeten er expliciet boven */
  .site-head .wordmark { position: relative; z-index: 71; }
  /* boven een hero is de wordmark wit; met het paneel open staat hij op wit.
     De tweede selector moet de :not(.ghost)-regels hierboven overtreffen. */
  body.menu-open .site-head .wordmark,
  body.menu-open .site-head.over-hero .wordmark:not(.ghost) { text-shadow: none; opacity: 1; }
  body.menu-open .site-head .wordmark strong,
  body.menu-open .site-head.over-hero .wordmark:not(.ghost) strong { color: var(--ink); }
  body.menu-open .site-head .wordmark span,
  body.menu-open .site-head.over-hero .wordmark:not(.ghost) span { color: var(--grey); }
  /* met het paneel open is de grote naam weg, dus toont de header de ghost */
  body.menu-open .site-head .wordmark.ghost strong,
  body.menu-open .site-head .wordmark.ghost span { opacity: 1; }
  .menu-knop { display: flex; }
  .site-nav {
    position: fixed; inset: 0; z-index: 70;
    flex-direction: column; align-items: flex-start; justify-content: center;
    gap: 2px; padding: 0 var(--pad) 8vh;
    background: rgba(252, 252, 253, .97);
    -webkit-backdrop-filter: blur(20px); backdrop-filter: blur(20px);
    opacity: 0; pointer-events: none; transform: translateY(-6px);
    transition: opacity .3s ease, transform .3s cubic-bezier(.2, .7, .2, 1);
  }
  body.menu-open { overflow: hidden; }
  /* blur op de header zou hem tot containing block maken; dan valt het paneel
     binnen de headerbalk in plaats van over het hele scherm */
  body.menu-open .site-head { background: transparent; box-shadow: none;
    -webkit-backdrop-filter: none; backdrop-filter: none; }
  body.menu-open .site-nav { opacity: 1; pointer-events: auto; transform: none; }
  body.menu-open .namestage { opacity: 0; pointer-events: none; }
  .namestage { transition: opacity .3s ease; }
  .site-nav a {
    font-size: clamp(2rem, 11vw, 3rem); letter-spacing: -.02em; text-transform: none;
    color: var(--ink); padding: 6px 0; border-bottom: 0; font-weight: 300;
    opacity: 0; transform: translateY(10px);
    transition: opacity .4s ease, transform .4s cubic-bezier(.2, .7, .2, 1);
  }
  body.menu-open .site-nav a { opacity: 1; transform: none; }
  body.menu-open .site-nav a:nth-child(1) { transition-delay: .06s; }
  body.menu-open .site-nav a:nth-child(2) { transition-delay: .11s; }
  body.menu-open .site-nav a:nth-child(3) { transition-delay: .16s; }
  body.menu-open .site-nav a:nth-child(4) { transition-delay: .21s; }
  /* in het paneel staan de talen klein onderaan, niet als vijfde grote regel */
  .site-nav .taal {
    margin-top: 28px; padding-left: 0; border-left: 0; gap: 22px;
    opacity: 0; transform: translateY(10px);
    transition: opacity .4s ease .26s, transform .4s cubic-bezier(.2, .7, .2, 1) .26s;
  }
  body.menu-open .site-nav .taal { opacity: 1; transform: none; }
  .site-nav .taal a,
  .site-head.over-hero .site-nav .taal a,
  .site-head.over-hero-licht .site-nav .taal a {
    font-size: .95rem; letter-spacing: .18em; text-transform: uppercase; font-weight: 400;
    color: var(--grey); padding: 8px 0; opacity: 1; transform: none;
  }
  /* het paneel staat altijd op wit, ook op pagina's met een hero eronder — dus
     hier gewoon inkt, of de header boven die hero nu wit is of niet */
  .site-head.over-hero .site-nav a,
  .site-head.over-hero .site-nav a:hover,
  .site-head.over-hero-licht .site-nav a,
  .site-head.over-hero-licht .site-nav a:hover { color: var(--ink); text-shadow: none; }
  .site-nav a[aria-current="page"],
  .site-head.over-hero .site-nav a[aria-current="page"],
  .site-head.over-hero-licht .site-nav a[aria-current="page"] {
    color: var(--grey); border-bottom-color: transparent;
  }
}

@media (max-width: 639px) {
  .specs .row { grid-template-columns: 120px 1fr; }
  .tl-rij { grid-template-columns: 38px 1fr; gap: 0 15px; }
  .tl-rij::before { left: 18px; top: 36px; }
  .tl-merk { width: 36px; height: 36px; }
  .tl-merk svg { width: 18px; height: 18px; }
  .tl-jaar { min-height: 36px; font-size: 1.25rem; }
  .tl-wat { font-size: 1.02rem; }
  .pub { grid-template-columns: 1fr; gap: 4px; }
  /* vorig/volgend blijven naast elkaar, alleen wat compacter */
  .prevnext a { padding: 20px var(--pad); }
  .prevnext .dir { font-size: .7rem; letter-spacing: .14em; }
  .prevnext .name { font-size: 1rem; }
  /* de call to action in het midden, over bijna de volle breedte */
  .specs .enquire { justify-self: center; padding: 18px 30px; letter-spacing: .16em; }
  .foot-contact { text-align: left; }
}

/* ---------- toegankelijkheid ---------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .rv { opacity: 1; transform: none; transition: none; }
  [data-plx] { transform: none !important; }
  .workcard img { transition: none; }
}

/* ---------- de kunst beschermen ----------
   Wat op een scherm staat kan niemand helemaal tegenhouden: een screenshot regelt
   de computer zelf. Maar opslaan hoeft niet makkelijk te zijn, en wat er te pakken
   valt is een webversie (webbeelden.py), nooit het origineel. Een schilderij
   reageert daarom niet op de muis of een vinger: rechtsklikken, slepen en lang
   drukken ('Bewaar in Foto's', 'Bewaar in Bestanden') komen bij de lijst, de knop
   of de link eronder uit, en daar zit geen afbeelding in om te bewaren. site.js
   houdt boven een werk ook het menu van de rechtermuisknop dicht. */
/* de <picture> om een werk heen (AVIF met JPEG als terugval) doet zelf niet mee:
   het beeld staat in de opmaak alsof hij er niet is */
picture.kunst-p { display: contents; }
img.kunst {
  pointer-events: none;
  -webkit-user-select: none;
  user-select: none;
  -webkit-user-drag: none;
  -webkit-touch-callout: none;
}
.mount, .mat, .crop-box, .hc-plx, .scene-crop, .loepbak, .yb-thumb, .wk {
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
}

/* Wie de pagina afdrukt, krijgt de tekst maar geen schilderijen. */
@media print {
  img.kunst, .loepbak { visibility: hidden !important; }
  body::before {
    content: "De werken van Johan Meeske worden niet mee afgedrukt. Bekijk ze op de website.";
    display: block; padding: 0 0 14pt; font-size: 10pt; color: #555;
  }
  html:lang(de) body::before { content: "Die Werke von Johan Meeske werden nicht mitgedruckt. Sie finden sie auf der Website."; }
  html:lang(en) body::before { content: "The works of Johan Meeske are not printed. You can see them on the website."; }
}

/* ---------- aan de muur: Rolands interieurs op de home ----------
   Elk werk op zijn echte maat in een kamer. Een rij die opzij schuift; hij
   begint op de lijn van de tekst en loopt door tot de rand van het scherm. */
.home-kamers { padding-top: clamp(64px, 9vw, 130px); }
.home-kamers .sec-head { align-items: center; }
.kamer-knoppen { display: flex; gap: 10px; }
.kamer-pijl {
  display: grid; place-items: center; width: 46px; height: 46px; padding: 0;
  border-radius: 50%; border: 1px solid var(--hairline); background: var(--paper);
  color: var(--ink); cursor: pointer;
  transition: border-color .2s ease, opacity .2s ease;
}
.kamer-pijl:hover { border-color: var(--ink); }
.kamer-pijl:disabled { opacity: .3; cursor: default; border-color: var(--hairline); }
@media (hover: none), (max-width: 767px) { .kamer-knoppen { display: none; } }
.kamer-rij {
  --rand: max(var(--pad), calc((100% - var(--maxw)) / 2 + var(--pad)));
  display: flex; gap: clamp(14px, 1.8vw, 28px);
  overflow-x: auto; overflow-y: hidden; overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory; scroll-padding-inline: var(--rand);
  padding: 4px var(--rand) 10px;
  scrollbar-width: none; -webkit-overflow-scrolling: touch;
}
.kamer-rij::-webkit-scrollbar { display: none; }
.kamer-rij:focus-visible { outline: 2px solid var(--ink); outline-offset: 4px; }
.kamer-kaart { flex: 0 0 min(70vw, 880px); scroll-snap-align: start; color: inherit; }
.kamer-kaart .card-name, .kamer-kaart .card-desc { display: block; }
.kamer-beeld {
  display: block; aspect-ratio: 2200 / 1462; overflow: hidden;
  background: var(--mist); box-shadow: var(--shadow-card);
}
.kamer-beeld img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform .9s cubic-bezier(.2, .6, .2, 1);
}
.kamer-kaart:hover .kamer-beeld img { transform: scale(1.025); }
@media (prefers-reduced-motion: reduce) { .kamer-beeld img { transition: none; } }
@media (max-width: 767px) { .kamer-kaart { flex-basis: 86vw; } }

/* ============================================================
   TELEFOON LIGGEND
   ============================================================ */
/* Een iPhone in liggende stand is breed (844 of 852px) maar laag (±393px).
   Alle breekpunten hierboven kijken alleen naar BREEDTE, en twee ervan liggen
   net boven die 852px: .intro-grid schakelt pas bij 860px naar twee kolommen
   en .wt-inner pas bij 960px. Juist een telefoon in liggende stand viel daar
   dus doorheen en kreeg de gestapelde smalle-telefoonopmaak in een brede, lage
   strook. Daar kwamen de klachten van Johan vandaan (via Ruben, 23 oktober
   2026): een portret van 538px hoog in een scherm van 393px, een werk dat
   gecentreerd stond met de tekst eronder over de volle breedte, een menu dat
   over de header heen liep, en de grote naam die dwars door de header schemerde.

   Dit blok kijkt daarom op HOOGTE. Een staande telefoon is ~812px hoog en valt
   er buiten, dus de verticale weergave blijft precies zoals hij was. De
   max-width houdt brede bureaubladvensters die toevallig laag staan erbuiten.
   Het staat achteraan zodat het wint van de breedte-regels hierboven. */
@media (orientation: landscape) and (max-height: 540px) and (max-width: 1023px) {

  /* ---- niets hoger dan het scherm ---- */
  .hero-full { min-height: 0; }
  .hero-cover { min-height: 0; }
  .namestage { height: 100svh; }
  .hero-page { height: min(100svh, 420px); }
  .hero-zaal { height: min(100svh, 420px); }

  /* ---- de naam ---- */
  /* kleiner dan staand, anders eet hij de lage strook op; bij het scrollen
     vliegt hij naar de header (zie 'telefoon: de naam vliegt' hierboven) */
  .bigname { font-size: clamp(1.5rem, 4.4vw, 2.4rem); }
  /* Boven een hero is ook de wordmark in de header dubbelop: het werk zelf is
     de kop, en in deze lage strook maakte dat het beeld druk. Zodra je de hero
     voorbij bent komt hij terug — hij moet blijven bestaan, want het menu heeft
     geen 'Home' en dit is de enige weg terug naar de voorpagina. Met het menu
     open blijft hij sowieso staan. */
  body:not(.menu-open) .site-head.over-hero .wordmark,
  body:not(.menu-open) .site-head.over-hero-licht .wordmark {
    opacity: 0; pointer-events: none;
  }

  /* ---- de werken ---- */
  /* --fit-h trekt 260px van de schermhoogte af zodat staand werk past; liggend
     bleef daar 130px van over en werden de werken piepklein. */
  .art-card { --fit-h: calc(100svh - 110px); }
  /* lijst en verhaal naast elkaar in plaats van gecentreerd boven volle-breedte
     tekst; dat las als scheef uitgelijnd */
  .wt-inner { grid-template-columns: minmax(0, 6fr) minmax(0, 6fr); gap: clamp(18px, 3vw, 40px); }
  .wt-tile { padding: 8px 0; }

  /* ---- de foto van Johan (home en biografie) ---- */
  /* Twee kolommen op de home, en op beide pagina's een bovengrens voor de foto
     zodat hij in één keer in beeld past. Het portret is 4:5, dus de hoogte is
     de breedte maal 1,25 — vandaar de factor 0,8. */
  .intro-grid { grid-template-columns: 5fr 6fr; gap: clamp(20px, 3vw, 44px); }
  .intro-portrait,
  .over-portrait { max-width: calc((100svh - 110px) * 0.8); }

  /* ---- lucht tussen de secties ---- */
  /* de verticale marges rekenen in vw; liggend is vw groot en de hoogte klein,
     dus werd het meeste scherm leegte */
  .home-intro { padding-top: clamp(28px, 5vw, 56px); padding-bottom: clamp(24px, 4vw, 48px); }
  .wt { padding-top: clamp(24px, 4vw, 48px); padding-bottom: clamp(24px, 4vw, 48px); }

  /* ---- menupaneel ---- */
  /* vier regels plus de taalkeuze passen niet gecentreerd in ±393px; vanaf de
     bovenkant stapelen en mogen scrollen is hier het enige dat werkt */
  .site-nav {
    justify-content: flex-start;
    padding-top: 64px; padding-bottom: 16px;
    overflow-y: auto;
  }
  .site-nav a { font-size: clamp(1.3rem, 3.4vw, 1.75rem); padding: 3px 0; }
}

/* ---------- telefoon liggend, met de tabbalk van Safari erbij ----------
   Johan browst liggend én met Safari's tabbalk open. Dan blijft er van de
   393px schermhoogte nog ~287px over, en bij veel tabs nog minder. Het menu
   paste daar niet meer: de vier regels wel, maar de taalkeuze viel eronder —
   die kost 69px onderaan de stapel (28px marge + 41px hoog), terwijl rechts
   de halve breedte leegstaat (gemeten 24 oktober 2026).
   Hier dus de taalkeuze uit de stapel en rechtsonder in de lege ruimte, en de
   regels iets dichter op elkaar. De regelhoogte blijft groot genoeg om met een
   vinger te raken; kleiner zetten zou voor Johan juist slechter zijn. */
@media (orientation: landscape) and (max-height: 360px) and (max-width: 1023px) {
  /* het paneel is fixed met inset 0, dus dit hangt aan het paneel zelf */
  .site-nav .taal { position: absolute; right: var(--pad); bottom: 16px; margin-top: 0; }
  .site-nav a { line-height: 1.32; padding: 1px 0; }
}
