/*
Theme Name: Jimmy-Dean 2026
Theme URI: https://jimmy-dean.nl/
Author: Jimmy-Dean
Author URI: https://jimmy-dean.nl/
Template: Bootstrap-on-WordPress
Description: Portfolio thema op basis van Materialize CSS v2.3. Opvolger van Jimmy-Dean 2024. Het parent theme levert Bootstrap, maar dit thema schakelt dat uit in remove_theme_codes(); de opmaaklaag is volledig Materialize, met een compatibiliteitsblok in style.css voor de overstap van v1 naar v2.
Version: 4.0
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: jimmydean
*/
/* Vormschaal
   ---------------------------------------------------------------------------
   Material Design 3 werkt met een vaste reeks hoekrondingen in plaats van één
   waarde overal: extra small 4dp, small 8dp, medium 12dp, large 16dp en full.
   Elk componenttype heeft er een vaste plek in, zodat de vorm iets zegt over
   hoe groot en hoe belangrijk iets is.

   Dit thema stond overal op 4px, ook op de kaarten en de grote witte vlakken.
   Materialize v2.3.3 houdt zelf ook 4px aan voor knoppen (--btn-border-radius),
   dus dat kwam niet van MD3 maar van het framework.

   De waarden staan hier als variabelen zodat één regel de hele schaal verzet
   als de vorm te rond of te hoekig uitpakt. */
:root {
  --jd-vorm-xs: 4px;    /* kleine vlakken: tooltip, thumbnails in de kaart */
  --jd-vorm-s: 8px;     /* invoervelden */
  --jd-vorm-m: 12px;    /* kaarten en de grote inhoudsvlakken */
  --jd-vorm-l: 16px;    /* niet in gebruik; staat er voor als er een dialoog bijkomt */
  --jd-vorm-vol: 999px; /* knoppen en chips */

  /* Hoogte van de hulpbalk bovenin (.header .nav-content): 8px padding boven,
     32px min-height op de links, 8px onder -- gemeten 48,0px. Dit is het stuk dat
     wegscrollt voordat de navigatiebalk blijft hangen, dus de sticky-offset onder
     "Meelopende navigatiebalk" rekent hiermee. Stond daar als kaal getal, los van
     de --navbar-height-tokens waar de balk eronder wél mee rekent; verander je de
     padding of de tekstgrootte van die hulpbalk, dan hoort dit getal mee. */
  --jd-hulpbalk-hoogte: 48px;
}

/* Themakleur
   ---------------------------------------------------------------------------
   Materialize v2 is gebouwd op de kleurtokens van Material Design 3, afgeleid
   van één bronkleur: --md-source: #006495, een staalblauw. Elk onderdeel dat
   Materialize zelf kleurt grijpt naar die tokens -- --md-sys-color-primary komt
   78 keer voor in materialize.min.css.

   Dat blauw komt in dit thema nergens voor, en dook daardoor telkens op bij
   iets nieuws: de actieve pagina in de paginering, het vlak achter een chip met
   focus, en het pictogram naar de klantwebsite als je erover gaat. Elke keer
   losten we het op met een eigen regel op dat ene onderdeel -- dweilen terwijl
   de kraan openstaat.

   Hieronder staat de kraan dicht. Materialize zet de tokens in twee lagen op
   :root: eerst de kleuren zelf (--md-sys-color-primary-light en -dark), daarna
   een koppeling die per kleurmodus de juiste van die twee kiest. Door alleen de
   eerste laag te overschrijven blijft die koppeling werken en volgen beide modi
   vanzelf. style.css laadt na materialize, dus dit wint zonder !important.

   Alleen de accentkleuren staan hier. Vlakken en achtergronden (surface,
   background) schildert dit thema zelf, en rood voor foutmeldingen hoort rood
   te blijven.

   Nieuw onderdeel toevoegen dat Materialize kleurt? Dan hoeft er niets meer:
   het komt vanzelf in de huisstijl binnen. */
:root {
  /* Lichte modus */
  --md-sys-color-primary-light: #1a237e;
  --md-sys-color-on-primary-light: #e8eaf6;
  --md-sys-color-primary-container-light: #e8eaf6;
  --md-sys-color-on-primary-container-light: #1a237e;
  --md-sys-color-inverse-primary-light: #9fa8da;
  --md-sys-color-secondary-light: #3949ab;
  /* Gedempte tekst en pictogrammen; stond op #41474d, een neutraal grijs. */
  --md-sys-color-on-surface-variant-light: #3949ab;
  /* De rand van een outlined-knop. Stond op #72787e: een neutraal grijs dat
     Materialize afleidt van zijn eigen bronkleur (#006495, staalblauw) en dat
     naast het indigo van dit thema vuil oogt. Deze waarde is indigo lighten-1,
     dus dezelfde familie als de rest. */
  --md-sys-color-outline-light: #5c6bc0;
  /* Zie de toelichting bij --md-sys-color-outline-light. Deze waarde stond nog
     op de standaard van Materialize en wordt nergens anders in dit thema
     gebruikt; hij is hier alleen gezet zodat de kleurrol klopt als hij ooit
     wél ergens opduikt. */
  --md-sys-color-surface-tint-light: #1a237e;

  /* Donkere modus. Zelfde rollen, omgekeerd: op donker moet het accent oplichten
     in plaats van verdiepen. De waarden komen overeen met --jd-accent en
     --jd-text-muted onderaan dit bestand. */
  --md-sys-color-primary-dark: #aab4ff;
  --md-sys-color-on-primary-dark: #1a237e;
  --md-sys-color-primary-container-dark: #283593;
  --md-sys-color-on-primary-container-dark: #e8eaf6;
  --md-sys-color-inverse-primary-dark: #3949ab;
  --md-sys-color-secondary-dark: #9fa8da;
  --md-sys-color-on-surface-variant-dark: #a9adc9;
  /* Op donker moet de rand oplichten in plaats van verdiepen, net als het
     accent. Indigo lighten-3 tegen de donkere kaart. */
  --md-sys-color-outline-dark: #9fa8da;
  --md-sys-color-surface-tint-dark: #aab4ff;
}

body, html { background-color: #c5cae9; height: 100%; margin: 0; padding: 0; width: 100%; }
html { line-height: 1.5; }
body .grecaptcha-badge { display: none; }
/* De wikkel om alles heen.
   ---------------------------------------------------------------------------
   Hier stond `height: 100%` én `min-height: 100%`. Die eerste won, en daarmee was
   de tweede dood -- maar hij was ook de bedoeling: min-height houdt een korte
   pagina toch schermvullend zodat de footer onderaan blijft, zonder een lange
   pagina af te kappen. Dat is nu wat er staat.

   `height: 100%` was bovendien de enige reden dat de startpagina niet scrolt.
   Gemeten: haal je dat weg, dan groeit de pagina van 900 naar 1163px. De
   vergrendeling staat daarom nu expliciet op .home hieronder, in plaats van als
   neveneffect op elke pagina. */
.wrapper { display: flex; flex-direction: column; min-height: 100%; }
.material-tooltip { background-color: #1a237e; color: #e8eaf6; }
.popup-wrapper { width: 350px; margin: 0 auto; }
.popup-block { max-width: 350px; margin: 40px auto; position: relative; }
.flex { display: flex; flex-wrap: wrap; }
/* De chiptekst stond op #5c6bc0: op het vlak van #e8eaf6 is dat 4,06:1, en met
   13px valt dat onder de 4,5:1 die WCAG 1.4.3 voor gewone tekst vraagt. #3949ab
   is dezelfde indigo, twee stappen donkerder, en komt op 6,46:1. Het raakt elke
   chip -- ook die onder de projectkaarten -- en dat was al zo voor de toollijst
   erbij kwam. */
.chip { background: #e8eaf6; color: #3949ab; overflow: hidden; text-transform: initial; word-break: break-all; }
.divider { margin: 30px 0 15px 0; }
.valign-grid { align-items: center; }
/* Zelfde reden als bij .card .process img: zonder height: auto klemmen max-width
   en max-height allebei de presentatie-hint uit de width/height-attributen, elk
   op hun eigen as, en gaat de verhouding verloren. Nu valt het niet op omdat alle
   uitgelichte afbeeldingen vierkant zijn -- getest met een 4:3-afbeelding werd
   192x192 in plaats van 192x144. */
.related-posts-grid .img { border-radius: var(--jd-vorm-m); height: auto; max-height: 192px; max-width: 192px; }

/* De projecttitels onder Gerelateerde projecten stonden op de volle h3-maat van
   30px, in een kolom van 202px. Daardoor brak elke titel over twee regels en
   zaten ze te dicht bij de sectiekop erboven (40px). Op 20px past de kortste
   titel weer op één regel en is het verschil met die kop weer een echte stap.

   De marge gaat mee omlaag: Materialize geeft een h3 29,2px boven en 17,5px
   onder, wat bij een kop van 30px klopte maar bij 20px meer ruimte is dan de
   tekst hoog is. Het gat tussen beeld en titel gaat zo van 35 naar 18px.

   Het niveau blijft h3 -- dat is de kopstructuur van de pagina, los van de maat. */
.related-posts-grid .grid-item h3 { font-size: var(--jd-tekst-h5); margin: .8rem 0 0; }

/* Het raster is het laatste blok vóór de footer, en de ondermarge van 17,5px die
   de titel daar had is met de regel hierboven verdwenen: de titels sloten
   daardoor naadloos op de footer aan, op elke schermbreedte. De ruimte hoort ook
   niet van de kop te komen maar van het blok. 2.5rem is hetzelfde ritme als de
   rest van deze pagina: 38px onder het uitnodigingsblok, 36px boven de sectiekop. */
.related-posts-grid { padding-bottom: 2.5rem; }
.indigo-text.text-darken-5 { color: #101974 !important; }
.indigo.darken-5 { background-color: #101974 !important; }
.row .colold { padding: 0 .75rem; }

/* Typography */
/* text-wrap: balance verdeelt de regels van een kop gelijkmatig in plaats van de
   laatste regel met één woord te laten eindigen. De browser doet dat alleen bij
   koppen van hooguit een handvol regels, dus het is veilig op alles hier.
   Browsers die het niet kennen negeren de regel en breken zoals voorheen.
   .card-title staat erbij omdat de projecttitel over het beeld ligt en juist
   daar een eenzaam laatste woord opvalt. */
h1, h2, h3, h4, h5, h6, .card-title { overflow-wrap: break-word; text-wrap: balance; }
h1, h2, h3, h4, h5, h6, .brand-logo, .card-title, .content .aside span, nav ul a.btn { font-family: 'Raleway'; font-weight: 700; }

/* Tekstschaal
   ---------------------------------------------------------------------------
   Gemeten voordat dit erin kwam: h1 63px, h2 53,4, h3 43,8, h4 34,2, h5 24,6,
   h6 17,25 -- de standaardschaal van Materialize, met stappen van 1,18 tot 1,43.
   Die koppen waren dus niet te klein. Het probleem was dat de pagina's die ertoe
   doen ze niet gebruikten (de homepage begon bij h5) en dat `.flow-text` op een
   h3 of h6 de maat terugzette naar 25,2px, waardoor kop en alinea even zwaar
   werden.

   Deze schaal maakt de stappen bewust ongelijk: 1,5 aan de top waar het verschil
   moet vallen, aflopend naar 1,18 onderin waar koppen dicht bij de lopende tekst
   staan. Van boven naar beneden op een breed scherm: 60 / 40 / 30 / 24 / 20 / 17.

   clamp() in rem, niet in px, en zonder aan de lettergrootte van `html` te komen:
   die staat op 15px en er hangen 217 rem-waarden aan. Zou je die verhogen, dan
   groeit de tekst maar blijven de handgemeten dozen (chips 32px, invoervelden
   56px, de navigatiebalk) staan -- en je overschrijft de lettergrootte die de
   bezoeker zelf heeft ingesteld.

   De middelste waarde van elke clamp bepaalt hoe snel de maat meegroeit met het
   scherm; de vw-component is groter naarmate de kop groter is, zodat de
   verhouding tussen de niveaus op elke breedte ongeveer gelijk blijft. */
:root {
  /* De ondergrenzen zijn niet losjes gekozen. Met een vaste h6 en een lage
     ondergrens voor h5 kwamen die twee op een smal scherm uit op 15,9 en 16,2px:
     een stap van 1,02, dus twee kopniveaus die er identiek uitzagen. De grenzen
     hieronder houden ook op 375px een echte trap: 32,4 / 26 / 22 / 19 / 16,8 /
     14,7, met stappen van 1,24 tot 1,13. */
  --jd-tekst-h1: clamp(2.29rem, 1.4rem + 3.4vw, 4rem);
  --jd-tekst-h2: clamp(1.857rem, 1.3rem + 2vw, 2.667rem);
  --jd-tekst-h3: clamp(1.571rem, 1.2rem + 1.2vw, 2rem);
  --jd-tekst-h4: clamp(1.357rem, 1.15rem + .6vw, 1.6rem);
  --jd-tekst-h5: clamp(1.2rem, 1.05rem + .4vw, 1.333rem);
  --jd-tekst-h6: clamp(1.05rem, 1rem + .18vw, 1.133rem);
  --jd-tekst-lead: clamp(1.15rem, 1.05rem + .5vw, 1.4rem);

  /* Grote koppen mogen strakker zetten dan kleine: bij 60px is 1,5 regelafstand
     een gat, bij 17px is 1,15 te krap. */
  --jd-regel-groot: 1.08;
  --jd-regel-midden: 1.2;
  --jd-regel-klein: 1.32;
}

h1 { font-size: var(--jd-tekst-h1); line-height: var(--jd-regel-groot); letter-spacing: -.02em; }

/* De paginatitel in de smalle kolom.
   ---------------------------------------------------------------------------
   .popup-wrapper is 650px breed en wordt gebruikt door de categorie-, tag-,
   klant- en projectpagina's. De volle h1-schaal van 60px is voor een bredere
   kolom bedoeld: "Gedrukte communicatiemiddelen" liep daar over drie regels en
   194px hoogte, "Websites, van ontwerp tot ontwikkeling" over twee.

   Met 2.6rem (39px) past de eerste op één regel en de langste titel van de site
   op twee. De ondergrens van 1.7rem houdt hem op een telefoon boven de h2.
   De projecttitel over het beeld heeft een eigen regel met meer gewicht in de
   selector en blijft dus op zijn eigen maat. */
.popup-wrapper h1 { font-size: clamp(1.7rem, 1.2rem + 2.2vw, 2.6rem); }
h2 { font-size: var(--jd-tekst-h2); line-height: var(--jd-regel-groot); letter-spacing: -.015em; }
h3 { font-size: var(--jd-tekst-h3); line-height: var(--jd-regel-midden); letter-spacing: -.01em; }
h4 { font-size: var(--jd-tekst-h4); line-height: var(--jd-regel-midden); }
h5 { font-size: var(--jd-tekst-h5); line-height: var(--jd-regel-klein); }
h6 { font-size: var(--jd-tekst-h6); line-height: var(--jd-regel-klein); }

/* Aanloopalinea. Dit is wat `.flow-text` altijd al probeerde te zijn: iets groter
   dan de lopende tekst, voor de eerste alinea van een pagina. Materialize zet er
   alleen een font-size op; hier komt de regelhoogte en een leesbreedte bij, want
   25px tekst over de volle kaartbreedte leest slecht.
   Op koppen hoort hij niet meer te staan -- die zijn uit de templates gehaald. */
.flow-text { font-size: var(--jd-tekst-lead); line-height: 1.5; max-width: 62ch; }
.flow-text.center-align { margin-left: auto; margin-right: auto; }

/* Icons */
.fa, .fab, .fad, .fal, .far, .fas { display: inline; }
.material-icons { font-family: 'Material Icons'; font-weight: normal; font-style: normal; font-size: 24px; display: inline; line-height: 1; text-transform: none; letter-spacing: normal; word-wrap: normal; white-space: nowrap; direction: ltr; -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; -moz-osx-font-smoothing: grayscale; font-feature-settings: 'liga'; }

/* Buttons */
a { color: #1a237e; }
/* MD3 geeft knoppen een volledig ronde vorm; Materialize v2.3.3 houdt 4px aan.
   De pil is het duidelijkste verschil tussen "knop" en "vlak" in MD3. */
/* Geen hoofdletters meer op knoppen. Material Design 2 zette knoplabels in
   kapitalen; Material Design 3 -- waar de rest van dit thema op staat -- gebruikt
   zinsnotatie. Kapitalen lezen trager omdat de woordvorm wegvalt, en ze maken van
   elke knop een uitroep. Ze blijven wel staan waar ze wél iets doen: op de
   meta-labels ("Klant:", "Categorie 3 van 8", "Vorige project"), die juist als
   etiket moeten lezen en niet als tekst.
   Terugdraaien is één woord: zet text-transform hier weer op uppercase. */
.btn, .btn-large, .btn-small, .btn-flat { border-radius: var(--jd-vorm-vol); text-transform: none; }
.btn-floating { border-radius: 50%; }
.btn-floating i { color: #e8eaf6; }
.btn, .btn-large, .btn-small, .btn-floating, .btn:focus, .btn-large:focus, .btn-small:focus, .btn-floating:focus { background-color: #1a237e; color: #e8eaf6; }
.btn:hover, .btn-large:hover, .btn-small:hover, .btn-floating:hover { background-color: #010A65; }
.btn-flat:focus { background-color: rgba(26, 35, 126, 0.1); }
.sidenav li > a.btn, .sidenav li > a.btn-large, .sidenav li > a.btn-small, .sidenav li > a.btn-large { background-color: #1a237e; color: #ffffff; }
.sidenav li > a.btn:hover, .sidenav li > a.btn-large:hover, .sidenav li > a.btn-small:hover, .sidenav li > a.btn-large:hover { background-color: #010A65; }
.wp-block-buttons { text-align: center; justify-content: center; }
.wp-block-buttons .wp-block-button { padding: 0 8px; margin: 1rem 0 0; }
/* De blokeditor levert een knop als <div class="wp-block-button"><a
   class="wp-block-button__link">. De Materialize-klassen staan op die div, dus de
   div ís de knop en de link erbinnen moet onzichtbaar zijn -- daar gaat deze
   regel over.

   border-radius stond op `unset`, en dat is voor deze eigenschap hetzelfde als 0.
   De link kreeg daardoor rechte hoeken binnen een pil van 999px, en omdat hij maar
   8px van de rand begint -- dus bínnen de ronding -- staken zijn vier hoeken als
   blokjes buiten de pilrand uit. `inherit` neemt de ronding van de div over.

   color hoorde er ook bij: zonder die regel geeft Gutenberg de link wit, terwijl
   elke andere knop op de site #e8eaf6 is. */
.wp-block-buttons .wp-block-button__link { background-color: inherit; border: none; border-radius: inherit; box-shadow: none; color: inherit; font-size: inherit; padding: inherit; text-align: inherit; text-decoration: none; overflow-wrap: unset; }

/* Focus
   ---------------------------------------------------------------------------
   Materialize zet op een reeks elementen `outline: none` of `outline: 0`. Gemeten
   op de categorietegel, de menulinks, de CONTACT-knop, het logo en de hamburger:
   bij alle vijf veranderde er niets tussen rust en focus. Wie met Tab navigeert
   zag dus nergens waar hij stond — dat is een WCAG-eis (2.4.7) en Material Design
   schrijft het ook voor.

   :focus-visible en niet :focus, zodat de ring alleen verschijnt bij toetsenbord-
   navigatie en niet na een muisklik. 3px komt overeen met wat Materialize zelf
   voor zijn eigen focusring aanhoudt. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible,
summary:focus-visible,
[tabindex]:focus-visible {
  outline: 3px solid #1a237e;
  outline-offset: 2px;
}

/* Op de donkere vlakken — navigatiebalk, lade, footer, de gekleurde tegels en de
   knoppen in de popup — zou indigo wegvallen. Daar een lichte ring. */
.navbar a:focus-visible,
.navbar button:focus-visible,
.sidenav a:focus-visible,
.page-footer a:focus-visible,
.footer-copyright a:focus-visible,
.content .aside:focus-visible {
  outline-color: #e8eaf6;
}

/* De tegel is een groot vlak; een ring strak om de rand leest rustiger dan een
   ring op 2px afstand die buiten de tegel valt. */
.content .aside:focus-visible { outline-offset: -3px; }

/* Vier selectors uit materialize.min.css zetten `outline` uit met een hogere
   specificiteit dan de elementselectors hierboven, dus daar bleef de ring weg.
   Gemeten in de popup: de klantlink en de toolchips onder een projectkaart
   kregen focus zonder dat er iets zichtbaar veranderde.

     .tabs .tab a:focus            (0,3,1) — klant- en jaarlink in de kaart
     .card .card-action a           (0,2,1) — de toolchips
     .chip:focus                    (0,2,0)
     .collapsible-header:focus      (0,2,0) — de blokken op Over mij

   Onderstaande selectors liggen er net boven of gelijk; style.css laadt na
   materialize, dus gelijk is genoeg. */
.card .jd-projectmeta-lijst li a:focus-visible,
.card .card-action a:focus-visible,
.chip:focus-visible,
.collapsible-header:focus-visible {
  outline: 3px solid #1a237e;
  outline-offset: 2px;
}

/* De chips zitten in een <a> zonder eigen vorm, dus de ring liep als rechthoek
   om de pil heen -- alsof het vlak eromheen de focus had in plaats van de chip
   zelf. Een outline volgt de border-radius van het element, dus de link krijgt
   dezelfde pilvorm als de chip erin. */
.jd-toollijst a,
.post_tags a,
/* In de kaart geeft Materialize .card .card-action a (0,2,1) de knopvorm van
   4px mee; deze selector ligt daarboven. */
.card .card-action .post_tags a { border-radius: var(--jd-vorm-vol); }

/* Materialize kleurt een chip met focus om naar --md-sys-color-primary (#006495),
   een blauw dat in dit thema nergens voorkomt. De chip zelf is hier nooit
   focusbaar -- de link eromheen is dat -- maar deze regel houdt dat blauw hoe dan
   ook buiten de deur. */
.chip:focus { background-color: inherit; color: inherit; }

/* De link om een chip in een kaart is bij Materialize een knop: .card .card-action a
   deelt zijn opmaak met .btn, inclusief het vlak dat een knop bij focus krijgt.
   Gemeten op een projectkaart werd dat rgba(0, 75, 113, .765) over 160 bij 74
   pixels, terwijl de pil zelf maar 107 bij 32 is -- een grote lap van hetzelfde
   afwijkende blauw rondom de chip. */
.card .card-action .post_tags a:focus,
.card .card-action .post_tags a:hover { background-color: transparent; }

/* De ring volgde het linkvlak, en dat is bij een chip in een kaart 160 bij 74
   pixels terwijl de pil zelf 107 bij 32 is: een ovaal op ruime afstand om de
   chip heen. Bij een chip laat de focus zich daarom niet met een ring zien maar
   met de pil zelf -- die kleurt om naar dezelfde indigo als de chip van de tool
   waar je op staat in de toollijst, zodat focus en "hier ben je" dezelfde taal
   spreken.

   outline: none mag hier omdat er iets anders voor in de plaats komt dat groter
   en duidelijker is: het vlak van de pil gaat van #e8eaf6 naar #1a237e, een
   verschil van 11,06:1. Daarmee is aan WCAG 2.4.7 voldaan. */
.post_tags a:focus-visible,
.jd-toollijst a:focus-visible,
.card .card-action .post_tags a:focus-visible { outline: none; }

.post_tags a:focus-visible .chip,
.jd-toollijst a:focus-visible .chip { background-color: #1a237e; color: #e8eaf6; }

/* Paginering (jd_pagination in functions.php)
   ---------------------------------------------------------------------------
   Materialize v2 kleurt .pagination met de Material Design 3-systeemkleuren: de
   actieve pagina kreeg --md-sys-color-primary (#006495), een blauw dat verder
   nergens in dit thema voorkomt. Daarom staan de kleuren hier, met dezelfde
   waarden als de knoppen hierboven: #1a237e, hover #010A65, tekst #e8eaf6.

   Deze regels staan bewust op dezelfde specificiteit als die van Materialize;
   style.css laadt erna, dus ze winnen zonder !important.

   De hoogte van 40px vervangt de 2rem (28px) van Materialize: dat is te klein
   om betrouwbaar aan te tikken op een telefoon. */
.pagination { margin: 2rem 0 0; }
.pagination li { margin: 0 2px; vertical-align: middle; }
.pagination li a {
  align-items: center;
  border-radius: 4px;
  color: #1a237e;
  display: inline-flex;
  font-size: 1rem;
  font-weight: 500;
  height: 40px;
  justify-content: center;
  min-width: 40px;
  padding: 0 0.5rem;
  transition: background-color .2s ease-out, color .2s ease-out;
}
.pagination li a:hover, .pagination li a:focus { background-color: rgba(26, 35, 126, 0.1); }
.pagination li a:focus-visible { outline: 2px solid #1a237e; outline-offset: 2px; }

/* De actieve pagina krijgt hetzelfde blok als een .btn, zodat de paginering
   herkenbaar bij de rest van de site hoort. */
.pagination li.active a, .pagination li.active a:focus { background-color: #1a237e; color: #e8eaf6; }
.pagination li.active a:hover { background-color: #010A65; color: #e8eaf6; }

/* Uiteinden en beletselteken: gedempt indigo in plaats van het grijs van
   Materialize, en geen achtergrondvlak. */
.pagination li.disabled a, .pagination li.disabled a:hover, .pagination li.disabled a:focus {
  background-color: transparent;
  color: rgba(26, 35, 126, 0.32);
}

/* 2rem valt te zwaar uit naast cijfers van 1rem. */
.pagination li i { font-size: 1.5rem; line-height: 1; }

/* Materialize v2.3 compatibiliteit
   ---------------------------------------------------------------------------
   Materialize v2.3.3 stylet de navigatiebalk via .navbar in plaats van de
   element-selector nav, maakt .nav-wrapper een flexbox met eigen achtergrond,
   en liet de regels voor .nav-extended, .nav-content en .sidenav-trigger
   vervallen. Onderstaande regels zijn overgenomen uit Materialize v2.1.1 zodat
   de bestaande header-markup en de eigen regels hieronder blijven werken.
   Verwijderbaar zodra de header naar de v2.3-opzet is herschreven. */
.navbar { color: var(--md-sys-color-on-primary); line-height: var(--navbar-height-mobile); }
/* v2.0.3 gaf `nav` een slagschaduw; in v2.3.3 heeft .navbar er geen meer, waardoor
   de balk vlak op de witte inhoud aansloot. Dezelfde waarden als .btn hierboven. */
.navbar {
  -webkit-box-shadow: 0 2px 2px 0 rgba(0,0,0,.14), 0 3px 1px -2px rgba(0,0,0,.12), 0 1px 5px 0 rgba(0,0,0,.2);
  box-shadow: 0 2px 2px 0 rgba(0,0,0,.14), 0 3px 1px -2px rgba(0,0,0,.12), 0 1px 5px 0 rgba(0,0,0,.2);
}
.navbar.nav-extended { height: auto; }
.navbar .nav-wrapper { display: block; height: 100%; position: relative; background-color: transparent; padding-left: 0; padding-right: 0; }
.navbar.nav-extended .nav-wrapper { min-height: var(--navbar-height-mobile); height: auto; }
.navbar.nav-extended .nav-content { position: relative; line-height: normal; }
.navbar ul:not(.dropdown-content) { display: block; gap: 0; }
.navbar ul:not(.dropdown-content) > li { float: left; }
.navbar ul:not(.dropdown-content) > li > a { padding: 0 15px; font-size: 1rem; }
.navbar ul:not(.dropdown-content) > li > a.btn, .navbar ul:not(.dropdown-content) > li > a.btn-small, .navbar ul:not(.dropdown-content) > li > a.btn-large, .navbar ul:not(.dropdown-content) > li > a.btn-flat, .navbar ul:not(.dropdown-content) > li > a.btn-floating { margin-top: -2px; margin-left: 15px; margin-right: 15px; display: inline-block; }
.navbar .brand-logo { position: absolute; font-size: 2.1rem; }
.navbar .brand-logo i { float: left; margin-right: 15px; }
.navbar .sidenav-trigger { float: left; position: relative; z-index: 1; height: var(--navbar-height-mobile); margin: 0 18px; }
.navbar .sidenav-trigger i { height: var(--navbar-height-mobile); line-height: var(--navbar-height-mobile); }
/* v2.0.3 had `nav a { color: var(--font-on-primary-color-main) }`; die regel is in
   v2.3.3 vervallen. De hamburger is een <a> zonder eigen kleurklasse, dus viel hij
   terug op de algemene `a { color: #1a237e }` hierboven: indigo op een indigo balk,
   contrast 1.12. De overige items in de balk hebben wel een kleurklasse en waren
   daardoor niet geraakt. #e8eaf6 is dezelfde kleur als het logo en de menu-items. */
.navbar .sidenav-trigger, .navbar .sidenav-trigger i { color: #e8eaf6; }
@media only screen and (min-width: 601px) {
  .navbar, .navbar .nav-wrapper i, .navbar a.sidenav-trigger, .navbar a.sidenav-trigger i { height: var(--navbar-height); line-height: var(--navbar-height); }
  .navbar.nav-extended .nav-wrapper { min-height: var(--navbar-height); }
}
@media only screen and (max-width: 992.99px) {
  .navbar .brand-logo { left: 50%; transform: translateX(-50%); }
  .navbar .brand-logo.left, .navbar .brand-logo.right { padding: 0; transform: none; }
}
@media only screen and (min-width: 993px) {
  .navbar a.sidenav-trigger { display: none; }
  .navbar .brand-logo.center { left: 50%; transform: translateX(-50%); }
}

/* Formuliervelden. v2.3.3 liet de regel vervallen die invoervelden een breedte
   en hoogte gaf. Zonder die regel valt de browserstandaard terug: het veld werd
   394px breed in een kolom van 308px en overlapte de kolom ernaast, en de
   hoogte zakte van 56 naar 38px. Waarden overgenomen uit v2.0.3-alpha. */
input:not([type]):not(.browser-default),
input[type=text]:not(.browser-default),
input[type=password]:not(.browser-default),
input[type=email]:not(.browser-default),
input[type=url]:not(.browser-default),
input[type=time]:not(.browser-default),
input[type=date]:not(.browser-default),
input[type=datetime]:not(.browser-default),
input[type=datetime-local]:not(.browser-default),
input[type=month]:not(.browser-default),
input[type=tel]:not(.browser-default),
input[type=number]:not(.browser-default),
input[type=search]:not(.browser-default),
textarea.materialize-textarea { outline: none; width: 100%; font-size: 16px; height: 56px; }

/* Knoppen. v2.3.3 haalde de slagschaduw van .btn af (die zit daar nu alleen nog
   op .btn.elevated) en verruimde de padding van 16 naar 24px. Het icoon in een
   knop verloor bovendien zijn marge en kreeg een vaste regelhoogte, waardoor er
   een blok naast het label ontstond. */
.btn, .btn-small, .btn-large, .btn-flat { --btn-padding: 16px; }
/* v2.0.3 centreerde het label met line-height in een inline-block; v2.3.3 doet
   dat met inline-flex en zet geen line-height meer. In de navigatiebalk erfde
   de knop daardoor de line-height van .navbar (64px). */
.btn, .btn-small, .btn-large, .btn-flat { display: inline-block; line-height: var(--btn-height); }
/* De letterspatiëring van .5px hoorde bij de kapitalen hierboven: die hebben
   lucht nodig omdat alle letters even hoog zijn. In zinsnotatie werkt dezelfde
   spatiëring averechts en trekt ze het woord uit elkaar. */
.btn, .btn-small, .btn-large { text-align: center; letter-spacing: normal; }
.btn, .btn-small, .btn-large {
  -webkit-box-shadow: 0 2px 2px 0 rgba(0,0,0,.14), 0 3px 1px -2px rgba(0,0,0,.12), 0 1px 5px 0 rgba(0,0,0,.2);
  box-shadow: 0 2px 2px 0 rgba(0,0,0,.14), 0 3px 1px -2px rgba(0,0,0,.12), 0 1px 5px 0 rgba(0,0,0,.2);
}
.btn i, .btn-floating i, .btn-large i, .btn-small i, .btn-flat i { font-size: 1.3rem; line-height: inherit; height: auto; }
.btn i.right, .btn-large i.right, .btn-small i.right, .btn-flat i.right { margin-left: 15px; }
.btn i.left, .btn-large i.left, .btn-small i.left, .btn-flat i.left { margin-right: 15px; }

/* Accordeon. v2.3.3 voegde een chevron toe via .collapsible-header::after. De
   koppen hier bevatten een h5 op blokniveau, waardoor die pijl los onderaan
   naast het blok komt te hangen. v2.0.3 had geen pijl.

   Materialize zet de pijl in uitgeklapte toestand nog een keer met
   `.active .collapsible-header::after`. Die selector weegt zwaarder (0,2,1 tegen
   0,1,1), dus zonder de tweede regel hieronder kwam de pijl bij het openklappen
   alsnog tevoorschijn. Beide toestanden moeten dus expliciet uit. */
.collapsible-header::after,
.active .collapsible-header::after { content: none; }

/* Kaartvoet met de tags. v2.3.3 gaf .card-action een padding van 0 24px en liet
   `background-color: inherit` vervallen, en haalde de marge en de pilvorm van de
   chips af. Zonder die marge raken de chips elkaar en vormen ze een aaneengesloten
   lichtblauwe balk; met alles op één regel viel de kaartvoet van 76 naar 41px.
   In v2.3.3 kreeg .card bovendien een lichtblauwe achtergrond in plaats van
   #fcfcff; omdat .card-action die met `inherit` overneemt, kleurde de hele
   kaartvoet mee. */
.card { background-color: var(--md-sys-color-surface); }
/* De 0 was hier goed zolang de <a> eromheen 24px padding had: er pasten dan maar
   twee chips op een regel en die rij bleef vanzelf smaller dan de kaart. Met de
   kleinere padding hieronder past er een derde bij, wordt de rij breder dan de
   kaart, en liep de eerste chip er 21px links buiten -- de rij is gecentreerd, dus
   hij stak aan beide kanten uit. Zonder padding is er niets dat de regelafbreking
   binnen de kaart houdt. */
.card .card-action { background-color: inherit; padding: 10px 8px; }

/* De chips stonden scheef in de kaartvoet: 7px ruimte erboven tegen 16,5px eronder.
   Twee oorzaken, allebei onder de motorkap.

   De chip is een inline-block en stond dus op een tekstregel, met de onderruimte
   voor stokletters eronder -- 5,5px die niemand ziet maar die wel meetelt. En de
   chip had `margin-bottom: 5px` voor de ruimte tussen twee regels chips; op de
   laatste regel bleef die als extra ruimte onderaan hangen.

   Flex met een gap lost allebei op: de gap geeft dezelfde 5px tussen de chips als
   de marge deed, maar alleen tússen ze en niet erna, en als flexitem staat de chip
   niet meer op een tekstregel. align-items: center legt hem netjes in het midden
   van zijn link. Resultaat: 17px boven en 16px onder, waarbij die ene pixel
   afronding op halve pixels is. */
.card .card-action .post_tags { display: flex; flex-wrap: wrap; justify-content: center; gap: 5px; }
.card .card-action .post_tags a { display: flex; align-items: center; }
.card .card-action .post_tags .chip { margin: 0; }
/* De witruimte boven en onder de tags komt niet van .card-action zelf maar van
   de <a> eromheen. v2.3.3 zet daar bovendien height: var(--btn-height) op, wat
   met box-sizing: border-box de padding opslokt -- vandaar height: auto.

   Die padding stond op de 16px 24px van Materialize, en dat was te veel: op een
   kaart met vijf chips gaf dat 53px tussen twee chips en een kaartvoet van 225px.
   Er pasten er nog maar twee op een regel.

   Met 8px passen er drie op een regel, staan ze 21px uit elkaar (8 + 8 plus de 5px
   gap hieronder) en is de kaartvoet 69px in plaats van 225.

   Niet strakker: deze padding is het aanraakvlak. De chip is 32px hoog, en met 8px
   erboven en eronder komt de link op precies 48px -- de maat die Material Design
   aanhoudt en die dit thema elders ook gebruikt. Op 6px werd dat 44px: nog altijd
   ruim boven de 24px van WCAG 2.5.8, maar onder de eigen norm. */
.card .card-action a { display: inline-block; padding: 8px; height: auto; }
/* Materialize trekt de buitenste links in een kaartvoet naar buiten met
   `margin-left: -1.6rem` op de eerste en `margin-right: -1.6rem` op de laatste. Dat
   hoort bij zijn eigen tekstlinks met 24px padding: zo ligt de tekst gelijk met de
   kaartrand. Onze chips staan gecentreerd, dus die uitlijning speelt hier niet.

   Met de kleinere padding hierboven werden die -22,4px schadelijk. Links trok het de
   hele rij naar buiten (eerste chip 14px buiten de kaart); rechts was het verraderlijker,
   want een negatieve rechtermarge verkort de ruimte die de laatste chip opeist -- een
   rij van 345px 'paste' daardoor in een vak van 334px en brak niet af, om vervolgens
   9px buiten de kaart te steken. */
.card .card-action a:first-child { margin-left: 0; }
.card .card-action a:last-child { margin-right: 0; }
/* v2.3.3 maakt de chip een inline-flex met gap: 8px en vertical-align: top.
   Die gap maakt elke chip breder dan de natuurlijke spatie tussen icoon en
   tekst, en top-uitlijning haalt de onderruimte onder de regel weg. */
.chip { line-height: 32px; border-radius: 16px; margin: 0 5px 5px 0; padding: 0 12px; font-size: 13px; display: inline-block; vertical-align: baseline; }

/* Tooltip. v2.3.3 stapte over op de Material Design 3-typografietokens en zet
   font-family op var(--md-sys-typescale-body-small-font-family-name), wat naar
   Roboto verwijst. Dit thema laadt Roboto niet, dus viel de browser terug op
   zijn standaardlettertype. inherit pakt de fontstack van de site (de tooltip
   hangt onder <body>) en blijft kloppen als je later een ander lettertype kiest.
   De rest van de maatvoering is de v2.0.3-waarde. */
.material-tooltip { font-family: inherit; font-size: 15px; line-height: 18px; letter-spacing: normal; padding: 10px 8px; border-radius: 2px; }

/* Footer. v2.0.3 zette hier de tekstkleur (wit op indigo); v2.3.3 laat dat weg,
   waardoor koppen zonder eigen class de donkere bodykleur erven en onleesbaar
   worden. De nieuwe marge en stippellijn horen niet bij dit ontwerp. */
/* margin-top: auto en niet 0. Beide halen de 5rem van v2.3.3 weg, maar auto
   duwt de footer in de flexkolom van .wrapper naar de onderkant zodra de pagina
   korter is dan het scherm — zoals bij de 404 en een leeg archief, waar hij
   anders halverwege bleef zweven met achtergrond eronder. Op langere pagina's is
   er geen vrije ruimte en gedraagt auto zich als 0. */
.page-footer { color: var(--md-sys-color-on-primary); margin-top: auto; padding-top: 20px; border-top: 0; }

/* De twee kopjes in de footer waren h5. Ze staan op élke pagina, dus na een
   pagina met h1, h2 en h3 sprong de structuur daar naar niveau vijf. Het zijn
   sectiekoppen van de pagina en dus h2 -- maar wel met een eigen maat: de volle
   40px van de schaal zou de footer zwaarder maken dan de inhoud erboven. */
/* De marges horen erbij, niet alleen de maat. Deze koppen waren h5 en zijn h2
   geworden om de kopstructuur kloppend te maken -- maar Materialize geeft een h2
   fors ruimere standaardmarges dan een h5: gemeten 35,6px erboven en 21,4px
   eronder, tegen de lijst die daar zelf ook nog 15px bovenop legde. De footer
   werd daardoor zichtbaar hoger zonder dat er iets bij was gekomen.
   Deze waarden brengen het blok terug naar de compactheid van voorheen: geen
   marge boven -- de kolom begint daar -- en een bescheiden gat naar wat volgt. */
.page-footer h2 { font-size: clamp(1.2rem, 1.08rem + .5vw, 1.45rem); line-height: 1.25; margin: 0 0 .6rem; }
/* De lijst eronder legde er nog 15px bovenop; die is niet nodig naast de marge
   van de kop. */
.page-footer h2 + ul { margin-top: 0; }

/* TWEE FUNCTIES BIJ DEZELFDE WERKGEVER
   Bij Lindenhaeghe staat het bedrijf als kop en staan de functies eronder, aan
   een verticale lijn met een stip per functie. Die lijn is het hele punt: hij
   maakt zichtbaar dat het om doorgroei binnen één dienstverband gaat en niet om
   twee losse banen.

   De bovenste stip is gevuld en de rest open -- hetzelfde onderscheid dat een
   tijdlijn maakt tussen 'nu' en 'geweest'. Dat scheelt een woord als "huidige"
   en werkt ook als je de tekst niet leest.

   De stippen staan met een negatieve left buiten de lijst. Zou een voorouder
   ooit overflow: hidden krijgen, dan worden ze afgeknipt. */
.jd-rollen {
  list-style: none;
  margin: .6rem 0 1.1rem;
  padding-left: 1.25rem;
  /* Niet #c5cae9: dat is de paginakleur en haalt op wit maar 1,62:1 -- de lijn
     was er wel maar zag je niet. #9fa8da geeft 2,31:1 en gebruikt het thema al
     voor de randen van de zoekvelden. Bewust niet donkerder: de stippen staan op
     ruim 4:1 en dragen de betekenis, de lijn verbindt ze alleen. */
  border-left: 2px solid #9fa8da;
}
.jd-rollen > li { position: relative; }
.jd-rollen > li + li { margin-top: .9rem; }
.jd-rollen > li::before {
  content: '';
  position: absolute;
  /* 12px stip gecentreerd op een lijn van 2px: halve stip (6px) plus de helft
     van de lijn (1px) terug vanaf de linkerrand van de tekst. */
  left: calc(-1.25rem - 5px);
  top: .45em;
  width: 12px;
  height: 12px;
  box-sizing: border-box;
  border-radius: 50%;
  border: 2px solid #5c6bc0;
  background-color: #fff;
}
/* Gevuld betekent 'loopt nu', niet 'staat bovenaan'. Met :first-child kreeg elke
   werkgever met één functie een gevulde stip, ook de banen die allang voorbij
   zijn. CSS kan dat verschil niet zien, dus .jd-nu staat in de markup. */
.jd-rollen > li.jd-nu::before { background-color: #3949ab; border-color: #3949ab; }

/* Bij één functie valt er niets te verbinden; de lijn zou een streepje naast een
   losse stip worden. De inspringing blijft wel staan, zodat de functietitels bij
   alle werkgevers op dezelfde plek beginnen -- dat is het hele punt van deze
   opzet. Kent een browser :has() niet, dan blijft de lijn overal staan: hinderlijk
   noch onjuist, alleen wat minder rustig. */
.jd-rollen:not(:has(> li + li)) { border-left-color: transparent; }
/* Niet het h4-token uit het typeschema: #about-me h3 hierboven zet alle kopjes in
   deze sectie op ten hoogste 1.25rem, en met de standaard h4 (1.36rem) werden de
   functies groter dan de werkgever erboven -- omgekeerde hiërarchie. Een stap
   kleiner dan de werkgever, en het gewicht een stap lichter: de lijn en de stip
   maken al duidelijk dat dit kopjes zijn. */
.jd-rollen h4 { font-size: var(--jd-tekst-h6); font-weight: 600; margin: 0; }
.jd-rollen p { margin: .1rem 0 0; }

/* Profielfoto Over mij. Los van de Materialize-versie: #about-me img krijgt
   height:100% en de kolom eromheen is een flexbox die meerekt met de tekst
   ernaast. De bron is 300x300, maar werd zo tot 117x218 uitgerekt - een ovaal in
   plaats van een cirkel. aspect-ratio houdt hem vierkant, object-fit snijdt bij
   in plaats van te vervormen, en align-self voorkomt dat flex hem alsnog oprekt.
   Alleen de directe kindafbeelding: de klantlogo's zitten in een <a>. */
#about-me .col > img.circle { height: auto; aspect-ratio: 1 / 1; object-fit: cover; align-self: flex-start; }

/* Header */
.header { display: flex; flex-direction: column; justify-content: center; }

/* MEELOPENDE NAVIGATIEBALK
   Alleen .nav-wrapper blijft tijdens het scrollen staan; de hulpbalk erboven
   (contact, LinkedIn, e-mailadres) schuift gewoon weg en komt bij terugscrollen
   vanzelf weer tevoorschijn.

   WAAROM DE REGEL OP .header STAAT EN NIET OP .nav-wrapper
   Een sticky element loopt alleen mee binnen de box van zijn ouder. De ouder van
   .nav-wrapper is <nav>, en die is precies zo hoog als de balk zelf: er is nul
   ruimte om in mee te lopen, dus het element laat meteen weer los. .header zit in
   .wrapper, en die is zo hoog als de pagina.

   HOE DAN ALLEEN DE ONDERSTE BALK BLIJFT STAAN
   De hele header loopt mee, maar met een negatieve offset ter grootte van de
   hulpbalk. Hij pint dus pas als zijn bovenrand 48px boven de viewport staat --
   precies het moment waarop de hulpbalk uit beeld is en .nav-wrapper de bovenkant
   van het scherm raakt.

   DE 48px IS GEMETEN, NIET GESCHAT
   8px padding boven + 32px min-height op de links + 8px onder. Die balk kan niet
   omslaan naar twee regels: hij verschijnt pas vanaf 601px terwijl zijn inhoud
   478px vraagt (NL) of 383px (EN). Groeit die tekst fors, meet dit getal dan
   opnieuw -- anders blijft er een streepje hulpbalk in beeld hangen. Onder 601px
   is de hulpbalk verborgen (hide-on-small-only) en is de offset dus 0.

   Het getal staat als --jd-hulpbalk-hoogte bovenaan dit bestand, naast de andere
   tokens, en niet hier als los cijfer.

   Z-INDEX
   Boven de inhoud, die nergens hoger komt dan 1. Onder .sidenav-overlay (997),
   zodat het uitschuifmenu de balk mee verduistert zoals het dat nu ook doet. En
   onder .jd-skip (1000), zodat de skip-link zichtbaar blijft. Let op: hierdoor
   wordt .header een stacking context -- daarom staat het sidenav-menu niet meer
   binnen <header>, zie parts/shared/header.php. */
.header {
  position: -webkit-sticky;
  position: sticky;
  top: 0;
  z-index: 995;
}

/* Zonder dit springt een anker of de skip-link onder de balk. scroll-padding-top
   op de scrollcontainer vangt dat in één regel af voor alles wat scrolt:
   #jd-inhoud, :target en scrollIntoView(). */
html { scroll-padding-top: calc(var(--navbar-height-mobile) + 1rem); }

@media only screen and (min-width: 601px) {
  .header { top: calc(-1 * var(--jd-hulpbalk-hoogte)); }
  html { scroll-padding-top: calc(var(--navbar-height) + 1rem); }
}

/* DE ADMINBALK VAN WORDPRESS
   Vanaf 783px staat #wpadminbar fixed op top:0, 32px hoog en op z-index 99999 --
   hij wint dus altijd. De header pint op -48px, waardoor .nav-wrapper op y=0 komt
   en zijn bovenste 32px (logo, zoekknop, de kop van de menu-items) onder die balk
   verdween zodra je scrolde. `body.admin-bar .header { margin: ... }` verderop in
   dit bestand verzet alleen de startpositie, niet waar hij blijft hangen.

   Onder 783px maakt WordPress de adminbalk position:absolute -- hij scrollt dan
   gewoon mee weg en er valt niets te corrigeren. */
@media only screen and (min-width: 783px) {
  body.admin-bar .header { top: calc(32px - var(--jd-hulpbalk-hoogte)); }
}

/* Op papier bestaat scrollen niet: een meelopende balk zou daar alleen maar op
   een onvoorspelbare plek terechtkomen. */
@media print {
  .header { position: static; }
}

.header .nav-content { font-size: 12px; padding: 8px 15px; }
.header .nav-content ul li a { font-size: 12px; }
.header .nav-content ul li a:hover { background: none; }
.header .nav-content ul li:last-child a { padding: 0 0 0 15px; }
.header .nav-extended .nav-wrapper a.btn { background: #e8eaf6; color: #1a237e; }
.header .nav-extended .nav-wrapper { overflow: hidden; text-align: center; }
.header .nav-extended .nav-wrapper ul li a { color: #e8eaf6; }
.header .nav-extended ul:not(.dropdown-content) > li > a:hover:not(.active):not(.btn) { background-color: rgba(0,0,0,0.1); }
.header .nav-extended .nav-wrapper ul li.lang-item a { color: #9fa8da; }
.header .nav-extended .brand-logo { color: #e8eaf6; }

/* Actief menu-item
   ---------------------------------------------------------------------------
   WordPress zet current-menu-item en active op het item van de huidige pagina,
   maar er was niets dat die classes opmaakte: op /diensten/ zag je in het menu
   niet waar je stond. Dat er ooit opmaak bij hoorde blijkt uit de hoverregel
   hierboven, die .active al uitsluit -- die is bij een Materialize-versie
   verdwenen, net als de andere regels in het compatibiliteitsblok.

   Material Design 3 geeft de actieve bestemming een eigen aanduiding. Hier een
   streep eronder en geen gevuld vlak: CONTACT is al een pil, en twee pillen
   naast elkaar leest als twee knoppen in plaats van als "hier ben je".

   De streep staat op de <li> en niet op de <a>, zodat hij voor een gewone link
   en voor de CONTACT-pil op dezelfde hoogte zit -- onderaan de balk van 64px,
   niet halverwege binnen de pil. */
.header .nav-extended .nav-wrapper ul li.active { box-shadow: inset 0 -3px 0 0 #e8eaf6; }

/* De taalwisselaar wordt nooit actief (WordPress markeert alleen pagina-items),
   maar mocht dat ooit veranderen: die staat gedempt en hoort geen streep te
   krijgen die zwaarder weegt dan de pagina waar je op staat. */
.header .nav-extended .nav-wrapper ul li.lang-item.active { box-shadow: none; }

/* In de lade zorgt Materialize zelf al voor een gevulde pil op het actieve item,
   maar met 10% van het accent -- net te licht om op te vallen. De vorm blijft,
   alleen de vulling wordt iets steviger. */
.sidenav li.active > a:not(.btn) { background-color: rgba(26, 35, 126, 0.10); }

/* Zoeken
   ---------------------------------------------------------------------------
   Het pictogram in de navigatiebalk klapt #jd-zoekbalk uit; zie searchform.php,
   search.php en het blok in js/functions.js.

   .jd-zoek-knop is een <button> en geen <a>: hij navigeert niet maar bedient
   iets op dezelfde pagina, en alleen een button kan aria-expanded dragen. De
   opmaak hieronder haalt de knopstijl van de browser eraf en zet hem op dezelfde
   maat als de hamburger ernaast (64px hoog, dezelfde kleur). */
.jd-zoek-knop {
  background: none;
  border: 0;
  color: #e8eaf6;
  cursor: pointer;
  float: right;
  height: var(--navbar-height-mobile);
  margin: 0 18px;
  padding: 0;
  /* 48px breed: het minimum aanraakvlak uit Material Design. Het pictogram zelf
     is 24px, dus zonder deze breedte is de knop de helft te klein. */
  min-width: 48px;
}
.jd-zoek-knop i { line-height: var(--navbar-height-mobile); vertical-align: top; }
.jd-zoek-knop:hover { background-color: rgba(0,0,0,0.1); }

@media only screen and (min-width: 993px) {
  .jd-zoek-knop { height: var(--navbar-height); }
  .jd-zoek-knop i { line-height: var(--navbar-height); }
}

/* De balk zelf is een tweede .nav-content-rij onder de navigatiebalk. Zonder
   text-align blijft hij de center-align van .nav-wrapper erven. */
.jd-zoekbalk { padding: 12px 15px; text-align: left; }

.jd-zoekformulier-veld { display: flex; gap: 8px; margin: 0 auto; max-width: 640px; }

/* Materialize stylet alleen input:not([type]) en een handjevol types; type=search
   valt daarbuiten, dus dit veld kwam zonder rand en zonder hoogte binnen. */
.jd-zoekformulier input[type="search"] {
  background-color: #ffffff;
  border: 0;
  border-radius: var(--jd-vorm-s);
  box-sizing: border-box;
  color: #1a237e;
  flex: 1;
  font-size: 1rem;
  height: 44px;
  margin: 0;
  min-width: 0;
  padding: 0 12px;
}
.jd-zoekformulier input[type="search"]::placeholder { color: #5c6bc0; opacity: 1; }
/* Materialize geeft .btn 40px; naast een veld van 44px scheelt dat 4px aan de
   onder- en bovenkant. Op 44px staan ze gelijk en haalt de knop meteen het
   aanraakvlak dat Material Design vraagt. */
.jd-zoekformulier .btn { flex: 0 0 auto; height: 44px; line-height: 44px; padding: 0 16px; }
.jd-zoekformulier .btn i { line-height: inherit; }

/* Op de resultatenpagina: het aantal onder de kop en het formulier erboven. */
.jd-zoek-aantal { margin: 0 0 1rem; }
.jd-zoek-opnieuw { margin: 0 auto 2rem; max-width: 640px; }
.jd-zoek-opnieuw .jd-zoekformulier input[type="search"] { border: 1px solid #9fa8da; }

/* Verbergt tekst voor het oog maar niet voor een schermlezer. Het label bij het
   zoekveld en de tekst in de knop hebben dit nodig: een placeholder is geen
   label en een pictogram zonder tekst leest als "knop". clip-path in plaats van
   display:none, want dat laatste haalt het ook uit de toegankelijkheidsboom. */
.jd-visueel-verborgen {
  clip-path: inset(50%);
  height: 1px;
  overflow: hidden;
  position: absolute;
  white-space: nowrap;
  width: 1px;
}

/* Content */
.container { border-radius: var(--jd-vorm-m); flex: 1; margin: 30px auto; }
.container > .row { height: 100%; margin-bottom: 0; width: 100%; }
.container h1 { margin: 1.8rem 0 1.68rem 0; }
.container .valign-wrapper { display: flex; }
.container > .row > .col > .section > .col { padding: 0; }

/* Sidebar */
.sidenav { z-index: 100000; }

/* Materialize houdt de lade krap: --sidenav-padding staat standaard op 16px, wat
   met de marge van 12px om de items neerkomt op 28px tot de tekst. Die variabele
   is er om aan te passen, dus dat kan zonder de framework-selectoren te
   overschrijven. Op 24px begint de tekst op 36px. */
.sidenav { --sidenav-padding: 24px; }

/* Knoppen in de lade kregen van Materialize `margin: 10px 15px`, terwijl de
   gewone items op 12px staan. Die 3px maakte de CONTACT-pil zichtbaar smaller
   dan de pil van het actieve item erboven. De verticale 10px blijft: die geeft
   de knop lucht ten opzichte van de items eromheen. */
.sidenav li > a.btn,
.sidenav li > a.btn-large,
.sidenav li > a.btn-small,
.sidenav li > a.btn-flat,
.sidenav li > a.btn-floating { margin-left: 12px; margin-right: 12px; }

/* About */
#about-me img { background-color: #ffffff; height: 100%; width: 100%; }
#about-me .col.m3.hide-on-small-only,
#about-me .col.s3.m3.l2 a { display: flex; }
#about-me img:hover { background-color: #f5f7ff; }
/* Het cv op Over mij: h1 (paginatitel) > h2 (Ervaring, Opleiding, Stages) >
   h3 (functietitel per plek). Dit waren een h5 en een h6, waardoor de pagina van
   niveau één naar niveau vijf sprong en er drie niveaus ontbraken.

   De maten staan hier apart en volgen de volle schaal niet: h2 op 40px en h3 op
   30px zou een cv met twaalf functietitels tot een reeks koppen maken. Het
   niveau is structuur, de maat is ontwerp -- zelfde afweging als bij de kop op de
   startpagina en de projecttitel. Wel blijft de trap intact: sectiekop groter dan
   functietitel, functietitel groter dan de lopende tekst eronder. */
#about-me h2 { font-size: clamp(1.35rem, 1.15rem + .8vw, 1.75rem); line-height: 1.2; width: 100%; word-break: initial; }
#about-me h3 { font-size: clamp(1.1rem, 1.02rem + .35vw, 1.25rem); line-height: 1.3; letter-spacing: normal; }
#about-me .valign-grid { margin: 15px 0; }
.collapsible { border-top: 1px solid #e8eaf6; border-right: 1px solid #e8eaf6; border-left: 1px solid #e8eaf6; }
.collapsible-header { border-bottom: 1px solid #e8eaf6; }
/* De kop van een uitklapblok is een <h2> en erfde daarmee de standaardmarges van
   Materialize: 33,2px boven en 19,9px onder, om een kop van 29px hoog. Samen met
   de padding van 1rem werd elke header 111px terwijl er één regel tekst in staat.
   De ruimte in dit blok hoort van de padding te komen, niet van de kop.
   (Dezelfde erfenis als eerder in .page-footer.) */
.collapsible-header h2 { margin: 0; }
.collapsible-body { border-bottom: 1px solid #e8eaf6; padding: 0; }

/* Services */
#services .card-content { background-color: #1A237E; border-radius: var(--jd-vorm-m); cursor: pointer; }
#services .card-content:hover { background-color: #101974; }
/* De twaalf dienstenkaarten. Deze koppen waren h5 en zijn h2 geworden omdat het
   de secties van deze pagina zijn -- de structuur sprong daar van niveau één
   naar vijf. De maat volgt de volle schaal niet: de kaart is 194px breed, en op
   40px past "Websites" er net in maar "Visitekaartjes" niet meer. */
#services .card-content h2,
#services .card-reveal h2 { font-size: clamp(1.15rem, 1.05rem + .5vw, 1.4rem); line-height: 1.25; }
#services .card-content h2 { margin: 34px 0; text-align: center; }
#services .card-content i { display: block; font-size: 6rem; margin: 34px 0; text-align: center; }
#services .card-reveal h2 { display: inline-block; margin: 0; }
#services .card-reveal i.right { margin-top: 6px; }

/* Contact */
/* De verticale ritmiek van het formulier op mobiel.
   Materialize v2.3 maakt van .row een CSS Grid. Op mobiel staan de twee kolommen
   onder elkaar, en dan komt de ruimte tussen twee velden in dezelfde rij uit de
   gap van het grid, terwijl de ruimte tussen twee rijen uit margin-bottom komt.
   Verschillen die twee, dan wisselt de tussenruimte om en om -- gemeten was dat
   11 / 0 / 11 / 0 px, waardoor de velden paarsgewijs aan elkaar plakten.

   Onder v1 stond hier 0, en dat klopte toen: .row was float-gebaseerd zonder gap
   en de gestapelde velden brachten hun eigen marge mee. In v2.3 hebben de velden
   marge 0, dus die nul liet op mobiel de helft van de tussenruimtes wegvallen.

   Waarom 11.25px en geen ronder getal: het formulier komt uit Contact Form 7 en
   staat in de database, en in die opgeslagen HTML hebben de rijen een inline
   `style="gap: 11.25px"`. Een inline-stijl wint van elke regel hier, dus die gap
   valt van hieruit niet te veranderen -- alleen te evenaren. Verdwijnt die
   inline-stijl ooit uit het formulier, dan valt de gap terug op --gap-size (1.5rem
   = 21px) en moet deze waarde mee. */
#contact .wpcf7 .row, #contact-me .wpcf7 .row { margin-bottom: 11.25px; }
.wpcf7 .screen-reader-response, .wpcf7 .wpcf7-response-output { display: none; }
/* Contact Form 7 zet zijn verborgen velden in een <fieldset>, die zonder eigen
   opmaak de standaard browserrand toont: een leeg kadertje boven het formulier. */
.wpcf7 .hidden-fields-container { display: none; }

/* Samenwerkingen */
#collaborations { padding-bottom: 30px; }
#collaborations img { padding: 10px; }

/* Portfolio */
.content, .main, .aside { display: flex; flex: 1; flex-direction: column; justify-content: center; }
.content .main { z-index: 0; }
/* De fotokolom stond op een vaste 150px. Dat werkt op een brede kaart, maar tussen
   993 en ongeveer 1200px is de kaart maar een derde van het venster: bij 1000px is hij
   333px breed, en dan slokt die 150px met de padding erbij zo veel op dat er 118px
   overblijft voor de tekst. Daar paste zelfs 'Op zoek naar een' niet meer op één regel.

   Met een percentage schaalt de foto mee en houdt de tekst genoeg ruimte; de bovengrens
   van 150px zorgt dat er op een brede kaart niets verandert, en de ondergrens dat de
   foto niet in het niet valt. */
.content .main .main-wrapper { display: grid; grid-template-columns: 1fr clamp(80px, 26%, 150px); align-items: center; padding: 1.5rem; }

/* De foto vult zijn kolom en steekt er nooit buiten. In de markup staat width="100" als
   attribuut, en zolang de kolom vast op 150px stond viel dat niet op. Nu de kolom
   meeschaalt kan hij smaller worden dan 100px -- op een telefoon is hij 87px -- en dan
   liep de foto over de alinea ernaast heen. */
.content .main .main-wrapper .main-image img { width: 100%; height: auto; max-width: 100%; }

/* RUIMTE TUSSEN DE TEKST EN DE FOTO
   De foto is 100px breed in een kolom van 150px en staat rechts uitgelijnd; die
   50px overschot wás de enige tussenruimte, en dat is te krap -- de kop liep er
   precies tegenaan. Een echte column-gap maakt er 71 tot 73px van, over alle
   breedtes.

   WAAROM 1.5rem EN NIET MEER
   De ruimte moet uit de tekstkolom komen, en die is smal. Bij 2rem valt de kop
   op een extra regel en groeit de kaart van 284 naar 322px -- precies het
   verspringen dat we er eerder uit hebben gehaald. Bij 1.5rem blijft de hoogte
   op elke gemeten breedte gelijk (601, 993, 1200, 1440 en 1730+).

   WAAROM NU OOK ONDER 601px
   Dit stond eerst achter @media (min-width: 601px). De reden daarvoor: op een
   telefoon had de tekst maar 183px en kostte zelfs 1rem de alinea een regel,
   waardoor de kaart van 261 naar 309px groeide.

   Die meting hoort bij de oude opzet met een vaste kolom van 150px voor de foto.
   Sinds die kolom op clamp(80px, 26%, 150px) staat is de fotokolom op een
   telefoon nog maar 96px en heeft de tekst er ruim honderd pixels bij. Opnieuw
   gemeten, met de kaarthoogte per waarde:

     breedte   geen gap   0,5rem   0,75rem   1rem   1,5rem
     320px       222        221      220      219     218
     360px       269        268      267      267     265
     412px       281        280      280      279     278

   De kaart groeit dus nergens meer -- hij wordt zelfs een pixel of drie lager,
   omdat de tekstkolom smaller wordt en de regels anders vallen. Daarmee is er
   geen reden meer om de tussenruimte op een telefoon weg te laten, en stond de
   alinea daar tegen de foto aan (gemeten op een Pixel 10, 412px: 0px ertussen).

   Eén waarde voor alle breedtes; vanaf 1730px zet het blok verderop hem op
   4.5rem, omdat de foto zijn kolom daar helemaal vult. */
.content .main .main-wrapper { column-gap: 1.5rem; }

/* WITRUIMTE IN DE INTROKAART, RUIMER NAARMATE DE KAART GROTER IS
   De padding stond vast op 1.5rem (2.5rem boven 1730px). Verhoudingsgewijs was dat op
   elk scherm ongeveer gelijk -- 5,6% van de kaart op een telefoon en 5,9% op 1900px --
   en juist dat is het probleem: op een kaart van 633px oogt eenzelfde percentage krap,
   want de inhoud erin is dan groot. De tekst plakte tegen de linkerrand en de foto
   tegen de rechter.

   De clamp hieronder groeit daarom sneller dan de kaart. De ondergrens houdt hem tot
   ongeveer een kaartbreedte van 380px op de oude 1.5rem, dus op smalle en middelbare
   schermen verandert er niets; daarboven loopt hij op tot 5rem. Gemeten op 1900px:
   37,5px wordt 53,5px, oftewel 5,9% wordt 8,5% van de kaart.

   Alleen vanaf 993px. Daaronder is de kaart de volle vensterbreedte en klopt de
   bestaande maat -- daar was het immers goed.

   De container staat op .main en niet op .main-wrapper zelf: een element kan zijn eigen
   padding niet op zijn eigen containerbreedte baseren zonder kringverwijzing. */
@media only screen and (min-width: 993px) {
  .content .main { container-type: inline-size; }
  .content .main .main-wrapper { padding: clamp(1.5rem, -1.5rem + 12cqi, 5rem); }
}
/* De kop in de introkaart, op de startpagina en op /projecten.

   Bewust kleiner dan een volwaardige h1: deze kaart is één cel van het tegelraster,
   dus 60px tekst zou er niet in passen. Het niveau in de documentstructuur staat los
   van de maat -- dát het een h1 is, is semantiek; hóé groot hij is, is ontwerp.

   DE MAAT VOLGT DE TEKSTKOLOM, NIET HET VENSTER
   Hier stond een clamp op vw. Dat werkt niet, want de kaart schaalt niet evenredig mee
   met het venster: bij een venster van 1134px was de kaart 421px en de tekstkolom
   ernaast maar 206px, terwijl de kop al op 31,9px stond -- zo'n zes tekens per regel.

   Met een container query volgt de maat de ruimte die de kop werkelijk heeft. 1cqi is
   1% van de breedte van .main-text, dus de verhouding tussen kop en kolom blijft op elk
   scherm gelijk en de kop mag op een breed scherm gewoon groot worden.

   Bewust de tekstkolom als container en niet de kaart. De fotokolom van 150px is een
   vaste aftrek, dus de tekstkolom groeit sneller dan de kaart: gemeten op 1900px is de
   kaart 633px en de kolom 391px. Op de kaart afstemmen gaf daar 28,7px, op de kolom
   ruim 36 -- en dat laatste vult de ruimte zoals het hoort.

   WAAROM 8.7cqi EN GEEN VASTE OPTELLING ERBIJ
   De kop hoort altijd op twee regels te passen: 'Op zoek naar een' op de eerste en het
   getypte beroep op de tweede. Doorgemeten is de langste variant 'interactie ontwerper?'
   inclusief cursor, en die past op één regel zolang de kop hoogstens 9,25% van de
   kolombreedte is -- een verhouding die over alle breedtes lineair blijft. 8,7% houdt
   daar ruim 6% marge op.

   Een vaste optelling erbij (zoals 0.3rem + 9cqi) breekt dat: die telt op smalle
   kolommen relatief zwaarder mee, waardoor de verhouding kantelt en er alsnog een derde
   regel ontstaat. Puur cqi houdt hem overal kloppend.

   De containment die container-type meebrengt heeft een neveneffect dat hier gunstig
   uitpakt: de kolom rekt zijn rastercel niet langer op met zijn langste woord, dus het
   tegelraster verdeelt de breedte weer eerlijk. */
.content .main .main-text { container-type: inline-size; }

.content .main .main-wrapper h1 {
  font-size: clamp(1.05rem, 8.7cqi, 3.2rem);
  line-height: 1.15;
  margin-top: 0;
}

/* Houder voor het typemachine-effect. Alle varianten liggen als onzichtbare
   kopieën in dezelfde grid-cel als de getypte tekst, zodat de cel altijd zo hoog
   is als de langste variant op die breedte. Zonder dit sprong de kaart een hele
   regel op en neer zodra een variant wel of niet omsloeg -- op 375px 27,3px.

   Deze houder staat op blokniveau en begint dus zelf een nieuwe regel; daarom is
   de <br> die hier stond uit index.php en page-projects.php gehaald. Zou je hem
   laten staan, dan kwam er een lege regel bij.

   Bewust geen min-height met een vast getal: hoeveel regels een variant nodig
   heeft hangt af van de breedte, de tekstgrootte en de taal. De browser rekent
   dat hier zelf uit, dus het blijft kloppen als er een variant bij komt of als
   de Engelse vertaling langer uitvalt.

   De kopieën worden in js/functions.js aangemaakt uit dezelfde lijst die het
   effect zelf gebruikt, zodat er één bron is. */
.jd-typer { display: grid; }
.jd-typer > * { grid-area: 1 / 1; }
.jd-typer-ruimte { visibility: hidden; }
.content .aside { padding: 10px 0; }

/* Aanraakfeedback op de categorietegels.
   Vanaf 993px zijn de tegels in rust kleurloos en komt de kleur bij hover; de
   knop schaalt dan mee. Daaronder staat de kleur er al en bestaat hover niet,
   dus gaf een tik nul reactie: je wist pas dat je iets geraakt had toen de
   volgende pagina verscheen. Een korte indruk van de knop vult dat gat.
   Alleen transform, en kort genoeg om niet in de weg te zitten bij het scrollen. */
@media only screen and (max-width: 992.99px) {
  .content .aside div { transition: transform 120ms ease-out; }
  .content .aside:active div { transform: scale(.96); }
}
/* Kleur van de categorietegels.
   ---------------------------------------------------------------------------
   Hier stonden acht losse kleuren uit een Flat-UI-palet (#00b894, #fdcb6e,
   #e84393 en zo verder). Die hadden geen enkele relatie met het indigo van dit
   thema en oogden onrustig, zeker op een klein scherm waar ze allemaal tegelijk
   zichtbaar zijn in plaats van één voor één bij hover.

   Ze haalden bovendien de norm niet. WCAG 1.4.11 vraagt 3:1 tussen een
   bedieningselement en wat eromheen ligt, en de knop op de rode tegel (#d63031)
   en de paarse (#6c5ce7) kwam niet verder dan 2,73:1.

   Nu is het één ladder uit de indigo die het thema al gebruikt: acht stappen van
   lichten-5 naar lichten-2, met gelijke afstanden in oklab zodat het oog ze als
   even grote stappen ziet. De donkerste stap is bewust #7986cb: daar haalt de
   knop nog 3,84:1, en bij lichten-1 zou dat naar 2,72 zakken en dus de norm niet
   meer halen.

   De waarden staan als variabelen omdat ze op drie plekken nodig zijn: de tegel
   zelf, de hover- en actieve staat vanaf 993px, en de donkere modus onderaan dit
   bestand die alleen deze acht regels hoeft te overschrijven. */
:root {
  --jd-tegel-1: #e8eaf6;
  --jd-tegel-2: #d7dbf0;
  --jd-tegel-3: #c7cdeb;
  --jd-tegel-4: #b7bfe5;
  --jd-tegel-5: #a7b1de;
  --jd-tegel-6: #97a2d8;
  --jd-tegel-7: #8894d2;
  --jd-tegel-8: #7986cb;
}
.content .aside-1 { background-color: var(--jd-tegel-1); }
.content .aside-2 { background-color: var(--jd-tegel-2); }
.content .aside-3 { background-color: var(--jd-tegel-3); }
.content .aside-4 { background-color: var(--jd-tegel-4); }
.content .aside-5 { background-color: var(--jd-tegel-5); }
.content .aside-6 { background-color: var(--jd-tegel-6); }
.content .aside-7 { background-color: var(--jd-tegel-7); }
.content .aside-8 { background-color: var(--jd-tegel-8); }
.content .aside div span { height: 32.4px; line-height: 32.4px; font-size: 13px; }

/* Card */
/* overflow hoort bij de ronding: de uitgelichte afbeelding en het indigo vlak
   eronder vullen de bovenkant van de kaart en liepen zonder dit over de ronde
   hoek heen, zodat de kaart bovenaan vierkant bleef. Materialize v2.3.3 zet
   geen overflow meer op .card; in v1 stond dat er wel op. */
.card { border-radius: var(--jd-vorm-m); overflow: hidden; }
.card .card-image { overflow: hidden; }
/* height: auto hoort bij width: 100%. the_post_thumbnail() zet height="300" als
   attribuut; zonder deze regel blijft die 300px staan terwijl de breedte meerekt
   met de kaart, en werd een vierkante projectafbeelding op mobiel tot 350x300
   platgedrukt. */
/* De transitie noemt nu de eigenschap. Hij stond op `300ms ease-in-out 50ms`
   zonder eigenschapsnaam, wat 'alles' betekent: de browser houdt dan elke
   veranderende eigenschap van dit element in de gaten, ook breedte en hoogte bij
   het wisselen van de galerijafbeelding. De vertraging van 50ms kon weg -- die
   maakte de reactie op een hover alleen maar trager zonder iets toe te voegen. */
.card .card-image img { margin: 0 auto; max-height: 650px; max-width: 650px; transition: opacity 200ms ease-in-out; width: 100%; height: auto; }
.card:hover .card-image img { transition: .25s ease-in-out .05s; transform: scale(1.05); }
/* transform in plaats van margin-left, en een benoemde transitie in plaats van
   `all`. Een marge verschuift het element in de layout: de browser moet dan bij
   elke stap van de animatie opnieuw uitrekenen waar de tekst afbreekt. Een
   transform gebeurt in de compositor, buiten layout om, en kost dus niets. */
/* De schaduw onder de projecttitel.
   Hier stonden drie schaduwen van 7px op 40% dekking, links, rechts en onder.
   Dat gaf een wollige grijze waas in plaats van een rand.

   Het advies was om terug te gaan naar één schaduw. Dat is hier niet gedaan, en
   dat is een bewuste afwijking: gemeten op /categorie/websites/ is de achtergrond
   achter de titel vrijwel wit -- mediaan contrast 1,00 tot 1,07, want die
   uitgelichte afbeeldingen zijn screenshots van websites. De schaduw is daar het
   enige dat de witte titel leesbaar houdt. Eén zachtere schaduw zou de bekende
   zwakke plek verder verzwakken.

   Twee lagen dus, maar strakker en donkerder: een korte harde voor de rand van de
   letter, en een wijdere zachte die de tekst van het beeld tilt. Minder waas,
   meer houvast. De titel blijft over het beeld staan en er komt geen verloop
   onder -- dat is een eerder genomen besluit. */
.card .card-image .card-title { transition: transform 200ms ease-out; line-height: inherit; text-shadow: 0 1px 2px rgba(0,0,0,.6), 0 0 10px rgba(0,0,0,.5) }
.card:hover .card-image .card-title { transform: translateX(10px); }
/* Transparant in plaats van #ffffff, om dezelfde reden als bij .card-tabs .tabs
   hieronder: de kaart zelf is #fcfcff (Materialize mengt surface met 17%
   surface-tint), dus een vaste witte inhoud gaf twee tinten binnen één kaart.
   Nu volgen inhoud, Klant/Jaar-strook en tagrij allemaal de kaart.
   De tegels op /diensten houden hun indigo: #services .card-content weegt
   zwaarder (id) dan deze regel. */
.card .card-content { border-radius: 0 0 var(--jd-vorm-m) var(--jd-vorm-m); background-color: transparent; position: relative; }

/* Leesbreedte van de projecttekst.
   ---------------------------------------------------------------------------
   Hier stond `max-width: 32rem` op de alinea's, om de regellengte terug te brengen
   van 87 naar 69 tekens. Dat las prettiger, maar liet 122px van de kaart ongebruikt
   en dat oogde als een fout in plaats van als een keuze -- op verzoek weggehaald.

   De tekst loopt nu weer over de volle 602px van het inhoudsvak. Dat is zo'n 75
   tekens per regel: de bovengrens van wat nog comfortabel leest, maar wel binnen
   de marge. Wordt de kaart ooit breder, kijk hier dan opnieuw -- boven de 75 gaat
   het oog terugzoeken waar de volgende regel begint. */
.card .card-content > p,
.card .card-content > ul,
.card .card-content > ol { max-width: none; }
.card .process { margin: 0 auto 10px; display: block; width: 100%; }
/* De height: auto hoort bij de width: auto en is geen overbodige toevoeging.
   WordPress schrijft width="300" height="300" als attributen uit, en de HTML-spec
   maakt daar presentatie-hints voor de CSS-eigenschappen width en height van.
   Deze regel overschreef alleen de breedte, dus de hoogte van 300px bleef staan,
   werd door max-height naar 60px geknepen en de breedte liep los daarvan tegen
   max-width: 17% aan. Bij een smal scherm is 17% minder dan 60px en werd een
   vierkant logo van 110x110 weergegeven als 51x60 -- 14% uitgerekt. Op desktop
   is 17% ruimer dan 60px, daar bond alleen de hoogte en viel het niet op. */
/* 140ms in plaats van 500ms, en alleen op opacity -- dat is het enige wat hier
   verandert (zie de :hover-regel hieronder). Een halve seconde voor een
   hoverreactie voelt als vertraging in plaats van als reactie. */
.card .process img { border-radius: var(--jd-vorm-xs); margin: 0 1% 0 0; width: auto; height: auto; display: inline; max-height: 60px; max-width: 17%; opacity: 1; transition: opacity 140ms ease; backface-visibility: hidden;}
.card .process img:last-child { margin: 0; }
.card .process img:hover { cursor: pointer; opacity: 0.75; }
/* Materialize geeft .tabs een eigen achtergrond: var(--md-sys-color-surface).
   De kaart gebruikt daarentegen een getinte variant (surface gemengd met 17%
   surface-tint). In lichte modus schelen die twee nauwelijks, maar in donkere
   modus werd de Klant/Jaar-strook rgb(26,28,30) tegen een kaart van rgb(27,30,51):
   een zichtbare band dwars door de kaart. Transparant laten is de duurzame
   oplossing — de strook volgt dan altijd de kaart, ook wat het dark-mode blok
   onderaan dit bestand met --jd-surface doet. */
/* Klant en jaar onder een project.
   ---------------------------------------------------------------------------
   Deze strook heette `card-tabs` met daarin `ul.tabs.tabs-fixed-width` en
   `li.tab`, maar het zijn geen tabbladen: er valt niets te wisselen, beide
   regels staan altijd zichtbaar naast elkaar. Dat was niet alleen misleidend
   maar ook een valstrik: M.Tabs zoekt `li.tab > a`, vindt hier niets en gooit
   een TypeError. Wie ooit M.AutoInit() aanzet, sloopt daarmee stilzwijgend elke
   pagina met een projectkaart -- en de klantlink in die eerste tab zou sowieso
   dood zijn, want M.Tabs eindigt zijn klikafhandeling met preventDefault().

   De vier declaraties hieronder zijn wat Materialize' .tabs, .tab en
   .tabs-fixed-width feitelijk deden; overgenomen zodat de strook er precies
   hetzelfde uitziet. Gemeten voor en na op /categorie/flyers/: 650 bij 48px,
   items van 394,8 en 255,2px. */
.card .jd-projectmeta-lijst { background-color: transparent; display: flex; list-style: none; margin: 0; padding: 0; }
.card .jd-projectmeta-lijst li { display: block; flex: 1 1 auto; line-height: 48px; text-align: center; text-transform: uppercase; }
/* color: inherit in plaats van een vaste rgba(0,0,0,0.87). Die zwarte waarde
   klopte zolang de kaart wit was, maar sinds theme="light" uit html-header.php is
   gehaald kleurt Materialize de kaart in dark mode donker: zwart op rgb(27,30,51),
   contrast 1.23. Met inherit volgt de klantnaam de tekstkleur van de kaart en
   klopt hij in beide modi. */
.card .jd-projectmeta-lijst li span a.client { color: inherit; display: inline; font-size: inherit; padding: 0; overflow: inherit; }
.card .card-action { border-top: 1px solid #e8eaf6; }
.card .card-reveal .card-title { width: 100%; }

/* De projecttitel over de uitgelichte afbeelding, op single.php.
   Was een <p class="flow-text"> van 25,2px en is nu de h1 van de pagina. De maat
   staat hier apart omdat de volle h1-schaal (tot 60px) een titel als "Website
   Roadside Barbershop" over drie regels zou trekken, boven op het beeld.
   Marge op nul: de titel wordt door .card-title absoluut geplaatst, en de
   standaardmarge van een h1 zou hem uit dat kader duwen. */
.card .card-image .jd-projecttitel {
  /* De bovengrens is bewust 2.4rem en niet 2rem. Met 2rem kwam de titel op
     precies 30px uit -- even groot als de h3 "Gerelateerde projecten" verderop
     op dezelfde pagina, waardoor de paginatitel en een tussenkop even zwaar
     wogen. Dat was nu juist het probleem dat deze ronde oplost. */
  font-size: clamp(1.5rem, 1.1rem + 1.8vw, 2.4rem);
  line-height: 1.15;
  margin: 0;
}

/* Hier stond het volledige uiterlijk van de magnific-popup: de achtergrond, de
   zoomovergang, de vaste sluitknop en pijlen, en een mediaquery die die pijlen op
   smalle schermen naar een pager onderaan verplaatste. Tweeënzestig regels in
   totaal.

   Allemaal weg met de popup zelf. De opmaak die eruit ziet alsof hij erbij hoorde
   maar dat niet doet -- .popup-wrapper en .popup-block -- blijft staan: dat zijn
   de namen van de kaart en de contentwikkel, en die worden nu op gewone pagina's
   gebruikt. Verwarrend gekozen namen, maar ze hernoemen raakt zes templates voor
   nul winst.

   De regel .mfp-wrap button:focus-visible verderop is ook vervallen. */

/* Terug naar de categorie, boven een project (single.php). */
/* Klantarchief (taxonomy-clients.php) en het pictogram naar de website van de
   klant in de projectkaart. */
.jd-klant-aantal { margin: -0.5rem 0 1rem; }
.jd-klant-omschrijving { margin: 0 auto 1rem; max-width: 650px; }

/* Naam en pictogram horen bij elkaar en mogen niet uit elkaar getrokken worden:
   zonder dit viel het pictogram bij een lange klantnaam alleen op een tweede
   regel. Nu breekt de tab ervoor af en schuift het paar als geheel mee. */
.jd-klant { white-space: nowrap; }

/* Het pictogram naar de website van de klant: naast de naam in de kaart en
   achter de kop op het klantarchief. .5em houdt het in verhouding tot de tekst
   waar het naast staat -- in een kaart is dat 13px, in de <h2> ruim 40px. */
/* vertical-align: middle legt het midden van het pictogram op de basislijn plus
   de halve x-hoogte -- de hoogte van een kleine letter. Naast tekst in kapitalen
   ligt het optische midden daar iets boven, dus zakt het pictogram weg.

   Gemeten met measureText: het pictogrammidden lag 1,25px onder het midden van de
   kaphoogte in een kaart (14px tekst) en 2,33px eronder achter de kop op een
   klantarchief (25px tekst). Dat is in beide gevallen 0,09em, dus één waarde dekt
   allebei -- in em zodat hij meeschaalt. */
.jd-klant-site { display: inline-flex; margin-left: .3em; vertical-align: middle; position: relative; top: -.09em; }
.jd-klant-site i { font-size: 1.25em; line-height: 1; }
.popup-wrapper h2 .jd-klant-site i { font-size: .5em; }

/* Het pictogram is in de kaart 18 bij 18 pixels en zou daarmee onder de 24 van
   WCAG 2.5.8 vallen. Padding zou de regel oprekken en de tab hoger maken; een
   pseudo-element vergroot alleen het aanraakvlak en laat de opmaak met rust.
   Links maar 3px erbij: verder zou het over de klantnaam ernaast heen komen. */
.jd-klant-site::after { content: ''; position: absolute; top: -8px; right: -8px; bottom: -8px; left: -3px; }

/* "Meer bekijken" boven de logo's op de dienstenpagina is 17,5px hoog en staat
   alleen in zijn eigen span, dus geen van de uitzonderingen van WCAG 2.5.8 gaat
   op: het is geen link in een lopende zin en er is geen tweede, groter element
   dat naar /samenwerkingen wijst. 4px boven en onder maakt er 25,5px van.

   Bewust hetzelfde pseudo-element als hierboven en geen inline-flex met een
   min-height: deze link heeft dezelfde opbouw als die in de balk bovenin
   (tekst, spatie, pictogram), en flex zou daar de spatie opeten en de eigen
   verticale correctie van Font Awesome negeren. */
#collaborations span.right a { position: relative; }
#collaborations span.right a::after { content: ''; position: absolute; top: -4px; right: 0; bottom: -4px; left: 0; }

/* Materialize richt elke link in een tab in als een tabknop:
   `.tabs .tab a { display: flex; flex-direction: column; width: 100%;
   height: 100%; min-height: 48px; padding: 0 12px; }` -- specificiteit (0,2,1).
   Daardoor werd het pictogram een blok over de volle breedte van de tab en viel
   het onder de klantnaam, precies wat de nowrap eromheen moest voorkomen. Deze
   selector ligt erboven en zet die vijf eigenschappen terug. */
.card .jd-projectmeta-lijst li span a.jd-klant-site {
  display: inline-flex;
  flex-direction: row;
  height: auto;
  min-height: 0;
  /* Materialize zet hier overflow: hidden bij text-overflow: ellipsis. Dat knipte
     het vergrote aanraakvlak (het pseudo-element hierboven) weg tot precies de
     18px van het pictogram zelf. */
  overflow: visible;
  padding: 0;
  /* Hier stond `top: -0.45em` (6,3px omhoog). Dat compenseerde de tab-opmaak van
     Materialize, die het pictogram omlaag duwde: `.tabs .tab a` gaf het een
     min-height van 48px waarin het naar onderen uitzakte.

     Die tabs bestaan niet meer sinds de popup-opzet eruit is, maar de compensatie
     bleef staan -- en dus stond het pictogram voortaan 5,05px te hóóg. Zonder deze
     regel vraagt de kaart dezelfde 0,09em als het klantarchief, en die staat nu op
     .jd-klant-site zelf. */
  width: auto;
}

/* Aanraakvlakken
   ---------------------------------------------------------------------------
   Material Design houdt 48dp aan als kleinste aanraakvlak; WCAG 2.5.8 (AA) legt
   de ondergrens op 24 bij 24 CSS-pixels. Gemeten op /tag/figma/ zaten vier
   soorten links onder die 24: de balk bovenin (15px), de menulijst in de footer
   (18px), de klantnaam in een kaart (18px) en de terugkoppeling (21px).

   De chips blijven 32px: dat is de hoogte die Material Design zelf voor een chip
   voorschrijft, en 32 haalt de WCAG-ondergrens ruim. Ze staan bovendien met 6px
   ertussen, zodat je er niet naast tikt. */

/* De balk bovenin is een smalle hulpbalk; 48px zou hem hoger maken dan de
   navigatie eronder en de verhouding omdraaien. 32px haalt de ondergrens en
   houdt de balk smal.

   De tweede selector lijkt overbodig maar is het niet. Materialize zet met
   `.navbar ul:not(.dropdown-content) > li > a` een display: block op de links in
   de lijst, en die selector weegt zwaarder dan `.header .nav-content a`. De
   losse link ("Vrijblijvend contact opnemen") stond daardoor wél gecentreerd en
   de drie links in de lijst niet: hun tekst hing 9px te hoog in dezelfde balk.
   Deze selector weegt even zwaar als die van Materialize en staat later, dus
   hij wint zonder !important.

   De gap hoort bij die inline-flex en is geen smaakkwestie. In de markup staat
   een gewone spatie tussen het icoon en de tekst (`<i ...></i> LinkedIn`). Een
   flexcontainer verpakt die tekst in een eigen anonieme flexitem, en witruimte
   aan het begin of eind van een regel wordt door CSS weggehaald -- dus precies
   die spatie verdwijnt. Zonder gap plakken icoon en tekst tegen elkaar. 0.28em
   geeft bij de 12px van deze balk 3,36px, tegenover de 3,38px die de spatie zelf
   breed was, en het schaalt mee als de tekstgrootte ooit wijzigt. */
.header .nav-content a,
.header .nav-content ul li > a { display: inline-flex; align-items: center; min-height: 32px; gap: .28em; }

/* Optische correctie op het pictogram, en de reden is dezelfde inline-flex.
   Font Awesome zet op .fa-sm een eigen `vertical-align` om het pictogram op de
   tekst uit te lijnen, maar vertical-align doet niets bij een flexitem: daar
   bepaalt align-items de plek. Die centreert de boxen, en de box van een
   FA-pictogram staat niet op dezelfde hoogte als de letterbeeldhoogte ernaast.

   Gemeten: het inktmidden van het pictogram lag 0,71px boven het midden van de
   kapitaalhoogte van de tekst. Bij de 10,5px van fa-sm is 0.07em daar 0,02px
   naast, dus dat zet het pictogram optisch gelijk. In em zodat het meeschaalt.
   Alleen deze balk: elders staan de pictogrammen in gewone inline-tekst, waar
   de correctie van Font Awesome zelf nog wel werkt. */
.header .nav-content a i { position: relative; top: .07em; }

/* De footer is een echte navigatielijst, dus daar wel de volle 48px. */
.page-footer ul li a { display: flex; align-items: center; min-height: 48px; }

.jd-terug a { min-height: 48px; }
.jd-projectpager a { min-height: 48px; }

/* De klantnaam staat als tekst midden in "Klant: ...". Padding op een inline
   element vergroot het aanraakvlak zonder de regelhoogte te veranderen, dus de
   tabs blijven even hoog als ze waren. */
.card .jd-projectmeta-lijst li span a.client { padding: .45rem 0; }

/* Beschikbaarheidsindicator (inc/beschikbaarheid.php). Een pil met een stip
   ervoor; de kleur van de stip volgt de stand. De tekst staat er altijd bij, dus
   de kleur is een extraatje en niet de enige drager van de betekenis -- dat is
   wat WCAG 1.4.1 vraagt. */
.jd-beschikbaarheid {
  align-items: center;
  background-color: rgba(232, 234, 246, 0.14);
  border-radius: 999px;
  display: inline-flex;
  font-size: .875rem;
  gap: .5rem;
  margin: 0 0 1rem;
  padding: .35rem .85rem;
}
.jd-beschikbaarheid-stip { border-radius: 50%; flex: 0 0 auto; height: 9px; width: 9px; }
.jd-beschikbaarheid-beschikbaar .jd-beschikbaarheid-stip { background-color: #00b894; }
.jd-beschikbaarheid-beperkt .jd-beschikbaarheid-stip { background-color: #fdcb6e; }
.jd-beschikbaarheid-volgeboekt .jd-beschikbaarheid-stip { background-color: #e17055; }

/* De <p> in de footer erft anders de grijze standaardtekstkleur van Materialize
   (#72787e); op het doorschijnende vlak komt dat neer op 2,07:1. De kleur van de
   rest van de footer geeft 7,72:1. */
.page-footer .jd-beschikbaarheid { color: #e8eaf6; }

/* Op de contactpagina staat de pil op een kaart in plaats van op de donkere
   footer; daar is een licht vlak met donkere tekst leesbaarder (11,06:1), in
   beide modi, want die kaart is in de donkere modus ook donker. */
#contact .jd-beschikbaarheid { background-color: #e8eaf6; color: #1a237e; }

/* DE PIL IN DE HULPBALK BOVENIN
   Die balk is precies 48px hoog en dat getal staat als --jd-hulpbalk-hoogte
   bovenaan dit bestand; de meelopende navigatiebalk pint op -48px zodat hij
   wegscrollt. Wordt de pil hoger dan de 32px die de links daar innemen, dan groeit
   de balk mee en blijft er een streepje in beeld hangen.

   Vandaar een vaste hoogte van 24px in plaats van verticale padding: dan kan de
   inhoud hem niet oprekken, ongeacht de tekstlengte. Met 12px tekst -- gelijk aan
   de rest van de balk -- en de stip erbij past dat ruim binnen de 32px.

   De marge eraf: die 1rem eronder is voor de footer en de contactpagina, waar de
   pil boven een alinea staat. Hier staat hij naast een link.

   De 4px erboven is uitlijning, geen ruimte. De links in deze balk nemen 32px in,
   de pil 24px; allebei beginnen ze onder dezelfde 8px padding, dus zonder die
   marge zit het midden van de pil op 20px en dat van de link op 24px -- gemeten,
   en met dit lettertype op deze maat ook zichtbaar. Vier pixels erbij zet de twee
   middens gelijk zonder de balk hoger te maken. */
.header .nav-content .jd-beschikbaarheid {
  color: #c5cae9;
  float: left;
  font-size: 12px;
  height: 24px;
  line-height: 24px;
  margin: 4px 14px 0 0;
  padding: 0 10px;
}
.header .nav-content .jd-beschikbaarheid-stip { height: 7px; width: 7px; }

/* De toelichting is een vrij tekstveld in de Customizer, en een lange zin duwde de
   pil hier onder 700px naar een tweede regel: de balk werd 76px in plaats van 48 en
   de meelopende navigatiebalk liet daarna een streepje staan. Gemeten met een
   toelichting van 85 tekens.

   Een harde bovengrens met afkapping houdt dat tegen. Zie je op je eigen site een
   afgekapte zin met puntjes, dan is dat het signaal om hem korter te maken -- de
   volledige tekst blijft in de footer en op de contactpagina gewoon staan. */
.header .nav-content .jd-beschikbaarheid-tekst {
  display: block;
  max-width: 28ch;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Onder 601px is de hulpbalk verborgen (hide-on-small-only) en valt de indicator
   daar dus weg. Daar neemt de footer het over; boven die grens zou hij dubbel
   staan, dus daar gaat de footervariant uit. */
@media only screen and (min-width: 601px) {
  .page-footer .jd-beschikbaarheid { display: none; }
}

/* Vorige/volgende project onderaan een projectpagina (single.php).
   Twee kolommen die uit elkaar staan; heeft een project maar één buur, dan blijft
   die aan de juiste kant staan door de space-between met een enkel kind -- daarom
   krijgt de volgende-link margin-left:auto. */
.jd-projectpager { display: flex; gap: 1rem; justify-content: space-between; margin: 2rem 0 0; }
.jd-projectpager a { align-items: center; display: flex; gap: .25rem; max-width: 48%; }
.jd-projectpager-volgende { margin-left: auto; text-align: right; }
.jd-projectpager-tekst { display: block; min-width: 0; }
.jd-projectpager-label { display: block; font-size: .75rem; letter-spacing: .04em; opacity: .75; text-transform: uppercase; }

/* De titel op één regel met een beletselteken: projecttitels lopen tot ruim
   dertig tekens en zouden de twee kolommen anders ongelijk hoog maken. */
.jd-projectpager-titel { display: block; font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.jd-projectpager i { flex: 0 0 auto; }

@media only screen and (max-width: 600px) {
  /* Naast elkaar blijft er per kolom te weinig over voor een leesbare titel. */
  .jd-projectpager { flex-direction: column; gap: 1.25rem; }
  .jd-projectpager a, .jd-projectpager-volgende { max-width: 100%; }
  .jd-projectpager-volgende { justify-content: flex-end; }
}

/* Toollijst (parts/shared/tool-chips.php) in de footer en onderaan tag.php. */
.jd-tools h2 { font-size: 1.1rem; margin-bottom: .75rem; }
.jd-toollijst { display: flex; flex-wrap: wrap; gap: 6px; justify-content: center; }
.jd-tools-archief { margin-top: 2.5rem; }

/* De chips staan hier in een flexrij; de marge die Materialize ze geeft zou daar
   bovenop de gap komen. */
.jd-toollijst .chip { margin: 0; }
.jd-toollijst a { display: inline-flex; }

/* Op Over mij staat de lijst links uitgelijnd, in lijn met de blokken erboven;
   op een toolarchief gecentreerd, zoals de rest van die pagina. */
#about-me .jd-toollijst { justify-content: flex-start; }
#about-me .jd-tools { margin-top: 2rem; }

/* De tool waar je op staat: geen link, wel duidelijk de huidige. */
.jd-tool-huidig .chip { background-color: #1a237e; color: #e8eaf6; }

/* Het aantal achter de naam, alleen op het archief. */
.jd-tool-aantal { margin-left: .4rem; opacity: .7; font-size: .8125rem; }

.jd-terug { margin: 0 0 1rem; }
.jd-terug a { align-items: center; display: inline-flex; font-size: .9375rem; gap: .25rem; }
.jd-terug a:hover { text-decoration: underline; }
.jd-terug i { font-size: 1.125rem; }

/* Aantal projecten, op een tweede regel binnen de knop. De knop van .content .aside
   heeft een vaste hoogte van 32.4px met bijpassende line-height; die moet los voor
   twee regels, vandaar height:auto en eigen padding.

   De padding volgt Material Design 3. Daar is de filled button 40dp hoog met een
   label van 20dp regelhoogte, dus 10dp lucht boven en onder, en 24dp links en
   rechts (leading/trailing space) -- een verhouding van 2,4 : 1. Hier stond
   6px verticaal tegen 28px horizontaal, oftewel 4,67 : 1: te weinig lucht boven
   en onder en meer links en rechts dan de richtlijn zelfs voor de standaardknop
   aanhoudt. Met 10px/24px klopt de verhouding weer en komt de knop op 55px,
   wat neerkomt op de M3-maat "medium" (56dp) -- passend, want twee regels tekst
   horen niet in de 40dp van de standaardknop.

   M3 Expressive raadt voor de kléine knop 16dp aan in plaats van 24dp. Dat geldt
   hier niet: deze knop zit met 55px in de medium-klasse, waar de padding juist
   mee omhoog schaalt. */
.content .aside div span.btn { height: auto; line-height: 1.35; }

/* DE PIL SCHAALT MEE MET ZIJN TEGEL
   De maten stonden vast: 15px tekst en 10px/24px padding, ongeacht het scherm. Daardoor
   bleef de pil altijd 118px breed terwijl de tegel meegroeide -- gemeten van 63% van de
   tegel op een telefoon naar 19% op een breed scherm. Op zo'n scherm oogt hij dan
   verloren in een grote cel.

   Net als bij de kop in de introkaart volgt de maat nu de cel zelf via een container
   query, en niet het venster: de tegels zijn rastercellen en die schalen niet evenredig
   met de viewport.

   De ondergrens staat bewust in px en niet in rem. De basismaat van het thema verschilt
   per breekpunt (14px op een telefoon, 15px daarboven), dus 1rem zou op mobiel 14px zijn
   en de pil daar juist kleiner maken dan hij was -- gemeten 14,2px in plaats van 15. Met
   15px blijft mobiel exact zoals het was. Op 1900px komt de pil op 22,9px tekst en 180px
   breed.

   padding en de teller staan in em, zodat de verhoudingen binnen de pil kloppen blijven
   bij elke maat. 0.667em en 1.6em zijn exact de oude 10px en 24px bij 15px tekst, en
   0.6875em is exact de oude .6875rem. */
.content .aside { container-type: inline-size; }

.content .aside div span.btn {
  font-size: clamp(15px, 0.77rem + 1.8cqi, 1.55rem);
  padding: .667em 1.6em;
}
/* height, line-height en padding moeten hier expliciet. De selector
   `.content .aside div span` legt élke span in de tegel zijn maten op, en deze
   tweede regel is óók zo'n span -- de bedoeling was alleen de knop eromheen.

   De padding was daarbij het schadelijkst. Vanaf 360px geeft die regel elke span
   28px links en rechts, dus kreeg deze binnenste regel er nog eens 56px bij
   bovenop de 56px van de knop zelf. Daardoor werd niet de categorienaam de
   breedste regel maar deze, en kwam elke knop uit op de breedte van "N projecten"
   plus twee keer de padding: allemaal 173 of 179px, ongeacht de naam erboven.
   Met padding: 0 volgt de knop weer de langste van beide regels en lopen de
   breedtes van 117px ("Studie") tot 166px ("Social Media"). */
.content .aside div span.jd-aantal { display: block; font-family: inherit; font-size: .6875em; font-weight: 400; height: auto; letter-spacing: .04em; line-height: 1.3; margin-top: .1rem; opacity: .8; padding: 0; text-transform: none; }

/* Footer */
.page-footer p a { text-decoration: underline; }
.page-footer p a:hover { text-decoration: none; }
.page-footer ul li a { color: #c5cae9; }
.page-footer ul li.active a { display: none; }
.page-footer .footer-copyright a { overflow: inherit; min-height: inherit; display: inline; padding: inherit; background-color: initial; }
/* Het menu-item CONTACT heeft de class .btn, maar in de footer moet het als
   gewone tekst lezen; deze regel haalt de knopopmaak eraf. display was hier
   inline, waardoor de min-height van 48px uit het blok Aanraakvlakken er niet op
   pakte en dit als enige link in de lijst 18px hoog bleef. Met flex staat hij
   gelijk aan de vier links erboven. */
.page-footer ul li a.btn { background: none; box-shadow: none; display: flex; align-items: center; font-size: inherit; letter-spacing: initial; line-height: initial; overflow: visible; padding: 0; text-transform: initial; vertical-align: initial; }
.footer-copyright { font-size: 12px; padding: 0; }
.page-footer .footer-copyright .container { margin: 0 auto; }

/* Form */
input:not([type]):focus:not([readonly]) + label, input[type="text"]:not(.browser-default):focus:not([readonly]) + label, input[type="password"]:not(.browser-default):focus:not([readonly]) + label,
input[type="email"]:not(.browser-default):focus:not([readonly]) + label, input[type="url"]:not(.browser-default):focus:not([readonly]) + label, input[type="time"]:not(.browser-default):focus:not([readonly]) + label,
input[type="date"]:not(.browser-default):focus:not([readonly]) + label, input[type="datetime"]:not(.browser-default):focus:not([readonly]) + label, input[type="datetime-local"]:not(.browser-default):focus:not([readonly]) + label,
input[type="tel"]:not(.browser-default):focus:not([readonly]) + label, input[type="number"]:not(.browser-default):focus:not([readonly]) + label, input[type="search"]:not(.browser-default):focus:not([readonly]) + label,
textarea.materialize-textarea:focus:not([readonly]) + label, .input-field .prefix.active { color: #1a237e; }
input:not([type]):focus:not([readonly]), input[type="text"]:not(.browser-default):focus:not([readonly]), input[type="password"]:not(.browser-default):focus:not([readonly]), input[type="email"]:not(.browser-default):focus:not([readonly]),
input[type="url"]:not(.browser-default):focus:not([readonly]), input[type="time"]:not(.browser-default):focus:not([readonly]), input[type="date"]:not(.browser-default):focus:not([readonly]), input[type="datetime"]:not(.browser-default):focus:not([readonly]),
input[type="datetime-local"]:not(.browser-default):focus:not([readonly]), input[type="tel"]:not(.browser-default):focus:not([readonly]), input[type="number"]:not(.browser-default):focus:not([readonly]), input[type="search"]:not(.browser-default):focus:not([readonly]),
textarea.materialize-textarea:focus:not([readonly]) { border-bottom: 1px solid #1a237e; -webkit-box-shadow: 0 1px 0 0 #1a237e; box-shadow: 0 1px 0 0 #1a237e; }
.waves-effect input[type="submit"] { color: #ffffff; cursor: pointer; line-height: inherit; }

/* WordPress Adminbar */
#wpadminbar { background-color: #101974; }
#wpadminbar .quicklinks .ab-sub-wrapper .menupop.hover > a,
#wpadminbar .quicklinks .menupop ul li a:focus,
#wpadminbar .quicklinks .menupop ul li a:focus strong,
#wpadminbar .quicklinks .menupop ul li a:hover,
#wpadminbar .quicklinks .menupop ul li a:hover strong,
#wpadminbar .quicklinks .menupop.hover ul li a:focus,
#wpadminbar .quicklinks .menupop.hover ul li a:hover,
#wpadminbar .quicklinks .menupop.hover ul li div[tabindex]:focus,
#wpadminbar .quicklinks .menupop.hover ul li div[tabindex]:hover,
#wpadminbar li #adminbarsearch.adminbar-focused::before,
#wpadminbar li .ab-item:focus .ab-icon::before,
#wpadminbar li .ab-item:focus::before,
#wpadminbar li a:focus .ab-icon::before,
#wpadminbar li.hover .ab-icon::before,
#wpadminbar li.hover .ab-item::before,
#wpadminbar li:hover #adminbarsearch::before,
#wpadminbar li:hover .ab-icon::before,
#wpadminbar li:hover .ab-item::before,
#wpadminbar.nojs .quicklinks .menupop:hover ul li a:focus,
#wpadminbar.nojs .quicklinks .menupop:hover ul li a:hover,
#wpadminbar:not(.mobile) > #wp-toolbar a:focus span.ab-label,
#wpadminbar:not(.mobile) > #wp-toolbar li:hover span.ab-label,
#wpadminbar > #wp-toolbar li.hover span.ab-label,
#wpadminbar .ab-empty-item,
#wpadminbar a.ab-item, #wpadminbar > #wp-toolbar span.ab-label,
#wpadminbar > #wp-toolbar span.noticon { color: #c5cae9; }
#wpadminbar .ab-top-menu > li.hover > .ab-item,
#wpadminbar.nojq .quicklinks .ab-top-menu > li > .ab-item:focus,
#wpadminbar:not(.mobile) .ab-top-menu > li:hover > .ab-item,
#wpadminbar:not(.mobile) .ab-top-menu > li > .ab-item:focus { background-color: #030C67; color: #c5cae9; }
#wpadminbar .menupop .ab-sub-wrapper,
#wpadminbar .shortlink-input { background-color: #030C67; }
body.admin-bar .header { margin: 46px 0 0; }
#wp-admin-bar-user-info .avatar { border-radius: 50%; }

@media all and (min-width: 360px) {
  .content { flex-direction: row; flex-wrap: wrap; }
  .content .main { flex: 0 0 100%; }
  .content .aside { flex: 0 0 50%; }
  /* Geen padding meer hier: de knop zet zijn eigen 10px/24px volgens Material
     Design en de aantalregel staat op 0. Die 28px raakte allebei die spans en
     deed daardoor meer kwaad dan goed. */
  .content .aside div span { height: 54px; line-height: 54px; font-size: 15px; }
}
@media all and (min-width: 451px) {
  .container h1 { margin: 1.8rem 0 1.68rem 0; }
  .popup-wrapper { width: 450px; }
  .popup-block { max-width: 450px; }
}
@media all and (min-width: 601px) {
  /* Vanaf hier staan de twee velden van een rij naast elkaar. De gap van het grid
     werkt dan horizontaal en margin-bottom is de enige verticale ruimte, dus die
     mag hier ruimer dan de 11.25px waarmee hij op mobiel gelijk moet lopen. */
  #contact .wpcf7 .row, #contact-me .wpcf7 .row { margin-bottom: 20px; }
}
@media all and (min-width: 782px) {
  body.admin-bar .header { margin: 32px 0 0; }
  .collapsible-body { padding: 0 2rem; }
}
@media all and (min-width: 993px) {
  .container h1 { margin: 2.8rem 0 1.68rem 0; }
  .header .nav-extended .nav-wrapper { margin: 0 0 0 15px; text-align: left; }
  /* De startpagina is bewust precies één scherm hoog: het tegelraster is een
     compositie die je in één blik ziet, geen lijst om doorheen te scrollen.
     Die vergrendeling staat hier en niet meer als `height: 100%` op .wrapper,
     waar hij ongemerkt ook elke andere pagina raakte.

     Wil je de startpagina ooit laten scrollen -- voor een groter werkraster, een
     klantenrij of een CTA eronder -- dan is dit de regel die eraf moet. Doe dat
     samen met die nieuwe inhoud en niet ervoor: zonder extra secties wordt de
     pagina alleen maar 263px langer zonder dat er iets te zien is. Gemeten op
     1280 bij 900: van 900px naar 1163px. */
  body.home .wrapper { height: 100%; }
  .content { display: grid; grid-gap: 0px; grid-template-columns: repeat(3, 1fr); grid-auto-rows: 1fr; height: 100%; overflow: hidden; }
  .container { display: flex; flex-direction: column; }
  .content .main,
  .content .aside { flex: 0 0 33.333333%; }
  .content .main { border-radius: var(--jd-vorm-m); }
  .popup-wrapper { width: 650px; }
  .popup-block { max-width: 650px; }
  /* Hier stond width: auto. Dat werkte zolang de <img> alleen een width="150"
     als attribuut had: de CSS won van dat attribuut, de afbeelding nam haar
     eigen breedte aan en max-width: 650px kapte die af op de kaartbreedte.
     Sinds de kaarten via the_post_thumbnail('medium') een srcset plus
     width="300" height="300" meekrijgen, levert width: auto juist die 300px op
     en stond de projectafbeelding als klein blokje in een kaart van 650px.
     Met 100% vult hij de kaart weer; sizes in de template zorgt dat de browser
     een bron van de juiste maat ophaalt. height: auto hoort daarbij: zonder dat
     blijft het height="300"-attribuut staan en wordt een vierkante afbeelding
     tot 650x300 platgedrukt. */
  .card .card-image img { width: 100%; height: auto; }
  .aside-1 { order: 1; }
  .aside-2 { order: 2; }
  .aside-3 { order: 3; }
  .aside-4 { order: 4; }
  .main    { order: 5; }
  .aside-5 { order: 6; }
  .aside-6 { order: 7; }
  .aside-7 { order: 8; }
  .aside-8 { order: 9; }
  .content .aside { background-color: unset; }
  /* Dezelfde ladder als hierboven; vanaf deze breedte is de tegel standaard
     kleurloos en komt de kleur pas bij hover of op de actieve categorie. */
  .content .aside-1:hover,
  .content .aside-1.current { background-color: var(--jd-tegel-1); }
  .content .aside-2:hover,
  .content .aside-2.current { background-color: var(--jd-tegel-2); }
  .content .aside-3:hover,
  .content .aside-3.current { background-color: var(--jd-tegel-3); }
  .content .aside-4:hover,
  .content .aside-4.current { background-color: var(--jd-tegel-4); }
  .content .aside-5:hover,
  .content .aside-5.current { background-color: var(--jd-tegel-5); }
  .content .aside-6:hover,
  .content .aside-6.current { background-color: var(--jd-tegel-6); }
  .content .aside-7:hover,
  .content .aside-7.current { background-color: var(--jd-tegel-7); }
  .content .aside-8:hover,
  .content .aside-8.current { background-color: var(--jd-tegel-8); }
  /* De transitie noemt de eigenschap: het enige wat hier verandert is de
     transform. `filter: opacity(100%)` stond erbij en is een no-op -- 100%
     dekking is de standaard -- maar dwong de browser wel een filterlaag aan te
     maken. Weg. De leverancierprefixen op de tegel eronder ook. */
  .content .aside div { transition: transform 0.25s ease-out; }
  .content .aside:hover div,
  .content .aside.current div { transform: scale(1.5); }
  .content .aside { transition: background-color 0.25s linear; }
  #about-me .about-me img { max-height: unset; max-width: unset; }
}

@media only screen and (min-width: 1200px) {
}

@media only screen and (min-width: 1730px) {
  /* Hier is de gap van 1.5rem hierboven niet genoeg. Op deze breedte vult de foto
     zijn kolom helemaal (width: 100% met min-width: 100px), dus er is geen 50px
     overschot meer om op mee te liften: zonder gap raakte de kop de foto op 0px.
     4.5rem brengt het op 68px, gelijk aan de 71-73px op de smallere breedtes. De
     tekstkolom is hier 403px en kan dat hebben; bij 5.5rem valt de kop alsnog om
     en groeit de kaart van 276 naar 314px. */
  /* padding staat hier niet meer: de clamp bij het blok over de witruimte hierboven
     regelt dat nu vloeiend, en een vaste waarde hier zou die overschrijven omdat deze
     regel later in het bestand staat. */
  .content .main .main-wrapper { grid-template-columns: 6fr 1fr; column-gap: 4.5rem; }
  /* width/height staan nu in de basisregel hierboven; min-width zorgt dat de foto op
     een heel breed scherm niet te klein wordt. */
  .content .main .main-wrapper .main-image img { min-width: 100px; }
}
/* Fonts */
@font-face {
  font-family: 'Raleway'; font-display: swap; font-style: normal; font-weight: 700; src: url('fonts/raleway/raleway-v22-latin-700.woff2') format('woff2'), url('fonts/raleway/raleway-v22-latin-700.woff') format('woff'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Material Icons'; font-display: swap; font-style: normal; font-weight: 400; src: url('fonts/materialicons/materialicons-regular.woff2') format('woff2'), url('fonts/materialicons/materialicons-regular.woff') format('woff');
}

/* Lijnenpatroon op de achtergrond
   ---------------------------------------------------------------------------
   Hier stond een animatie die background-position oneindig verschoof: acht
   @keyframes-blokken (vier met leverancierprefix, plus een tweede paar dat
   nergens werd aangeroepen) en 150s per cyclus.

   Weggehaald, om twee redenen. Eén cyclus van 150 seconden over 600px is zo traag
   dat vrijwel niemand hem ooit als beweging herkent, terwijl de browser er wel
   elk frame de hele viewport voor moet bijwerken. En het is beweging die
   automatisch start en nooit stopt -- precies wat je niet wilt op het moment dat
   je bewuste beweging gaat toevoegen die de aandacht wél moet vangen.

   Eerlijk gemeten op /categorie/flyers/ liep het scrollen met de animatie erin
   gewoon soepel: mediaan 8,4ms per frame, p95 17,5ms, nul frames boven de 20ms.
   Het weghalen is dus geen reparatie van een haperende site maar het vrijmaken
   van hoofdruimte, en op zuiniger apparaten dan deze scheelt het wel degelijk.

   background-attachment: fixed is er eerst uitgehaald en daarna teruggezet, en
   dat is een correctie waard. Het advies was dat het de browser dwingt de
   achtergrond bij elke scrollstap opnieuw te schilderen. Nagemeten met de
   animatie er al uit: 359 frames zonder tegen 360 mét, p95 8,9 tegen 9,0 ms --
   geen meetbaar verschil. De hele kostenpost was de animatie.

   En het weghalen brak wél iets zichtbaars. Deze regel geldt voor vier soorten
   elementen tegelijk: html, de body, elke categorietegel en de popup-achtergrond.
   Met `fixed` lijnen die allemaal uit op het venster, waardoor het patroon als
   één doorlopend vel achter de hele pagina ligt. Met `scroll` begint elk element
   zijn eigen 600px-herhaling in zijn eigen linkerbovenhoek, en zie je bij elke
   tegelrand een naad in de golven.

   Het patroon zelf is nooit weggeweest; de donkere variant onderaan dit bestand
   evenmin. Je ziet dus exact hetzelfde als voorheen, het staat alleen stil.

   Dezelfde animatie stond ook in login/custom-login-style.css en is daar op
   dezelfde manier verwijderd, mét behoud van background-attachment. */
html, body:not(.home), .aside {
  background-attachment: fixed;
  background-image: url('images/pattern-wit.svg');
}

/* Beweging verminderen
   ---------------------------------------------------------------------------
   De achtergrond hierboven schuift oneindig door en het typemachine-effect typt
   en wist eindeloos. Beide starten vanzelf, duren langer dan vijf seconden en
   staan naast andere inhoud, zonder pauzeknop -- dat is WCAG 2.2.2 Pause Stop
   Hide, niveau A. Voor wie 'Beweging verminderen' aan heeft staan zetten we die
   beweging stil.

   De achtergrond blijft staan, alleen het schuiven stopt: het patroon is
   decoratie en hoeft niet te verdwijnen. Overige overgangen krijgen een zeer
   korte duur in plaats van 0, zodat een hoverkleur nog wel omslaat en de
   bezoeker feedback houdt, maar er niets meer beweegt.

   js/functions.js leest dezelfde voorkeur en zet dan de eindtekst van het
   typemachine-effect gewoon stil neer. */
@media (prefers-reduced-motion: reduce) {
  html, body:not(.home), .aside {
    -webkit-animation: none;
    -moz-animation:    none;
    -o-animation:      none;
    animation:         none;
  }

  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
    /* Deze twee horen erbij zodra er getrapte effecten bijkomen. Een vertraging
       wordt niet geraakt door een duur: zonder de eerste regel staat een reveal
       met transition-delay nog steeds seconden te wachten voordat hij in nul
       milliseconden verschijnt. En animation-timeline koppelt een animatie aan
       de scrollpositie in plaats van aan tijd, waar een duur van .01ms niets
       tegen uitricht. */
    transition-delay: 0ms !important;
    animation-timeline: none !important;
    /* Zelfde reden als transition-delay, maar dan voor de entree van de tegels:
       die staat op een animation-delay. Met een duur van .01ms en een vertraging
       van 210ms zou een tegel eerst tweetiende seconde onzichtbaar blijven --
       animation-fill-mode: backwards houdt hem immers op het beginframe -- en dan
       pas verschijnen. Dat is precies de flikkering die dit blok moet voorkomen. */
    animation-delay: 0ms !important;
  }
}

/* De uitnodiging in de inhoud
   ---------------------------------------------------------------------------
   Een indigo band binnen het witte vlak, precies na het werk. Volledig indigo,
   geen tegenkleur: dat is een bewuste merkkeuze.

   Juist omdat het dezelfde kleur is als de footer, moet de band los staan van
   wat eronder komt -- vandaar de eigen afronding en de marge. Zonder die twee
   zou hij op een projectpagina visueel aan de footer vastplakken en niet meer
   lezen als een moment maar als het begin van de voettekst.

   De knop kan hier niet de gewone indigo knop zijn: indigo op indigo is niets.
   Hij keert daarom om, net als in donkere modus: licht vlak, donkere letters.
   Gemeten: kop op de band 11,06, knoptekst op de knop 11,06 en de knop tegen de
   band 11,06 -- alle drie hetzelfde, want het is steeds #e8eaf6 tegen #1a237e. */
.jd-cta {
  align-items: center;
  border-radius: var(--jd-vorm-m);
  display: flex;
  flex-wrap: wrap;
  gap: 12px 28px;
  justify-content: space-between;
  margin: 2.5rem 0;
  padding: 2rem 2rem 2.25rem;
}
.jd-cta h2 {
  font-size: clamp(1.35rem, 1.15rem + .9vw, 1.85rem);
  line-height: 1.2;
  margin: 0;
}
.jd-cta .btn {
  background-color: #e8eaf6;
  color: #1a237e;
  flex: none;
}
.jd-cta .btn:hover,
.jd-cta .btn:focus { background-color: #ffffff; color: #1a237e; }
.jd-cta .btn:focus-visible { outline: 3px solid #e8eaf6; outline-offset: 3px; }

@media only screen and (max-width: 600px) {
  /* Op een smal scherm naast elkaar zetten knijpt de knop tot twee regels. */
  .jd-cta { display: block; padding: 1.5rem; }
  .jd-cta h2 { margin-bottom: 1rem; }
}

/* Onthullen bij scroll
   ---------------------------------------------------------------------------
   De begintoestand hangt aan .jd-motion op <html>, en die klasse wordt gezet
   door een klein script in parts/shared/html-header.php -- niet hier. Zonder dat
   script is er niets verborgen: gaat de JavaScript stuk, staat hij uit, of kent
   de browser IntersectionObserver niet, dan staat alles er gewoon. Een
   `opacity: 0` die onvoorwaardelijk in de CSS staat, maakt van één JS-fout een
   lege projectlijst.

   Alleen transform en opacity. Beide worden door de compositor afgehandeld,
   buiten layout en paint om, dus dit kost geen enkele herberekening. Géén
   will-change: op een archief met 27 kaarten zijn dat 27 permanente
   compositorlagen, en dan werkt het middel averechts.

   12px en 260ms zijn bewust bescheiden. Het effect hoort op te vallen als
   beweging in je ooghoek, niet als iets waar je op moet wachten.

   Geen animation-timeline: view(), hoe verleidelijk ook. Een scroll-tijdlijn is
   omkeerbaar: scroll je terug omhoog, dan verdwijnt je werk weer. Een observer
   die na de eerste keer loslaat, onthult één keer en laat het daarna met rust. */
.jd-motion .jd-reveal {
  opacity: 0;
  transform: translateY(12px);
}
/* De categorietegels onthullen alleen met opacity. Zij dragen het lijnenpatroon
   op background-attachment: fixed, en een transform maakt van het element het
   referentiekader voor die achtergrond -- waarna het patroon in de tegel niet
   meer aansluit op dat van de pagina eromheen. Zie de toelichting bij
   @keyframes jd-tegel-entree onderaan. */
.jd-motion .content .aside.jd-reveal { transform: none; }
.jd-motion .content .aside.jd-reveal.jd-zichtbaar { transform: none; }
.jd-motion .jd-reveal.jd-zichtbaar {
  opacity: 1;
  transform: none;
  transition: opacity 260ms ease-out, transform 260ms ease-out;
}
/* Voor elementen die bij het laden al voorbij het kijkvenster liggen -- denk aan
   een herstelde scrollpositie na de terugknop. Die horen er gewoon te staan; ze
   alsnog laten infaden zou beweging tonen voor iets wat de bezoeker allang
   voorbij is. Zie jdOnthulInit() in js/functions.js. */
.jd-motion .jd-reveal.jd-zonder-overgang { transition: none; }

/* Getrapte binnenkomst op de dienstenpagina.
   Twaalf kaarten die tegelijk verschijnen is één blok; één voor één is een
   polonaise. De trap loopt daarom per rij en niet over alle twaalf: elke rij
   begint weer bij nul, met 0 / 55 / 110ms. Zo staat geen enkele kaart langer dan
   een tiende seconde te wachten.

   Dat is bewust anders dan een oplopende vertraging over de hele lijst. Die
   onthult hier namelijk niet alles tegelijk maar per rij, zodra die in beeld
   scrollt -- en dan zou kaart twaalf in zijn eentje 220ms staan wachten zonder
   dat er iets naast hem gebeurt. Dat leest als haperen, niet als ritme.

   De selector gaat over de kolom en niet over de kaart: elke kaart is het enige
   kind van zijn eigen .col, dus :nth-of-type op de kaart is altijd 1. De rij
   begint met de introkolom, vandaar dat de eerste kaart op kind 2 staat.

   Op de klantlogo's staat dit bewust niet -- logo's die één voor één
   binnendruppelen is versiering op bewijsmateriaal. */
#services > .col:nth-child(3n+2) .jd-reveal.jd-zichtbaar { transition-delay: 0ms; }
#services > .col:nth-child(3n+3) .jd-reveal.jd-zichtbaar { transition-delay: 55ms; }
#services > .col:nth-child(3n+4) .jd-reveal.jd-zichtbaar { transition-delay: 110ms; }

/* Binnenkomst van de acht categorietegels
   ---------------------------------------------------------------------------
   Vanaf 993px scrolt de startpagina niet: .content is een grid met height: 100%
   en overflow: hidden. Onthullen bij scroll kan daar dus per definitie niet, en
   de dynamiek moet uit de binnenkomst komen.

   De vertraging volgt de order-waarden hieronder en niet de broncodevolgorde.
   Die twee lopen uiteen: de introkaart neemt plek vijf in het raster in, dus de
   tegels staan op 1-2-3-4 en 6-7-8-9. Op broncodevolgorde zou de trap over het
   scherm heen en weer springen.

   Zeven stappen van 30ms, dus 210ms voor de hele keten. Dit speelt bij élk
   bezoek af: wat de eerste keer aardig is, is de vijfde keer wachttijd op je
   eigen visitekaartje.

   animation-fill-mode: backwards houdt de tegel op het beginframe tijdens zijn
   vertraging -- zonder dat knippert hij eerst zichtbaar voordat hij begint.

   De introkaart (.main) doet hier niet aan mee, en dat is geen vergetelheid: daar
   staan de getypte kop en de portretfoto, de twee kandidaten voor de Largest
   Contentful Paint. Een element dat op opacity: 0 begint telt voor Chrome niet
   als geschilderd, dus een entree daarop zou de gemeten laadtijd van de pagina
   direct verslechteren. */
@media only screen and (min-width: 993px) {
  /* Boven deze breedte geldt de scroll-onthulling niet; de tegels staan al in
     beeld en krijgen in plaats daarvan de entree hieronder. */
  .jd-motion .content .aside.jd-reveal { opacity: 1; transform: none; }

  /* De vertraging gaat via een variabele en niet via losse animation-delay-regels.
     Dat is geen stijlkwestie: de animation-shorthand hieronder zet delay impliciet
     terug op 0, en met vier klassen in de selector weegt hij zwaarder dan een
     losse regel met drie. Alle acht tegels kwamen daardoor tegelijk binnen. Een
     variabele wordt op gebruiksmoment gelezen en kan die botsing niet krijgen. */
  .jd-motion .content .aside.jd-reveal {
    animation: jd-tegel-entree 260ms ease-out var(--jd-entree, 0ms) backwards;
  }
  .jd-motion .content .aside-1 { --jd-entree: 0ms; }
  .jd-motion .content .aside-2 { --jd-entree: 30ms; }
  .jd-motion .content .aside-3 { --jd-entree: 60ms; }
  .jd-motion .content .aside-4 { --jd-entree: 90ms; }
  .jd-motion .content .aside-5 { --jd-entree: 120ms; }
  .jd-motion .content .aside-6 { --jd-entree: 150ms; }
  .jd-motion .content .aside-7 { --jd-entree: 180ms; }
  .jd-motion .content .aside-8 { --jd-entree: 210ms; }
}

/* Alleen opacity, géén transform -- en dat is geen stijlkeuze.
   De tegel is doorzichtig maar schildert wél het lijnenpatroon, en `html` doet dat
   ook: twee identieke lagen over elkaar, allebei op background-attachment: fixed
   en dus uitgelijnd op het venster. Een transform maakt van het element het
   referentiekader voor die fixed achtergrond, waardoor de laag van de tegel
   losraakt van die van de pagina. Tijdens de entree schoof het patroon daardoor
   zichtbaar door de tegel heen en sprong het terug zodra de animatie klaar was.
   Zie ook .jd-reveal hierboven, waar .aside om dezelfde reden is uitgezonderd. */
@keyframes jd-tegel-entree {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* Skip-link
   ---------------------------------------------------------------------------
   Zie parts/shared/html-header.php. Onzichtbaar tot hij focus krijgt, en dan als
   gewone knop linksboven. Niet met display:none of visibility:hidden verstoppen:
   dan haalt de browser hem ook uit de tabvolgorde en is er niets gewonnen. */
.jd-skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 1000;
}
.jd-skip:focus {
  left: 8px;
  top: 8px;
  background-color: var(--md-sys-color-primary);
  border-radius: var(--jd-vorm-vol);
  color: var(--md-sys-color-on-primary);
  font-weight: 700;
  padding: 12px 24px;
}

/* De marker aan het eind van parts/shared/header.php krijgt focus na een klik op
   de skip-link. Zonder outline:none tekent de browser er een kader omheen, om
   een element van nul pixels hoog. */
#jd-inhoud:focus { outline: none; }
#services .card-content {
    background-image: url('images/pattern-indigo.svg'); }

/* Donkere modus
   ===========================================================================
   Volgt de systeemvoorkeur van de bezoeker; er is bewust geen schakelaar. Het
   lichte ontwerp hierboven is ongewijzigd: alles staat in dit ene blok, dus
   verwijderen betekent terug naar altijd licht (zet dan ook theme="light"
   terug in parts/shared/html-header.php).

   Materialize v2.3.3 wisselt zijn eigen --md-sys-color-* tokens al vanzelf om.
   Wat niet meebeweegt zijn twee dingen, en die vangt dit blok op:

   1. De eigen kleuren hierboven (#c5cae9 als paginakleur, #ffffff voor kaarten,
      #1a237e voor links).
   2. De Materialize-kleurklassen in de markup. Die zijn vaste waarden: 71
      koppen dragen `indigo-text text-darken-4`, wat op een donkere kaart
      onleesbaar donkerblauw zou zijn.

   De navigatiebalk en de footer blijven ongemoeid: die dragen `indigo darken-4`
   en `indigo darken-5` en waren al donker.

   Uitgangspunt voor de kleuren is niet zwart maar hetzelfde indigo, alleen
   omgekeerd: donkere vlakken met een lichte indigo als accent. Contrast is
   nagerekend op ten minste 4.5:1 voor tekst. */
@media (prefers-color-scheme: dark) {
  :root {
    --jd-bg: #10121f;            /* paginakleur, tegenhanger van #c5cae9 */
    --jd-surface: #1b1e33;       /* kaarten, tegenhanger van #ffffff */
    --jd-surface-hover: #232741;
    /* Material Design 3 laat hoogte in de donkere modus niet door een slagschaduw
       zien maar door een lichtere ondergrond: hoe hoger iets zweeft, hoe lichter.
       Een schaduw op #1b1e33 is nauwelijks te zien, dus de popup -- die als enige
       boven de pagina hangt -- krijgt deze stap. */
    --jd-surface-verhoogd: #242844;
    --jd-text: #dfe1f0;          /* bodytekst */
    --jd-text-muted: #a9adc9;
    --jd-accent: #aab4ff;        /* indigo, opgelicht zodat het op donker leest */
    --jd-line: rgba(223, 225, 240, 0.14);
  }

  /* Vlakken */
  body, html { background-color: var(--jd-bg); }
  body { color: var(--jd-text); }
  .card, .card .card-content, .container.white, .white { background-color: var(--jd-surface) !important; }

  .card .card-action { background-color: inherit; }
  /* De navigatielade gebruikt de neutrale surface van Materialize (rgb(26,28,30)),
     terwijl de kaarten hier op --jd-surface staan: net iets anders donker. In
     lichte modus valt dat samen, in donkere niet. */
  .sidenav { background-color: var(--jd-surface); }

  /* Het actieve item in de lade: indigo op een donkere ondergrond valt weg, dus
     hier het accent in plaats van #1a237e. */
  .sidenav li.active > a:not(.btn) { background-color: rgba(170, 180, 255, 0.16); }

  /* De dienstentegels zijn ook opgebouwd als .card > .card-content, dus de regel
     hierboven pakte ze mee en maakte ze net zo grijsblauw als elke andere kaart.
     Dat is juist het sterkste merkelement op die pagina, dus het indigo blijft.
     !important is hier nodig omdat de regel hierboven het ook heeft; zonder dat
     wint die, ondanks de lagere specificiteit. Dat geldt ook voor de hover. */
  #services .card-content { background-color: #1a237e !important; }
  #services .card-content:hover { background-color: #101974 !important; }
  #about-me img { background-color: var(--jd-surface); }
  #about-me img:hover { background-color: var(--jd-surface-hover); }

  /* Klantlogo's: de inkt aanpassen, niet de ondergrond.
     Het zijn vaste SVG's in de huisstijlkleur van de klant. Op de donkere kaart
     gemeten haalden 41 van de 49 een contrast onder 3: de 36 op /samenwerkingen
     en /diensten zaten allemaal rond 1.24 (bijna allemaal getekend in #1a237e),
     en op Over mij verdween onder meer het zwarte Skateland-logo op 1.28.

     brightness(0) maakt het logo eerst egaal zwart, invert(1) daarna egaal wit:
     een silhouet. Dat werkt voor lijnwerk op een transparante achtergrond, en dat
     is 47 van de 49 logo's — alle 24 op /samenwerkingen, alle 12 op /diensten en
     11 van de 13 op Over mij.

     De opacity dempt het harde wit tot ongeveer de tekstkleur van de site.

     Bewust .collapsible-body en niet #about-me img: die laatste raakt ook de
     profielfoto, en een foto wil je hier niet in silhouet.

     background-color terug naar transparant: een CSS-filter werkt op de hele
     elementweergave, dus ook op de achtergrond van het element zelf. De cirkels in
     de accordeon hebben er via #about-me img een, en die werd door invert(1) een
     witte schijf waar het logo in verdween. */
  #collaborations img,
  #about-me .collapsible-body img {
    background-color: transparent;
    filter: brightness(0) invert(1);
    opacity: 0.88;
  }

  /* Twee uitzonderingen, allebei op Over mij. Dit zijn knock-outlogo's: ze dragen
     hun eigen gevulde blok met de tekst eruit gespaard. Een silhouet vult dat blok
     volledig wit en de tekst verdwijnt erin — je houdt een blanco rechthoek over.
     Herkenbaar aan de pixelverdeling: veel dekkende pixels én een flink lichte
     fractie (Grafisch Lyceum 33%/52%, Buro BRAND 20%/23%), waar lijnwerk zoals
     Premium Argan op 8%/0% zit.

     Grafisch Lyceum is een licht blok met donkere tekst en een groene balk.
     grayscale(1) haalt het groen eruit, invert(1) maakt de tekst wit en het kader
     zwart — dat kader valt weg tegen de donkere kaart, dus je ziet witte letters.
     Let op: een filter kan een opaak vlak niet transparant maken. De balk blijft
     daardoor als grijs vlak zichtbaar; helemaal weg krijgen vraagt een eigen
     monochrome SVG van dit logo.
     Buro BRAND is het omgekeerde, een zwart blok met witte tekst. invert(1) keert
     dat om naar een licht blok, en hue-rotate(180deg) zet de kleur weer goed. */
  #about-me .collapsible-body img[src*="grafischlyceum"] {
    filter: grayscale(1) invert(1);
    opacity: 1;
  }
  #about-me .collapsible-body img[src*="burobrand"] {
    filter: invert(1) hue-rotate(180deg);
    opacity: 1;
  }

  /* Tekst. De -darken-varianten zijn in de markup bedoeld als "opvallend
     indigo"; op donker is dat juist de lichte variant. */
  .indigo-text.text-darken-1,
  .indigo-text.text-darken-2,
  .indigo-text.text-darken-3,
  .indigo-text.text-darken-4,
  .indigo-text.text-darken-5 { color: var(--jd-accent) !important; }
  /* text-lighten-1 (#5c6bc0) haalde op een donkere kaart maar 3.37: de badges bij
     Ervaring/Opleiding/Stages en het sterretje bij verplichte formuliervelden.
     Bewust alleen -1: de varianten -3 en -5 staan in de header en de footer op een
     vaste indigo balk, waar ze wél goed leesbaar zijn en niets aan mag veranderen. */
  .indigo-text.text-lighten-1 { color: var(--jd-accent) !important; }
  a { color: var(--jd-accent); }
  h1, h2, h3, h4, h5, h6 { color: var(--jd-text); }
  .card .card-content, .card .card-content p, .container.white p { color: var(--jd-text); }

  /* Haarlijnen waren #e8eaf6: op donker een vlakke lichte streep. */
  .collapsible, .collapsible-header, .collapsible-body, .card .card-action,
  .collapsible { border-color: var(--jd-line); }

  /* Chips: geen lichtblauw vlak meer, maar een gedempt vlak met lichte tekst. */
  .chip { background: rgba(170, 180, 255, 0.14); color: #c8cdf5; }

  /* Knoppen blijven indigo met lichte tekst; alleen iets opgelicht zodat ze
     niet wegvallen tegen de donkere achtergrond. */
  .btn, .btn-large, .btn-small, .btn-floating,
  .btn:focus, .btn-large:focus, .btn-small:focus, .btn-floating:focus { background-color: #3949ab; }
  .btn:hover, .btn-large:hover, .btn-small:hover, .btn-floating:hover { background-color: #4d5cc4; }

  /* Paginering volgt de knoppen. */
  .pagination li a { color: var(--jd-accent); }
  .pagination li a:hover, .pagination li a:focus { background-color: rgba(170, 180, 255, 0.14); }
  .pagination li a:focus-visible { outline-color: var(--jd-accent); }

  /* De focusring is standaard indigo (#1a237e); op de donkere vlakken van deze
     modus valt die weg. De uitzonderingen voor navigatiebalk, lade en tegels
     hierboven blijven staan, die zijn daar al licht. */
  a:focus-visible,
  button:focus-visible,
  input:focus-visible,
  textarea:focus-visible,
  select:focus-visible,
  summary:focus-visible,
  [tabindex]:focus-visible { outline-color: var(--jd-accent); }
  .card .jd-projectmeta-lijst li a:focus-visible,
  .card .card-action a:focus-visible,
  .chip:focus-visible,
  .collapsible-header:focus-visible { outline-color: var(--jd-accent); }

  /* De pil met focus. In de lichte modus gaat hij van licht naar donker; hier
     moet het andersom, want de chip staat in rust al op een donker vlak.
     Gemeten: met #3949ab was het verschil tussen rust en focus 1,59:1 -- je zag
     het nauwelijks. Met --jd-accent, dezelfde kleur als de focusring elders in
     deze modus, is dat 6,25:1, en de donkere tekst erop 6,74:1. */
  .post_tags a:focus-visible .chip,
  .jd-toollijst a:focus-visible .chip { background-color: var(--jd-accent); color: #1a237e; }
  .pagination li.active a, .pagination li.active a:focus { background-color: #3949ab; }
  .pagination li.active a:hover { background-color: #4d5cc4; }
  .pagination li.disabled a, .pagination li.disabled a:hover, .pagination li.disabled a:focus { color: rgba(223, 225, 240, 0.32); }

  /* Formuliervelden: het label en de onderlijn waren #1a237e. */
  /* De browser geeft <input> in donkere modus een eigen grijs vlak (rgb(59,59,59))
     en <textarea> niet, waardoor vier velden een blok kregen en het vijfde niet.
     Het ontwerp heeft transparante velden met alleen een onderlijn. */
  input:not([type]):not(.browser-default),
  input[type=text]:not(.browser-default),
  input[type=email]:not(.browser-default),
  input[type=tel]:not(.browser-default),
  input[type=url]:not(.browser-default),
  textarea.materialize-textarea { color: var(--jd-text); background-color: transparent; }
  .input-field label { color: var(--jd-text-muted); }
  input:not([type]):not(.browser-default):focus:not([readonly]) + label,
  input[type=text]:not(.browser-default):focus:not([readonly]) + label,
  input[type=email]:not(.browser-default):focus:not([readonly]) + label,
  input[type=tel]:not(.browser-default):focus:not([readonly]) + label,
  input[type=url]:not(.browser-default):focus:not([readonly]) + label,
  textarea.materialize-textarea:focus:not([readonly]) + label,
  .input-field .prefix.active { color: var(--jd-accent); }
  input:not([type]):not(.browser-default):focus:not([readonly]),
  input[type=text]:not(.browser-default):focus:not([readonly]),
  input[type=email]:not(.browser-default):focus:not([readonly]),
  input[type=tel]:not(.browser-default):focus:not([readonly]),
  input[type=url]:not(.browser-default):focus:not([readonly]),
  textarea.materialize-textarea:focus:not([readonly]) {
    border-bottom: 1px solid var(--jd-accent);
    -webkit-box-shadow: 0 1px 0 0 var(--jd-accent);
    box-shadow: 0 1px 0 0 var(--jd-accent);
  }

  /* Zoekveld. In de lichte modus is dat een wit vlak, wat hier als een lamp in
     de donkere balk staat. De regels hierboven raken het niet: die noemen elk
     type apart op en type=search staat er niet bij. */
  .jd-zoekformulier input[type="search"] {
    background-color: var(--jd-surface);
    border: 1px solid rgba(170, 180, 255, 0.32);
    color: var(--jd-text);
  }
  .jd-zoekformulier input[type="search"]::placeholder { color: var(--jd-text-muted); }
  .jd-zoek-opnieuw .jd-zoekformulier input[type="search"] { border-color: rgba(170, 180, 255, 0.32); }

  /* De rollenlijst bij Lindenhaeghe. #c5cae9 en #5c6bc0 uit de lichte modus zijn
     hier veel te hard; dezelfde gedempte lijnkleur als de invoervelden hierboven
     houdt de tijdlijn een hulplijn in plaats van een streep die de aandacht pakt.
     De open stip krijgt de kaartachtergrond als vulling, zodat hij hol blijft
     lezen in plaats van als een wit vlekje op donker. */
  .jd-rollen { border-left-color: rgba(170, 180, 255, 0.32); }
  .jd-rollen > li::before { background-color: var(--jd-surface); border-color: var(--jd-accent); }
  .jd-rollen > li.jd-nu::before { background-color: var(--jd-accent); border-color: var(--jd-accent); }

  /* Het lijnenpatroon hoort bij de site, maar pattern-wit.svg is wit op 40%
     dekking en licht op een donkere achtergrond te fel op. pattern-indigo.svg
     is hetzelfde patroon in #283593 en geeft dezelfde textuur, gedempt. */
  html, body:not(.home), .aside { background-image: url('images/pattern-indigo.svg'); }

  .content .aside { border-color: var(--jd-line); }

  /* De categorietegels krijgen hier dezelfde ladder, doorgerekend naar donker.
     Eerder stond hier de afweging dat die tegels merkkleur waren en dus mochten
     blijven staan; dat ging op zolang het losse felle kleuren waren die overal
     hetzelfde bedoeld waren. Nu het een indigo-ladder is die het thema volgt,
     hoort hij ook de donkere modus te volgen -- anders krijg je op een klein
     scherm acht lichte vlakken tegen een donkere pagina.

     Dezelfde acht stappen, van #171a2b naar #2b3154. */
  :root {
    --jd-tegel-1: #171a2b;
    --jd-tegel-2: #1a1d31;
    --jd-tegel-3: #1d2036;
    --jd-tegel-4: #1f243c;
    --jd-tegel-5: #222742;
    --jd-tegel-6: #252a48;
    --jd-tegel-7: #282e4e;
    --jd-tegel-8: #2b3154;
  }

  /* De knop moet hier omkeren, en dat is geen smaakkwestie. In donkere modus is
     de knop #3949ab, en tegen een donkere tegel komt die niet boven 2,4:1 uit:
     twee donkere kleuren halen door de manier waarop contrast wordt berekend
     nooit de 3:1 van WCAG 1.4.11, hoe donker je de tegel ook maakt. Material
     lost dat in donkere thema's op door primary licht te maken en de tekst
     donker, en die twee kleuren staan al in de tokens hierboven als
     --md-sys-color-primary-dark en -on-primary-dark. Zo komt de knop op 6,4 tot
     8,8:1 tegen de tegel en de tekst op 6,7:1 tegen de knop. */
  .content .aside div span.btn {
    background-color: var(--jd-accent) !important;
    color: var(--md-sys-color-on-primary-dark) !important;
  }
}

/* ==========================================================================
   REACTIE OP DE MUISPOSITIE                                    (verwijderbaar)
   ==========================================================================
   Twee losse effecten, elk met een eigen JavaScript-bestand en een eigen klasse.
   Ze staan hier bij elkaar omdat ze bij elkaar horen, maar ze werken onafhankelijk:

     .jd-interactief  -> js/interactie.js   (de categorietegels)
     .jd-shader       -> js/achtergrond.js  (de levende achtergrond)

   WEGHALEN: schrap de bijbehorende enqueue-regel in functions.php. Die klasse wordt
   dan nooit gezet en de regels hieronder doen niets meer. Beide klassen worden pas
   gezet als het effect ook echt kan draaien -- .jd-shader zelfs pas nadat WebGL is
   opgestart, zodat een machine zonder WebGL gewoon het SVG-patroon houdt. */

/* --- De levende achtergrond ---------------------------------------------- */

/* body moet een eigen stapelcontext worden, anders is het doek hieronder onzichtbaar.
   Zonder isolation valt een kind met z-index: -1 buiten body's eigen laag en tekent
   de browser de achtergrondkleur van body er overheen -- getest met een knalrood
   vlak: dat was niet te zien. Met isolation tekent body eerst zijn achtergrond, dan
   de negatieve laag, dan pas de inhoud.

   Dit raakt de stapeling van de balk (995), de overlay (997) en het uitschuifmenu
   (100000) niet: die zitten allemaal binnen body en houden onderling dezelfde volgorde. */
.jd-shader body { isolation: isolate; }

/* Achter .jd-shader, net als alle andere regels hier. Raakt de GPU-context kwijt,
   dan haalt het script die klasse eraf en moet het doek meteen weg zijn -- anders
   blijft een schermvullend canvas met het laatste, bevroren beeld hangen. Dat het
   in de praktijk toch verdween kwam alleen doordat `isolation: isolate` hierboven
   tegelijk wegviel, waardoor z-index: -1 achter de achtergrond van body verdwijnt.
   Dat is een indirect gevolg om niet op te leunen.

   Het canvas draagt zijn eigen breedte en hoogte als attribuut -- 2040x1275 op een
   scherm van 1440 -- dus zonder position: fixed zou het als gewoon blok bovenaan de
   pagina komen te staan en alles wegduwen. Daarom eerst uit, en pas aan zodra de
   klasse er staat. */
.jd-doek { display: none; }

.jd-shader .jd-doek {
  display: block;
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: -1;
  pointer-events: none;
}

/* Het SVG-patroon gaat uit zodra de shader draait, anders liggen er twee patronen
   over elkaar. Dit staat bewust achter .jd-shader en niet in het script: gaat er
   iets mis bij het opstarten van WebGL, dan wordt die klasse nooit gezet en blijft
   het patroon staan. Hetzelfde geldt als de GPU-context verloren gaat -- het script
   haalt de klasse er dan weer af.

   Dat geldt ook voor de tegels op de startpagina, en dat is geen vergissing: hun
   patroon gaat er juist af omdat de ::before-laag verderop met mix-blend-mode het
   doek dwárs door de tegel heen laat zien. Een eigen patroon zou daar bovenop een
   tweede laag lijnen geven. Haal je die blend-aanpak ooit weg, haal .aside dan uit
   deze regel -- anders houd je tegels zonder enig patroon over.

   WAAROM DIT ACHTER EEN MEDIA QUERY STAAT
   Zet iemand ná het laden 'beweging verminderen' aan, dan verbergt het vangnet
   onderaan dit bestand het doek. Zonder deze query bleef het patroon dan óók uit en
   hield je een kale achtergrond over. Het terugzetten daar liep telkens mis -- eerst
   met revert-layer, dat zonder @layer doorvalt naar de browserstandaard none; daarna
   met een custom property, waarin een relatieve url() niet vanaf deze stylesheet maar
   vanaf de pagina-URL wordt opgelost en dus een 404 gaf. Niets terugzetten is beter:
   dan hoeft dit patroon alleen niet uitgezet te worden, en blijven licht en donker
   hierboven vanzelf kloppen.

   `not all and` in plaats van het kortere `not (...)`: een browser die deze voorkeur
   helemaal niet kent leest dit nog steeds goed en zet het patroon dus gewoon uit. */
@media not all and (prefers-reduced-motion: reduce) {
  .jd-shader,
  .jd-shader body,
  .jd-shader .aside { background-image: none; }
}

/* --- De categorietegels --------------------------------------------------- */

/* Op de binnenste div en niet op .aside zelf: die tegel schildert het lijnenpatroon
   met background-attachment: fixed, en een transform daarop maakt van het element
   het referentiekader voor zijn eigen achtergrond -- precies de bug die het patroon
   eerder liet verspringen. De div eronder heeft geen eigen achtergrond en is veilig;
   het thema gebruikt hem om dezelfde reden al voor de tikreactie. */
.jd-interactief .content .aside > div {
  transform: translate3d(var(--jd-tx, 0px), var(--jd-ty, 0px), 0) scale(var(--jd-schaal, 1));
  will-change: transform;
}

/* De bestaande hover- en tiktoestanden moeten blijven werken. Het thema laat een
   tegel vanaf 993px bij hover naar 1,5x schalen en bij aantikken naar 0,96. Die
   regels staan eerder in dit bestand en wegen even zwaar als de regel hierboven,
   dus zonder deze twee zou de nabijheidstransform ze allebei overschrijven -- en
   dat is precies wat er gebeurde: het hover-effect op de tegels was weg.

   De twee vermenigvuldigen nu in plaats van elkaar te verdringen. Bij hover staat
   de cursor per definitie vlakbij, dus de nabijheidsfactor loopt er soepel in over. */
.jd-interactief .content .aside:hover > div,
.jd-interactief .content .aside.current > div {
  transform: translate3d(var(--jd-tx, 0px), var(--jd-ty, 0px), 0) scale(calc(var(--jd-schaal, 1) * 1.5));
}
.jd-interactief .content .aside:active > div {
  transform: translate3d(var(--jd-tx, 0px), var(--jd-ty, 0px), 0) scale(calc(var(--jd-schaal, 1) * .96));
}

/* DE TEGELKLEUR TINT DE LIJNEN IN PLAATS VAN ZE AF TE DEKKEN

   Eerst dekte de hoverkleur het effect volledig af; daarna maakte ik hem doorzichtig,
   maar dan komt er hooguit een derde van de lijnen doorheen en blijft het flauw.
   Vóór de shader lag het patroon gewoon óp de tegel, op volle sterkte -- dat is wat
   hier terugkomt.

   De kleur zit nu in een ::before-laag met mix-blend-mode. Die vermengt zich met wat
   eronder ligt in plaats van het te bedekken, dus de hoogtelijnen lopen zichtbaar door
   de tegel heen. Omdat body een eigen stapelcontext heeft (isolation hierboven) hoort
   het doek bij die vermenging.

   Op licht multiply: de tegelkleur donkert de ondergrond, de lichte lijnen blijven
   erbovenuit steken. Op donker screen: daar zijn de tegelkleuren juist donkerder dan
   het patroon en zou multiply alles wegdrukken.

   De inhoud staat op z-index 1 zodat de knoptekst niet meevermengt. */
.jd-shader .content .aside { position: relative; }
.jd-shader .content .aside > div { position: relative; z-index: 1; }

.jd-shader .content .aside::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 0;
  opacity: 1;
  transition: opacity .25s linear;
  mix-blend-mode: multiply;
}

.jd-shader .content .aside-1::before { background-color: var(--jd-tegel-1); }
.jd-shader .content .aside-2::before { background-color: var(--jd-tegel-2); }
.jd-shader .content .aside-3::before { background-color: var(--jd-tegel-3); }
.jd-shader .content .aside-4::before { background-color: var(--jd-tegel-4); }
.jd-shader .content .aside-5::before { background-color: var(--jd-tegel-5); }
.jd-shader .content .aside-6::before { background-color: var(--jd-tegel-6); }
.jd-shader .content .aside-7::before { background-color: var(--jd-tegel-7); }
.jd-shader .content .aside-8::before { background-color: var(--jd-tegel-8); }

/* De eigen achtergrondkleur van de tegel gaat eruit; de laag hierboven neemt hem over.
   Vier klassen diep, zodat dit zwaarder weegt dan de hoverregels eerder in dit bestand. */
.jd-shader .content .aside,
.jd-shader .content .aside:hover,
.jd-shader .content .aside.current { background-color: transparent; }

/* Vanaf 993px is de tegel in rust kleurloos en komt de kleur pas bij hover -- precies
   zoals het thema het al deed. Daaronder staat de kleur er altijd, en dan is de laag
   hierboven dus meteen zichtbaar. */
@media only screen and (min-width: 993px) {
  .jd-shader .content .aside::before { opacity: 0; }
  .jd-shader .content .aside:hover::before,
  .jd-shader .content .aside.current::before { opacity: 1; }
}

@media (prefers-color-scheme: dark) {
  .jd-shader .content .aside::before { mix-blend-mode: screen; }
}

/* --- Vangnetten ----------------------------------------------------------- */

/* Beide scripts kijken hier zelf al naar en starten dan niet eens, maar verandert
   iemand die voorkeur ná het laden, dan valt alles hiermee alsnog stil. */
/* Hier stond ook `background-image: revert-layer`, om het SVG-patroon terug te halen
   zodra het doek verdwijnt. Dat deed het omgekeerde: revert-layer valt terug op de
   vorige cascadelaag, dit bestand kent geen enkele @layer, en dus viel het door tot de
   browserstandaard -- none. Gemeten met een testregel in de console: 'revert-layer
   resultaat: none'. Samen met display:none op het doek bleef er dan helemaal geen
   achtergrond over, precies het geval waarvoor dit vangnet is geschreven.

   Terugzetten hoeft nu niet meer: de regel die het patroon uitzet staat zelf achter
   `not all and (prefers-reduced-motion: reduce)` en geldt hier dus gewoon niet. */
@media (prefers-reduced-motion: reduce) {
  .jd-shader .jd-doek { display: none; }
  .jd-interactief .content .aside > div,
  .jd-interactief .content .aside:active > div { transform: none; }
}

/* --- Het afstelpaneel voor de achtergrond --------------------------------- *
   De opmaak daarvan stond hier. Die is verhuisd naar js/achtergrond-paneel.js, dat
   zijn eigen CSS meebrengt: het paneel is gereedschap voor de beheerder en hoort niet
   in de stylesheet die elke bezoeker ophaalt. Dat bestand laadt alleen als je
   ingelogd bent en ?shader achter de URL zet -- zie functions.php.               */
