/* ==========================================================================
   Titans of Hair — stijlkader
   --------------------------------------------------------------------------
   Zwart-wit, DirtyHeadline voor de koppen, glazen bollen als navigatie.
   Alles zelf gehost: geen externe verzoeken, dus ook geen cookiebanner
   nodig voor lettertypen.
   ========================================================================== */

/* ------------------------------------------------------------ lettertypen */

@font-face {
  font-family: "DirtyHeadline";
  src: url("../fonts/dirtyheadline.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Special Elite";
  src: url("../fonts/special-elite-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: "Special Elite";
  src: url("../fonts/special-elite-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 {
  /* Kleuren — bewust zwart-wit, overgenomen van de bestaande site. */
  --zwart:        #000000;
  --inkt:         #111111;
  --grijs-donker: #54595f;
  --grijs-lijn:   #585454;
  --grijs:        #6f6f6f;
  --grijs-licht:  #f1f1f1;
  --wit:          #ffffff;

  /* Lettertypen.
     --font-tekst staat op Special Elite, precies zoals de huidige site.
     Leest dat over lange stukken te zwaar? Dan is dit de enige regel die
     hoeft te wijzigen; alles schaalt mee. */
  --font-kop:     "DirtyHeadline", "Special Elite", Impact, sans-serif;
  --font-tekst:   "Special Elite", "Courier New", monospace;
  /* Vetgedrukte tekst krijgt hetzelfde displaylettertype als de koppen. */
  --font-nadruk:  "DirtyHeadline", "Special Elite", Impact, sans-serif;
  --font-systeem: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;

  /* Typografie — clamp() laat de tekst meeschalen met het scherm,
     zonder mediaqueries en zonder ooit onleesbaar klein te worden. */
  --tekst-basis:  clamp(1rem, 0.95rem + 0.25vw, 1.125rem);
  --kop-1:        clamp(2.25rem, 1.6rem + 3.2vw, 4.5rem);
  --kop-2:        clamp(1.75rem, 1.35rem + 2vw, 3rem);
  --kop-3:        clamp(1.35rem, 1.15rem + 1vw, 2rem);
  --kop-4:        clamp(1.15rem, 1.05rem + 0.5vw, 1.4rem);

  --regelhoogte:  1.75;

  /* De leeskolom is gelijk aan de sitebreedte. Waren die verschillend, dan
     begon tekst op een andere rooilijn dan het team of de prijslijst, en
     verspringt de rand zodra je doorklikt. Bij 820px komt een regel op zo'n
     74 tekens uit; dat valt ruim binnen wat prettig leest. */
  --leesbreedte:  var(--breedte);

  /* Ruimte — één schaal, zodat afstanden overal kloppen. */
  --ruimte-xs:  0.5rem;
  --ruimte-s:   1rem;
  --ruimte-m:   1.75rem;
  --ruimte-l:   3rem;
  --ruimte-xl:  clamp(3rem, 2rem + 5vw, 6rem);

  /* Eén breedte voor de hele site: teksten, team, prijzen, updates en de
     bollen staan allemaal binnen dezelfde rooilijn. Wisselende breedtes
     laten de rand verspringen zodra je doorklikt, en dat oogt onrustig.
     Dit is het enige getal dat je hoeft te wijzigen om de site breder of
     smaller te maken. */
  --breedte:      820px;

  --rand:      2px solid var(--zwart);
  --lijn:      5px groove var(--grijs-lijn);
  --overgang:  180ms ease;
}

/* ------------------------------------------------------------------ basis */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

/* Wie bewegingen liever vermijdt, krijgt ze niet. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

body {
  margin: 0;
  font-family: var(--font-tekst);
  font-size: var(--tekst-basis);
  line-height: var(--regelhoogte);
  color: var(--inkt);
  background: var(--wit);
  -webkit-font-smoothing: antialiased;
}

img, svg, video { max-width: 100%; height: auto; display: block; }

h1, h2, h3, h4 {
  font-family: var(--font-kop);
  font-weight: 400;
  line-height: 1.05;
  letter-spacing: 0.01em;
  text-transform: uppercase;
  margin: 0 0 var(--ruimte-s);
  color: var(--zwart);
}

h1 { font-size: var(--kop-1); }
h2 { font-size: var(--kop-2); }
h3 { font-size: var(--kop-3); }
h4 { font-size: var(--kop-4); font-family: var(--font-tekst); text-transform: none; }

p { margin: 0 0 var(--ruimte-s); }
p:last-child { margin-bottom: 0; }

a { color: inherit; text-decoration: underline; text-underline-offset: 3px; }
a:hover { text-decoration-thickness: 2px; }

/* Vetgedrukt wordt DirtyHeadline, net als de koppen.

   Geen font-weight: 700 erbij. Dit lettertype kent maar één gewicht, dus de
   browser zou een nep-vet maken door de letters te verdikken — bij een ruw,
   verweerd lettertype loopt dat dicht. Het is ook niet nodig: DirtyHeadline
   zet op dezelfde puntgrootte al ruim anderhalf keer zoveel inkt op de pagina
   als Special Elite, dus het valt vanzelf op.

   De maat gaat een fractie omhoog omdat dit lettertype zo'n 20% smaller loopt;
   zonder die correctie oogt een vetgedrukt woord kleiner dan de tekst eromheen.

   LET OP: dit lettertype heeft geen letters met accenten (é ë ö à), geen
   euroteken en geen haakjes of apostrof. Die tekens vallen terug op Special
   Elite en wijken dus af binnen een vetgedrukt woord. */
strong, b {
  font-family: var(--font-nadruk);
  font-weight: 400;
  font-size: 1.06em;
  letter-spacing: 0.01em;
}

/* In een kop staat alles al in dit lettertype; daar hoeft vet niets te doen. */
h1 strong, h2 strong, h3 strong,
h1 b, h2 b, h3 b { font-size: inherit; letter-spacing: inherit; }

hr {
  border: 0;
  border-top: var(--lijn);
  margin: var(--ruimte-l) 0;
}

/* Toetsenbordgebruikers moeten altijd kunnen zien waar ze zijn. */
:focus-visible {
  outline: 3px solid var(--zwart);
  outline-offset: 3px;
}

/* Op de zwarte vlakken van de site is een zwarte focusrand onzichtbaar. Dat
   raakt precies de plekken waar de belangrijkste links staan: het e-mailadres,
   het telefoonnummer, de sociale iconen, de privacylink en de afspraakknop. */
.voet :focus-visible,
.voet__onder :focus-visible,
.sectie--zwart :focus-visible,
.meldingsbalk :focus-visible { outline-color: var(--wit); }

.overslaan {
  position: absolute;
  left: -9999px;
  z-index: 200;
  padding: var(--ruimte-xs) var(--ruimte-s);
  background: var(--zwart);
  color: var(--wit);
  text-decoration: none;
}
.overslaan:focus { left: var(--ruimte-xs); top: var(--ruimte-xs); }

/* Zichtbaar voor schermlezers, onzichtbaar op het scherm. */
.alleen-voorlezer {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* ------------------------------------------------------------- meldingsbalk */

.meldingsbalk {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--ruimte-xs);
  padding: var(--ruimte-xs) var(--ruimte-s);
  background: var(--zwart);
  color: var(--wit);
  text-align: center;
  font-size: 0.9375rem;
}

/* Lopen er meer meldingen tegelijk, dan staan ze onder elkaar. Zonder deze
   scheiding ogen twee zwarte balken als een blok en lees je twee losse
   mededelingen als een. */
.meldingsbalk + .meldingsbalk { border-top: 1px solid rgba(255, 255, 255, 0.25); }

.meldingsbalk strong {
  font-family: var(--font-kop);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* -------------------------------------------------------------------- kop */

.kop {
  display: grid;
  justify-items: center;
  gap: var(--ruimte-s);
  padding: var(--ruimte-m) var(--ruimte-s) var(--ruimte-s);
  background: var(--wit);
}

.kop__logo { display: block; line-height: 0; }
.kop__logo img { width: min(280px, 62vw); height: auto; }

/* ---------------------------------------------------------------- menu */

.hoofdmenu ul {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--ruimte-s) var(--ruimte-m);
  margin: 0;
  padding: 0;
  list-style: none;
}

.hoofdmenu a {
  position: relative;
  display: inline-block;
  padding: 0.25rem 0;
  font-family: var(--font-kop);
  font-size: 1.05rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-decoration: none;
}

/* Onderstreping die opgroeit — subtiel, past bij het strakke zwart-wit. */
.hoofdmenu a::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 2px;
  background: var(--zwart);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--overgang);
}
.hoofdmenu a:hover::after,
.hoofdmenu a:focus-visible::after,
.hoofdmenu a[aria-current="page"]::after { transform: scaleX(1); }

.hoofdmenu a[aria-current="page"] { font-weight: 700; }

/* Hamburger — alleen op smalle schermen. */
.menuknop {
  display: none;
  align-items: center;
  gap: 0.55rem;
  padding: 0.5rem 0.9rem;
  font: inherit;
  font-family: var(--font-kop);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--zwart);
  background: var(--wit);
  border: var(--rand);
  cursor: pointer;
}

.menuknop__streepjes {
  display: grid;
  gap: 4px;
  width: 20px;
}
.menuknop__streepjes span {
  display: block;
  height: 2px;
  background: var(--zwart);
  transition: transform var(--overgang), opacity var(--overgang);
}

.menuknop[aria-expanded="true"] .menuknop__streepjes span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.menuknop[aria-expanded="true"] .menuknop__streepjes span:nth-child(2) { opacity: 0; }
.menuknop[aria-expanded="true"] .menuknop__streepjes span:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

/* --------------------------------------------------------------- secties */

.sectie {
  padding: var(--ruimte-xl) var(--ruimte-s);
}

.omhulsel {
  width: 100%;
  max-width: var(--breedte);
  margin-inline: auto;
}

/* Een leeskolom van ~68 tekens: het verschil tussen doorlezen en afhaken.
   Let op het onderscheid: de KOLOM staat midden op de pagina, de TEKST
   erin blijft links uitgelijnd. Gecentreerde lopende tekst leest slecht,
   want je oog moet elke regel opnieuw het begin zoeken. */
.leeskolom {
  max-width: var(--leesbreedte);
  margin-inline: auto;
}

/* Oude naam, blijft werken voor blokken die hem nog gebruiken. */
.leestekst {
  max-width: var(--leesbreedte);
  margin-inline: auto;
}

.sectie--zwart {
  background: var(--zwart);
  color: var(--wit);
}
.sectie--zwart h1, .sectie--zwart h2, .sectie--zwart h3 { color: var(--wit); }

.sectie--grijs { background: var(--grijs-licht); }

.sectie__kop {
  text-align: center;
  margin-bottom: var(--ruimte-l);
}

.midden { text-align: center; }

/* ------------------------------------------------------------------- hero */

.hero {
  display: grid;
  place-items: center;
  gap: var(--ruimte-m);
  padding: var(--ruimte-xl) var(--ruimte-s);
  text-align: center;
}

.hero--vol { min-height: min(80vh, 700px); }

.hero__logo { width: min(560px, 88vw); }
.hero__titel { margin: 0; }
.hero__onder {
  max-width: 55ch;
  margin: 0 auto;
  font-size: 1.05em;
}

/* ------------------------------------------------------------------ bollen
   De glazen bol is een achtergrondafbeelding; het label is ECHTE tekst.
   Op de oude site zat de tekst in de PNG gebakken — onzichtbaar voor Google
   en voor schermlezers, en niet aanpasbaar zonder Photoshop. */

.bollen {
  /* Flexbox en geen grid, om twee redenen.
     Ten eerste: bij een grid met automatische sporen ontstaat een
     kringverwijzing zodra een cel `max-width: 100%` krijgt — het spoor
     hangt dan af van de cel en de cel van het spoor, en de browser lost
     dat op met nul breedte.
     Ten tweede: flexbox breekt vanzelf af zodra de bollen niet meer passen,
     dus er zijn geen breekpunten nodig om het aantal per rij te regelen. */
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: flex-end;
  gap: var(--bolgat, 1.25rem);

  /* Het gekozen aantal naast elkaar wordt een breedte: zoveel bollen plus
     de tussenruimtes. De factor 1.15 vangt de maatvariatie op — zonder die
     marge past een rij met een grotere bol er net niet meer bij en wikkelt
     hij een bol te vroeg. Past de hele rij niet op het scherm, dan wikkelt
     hij alsnog; dat is precies wat je op een telefoon wilt. */
  max-width: calc(var(--kolommen, 3) * var(--bolmaat, 220px) * 1.15
                  + (var(--kolommen, 3) - 1) * var(--bolgat, 1.25rem));
  margin-inline: auto;

  list-style: none;
  margin-block: 0;
  padding: 0;
}

/* Tussenruimte, instelbaar bij het blok. */
.bollen--afstand-krap    { --bolgat: 0.5rem; }
.bollen--afstand-normaal { --bolgat: 1.25rem; }
.bollen--afstand-ruim    { --bolgat: 2.5rem; }

/* Bij "vullend" vullen de bollen de beschikbare ruimte. */
.bollen--vullend { max-width: 100%; }
.bollen--vullend li { flex: 1 1 calc(100% / var(--kolommen, 3) - var(--bolgat, 1.25rem)); }
.bollen--vullend .bol { width: 100%; max-width: none; }

.bol {
  position: relative;
  display: grid;
  place-items: center;
  aspect-ratio: 1;
  text-decoration: none;
  color: var(--zwart);
  transition: transform var(--overgang);

  /* --bolmaat komt uit het CMS en is een bovengrens, geen vaste breedte:
     in een smalle kolom blijft de bol gewoon meeschalen. */
  /* De ingestelde maat, vermenigvuldigd met de variatie en de nadruk.
     Een eigen breedte en niet width:100%, want de kolommen staan op auto:
     zou de bol de kolom vullen, dan bepaalde de kolom de maat en deden de
     variatie- en nadruk-instellingen niets meer. */
  width: calc(var(--bolmaat, 220px) * var(--schaal, 1) * var(--nadruk, 1));
  max-width: 100%;
  margin-inline: auto;

  /* Maakt de bol de maatstaf voor cq-eenheden hieronder, zodat het label
     meeschaalt met de bol in plaats van met het scherm. */
  container-type: inline-size;
}

.bol__beeld {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  pointer-events: none;
  user-select: none;
}

.bol__label {
  position: relative;
  z-index: 1;
  max-width: 72%;
  font-family: var(--font-kop);
  font-size: clamp(0.8rem, 9cqw, 1.9rem);
  line-height: 1.05;
  letter-spacing: 0.02em;
  text-align: center;
  text-transform: uppercase;
  /* Het glas is lichtgrijs; een zachte gloed houdt de tekst overal leesbaar. */
  text-shadow: 0 0 12px rgba(255, 255, 255, 0.9), 0 0 4px rgba(255, 255, 255, 0.9);
}

.bol:hover, .bol:focus-visible { transform: translateY(-6px) scale(1.03); }

/* Instelbaar vanuit het CMS: aantal naast elkaar ... */
.bollen--k2 { --kolommen: 2; }
.bollen--k3 { --kolommen: 3; }
.bollen--k4 { --kolommen: 4; }
.bollen--k5 { --kolommen: 5; }

/* ... en hoe groot een bol maximaal wordt. */
.bollen--klein   { --bolmaat: 160px; }
.bollen--normaal { --bolmaat: 220px; }
.bollen--groot   { --bolmaat: 300px; }
.bollen--vullend { --bolmaat: none; }

/* Bij "vullend" vervalt de bovengrens helemaal. Dit staat apart omdat
   calc() niet met de waarde none kan rekenen; die combinatie zou de hele
   regel ongeldig maken. */
.bollen--vullend .bol { max-width: none; }

/* De cel mag krimpen maar nooit breder worden dan de rij. Binnen flexbox
   is de breedte van de rij vastgesteld, dus deze procentwaarde is eenduidig. */
.bollen li {
  flex: 0 1 auto;
  min-width: 0;
  max-width: 100%;
}

/* Verschil in grootte tussen de bollen onderling. Een strak raster van
   gelijke cirkels oogt mechanisch; een beetje verloop maakt het losser.
   --schaal wordt onderaan verrekend met de maat. */
.bolcel { --schaal: 1; }

.bollen--variatie-subtiel .bolcel:nth-child(5n + 1) { --schaal: 1.00; }
.bollen--variatie-subtiel .bolcel:nth-child(5n + 2) { --schaal: 0.88; }
.bollen--variatie-subtiel .bolcel:nth-child(5n + 3) { --schaal: 1.08; }
.bollen--variatie-subtiel .bolcel:nth-child(5n + 4) { --schaal: 0.94; }
.bollen--variatie-subtiel .bolcel:nth-child(5n)     { --schaal: 1.03; }

.bollen--variatie-sterk .bolcel:nth-child(5n + 1) { --schaal: 1.00; }
.bollen--variatie-sterk .bolcel:nth-child(5n + 2) { --schaal: 0.72; }
.bollen--variatie-sterk .bolcel:nth-child(5n + 3) { --schaal: 1.22; }
.bollen--variatie-sterk .bolcel:nth-child(5n + 4) { --schaal: 0.84; }
.bollen--variatie-sterk .bolcel:nth-child(5n)     { --schaal: 1.12; }

/* Handmatige nadruk per bol; telt op bij de automatische variatie, zodat
   je een enkele bol bewust kunt laten opvallen. */
.bolcel--groter  { --nadruk: 1.25; }
.bolcel--kleiner { --nadruk: 0.78; }
.bolcel--normaal { --nadruk: 1; }


/* --------------------------------------------------------------- knoppen */

.knop {
  display: inline-block;
  padding: 0.85rem 2rem;
  font-family: var(--font-kop);
  font-size: 1.1rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--wit);
  background: var(--zwart);
  border: var(--rand);
  transition: color var(--overgang), background var(--overgang);
}

.knop:hover, .knop:focus-visible {
  color: var(--zwart);
  background: var(--wit);
}

.knop--omgekeerd {
  color: var(--zwart);
  background: var(--wit);
}
.knop--omgekeerd:hover {
  color: var(--wit);
  background: var(--zwart);
}

.sectie--zwart .knop {
  color: var(--zwart);
  background: var(--wit);
  border-color: var(--wit);
}
.sectie--zwart .knop:hover {
  color: var(--wit);
  background: var(--zwart);
}

.knoprij {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ruimte-s);
}
.knoprij--midden { justify-content: center; }

/* ------------------------------------------------------- tekst + afbeelding */

.duo {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  align-items: center;
  gap: var(--ruimte-l);
}

/* Waar de foto staat is een keuze in het CMS. De tekst staat altijd eerst in
   de HTML; hier zetten we de foto op zijn plek. */
.duo--links .duo__beeld { order: -1; }

/* Boven of onder: alles in een kolom, gecentreerd. De tekst loopt dan over de
   volle breedte, dus krijgt hij een leesbreedte mee -- net als bij de losse
   bol. Vandaag is die gelijk aan de kolombreedte; wordt de leeskolom ooit
   smaller, dan klopt dit meteen. */
.duo--boven,
.duo--onder {
  grid-template-columns: 1fr;
  justify-items: center;
}
.duo--boven .duo__beeld { order: -1; }
.duo--boven .duo__tekst,
.duo--onder .duo__tekst {
  width: 100%;
  max-width: var(--leesbreedte);
}

/* De maat van de bubbel is een keuze in het CMS. Zonder maat vulde de foto
   de hele kolom -- op een breed scherm zo'n 400 px -- en dat overheerste de
   tekst ernaast. De schaal is dezelfde als bij de losse bol. */
.duo__beeld { display: flex; justify-content: center; }
.duo__beeld img { width: 100%; max-width: var(--beeldmaat, 100%); height: auto; }

.duo__beeld--klein  { --beeldmaat: 160px; }
.duo__beeld--middel { --beeldmaat: 220px; }
.duo__beeld--groot  { --beeldmaat: 300px; }

/* ---------------------------------------------------- losse bol met tekst

   Het bollenraster is navigatie; dit is iets anders: één bol als beeld bij
   een verhaal. De bol zelf is dezelfde `.bol` als in het raster, zodat hij
   er precies zo uitziet en op dezelfde manier meedeint.

   Waar de bol staat is een keuze in het CMS. De bol staat altijd eerst in de
   HTML — dat houdt de voorleesvolgorde logisch — en de opmaak zet hem op
   zijn plek. Op een telefoon is er geen ruimte voor naast elkaar; daar valt
   links en rechts terug op boven en onder.
   ------------------------------------------------------------------------ */

.bolduo {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--ruimte-l);
}

.bolduo--links  { flex-direction: row; }
.bolduo--rechts { flex-direction: row-reverse; }
.bolduo--boven  { flex-direction: column; }
.bolduo--onder  { flex-direction: column-reverse; }

.bolduo__bol {
  flex: 0 0 auto;
  max-width: 100%;
}

.bolduo__tekst {
  flex: 1 1 auto;
  min-width: 0;
}

/* Staat de bol boven of onder, dan loopt de tekst over de volle breedte;
   dan is een leesbreedte nodig, anders worden de regels te lang. */
.bolduo--boven .bolduo__tekst,
.bolduo--onder .bolduo__tekst {
  width: 100%;
  max-width: var(--leesbreedte);
}

/* De maat van de bol. Dezelfde variabele als in het raster, zodat de bol
   zich verder precies zo gedraagt. */
.bolduo--klein   { --bolmaat: 160px; }
.bolduo--normaal { --bolmaat: 220px; }
.bolduo--groot   { --bolmaat: 300px; }
.bolduo--extra   { --bolmaat: 400px; }

/* Een bol zonder link is geen knop: geen hover-effect. */
.bol--stil { cursor: default; }
.bol--stil:hover, .bol--stil:focus-visible { transform: none; }

@media (prefers-reduced-motion: no-preference) {
  .bolduo                    { --kracht: 0.55; }
  .bolduo--beweging-rustig   { --kracht: 0.55; }
  .bolduo--beweging-normaal  { --kracht: 1; }
  .bolduo--beweging-uit .bol { animation: none; }
}

@media (max-width: 700px) {
  .bolduo--links,
  .bolduo--rechts { flex-direction: column; }

  .bolduo { gap: var(--ruimte-m); }
}

/* ------------------------------------------------------------------- team */

.teamlijst {
  display: grid;
  gap: var(--ruimte-xl);
}

.teamlid {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(0, 3fr);
  align-items: center;
  gap: var(--ruimte-l);
}

/* Om en om staat de foto links en rechts. De kolommen wisselen dan mee:
   zonder die omkering bleef de smalle kolom links staan terwijl de foto naar
   rechts verhuisde, en werd elke tweede bol de helft groter dan de rest. */
.teamlid:nth-child(even) { grid-template-columns: minmax(0, 3fr) minmax(0, 2fr); }
.teamlid:nth-child(even) .teamlid__foto { order: 1; }

.teamlid__foto img {
  width: 100%;
  filter: grayscale(1);
  transition: filter var(--overgang);
}
.teamlid:hover .teamlid__foto img { filter: grayscale(0); }

.teamlid__naam { margin-bottom: 0.15em; }

.teamlid__functie {
  margin: 0 0 var(--ruimte-s);
  font-family: var(--font-kop);
  font-size: 1.05rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--grijs-donker);
}

.teamlid__citaat {
  margin-top: var(--ruimte-s);
  padding-left: var(--ruimte-s);
  border-left: 3px solid var(--zwart);
  font-style: italic;
}

.teamraster {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: var(--ruimte-m);
}
.teamraster .teamlid { grid-template-columns: 1fr; text-align: center; }
.teamraster .teamlid__foto { order: 0 !important; }

/* ---------------------------------------------------------------- prijzen */

.prijsgroep { margin-bottom: var(--ruimte-xl); }
.prijsgroep:last-child { margin-bottom: 0; }

.prijsgroep__intro {
  max-width: var(--leesbreedte);
  margin-bottom: var(--ruimte-m);
}

.prijslijst {
  margin: 0;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--grijs-lijn);
}

.prijsregel {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0 var(--ruimte-xs);
  padding: 0.85rem 0;
  border-bottom: 1px solid var(--grijs-lijn);
}

.prijsregel__naam { flex: 1 1 60%; }

/* Stippellijn tussen dienst en prijs — leest prettiger dan een tabel. */
.prijsregel__vulling {
  flex: 1 1 auto;
  min-width: 1.5rem;
  align-self: center;
  height: 1px;
  border-bottom: 1px dotted var(--grijs);
}

.prijsregel__prijs {
  flex: 0 0 auto;
  font-family: var(--font-kop);
  font-size: 1.15rem;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  white-space: nowrap;
}

.prijsregel__toelichting {
  flex: 1 1 100%;
  font-size: 0.9em;
  color: var(--grijs-donker);
}

.prijsnoot {
  margin-top: var(--ruimte-s);
  padding: var(--ruimte-s);
  background: var(--grijs-licht);
  font-size: 0.95em;
}

/* -------------------------------------------------------------- berichten */

.berichtenraster {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: var(--ruimte-m);
}

.berichtkaart {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--grijs-lijn);
  background: var(--wit);
  transition: transform var(--overgang), box-shadow var(--overgang);
}
.berichtkaart:hover {
  transform: translateY(-4px);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
}

.berichtkaart__beeld { aspect-ratio: 16 / 10; overflow: hidden; }
.berichtkaart__beeld img { width: 100%; height: 100%; object-fit: cover; }

.berichtkaart__inhoud { padding: var(--ruimte-s); }

.berichtkaart__datum {
  display: block;
  margin-bottom: 0.35rem;
  font-size: 0.85rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--grijs-donker);
}

.berichtkaart__titel { font-size: var(--kop-3); margin-bottom: 0.4em; }
.berichtkaart__titel a { text-decoration: none; }
.berichtkaart__titel a:hover { text-decoration: underline; }

.bericht__kop { margin-bottom: var(--ruimte-m); text-align: center; }
.bericht__inhoud { max-width: var(--leesbreedte); margin-inline: auto; }

/* --------------------------------------------------------------- galerij */

.galerij {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: var(--ruimte-xs);
  list-style: none;
  margin: 0;
  padding: 0;
}

.galerij img {
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
  transition: transform var(--overgang);
}
.galerij li { overflow: hidden; }
.galerij li:hover img { transform: scale(1.05); }

/* -------------------------------------------------------------- partners */

.partners {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--ruimte-l);
  list-style: none;
  margin: 0;
  padding: 0;
}

.partners img {
  width: auto;
  max-height: 90px;
  /* Was 0.75. Deze logo's staan op de achtergrondfoto, en die is precies hier
     op zijn drukst: doorschijnend maakte ze niet ingetogen maar onleesbaar. */
  opacity: 0.9;
  transition: opacity var(--overgang);
}
.partners a:hover img, .partners a:focus-visible img { opacity: 1; }

/* Er stond hier grayscale(1). Dat had geen zichtbaar effect op de vlakke
   woordmerken — die zijn al zwart-wit — en haalde bij de enige partner met
   een eigen kleur (het oranje van Pedisole) juist het herkenpunt weg. */

/* De glazen bollen zijn groter aangeleverd dan de vlakke woordmerken; op
   gelijke hoogte oogt de bol dan klein, want een groot deel ervan is rand. */
.partners__logo--bol img { max-height: 110px; }

/* --- lege rand goedmaken --------------------------------------------------
   Twee bestanden van 370 bij 370 kunnen een bol van heel verschillende grootte
   bevatten: bij pune raakt de bol de rand, bij BY-ES en Pedisole zit er
   veertien procent niets omheen. Een maximumhoogte begrenst het hele bestand,
   dus dan staat de ene bol groter dan de andere — precies wat er te zien was.

   Hier staat per vullingspercentage hoe ruim de begrenzing dan moet zijn, zo
   gekozen dat de bol zélf altijd 110 pixels hoog wordt. Een ladder in stappen
   van twee procent en geen berekening per bestand, omdat het beveiligingsbeleid
   geen stijl in de pagina zelf toestaat; twee procent op 110 pixels is ruim
   binnen wat een oog ziet. Welke stap een logo krijgt, wordt gemeten en niet
   ingesteld — zie Media::vulling(). */
:root {
  --logo-vul-70: 157px;
  --logo-vul-72: 153px;
  --logo-vul-74: 149px;
  --logo-vul-76: 145px;
  --logo-vul-78: 141px;
  --logo-vul-80: 138px;
  --logo-vul-82: 134px;
  --logo-vul-84: 131px;
  --logo-vul-86: 128px;
  --logo-vul-88: 125px;
  --logo-vul-90: 122px;
  --logo-vul-92: 120px;
  --logo-vul-94: 117px;
  --logo-vul-96: 115px;
  --logo-vul-98: 112px;
  --logo-vul-100: 110px;
}

.partners__logo--bol.partners__logo--vul70 img { max-height: var(--logo-vul-70); }
.partners__logo--bol.partners__logo--vul72 img { max-height: var(--logo-vul-72); }
.partners__logo--bol.partners__logo--vul74 img { max-height: var(--logo-vul-74); }
.partners__logo--bol.partners__logo--vul76 img { max-height: var(--logo-vul-76); }
.partners__logo--bol.partners__logo--vul78 img { max-height: var(--logo-vul-78); }
.partners__logo--bol.partners__logo--vul80 img { max-height: var(--logo-vul-80); }
.partners__logo--bol.partners__logo--vul82 img { max-height: var(--logo-vul-82); }
.partners__logo--bol.partners__logo--vul84 img { max-height: var(--logo-vul-84); }
.partners__logo--bol.partners__logo--vul86 img { max-height: var(--logo-vul-86); }
.partners__logo--bol.partners__logo--vul88 img { max-height: var(--logo-vul-88); }
.partners__logo--bol.partners__logo--vul90 img { max-height: var(--logo-vul-90); }
.partners__logo--bol.partners__logo--vul92 img { max-height: var(--logo-vul-92); }
.partners__logo--bol.partners__logo--vul94 img { max-height: var(--logo-vul-94); }
.partners__logo--bol.partners__logo--vul96 img { max-height: var(--logo-vul-96); }
.partners__logo--bol.partners__logo--vul98 img { max-height: var(--logo-vul-98); }
.partners__logo--bol.partners__logo--vul100 img { max-height: var(--logo-vul-100); }

/* --- rustige band achter de logo's ----------------------------------------
   De bollen zijn van glas: de achtergrondfoto schijnt er dwars doorheen, en
   precies achter deze strook is die foto op zijn drukst (fel groen haar). Geen
   filter lost dat op, want het probleem zit niet in het logo maar erachter.

   Vandaar een donkere band die aan de boven- en onderkant uitvloeit. Geen
   vlak met randen: dan wordt het een kader midden op de foto. Alleen wanneer
   er een achtergrondfoto is — zonder foto valt er niets te dempen. */
.heeft-achtergrondfoto .sectie--partners {
  background: linear-gradient(
    to bottom,
    rgba(0, 0, 0, 0) 0%,
    rgba(0, 0, 0, .72) 22%,
    rgba(0, 0, 0, .72) 78%,
    rgba(0, 0, 0, 0) 100%
  );
}

/* ---------------------------------------------------------------- citaat */

.citaat {
  max-width: 30ch;
  margin: 0 auto;
  text-align: center;
}

.citaat__tekst {
  font-family: var(--font-kop);
  font-size: var(--kop-2);
  line-height: 1.15;
  text-transform: uppercase;
}

.citaat__bron {
  display: block;
  margin-top: var(--ruimte-s);
  font-family: var(--font-tekst);
  font-size: 0.9rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--grijs-donker);
}

/* ----------------------------------------------------------------- video */

.video {
  position: relative;
  aspect-ratio: 16 / 9;
  background: var(--zwart);
  border: none;
  padding: 0;
  cursor: pointer;
  width: 100%;
}

.video img { width: 100%; height: 100%; object-fit: cover; opacity: 0.85; }

/* Zodra de bezoeker op de knop drukt, wordt die vervangen door dit vak met
   de video erin — een iframe hoort niet binnen een button te staan. */
.video--speelt { cursor: default; }
.video--speelt iframe { width: 100%; height: 100%; border: 0; display: block; }

.video__knop {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  color: var(--wit);
  font-family: var(--font-kop);
  font-size: 1.2rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.video iframe { width: 100%; height: 100%; border: 0; }

/* ------------------------------------------------------------- gegevens */

.gegevens {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: var(--ruimte-l);
}

.openingstijden { margin: 0; }
.openingstijden > div {
  display: flex;
  justify-content: space-between;
  gap: var(--ruimte-s);
  padding: 0.3rem 0;
  border-bottom: 1px solid rgba(0, 0, 0, 0.12);
}
.openingstijden dt { font-weight: 700; }
.openingstijden dd { margin: 0; }
/* --grijs op lichtgrijs haalt 4,45:1 en blijft daarmee net onder de
   4,5:1 die nodig is om vlot leesbaar te zijn. */
.openingstijden .gesloten { color: var(--grijs-donker); }

/* -------------------------------------------------------------- formulier */

/* Gecentreerd, net als .leeskolom en .sectie__kop erboven. De maximumbreedte
   stond er al, de marge niet — daardoor plakte het contactformulier tegen de
   linkerkant terwijl "Contactformulier" erboven keurig in het midden stond.
   Dit raakt alleen de site: het beheer laadt beheer.css en niet site.css. */
.formulier {
  display: grid;
  gap: var(--ruimte-s);
  max-width: 34rem;
  margin-inline: auto;
}

.veld { display: grid; gap: 0.35rem; }

.veld__label {
  font-family: var(--font-kop);
  font-size: 1rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.formulier input, .formulier textarea {
  width: 100%;
  padding: 0.7rem 0.8rem;
  font: inherit;
  color: var(--inkt);
  background: var(--wit);
  border: var(--rand);
}

.formulier textarea { min-height: 9rem; resize: vertical; }

/* Honeypot: onzichtbaar voor mensen, aantrekkelijk voor invulrobots. */
.honingpot {
  position: absolute;
  left: -9999px;
  opacity: 0;
  pointer-events: none;
}

/* --- meldingen bij een formulier ------------------------------------------
   Een melding zet altijd zélf én zijn achtergrond én zijn tekstkleur. Dat
   klinkt vanzelfsprekend maar stond hier niet: er stond alleen een lichte
   vulling. Op een site die wit op zwart is, erft de tekst dan wit — en dan
   staat er witte tekst op een bijna witte balk. De bevestiging na het
   contactformulier was daardoor letterlijk niet te lezen. */
.melding {
  /* Even breed en even ver ingesprongen als het formulier eronder; anders
     staat er een balk over de volle breedte boven een smalle kolom. */
  max-width: 34rem;
  margin-inline: auto;
  margin-block-end: var(--ruimte-m);
  padding: var(--ruimte-s);
  border-left: 4px solid var(--zwart);
  background: var(--grijs-licht);
  color: var(--inkt);
}
.melding--fout   { border-left-color: #a4262c; background: #fde7e9; color: #5c1418; }
.melding--succes { border-left-color: #0b6a3a; background: #e4f6ec; color: #0b3d24; }
.melding a { color: inherit; }

/* --- het bericht is verstuurd ---------------------------------------------
   Na het versturen stond er een pastelgroen balkje onder een formulier dat
   gewoon weer leeg klaarstond. Twee dingen mis: het balkje hoort niet bij een
   site die zwart-wit is, en een leeg formulier eronder leest als "er is niets
   gebeurd, probeer het nog eens".

   Dus: het formulier maakt plaats voor de bevestiging. Wie tóch nog een
   bericht wil sturen krijgt daar een link voor, en wie liever meteen antwoord
   wil, ziet het telefoonnummer. */
.verstuurd {
  max-width: 32rem;
  margin: 0 auto;
  padding: var(--ruimte-l) var(--ruimte-m);
  border: 1px solid var(--grijs-lijn);
  text-align: center;
}

/* De ring met het vinkje. Dezelfde vorm als de bollen die de site overal
   gebruikt, alleen leeg — een bevestiging hoort rustig te zijn. */
.verstuurd__teken {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 3.5rem;
  height: 3.5rem;
  margin: 0 auto var(--ruimte-s);
  border: 1px solid currentColor;
  border-radius: 50%;
}
.verstuurd__teken svg { width: 1.5rem; height: 1.5rem; }

.verstuurd__kop {
  margin: 0 0 var(--ruimte-xs);
  font-family: var(--font-kop);
  font-size: var(--kop-3);
  letter-spacing: .02em;
  text-transform: uppercase;
}
.verstuurd p { margin: 0 0 var(--ruimte-xs); }
.verstuurd p:last-child { margin-bottom: 0; }
.verstuurd__nogmaals { font-size: .9em; }

/* ------------------------------------------------------------------- voet */

.voet {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: var(--ruimte-l);
  padding: var(--ruimte-xl) var(--ruimte-s) var(--ruimte-l);
  border-top: var(--lijn);
  background: var(--zwart);
  color: var(--wit);
}

.voet a { color: var(--wit); }

.voet__blok { max-width: 22rem; margin-inline: auto; width: 100%; }

.voet__naam {
  font-family: var(--font-kop);
  font-size: var(--kop-3);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.voet__klein { font-size: 0.85rem; color: rgba(255, 255, 255, 0.7); }

.voet .openingstijden > div { border-bottom-color: rgba(255, 255, 255, 0.18); }
.voet .openingstijden .gesloten { color: rgba(255, 255, 255, 0.55); }

.sociaal {
  display: flex;
  gap: var(--ruimte-s);
  list-style: none;
  margin: var(--ruimte-s) 0 0;
  padding: 0;
}
.sociaal a { display: grid; place-items: center; width: 40px; height: 40px; border: 1px solid currentColor; text-decoration: none; }
.sociaal a:hover { background: var(--wit); color: var(--zwart); }
.sociaal svg { width: 20px; height: 20px; fill: currentColor; }

.voet__onder {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--ruimte-s) var(--ruimte-m);
  padding: var(--ruimte-s);
  background: var(--zwart);
  color: rgba(255, 255, 255, 0.7);
  font-size: 0.85rem;
  text-align: center;
}
.voet__onder a { color: inherit; }

.leeg { color: var(--grijs); font-style: italic; text-align: center; padding: var(--ruimte-xl) var(--ruimte-s); }

/* --------------------------------------------------------------- paginering */

.paginering {
  display: flex;
  justify-content: center;
  gap: var(--ruimte-xs);
  margin-top: var(--ruimte-l);
}
.paginering a, .paginering span {
  padding: 0.5rem 0.9rem;
  border: 1px solid var(--grijs-lijn);
  text-decoration: none;
}
.paginering [aria-current="page"] { background: var(--zwart); color: var(--wit); border-color: var(--zwart); }

/* -------------------------------------------------------------- witruimte */

.witruimte--klein   { height: var(--ruimte-m); }
.witruimte--normaal { height: var(--ruimte-l); }
.witruimte--groot   { height: var(--ruimte-xl); }

/* ================================================================ mobiel */

@media (max-width: 900px) {
  /* Onder elkaar op een smal scherm. De even rijen worden hier apart
     genoemd omdat die hierboven hun eigen kolomverdeling krijgen; zonder die
     regel bleven ze in twee kolommen staan en liep de pagina over. */
  .duo, .teamlid, .teamlid:nth-child(even) { grid-template-columns: 1fr; }
  /* Links of rechts kan hier niet meer, dus valt de foto onder de tekst.
     Boven en onder blijven wel staan: dat is een bewuste keuze, geen
     kolomverdeling die op een smal scherm niet past. */
  .duo--links .duo__beeld, .teamlid:nth-child(even) .teamlid__foto { order: 0; }
}

@media (max-width: 700px) {
  /* Het menu wordt alleen verstopt als JavaScript draait — site.js zet de
     klasse `js` op <html>. Laadt dat bestand niet, dan staat het menu er
     gewoon uitgeklapt en is de site nog te bedienen. Zonder deze koppeling
     was er buiten het logo geen enkele navigatie. */
  .js .menuknop { display: inline-flex; }

  .js .hoofdmenu {
    display: none;
    width: 100%;
  }
  .js .hoofdmenu.is-open { display: block; }

  .hoofdmenu ul {
    flex-direction: column;
    align-items: center;
    gap: var(--ruimte-s);
    padding: var(--ruimte-s) 0;
  }

  .hoofdmenu a { font-size: 1.2rem; }

  .voet { text-align: center; }
  .sociaal { justify-content: center; }
}

@media (max-width: 500px) {
  /* Op een telefoon past er nog één bol per rij; die wikkeling regelt
     flexbox zelf. Wel een bovengrens, zodat één bol niet het halve scherm
     vult op een groot toestel. */
  .bol { max-width: min(calc(var(--bolmaat, 220px) * var(--schaal, 1) * var(--nadruk, 1)), 320px); }
}

/* ================================================================ afdruk */

@media print {
  .meldingsbalk, .hoofdmenu, .menuknop, .knop, .sociaal { display: none !important; }
  body { color: #000; background: #fff; font-family: Georgia, serif; }
  .voet, .voet__onder { background: #fff; color: #000; border-top: 1px solid #000; }
  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 0.85em; }
}

/* ------------------------------------------------------------ cookiebanner
   Staat standaard uit: de site laadt niets van buitenaf, dus er worden geen
   cookies van derden geplaatst en is er juridisch geen toestemming nodig.
   De module zit er wel in, voor als er later toch een embed bij komt. */

.cookiebalk {
  position: fixed;
  left: 50%;
  bottom: var(--ruimte-s);
  transform: translateX(-50%);
  z-index: 150;
  width: min(680px, calc(100vw - 2rem));
  padding: var(--ruimte-s) var(--ruimte-m);
  background: var(--zwart);
  color: var(--wit);
  border: 2px solid var(--wit);
  box-shadow: 0 10px 40px rgba(0, 0, 0, .4);
  font-size: .95rem;
}

.cookiebalk[hidden] { display: none; }
.cookiebalk p { margin: 0 0 var(--ruimte-s); }
.cookiebalk a { color: var(--wit); }

.cookiebalk__knoppen { display: flex; flex-wrap: wrap; gap: var(--ruimte-xs); }
.cookiebalk .knop { padding: .5rem 1.1rem; font-size: .95rem; }

/* ==========================================================================
   Bewegende bollen
   --------------------------------------------------------------------------
   Twee bewegingen tegelijk, net als op de oude site:

   1. ZWEVEN  — elke bol maakt continu een klein rondje, met een eigen duur en
      een eigen startpunt, zodat ze nooit synchroon lopen.
   2. DRIJVEN — tijdens het scrollen drijft elke bol een eigen kant op, de een
      naar links, de ander naar rechts, met verschillende snelheden.

   Hoeveel er beweegt is instelbaar bij het blok (--kracht). Op een telefoon
   wordt dat automatisch gehalveerd: daar staan de bollen onder elkaar, is er
   minder ruimte, en beweging leidt eerder af dan dat het mooi is.

   Waarom dit botsingsvrij is: het zweven gebruikt de eigenschap `translate`
   op de bol, het drijven `translate` op de cel eromheen, en hover gebruikt
   `transform`. Drie losse eigenschappen die de browser optelt tot één
   beweging — met drie keer `transform` had de laatste de rest gewist.
   ========================================================================== */

@media (prefers-reduced-motion: no-preference) {

  /* Sterkte, instelbaar per blok. 1 is de basis; alle uitslagen hieronder
     worden ermee vermenigvuldigd. */
  .bollen                    { --kracht: 1; }
  .bollen--beweging-rustig   { --kracht: 0.55; }
  .bollen--beweging-normaal  { --kracht: 1; }
  .bollen--beweging-levendig { --kracht: 1.8; }

  /* ------------------------------------------------------- 1. continu zweven */

  .bollen--beweging-uit .bol { animation: none; }

  .bol {
    --zweef-x: 8px;
    --zweef-y: 11px;
    --zweef-duur: 9s;
    --zweef-start: 0s;
    --kantel: 1deg;

    animation: bol-zweeft var(--zweef-duur) ease-in-out infinite;
    animation-delay: var(--zweef-start);
  }

  /* Een klein rondje in plaats van heen en weer: dat oogt organischer
     en er is geen moment waarop de bol stilstaat. */
  @keyframes bol-zweeft {
    0% {
      translate: 0 0;
      rotate: 0deg;
    }
    25% {
      translate: calc(var(--zweef-x) * var(--kracht)) calc(var(--zweef-y) * var(--kracht) * -0.7);
      rotate: calc(var(--kantel) * var(--kracht));
    }
    50% {
      translate: calc(var(--zweef-x) * var(--kracht) * 0.3) calc(var(--zweef-y) * var(--kracht) * -1);
      rotate: 0deg;
    }
    75% {
      translate: calc(var(--zweef-x) * var(--kracht) * -1) calc(var(--zweef-y) * var(--kracht) * -0.4);
      rotate: calc(var(--kantel) * var(--kracht) * -1);
    }
    100% {
      translate: 0 0;
      rotate: 0deg;
    }
  }

  /* Elke bol een eigen ritme. De negatieve vertraging laat de animatie
     midden in de beweging beginnen, zodat ze meteen uit de pas lopen in
     plaats van pas na de eerste ronde. */
  .bollen li:nth-child(7n + 1) .bol { --zweef-x:  10px; --zweef-y:  13px; --zweef-duur:  9s;   --zweef-start: -0.4s; --kantel:  1.3deg; }
  .bollen li:nth-child(7n + 2) .bol { --zweef-x:  -8px; --zweef-y:  10px; --zweef-duur: 11s;   --zweef-start: -3.1s; --kantel: -0.9deg; }
  .bollen li:nth-child(7n + 3) .bol { --zweef-x:   7px; --zweef-y: -12px; --zweef-duur:  8s;   --zweef-start: -5.6s; --kantel:  1.6deg; }
  .bollen li:nth-child(7n + 4) .bol { --zweef-x: -12px; --zweef-y:   9px; --zweef-duur: 12s;   --zweef-start: -1.9s; --kantel: -1.3deg; }
  .bollen li:nth-child(7n + 5) .bol { --zweef-x:   9px; --zweef-y:  12px; --zweef-duur: 10s;   --zweef-start: -7.2s; --kantel:  0.8deg; }
  .bollen li:nth-child(7n + 6) .bol { --zweef-x:  -7px; --zweef-y: -10px; --zweef-duur: 13s;   --zweef-start: -2.5s; --kantel: -1.7deg; }
  .bollen li:nth-child(7n)     .bol { --zweef-x:  11px; --zweef-y:  10px; --zweef-duur:  9.5s; --zweef-start: -6.3s; --kantel:  1.2deg; }

  /* --------------------------------------------------- 2. drijven bij scrollen */

  @supports (animation-timeline: view()) {

    .bollen li {
      --drijf-x: 0px;
      --drijf-y: 40px;

      /* Twee animaties: verschijnen regelt de doorzichtigheid, drijven de
         verplaatsing. Verschillende eigenschappen, dus ze bijten elkaar niet. */
      animation: bol-verschijnt linear both, bol-drijft linear both;
      animation-timeline: view(), view();
      animation-range: entry 5% entry 55%, entry 0% exit 100%;
    }

    .bollen--beweging-uit li { animation: bol-verschijnt linear both; animation-timeline: view(); }

    @keyframes bol-verschijnt {
      from { opacity: 0; }
      to   { opacity: 1; }
    }

    @keyframes bol-drijft {
      from {
        translate: calc(var(--drijf-x) * var(--kracht) * -1) calc(var(--drijf-y) * var(--kracht));
      }
      to {
        translate: calc(var(--drijf-x) * var(--kracht)) calc(var(--drijf-y) * var(--kracht) * -1);
      }
    }

    /* Richtingen en snelheden door elkaar, zoals op de oude site: de een
       schuift naar links terwijl de ander naar rechts gaat. */
    .bollen li:nth-child(7n + 1) { --drijf-x: -52px; --drijf-y:  44px; }
    .bollen li:nth-child(7n + 2) { --drijf-x:  38px; --drijf-y: -54px; }
    .bollen li:nth-child(7n + 3) { --drijf-x: -28px; --drijf-y:  62px; }
    .bollen li:nth-child(7n + 4) { --drijf-x:  58px; --drijf-y:  30px; }
    .bollen li:nth-child(7n + 5) { --drijf-x: -44px; --drijf-y: -38px; }
    .bollen li:nth-child(7n + 6) { --drijf-x:  24px; --drijf-y:  50px; }
    .bollen li:nth-child(7n)     { --drijf-x: -34px; --drijf-y: -46px; }

    /* Een glansje dat met het scrollen over het glas trekt. */
    .bol__beeld {
      animation: bol-glans linear both;
      animation-timeline: view();
      animation-range: entry 0% exit 100%;
    }

    @keyframes bol-glans {
      from { filter: brightness(0.94) saturate(0.9); }
      50%  { filter: brightness(1.06) saturate(1.05); }
      to   { filter: brightness(0.94) saturate(0.9); }
    }
  }

  /* Op een telefoon de helft: daar staan de bollen onder elkaar, is er weinig
     ruimte, en te veel beweging leidt af van waar het om gaat. */
  @media (max-width: 700px) {
    .bollen                    { --kracht: 0.45; }
    .bollen--beweging-rustig   { --kracht: 0.25; }
    .bollen--beweging-normaal  { --kracht: 0.45; }
    .bollen--beweging-levendig { --kracht: 0.8; }
  }
}

/* ==========================================================================
   Donkere achtergrond
   --------------------------------------------------------------------------
   Zodra de achtergrond donker is, keert de site om. Dat is niet alleen een
   kwestie van smaak: zwarte tekst en zwarte logo's verdwijnen letterlijk in
   een donkere achtergrond.

   De klasse komt van de server, die de werkelijke helderheid van de
   achtergrondfoto meet (inclusief de witte sluier eroverheen). Handmatig
   vastzetten kan ook, bij Instellingen.
   ========================================================================== */

.donkere-achtergrond {
  color: var(--wit);
}

.donkere-achtergrond h1,
.donkere-achtergrond h2,
.donkere-achtergrond h3,
.donkere-achtergrond h4 { color: var(--wit); }

/* --- kop en menu ---------------------------------------------------------- */

.donkere-achtergrond .kop {
  background: var(--zwart);
}

/* Het logo is zwart met een doorzichtige achtergrond; omkeren maakt er
   een wit logo van zonder dat er een tweede bestand nodig is. */
.donkere-achtergrond .kop__logo img { filter: invert(1); }

.donkere-achtergrond .hoofdmenu a { color: var(--wit); }
.donkere-achtergrond .hoofdmenu a::after { background: var(--wit); }

.donkere-achtergrond .menuknop {
  color: var(--wit);
  background: var(--zwart);
  border-color: var(--wit);
}
.donkere-achtergrond .menuknop__streepjes span { background: var(--wit); }

/* --- inhoud --------------------------------------------------------------- */

.donkere-achtergrond .sectie--grijs {
  background: rgba(0, 0, 0, 0.45);
  color: var(--wit);
}
.donkere-achtergrond .sectie--grijs h2,
.donkere-achtergrond .sectie--grijs h3 { color: var(--wit); }

/* Een zwart vlak op een donkere achtergrond valt weg; daar draaien we om. */
.donkere-achtergrond .sectie--zwart {
  background: var(--wit);
  color: var(--inkt);
}
.donkere-achtergrond .sectie--zwart h1,
.donkere-achtergrond .sectie--zwart h2,
.donkere-achtergrond .sectie--zwart h3 { color: var(--inkt); }

.donkere-achtergrond .knop {
  color: var(--zwart);
  background: var(--wit);
  border-color: var(--wit);
}
.donkere-achtergrond .knop:hover,
.donkere-achtergrond .knop:focus-visible {
  color: var(--wit);
  background: transparent;
}

.donkere-achtergrond :focus-visible { outline-color: var(--wit); }

/* --- de logo's onderaan de pagina ----------------------------------------- */

/* Alleen de zwarte tekeningen worden omgekeerd; die worden dan wit en blijven
   op een donkere achtergrond leesbaar.

   Dit stond eerst op álle partnerlogo's, en dat was mis. Drie van de vijf zijn
   glazen bollen met het logo van de partner erin — dezelfde bollen die de site
   als navigatie gebruikt, eentje zelfs met een oranje vlak. Die zijn al licht
   en horen al op zwart thuis. Omgekeerd werden het donkergrijze schijven waar
   niets meer in te lezen viel.
   
   Welke van de twee het is, wordt niet met de hand ingesteld maar gemeten:
   zie Media::isDonker(). Een logo dat er later bij komt staat daarmee vanzelf
   goed. */
.donkere-achtergrond .partners__logo--donker img { filter: invert(1); }

/* --- bollen --------------------------------------------------------------- */

/* Het glas blijft licht; alleen het label draait om, met een donkere gloed
   in plaats van een witte. */
.donkere-achtergrond .bol__label {
  color: var(--wit);
  text-shadow: 0 0 14px rgba(0, 0, 0, 0.95), 0 0 5px rgba(0, 0, 0, 0.95);
}

/* --- lijsten, randen en formulieren --------------------------------------- */

.donkere-achtergrond .prijslijst,
.donkere-achtergrond .prijsregel { border-color: rgba(255, 255, 255, 0.28); }

/* Op een donkere achtergrond laat de bevestiging de foto nog nét schemeren; de
   rand houdt hem afgebakend zonder er een wit vlak van te maken.

   0.72 en niet 0.45 — nagemeten, niet gekozen op gevoel. De achtergrondfoto op
   de site heeft lichte plekken tot rgb(255,233,255), en de sluier over de foto
   staat op nul. Witte tekst op 45 procent zwart kwam daar uit op 3,8:1, onder
   de norm van 4,5:1. Bij 0.72 is het slechtste punt 9,9:1, en dat blijft ook
   goed als er ooit een lichtere foto wordt ingesteld: zelfs op zuiver wit komt
   het nog op 9,1:1 uit. */
.donkere-achtergrond .verstuurd {
  border-color: rgba(255, 255, 255, 0.35);
  background: rgba(0, 0, 0, 0.72);
  color: var(--wit);
}

.donkere-achtergrond .prijsregel__vulling { border-bottom-color: rgba(255, 255, 255, 0.4); }
.donkere-achtergrond .prijsregel__toelichting { color: rgba(255, 255, 255, 0.75); }

.donkere-achtergrond .prijsnoot {
  background: rgba(255, 255, 255, 0.12);
  color: var(--wit);
}

.donkere-achtergrond .berichtkaart {
  background: rgba(0, 0, 0, 0.4);
  border-color: rgba(255, 255, 255, 0.28);
}
.donkere-achtergrond .berichtkaart__datum { color: rgba(255, 255, 255, 0.7); }

.donkere-achtergrond .teamlid__functie,
.donkere-achtergrond .citaat__bron { color: rgba(255, 255, 255, 0.75); }

.donkere-achtergrond .teamlid__citaat { border-left-color: var(--wit); }

.donkere-achtergrond .formulier input,
.donkere-achtergrond .formulier textarea {
  color: var(--wit);
  background: rgba(0, 0, 0, 0.35);
  border-color: var(--wit);
}
.donkere-achtergrond .formulier input::placeholder,
.donkere-achtergrond .formulier textarea::placeholder { color: rgba(255, 255, 255, 0.6); }

.donkere-achtergrond .openingstijden > div { border-bottom-color: rgba(255, 255, 255, 0.2); }
.donkere-achtergrond .openingstijden .gesloten { color: rgba(255, 255, 255, 0.6); }

.donkere-achtergrond .leeg { color: rgba(255, 255, 255, 0.65); }

.donkere-achtergrond .paginering a,
.donkere-achtergrond .paginering span { border-color: rgba(255, 255, 255, 0.35); }
.donkere-achtergrond .paginering [aria-current="page"] {
  background: var(--wit);
  color: var(--zwart);
}

/* ==========================================================================
   Achtergrondfoto: welke vlakken wijken
   --------------------------------------------------------------------------
   Zodra er een achtergrondfoto is gekozen, moeten de dekkende vlakken
   opzijgaan — anders zie je de foto alleen in een smalle strook tussen de
   kop en de voet.

   Deze regels staan hier en niet in de gegenereerde stylesheet, omdat een
   regel als `.donkere-achtergrond .kop` twee klassen heeft en daarmee
   zwaarder weegt dan een losse `.kop`. De gegenereerde stylesheet bevat
   alleen de waarden die pas bekend zijn als er iets gekozen is; de opmaak
   hoort hier, waar de volgorde en zwaarte kloppen.
   ========================================================================== */

/* De achtergrondfoto zit in een eigen laag achter de pagina, niet op body
   zelf. Dat is niet netter maar noodzakelijk:

   Op body met `background-attachment: scroll` schaalt de browser de foto op
   de HELE PAGINAHOOGTE. Bij een pagina van bijna 4000px op een telefoon van
   390px breed werd de foto 1,9x uitvergroot en zag je nog maar een strook
   van 200px breed - een uitgesmeerde veeg. Met `fixed` gebeurt dat niet,
   maar dat schokt op iOS bij het scrollen.

   Een vaste laag lost allebei op: hij is precies zo groot als het scherm,
   schaalt dus altijd goed, en schokt niet. */
.heeft-achtergrondfoto {
  position: relative;
}

.heeft-achtergrondfoto::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  background-position: center;
  background-size: cover;
  background-repeat: no-repeat;
  pointer-events: none;
}

/* Meescrollend: de laag hangt aan de bovenkant van de pagina en schuift weg. */
.heeft-achtergrondfoto.achtergrond-meescrollend::before {
  position: absolute;
  inset: 0 0 auto 0;
  height: 100vh;
}

/* Herhalend patroon: geen uitsnede, gewoon tegelen op ware grootte. */
.heeft-achtergrondfoto.achtergrond-herhalend::before {
  background-size: auto;
  background-repeat: repeat;
}

/* De kop met het logo laat de foto volledig door. Twee selectors met
   dezelfde zwaarte als de donkere-modusregel, en later in het bestand,
   zodat ze het altijd winnen. De kop heeft sinds 23-08-2026 geen streep
   meer onderaan; de losse <hr> en de bovenrand van de voet gebruiken
   --lijn nog wel. */
.heeft-achtergrondfoto .kop,
.heeft-achtergrondfoto.donkere-achtergrond .kop {
  background: transparent;
}

/* De meldingsbalk blijft leesbaar maar laat de foto schemeren. */
.heeft-achtergrondfoto .meldingsbalk {
  background: rgba(0, 0, 0, 0.82);
}

/* De voet blijft donker genoeg om te lezen, maar wordt geen harde plaat
   over de foto heen. */
.heeft-achtergrondfoto .voet,
.heeft-achtergrondfoto .voet__onder,
.heeft-achtergrondfoto.donkere-achtergrond .voet,
.heeft-achtergrondfoto.donkere-achtergrond .voet__onder {
  background: rgba(0, 0, 0, 0.78);
  border-top-color: rgba(255, 255, 255, 0.25);
}

/* Grijze secties worden een sluier in plaats van een vlak. */
.heeft-achtergrondfoto .sectie--grijs {
  background: rgba(241, 241, 241, 0.82);
}
.heeft-achtergrondfoto.donkere-achtergrond .sectie--grijs {
  background: rgba(0, 0, 0, 0.5);
}

/* Kaarten mogen ook wat doorschijnen, anders staan er losse witte blokken
   over de foto. */
.heeft-achtergrondfoto .berichtkaart { background: rgba(255, 255, 255, 0.9); }
.heeft-achtergrondfoto.donkere-achtergrond .berichtkaart { background: rgba(0, 0, 0, 0.55); }

/* Het logo in de kop staat nu direct op de foto; een zachte schaduw houdt
   het leesbaar, ook als de foto op die plek toevallig licht is. */
.heeft-achtergrondfoto .kop__logo img {
  filter: drop-shadow(0 2px 10px rgba(0, 0, 0, 0.45));
}
.heeft-achtergrondfoto.donkere-achtergrond .kop__logo img {
  filter: invert(1) drop-shadow(0 2px 10px rgba(0, 0, 0, 0.55));
}

/* Dezelfde reden voor de menu-items. */
.heeft-achtergrondfoto .hoofdmenu a,
.heeft-achtergrondfoto .meldingsbalk {
  text-shadow: 0 1px 6px rgba(0, 0, 0, 0.5);
}
.heeft-achtergrondfoto:not(.donkere-achtergrond) .hoofdmenu a {
  text-shadow: 0 1px 6px rgba(255, 255, 255, 0.85);
}

/* Kleine hulpklassen voor losse ruimte. Deze bestaan omdat een
   style-attribuut door de beveiligingsregels wordt geblokkeerd; met een
   handvol vaste maten is een klasse ook gewoon netter. */
.ruimte-boven-s { margin-top: var(--ruimte-s); }
.ruimte-boven-m { margin-top: var(--ruimte-m); }
.ruimte-boven-l { margin-top: var(--ruimte-l); }
