/* ds-componenten.css — GEGENEREERD door design/system/onderdelen/bouw.py.
   Verander dit bestand niet met de hand; verander de css in de map van het onderdeel.

   Elk onderdeel staat in design/system/onderdelen/ds/<naam>/ met zijn macro, zijn stijl,
   zijn toelichting en zijn toets. Dit bestand is alleen de volgorde.
*/

/* === actiebalk === */
/* Actiebalk. De vastgezette balk onderaan een flowscherm.
 *
 * Canoniek: design/system/css/site.css:730 (.ev-voet, position fixed, z-index 20).
 *
 * Twee dingen zijn hier anders dan vandaag, allebei een reparatie:
 *
 * 1. DE ONDERRUIMTE IS EEN SOM EN GEEN METING. Vandaag rekent base.html de hoogte van de balk
 *    in de browser uit en zet hem als --ev-voet-h; die meting hangt aan een MutationObserver
 *    en niet aan het laden van de letters, en levert vijf verschillende onderruimtes op voor
 *    dezelfde kolom: 24, 94, 171, 173 en 190px. Dat zijn vijf vingerafdrukken van een ding en
 *    daarmee komt een drifttoets nooit op nul. actiebalk.onderruimte is de som uit de tokens
 *    die de balk vullen: een knop van maat.raakvlak met space.kop-tekst erboven en eronder,
 *    plus space.afsluiting.
 * 2. DE SCHEIDING IS GEEN LIJN. De balk zet zich vandaag van de pagina af met een lijn van
 *    1,150:1, die de regel van tokens.css breekt en tegelijk niet te zien is. In plaats
 *    daarvan color.surface.page met elevation.raised: het vlak scheidt, zoals overal in dit
 *    systeem.
 *
 * De kolom erboven houdt actiebalk.onderruimte vrij. Dat is werk van de schil en niet van dit
 * bestand, want een component hoort niet in de opmaak van een ander te schrijven; het token
 * staat er en het sjabloon van fase 4b gebruikt hem.
 */

@layer patronen {
  /* De balk dekt bij Tab het element met focus af. Deze regel hangt aan de aanwezigheid van de
     balk, zodat een scherm zonder Actiebalk er ook geen ruimte voor vrijhoudt. */
  html:has(.ds-actiebalk) { scroll-padding-block-end: var(--ds-actiebalk-onderruimte); }

  /* fixed en niet sticky: een sticky element schuift mee met het terugveren van de pagina aan
     het begin en het einde, en dat was de onrust die op 10 september 2026 gemeten werd. */
  .ds-actiebalk {
    position: fixed;
    inset-inline: 0;
    inset-block-end: 0;
    z-index: var(--ds-layer-overlay);
    background: var(--ds-color-surface-page);
    box-shadow: var(--ds-elevation-raised);
  }

  .ds-actiebalk__in {
    display: flex;
    flex-direction: column;
    gap: var(--ds-space-tussen);
    max-inline-size: var(--ds-maat-kolom);
    margin-inline: auto;
    padding-block: var(--ds-space-binnen-blok);
    padding-inline: var(--ds-space-blok);
  }
  /* 900px is --ds-breekpunt-breed; een mediavraag kan geen custom property lezen, dus het getal staat hier letterlijk. Strikt groter dan en niet vanaf: Modern Delft zet zijn smalle waarden in `@media (max-width: 900px)`, dus op precies 900px is het merk smal. Met `min-width: 900px` was het systeem daar breed en het merk smal, en dat verschil van een pixel viel nergens op omdat geen enkele meting op de rand zelf keek. */
  @media (width > 900px) {
    .ds-actiebalk__in { max-inline-size: var(--ds-maat-kolom-breed); }
  }

  /* De knoppen breken af in plaats van de balk breder te maken. Op 320px is dat het verschil
     tussen twee knoppen onder elkaar en een knop die half buiten beeld staat. */
  .ds-actiebalk__knoppen {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--ds-space-binnen-blok);
  }

  .ds-actiebalk__fijndruk {
    margin: 0;
    max-inline-size: var(--ds-maat-regel);
    color: var(--ds-color-text-muted);
    font: var(--ds-type-fijn);
  }

  /* bezig is een echt attribuut en geen klasse. De knop in de balk draagt zijn eigen
     bezig-stand; dit is wat de balk eromheen ervan laat zien. */
  .ds-actiebalk[aria-busy='true'] { cursor: progress; }
}

/* === alleenvoorlezen === */
/* AlleenVoorlezen. Tekst die alleen voor een schermlezer bestaat.
 *
 * Canoniek: de bestaande verbergklasse uit pipeline/templates/site/vier.html:66, met zijn regel in
 * design/system/css/site.css:978.
 *
 * Er staat hier geen enkele kleur, geen letter en geen maat, en dat is het hele punt: wat hier in
 * staat is niet te zien en verandert dus nooit iets aan de pagina.
 *
 * Wat er anders is dan de canonieke regel. Die zet het element op left: -9999px. Dat werkt, maar
 * het is een plek buiten de pagina en geen verborgen doos: in een rechts-naar-links leesrichting
 * valt hij aan de verkeerde kant naar buiten en trekt hij de pagina breder. De vorm hieronder
 * houdt het element op zijn eigen plek in de leesvolgorde en knipt hem weg. De maten 1px en -1px
 * zijn geen ontwerpwaarden en er bestaat geen token voor: ze zijn de kleinste doos die een
 * schermlezer nog meeneemt.
 *
 * Wat hier met opzet NIET staat: display: none en visibility: hidden. Die twee halen het element
 * ook uit de toegankelijkheidsboom, en dan leest niemand het meer.
 */

@layer componenten {
  .ds-alleenvoorlezen {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
  }
}

/* === band === */
/* Band. De rasterband, en het enige onderdeel dat op alle vijf de oppervlakken staat.
 *
 * Canoniek: design/system/css/tokens.css:170-190 voor de drie schermdichtheden en :214-243 voor
 * de drukuitvoering.
 *
 * De meetkunde. De band haalt zijn hoogte uit zijn breedte: de steek is de breedte gedeeld door
 * het aantal kolommen, en de hoogte volgt uit het aantal rijen. Toen die meetkunde eerder alleen
 * op de basisklasse stond, hadden zes banden in het boek een hoogte van nul; daarom staat hij hier
 * op de basis en erven alle vier de dichtheden hem.
 *
 * De dichtheden verschillen alleen in bolgrootte. De steek zit in het kolomaantal dat het
 * oppervlak zet, want alleen daar is de breedte bekend.
 *
 * De kleur komt van de grond en niet van de dichtheid. Op papier is de stip color.mark (3,806),
 * op het inktvlak color.mark.on-ink (6,417). Het omhullende vlak zet die keuze door in de
 * plaatselijke variabele --band-stip; zonder omhulling geldt papier.
 *
 * De gedrukte band is tekst en geen tekening. Tot 9 september 2026 was dit een verloop, en
 * Chromium rastert zo'n herhaalde achtergrond naar een bitmap: de stippen kregen zachte, ongelijke
 * randen en drukten vaag, en geen inktwaarde repareerde dat. Een letterteken is een vectorvorm in
 * de pdf en drukt scherp op elke resolutie. De maten hieronder zijn gemeten op het teken zelf: het
 * bolletje draagt 0,251 em inkt op een advance van 0,609 em, de steek is 2,667mm, en daaruit volgt
 * korps 4,15mm, advance 2,53mm en spatiëring 0,14mm. De 0,1775mm is de gemeten correctie: met
 * 0,14mm meten 51 bolletjes 134,09mm op een kolom van 136mm.
 */

@layer componenten {
  .ds-band {
    /* Elk oppervlak mag zijn eigen kolomaantal zetten; zonder dat geldt het token. */
    --band-kol: var(--band-kolommen, var(--ds-band-kolommen));
    --band-rij: var(--band-rijen, 3);
    flex: none;
    inline-size: 100%;
    aspect-ratio: var(--band-kol) / var(--band-rij);
    background-repeat: repeat;
    background-position: 0 0;
    background-size: calc(100% / var(--band-kol)) calc(100% / var(--band-rij));
  }

  /* De bolgroottes staan als getal en niet als token: er bestaat geen token voor een bolradius en
     het voorstel voegt er geen toe. De drie waarden komen woordelijk uit tokens.css:181-187. */
  .ds-band--los {
    background-image: radial-gradient(var(--band-stip, var(--ds-color-mark)) 2.6px, transparent 2.7px);
  }
  .ds-band--midden {
    background-image: radial-gradient(var(--band-stip, var(--ds-color-mark)) 1.7px, transparent 1.8px);
  }
  .ds-band--dicht {
    background-image: radial-gradient(var(--band-stip, var(--ds-color-mark)) 1.6px, transparent 1.7px);
  }

  /* druk: een letterteken in plaats van een verloop. Het aantal bolletjes staat in de html, want
     Chromium neemt het klippen van deze doos niet mee naar de pdf. */
  .ds-band--druk {
    background-image: none;
    overflow: hidden;
    font-family: var(--ds-band-letter);
    font-size: 4.15mm;
    line-height: 2.667mm;
    letter-spacing: 0.1775mm;
    color: var(--ds-color-print-mark);
    word-break: break-all;
    text-indent: 0;
  }

  /* De spatiëring staat ook achter het laatste teken van een regel, dus 51 bolletjes vragen
     136,017mm op een kolom van 136mm en viel de 51e om: op een band van drie regels ontbrak de
     hele rechterkolom. Een vijfde millimeter extra ruimte rechts lost dat op zonder aan de steek
     te komen; de band zelf blijft even breed, want de marge valt buiten de doos. */
  .ds-band__stippen { margin-inline-end: -0.2mm; }
}

/* === beeld === */
/* Beeld. Een afbeelding met vaste afmetingen en een optioneel onderschrift.
 *
 * Canoniek: etalage/index.html:145 (27d5eb9f9ed0, 440 gewogen) voor de kolomvorm, en
 * design/system/css/site.css:306-310 (de akte) voor de kadervorm.
 *
 * Drie dingen die hier anders zijn dan vandaag:
 *
 * 1. De verhouding staat in de stijl en niet in de hoop. Het onderdeel zet aspect-ratio uit de
 *    breedte en de hoogte die de macro afdwingt, dus de doos heeft zijn maat voordat het bestand
 *    binnen is. De scan op flow/hoofdstuk is vandaag 2px hoog tot hij binnen is en 503px daarna,
 *    goed voor een CLS van 0,320 op dat scherm.
 * 2. Het kader gaat van de lichtste inkt (2,984 op drukpapier) naar color.border (5,546).
 * 3. De ruimte die gereserveerd is, is ook te zien: de doos draagt de tint tot het bestand
 *    geverfd is. Dat is de toestand laden, en hij gaat vanzelf weg.
 */

@layer componenten {
  .ds-beeld {
    display: block;
    margin: 0;
  }

  .ds-beeld__foto {
    display: block;
    inline-size: 100%;
    max-inline-size: 100%;
    block-size: auto;
    /* De verhouding komt uit de props en staat als plaatselijke variabele op het element zelf.
       Zonder waarde valt hij terug op de maat die de breedte- en hoogteattributen geven. */
    aspect-ratio: var(--beeld-verhouding, auto);
    /* Toestand laden: de gereserveerde doos draagt wit tot de browser het bestand verft. Modern
       Delft zet elk beeld op wit (de tegel, het blad, de aktekaart), dus de doos eronder ook.
       Op papier is wit 1,09 en dus vrijwel onzichtbaar; dat is hier goed, want deze doos is
       alleen tijdens het laden leeg en daarna vult het beeld hem. Waar een doos ook leeg kan
       BLIJVEN, zoals het beeldvlak van een Kaart, staat er wel een haarlijn omheen. */
    background-color: var(--ds-color-surface-raised);
  }

  /* kolom: binnen de leeskolom, de gewone vorm. */
  .ds-beeld--kolom { margin-inline: 0; }

  /* volle-breedte: het beeld breekt door de goot van de kolom heen, alleen in het openingsslot.
     De goot is space.blok en dat is precies wat hier wordt teruggenomen. */
  .ds-beeld--volle-breedte { margin-inline: calc(-1 * var(--ds-space-blok)); }
  .ds-beeld--volle-breedte .ds-beeld__onderschrift { padding-inline: var(--ds-space-blok); }

  /* kader: de scan. Een haarlijn in color.border, op de paginagrond, zodat een licht papier op
     een licht papier nog een begrenzing heeft. */
  .ds-beeld--kader .ds-beeld__foto {
    border: var(--ds-border-hairline) solid var(--ds-color-border);
    background-color: var(--ds-color-surface-page);
  }

  /* Het onderschrift is de bronregel onder een beeld: type.fijn en tekst.muted, de twee tokens
     die deze rol met zoveel woorden dragen. */
  .ds-beeld__onderschrift {
    margin-block-start: var(--ds-space-binnen-blok);
    font: var(--ds-type-fijn);
    color: var(--ds-color-text-muted);
    max-inline-size: var(--ds-maat-regel);
  }
}

/* === bladerband === */
/* Bladerband. De horizontale band met bladzijden uit het boek, met twee pijlen en stippen.
 *
 * Canoniek: web/publiek/sjablonen/voorouderboek.html:71 en voorpagina.html:78 met
 * etalage/js/bladeren.js en publiek.css:496-505. De wrapper, de twee pijlknoppen, hun svg-paden
 * en hun aria-labels staan woord voor woord gelijk op die twee pagina's (B114).
 *
 * Drie dingen die hier anders zijn dan vandaag:
 *
 * 1. De pijl gaat nooit op opacity 0 en verdwijnt nooit uit de tabvolgorde. Vandaag zet hij
 *    zichzelf uit terwijl hij de focus draagt (publiek.css:505), dus de focus valt in het niets.
 *    Aan het begin en aan het eind draagt hij aria-disabled, blijft hij staan en blijft hij
 *    bereikbaar.
 * 2. Het raakdoel van de pijl staat hier en niet in de binnenruimte, dus hij kan zijn 44px niet
 *    verliezen.
 * 3. Het schuifgebied draagt het contract van Schuifbak: een eigen schuifas, tabindex en een
 *    naam. Vier van de 41 serious-meldingen staan vandaag op .ev-bladen__spoor.
 *
 * De plaatsing komt van Rij. Wat dit blad zelf schrijft gaat over schuiven, en daar gaat dit
 * onderdeel zelf over.
 */

@layer componenten {
  .ds-bladerband {
    display: block;
  }

  .ds-bladerband__spoor {
    overflow-x: auto;
    overflow-y: hidden;
    overscroll-behavior-inline: contain;
    scroll-snap-type: inline mandatory;
    /* Zacht schuiven hangt aan motion.state en verdwijnt onder prefers-reduced-motion; die
       regel staat een keer in ds-basis.css en niet hier. Het script leest deze eigenschap voor
       de duur van zijn eigen schuifbeweging, zodat er maar een waarde is. */
    scroll-behavior: smooth;
    --bladerband-schuifduur: var(--ds-motion-state);
  }

  .ds-bladerband__blad {
    flex: 0 0 auto;
    scroll-snap-align: start;
  }

  .ds-bladerband__bediening {
    justify-content: center;
    margin-block-start: var(--ds-space-binnen-blok);
  }

  /* Het raakdoel staat in deze laag en niet in de binnenruimte, dus de pijl kan zijn 44px niet
     verliezen. */
  .ds-bladerband__pijl {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-block-size: var(--ds-maat-raakvlak);
    min-inline-size: var(--ds-maat-raakvlak);
    border-radius: var(--ds-radius-control);
    color: var(--ds-color-text-default);
    cursor: pointer;
    transition: background-color var(--ds-motion-feedback);
  }
  .ds-bladerband__pijl:hover {
    background: var(--ds-color-surface-sunken);
  }

  /* Aan het begin en aan het eind. Geen opacity, geen display none, geen disabled: de pijl
     blijft staan, blijft bereikbaar en zegt alleen dat hij niets meer doet. Kleur draagt de
     betekenis niet alleen, want de zweefstand valt er ook af. */
  .ds-bladerband__pijl[aria-disabled='true'] {
    color: var(--ds-color-text-muted);
    cursor: default;
  }
  .ds-bladerband__pijl[aria-disabled='true']:hover {
    background: none;
  }

  .ds-bladerband__stippen {
    display: flex;
    align-items: center;
    gap: var(--ds-space-tussen);
  }

  /* Er is geen maattoken voor een stip. space.tussen is de kleinste stap die er wel is en die
     8px is de gemeten diameter van de bestaande bladerstip (7af51e74). */
  .ds-bladerband__stip {
    inline-size: var(--ds-space-tussen);
    block-size: var(--ds-space-tussen);
    border-radius: var(--ds-radius-pil);
    background: var(--ds-color-border);
  }
  .ds-bladerband__stip--hier {
    background: var(--ds-color-mark);
  }
}

/* === boek === */
/* Boek. Het boek als voorwerp in beeld: een omslag met een rug, een titel en een okeren streep.
 *
 * Canoniek: de merkbron, `bundel/stijl.css` regel 283 tot 299, op de jaargang die het merkspoor
 * op 12 september 2026 stempelde (`origin/ontwerp/modern-delft`, `7ab18dc`, jaargang
 * `423fc022`).
 *
 * DIT ONDERDEEL ONTHULT ZICHZELF NIET, EN DAT IS EEN KEUZE. De merkbron geeft het boek een eigen
 * onthulling: 1100ms met 150ms vertraging, 24px omhoog en `scale(.985)`. Onthuller doet hetzelfde
 * in 900ms zonder vertraging, met 30 of 48px en zonder schaal in zijn schuifvorm. Dat verschil is
 * echt en het is klein, en het systeem heeft al een onthulling.
 *
 * Gekozen: wikkel dit onderdeel in een Onthuller in plaats van hem een derde kopie van wapenen en
 * waarnemen te geven. Een onderdeel dat zijn eigen onthulling meebrengt omdat hij 200ms anders
 * wil, is precies de drift waar dit systeem tegen gebouwd is. Wat het kost staat hierboven
 * gemeten, zodat het terug te draaien is als iemand dat verschil toch wil.
 *
 * HET DRIJVEN IS EEN EIGEN LAAG EN GEEN EIGENSCHAP VAN HET OMSLAG. `__drijf` ligt tussen het
 * kader en het omslag, en `boek.js` verschuift alleen die laag terwijl je scrolt. Zonder script
 * staat het boek stil, en dat is een boek en geen gebrek.
 */

@layer componenten {
  /* Het kader. Hij reserveert zijn hoogte met aspect-ratio, zodat er niets verspringt terwijl de
     omslagfoto laadt. */
  .ds-boek {
    position: relative;
    inline-size: min(100%, var(--ds-boek-maat));
    aspect-ratio: var(--ds-boek-verhouding);
  }

  .ds-boek__drijf {
    position: absolute;
    inset: 0;
  }

  /* De straal is niet rondom gelijk: links waar de rug zit is hij bijna vierkant, rechts waar de
     bladzijden zijn is hij rond. Dat is wat een boek doet. */
  .ds-boek__kaft {
    position: absolute;
    inset: 0;
    overflow: hidden;
    border-start-start-radius: var(--ds-radius-fijn);
    border-start-end-radius: var(--ds-radius-control);
    border-end-end-radius: var(--ds-radius-control);
    border-end-start-radius: var(--ds-radius-fijn);
    background: var(--ds-color-surface-raised);
    box-shadow: var(--ds-elevation-papier);
  }
  .ds-boek__kaft img {
    inline-size: 100%;
    block-size: 100%;
    object-fit: cover;
  }

  /* De rug: een donkere strook die naar rechts uitdooft en het boek dikte geeft. Hij vangt geen
     muis, want er valt niets op te klikken en hij ligt over het omslag heen. */
  .ds-boek__rug {
    position: absolute;
    inset-block: 0;
    inset-inline-start: 0;
    inline-size: var(--ds-boek-rug);
    border-start-start-radius: var(--ds-radius-fijn);
    border-end-start-radius: var(--ds-radius-fijn);
    background: linear-gradient(90deg,
      color-mix(in oklch, var(--ds-color-surface-inverse) 22%, transparent),
      transparent);
    pointer-events: none;
  }

  .ds-boek__titel {
    position: absolute;
    inset-inline: var(--ds-boek-inspringing);
    inset-block-start: 7.5%;
    display: flex;
    flex-direction: column;
    gap: var(--ds-space-inline);
  }

  .ds-boek__reeks {
    font: var(--ds-type-kaft-etiket);
    letter-spacing: var(--ds-type-kaft-etiket-spatiering);
    color: var(--ds-color-text-accent);
  }

  /* `nowrap`, want een titel die over twee regels breekt op een omslag van 200px hoog loopt over
     de tekening heen. Wie een langere titel heeft, heeft een ander omslag nodig. */
  .ds-boek__naam {
    font: var(--ds-type-kaft);
    letter-spacing: var(--ds-type-kaft-spatiering);
    color: var(--ds-color-text-default);
    white-space: nowrap;
  }

  /* De regel eronder schaalt MEE met de kafttitel en staat niet op een vaste maat. Met 11px liep
     hij op een klein omslag over de tekening en brak een plaatsnaam naar een derde regel; dat
     staat zo in de merkbron. Daarom em en geen token: hij is een verhouding tot zijn buurman en
     geen maat op zichzelf. */
  .ds-boek__voor {
    margin-block-start: 0.35em;
    font-size: 0.4em;
    line-height: 1.4;
    color: var(--ds-color-text-body);
    text-wrap: balance;
  }
  .ds-boek__voor b { font-weight: var(--ds-type-nadruk); color: var(--ds-color-text-default); }

  /* De okeren streep onderaan het omslag. Geen Haarlijn: die is een pixel hoog, tekent zichzelf
     en heeft een eigen waarnemer; deze is twee pixels, staat stil en hoort bij dit voorwerp. De
     merkbron gebruikt voor allebei de naam `streep`, en dat is precies waarom het register die
     47 voorkomens verkeerd afbeeldde. */
  .ds-boek__streep {
    position: absolute;
    inset-inline: var(--ds-boek-inspringing);
    inset-block-end: 6%;
    block-size: 2px;
    background: var(--ds-color-mark);
  }

  /* In hoog contrast verdwijnt elke grond en elke schaduw, dus ook de omtrek van het omslag. Een
     rand houdt het boek een boek. */
  @media (forced-colors: active) {
    .ds-boek__kaft { border: var(--ds-border-hairline) solid CanvasText; }
    .ds-boek__streep { background: CanvasText; }
  }
}

/* === brontag === */
/* Brontag. De verwijzing achter een feitzin, met zijn peildatum erbij.
 *
 * Geen canonieke bron in de gemeten stijlbladen: dit onderdeel bestond niet. De namensessie liep
 * op 13 september 2026 alle 48 onderdelen na en vond niets dat deze rol draagt, en het staat
 * sindsdien in design/system/register.py als gevraagd buiten de meting.
 *
 * DE ROL IS EEN VOETNOOT EN GEEN MEDEDELING, dus type.code en color.text.muted: een lezer die
 * de zin leest moet er niet over struikelen, en een lezer die de bron wil zien moet hem vinden.
 * Daarom mono en niet gedempte broodtekst: de query is machinetekst en leest als machinetekst.
 *
 * DE TWEE VORMEN VERSCHILLEN IN VORM EN NIET ALLEEN IN KLEUR. Een record is een link en draagt
 * een streep; een telling is geen link en draagt er geen. Wie ze alleen op kleur zou scheiden,
 * zet het verschil tussen "hier kun je klikken" en "hier niet" in iets dat een deel van de
 * lezers niet ziet.
 *
 * Wat dit bestand NIET kan zien: de grond. color.text.muted haalt 5,181 op papier en 4,507 op de
 * tint, en op color.surface.warm 4,285, dus daar staat hij niet. Die regel hangt aan Vlak en
 * staat in brontag.md.
 *
 * De focusring staat hier niet. Hij staat een keer in ds-basis.css op :focus-visible.
 */

@layer componenten {
  .ds-brontag {
    font: var(--ds-type-code);
    color: var(--ds-color-text-muted);
    /* Hij hoort bij de zin ervoor en niet bij de regel eronder, dus hij breekt niet los van
       zijn zin. De query zelf mag wel breken; zie __wat hieronder. */
    white-space: nowrap;
  }

  /* De query of de akte. Dit is het enige stuk dat lang kan worden, dus hier mag de regel wel
     afbreken: een query van tachtig tekens die niet breekt, duwt de hele kolom open en dat is
     precies de horizontale overloop waar de poort op weegt. */
  .ds-brontag__wat {
    white-space: normal;
    overflow-wrap: anywhere;
  }

  /* De datum breekt nooit van zijn getal los: "13 september" op de ene regel en "2026" op de
     volgende is een datum die twee dingen lijkt. */
  .ds-brontag__datum { white-space: nowrap; }

  /* Een record wijst naar een akte, dus hij is een link en ziet er ook zo uit. Dezelfde streep
     als Link met vorm tekst, en om dezelfde reden: zonder streep is een link in een alinea
     alleen aan zijn kleur te herkennen. */
  .ds-brontag--record {
    text-decoration: underline;
    text-decoration-color: var(--ds-color-border-subtle);
    text-decoration-thickness: var(--ds-border-hairline);
    text-underline-offset: var(--ds-link-streep-afstand);
  }

  .ds-brontag--record:visited { color: var(--ds-color-text-muted); }

  .ds-brontag--record:hover {
    color: var(--ds-color-text-accent);
    text-decoration-color: currentColor;
  }
}

/* === cijferrij === */
/* Cijferrij. Een rij getallen met hun bijschrift eronder: wat er gevonden is.
 *
 * Canoniek: de merkbron, `bundel/stijl.css` regel 379 tot 382 (`.telling`) en 545 tot 547
 * (`.cijfer-een`), op de jaargang die het merkspoor op 12 september 2026 stempelde
 * (`origin/ontwerp/modern-delft`, `7ab18dc`, jaargang `423fc022`).
 *
 * TWEE PLEKKEN IN DE MERKBRON EN EEN ONDERDEEL HIER. `.telling` staat vrij op een scherm
 * (Archivo 800 in oker, `--t-getal`, met ruimte van 48px ertussen) en `.cijfer-een` staat in de
 * cijferstrook van de flowkaart (Archivo 800 in diep, `--t-getal-strook`, zonder ruimte maar met
 * een scheidingslijn). Dat is hetzelfde ding op twee maten en met twee gronden, dus het is een
 * onderdeel met twee vormen en niet twee onderdelen.
 *
 * DE SCHEIDING TUSSEN TWEE CIJFERS IS EEN LIJN EN GEEN RUIMTE, in de strookvorm. Daarom staat
 * het gat daar op nul: haal je de lijn weg, dan raken de cijfers elkaar, en dat is precies wat
 * je wilt zien als iemand die lijn ooit weghaalt. De lijn draagt `color.border.on-sunken`, want
 * `border.subtle` is de haarlijn op papier en die valt weg op het getinte vlak van die strook;
 * die reden staat in de merkbron zelf.
 */

@layer componenten {
  .ds-cijferrij {
    display: flex;
    flex-wrap: wrap;
    align-items: stretch;
    gap: var(--ds-cijferrij-ruimte);
    margin: 0;
    padding: 0;
    list-style: none;
  }

  .ds-cijferrij__een {
    display: flex;
    flex-direction: column;
    gap: var(--ds-space-inline);
  }

  .ds-cijferrij__getal {
    font: var(--ds-type-getal);
    letter-spacing: var(--ds-type-getal-spatiering);
    color: var(--ds-color-mark);
    font-variant-numeric: tabular-nums;
  }

  .ds-cijferrij__label {
    font: var(--ds-type-klein);
  }

  /* De strookvorm: kleiner, in inkt, en zonder gat omdat de scheiding een lijn is. */
  .ds-cijferrij--strook {
    gap: 0;
  }
  .ds-cijferrij--strook .ds-cijferrij__een {
    padding-inline: var(--ds-cijferrij-strook-ruimte);
  }
  .ds-cijferrij--strook .ds-cijferrij__een:first-child { padding-inline-start: 0; }
  .ds-cijferrij--strook .ds-cijferrij__een + .ds-cijferrij__een {
    border-inline-start: var(--ds-border-hairline) solid var(--ds-color-border-on-sunken);
  }
  .ds-cijferrij--strook .ds-cijferrij__getal {
    font: var(--ds-type-getal-strook);
    letter-spacing: var(--ds-type-getal-spatiering);
    color: var(--ds-color-text-default);
  }
  .ds-cijferrij--strook .ds-cijferrij__label {
    font: var(--ds-type-fijn);
    color: var(--ds-color-text-default);
  }
  /* Hoogstens twee getallen in oker; de merkbron schrijft dat bij die strook. Welke twee is een
     keuze van de pagina, dus het is een prop en geen selector per kind. */
  .ds-cijferrij--strook .ds-cijferrij__een--gemerkt .ds-cijferrij__getal {
    color: var(--ds-color-mark);
  }

  /* Op een smalle kaart staan ze onder elkaar, met de lijn boven in plaats van opzij. De
     containervraag hangt aan de kaart en niet aan het venster; zie `flowkaart.css` voor waar de
     552 vandaan komt. */
  @container ds-flowkaart (max-width: 552px) {
    .ds-cijferrij--strook { flex-direction: column; }
    .ds-cijferrij--strook .ds-cijferrij__een {
      padding-inline: 0;
      padding-block: var(--ds-space-binnen-blok);
    }
    .ds-cijferrij--strook .ds-cijferrij__een:first-child { padding-block-start: 0; }
    .ds-cijferrij--strook .ds-cijferrij__een:last-child { padding-block-end: 0; }
    .ds-cijferrij--strook .ds-cijferrij__een + .ds-cijferrij__een {
      border-inline-start: 0;
      border-block-start: var(--ds-border-hairline) solid var(--ds-color-border-on-sunken);
    }
  }
}

/* === clusterkaart === */
/* Clusterkaart. Punten op hun eigen plek, met een streek die oplicht.
 *
 * Geen canonieke bron in de gemeten stijlbladen: dit onderdeel bestond niet, en er staat in deze
 * hele repo geen enkele inline svg. Elke svg op de site is tot vandaag een los bestand achter een
 * `<img>`, en een `<img>` kan geen punt oplichten. Dat maakt dit een nieuw patroon en geen
 * variant op een bestaand, en daarom staat het hier uitgeschreven.
 *
 * DE PUNTEN STAAN ALLEMAAL IN DEZELFDE INKT. Er zijn 223 streken; een kleur per streek zou een
 * regenboog zijn waarvan de helft het contrast niet haalt, en het zou de indeling gewichtiger
 * laten lijken dan ze is. Wat kleur krijgt is de GEKOZEN streek, en die krijgt tegelijk een
 * grotere straal en een ring: drie signalen, want kleur alleen zegt niets tegen wie hem niet
 * ziet.
 *
 * DE STRAAL STAAT IN GEBRUIKERSEENHEDEN VAN DE VIEWBOX EN NIET IN PIXELS. De svg schaalt mee met
 * zijn doos, dus een punt van zes eenheden is op een telefoon evenveel waard als op een
 * bureaublad. In pixels zou een punt op 360px een vlek zijn en op 1920px een speldenprik.
 *
 * GEEN OVERGANG OP DE STRAAL. Honderdzevenenvijftig cirkels die tegelijk animeren is werk dat
 * een telefoon merkt, en het levert niets op: de streek moet meteen te zien zijn.
 */

@layer componenten {
  .ds-clusterkaart {
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: var(--ds-space-kop-tekst);
  }

  /* GEEN GROND ONDER DE TEKENING, EN DAT IS GEMETEN EN GEEN SOBERHEID. Hier stond
     `color.surface.sunken` als tint. In de browser komt dat uit op oklch(0.923 0.019 248) en dat
     is blauwig; op de crèmekleurige pagina van dit merk leest het als een vreemd paneel dat er
     overheen ligt. De punten tekenen hun eigen vlak, en een veld eromheen voegt niets toe. */
  .ds-clusterkaart__vlak {
    inline-size: 100%;
    block-size: auto;
  }

  .ds-clusterkaart__punt {
    fill: var(--ds-color-text-muted);
  }

  /* De gekozen streek. Drie dingen tegelijk, en de straal staat hier en niet in het attribuut,
     zodat een punt dat niet gekozen is nooit per ongeluk groot blijft staan. */
  .ds-clusterkaart__punt--op {
    fill: var(--ds-color-text-accent);
    r: 11;
    stroke: var(--ds-color-text-default);
    stroke-width: 2;
  }

  /* Wat NIET in de gekozen streek zit, zakt weg. NIET onzichtbaar, want waar de rest staat is
     juist het punt van de tekening: de vorm van het land komt uit alle punten samen.

     Dit ging eerst met `color.border.subtle` als vulling, en dat is te licht: gemeten in de
     browser bleef er oklch(0.899 0.003 165) over en waren de weggezakte punten praktisch weg.
     Met doorzichtigheid houdt een punt zijn eigen kleur en zijn eigen gewicht, en blijft de
     omtrek staan. */
  .ds-clusterkaart__punt--af {
    opacity: 0.28;
  }

  .ds-clusterkaart__onderschrift {
    font: var(--ds-type-fijn);
    color: var(--ds-color-text-muted);
  }

  /* Bij geforceerde kleuren verdwijnt `fill` uit een stylesheet en houdt het systeem zijn eigen
     palet aan. Dan draagt alleen de straal en de rand nog het verschil, en die blijven staan. */
  @media (forced-colors: active) {
    .ds-clusterkaart__punt {
      fill: CanvasText;
    }
    .ds-clusterkaart__punt--op {
      fill: Highlight;
      stroke: CanvasText;
    }
    .ds-clusterkaart__punt--af {
      fill: GrayText;
      opacity: 1;
    }
  }

  /* Wie beweging liever niet heeft, merkt hier niets: er beweegt niets. Deze regel staat er
     zodat een latere hand er geen overgang bij zet zonder die vraag te stellen. */
  @media (prefers-reduced-motion: reduce) {
    .ds-clusterkaart__punt {
      transition: none;
    }
  }
}

/* === etiket === */
/* Etiket. Het kapitaaltje boven een blok of naast een waarde.
 *
 * Canoniek: design/system/css/publiek.css:208-211 (.ev-voet__t), commit 235bdf69 van
 * 11 september 2026 09:22. Criterium recent.
 *
 * De audit koos hier cfe54979bacd op criterium 1, omdat het zwaarste etiket (795789e71db0,
 * .ev-label, 328 gewogen) 2,912:1 haalt. Dat oordeel klopt en de bron is verkeerd gekozen:
 * publiek.css:208 doet precies dezelfde ruil, schrijft de reden erbij (--ev-ink-faint haalt
 * 2,64 op de tint, en een kapitaaltje is ook tekst) en staat al op 27 routes. Criterium 1 en
 * criterium 4 wijzen dus dezelfde kant op. Daarmee is ook G003 op: .ev-label is een bronregel
 * die de meting over drie families verdeelde, waarna de ene werkeenheid hem canoniseerde en de
 * andere hem afwees.
 *
 * Twee kleuren, en geen derde. Het showroometiket #7A7568 (3,484:1) landt op color.text.muted
 * (5,181 op papier, 4,507 op de tint).
 *
 * Wat dit bestand NIET kan zien: de grond. Op color.surface.warm haalt color.text.muted 4,285
 * en geldt color.text.body (6,353). Die regel hangt aan Vlak en staat in etiket.md.
 */

@layer componenten {
  .ds-etiket {
    /* Het gewicht zit sinds 12 september 2026 in de rol zelf (Archivo 800) en hoort daarom
       niet meer na de kortschrijfwijze. Stond hier op vet (700) en dat overschreef de rol. */
    font: var(--ds-type-etiket);
    letter-spacing: var(--ds-type-etiket-spatiering);
    /* De kapitalen komen hier vandaan en niet uit de tekst, zodat een schermlezer een woord
       voorleest en geen letters spelt. */
    text-transform: var(--ds-type-etiket-kapitaal);
  }

  .ds-etiket--gedempt { color: var(--ds-color-text-muted); }
  .ds-etiket--accent  { color: var(--ds-color-text-accent); }
}

/* === film === */
/* Film. Een korte film die vanzelf loopt, met een knop die hem stilzet.
 *
 * Canoniek: de merkbron, `bundel/stijl.css` regel 318 tot 341, op de jaargang die het merkspoor
 * op 12 september 2026 stempelde (`origin/ontwerp/modern-delft`, `7ab18dc`, jaargang
 * `423fc022`). Tien voorkomens, alle tien op de voorpagina.
 *
 * DE KNOP IS GEEN GEMAK MAAR EEN EIS, EN DAAR HANGT DE VORM VAN DIT ONDERDEEL AAN. Wat langer
 * dan vijf seconden vanzelf beweegt, moet te stoppen zijn (WCAG 2.2.2). De merkbron zet
 * `autoplay` in de opmaak en verbergt de knop met `.filmknop { display: none }` tot er een
 * script draait. Zonder script loopt de film daar dus wel en is hij niet te stoppen, en dat is
 * precies de verkeerde kant om op te falen.
 *
 * HIER STAAT `autoplay` NIET IN DE OPMAAK. Het script start de film in dezelfde handeling
 * waarmee het de knop tevoorschijn haalt, net zoals Onthuller wapent vanuit zijn eigen
 * waarnemer. Er bestaat dus geen toestand waarin er iets beweegt zonder knop om het te stoppen.
 * Draait er geen script, dan staat de film stil op zijn eerste beeld: dat is een foto en geen
 * gebrek.
 *
 * HET EERSTE BEELD STAAT IN DE STIJL EN NIET IN HET ATTRIBUUT `poster`. Een poster is een
 * bestand voor elk scherm; zo krijgt een telefoon het kleine beeld en de rest het grote, zonder
 * javascript. Die reden komt uit de merkbron en is daar gemeten: 52 kB tegen 184.
 */

@layer componenten {
  /* De houder reserveert zijn hoogte met aspect-ratio, zodat er niets verspringt terwijl de
     film laadt. De maskers laten het beeld aan alle vier de randen uitvloeien; ze staan als
     paar, want een enkel verloop maskeert maar in een richting. */
  .ds-film {
    position: relative;
    aspect-ratio: var(--ds-film-verhouding);
    inline-size: 100%;
    margin-inline: auto;
    -webkit-mask-image:
      linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent),
      linear-gradient(transparent, #000 8%, #000 90%, transparent);
    -webkit-mask-composite: source-in;
    mask-image:
      linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent),
      linear-gradient(transparent, #000 8%, #000 90%, transparent);
    mask-composite: intersect;
  }

  /* Het eerste beeld komt als custom property van de macro; de eigenschap staat hier. Zonder
     beeld blijft de grond staan en is het vlak leeg maar niet zwart. */
  .ds-film__beeld {
    inline-size: 100%;
    block-size: 100%;
    object-fit: cover;
    background: var(--ds-color-surface-raised) var(--ds-film-beeld, none) center / cover no-repeat;
  }
  /* Onder 700px hoort het kleine eerste beeld bij de kleine bron. Diezelfde grens staat als
     `media` op de `<source>`; hij hoort bij de bestanden en niet bij de opmaak, en daarom is er
     geen token voor en staat het getal op allebei de plekken letterlijk. */
  @media (max-width: 700px) {
    .ds-film__beeld {
      background-image: var(--ds-film-beeld-smal, var(--ds-film-beeld, none));
    }
  }

  /* De knop hangt in de hoek VAN het beeld en niet erover: de regel dat er geen tekst over een
     beeld komt blijft staan, en een bediening is geen tekst.

     Hij staat er niet zolang het script hem niet heeft vrijgegeven, en dat is geen verstopte
     bediening: zolang de knop weg is, loopt de film ook niet. De twee horen bij elkaar. */
  .ds-film__knop {
    display: none;
    position: absolute;
    inset-block-end: var(--ds-space-binnen-blok);
    inset-inline-end: var(--ds-space-binnen-blok);
    z-index: 1;
    align-items: center;
    min-block-size: var(--ds-maat-raakvlak);
    padding-inline: var(--ds-space-kop-tekst);
    border: var(--ds-border-hairline) solid var(--ds-color-border-subtle);
    border-radius: var(--ds-radius-control);
    background: var(--ds-color-surface-raised);
    color: var(--ds-color-text-default);
    font: var(--ds-type-knop);
    cursor: pointer;
  }
  .ds-film--bedienbaar .ds-film__knop { display: inline-flex; }
  .ds-film__knop:hover { border-color: var(--ds-color-surface-brand); }

  /* Eén knop met twee opschriften, en de stand zegt welke er staat. `aria-pressed` draagt de
     toestand voor wie hem hoort; zonder de twee spans zou een schermlezer de knop horen
     veranderen zonder te weten wat er staat te gebeuren. */
  .ds-film__aan { display: none; }
  .ds-film__knop[aria-pressed='true'] .ds-film__uit { display: none; }
  .ds-film__knop[aria-pressed='true'] .ds-film__aan { display: inline; }
}

/* === flowkaart === */
/* Flowkaart. De schil van elk scherm van de bestelflow: een kaart met stroken.
 *
 * Canoniek: de merkbron, `bundel/stijl.css` regel 707 tot 763, op de jaargang die het
 * merkspoor op 12 september 2026 stempelde (`origin/ontwerp/modern-delft`, `7ab18dc`,
 * jaargang `423fc022`). Met 566 voorkomens over zeven klassen is dit het zwaarste
 * patroon van de nieuwe site.
 *
 * EEN ONDERDEEL EN NIET TWEE, EN DAT IS DE VORM VAN DE ZAAK. De overdracht knipte de
 * kaart en de strook uit elkaar. Dat kan niet: de scheiding tussen twee stroken zit op
 * `.kaartstrook + .kaartstrook`, dus op de OPVOLGING binnen de kaart en niet op een
 * eigenschap van een strook. Een strook die je los bouwt heeft geen buur, dus hij meet
 * iets anders dan wat er op de pagina staat.
 *
 * ZEVEN KLASSEN WERDEN ER VIJF, EN 169 VOORKOMENS VERDWENEN. `kaartstrook--vraag` (85
 * voorkomens) en `kaartstrook--blok` (84) dragen in de merkbron NUL verklaringen: geen
 * regel in `stijl.css` matcht erop, ook niet in een mediavraag, en `beweging.js` raakt ze
 * niet. Nagemeten door het merkspoor op 13 september 2026, dat bevestigde dat ze als
 * etiket zijn ontstaan tijdens het bouwen en nooit een regel hebben gekregen. Ze vallen
 * hier allebei op de standaardvorm, die geen variantklasse schrijft.
 *
 * PAS OP WAT DAARBIJ NIET MAG VERVALLEN, en het merkspoor wees erop: de scheidingslijn
 * selecteert op de BASISKLASSE en niet op een vorm. De basisklasse staat er dus altijd,
 * ook bij de standaardvorm; alleen de variantklasse blijft weg. Laat je de basisklasse
 * ook vervallen, dan verdwijnt de lijn tussen twee stroken, en dat is een zichtbaar
 * verschil dat geen poort meet.
 *
 * `flowvel` STAAT HIER NIET. Dat is de zijmarge van het vel waarin de kaart staat, dus
 * paginaruimte en geen eigenschap van de kaart. Hij komt mee met het sjabloon
 * `Flow/Scherm`, dat in dezelfde ronde omgaat. Een kaart die zijn eigen paginamarge zet,
 * is niet ergens anders neer te zetten.
 *
 * DE SMALLE STAND IS EEN CONTAINERVRAAG EN GEEN MEDIAVRAAG, en dat is het scherpste
 * besluit in dit blad. De merkbron doet het met `@media (max-width: 600px)`. Dat getal is
 * echt maar het is geen breekpunt van de site: het merkspoor mat op 13 september dat
 * `stijl.css` er vier draagt (twintig maal 900, negen maal 600, een maal 700 en een maal
 * 380), terwijl hun eigen `WEBSITE.md` er een documenteert. Die negen op 600 zijn een
 * tweede laag die nooit is uitgesproken: een tweekolomsding dat op een telefoon een kolom
 * wordt.
 *
 * Dit systeem heeft daar al een beter antwoord voor, en het staat in `kaart.css`: zulke
 * omslagpunten zijn containervragen, want hetzelfde onderdeel staat in meer dan een
 * breedte. Hier geldt dat letterlijk: deze kaart staat vandaag in een vel dat het venster
 * volgt, en morgen naast iets anders. Wat er moet gebeuren hangt aan hoe breed de KAART
 * is en niet aan hoe breed het venster is.
 *
 * De drempel is 552px en dat is een afgeleide en geen meting: bij een venster van 600 zet
 * `flowvel` aan weerszijden `ruimte.rand`, dat daar `clamp(20px, 4vw, 56px)` op 24px
 * uitkomt, dus de kaart is er 600 min 48 breed. Verandert die zijmarge, dan verschuift
 * dit getal mee en dan hoort het hier bijgesteld te worden. Een containervraag kan geen
 * custom property lezen, dus hij staat als getal; dezelfde beperking staat in `kaart.css`
 * bij `raster.omslag.tegel`.
 */

@layer componenten {
  /* De kaart. `overflow: hidden` is niet netheid maar noodzaak: de stroken lopen van rand
     tot rand en de cijferstrook draagt een eigen grond, dus zonder dit steekt die grond
     buiten de straal uit. */
  .ds-flowkaart {
    container-type: inline-size;
    container-name: ds-flowkaart;
    max-inline-size: var(--ds-flowkaart-maat);
    margin-inline: auto;
    overflow: hidden;
    border: var(--ds-border-hairline) solid var(--ds-color-border-subtle);
    border-radius: var(--ds-radius-vlak);
    background: var(--ds-color-surface-raised);
  }

  .ds-flowkaart__strook {
    padding: var(--ds-flowkaart-strook-ruimte) var(--ds-flowkaart-strook-ruimte-zij);
  }

  /* ALLEEN min-inline-size, EN GEEN max-inline-size ERNAAST. Die noot komt woordelijk uit
     de merkbron en het is een gemeten val: een `max-width: 100%` hier overstemt elke maat
     van een onderdeel die even zwaar weegt en eerder staat. Het tekstvak van scherm 6 werd
     daarmee 840px in plaats van de 640 die zijn eigen regel zet, en een vlak verloor zijn
     uitstek. Gemeten aan de breedte van dat tekstvak en niet op het oog. */
  .ds-flowkaart__strook > * {
    min-inline-size: 0;
  }

  /* De scheiding hangt aan de opvolging en niet aan een vorm. Zie de kop: daarom draagt
     ook de standaardvorm zijn basisklasse. */
  .ds-flowkaart__strook + .ds-flowkaart__strook {
    border-block-start: var(--ds-border-hairline) solid var(--ds-color-border-subtle);
  }

  /* De cijferstrook: een getint vlak van rand tot rand, met de getallen naast elkaar en
     zonder gat ertussen. Het gat is nul omdat de scheiding een lijn is en geen ruimte;
     die lijn zet Cijferrij, want hij hangt tussen twee cijfers en niet aan deze strook. */
  .ds-flowkaart__strook--cijfers {
    display: flex;
    flex-wrap: wrap;
    align-items: stretch;
    gap: 0;
    padding-block: var(--ds-flowkaart-cijfers-ruimte);
    background: var(--ds-color-surface-sunken);
  }

  /* De voetstrook: de knoprij met de uitleg ernaast.
     DEZE VORM STAAT HIER EN LEUNT NIET OP HET PRIMITIEF Rij, EN DAT IS EEN KEUZE. De brede
     stand is precies wat `ds-rij--blok ds-rij--midden` doet, dus dat was verleidelijk. De
     smalle stand is dat niet: daar gaat hij naar een kolom die uitrekt, en die omslag hoort
     bij de containervraag van DEZE kaart. Een onderdeel mag geen regel op `.ds-rij`
     schrijven (`bouw.py` weigert dat terecht), dus de omslag zou dan nergens kunnen staan.
     Twee helften van een vorm op twee plekken is erger dan een vorm die zijn eigen laag
     herhaalt. */
  .ds-flowkaart__strook--voet {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--ds-space-blok);
  }

  /* De uitleg naast de knop in de voetstrook. Hij staat naast de knoprij en niet eronder,
     zodat wie de cijfers gelezen heeft niet terug omhoog hoeft; dat is reparatie 4 uit de
     opzet van het merkspoor. Zijn ondergrens laat hem omslaan zodra er te weinig ruimte
     naast de knop overblijft, dus het omslaan hangt aan wat er werkelijk naast staat. */
  .ds-flowkaart__voetuitleg {
    flex: 1;
    min-inline-size: var(--ds-flowkaart-voetuitleg-min);
    max-inline-size: var(--ds-flowkaart-voetuitleg-max);
  }

  /* In hoog contrast dwingt het systeem de kleuren af en verdwijnt elke grond. Dat is precies
     de stand waarin de cijferstrook zijn enige onderscheid kwijtraakt: hij verschilt van een
     gewone strook alleen doordat hij getint is. Hij krijgt hier de lijn die hij in die stand
     nodig heeft. De scheiding tussen twee stroken en de rand van de kaart zijn al randen en
     blijven dus vanzelf staan. */
  @media (forced-colors: active) {
    .ds-flowkaart__strook--cijfers {
      border-block-start: var(--ds-border-hairline) solid CanvasText;
      border-block-end: var(--ds-border-hairline) solid CanvasText;
    }
  }

  /* Smal. Zie de kop voor waarom dit een containervraag is en waar 552 vandaan komt. */
  @container ds-flowkaart (max-width: 552px) {
    .ds-flowkaart__strook {
      padding: var(--ds-space-blok);
    }

    .ds-flowkaart__strook--cijfers {
      flex-direction: column;
      padding-block: var(--ds-space-blok);
    }

    .ds-flowkaart__strook--voet {
      flex-direction: column;
      align-items: stretch;
    }

    /* De knoprij en de uitleg onder elkaar, allebei over de volle breedte. `flex: 1` zou
       hier niets meer doen en de ondergrens zou de kaart kunnen uitduwen, dus allebei
       terug naar de vrije stand. */
    .ds-flowkaart__voetuitleg {
      flex: none;
      min-inline-size: 0;
      max-inline-size: none;
    }
  }
}

/* === haarlijn === */
/* Haarlijn. Een okeren lijn van een pixel, die zichzelf tekent als hij in beeld komt.
 *
 * Canoniek: de merkbron, `bundel/stijl.css` regel 188 tot 192, op de jaargang die het merkspoor
 * op 12 september 2026 stempelde (`origin/ontwerp/modern-delft`, `7ab18dc`, jaargang
 * `423fc022`).
 *
 * DRIE VAN DE VIER KLASSEN DIE HET REGISTER HIER OP AFBEELDDE, HOREN HIER NIET. Gemeten op
 * 13 september 2026 over de hele bundel:
 *
 *   `streep`  47 voorkomens, en GEEN eigen regel. Hij bestaat alleen in afstammingsregels van
 *             twee andere onderdelen: `.kruimel .streep` is het teken tussen twee kruimels
 *             (41 keer, en dat is Padwijzer, die het al heeft als `ds-padwijzer__streep`) en
 *             `.boek .streep` is de okeren lijn op het omslag (6 keer, en dat is Boek).
 *             Dezelfde naam voor twee dingen, precies de vorm waar de cascadepoort voor is.
 *   `lat`      1 voorkomen, de baan van de voortgangslijn onder de boekengalerij. Die hoort bij
 *             de spoorstrook, samen met `vol`; het merkspoor heeft dat bevestigd.
 *
 * Wat er overblijft is `lijn` en `boven-lijn`, en dat is wat hier staat.
 *
 * DE KALE KLASSE VERBERGT NIETS, om dezelfde reden als bij Onthuller. Een lijn die zichzelf
 * tekent staat op `scaleX(0)`, en dat is onzichtbaar. Komt de klasse die hem terugzet er niet,
 * dan is de lijn er niet, en een ontbrekende haarlijn ziet er precies zo uit als een ontwerp
 * zonder haarlijn. Verbergen zit daarom op `--gewapend`, en die zet `haarlijn.js` vanuit de
 * terugroep van de waarnemer die datzelfde element al volgt.
 *
 * HIJ IS SIER EN GEEN INHOUD, en dat is het verschil met Onthuller. Daar kan een blok met tekst
 * verdwijnen; hier verdwijnt een streep. De vorm is toch dezelfde, want de kosten van die vorm
 * zijn nul en het alternatief is een tweede manier om hetzelfde te doen.
 */

@layer componenten {
  .ds-haarlijn {
    block-size: var(--ds-border-hairline);
    background: var(--ds-color-border-accent);
    transform-origin: left;
  }

  /* De kale klasse tekent zich meteen. Pas gewapend begint hij op nul. */
  .ds-haarlijn--gewapend {
    transform: scaleX(0);
  }

  .ds-haarlijn--gewapend.ds-haarlijn--in {
    transform: scaleX(1);
    transition: transform var(--ds-motion-lijn) var(--ds-motion-onthul-kromme);
  }

  /* Een lijn boven een blok, over de volle breedte, met ruimte eronder. De wikkel draagt de
     plek; de lijn zelf blijft dezelfde lijn. */
  .ds-haarlijn__boven {
    position: relative;
    padding-block-start: var(--ds-space-kop-tekst);
  }
  .ds-haarlijn__boven > .ds-haarlijn {
    position: absolute;
    inset-inline: 0;
    inset-block-start: 0;
  }

  /* Wie beweging uitzet krijgt de lijn, en niet een snellere afwezigheid. Dezelfde regel als bij
     Onthuller en om dezelfde reden: `ds-basis.css` maakt de overgang korter en zet de transform
     niet terug. */
  @media (prefers-reduced-motion: reduce) {
    .ds-haarlijn--gewapend,
    .ds-haarlijn--gewapend.ds-haarlijn--in {
      transform: none;
      transition: none;
    }
  }

  /* In hoog contrast dwingt het systeem elke grond af en verdwijnt de lijn. Een rand houdt hem. */
  @media (forced-colors: active) {
    .ds-haarlijn {
      background: CanvasText;
      border-block-start: var(--ds-border-hairline) solid CanvasText;
    }
  }
}

/* === kaart === */
/* Kaart. Een product als tegel, met een doel dat de hele kaart is. Kiezen doet Keuzetegel,
 * want daar zit een echt invoerelement in.
 *
 * Canoniek: design/system/css/tegel.css:39-115 (.ev-kaart), gekozen op samenhang. Dat is het
 * enige stijlblad dat beide schermoppervlakken laadt.
 *
 * LET OP DE NAAMBOTSING. .ev-kaart betekent in book.css een landkaart van Nederland en in
 * tegel.css deze producttegel. Ze laden nooit samen, dus er is vandaag geen conflict, maar een
 * componentregister kan geen twee componenten met die naam dragen. De landkaart heet in het
 * systeem Kaartbeeld en hoort bij het sjabloon Druk/Binnenwerk.
 *
 * Drie dingen die hier anders zijn dan vandaag:
 *
 * 1. Een link per kaart in plaats van drie naar hetzelfde adres. Het klikvlak is een
 *    uitgestrekt pseudo-element, dus de hele kaart blijft aanraakbaar.
 * 2. De ring staat om de hele kaart, uit color.focus (3,806 op surface.page) in plaats van uit
 *    --ev-accent-lt, dat daar 1,916 haalde, en hij hangt aan :has(:focus-visible) en niet aan
 *    :focus-within. Een muisklik roept hem dus niet op.
 * 3. De levertijd gaat van --ev-ink-faint (2,912 op papier) naar color.text.muted (5,181).
 *
 * Wat hier NIET staat: de subgrid waarmee tegel.css de regels van alle kaarten in een rij op
 * dezelfde hoogte legt. Dat vraagt een vast aantal rijen per kaart terwijl beeld, prijs en
 * levertijd optionele sloten zijn, en het is een eigenschap van het raster en niet van de
 * kaart. De staart schuift wel naar beneden, dus de laatste regels van een rij liggen gelijk;
 * dat is de terugval die tegel.css zelf "de oude toestand en niet stuk" noemt.
 */

@layer componenten {
  /* Geen display hier: de indeling binnen de kaart komt van Stapel, uit de laag eronder.
     position: relative is er voor het uitgestrekte klikvlak. */
  .ds-kaart {
    position: relative;
    color: var(--ds-color-text-default);
  }

  /* Verhoogd: iets dat van de pagina af ligt maar er niet overheen. Dan hoort er ook een
     grond en een binnenruimte bij, anders zweeft de schaduw om losse tekst. */
  .ds-kaart--verhoogd {
    padding: var(--ds-space-binnen-blok);
    border-radius: var(--ds-radius-control);
    background: var(--ds-color-surface-page);
    box-shadow: var(--ds-elevation-raised);
  }

  /* Het beeldvlak. Staand op een smalle kolom en liggend daarboven: alles wat hier in staat
     is een staand blad, en in een liggend kader krijgt zo'n blad op een telefoon nog geen
     kwart van de breedte. In drie kolommen is liggend juist de goede maat, want staand zou
     daar kaarten van bijna duizend pixels hoog geven. Het omslagpunt is een containervraag en
     geen mediavraag, want dezelfde kaartenrij staat in een brede pagina en in een smalle
     kolom. Een containervraag kan geen custom property lezen, dus raster.omslag.tegel staat
     hier als getal. */
  .ds-kaart__vlak {
    display: grid;
    aspect-ratio: 3 / 4;
    overflow: hidden;
    padding: var(--ds-space-blok);
    border-radius: var(--ds-radius-control);
    /* HET BEELDVLAK GAAT NAAR WIT EN KRIJGT DAAROM EEN HAARLIJN TERUG. In dit systeem vervangt de
       tint elke lijn en elk kader; haal je hem weg, dan moet iets anders de omtrek doen. Wit op
       papier is 1,090 en dat is geen omtrek. Een kaart zonder omslagfoto zou daarmee een leeg vlak
       zonder rand worden, en ook mét foto is dit vlak een letterbox: `object-fit: contain` laat
       een witte rand staan die anders in de pagina wegvalt.

       De lijn is color.border.subtle (1,352 op wit) en geen schaduw. Een schaduw zegt "dit ligt
       erop" en dat is elevation.raised, de vorm van Kaart --verhoogd; een lijn zegt "dit is een
       doos", en dat is wat hier moet staan. Besluit B59. */
    background: var(--ds-color-surface-raised);
    box-shadow: inset 0 0 0 var(--ds-border-hairline) var(--ds-color-border-subtle);
  }
  @container (min-width: 600px) {
    .ds-kaart__vlak { aspect-ratio: 4 / 3; }
  }
  /* Wat in het slot staat past zich in het kader en loopt er niet uit. object-fit: contain
     schaalt het beeld mee en snijdt het niet bij; de letterbox die overblijft draagt dezelfde
     tint als het kader. De regel pakt zowel het kind van het slot als de afbeelding erin,
     zodat het ook klopt als Beeld zijn figuur eromheen zet. Een onderschrift hoort niet in een
     kaart: de kaart draagt zijn eigen kop. */
  .ds-kaart__vlak > *,
  .ds-kaart__vlak img {
    inline-size: 100%;
    block-size: 100%;
    object-fit: contain;
  }

  .ds-kaart__kop { font: var(--ds-type-sectie);
    letter-spacing: var(--ds-type-sectie-spatiering); }

  .ds-kaart__link {
    color: inherit;
    text-decoration: none;
    transition: color var(--ds-motion-feedback);
  }
  /* Het klikvlak is de hele kaart. Zo is er een link en toch een doel van kaartformaat. */
  .ds-kaart__link::after {
    content: '';
    position: absolute;
    inset: 0;
  }

  /* Zweven verandert de kop en zet er een streep onder, zodat kleur niet het enige verschil
     is. De grond blijft, want de kaart staat in een rij en een wisselende grond leest daar
     als een tweede vorm. */
  .ds-kaart:hover .ds-kaart__link {
    color: var(--ds-color-text-accent);
    text-decoration: underline;
    text-underline-offset: var(--ds-link-streep-afstand);
  }

  /* De ring hoort om het doel en het doel is de hele kaart, dus de link geeft hem hier af.
     Dit is de enige plek waar dat mag: de ring verdwijnt niet, hij verhuist. */
  .ds-kaart:has(.ds-kaart__link:focus-visible) {
    outline: var(--ds-control-focus-breedte) solid var(--ds-color-focus);
    outline-offset: var(--ds-control-focus-afstand);
  }
  .ds-kaart__link:focus-visible { outline: none; }

  /* De staart zakt naar de onderkant, zodat de prijzen van een rij kaarten op dezelfde hoogte
     eindigen ook als de ene naam over twee regels loopt en de andere niet. */
  .ds-kaart__staart { margin-block-start: auto; }
  .ds-kaart__prijs {
    font: var(--ds-type-code);
    color: var(--ds-color-text-muted);
  }
  .ds-kaart__levering {
    font: var(--ds-type-klein);
    color: var(--ds-color-text-muted);
  }
}

/* === keuzelijst === */
/* Keuzelijst. Een keuze uit een lijst die te lang is voor knoppen.
 *
 * Canoniek: pipeline/templates/site/vier.html:112 (965edf4da6dc), de select op scherm 2 die
 * vandaag .ev-field .ev-field--klein draagt. De vorm is die van Veld maat klein.
 *
 * Er staat met opzet geen appearance: none. Het eigen element van de browser is de enige vorm die
 * op elk apparaat werkt, en zonder de chevron van de browser moet er een eigen komen; dat is
 * herontwerp en geen consolidatie. De hoogte staat op maat.raakvlak, want de select van vandaag
 * rekent zijn hoogte uit de letter en komt op smalle schermen onder de 44px uit.
 */

@layer componenten {
  .ds-keuzelijst {
    inline-size: 100%;
    min-block-size: var(--ds-maat-raakvlak);
    /* Dezelfde binnenruimte als Veld, want een keuzelijst staat in dezelfde rij als een veld en
       een knop. Stond op space.binnen-blok en kwam daarmee op 47px naast 52px; maatpoort.mjs
       weegt die drie sinds 12 september 2026 tegen elkaar. */
    padding: calc(var(--ds-space-kop-tekst) - var(--ds-keuzelijst-hoogtecorrectie)) var(--ds-space-kop-tekst);
    border: 0;
    border-radius: var(--ds-radius-control);
    /* WIT EN NIET DE TINT. Ernst koos op 12 september 2026 dat het merk voorgaat: Modern Delft zet
       een veld, een tegel, een kaart en de kaft van het boek op `--wit` en dit systeem zette ze op
       de tint. De tint blijft waar hij iets werkelijk verzonken maakt (een zebrarij, een uitstand,
       een blok dat inhoud groepeert); wit is de grond van wat OP de pagina ligt. Zie besluit B59. */
    background: var(--ds-color-surface-raised);
    /* type.veld en niet de losse letterfamilie. Tot 12 september 2026 stond hier
       `font-family: var(--ds-letter-display)` met de toelichting dat het veld de enige bediening
       met de displayletter is. Dat klopte zolang de displayletter Libre Caslon was; sinds hij
       Archivo is, zette die regel elk invoerveld in de merkletter, en Modern Delft zet zijn velden
       juist in de leesletter. Een onderdeel dat een primitief aanraakt in plaats van een rol merkt
       een merkwissel op de verkeerde manier. */
    font: var(--ds-type-veld);
    color: var(--ds-color-text-default);
    cursor: pointer;
    transition: box-shadow var(--ds-motion-feedback), color var(--ds-motion-feedback);
  }

  /* gekozen: zolang er niets gekozen is staat de lege regel er als plaatshouder, in gedempte
     inkt. Zodra er een keuze staat, is de lijst geldig en draagt hij de volle inkt. Dat is
     dezelfde afspraak als de plaatshouder van Veld, met dezelfde twee kleuren. */
  .ds-keuzelijst:required:invalid { color: var(--ds-color-text-muted); }

  .ds-keuzelijst:focus-visible {
    outline: var(--ds-control-focus-breedte) solid var(--ds-color-focus);
    outline-offset: var(--ds-control-focus-afstand);
  }

  .ds-keuzelijst[aria-invalid='true'] {
    box-shadow: inset 0 0 0 var(--ds-border-hairline) var(--ds-color-border-danger);
  }

  .ds-keuzelijst:disabled {
    box-shadow: none;
    color: var(--ds-color-text-muted);
    cursor: not-allowed;
  }

  /* HOGE CONTRASTMODUS, dezelfde reparatie als Veld en Tekstvak; zie veld.css. Gemeten in
     Chromium op 12 september 2026: geldig tegen ongeldig verschilde 0 van de 48576 pixels, buiten
     die modus 2114. Er staat met opzet geen appearance: none op dit onderdeel, dus de chevron van
     de browser blijft ook in deze modus staan; wat ontbrak was de grens om het vlak eromheen en
     het verschil tussen geldig en ongeldig. Een rand overleeft de modus en heeft geen
     forced-color-adjust nodig. */
  @media (forced-colors: active) {
    .ds-keuzelijst {
      border: var(--ds-border-hairline) solid;
    }
    .ds-keuzelijst[aria-invalid='true'] {
      border-style: dashed;
    }
    .ds-keuzelijst:focus-visible {
      outline-color: Highlight;
    }
  }
}

/* === keuzerondje === */
/* Keuzerondje. Een keuze uit twee tot vijf mogelijkheden die elkaar uitsluiten: de stem, het
 * wapen.
 *
 * Canoniek: de optieregel op pipeline/templates/site/maak.html, met dezelfde markreset als
 * Vinkje. De vorm is die van Vinkje maar rond, en de stip is dezelfde stip.
 *
 * Ook hier is het echte rondje de bediening en niet een span ernaast; zie vinkje.css voor B007.
 * Een rondje hoort in een Veldgroep met een legenda, want een groep rondjes zonder groepsnaam
 * heeft geen vraag.
 */

@layer componenten {
  /* De stapeling komt van Stapel; dit blad zet alleen wat van het onderdeel zelf is. */
  .ds-keuzerondje__optie {
    min-block-size: var(--ds-maat-raakvlak);
    cursor: pointer;
  }

  .ds-keuzerondje__rondje {
    appearance: none;
    flex: none;
    inline-size: var(--ds-maat-raakvlak-min);
    block-size: var(--ds-maat-raakvlak-min);
    /* De optie kan twee regels lang zijn; het rondje blijft dan bij de eerste regel staan. */
    margin: 0;
    margin-block-start: var(--ds-space-inline);
    border-radius: var(--ds-radius-pil);
    background-color: var(--ds-color-surface-raised);
    background-position: center;
    background-repeat: no-repeat;
    box-shadow: inset 0 0 0 var(--ds-border-hairline) var(--ds-color-mark);
    cursor: pointer;
    transition: background-color var(--ds-motion-feedback);
  }

  /* aan: dezelfde stip als bij Vinkje, half zo breed als het rondje. */
  .ds-keuzerondje__rondje:checked {
    background-image: radial-gradient(closest-side, var(--ds-color-mark) 100%, transparent 100%);
    background-size: 50% 50%;
  }

  .ds-keuzerondje__rondje:focus-visible {
    outline: var(--ds-control-focus-breedte) solid var(--ds-color-focus);
    outline-offset: var(--ds-control-focus-afstand);
  }

  .ds-keuzerondje__tekst {
    display: block;
    font: var(--ds-type-brood);
    color: var(--ds-color-text-body);
    max-inline-size: var(--ds-maat-regel);
  }

  .ds-keuzerondje__hulp {
    display: block;
    font: var(--ds-type-klein);
    color: var(--ds-color-text-muted);
  }

  .ds-keuzerondje__rondje:disabled {
    background-color: var(--ds-color-surface-sunken);
    box-shadow: inset 0 0 0 var(--ds-border-hairline) var(--ds-color-border);
    cursor: not-allowed;
  }
  .ds-keuzerondje__rondje:disabled:checked {
    background-image: radial-gradient(closest-side, var(--ds-color-text-muted) 100%, transparent 100%);
  }
  .ds-keuzerondje__optie:has(.ds-keuzerondje__rondje:disabled) {
    cursor: not-allowed;
  }
  .ds-keuzerondje__optie:has(.ds-keuzerondje__rondje:disabled) .ds-keuzerondje__tekst {
    color: var(--ds-color-text-muted);
  }

  /* HOGE CONTRASTMODUS, en het is dezelfde stip als bij Vinkje dus dezelfde reparatie. Gemeten in
     Chromium op 12 september 2026: 0 van de 600 pixels verschilden tussen gekozen en niet
     gekozen, want de stip is een background-image en die gooit de modus weg.

     Zie vinkje.css voor de volledige afweging. Kort: het zichtbare rondje IS het invoerveld, dus
     een ::after zou een pseudo-element op een input zijn, en het alternatief is het rondje weer
     naast het invoerveld zetten, wat B007 terugbrengt. forced-color-adjust: none haalt dit ene
     element uit de overname en hieronder staan alleen systeemkleuren, dus het rondje wordt
     getekend in het palet dat de gebruiker zelf koos. */
  @media (forced-colors: active) {
    .ds-keuzerondje__rondje {
      forced-color-adjust: none;
      background-color: Canvas;
      box-shadow: inset 0 0 0 var(--ds-border-hairline) CanvasText;
    }
    .ds-keuzerondje__rondje:checked {
      background-image: radial-gradient(closest-side, CanvasText 100%, transparent 100%);
    }
    .ds-keuzerondje__rondje:focus-visible {
      outline-color: Highlight;
    }
    .ds-keuzerondje__rondje:disabled {
      background-color: Canvas;
      box-shadow: inset 0 0 0 var(--ds-border-hairline) GrayText;
    }
    .ds-keuzerondje__rondje:disabled:checked {
      background-image: radial-gradient(closest-side, GrayText 100%, transparent 100%);
    }
  }
}

/* === keuzetegel === */
/* Keuzetegel. Kiezen met een tegel; een tegel die naar een pagina linkt is Kaart.
 *
 * Canoniek: pipeline/templates/site/kies.html:71-74 met design/system/css/site.css:1133-1156,
 * de okeren inzetring op de gekozen tegel, 88 voorkomens. Gekozen op gebruik.
 *
 * Vier dingen die hier anders zijn dan vandaag, en alle vier een standaardreparatie:
 *
 * 1. Het raakdoel staat in deze laag, op maat.raakvlak, dus de tegel kan hem niet verliezen.
 * 2. De ring blijft 1px en gaat niet naar 2px. WCAG 2.2 stelt aan een selectie-indicator een
 *    contrasteis van 3:1 en geen dikte-eis; color.border.selected haalt op 1px al 3,806 op
 *    papier en 3,311 op de tint. Criterium 1 onderscheidt dus niet, en dan beslist gebruik:
 *    88 tegen 4.
 * 3. De focusring hangt aan :focus-visible en niet aan :focus-within, zodat een muisklik hem
 *    niet oproept, en hij komt uit color.focus (3,806 op surface.page) in plaats van uit
 *    --ev-accent-lt, dat daar 1,916 haalde (publiek.css:549, waar het stijlblad zeven regels
 *    lager zelf opschrijft dat die oude kleur daar te weinig haalt).
 * 4. uit is een echt attribuut, disabled, en geen klasse. In negen stijlbladen staat vandaag
 *    nul keer :disabled.
 *
 * Kleur draagt de betekenis nooit alleen: de gekozen stand draagt de inzetring, een vinkteken
 * en de checked-stand op het echte invoerelement.
 */

@layer componenten {
  /* Geen display hier: de indeling binnen de tegel komt van Stapel, uit de laag eronder. */
  .ds-keuzetegel {
    position: relative;
    min-block-size: var(--ds-maat-raakvlak);
    padding: var(--ds-space-binnen-blok);
    border-radius: var(--ds-radius-control);
    background: var(--ds-color-surface-page);
    color: var(--ds-color-text-default);
    box-shadow: inset 0 0 0 var(--ds-border-hairline) var(--ds-color-border-subtle);
    cursor: pointer;
    transition: background-color var(--ds-motion-feedback), box-shadow var(--ds-motion-feedback);
  }

  /* Het echte invoerelement. Het blijft in de tabvolgorde en het houdt zijn stand; alleen de
     vorm die de browser eraan geeft is onzichtbaar, want de tegel is de vorm. De ring die de
     reset op :focus-visible zet valt hier dus ook weg, en daarom staat hij hieronder op de
     tegel zelf. Dat is de reparatie van de vijf bedieningselementen uit de audit die hun
     invoerveld verbergen en daardoor nooit een ring tonen. */
  .ds-keuzetegel__invoer {
    position: absolute;
    inset-block-start: 0;
    inset-inline-start: 0;
    margin: 0;
    opacity: 0;
    pointer-events: none;
  }

  .ds-keuzetegel:hover { background: var(--ds-color-surface-sunken); }

  .ds-keuzetegel:has(.ds-keuzetegel__invoer:focus-visible) {
    outline: var(--ds-control-focus-breedte) solid var(--ds-color-focus);
    outline-offset: var(--ds-control-focus-afstand);
  }

  /* Uitgeschakeld staat voor gekozen, zodat een tegel die allebei is zijn ring houdt: de
     stand blijft dan af te lezen en alleen de grond zegt dat er niets te kiezen valt. */
  .ds-keuzetegel:has(.ds-keuzetegel__invoer:disabled) {
    cursor: not-allowed;
    background: var(--ds-color-surface-sunken);
    color: var(--ds-color-text-muted);
  }

  .ds-keuzetegel:has(.ds-keuzetegel__invoer:checked) {
    box-shadow: var(--ds-elevation-selected) var(--ds-color-border-selected);
  }

  /* HET VINKVAK STAAT ER ALTIJD, in beide standen. Vandaag staat de hele markering op
     opacity 0 zolang er niets gekozen is, en dan valt de uit-stand uit elke meting weg en is
     aan de tegel niet te zien dat er iets te kiezen valt. Hier is het lege vak zichtbaar en
     verschijnt alleen het teken erin. Het vak is maat.raakvlak-min, dezelfde 24px als Vinkje
     en Keuzerondje. */
  .ds-keuzetegel__vink {
    position: absolute;
    inset-block-start: var(--ds-space-tussen);
    inset-inline-end: var(--ds-space-tussen);
    z-index: var(--ds-layer-raise);
    inline-size: var(--ds-maat-raakvlak-min);
    block-size: var(--ds-maat-raakvlak-min);
    background: var(--ds-color-surface-page);
    box-shadow: inset 0 0 0 var(--ds-border-hairline) var(--ds-color-mark);
  }
  /* Rond voor een keuze uit meer, hoekig voor een los bij te bestellen ding. Dat verschil
     staat naast het element zelf: rondje is een radio en vinkje een checkbox. */
  .ds-keuzetegel--rondje .ds-keuzetegel__vink { border-radius: var(--ds-radius-pil); }
  .ds-keuzetegel--vinkje .ds-keuzetegel__vink { border-radius: var(--ds-radius-control); }

  /* Het vinkteken zelf: twee randen van een gedraaid vlak. De maten zijn een verhouding van
     het vak en geen ruimte, dus ze komen niet uit de ruimtetrap. De streek is border.hairline,
     dezelfde dikte als de ring om het vak en als de ring om de gekozen tegel; border.focus is
     de enige plek in dit systeem waar een lijn dikker mag dan een haar en dit is die plek niet. */
  .ds-keuzetegel__vink::after {
    content: '';
    position: absolute;
    inset-block-start: 26%;
    inset-inline-start: 33%;
    inline-size: 30%;
    block-size: 48%;
    border-inline-end: var(--ds-border-hairline) solid var(--ds-color-mark);
    border-block-end: var(--ds-border-hairline) solid var(--ds-color-mark);
    transform: rotate(45deg);
    opacity: 0;
    transition: opacity var(--ds-motion-feedback);
  }
  .ds-keuzetegel:has(.ds-keuzetegel__invoer:checked) .ds-keuzetegel__vink::after { opacity: 1; }

  /* Het beeldvlak. Staand op een smalle kolom en liggend daarboven: alles wat hier in staat
     is een staand blad, en in een liggend kader krijgt zo'n blad op een telefoon nog geen
     kwart van de breedte. Het omslagpunt is een containervraag en geen mediavraag, want
     dezelfde tegel staat in een brede pagina en in een smalle kolom. Een containervraag kan
     geen custom property lezen, dus raster.omslag.tegel staat hier als getal. */
  .ds-keuzetegel__vlak {
    display: grid;
    aspect-ratio: 3 / 4;
    overflow: hidden;
    padding: var(--ds-space-binnen-blok);
    border-radius: var(--ds-radius-control);
    /* Zie Kaart: wit met een haarlijn, want de tint doet hier de omtrek niet meer. */
    background: var(--ds-color-surface-raised);
    box-shadow: inset 0 0 0 var(--ds-border-hairline) var(--ds-color-border-subtle);
  }
  @container (min-width: 600px) {
    .ds-keuzetegel__vlak { aspect-ratio: 4 / 3; }
  }
  /* Wat in het slot staat past zich in het kader en loopt er niet uit. object-fit: contain
     schaalt het beeld mee en snijdt het niet bij; de letterbox die overblijft draagt dezelfde
     tint als het kader. De regel pakt zowel het kind van het slot als de afbeelding erin,
     zodat het ook klopt als Beeld zijn figuur eromheen zet. */
  .ds-keuzetegel__vlak > *,
  .ds-keuzetegel__vlak img {
    inline-size: 100%;
    block-size: 100%;
    object-fit: contain;
  }

  /* De kop houdt de breedte van het vinkvak vrij, zodat de naam er niet onder doorloopt. */
  .ds-keuzetegel__kop {
    padding-inline-end: calc(var(--ds-maat-raakvlak-min) + var(--ds-space-tussen));
    font: var(--ds-type-brood);
    font-weight: var(--ds-type-nadruk);
  }
  .ds-keuzetegel__prijs {
    margin-block-start: auto;
    font: var(--ds-type-code);
    color: var(--ds-color-text-muted);
  }
  .ds-keuzetegel__btw {
    font: var(--ds-type-fijn);
    color: var(--ds-color-text-muted);
  }

  /* HOGE CONTRASTMODUS. Dit onderdeel kwam er als enige bediening heelhuids doorheen, en dat is
     geen toeval: het vinkteken is twee randen van een gedraaid vlak, en randen overleeft die
     modus. Gemeten in Chromium op 12 september 2026 bleven er 28 verschillende pixels over
     tussen gekozen en niet gekozen, dus de stand was af te lezen. Dat is het bewijs dat weg (b),
     de stand met randen tekenen, werkt waar hij kan; bij Vinkje en Schakelaar kon hij niet,
     want daar IS het invoerveld de vorm.

     Wat wel wegviel, is de inzetring om de hele tegel, want die is een box-shadow. Daarmee zakte
     het verschil van 2140 pixels naar 28: de stand bleef leesbaar maar niet meer luid. Een
     outline overleeft de modus wel, dus die zet hem terug op dezelfde plek en dezelfde dikte,
     zonder forced-color-adjust. Hij staat boven de focusregel hierboven in de bron, dus een
     tegel die gekozen is en focus heeft, toont de focusring; dat is dezelfde volgorde als
     daarbuiten, waar de ring een box-shadow is en de focus een outline. */
  @media (forced-colors: active) {
    .ds-keuzetegel:has(.ds-keuzetegel__invoer:checked) {
      outline: var(--ds-border-hairline) solid;
      outline-offset: calc(var(--ds-border-hairline) * -1);
    }
    .ds-keuzetegel:has(.ds-keuzetegel__invoer:focus-visible) {
      outline: var(--ds-control-focus-breedte) solid Highlight;
      outline-offset: var(--ds-control-focus-afstand);
    }
  }
}

/* === knop === */
/* Knop. Handelen; navigeren doet Knoplink.
 *
 * Canoniek: design/system/css/site.css:80-84 (.ev-btn), gemeten als b4964aa4a579, 638 gewogen
 * over 33 routes, als enige knopvorm op alle drie de schermoppervlakken.
 *
 * Drie dingen die hier anders zijn dan vandaag, alle drie een standaardreparatie:
 *
 * 1. Het raakdoel staat in deze laag en niet in de binnenruimte, dus een knop kan hem niet
 *    verliezen. De kop draagt er vandaag drie onder de 44px.
 * 2. Zweven verandert alleen de grond. Vandaag wint a:hover van de knopregel en wordt de tekst
 *    van de hoofdknop oker op donkerblauw: 3,614:1 bij vet 16px waar 4,5 geldt (G045). Dat is
 *    de knop waar elke bestelling op de publieke site doorheen gaat.
 * 3. uit en bezig zijn echte attributen en geen klasse. In negen stijlbladen staat vandaag nul
 *    keer :disabled.
 */

@layer componenten {
  .ds-knop {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--ds-space-tussen);
    min-block-size: var(--ds-maat-raakvlak);
    min-inline-size: var(--ds-maat-raakvlak);
    padding: var(--ds-knop-binnenruimte);
    border: 0;
    border-radius: var(--ds-radius-control);
    /* type.knop: Atkinson Hyperlegible 700 op 16px met regelhoogte 1. De hoogte van de knop is
       daarmee een som en geen getal: 18px binnenruimte boven en onder plus een regel van 16px is
       52px, en dat is wat de merkpagina meet. Stond op type.brood, dat regelhoogte 1,65 draagt en
       de knop twaalf pixels hoger maakte dan het veld ernaast. */
    font: var(--ds-type-knop);
    text-align: center;
    text-decoration: none;
    cursor: pointer;
    transition: background-color var(--ds-motion-feedback);
  }

  /* hoofd: de enige knop op een scherm die de handeling draagt waar de pagina voor bestaat. */
  /* DE GROND VAN DE HOOFDKNOP IS EEN AFSPRAAK EN GEEN VASTE KLEUR, sinds 14 september 2026.
     Hij staat standaard op `surface.brand`, en dat gaat mis op een vlak dat diezelfde grond al
     draagt. Gemeten op de voorpagina bij 1280px: in een Opening met `--merk` was de knop een vlak
     van 185 bij 52 in oklch(0.426 0.115 256.6), op een grond van oklch(0.426 0.115 256.6).
     Dezelfde kleur tot op het cijfer. De letters staan er wit op, dus je leest de woorden en je
     ziet geen knop: "Begin met uw naam" las als losse tekst. Dat is wat Ernst zag.

     DE KLEURPOORT KON DIT NIET ZIEN, en dat is geen verwijt aan die poort. Hij weegt tekst tegen
     haar eigen grond, en wit op kobalt haalt de eis ruim. Een knop die niet van zijn pagina te
     onderscheiden is, is geen verschil tussen tekst en grond maar tussen twee gronden.

     WAAROM EEN VARIABELE EN NIET EEN REGEL BIJ DE OPENING OF EEN VARIANT HIER. Een onderdeel mag
     de klasse van een ander niet opmaken en `bouw.py` houdt dat tegen, dus `.ds-opening--merk
     .ds-knoplink--hoofd` kan aan geen van beide kanten. Een variant erbij zou een klasse erbij in
     de opmaak vragen, en dat is precies de reden waarom de sitevoet op 13 september tegen een
     `--op-inkt`-variant per onderdeel koos. Een variabele vraagt niets van de opmaak: wie een
     grond neerlegt, zegt erbij wat een knop daarop moet doen. `--beeld-verhouding` in Beeld is
     dezelfde afspraak.

     GEEN NIEUWE KLEUR. De omkering leent `surface.page` en de merkkleur die er al zijn. */
  .ds-knop--hoofd {
    /* Kobalt en niet diep. Modern Delft zet zijn hoofdknop op `--kobalt` met wit erop (8,31) en
       laat hem bij zweven naar `--diep` gaan; diep is daar de grond van de voet en van de
       zweefstand, niet van de rust. Gemeten in web/delft/stijl.css:123 en :128. */
    background: var(--ds-knop-grond);
    /* DE INKT IS EEN VARIABELE EN GEEN VASTE KLEUR, net als de grond erboven.
       Gevonden op 14 september 2026: de opening op de merkgrond zet `--ds-knop-grond` op papier
       en `--ds-knop-inkt` op kobalt, zodat een knop daar omgekeerd staat. Knoplink leest die
       tweede al (knoplink.css:78); Knop las alleen de eerste en hield zijn tekst wit. Op een
       witte grond gaf dat wit op wit: de knop was er wel en je las hem niet.
       De terugval is de kleur die hier stond, dus buiten zo'n omkering verandert er niets. */
    color: var(--ds-knop-inkt, var(--ds-color-text-on-ink));
  }
  /* Bij zweven naar diep, de grond die het merk daarvoor aanwijst. Stond op inverse.hover
     (inkt.950), en dat is een trede die het merk niet kent. */
  .ds-knop--hoofd:hover { background: var(--ds-knop-grond-zweef); }

  /* stil: dezelfde maat, een inzetring in plaats van een vlak. De tweede weg op een scherm. */
  .ds-knop--stil {
    background: var(--ds-color-surface-page);
    color: var(--ds-color-text-default);
    box-shadow: inset 0 0 0 var(--ds-border-hairline) var(--ds-color-border);
  }
  .ds-knop--stil:hover { background: var(--ds-color-surface-sunken); }

  /* plat: geen vlak. Draagt een streep, zodat kleur niet het enige verschil is met tekst. */
  .ds-knop--plat {
    background: none;
    color: var(--ds-color-text-accent);
    text-decoration: underline;
    text-underline-offset: var(--ds-link-streep-afstand);
  }
  .ds-knop--plat:hover { background: var(--ds-color-surface-sunken); }

  .ds-knop--normaal { padding: var(--ds-knop-binnenruimte); }
  .ds-knop--klein {
    min-block-size: var(--ds-maat-raakvlak-min);
    min-inline-size: var(--ds-maat-raakvlak-min);
    padding: var(--ds-space-tussen) var(--ds-space-binnen-blok);
    font: var(--ds-type-klein);
    font-weight: var(--ds-type-nadruk);
  }

  .ds-knop--breedte-inhoud    { inline-size: auto; }
  .ds-knop--breedte-vol       { inline-size: 100%; }
  .ds-knop--breedte-begrensd  { inline-size: 100%; max-inline-size: var(--ds-maat-knop-max); }

  /* Uitgeschakeld met tokens en niet met doorzichtigheid. Een opacity op een knop haalt zijn
     contrast omlaag met een factor die niemand narekent; dit paar is nagerekend en staat in het
     voorstel: color.text.muted op color.surface.sunken is 4,507:1. Kleur is bovendien niet het
     enige verschil, want de knop verliest ook zijn ring en zijn zweefstand, en draagt disabled
     als echt attribuut. */
  .ds-knop:disabled {
    cursor: not-allowed;
    background: var(--ds-color-surface-sunken);
    color: var(--ds-color-text-muted);
    box-shadow: none;
  }
  .ds-knop:disabled:hover { background: var(--ds-color-surface-sunken); }

  /* ingedrukt. De brief eist de toestand en het voorstel noemt hem bij Knop; hij stond hier niet,
     en een knop zonder ingedrukt geeft bij een trage verbinding geen enkel teken dat de klik is
     aangekomen. Er is geen token voor een ingedrukte vorm en fase 3 voegt er geen toe, dus het is
     een verplaatsing van een haarlijn: de knop zakt border.hairline naar beneden. Dat is geen
     kleurverschil, dus het werkt ook zonder kleurwaarneming, en het is geen animatie, dus het
     valt niet onder de beperking van beweging. Uit en bezig doen niet mee: een knop die niets
     doet, hoort ook niet in te veren. */
  .ds-knop:active:not(:disabled):not([aria-busy='true']) {
    transform: translateY(var(--ds-border-hairline));
  }

  .ds-knop[aria-busy='true'] { cursor: progress; }

}

/* === knoplink === */
/* Knoplink. Navigeren; handelen doet Knop.
 *
 * Canoniek: design/system/css/publiek.css:96 (.ev-btn--link), gemeten als ed648f9f274f, 428
 * gewogen over 20 routes. De ingangsknop van de publieke site staat hierop: Begin met uw naam.
 * De keuze is op criterium 1 gemaakt, standaarden, en niet op gewicht.
 *
 * Waarom dit een eigen bestand is en geen vorm van Knop. Een anker en een knop delen hun vorm
 * maar nooit hun betekenis: de browser navigeert bij de een en verstuurt bij de ander, en een
 * schermlezer kondigt ze verschillend aan. Het voorstel zegt daarom met zoveel woorden dat dit
 * onderdeel de vorm van Knop deelt maar nooit de code.
 *
 * Drie dingen die hier anders zijn dan vandaag, alle drie een standaardreparatie:
 *
 * 1. De kleur staat op elke linktoestand en niet alleen in rust. Vandaag wint a:hover van de
 *    knopregel en wordt de tekst van de hoofdknop oker op donkerblauw: 3,614:1 bij vet 16px
 *    waar 4,5 geldt (G045). Dit is de link waar elke bestelling op de publieke site langs komt.
 * 2. Het raakdoel staat in deze laag en niet in de binnenruimte, dus een knoplink kan zijn 44
 *    pixel niet verliezen.
 * 3. De focusring staat NIET in dit blad. Hij staat een keer in ds-basis.css, net als bij Knop en
 *    bij Link, want een waarde op twee plekken loopt uiteen zodra er een verandert. De audit vond
 *    vijf bedieningen die nooit een ring tonen; dat is opgelost door de ring een keer goed te
 *    zetten en niet door hem overal te herhalen.
 */

@layer componenten {
  .ds-knoplink {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--ds-space-tussen);
    min-block-size: var(--ds-maat-raakvlak);
    min-inline-size: var(--ds-maat-raakvlak);
    padding: var(--ds-knop-binnenruimte);
    border-radius: var(--ds-radius-control);
    /* Dezelfde rol als Knop: een link die eruitziet als een knop hoort ook zo te meten. */
    font: var(--ds-type-knop);
    text-align: center;
    text-decoration: none;
    cursor: pointer;
    transition: background-color var(--ds-motion-feedback);
  }

  /* De focusring staat NIET hier. Hij staat een keer in ds-basis.css op :focus-visible, uit
     color.focus, en Knop en Link doen het ook zo. Deze regel stond er wel, woord voor woord
     dezelfde drie declaraties, en dat is de dubbeling die principe 2 van de brief verbiedt: een
     waarde op twee plekken loopt uiteen zodra er een verandert. De derde onafhankelijke toets van
     fase 3 vond hem. */

  /* hoofd: de ingang. Kleur op elke toestand, want een los a:hover mag hem niet overnemen. */
  /* DE GROND VAN DE HOOFDKNOP IS EEN AFSPRAAK EN GEEN VASTE KLEUR, sinds 14 september 2026.
     Hij staat standaard op `surface.brand`, en dat gaat mis op een vlak dat diezelfde grond al
     draagt. Gemeten op de voorpagina bij 1280px: in een Opening met `--merk` was de knop een vlak
     van 185 bij 52 in oklch(0.426 0.115 256.6), op een grond van oklch(0.426 0.115 256.6).
     Dezelfde kleur tot op het cijfer. De letters staan er wit op, dus je leest de woorden en je
     ziet geen knop: "Begin met uw naam" las als losse tekst. Dat is wat Ernst zag.

     DE KLEURPOORT KON DIT NIET ZIEN, en dat is geen verwijt aan die poort. Hij weegt tekst tegen
     haar eigen grond, en wit op kobalt haalt de eis ruim. Een knop die niet van zijn pagina te
     onderscheiden is, is geen verschil tussen tekst en grond maar tussen twee gronden.

     WAAROM EEN VARIABELE EN NIET EEN REGEL BIJ DE OPENING OF EEN VARIANT HIER. Een onderdeel mag
     de klasse van een ander niet opmaken en `bouw.py` houdt dat tegen, dus `.ds-opening--merk
     .ds-knoplink--hoofd` kan aan geen van beide kanten. Een variant erbij zou een klasse erbij in
     de opmaak vragen, en dat is precies de reden waarom de sitevoet op 13 september tegen een
     `--op-inkt`-variant per onderdeel koos. Een variabele vraagt niets van de opmaak: wie een
     grond neerlegt, zegt erbij wat een knop daarop moet doen. `--beeld-verhouding` in Beeld is
     dezelfde afspraak.

     GEEN NIEUWE KLEUR. De omkering leent `surface.page` en de merkkleur die er al zijn. */
  .ds-knoplink--hoofd {
    /* Zie Knop: kobalt in rust, diep bij zweven. */
    background: var(--ds-knop-grond);
  }
  .ds-knoplink--hoofd,
  .ds-knoplink--hoofd:visited,
  .ds-knoplink--hoofd:hover,
  .ds-knoplink--hoofd:focus,
  .ds-knoplink--hoofd:active { color: var(--ds-knop-inkt); }
  /* Zie Knop. */
  .ds-knoplink--hoofd:hover { background: var(--ds-knop-grond-zweef); }

  /* stil: dezelfde maat, een inzetring in plaats van een vlak. De tweede weg op een scherm. */
  .ds-knoplink--stil {
    background: var(--ds-color-surface-page);
    box-shadow: inset 0 0 0 var(--ds-border-hairline) var(--ds-color-border);
  }
  .ds-knoplink--stil,
  .ds-knoplink--stil:visited,
  .ds-knoplink--stil:hover,
  .ds-knoplink--stil:focus,
  .ds-knoplink--stil:active { color: var(--ds-color-text-default); }
  .ds-knoplink--stil:hover { background: var(--ds-color-surface-sunken); }

  /* plat: geen vlak. Draagt een streep, zodat kleur niet het enige verschil is met tekst. */
  .ds-knoplink--plat {
    background: none;
    text-decoration: underline;
    text-underline-offset: var(--ds-link-streep-afstand);
  }
  .ds-knoplink--plat,
  .ds-knoplink--plat:visited,
  .ds-knoplink--plat:hover,
  .ds-knoplink--plat:focus,
  .ds-knoplink--plat:active { color: var(--ds-color-text-accent); }
  .ds-knoplink--plat:hover { background: var(--ds-color-surface-sunken); }

  .ds-knoplink--normaal { padding: var(--ds-knop-binnenruimte); }
  .ds-knoplink--klein {
    min-block-size: var(--ds-maat-raakvlak-min);
    min-inline-size: var(--ds-maat-raakvlak-min);
    padding: var(--ds-space-tussen) var(--ds-space-binnen-blok);
    font: var(--ds-type-klein);
    font-weight: var(--ds-type-nadruk);
  }

  .ds-knoplink--breedte-inhoud    { inline-size: auto; }
  .ds-knoplink--breedte-vol       { inline-size: 100%; }
  .ds-knoplink--breedte-begrensd  { inline-size: 100%; max-inline-size: var(--ds-maat-knop-max); }

  /* ingedrukt, dezelfde vorm als bij Knop en om dezelfde reden: de knoplink zakt border.hairline.
     De :active-regels hierboven gaan alleen over kleur en zijn daar om a:active niet van de
     knopregel te laten winnen; dit is de toestand zelf. */
  .ds-knoplink:active { transform: translateY(var(--ds-border-hairline)); }

}

/* === kop === */
/* Kop. De koppenladder, en niets anders.
 *
 * Canoniek: design/system/css/publiek.css:62 (h1), :241 (h2) en :244 (h3), het enige stijlblad
 * dat alle vier de niveaus zet. Criterium standaarden.
 *
 * HET NIVEAU STAAT NIET IN DIT BESTAND. Er is geen regel die op h1, h2, h3 of h4 selecteert,
 * en dat is de hele vondst: de audit gaf vier koppenfamilies een en dezelfde vingerafdruk
 * (a209e948bc1e, G032), want een vingerafdruk is niet vier koppenniveaus. De vorm zit in de
 * klasse en het niveau in het element, zodat een kop nooit een niveau overslaat om kleiner te
 * lijken.
 *
 * De oude tokennamen logen daarover: --ev-t-h1 draagt in beide stijlbladen de h2 en --ev-t-h2
 * de h3. type.titel en type.sectie repareren die naam-naar-waarde-verwarring.
 *
 * Marges staan hier niet. Ze komen uit Stapel en Sectie, want een marge op een kop stapelt op
 * een marge op de tekst erboven, en dat is de oorzaak van de 15, 43, 29 en 21px die de meting
 * naast de ruimtetrap vond.
 */

@layer componenten {
  /* Koppen dragen de volle tekstkleur. De reset zet body op color.text.body; zonder deze regel
     zou een kop de kleur van lopende tekst erven en dat is een andere kop dan vandaag. */
  .ds-kop { color: var(--ds-color-text-default); }

  /* De vorm bepaalt de maat. hero is de enige vloeiende typestap van het systeem. */
  /* De aantrekking hoort bij de rol maar past niet in de kortschrijfwijze `font`, die geen
     letter-spacing draagt. Hij staat er dus naast, en design/system/onderdelen/bouw.py weigert
     een regel die de rol wel zet en de aantrekking niet. Modern Delft trekt een kop aan naar
     gelang zijn maat: -0,032em op niveau 1, -0,022em op 2, -0,01em op 3. */
  .ds-kop--hero   { font: var(--ds-type-hero);   letter-spacing: var(--ds-type-hero-spatiering); }
  .ds-kop--titel  { font: var(--ds-type-titel);  letter-spacing: var(--ds-type-titel-spatiering); }
  .ds-kop--sectie { font: var(--ds-type-sectie); letter-spacing: var(--ds-type-sectie-spatiering); }
  /* tekst: de leesletter, vet. De enige vorm zonder displayletter, voor een kop die in de
     lopende tekst staat in plaats van erboven. font-weight staat na font, want de
     font-kortschrijfwijze zet hem anders terug op normaal. */
  .ds-kop--tekst  { font: var(--ds-type-brood); font-weight: var(--ds-type-nadruk); }

  /* Logische eigenschappen, want tegenover twee logische staan er 233 fysieke in de repo. */
  .ds-kop--begin  { text-align: start; }
  .ds-kop--midden { text-align: center; }
}

/* === lijst === */
/* Lijst. Een opsomming, met of zonder teken.
 *
 * Canoniek: etalage/index.html:236 (c3838c334a2e) voor de vorm met een teken en
 * etalage/index.html:228 (2ec11ec7fd7b) voor de kale vorm, die in publiek.css:212 staat als
 * .ev-voet__lijst.
 *
 * Waarom het teken een prop is en geen canoniek. Bij F17 won criterium 2 met 1.376 tegen 140,
 * waardoor de lijst zonder teken canoniek zou worden terwijl de basisregel van de browser de
 * lijst met teken is. D0006 en D0054 staan allebei op bedoeld, met als reden dat listStyleType
 * navigatie van lopende tekst scheidt: de audit rekent listStyleType 40 keer bedoeld tegen 18
 * keer verloop. Wie het teken tot canoniek maakt, canoniseert de ene helft van een onderscheid
 * dat de audit zelf als bedoeld beoordeelde. Dus vier tekens, en geen van de vier is de norm.
 *
 * Deze laag zet geen lettermaat en geen tekstkleur. Dat doet Tekst, en de regels erven hem.
 * dichtheid gaat alleen over de ruimte tussen twee regels.
 */

@layer componenten {
  .ds-lijst {
    display: flex;
    flex-direction: column;
    gap: var(--lijst-ruimte, var(--ds-space-binnen-blok));
    margin: 0;
  }
  .ds-lijst--ruim  { --lijst-ruimte: var(--ds-space-binnen-blok); }
  .ds-lijst--dicht { --lijst-ruimte: var(--ds-space-inline); }

  /* De reset zet list-style uit op elke ul en ol met een klasse. De twee vormen met een teken
     zetten hem hier terug, want een teken dat de reset weghaalt is geen ontwerpkeuze meer.
     Een flexkolom toont geen markers, dus de twee vormen met een teken staan als blok. */
  .ds-lijst--stip,
  .ds-lijst--nummer {
    display: block;
    padding-inline-start: var(--ds-space-blok);
  }
  .ds-lijst--stip { list-style: disc; }
  .ds-lijst--nummer { list-style: decimal; }
  .ds-lijst--stip > .ds-lijst__regel,
  .ds-lijst--nummer > .ds-lijst__regel {
    display: list-item;
    margin-block-start: var(--lijst-ruimte, var(--ds-space-binnen-blok));
  }
  .ds-lijst--stip > .ds-lijst__regel:first-child,
  .ds-lijst--nummer > .ds-lijst__regel:first-child { margin-block-start: 0; }

  /* De kale vorm: navigatie en de vier voetkolommen. Geen teken, geen inspringing. */
  .ds-lijst--geen { padding-inline-start: 0; list-style: none; }

  /* Begrippen: het begrip in de displayletter, de uitleg eronder in de leesletter. Dit is de
     woordenlijst in het boek en dezelfde vorm als de sleutelrij, maar dan onder elkaar. */
  .ds-lijst--begrippen > .ds-lijst__paar {
    display: flex;
    flex-direction: column;
    gap: var(--ds-space-inline);
  }
  .ds-lijst__begrip {
    font: var(--ds-type-brood);
    font-weight: var(--ds-type-nadruk);
    color: var(--ds-color-text-default);
  }
  .ds-lijst__uitleg { margin: 0; color: var(--ds-color-text-body); }

  /* De zebratint. Kleur draagt hier nooit alleen de betekenis: hij verdeelt regels en zegt
     niets over de regel zelf. Wie er betekenis in legt, bouwt een tabel zonder kopcellen. */
  .ds-lijst--zebra > .ds-lijst__regel:nth-child(even),
  .ds-lijst--zebra > .ds-lijst__paar:nth-child(even) {
    background: var(--ds-color-surface-sunken);
    padding-inline: var(--ds-space-binnen-blok);
    margin-inline: calc(-1 * var(--ds-space-binnen-blok));
  }
  .ds-lijst--zebra > .ds-lijst__regel,
  .ds-lijst--zebra > .ds-lijst__paar { padding-block: var(--ds-space-inline); }
}

/* === link === */
/* Link. Navigeren; handelen doet Knop.
 *
 * Canoniek: design/system/css/publiek.css:37-39 voor de vorm tekst, en commit 599ea486 van
 * 11 september 2026 14:15 (publiek.css:229-233) voor de vorm navigatie. Criterium recent.
 *
 * DE ZWAARSTE REPARATIE ZIT IN DE FLOW. site.css:30 zet a op --ev-accent zonder streep: oker op
 * registerpapier is 3,806:1 waar 4,5 geldt, en zonder streep is een link in een alinea alleen
 * aan zijn kleur te herkennen. publiek.css deed die reparatie op 11 september 2026 en site.css
 * heeft hem nooit gekregen (B022). Hier staat hij een keer, voor allebei de oppervlakken.
 *
 * De okeren streep is een vorm en geen kleurverschil: de letters blijven inkt (11,770:1) en de
 * streep draagt de oker. Dat is de regel link-in-text-block.
 *
 * De kleur staat in plaatselijke variabelen en niet in een reeks selectors die elkaar met
 * specificiteit verslaan. --link-kleur draagt geen ds-voorvoegsel en is dus plaatselijk: de
 * prop op verzet alleen die drie waarden, en de regels voor rust, bezocht, huidig en zweven
 * blijven alle vier op dezelfde specificiteit staan.
 *
 * De focusring staat hier niet. Hij staat een keer in ds-basis.css op :focus-visible, uit
 * color.focus, zodat geen enkel onderdeel hem kan vergeten of net iets anders kan zetten.
 * Vandaag bestaat er in negen stijlbladen geen enkele focus-visible-regel voor een link.
 */

@layer componenten {
  .ds-link {
    --link-kleur: var(--ds-color-text-default);
    --link-kleur-zweef: var(--ds-color-text-accent);
    --link-streep: var(--ds-link-streep-kleur);
    color: var(--link-kleur);
  }

  /* tekst: tussen gewone woorden. De streep is er altijd, want hier moet je hem kunnen vinden. */
  .ds-link--tekst {
    text-decoration: underline;
    text-decoration-color: var(--link-streep);
    text-decoration-thickness: var(--ds-border-hairline);
    text-underline-offset: var(--ds-link-streep-afstand);
  }

  /* navigatie: in een lijst waar elke regel een link is. Geen streep in rust, want zeventien
     links onder elkaar met een streepje eronder zijn een gearceerd blok en geen lijst. De
     binnenruimte staat er om het raakvlak op maat.raakvlak-min te krijgen (WCAG 2.5.8); daarom
     is dit de enige vorm die inline-block is. */
  .ds-link--navigatie {
    display: inline-block;
    padding-block: var(--ds-space-inline);
    min-block-size: var(--ds-maat-raakvlak-min);
    text-decoration: none;
  }

  /* op="papier" staat hierboven al: dat is de grond van elk schermoppervlak en dus de basis.
     De klasse .ds-link--papier bestaat wel in de markup, zodat de vingerafdrukregistratie beide
     gronden ziet, maar zij hoeft hier niets te verzetten.

     op="inkt": de kop en het omslag. Alleen de drie waarden verzetten, geen enkele regel erbij. */
  .ds-link--inkt {
    --link-kleur: var(--ds-color-text-on-ink-muted);
    --link-kleur-zweef: var(--ds-color-text-on-ink);
    --link-streep: var(--ds-color-mark-on-ink);
  }

  /* Bezocht is dezelfde link. Hij staat hier omdat de toestand dan bestaat en vastgezet is:
     zonder deze regel hangt hij aan de vraag of een pagina verderop nog een a:visited schrijft. */
  .ds-link:visited { color: var(--link-kleur); }

  /* De huidige pagina. Kleur draagt de betekenis niet alleen: het gewicht verschilt ook, en op
     inkt gaat de tekst bovendien van de stillere naar de volle papierkleur. */
  .ds-link[aria-current='page'] { font-weight: var(--ds-type-nadruk); }
  .ds-link--inkt[aria-current='page'] { --link-kleur: var(--ds-color-text-on-ink); }

  /* Zweven staat achteraan, zodat hij van bezocht en van huidig wint zonder een selector die
     zwaarder weegt. De streep neemt de tekstkleur over: een link die je aanwijst is een ding en
     geen tekst met een streepje. */
  .ds-link:hover { color: var(--link-kleur-zweef); }
  .ds-link--tekst:hover { text-decoration-color: currentColor; }
  .ds-link--navigatie:hover {
    text-decoration: underline;
    text-decoration-color: currentColor;
    text-decoration-thickness: var(--ds-border-hairline);
    text-underline-offset: var(--ds-link-streep-afstand);
  }
}

/* === melding === */
/* Melding. Een mededeling van het systeem die niet bij een veld hoort. Hoort hij bij een veld,
 * dan is het Veldgroep; is het een handeling die loopt, dan is het Wachtblok.
 *
 * Canoniek: pipeline/templates/site/vier.html:24, de enige foutbanner van de flow met
 * role="alert" die de server invult. Gekozen op standaarden, want het systeem heeft vandaag
 * geen enkele mededelingsvorm: negen containers in de flow melden iets met een script en vijf
 * daarvan dragen geen rol (B026).
 *
 * TWEE TONEN EN NIET VIER. De tokenlaag draagt een foutkleur en verder geen betekeniskleur.
 * Let op, gelukt en bezig zouden drie nieuwe kleuren zijn en dat is een herontwerp; bezig is
 * bovendien geen melding maar het Wachtblok. Een eigen grond en kleur per toon staat in
 * herontwerp en niet hier.
 *
 * HET GEBIED DRAAGT GEEN VORM. Alle vorm zit in het blok erbinnen, dat er alleen is als er
 * iets te melden valt. Daardoor kan het gebied altijd in de dom staan zonder dat een lege
 * melding een gat in de pagina slaat, en dat is nodig: een schermlezer leest een wissel alleen
 * als het gebied er al stond voordat de inhoud kwam.
 */

@layer componenten {
  /* Een leeg gebied maakt geen doos. display: contents en niet display: none, want een gebied
     dat van none naar block springt telt bij een deel van de schermlezers als een nieuw
     element en niet als een wissel, en dan blijft de melding onuitgesproken. */
  .ds-melding:empty { display: contents; }

  .ds-melding__blok {
    padding: var(--ds-space-blok);
    border-radius: var(--ds-radius-control);
    background: var(--ds-color-surface-sunken);
    color: var(--ds-color-text-body);
    /* De plakkende kop mag de melding niet afdekken als het blok zichzelf in beeld brengt. */
    scroll-margin-block-start: var(--ds-space-sectie);
  }

  /* De fouttoon: color.text.danger haalt 4,877 op color.surface.sunken, en color.border.danger
     haalt daar dezelfde 4,877, want het is dezelfde kleur. Hier stond 3,311 voor die rand en dat
     is de verhouding van color.mark, een kleur die hier niet staat. Kleur draagt de betekenis niet
     alleen: er staat een teken en een woord bij. */
  .ds-melding--fout .ds-melding__blok {
    border: var(--ds-border-hairline) solid var(--ds-color-border-danger);
  }

  .ds-melding__kop {
    font: var(--ds-type-brood);
    font-weight: var(--ds-type-nadruk);
    color: var(--ds-color-text-default);
  }
  .ds-melding--fout .ds-melding__kop { color: var(--ds-color-text-danger); }

  /* Het teken. Zijn maat is een verhouding van de letter ernaast en geen ruimtestap, zodat hij
     met de tekst meegroeit op 200 procent zoom; er is geen pictogrammaat in de tokens. De ring
     is currentColor, dus hij volgt de kleur van de toon en kan er niet van afwijken. */
  .ds-melding__teken {
    flex: 0 0 auto;
    display: grid;
    place-items: center;
    inline-size: 1.5em;
    block-size: 1.5em;
    border-radius: var(--ds-radius-pil);
    box-shadow: inset 0 0 0 var(--ds-border-hairline) currentColor;
    font-weight: var(--ds-type-nadruk);
  }

  .ds-melding__tekst { max-inline-size: var(--ds-maat-regel); }
}

/* === naamrij === */
/* Naamrij. Een invoerveld met een knop ernaast, samen een bediening.
 *
 * Canoniek: de merkbron, `bundel/stijl.css` regel 177 tot 179, op de jaargang die het merkspoor
 * op 12 september 2026 stempelde (`origin/ontwerp/modern-delft`, `7ab18dc`, jaargang
 * `423fc022`). Negenenvijftig voorkomens, en daarmee het zwaarste stuk van wat het register
 * `Veldraster` noemde.
 *
 * HIJ HOORDE NIET BIJ VELDRASTER, EN DAT IS DE REDEN DAT HIJ APART STAAT. Het register beeldde
 * dertien klassen op een onderdeel af; gemeten op 13 september met
 * `design/system/klassentelling.py` zijn dat er drie: deze formulierrij (59), de wand met tegels
 * die omdraaien (191) en een kolom met namen per generatie (30). Deze rij is geen raster en heeft
 * niets met een kwartierstaat te maken.
 *
 * HIJ SCHRIJFT NIET IN `.ds-veld` EN `.ds-knop`, EN DAT IS EEN ECHTE BEPERKING GEWEEST. De
 * merkbron zet `flex` rechtstreeks op `.naamrij .veld` en `.naamrij .knop`. Dat mag hier niet:
 * `bouw.py` laat een onderdeel alleen zijn eigen klassen schrijven, en terecht, want zo kan geen
 * enkel onderdeel de maat van een ander van buitenaf veranderen. De groei zit daarom op een eigen
 * wikkel (`__groei`) die de macro om het veld zet, en de knop krijgt niets: wat niet groeit,
 * hoeft niets te verklaren.
 *
 * WAAROM DE RUIMTE 8 EN GEEN 10 IS. De merkbron zet 10px en dat is geen trede op de ruimteladder;
 * hij ligt tussen space.tussen (8) en space.binnen-blok (12). Gekozen: 8, want een veld en een
 * knop die samen één bediening vormen horen dicht op elkaar, en van de twee treden is dat de
 * enige die dat zegt. Twee pixels, geen inhoud, en terug te draaien door de rol te wisselen.
 */

@layer componenten {
  .ds-naamrij {
    display: flex;
    flex-wrap: wrap;
    align-items: stretch;
    gap: var(--ds-space-tussen);
    inline-size: 100%;
    max-inline-size: var(--ds-naamrij-maat);
  }

  /* Het veld groeit, en `min-inline-size: 0` erbij want een flexkind krimpt van zichzelf niet
     onder zijn inhoud; zonder die regel duwt een lange placeholder de knop uit de rij. */
  .ds-naamrij__groei {
    flex: 1 1 auto;
  }

  /* Alles wat geen veld is houdt zijn eigen maat en breekt niet af. Dat is de knop, en het is
     geen selector op `.ds-knop`: dit onderdeel weet niet wat er naast het veld staat en dat is
     de bedoeling. */
  .ds-naamrij > *:not(.ds-naamrij__groei) {
    flex: 0 0 auto;
    white-space: nowrap;
  }

  /* SMAL SLAAT HIJ OM, EN DAT DOET HIJ ZONDER VRAAG. `flex-wrap: wrap` hierboven plus een
     ondergrens op het veld: past de knop er niet meer naast, dan zakt hij naar zijn eigen regel.
     Dat hangt aan wat er werkelijk naast staat en niet aan een breedte die iemand opgeschreven
     heeft, en het werkt dus ook als deze rij in een smalle flowkaart staat in plaats van in een
     brede kolom.

     Hier stond een containervraag en die KAN NIET: een container kan zijn eigen opmaak niet uit
     zijn eigen breedte halen, dat is rond. En de merkbron heeft voor deze rij helemaal geen
     smalle stand; ik had er een verzonnen. Wat hier staat is wat flex zelf al doet. */
  .ds-naamrij__groei { min-inline-size: var(--ds-naamrij-veld-min); }
}

/* === onthuller === */
/* Onthuller. Een blok dat bij het scrollen in beeld komt in plaats van er te staan.
 *
 * Canoniek: de merkbron, `bundel/stijl.css` regel 194 tot 197, op de jaargang die het
 * merkspoor op 12 september 2026 stempelde (`origin/ontwerp/modern-delft`, `7ab18dc`,
 * jaargang `423fc022`). Met 531 voorkomens over 29 bestanden is dit het op een na
 * zwaarste patroon van de nieuwe site en het zwaarste dat uit een enkele klasse bestaat.
 *
 * DE TOKENS BESTONDEN AL EN HADDEN GEEN GEBRUIKER. `motion.enter` (900ms),
 * `motion.onthul-afstand` (30px smal, 48px boven 900px) en `motion.onthul-tussenpoos`
 * (90ms) zijn op 12 september in de tokenlaag gezet toen de merkrichting landde, met de
 * merkbron als herkomst erbij. Dit onderdeel is hun eerste gebruiker; er is hier geen
 * enkele nieuwe waarde bijgekomen.
 *
 * DE GEVAARLIJKE KANT VAN DIT ONDERDEEL, en daarom staat hij bovenaan. Een onthuller zet
 * `opacity: 0`. Komt de klasse die hem terugzet er niet, dan is de inhoud onzichtbaar en
 * niet stuk: geen foutmelding, geen lege plek in de opmaak, gewoon weg.
 *
 * DAAROM VERBERGT DE KALE KLASSE NIETS. `.ds-onthuller` alleen doet niets zichtbaars. Pas
 * `--gewapend` verbergt, en die zet `onthuller.js` uitsluitend VANUIT DE TERUGROEP van de
 * waarnemer die datzelfde element al volgt. Een gewapend element is daarmee het bewijs van zijn
 * eigen waarnemer: hij kan niet gewapend raken zonder dat die waarnemer voor hem gevuurd heeft,
 * dus er is geen toestand waarin iets verborgen is zonder dat er iemand is die hem weer
 * tevoorschijn haalt.
 *
 * Bij het merk hing dit aan `.js` op de wortel. Dat werkt ook, maar het hek staat dan ver van
 * wat het beschermt: elke onthuller op de pagina hangt aan een klasse die ergens anders gezet
 * is, en tussen "er draait een script" en "dit element wordt waargenomen" zit alles wat er
 * misgaat. De bouwer van dit systeem weigerde zo'n wortelklasse bovendien terecht, want een
 * onderdeel mag alleen zijn eigen klassen schrijven; die regel wees hier naar de betere vorm.
 *
 * Twee hekken staan er nog omheen, en allebei falen ze de goede kant op:
 *
 *   1. Onder `prefers-reduced-motion: reduce` verbergt ook `--gewapend` niets, en dat is
 *      niet hetzelfde als "de overgang duurt 0,01ms" uit ds-basis.css. Die regel haalt de
 *      beweging weg en zet `opacity` niet terug; een blok dat om welke reden dan ook nooit
 *      `--in` krijgt, blijft dan onzichtbaar. Vandaar hier een eigen regel die de
 *      begintoestand opheft in plaats van hem sneller te maken.
 *   2. `--in` is de enige toestand die iets zichtbaar maakt, en hij hoeft alleen te komen
 *      als `--gewapend` er is.
 *
 * `test_onthuller.py` legt die drie vast, want ze zijn geen van drieën aan het beeld te
 * zien: een pagina waar dit misgaat ziet er leeg uit en niet kapot. En `onthulpoort.mjs`
 * doet in een echte browser wat een broncontrole niet kan: een blok neerzetten, kijken of
 * het weg is, en kijken of het terugkomt.
 */

@layer componenten {
  /* De kale klasse verbergt NIETS. Zie de kop: dat is het verschil tussen een onthulling en
     een blok dat je kwijt bent. */
  .ds-onthuller--gewapend {
    opacity: 0;
    transform: translateY(var(--ds-motion-onthul-afstand));
  }

  /* Een tegel komt niet alleen omhoog maar ook naar voren. Twee eigenschappen tegelijk, en
     de afstand is korter: een kaart die 48px omhoog schuift duwt de rij ernaast weg. */
  .ds-onthuller--gewapend.ds-onthuller--schaal {
    transform: translateY(var(--ds-motion-onthul-afstand-tegel)) scale(.94);
  }

  /* DE OVERGANG STAAT HIER EN NIET OP DE REGEL HIERBOVEN, EN DAT IS GEMETEN EN GEEN SMAAK.
     Een overgang wordt gelezen uit de stand waar hij HEEN gaat. Stond hij op `--gewapend`, dan
     zou het wapenen zelf een overgang zijn: het blok vervaagt dan in 900ms van zichtbaar naar
     weg, en pas daarna kan het terugkomen. Zo stond het op 13 september 2026, en de onthulpoort
     mat het: een net gewapend blok stond op opacity 0,02 in plaats van 0, midden in een
     verdwijning die niemand besteld heeft.

     Dat is onzichtbaar voor een lezer, want wapenen gebeurt alleen onder de onthullijn. Het is
     wel fout: het script en de stijl beloven een begintoestand, en wat er werkelijk staat is een
     trage verdwijning. Hier gaat het wapenen ineens en beweegt alleen het onthullen. */
  .ds-onthuller--gewapend.ds-onthuller--in {
    opacity: 1;
    transform: none;
    transition:
      opacity var(--ds-motion-enter) var(--ds-motion-onthul-kromme),
      transform var(--ds-motion-enter) var(--ds-motion-onthul-kromme);
    /* De tussenpoos komt uit `--ds-onthuller-volgorde` en niet uit een selector per kind.
       Een `:nth-child` zou de volgorde aan de opmaak hangen; deze waarde hangt aan wat de
       pagina bedoelt, en dat is niet altijd de domvolgorde. */
    transition-delay: calc(var(--ds-onthuller-volgorde, 0) * var(--ds-motion-onthul-tussenpoos));
  }

  /* Wie beweging uitzet, krijgt de pagina compleet en niet leeg. Dit heft de begintoestand
     op; ds-basis.css maakt alleen de overgang korter en dat is hier niet genoeg.

     Alle drie de selectors staan erbij, en de derde is geen sier: `--gewapend.--in` is
     specifieker dan `--gewapend`, dus zonder die regel blijft de overgang van de onthulling
     staan terwijl de lezer beweging heeft uitgezet. */
  @media (prefers-reduced-motion: reduce) {
    .ds-onthuller--gewapend,
    .ds-onthuller--gewapend.ds-onthuller--schaal,
    .ds-onthuller--gewapend.ds-onthuller--in {
      opacity: 1;
      transform: none;
      transition: none;
    }
  }
}

/* === opening === */
/* Opening. Het bovenste blok van een publieke pagina.
 *
 * Canoniek: web/publiek/sjablonen/_foto.html:59 met publiek.css .ev-opening, gemeten als
 * etalage/index.html:102 (7ec88233), 20 pagina's in de kolomvorm en 7 in de beeldvorm.
 *
 * Wat hier anders is dan vandaag: de opening blijft binnen main in plaats van erbuiten te worden
 * gehaald om een schermbreed beeld mogelijk te maken. Daar komen alle 70 publieke region-knopen
 * vandaan, en de voorpagina draagt er bovendien een tweede banner door.
 *
 * Hoe het beeld dan wel tot de schermrand komt. De opening is zelf de volle breedte en zet zijn
 * eigen leeskolom binnenin; het paginasjabloon zet hem daarom boven de kolom en niet erin. Hier
 * stond een uitbraak met `inline-size: 100vw` plus `margin-inline-start: 50%` en een terugschuif,
 * en die heeft twee gaten. Het kleine: 100vw telt de klassieke schuifbalk mee en de pagina wordt
 * dan breder dan het venster, wat de brief verbiedt. Het grote: een Beeld met vorm volle-breedte
 * erin neemt daarna nog eens de goot van de kolom terug, en dan schuift de pagina op elke breedte
 * 22px. Gemeten op 11 september 2026 op 320, 360, 768, 1280 en 1920: scrollWidth min clientWidth
 * was 22 op alle vijf. Een blok dat zelf de volle breedte is, hoeft nergens uit te breken en kan
 * dus ook niet te ver breken.
 *
 * De plaatsing komt van Stapel. Dit blad zet alleen wat de opening zelf is: de volle breedte, de
 * leeskolom binnenin en de leesregel van de lead.
 */

@layer componenten {
  /* De opening staat buiten de leeskolom en is zelf zo breed als zijn ouder. Daarom geen enkele
     vw-waarde en geen negatieve marge: er valt niets uit te breken. */
  .ds-opening {
    display: block;
    inline-size: 100%;
  }

  /* De inhoud komt terug in de leeskolom, met dezelfde breedte en dezelfde goot als Kolom. Die
     twee tokens staan hier een tweede keer omdat een onderdeel niet in de opmaak van een ander
     schrijft; de waarden zijn dezelfde en veranderen mee. */
  .ds-opening__inhoud {
    max-inline-size: var(--ds-maat-kolom);
    margin-inline: auto;
    padding-inline: var(--ds-space-blok);
  }
  @media (width > 900px) {
    .ds-opening__inhoud { max-inline-size: var(--ds-maat-kolom-breed); }
  }

  /* De leesregel van de lead. De meting vond 205 alinea's van 90,7ch mediaan, ruim boven de grens; maat.regel is de
     grens uit de brief.

     EN `min()` EROMHEEN, WANT EEN VASTE LEESMAAT IS OP EEN SMAL SCHERM GEEN GRENS MAAR EEN EIS.
     Dit blok is een flexkind op de dwarsas met `align-items` op begin, dus het krijgt de breedte
     die het vraagt en niet die van zijn ouder. Wat het vraagt is de maat hierboven, of de
     min-content-breedte van zijn inhoud als die groter is: bij een kop in de heromaat is dat één
     lang woord. Gemeten op 13 september 2026 met de stijlgids op 320px: "Herroepingsrecht" op
     30px is 253px breed, de opening is daar 224px, en de pagina schoof 5px.
     `overflow-wrap: break-word` op de Kop kon niets doen, want het blok eromheen gaf hem de
     ruimte die hij vroeg. Met `min(..., 100%)` is de leesmaat een grens zolang hij past en
     anders de ouder, en dan breekt het woord wel. `min-inline-size: 0` alleen hielp niet: dat
     laat een flexkind krimpen en dit kind werd niet gekrompen maar te ruim gemeten.

     Deze val is met een klassenaam niet te zien; overlooppoort.mjs vond hem. */
  .ds-opening__tekst {
    max-inline-size: min(var(--ds-maat-regel), 100%);
  }

  /* Het beeld vult de volle breedte van de opening en dus van de pagina. */
  .ds-opening--beeld .ds-opening__beeld {
    inline-size: 100%;
    margin-block-end: var(--ds-space-blok-groot);
  }

  /* De kolomvorm begint met lucht boven de titel; de beeldvorm begint met het beeld en staat
     daarom vlak tegen de kop van de pagina aan. Dat is het enige verschil tussen de twee
     buiten het beeld zelf. */
  .ds-opening--kolom,
  .ds-opening--naast {
    padding-block-start: var(--ds-space-blok-groot);
  }

  /* DE DERDE VORM: HET VOORWERP NAAST DE TEKST, en dat is de STANDAARD van de merkbron en geen
     uitzondering. Daar is `.opening` een raster van 7fr naast 4fr met het voorwerp rechts, en
     `.opening.zonder-beeld` is de variant die dat raster naar 8fr naast 3fr zet en de tweede
     kolom leeg laat. Wij hadden alleen die tweede (`--kolom`) en de schermbrede (`--beeld`).
     Gemeten op 13 september 2026 in stijl.css van de gestempelde jaargang, regel 233 tot 235.

     Onder de omslagbreedte staat het voorwerp onder de tekst en niet ernaast: een kaft van
     vierhonderd pixels naast een leesregel van 320 laat van geen van beide iets over. De
     merkbron doet dat op 900px met een mediavraag; hier is het een containervraag op de opening
     zelf, want dezelfde opening staat op een productpagina in de volle breedte en straks in een
     smaller oppervlak, en dan is het venster het verkeerde ding om te meten. */
  /* EN DE BREED-VORM STAAT OP DE DOCUMENTBREEDTE, WANT DAAR ZET DE MERKBRON HEM.
     Toegevoegd 14 september 2026. De kolomvorm zet zijn inhoud op `maat.kolom-breed` (720px) en
     centreert hem; dat is een leesmaat en het is niet wat staging doet. Gemeten op
     staging.erfverhaal.nl bij 1280px: `.wrap` is 1178 breed en begint op x51, en de kop erin is
     810 breed en begint op diezelfde x51. Op het naamoppervlak stond dezelfde kop op x312 met een
     breedte van 656, dus een smalle kolom midden op de pagina. Zelfde letters, zelfde gewicht,
     andere bladspiegel, en dat is het eerste wat je ziet als je de twee naast elkaar zet.

     EEN VORM ERBIJ EN NIET `--kolom` VERBREED, want die staat onder tien pagina's die live zijn
     (voorwaarden, methode, privacy en zeven andere). Die horen ook naar de documentbreedte, maar
     dat is een zichtbare verandering aan wat er vandaag op erfverhaal.nl staat en dus een aparte
     stap met Ernst erbij. De tekst houdt zijn leesmaat: `__tekst` blijft op `maat.regel`, dus de
     regellengte verandert niet, alleen waar de kolom begint. */
  .ds-opening--breed .ds-opening__inhoud {
    /* De goot telt er net als bij Kolom bovenop en niet vanaf; zie ds-primitieven.css. */
    max-inline-size: calc(var(--ds-maat-document) + 2 * var(--ds-space-blok));
  }

  /* EN DE NAAST-VORM IS BREDER DAN DE LEESKOLOM, want er staat een voorwerp naast de tekst.
     `maat.kolom-breed` (720px) is de maat van een LEESREGEL; deelt een boek van 400px die
     breedte, dan houdt de tekst er 300 over en dat leest niet meer. De merkbron zet deze opening
     op de documentbreedte en niet op de leesbreedte; daar staat hij in `.wrap`. */
  .ds-opening--naast .ds-opening__inhoud {
    max-inline-size: var(--ds-maat-document);
    display: grid;
    grid-template-columns: minmax(0, 7fr) minmax(0, 4fr);
    column-gap: var(--ds-space-sectie);
    row-gap: var(--ds-space-blok);
    align-items: start;
  }
  /* DE CEL VULT ZIJN KOLOM EN HET VOORWERP LIJNT RECHTS UIT, en niet andersom. Met
     `justify-self: end` op de cel zelf krimpt die tot fit-content, en een Boek is
     `inline-size: min(100%, boek.maat)`: honderd procent van nul is nul. Gemeten op
     13 september 2026: het boek stond op 0px breed naast de tekst en er was niets te zien. */
  .ds-opening--naast .ds-opening__voorwerp {
    inline-size: 100%;
    display: flex;
    justify-content: flex-end;
  }

  /* DRIE KINDEREN IN TWEE KOLOMMEN, EN DAAROM STOND HET BOEK ONDER DE TEKST.
     Gevonden op 14 september 2026 door de voorpagina naast de merkbron te leggen: bij ons stond
     de kaft onder de tekst, bij hen ernaast. Het raster hierboven is goed en de containervraag
     ook; wat ontbrak was de PLAATSING.

     De opening draagt drie kinderen (tekst, oproep, voorwerp) en het raster heeft twee kolommen.
     Zonder plaatsing verdeelt de browser ze in bronvolgorde: tekst naar (1,1), oproep naar (1,2)
     en het voorwerp valt door naar (2,1). Het boek stond dus niet naast de tekst maar eronder,
     in de linkerkolom, en de rechterkolom droeg de knop. Dat is met een klassenaam niet te zien:
     `ds-opening--naast` stond er gewoon, en de containervraag deed precies wat hij moest.

     Tekst en oproep horen bij elkaar in de leeskolom; het voorwerp staat rechts en spant beide
     rijen, zodat een kaft van vierhonderd pixels naast de hele tekst staat en niet naast de helft.
     `span 2` en niet `1 / -1`: een opening zonder oproep heeft maar een rij, en dan zou `-1`
     hem over een rij spannen die er niet is. */
  .ds-opening--naast .ds-opening__tekst,
  .ds-opening--naast .ds-opening__oproep {
    grid-column: 1;
  }
  .ds-opening--naast .ds-opening__voorwerp {
    grid-column: 2;
    grid-row: 1 / span 2;
  }

  @container ds-opening (width < 760px) {
    .ds-opening--naast .ds-opening__inhoud {
      grid-template-columns: minmax(0, 1fr);
    }
    .ds-opening--naast .ds-opening__voorwerp {
      justify-content: flex-start;
    }
    /* EN DE PLAATSING TERUG, want in een raster van EEN kolom bestaat kolom 2 niet. Zonder deze
       drie regels zou het voorwerp in een impliciete tweede kolom belanden en de bladzijde
       breder maken dan het scherm. */
    .ds-opening--naast .ds-opening__tekst,
    .ds-opening--naast .ds-opening__oproep,
    .ds-opening--naast .ds-opening__voorwerp {
      grid-column: 1;
      grid-row: auto;
    }
  }
  .ds-opening {
    container: ds-opening / inline-size;
  }

  /* DE DONKERE GROND. In de merkbron heet hij `op-blauw` en hij staat op 8 secties over 5 van de
     29 bladen; geteld op 14 september 2026. Hij is geen variant van de VORM maar een eigenschap
     die over alle vormen heen ligt: een kolomopening, een naastopening en een beeldopening kunnen
     alle drie op inkt staan.

     WAT HIJ WEL EN NIET RAAKT. Hij zet de grond en de kleuren van wat er binnen deze opening
     staat, en verder niets. De Sitekop erboven krijgt zijn eigen `grond` van de PAGINA; zie de
     kop van dit onderdeel voor waarom dat niet vanuit hier mag.

     DE GROND IS KOBALT EN NIET DIEP, en dat is in een browser gemeten: de opening van de merkbron
     is rgb(31, 78, 140) en de voet rgb(18, 50, 92). Dat zijn twee rollen die het systeem al uit
     elkaar houdt, `surface.brand` en `surface.inverse`, met de reden erbij ("in Modern Delft is
     dat diep en niet kobalt"). Daarom staat hier `surface.brand` en in de voet `surface.inverse`.

     En daarom is de zachte tekst hier WIT en niet `wassing`. Wit haalt op kobalt 8,31; `wassing`
     haalt er 3,81 en is bedoeld voor diep, waar hij 5,88 haalt. Die twee getallen stonden al in
     de toelichting van `kleur.inkt.200` voordat iemand ze nodig had, met de waarschuwing erbij.
     Er komt voor deze hele omkering geen enkele nieuwe kleur bij.

     KOP EN TEKST WORDEN HIER NIET PER ONDERDEEL GEVERFD. Een Kop en een Tekst binnen deze opening
     erven hun kleur; dit blad zet daarom `color` op de opening zelf en raakt `ds-kop` en
     `ds-tekst` niet aan. Dat is dezelfde grens als overal: een onderdeel schrijft niet in de
     klassen van een ander. */
  /* DE OMKERING LIEP OP ERVING EN ERVING KWAM HIER NOOIT AAN. Gemeten op 13 september 2026 met
     `node design/meting/kleuretalage.mjs`: 16 van de 216 paar onder de WCAG-eis stonden niet in
     de voet maar hier, op `/` en alleen daar, op beide breedtes. Het etiket haalde 1,44, de kop
     1,54 en de lead 1,01 op deze kobaltgrond. De reden staat drie alinea's hierboven met zoveel
     woorden: dit blad zet `color` op de opening en rekent erop dat een Kop en een Tekst die
     kleur erven. Ze erven hem niet. `.ds-kop` zet `color: var(--ds-color-text-default)`
     (ds-componenten.css:1672), `.ds-tekst--kleur-body` zet `var(--ds-color-text-body)` (4283) en
     `.ds-etiket--accent` zet `var(--ds-color-text-accent)` (602). Drie eigen verklaringen slaan
     een geerfde kleur altijd.

     DE GROND ZET DE ROLLEN OM EN NIET DE KLASSEN. Wat hieronder staat verft geen enkele `ds-kop`
     of `ds-tekst`: het herdefinieert binnen deze opening de TOKENS waar die onderdelen zelf al
     naar wijzen. De grens uit de kop blijft dus staan, een onderdeel schrijft niet in de klassen
     van een ander, en de bedoelde erving werkt nu werkelijk. Nagerekend op kobalt #1F4E8C met de
     WCAG-formule, 13 september 2026: wit 8,31 en papier-100 6,63.

     HET ACCENT IS HIER GEEN OKER, en dat is geen noodgreep maar wat de tokens zelf al zeiden.
     `text.accent.on-ink` is oker-300 en haalt 6,42 op diep, waar hij voor gemaakt is, maar 4,16
     op kobalt; de plaatsingsregel bij `surface.brand` liet hem daar dan ook alleen toe boven
     24px of vet boven 18,66px. Een Etiket is elf punten. Geen okeren trede in het palet haalt
     het hier, dus staat er `text.accent.on-brand`, papier, 7,62. Papier en niet wit: ze halen
     het allebei, maar papier is de lichtste GROND van dit systeem en wit staat er als
     `surface.raised` en als `focus.on-brand`. Een tekstkleur erbij pakken om een poort groen te
     krijgen is precies de nieuwe kleur die deze omkering niet nodig had. Het etiket blijft een
     etiket door zijn kapitalen en zijn spatiering.

     TWEE SPOREN, DEZELFDE UITKOMST. Het merkspoor besloot dit los hiervan, met hetzelfde getal
     4,16, en legde het vast in `OVERDRACHT-2026-09-13.md` van `erfverhaal-design-delft`. Dit
     spoor mat het na zonder dat te weten. Zie sitevoet.md. */
  .ds-opening--merk {
    background: var(--ds-color-surface-brand);
    color: var(--ds-color-text-on-brand);
  }

  /* DE OMKERING STAAT OP DE TEKSTKOLOM EN NIET OP HET HELE VLAK, EN DAT IS DE REPARATIE VAN
     14 SEPTEMBER 2026. Zolang die vier rollen op `.ds-opening--merk` zelf stonden, erfden ze door
     naar ALLES in deze sectie, ook naar `__voorwerp`. Daar staat het Boek, en dat brengt zijn
     eigen witte omslag mee. Gemeten op de voorpagina bij 1280px: `.ds-boek__kaft` 380 bij 507 in
     oklch(1 0 90), met `__naam` en `__voor` in oklch(1 0 90) en `__reeks` in
     oklch(0.97 0.008 91.5). Wit op wit. Wat Ernst zag was een leeg wit vlak waar een omslag hoort
     te staan.

     WAAROM DE KLEURPOORT DIT NIET ZAG, en dat hoort erbij. `kleuretalage.mjs` zoekt de grond van
     een tekst bij zijn VOOROUDERS. `.ds-boek__titel` staat absoluut gepositioneerd en de kaft is
     een BROER eronder, dus de meting vond de blauwe grond van deze sectie en keurde wit op blauw
     goed: 25 pagina's, 4.081 tekstelementen, nul paar onder de eis, terwijl de titel onleesbaar
     was. Dezelfde vorm als drie andere gevallen van die dag: de goede eigenschap gewogen op de
     verkeerde verzameling.

     WAAROM DEZE PLEK EN NIET EEN REGEL IN boek.css. Een onderdeel mag alleen zijn eigen klassen
     opmaken, en `bouw.py` houdt dat tegen. Dat is ook de juiste kant op: wie de rollen omkeert,
     hoort te zeggen hoe ver die omkering reikt. Verder dan zijn eigen tekst en zijn eigen oproep
     reikt ze niet.

     EN NIET OP `__inhoud`, want `__voorwerp` staat DAARBINNEN en niet ernaast. Dat is de fout die
     ik hier eerst maakte: de omkering een laag omhoog zetten leek genoeg en de titel bleef wit op
     wit. Gemeten, niet geredeneerd.

     `color` blijft wel op het vlak staan, want losse tekst rechtstreeks in de sectie hoort ook
     op blauw leesbaar te zijn. */
  /* EN DE OPROEP ZEGT WAT EEN KNOP OP DIT VLAK MOET DOEN. De hoofdknop staat standaard op
     `surface.brand`, en dat is precies de grond die dit vlak neerlegt: gemeten op de voorpagina
     bij 1280px stond er een knopvlak van 185 bij 52 in oklch(0.426 0.115 256.6) op een grond van
     oklch(0.426 0.115 256.6), dezelfde kleur tot op het cijfer. Zichtbaar als losse tekst in
     plaats van een knop.

     Knop en Knoplink lezen hun grond sinds 14 september 2026 uit `--ds-knop-grond`; hier staat de
     waarde. Een regel die hun klasse noemt mag niet, en hoeft ook niet: wie een grond neerlegt,
     zegt erbij wat een knop daarop doet. Geen nieuwe kleur, en geen klasse erbij in de opmaak. */
  /* HET OPROEPSLOT REKT ZICH UIT, WANT ANDERS KRIMPT ZIJN INHOUD TOT EEN WOORD PER REGEL.
     De inhoudkolom is een `ds-stapel--begin`, dus `align-items: flex-start`, en in een flexkolom
     krimpt elk kind daar tot zijn inhoudsbreedte. Een knop wil dat; een Zoekrij niet, want die
     draagt zelf `container-type: inline-size` en meet dan die gekrompen breedte. Gemeten op
     13 september 2026 op /namen/ bij 1280px: het label "Zoek een naam of een plaats" brak af tot
     een woord per regel.

     Dit slot droeg tot 14 september 2026 geen enkele regel, terwijl zijn eigen kop zegt dat er
     een Zoekrij in kan. `web/publiek/sjablonen/hub.html` zette de zoekrij daarom in het
     lijstslot, met dat gat als reden erbij. Het gat is nu dicht; de zoekrij terugzetten is een
     zichtbare verandering op de hubs en dus een aparte stap.

     De breedte van de inhoud blijft aan de inhoud: `stretch` rekt het SLOT en niet wat erin
     staat. Een knop erin houdt zijn eigen breedtevariant. */
  .ds-opening__oproep {
    align-self: stretch;
  }

  /* DE KOP OP DE MERKGROND IS OKER EN NIET WIT, en dat is de merkbron en geen smaak. In
     stijl.css van de gestempelde jaargang staat op regel 309: `.opening.op-blauw .h1 { color:
     var(--oker-op-blauw) }`. Bij ons stond hij wit, en dat is het eerste wat opvalt als je de
     voorpagina naast erfverhaal.nl legt. Gevonden op 14 september 2026.

     DE CONTRASTEIS HAALT HIJ, EN ALLEEN OMDAT HET EEN GROTE KOP IS. Nagerekend: oker-op-blauw
     (#E3AE63) op kobalt (#1F4E8C) geeft 4,16. Dat is boven de 3 die voor grote tekst geldt en
     onder de 4,5 voor lopende tekst. Hetzelfde getal staat in stijl.css regel 98 met dezelfde
     waarschuwing erbij. Deze regel raakt daarom ALLEEN de kop van de opening en niets anders;
     wie hem breder trekt, zet tekst neer die de eis niet haalt.

     De variabele staat op het omhulsel en niet op `.ds-kop`: een onderdeel schrijft niet in de
     klassen van een ander. Zie de noot in opening.html. */
  .ds-opening--merk .ds-opening__kop {
    --ds-color-text-default: var(--ds-color-text-hero-on-brand);
  }

  .ds-opening--merk .ds-opening__oproep {
    --ds-knop-grond: var(--ds-color-surface-page);
    --ds-knop-grond-zweef: var(--ds-color-surface-sunken);
    --ds-knop-inkt: var(--ds-color-surface-brand);
  }

  .ds-opening--merk .ds-opening__tekst,
  .ds-opening--merk .ds-opening__oproep {
    color: var(--ds-color-text-on-brand);

    --ds-color-text-default: var(--ds-color-text-on-brand);
    --ds-color-text-body: var(--ds-color-text-on-brand);
    --ds-color-text-muted: var(--ds-color-text-on-brand-muted);
    --ds-color-text-accent: var(--ds-color-text-accent-on-brand);
  }
}

/* === openklap === */
/* Openklap. Een vraag die altijd staat en een antwoord dat op verzoek komt.
 *
 * Canoniek: design/system/css/site.css:869 (.ev-keuze en .ev-keuze[open]) voor de vorm blok,
 * en .ev-keuze__rij op :871 voor de vorm rij. Samen 4.235 gewogen. De veelgestelde vraag op de
 * publieke site (.ev-vraag, publiek.css:385) en de summary Menu in de kop komen hier ook op
 * uit: dat zijn F10 (5 varianten worden 1) en F11 (10 worden 1, waarvan vijf verloop).
 *
 * Vier dingen die hier anders zijn dan vandaag:
 *
 * 1. De summary draagt een zichtbare focusring uit color.focus. In de negen bestaande
 *    stijlbladen bestaat geen enkele focusregel voor summary. Wie met een toetsenbord door
 *    scherm 6 loopt, ziet vandaag niet waar hij staat.
 * 2. De rij haalt maat.raakvlak. Het raakdoel staat in deze laag en niet in de binnenruimte,
 *    dus geen enkele omhulling kan hem afnemen.
 * 3. Zweven bestaat, en ook in de open stand. Vandaag staat er op .ev-keuze geen enkele
 *    zweefregel, dus een muis krijgt nergens te zien dat die regel aanklikbaar is.
 * 4. De binnenruimte van het blok komt uit space.blok (24px, 32px boven het breekpunt) waar er vandaag een losse 18px
 *    staat, en de rij uit space.kop-tekst (16px) waar 15px stond. Zie het bouwverslag: het
 *    systeem heeft op die twee waarden geen token en de brief verbiedt er een te verzinnen.
 */

@layer componenten {
  .ds-openklap {
    display: block;
    border-radius: var(--ds-radius-control);
    transition: background-color var(--ds-motion-state);
  }

  /* De vraagregel. Hij is de bediening: alles wat hier staat gaat over aanwijzen en aantikken. */
  .ds-openklap__vraag {
    display: flex;
    align-items: center;
    gap: var(--ds-space-binnen-blok);
    min-block-size: var(--ds-maat-raakvlak);
    padding-block: var(--ds-space-kop-tekst);
    border-radius: var(--ds-radius-control);
    cursor: pointer;
    /* Het eigen driehoekje van de browser gaat uit; er staat een Pictogram voor in de plaats.
       list-style dekt Firefox en Chromium, de tweede regel dekt oudere WebKit. */
    list-style: none;
    transition: background-color var(--ds-motion-feedback);
  }
  .ds-openklap__vraag::-webkit-details-marker { display: none; }

  /* De focusring staat hier en niet alleen in de reset. In negen stijlbladen bestaat vandaag
     geen enkele focusregel voor summary, en dat is precies wat hier ophoudt. */
  .ds-openklap__vraag:focus-visible {
    outline: var(--ds-control-focus-breedte) solid var(--ds-color-focus);
    outline-offset: var(--ds-control-focus-afstand);
  }

  /* De letter volgt de vorm en niet een maat-as: een blok draagt de titel van een vlak, een rij
     draagt het etiket van een bediening. Dat vouwt de vier gemeten letters van deze familie
     samen: .ev-keuze__naam staat dicht op 17px display en open op 21 (dat is op zichzelf al
     verloop), .ev-vraag__v op 17px vet in de leesletter en de summary Menu in de kop op een
     kapitaaletiket van 11. */
  .ds-openklap__samenvatting {
    flex: 1;
    color: var(--ds-color-text-default);
  }
  .ds-openklap--blok .ds-openklap__samenvatting { font: var(--ds-type-sectie);
    letter-spacing: var(--ds-type-sectie-spatiering); }
  .ds-openklap--rij .ds-openklap__samenvatting {
    font: var(--ds-type-brood);
    font-weight: var(--ds-type-nadruk);
  }

  /* De omhulling van het teken draait, en niet het teken zelf: de browser vertelt het sjabloon
     niet dat er geklikt is, dus de stand moet uit css komen. */
  .ds-openklap__pijl {
    display: flex;
    flex: none;
    color: var(--ds-color-text-muted);
    transition: transform var(--ds-motion-state);
  }
  .ds-openklap[open] .ds-openklap__pijl { transform: rotate(180deg); }

  .ds-openklap__antwoord {
    padding-block-end: var(--ds-space-kop-tekst);
    color: var(--ds-color-text-body);
  }

  /* --- blok: het getinte vlak. De veelgestelde vraag en het betaalde optieblok. --- */
  .ds-openklap--blok { padding-inline: var(--ds-space-blok); }
  .ds-openklap--blok[open] { background: var(--ds-color-surface-sunken); }

  /* --- rij: dezelfde bediening zonder vlak. De summary Menu in de kop. --- */
  .ds-openklap--rij { padding-inline: 0; }

  /* Zweven. Dicht tint de regel bij; open is het vlak al getint, dus daar licht de regel juist
     op. Zo is er in allebei de standen te zien dat je hem kunt aantikken. */
  .ds-openklap__vraag:hover { background: var(--ds-color-surface-sunken); }
  .ds-openklap--blok[open] .ds-openklap__vraag:hover { background: var(--ds-color-surface-page); }
}

/* === padwijzer === */
/* Padwijzer. Waar de bezoeker is: een kruimelpad op de etalage, een stapteller in de flow.
 *
 * Canoniek: design/system/onderdelen/kop.html:47 (17d2ddad0f6d, 424 gewogen) met .ev-kruimel
 * uit design/system/css/kop.css.
 *
 * De stapteller (097356f7063a) verschilt van het kruimelpad in precies een gemeten eigenschap:
 * box-sizing, en die verdwijnt zodra de reset in @layer reset staat. Dat maakt het geen tweede
 * onderdeel en ook geen variant van een ander ding: het is een patroon met twee modi, want het
 * een kondigt voortgang aan en het ander navigeert.
 *
 * De huidige plek draagt aria-current en een vorm die niet alleen kleur is: hij staat in
 * color.text.default en in gewicht.vet tegenover de lichtere inkt van de links. In de negen
 * bestaande stijlbladen staan vandaag twee aria-current-regels.
 */

@layer patronen {
  /* GEEN EIGEN KOLOMBREEDTE EN GEEN AUTOMATISCHE MARGES MEER, 14 september 2026.
     Hier stond `max-inline-size: maat.kolom` met `margin-inline: auto`, en dat is een
     paginabreedteregel uit de tijd dat het kruimelpad los boven de opening stond. Sinds hij
     BINNEN de opening staat, zoals de kop van dit onderdeel zelf al zegt, centreerde hij zich
     in een doos van 440px binnen de tekstkolom. Gemeten op het naamoppervlak bij 1280px: het
     kruimelpad begon op x382 terwijl de kop eronder op x82 begon; op staging beginnen ze allebei
     op dezelfde x51.

     Nagerekend voordat het wegging: van de 26 pagina's in `etalage/` die een kruimelpad dragen
     staan er 22 binnen een opening en nul erbuiten. Deze regel bediende dus niemand meer, en de
     ruimte eromheen komt van de opening die hem draagt. */
  .ds-padwijzer {
    padding-block-start: var(--ds-space-kop-tekst);
    color: var(--ds-color-text-muted);
    font: var(--ds-type-fijn);
  }
  /* 900px is --ds-breekpunt-breed; een mediavraag kan geen custom property lezen, dus het getal staat hier letterlijk. Strikt groter dan en niet vanaf: Modern Delft zet zijn smalle waarden in `@media (max-width: 900px)`, dus op precies 900px is het merk smal. Met `min-width: 900px` was het systeem daar breed en het merk smal, en dat verschil van een pixel viel nergens op omdat geen enkele meting op de rand zelf keek. */
  @media (width > 900px) {
    .ds-padwijzer { max-inline-size: var(--ds-maat-kolom-breed); }
  }

  .ds-padwijzer__lijst {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--ds-space-inline);
    list-style: none;
    margin: 0;
    padding: 0;
  }
  .ds-padwijzer__item {
    display: flex;
    align-items: center;
    gap: var(--ds-space-inline);
  }

  /* Een kruimel is een doel en geen woord in een zin, dus hij haalt maat.raakvlak-min uit
     lucht en niet uit letters: op deze lettermaat is de regel anders 18px hoog en daarmee
     onder de ondergrens van WCAG 2.2 SC 2.5.8. */
  .ds-padwijzer__link {
    display: inline-flex;
    align-items: center;
    min-block-size: var(--ds-maat-raakvlak-min);
    color: var(--ds-color-text-muted);
  }
  .ds-padwijzer__link:hover { color: var(--ds-color-text-accent); }

  .ds-padwijzer__nu {
    display: inline-flex;
    align-items: center;
    min-block-size: var(--ds-maat-raakvlak-min);
    margin: 0;
    color: var(--ds-color-text-default);
    font-weight: var(--ds-type-nadruk);
  }

  .ds-padwijzer__streep { color: var(--ds-color-text-muted); }
}

/* === pictogram === */
/* Pictogram. Een svg in een vaste doos zodat hij niet uitrekt.
 *
 * Canoniek: pipeline/templates/site/maak.html:166, gemeten als 9c26aa807100, 492 voorkomens en
 * 2.460 gewogen. Dat is de zwaarste niet-typografische uitzondering van F01, de zwaarste
 * familie: van de 40 uitzonderingen daar zeggen er 29 met zoveel woorden dat ze typografie
 * zijn en naar Tekst en Kop gaan. Deze ene is een echt onderdeel.
 *
 * Wat de doos doet. `flex: none` is de hele reden dat dit bestaat: in een flexrij krimpt een
 * svg mee met de ruimte die overblijft, en dan is een pijl van 16px op een smal scherm ineens
 * 9px. De doos heeft een vaste maat, de svg vult hem, en de rij eromheen kan er niets aan
 * veranderen.
 *
 * Wat de doos NIET doet: een kleur zetten. Een pictogram erft de kleur van de tekst waar hij
 * bij staat, want hij hoort bij die tekst en draagt nooit zelf de betekenis. Daarom staat er
 * in dit bestand geen enkele kleur, en tekent elk teken in currentColor.
 */

@layer componenten {
  .ds-pictogram {
    display: inline-flex;
    flex: none;
    align-items: center;
    justify-content: center;
    inline-size: var(--pictogram-maat);
    block-size: var(--pictogram-maat);
    transition: transform var(--ds-motion-state);
  }

  .ds-pictogram > svg {
    inline-size: 100%;
    block-size: 100%;
  }

  /* klein: 16px, de maat van de uitklappijl. Er is geen maattoken van 16px, dus hier staat de
     semantische stap die die waarde draagt. Zie de afwijking in het bouwverslag: space.kop-tekst
     is 1rem en dus precies 16px, maar zijn naam gaat over ruimte en niet over een maat. */
  .ds-pictogram--klein   { --pictogram-maat: var(--ds-space-kop-tekst); }
  /* normaal: 24px, gelijk aan de ondergrens van een raakdoel uit WCAG 2.2 SC 2.5.8. */
  .ds-pictogram--normaal { --pictogram-maat: var(--ds-maat-raakvlak-min); }

  /* gedraaid: een halve slag. De stand van een teken dat bij het renderen al bekend is. Een
     Openklap die pas in de browser opengaat draait zijn eigen omhulling; zie openklap.css. */
  .ds-pictogram--gedraaid { transform: rotate(180deg); }
}

/* === prijsregel === */
/* Prijsregel. Een product met zijn prijs, als regel in een lijst.
 *
 * Canoniek: de merkbron, `bundel/stijl.css` regel 593 tot 610, op de jaargang die het merkspoor
 * op 12 september 2026 stempelde (`origin/ontwerp/modern-delft`, `7ab18dc`, jaargang
 * `423fc022`). Tweehonderdzevenentwintig voorkomens, de laatste van de elf die gebouwd kon
 * worden.
 *
 * HIJ SCHRIJFT NIET IN BOEK, EN DE MERKBRON DOET DAT WEL. Daar staat
 * `.prijsregel .tegelklein .boek .titel, ... .streep { display: none }`: de prijsregel reikt in
 * het boek en zet twee van zijn delen uit. Dat mag hier niet en het hoeft niet: Boek heeft sinds
 * 13 september 2026 een vorm `klein` die die twee niet RENDERT. Het verschil is niet cosmetisch.
 * Verborgen delen staan er nog, worden voorgelezen door een schermlezer die `display: none` niet
 * eerbiedigt in elke context, en ze verschijnen zodra iemand elders een specifiekere regel
 * schrijft. Wat er niet is, kan niet terugkomen.
 *
 * De breedte van het beeldje zet deze regel wel, en dat mag: hij zet hem op zijn EIGEN wikkel en
 * niet op het onderdeel erin. Boek vult de breedte die hij krijgt.
 *
 * DE PRIJS STAAT RECHTS EN LIJNT OP DE GRONDLIJN MET DE NAAM. Niet op de bovenkant: een prijs van
 * 22px naast een naam van 17px zou dan een halve regel te hoog hangen. Daarom `align-items:
 * baseline` in de rechterhelft, en `align-items: start` op de regel zelf, want de twee HELFTEN
 * beginnen wel op dezelfde hoogte.
 */

@layer componenten {
  /* De lijst, en hij heet `__lijst` en niet `ds-prijsregels`: een onderdeel mag alleen zijn
     eigen klasse schrijven en het meervoud is een andere klasse. `bouw.py` weigerde dat terecht.
     Geen ruimte tussen de regels: de scheiding is een lijn en die zit op de regel zelf,
     zodat een lijst van een regel er hetzelfde uitziet als de laatste regel van een lange lijst. */
  .ds-prijsregel__lijst {
    display: flex;
    flex-direction: column;
  }

  .ds-prijsregel {
    display: grid;
    grid-template-columns: minmax(0, 2fr) minmax(0, 3fr);
    align-items: start;
    gap: var(--ds-space-tussen) var(--ds-prijsregel-kolomgat);
    padding-block: var(--ds-prijsregel-ruimte);
    border-block-end: var(--ds-border-hairline) solid var(--ds-color-border-subtle);
  }

  /* Kaal: geen beeldje, dus geen linkerkolom. Het is een regel over iets dat geen product is, zoals
     de regel die zegt wat wij doen naast wat een genealoog en een drukker doen. */
  .ds-prijsregel--kaal {
    grid-template-columns: minmax(0, 1fr);
  }

  .ds-prijsregel__beeld {
    inline-size: var(--ds-prijsregel-beeld);
  }

  .ds-prijsregel__rechts {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--ds-prijsregel-kolomgat);
    min-inline-size: 0;
  }

  .ds-prijsregel__naam {
    display: flex;
    flex-direction: column;
    gap: var(--ds-space-inline);
    min-inline-size: 0;
  }

  .ds-prijsregel__omschrijving {
    font: var(--ds-type-klein);
    color: var(--ds-color-text-body);
  }

  /* Het bedrag. Tabulaire cijfers, want een kolom prijzen onder elkaar hoort op de komma te
     lijnen.

     EN `nowrap` STAAT OP HET BEDRAG EN NIET OP HET BLOK. Hij stond hier, en de fijne regel onder
     de prijs staat binnen datzelfde blok en erfde hem dus. Een levertijd van vier woorden kon
     daardoor niet afbreken en duwde de pagina open: gemeten op 13 september 2026 op /producten
     bij 320px, scrollWidth 340 tegen een venster van 320, met "gedrukt, 11 werkdagen · hoort bij
     het boek" als schuldige. "1.299" mag niet afbreken; een levertijd wel. */
  .ds-prijsregel__prijs {
    text-align: end;
    font-variant-numeric: tabular-nums;
    color: var(--ds-color-mark);
  }
  .ds-prijsregel__bedrag,
  .ds-prijsregel__munt {
    white-space: nowrap;
  }
  .ds-prijsregel__bedrag {
    font: var(--ds-type-getal-klein);
    letter-spacing: var(--ds-type-getal-klein-spatiering);
    color: var(--ds-color-mark);
  }
  /* Het euroteken staat kleiner dan het bedrag en in de tekstkleur van oker: het is een eenheid
     en geen getal, en een euroteken op 22px trekt de aandacht van het bedrag weg. */
  .ds-prijsregel__munt {
    font: var(--ds-type-klein);
    color: var(--ds-color-text-accent);
  }
  /* De regel onder de prijs, bijvoorbeeld een levertijd of "per stuk". */
  .ds-prijsregel__fijn {
    font: var(--ds-type-klein);
    color: var(--ds-color-text-body);
  }

  /* Op een smalle kolom staan de twee helften onder elkaar. Een containervraag en geen
     mediavraag: dezelfde lijst staat op een productpagina in een leeskolom en op de prijspagina
     over de volle breedte. 480px is de breedte waaronder 2fr naast 3fr twee kolommen van onder de
     honderd pixels geeft, en dan is het geen regel meer maar twee kolommen ruis. */
  .ds-prijsregel__lijst { container-type: inline-size; container-name: ds-prijsregel; }
  @container ds-prijsregel (max-width: 480px) {
    .ds-prijsregel { grid-template-columns: minmax(0, 1fr); }
    /* En de twee helften van de regel staan dan ook onder elkaar. Naast elkaar houden op deze
       breedte geeft een naam van honderd pixels naast een prijs van honderd, met het kolomgat
       ertussen; dat is dezelfde ruis die de buitenste kolom hierboven opheft. */
    .ds-prijsregel__rechts {
      display: flex;
      flex-direction: column;
      align-items: start;
      gap: var(--ds-space-tussen);
    }
    .ds-prijsregel__prijs { text-align: start; }
  }

  @media (forced-colors: active) {
    .ds-prijsregel { border-block-end: var(--ds-border-hairline) solid CanvasText; }
  }
}

/* === proefblok === */
/* Proefblok. Het blok dat op flow/hoofdstuk het gedrukte boek laat zien.
 *
 * Canoniek: pipeline/templates/site/hoofdstuk.html:4, de ongescoopte laadregel, wordt hier een
 * wortelklasse. De vorm die blijft is het kader zoals het op de andere 37 routes staat.
 *
 * Waar dit blad over gaat: het drukdomein staat achter .ds-proefblok--druk en niet op body. Deze
 * route laadt book.css vandaag ongescoopt op body (B017): 58 vingerafdrukken bestaan alleen hier,
 * waarvan 18 kopieen van het gedeelde kader. Daardoor krijgen kop, voet, kruimelpad en navigatie
 * op deze ene route een andere vorm dan op de andere 37. Achter een wortelklasse valt deltaklasse
 * D0028 (27 paren over zes families, verloop, high) in een keer weg en komt de h1 terug (B052).
 *
 * Er staat hier geen enkele regel op body of op een element buiten dit blok. Dat is de hele
 * reparatie en de toets zet hem vast.
 *
 * Twee waarden zijn de dichtstbijzijnde trede en niet de gemeten waarde, want fase 3 voegt geen
 * token toe:
 *   de hoofdstuktitel staat vandaag op 25px in gewicht 400 en krijgt hier type.sectie (19px).
 *   De proeftekst staat vandaag op 12,5px met regelhoogte 1,68 en krijgt hier type.fijn
 *   (11,5px op 1,60); het tokenblad zegt zelf dat regelhoogte 1,60 de 1,68 vangt.
 * Dat de titel in het boek 24pt in gewicht 700 is en op dit scherm niet, is geen consolidatie;
 * dat staat als punt 9 in herontwerp en wordt hier dus niet gerepareerd.
 */

@layer componenten {
  /* Het kader gaat van --ev-ink-faint (2,984 op drukpapier) naar color.border (5,546). */
  .ds-proefblok {
    border: var(--ds-border-hairline) solid var(--ds-color-border);
    padding: var(--ds-space-blok);
  }

  /* De wortelklasse van het drukdomein. Alles wat naar drukkleur ruikt staat hierbinnen. */
  .ds-proefblok--druk {
    background: var(--ds-color-print-surface);
    color: var(--ds-color-print-text);
  }

  .ds-proefblok__blad {
    max-inline-size: var(--ds-maat-regel);
    margin-inline: auto;
  }

  .ds-proefblok__titel {
    font: var(--ds-type-sectie);
    letter-spacing: var(--ds-type-sectie-spatiering);
    color: var(--ds-color-print-text);
  }

  .ds-proefblok__tekst {
    font: var(--ds-type-fijn);
    color: var(--ds-color-print-text-soft);
  }
}

/* === rapportkop === */
/* Rapportkop. De kop van een rapport: titel, datum, herkomst en eventueel een feitenblok.
 *
 * Canoniek: design/system/css/report.css:51 (.ev-doc h1).
 *
 * Wat hier anders is dan vandaag: de kop staat zeven keer los overgetikt en vier van de zeven
 * dragen daarna een div.ev-facts die de andere drie missen (B185). Of dat onderscheid bewust is,
 * is uit de inhoud niet te zien; het wordt daarom een slot dat leeg mag blijven.
 *
 * De plaatsing komt van Stapel. Geen straal op het feitenvlak: radius.control is voor knoppen en
 * invoervelden, een paneel krijgt er geen.
 */

@layer componenten {
  .ds-rapportkop {
    padding-block-end: var(--ds-space-blok);
    border-block-end: var(--ds-border-hairline) solid var(--ds-color-border-subtle);
  }

  .ds-rapportkop__meta {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--ds-space-tussen);
    font: var(--ds-type-klein);
    color: var(--ds-color-text-muted);
  }

  .ds-rapportkop__scheiding {
    color: var(--ds-color-border);
  }

  .ds-rapportkop__feiten {
    background: var(--ds-color-surface-sunken);
    padding: var(--ds-space-blok);
    font: var(--ds-type-klein);
    color: var(--ds-color-text-body);
  }
}

/* === schakelaar === */
/* Schakelaar. Een aan-uitkeuze die meteen werkt, met een bijschrift ernaast: akkoord en cadeau op
 * scherm 2.
 *
 * Canoniek: design/system/css/site.css:164-178 (.ev-switch), gemeten als 6c6db336227d op
 * pipeline/templates/site/vier.html:93, 174 gewogen.
 *
 * Vier dingen die hier anders zijn dan vandaag, alle vier een reparatie:
 *
 * 1. De baan gaat van --ev-ink-faint naar color.border, die 4,507 haalt op surface.sunken. De
 *    knop in papierkleur haalt daarmee 5,181 op de baan, waar hij met de oude kleur 2,912 haalde.
 *    (Beide oude getallen, 2,639 en 2,912, horen bij --ev-ink-faint.) De aan-stand blijft
 *    color.surface.inverse, 10,239 op de tint.
 * 2. Het invoerveld staat niet meer op opacity 0. Het IS de baan, met appearance: none, dus het
 *    blijft in de toegankelijkheidsboom en het draagt zelf de focusring. Vandaag heeft de
 *    schakelaar er geen.
 * 3. De dubbele straalberekening, 12px op een baan van 24 en 9px op een knop van 18, wordt
 *    radius.pil en verschuift geen pixel.
 * 4. De rij staat op maat.raakvlak. Vandaag meet web-audit --devices op scherm 2 vier tikdoelen
 *    van 13 bij 13, en dat zijn verborgen invoervelden als deze.
 *
 * De maten van de baan. 42 bij 24 en een knop van 18 staan niet als token in het systeem, en
 * fase 3 voegt er geen toe. Ze staan hier afgeleid van maat.raakvlak-min (24px), het token dat
 * de hoogte van de baan al is: de breedte is 1,75 maal die hoogte en de knop driekwart ervan. Dat
 * komt uit op precies 42 en 18, dus er verschuift geen pixel ten opzichte van de meting.
 *
 * De knop is een verloop op de achtergrond en geen pseudo-element, net als de stip van Vinkje, en
 * hij schuift met background-position. De rij draagt geen eigen grond: de getinte grond die
 * .ev-switch vandaag heeft is een Vlak en hoort daar.
 */

@layer componenten {
  .ds-schakelaar {
    min-block-size: var(--ds-maat-raakvlak);
    cursor: pointer;
  }

  .ds-schakelaar__baan {
    --baan-hoogte: var(--ds-maat-raakvlak-min);
    --knop: calc(var(--baan-hoogte) * 0.75);
    --kier: calc((var(--baan-hoogte) - var(--knop)) / 2);

    appearance: none;
    flex: none;
    inline-size: calc(var(--baan-hoogte) * 1.75);
    block-size: var(--baan-hoogte);
    margin: 0;
    border-radius: var(--ds-radius-pil);
    background-color: var(--ds-color-border);
    background-image: radial-gradient(closest-side, var(--ds-color-surface-page) 100%, transparent 100%);
    background-repeat: no-repeat;
    background-size: var(--knop) var(--knop);
    background-position: var(--kier) center;
    cursor: pointer;
    transition: background-color var(--ds-motion-state),
                background-position var(--ds-motion-state),
                box-shadow var(--ds-motion-feedback);
  }

  /* aan: de knop schuift naar de andere kant en de baan wordt inkt. De stand zit dus in de plek
     en niet alleen in de kleur. */
  .ds-schakelaar__baan:checked {
    background-color: var(--ds-color-surface-inverse);
    background-position: calc(100% - var(--kier)) center;
  }

  /* zweven: een ring om de baan. De kleur van de baan blijft staan, want die draagt de stand. */
  .ds-schakelaar:hover .ds-schakelaar__baan {
    box-shadow: inset 0 0 0 var(--ds-border-hairline) var(--ds-color-surface-inverse);
  }
  .ds-schakelaar:hover .ds-schakelaar__baan:checked {
    background-color: var(--ds-color-surface-inverse-hover);
  }

  .ds-schakelaar__baan:focus-visible {
    outline: var(--ds-control-focus-breedte) solid var(--ds-color-focus);
    outline-offset: var(--ds-control-focus-afstand);
  }

  .ds-schakelaar__bijschrift {
    font: var(--ds-type-klein);
    color: var(--ds-color-text-body);
    max-inline-size: var(--ds-maat-regel);
  }

  .ds-schakelaar__baan:disabled {
    background-color: var(--ds-color-surface-sunken);
    background-image: radial-gradient(closest-side, var(--ds-color-text-muted) 100%, transparent 100%);
    cursor: not-allowed;
  }
  .ds-schakelaar:has(.ds-schakelaar__baan:disabled) {
    cursor: not-allowed;
  }
  .ds-schakelaar:has(.ds-schakelaar__baan:disabled) .ds-schakelaar__baan {
    box-shadow: none;
  }
  .ds-schakelaar:has(.ds-schakelaar__baan:disabled) .ds-schakelaar__bijschrift {
    color: var(--ds-color-text-muted);
  }

  /* HOGE CONTRASTMODUS. Dit onderdeel was er het ergst aan toe. De baan draagt geen rand en de
     knop is een background-image, dus in die modus verdween de hele schakelaar: grond Canvas op
     een pagina in Canvas, beeld weg, niets meer te zien. Gemeten in Chromium op 12 september
     2026: 0 van de 1050 pixels verschilden tussen aan en uit, en de opname van de aan-stand was
     een leeg wit vlak van 42 bij 25.

     Weg (b), de stand met randen tekenen, haalt het hier niet. Een schuivende knop is een vlak
     dat over de baan beweegt en geen omlijning; een ::after zou bovendien op een input moeten
     staan, wat bij Vinkje al afviel. Dus weg (a): forced-color-adjust: none op de baan, en
     tekenen met de systeemkleuren.

     De stand zit daarmee in drie dingen tegelijk, net als daarbuiten: de baan wisselt van Canvas
     naar Highlight, de knop van CanvasText naar HighlightText, en de knop schuift van links naar
     rechts. Die laatste komt uit background-position hierboven; dat is geen kleur en staat er
     dus al.

     De baan krijgt hier een inzetring die hij buiten deze modus niet heeft, en dat is geen
     afwijking maar de eis van WCAG 1.4.11: zonder rand heeft de bediening geen grens tegen het
     papier, en in deze modus is de getinte grond die hem daarbuiten begrenst weg. */
  @media (forced-colors: active) {
    .ds-schakelaar__baan {
      forced-color-adjust: none;
      background-color: Canvas;
      background-image: radial-gradient(closest-side, CanvasText 100%, transparent 100%);
      box-shadow: inset 0 0 0 var(--ds-border-hairline) CanvasText;
    }
    .ds-schakelaar__baan:checked {
      background-color: Highlight;
      background-image: radial-gradient(closest-side, HighlightText 100%, transparent 100%);
    }
    /* Zweven verdikt de ring in plaats van hem van kleur te laten wisselen: in deze modus is er
       maar een inkt, dus een tweede kleur bestaat er niet. */
    .ds-schakelaar:hover .ds-schakelaar__baan,
    .ds-schakelaar:hover .ds-schakelaar__baan:checked {
      box-shadow: inset 0 0 0 var(--ds-border-focus) CanvasText;
    }
    .ds-schakelaar__baan:focus-visible {
      outline-color: Highlight;
    }
    .ds-schakelaar__baan:disabled,
    .ds-schakelaar:has(.ds-schakelaar__baan:disabled) .ds-schakelaar__baan {
      background-color: Canvas;
      background-image: radial-gradient(closest-side, GrayText 100%, transparent 100%);
      box-shadow: inset 0 0 0 var(--ds-border-hairline) GrayText;
    }
    .ds-schakelaar__baan:disabled:checked,
    .ds-schakelaar:has(.ds-schakelaar__baan:disabled) .ds-schakelaar__baan:checked {
      background-color: GrayText;
      background-image: radial-gradient(closest-side, Canvas 100%, transparent 100%);
    }
  }
}

/* === schuifbak === */
/* Schuifbak. Wijde inhoud schuift in zijn eigen doos en nooit het document.
 *
 * Canoniek: design/system/css/publiek.css:268 (div.ev-tabel, overflow-x auto met een minimum
 * van 460px op de tabel erin), gekozen op criterium 2: 12 publieke routes tegen 7 rapportroutes
 * voor .ev-tab, dat woord voor woord hetzelfde doet.
 *
 * Drie dingen die hier anders zijn dan vandaag:
 *
 * 1. Het gebied is met het toetsenbord te bereiken. Drie patronen doen vandaag hetzelfde
 *    (.ev-tab, .ev-tabel, .ev-bladen__spoor) en geen van de drie is met tab te bereiken; samen
 *    zijn dat alle 41 serious-meldingen van scrollable-region-focusable, verdeeld over 26, 11
 *    en 4. tabindex en role staan hier een keer, dus geen gebruiker kan ze vergeten.
 * 2. Het gebied draagt een naam. Een groep zonder naam wordt aangekondigd als "groep".
 * 3. Aan het begin en aan het eind zijn echte toestanden en geen aanname. De twee dekkende
 *    verlopen liggen vast aan de inhoud (background-attachment: local) en de twee randverlopen
 *    aan de doos, dus de rand verschijnt precies wanneer er aan die kant nog iets staat. Dat
 *    is de enige manier om die twee toestanden zonder javascript te tonen, en de brief vraagt
 *    geen script voor iets dat de cascade zelf kan.
 *
 * De dekkende verlopen zijn surface.page, want daar staat dit blok op. Een Schuifbak op een
 * getint vlak hoort niet in dit systeem: dan is het vlak zelf de afbakening.
 */

@layer componenten {
  .ds-schuifbak {
    --schuifbak-rand: color-mix(in oklch, var(--ds-color-border) 30%, transparent);
    overflow-x: auto;
    overscroll-behavior-inline: contain;
    background-color: var(--ds-color-surface-page);
    background-image:
      linear-gradient(to right, var(--ds-color-surface-page), transparent),
      linear-gradient(to left, var(--ds-color-surface-page), transparent),
      radial-gradient(farthest-side at 0 50%, var(--schuifbak-rand), transparent),
      radial-gradient(farthest-side at 100% 50%, var(--schuifbak-rand), transparent);
    background-position: left center, right center, left center, right center;
    background-size:
      var(--ds-space-blok) 100%, var(--ds-space-blok) 100%,
      var(--ds-space-tussen) 100%, var(--ds-space-tussen) 100%;
    background-repeat: no-repeat;
    background-attachment: local, local, scroll, scroll;
  }

  /* De ring staat ook hier, en niet alleen in de reset. Een Schuifbak is het enige onderdeel
     dat focus krijgt zonder een bediening te zijn; wie de reset niet laadt, mag hem niet
     kwijtraken. */
  .ds-schuifbak:focus-visible {
    outline: var(--ds-control-focus-breedte) solid var(--ds-color-focus);
    outline-offset: var(--ds-control-focus-afstand);
  }

  /* De minimumbreedte hoort bij de inhoud en niet bij de doos: de doos is altijd zo breed als
     zijn kolom. Zonder minimum drukt de browser een tabel van vier kolommen plat tot
     woordenkolommen in plaats van hem te laten schuiven. */
  .ds-schuifbak--min-tabel > * { min-inline-size: var(--ds-maat-tabel-min); }
  .ds-schuifbak--min-geen > * { min-inline-size: 0; }

  /* UITSTAPPEN IS NIET SCHUIVEN, EN DAAROM IS HET EEN TWEEDE PROP. Een Schuifbak schuift binnen
     zijn eigen gebied en trekt de pagina nooit mee; dat blijft. Wat hier bij komt is dat het
     gebied zelf breder mag zijn dan de kolom waar het in staat, zodat een brede tabel niet hoeft
     te schuiven op een scherm waar hij past.

     Gemeten op report/erfverhaal-product.html op 12 september 2026: de documentkolom is 1.056px op
     een venster van 1280 en van 1920. Een tabel die vandaag uitstapt is daar 1.236px en 1.516px,
     dus 90px per kant op 1280 en de volle 230 op 1920. Op 768px stapt hij niet uit en schuift hij
     wel.

     De klem doet het werk en hij is overgenomen zoals hij stond. `50% - 50vw` is wat er links van
     de kolom over is; daar gaat de goot vanaf, zodat de bak nooit tegen de vensterrand plakt.
     `min(0px, ...)` maakt de uitstap nul zodra er niets over is, en `max(..., -230px)` houdt hem
     op een breed scherm binnen de gemeten grens. Zonder die twee klemmen zou de bak op een smal
     venster buiten het scherm hangen en op een zeer breed venster eindeloos doorlopen. */
  .ds-schuifbak--uitstap-document {
    margin-inline: max(min(0px, calc(50% - 50vw + var(--ds-space-blok))),
                       calc(-1 * var(--ds-maat-uitstap)));
  }
}

/* === sitekop === */
/* Sitekop. De plakkende kop, op de 38 routes met een sitekader en op alle 52 met een skelet.
 *
 * Canoniek: design/system/onderdelen/kop.html:32 (e48e6250aea9, 848 gewogen) met
 * design/system/css/kop.css. Dat bestand is vandaag al het enige werkelijk gedeelde onderdeel
 * van de repo; wat hier verandert zijn vier standaardreparaties en verder niets.
 *
 * 1. Drie raakdoelen gaan naar maat.raakvlak (besluit B7): het menuknopje van 37 naar 44px,
 *    de zoeklink van 30 naar 44 en Begin met uw naam van 40 naar 44. Dat is de enige
 *    zichtbare verandering van dit voorstel die op alle 52 routes tegelijk staat.
 * 2. De drie lettermaten in de kop (14, 13 en 13px) worden alle drie type.klein.
 * 3. De kop plakt, dus de pagina houdt scroll-padding-block-start vrij ter hoogte van de kop.
 *    Zonder die regel schuift het element met focus eronder (G056); drie plakkende balken doen
 *    dat vandaag op alle 53 routes niet.
 * 4. De box-sizing-pleister (.ev-kop, .ev-kop *) vervalt: de reset in @layer reset doet dat nu
 *    voor de hele pagina. Die pleister stond er omdat site.css de reset miste en de kop van de
 *    flow daardoor 44px breder was dan die van de site (gemeten 12 september 2026).
 */

@layer patronen {
  /* De hoogte van de kop is een som uit de tokens die hem vullen en geen gemeten getal: een
     raakdoel van maat.raakvlak met space.kop erboven en eronder. Dezelfde som staat hieronder als
     min-block-size van de balk, en hij erft van hier naar beneden zodat de twee niet uit elkaar
     kunnen lopen.

     space.kop en niet space.kop-tekst sinds 12 september 2026. De kop haalde zijn maat uit de rol
     die ook de binnenruimte van een veld zet, en kreeg daarmee 16px boven en onder; Modern Delft
     zet de kop juist krapper dan een bediening: 8px op een telefoon en 14px op een bureaublad. De
     som volgt mee en komt daarmee op 60px smal en 72px breed, en die 72 staat ook bij het merk als
     `--kop-hoogte`. Was 76px (gemeten 10 september 2026, 500px breed). */
  html:has(.ds-sitekop) {
    --sitekop-hoogte: calc(var(--ds-maat-raakvlak) + 2 * var(--ds-space-kop));
    scroll-padding-block-start: var(--sitekop-hoogte);
  }

  /* sticky en niet fixed: sticky houdt zijn plek in de stroom, dus de pagina eronder schuift
     niet omhoog en er is geen opvulling nodig die iemand vergeet als de kop van hoogte
     verandert. layer.sticky ligt onder layer.overlay, want de toestemmingsbalk hoort overal
     overheen zolang er niets gekozen is. */
  /* DE KOP IS PAPIER EN NIET INKT, en dat is op 14 september 2026 gemeten en rechtgezet. Hij
     stond hier op `surface.inverse` en dus donker op alle 27 pagina's; de merkbron heeft
     `.kop { background: var(--papier) }` op alle 29 bladen. Alleen boven de kobalten opening van
     de voorpagina wordt hij daar doorzichtig, en dat is de variant `--merk` hieronder.

     Dat dit een van de vier gronden was die niet klopten, en dat ze alle vier buiten een
     vergelijking per sectie vielen, staat als afspraak 16 in docs/HOE-WIJ-WERKEN.md. */
  .ds-sitekop {
    position: sticky;
    inset-block-start: 0;
    z-index: var(--ds-layer-sticky);
    background: var(--ds-color-surface-page);
    color: var(--ds-color-text-default);
    border-block-end: var(--ds-border-hairline) solid var(--ds-color-border-subtle);
    transition: background 400ms, border-color 400ms;
  }

  /* HET TWEEDE MERKTEKEN STAAT ER ALTIJD EN CSS KIEST, want een bestandswissel in javascript gaat
     op de stand zonder script kapot. Zonder de variant `--merk` staat het witte er niet eens in;
     met die variant staan ze er allebei en is er altijd precies een zichtbaar. */
  .ds-sitekop__teken--wit { display: none; }

  /* DE STANDEN VAN EEN KOP BOVEN EEN KOBALTEN OPENING.

     ZONDER ATTRIBUUT IS DE STAND DEKKEND KOBALT, en dat is met opzet de eerste regel. Een pagina
     zonder javascript krijgt nooit een `data-stand`, en dan moet er een grond onder de kop staan.
     Het script zet daarna `boven` of `voorbij`, en alleen `voorbij` verft anders; zie de regel
     hieronder voor waarom `boven` hetzelfde kobalt draagt als deze.

     Er zijn dus drie standen en twee beelden: kobalt (zonder script en bovenaan) en papier
     (voorbij de opening). Tot 14 september 2026 waren het er vier, doordat `boven` doorzichtig
     was; dat gaf hetzelfde beeld als kobalt en een andere meting. */
  .ds-sitekop--merk {
    background: var(--ds-color-surface-brand);
    color: var(--ds-color-text-on-brand);
    border-block-end-color: transparent;
  }
  .ds-sitekop--merk .ds-sitekop__teken { display: none; }
  .ds-sitekop--merk .ds-sitekop__teken--wit { display: block; }

  /* BOVENAAN DRAAGT HIJ ZIJN EIGEN KOBALT EN NIET `transparent`, sinds 14 september 2026.
     Hier stond `background: transparent`, overgenomen uit de merkbron, met als redenering dat de
     opening eronder al kobalt is. Dat klopt en het scheelt niets aan wat een bezoeker ziet: de
     opening zet dezelfde `surface.brand` neer als deze kop. Maar het scheelt wel iets aan wat te
     meten is.

     Een doorzichtige grond betekent dat de kleurmeting de eerste DEKKENDE voorouder pakt, en de
     kop hangt `sticky` in de documentstroom boven `body`. Wat er in beeld achter hem ligt, staat
     nergens in die keten. Gemeten op 14 september 2026: wit op papier, verhouding 1,09, vijf keer
     rood op de voorpagina, terwijl er in beeld wit op kobalt staat en dat 8,31 haalt. De poort in
     infra/poorten/kleur.mjs meet op dezelfde manier en draait binnen het terugdraaipad van de
     uitrol; met `transparent` was de voorpagina dus niet uit te rollen zonder een poort weg te
     klikken die gelijk had over zijn eigen meting.

     De winst is groter dan die meting. De stand zonder script en de stand bovenaan zijn nu
     hetzelfde vlak in plaats van twee wegen naar hetzelfde beeld, en er blijft precies een ding
     over dat het script doet: papier maken voorbij de opening.

     Dit geldt zolang de opening een egale grond draagt. Krijgt hij ooit een foto, dan is
     doorzichtig weer het goede antwoord en hoort daar een meting bij die kijkt naar wat er in
     beeld achter de kop ligt en niet naar wat er in de dom boven hem staat. */

  /* Voorbij de opening: weer de gewone kop, met het gewone merkteken. */
  .ds-sitekop--merk[data-stand="voorbij"] {
    background: var(--ds-color-surface-page);
    color: var(--ds-color-text-default);
    border-block-end-color: var(--ds-color-border-subtle);
  }
  .ds-sitekop--merk[data-stand="voorbij"] .ds-sitekop__teken { display: block; }
  .ds-sitekop--merk[data-stand="voorbij"] .ds-sitekop__teken--wit { display: none; }

  .ds-sitekop__in {
    display: flex;
    align-items: center;
    gap: var(--ds-space-kop-tekst);
    inline-size: 100%;
    max-inline-size: var(--ds-maat-kolom);
    margin-inline: auto;
    min-block-size: var(--sitekop-hoogte, calc(var(--ds-maat-raakvlak) + 2 * var(--ds-space-kop)));
    padding-block: var(--ds-space-kop);
    padding-inline: var(--ds-space-blok);
  }
  /* 900px is --ds-breekpunt-breed; een mediavraag kan geen custom property lezen, dus het getal staat hier letterlijk. Strikt groter dan en niet vanaf: Modern Delft zet zijn smalle waarden in `@media (max-width: 900px)`, dus op precies 900px is het merk smal. Met `min-width: 900px` was het systeem daar breed en het merk smal, en dat verschil van een pixel viel nergens op omdat geen enkele meting op de rand zelf keek. */
  @media (width > 900px) {
    .ds-sitekop__in { max-inline-size: var(--ds-maat-document); }
  }

  /* `flex: none` EN DAT IS GEEN NETHEID. Een flexkind krimpt van zichzelf zodra de rij te smal
     wordt, en dit kind is een beeld: het krimpt dan tot NUL en het merkteken is weg. Gemeten op
     13 september 2026 bij 901px, de eerste breedte waarop het menu plat staat: het anker was daar
     0px breed terwijl het op 1440px 105px is. Dat is de stilste manier waarop deze kop kan
     falen, want een balk die overloopt zie je en een merkteken dat er niet meer is niet.
     `menupoort.mjs` weegt het sindsdien apart. */
  .ds-sitekop__merk {
    display: inline-flex;
    flex: none;
    align-items: center;
    min-block-size: var(--ds-maat-raakvlak);
    margin-inline-end: auto;
    color: var(--ds-color-text-on-ink);
    text-decoration: none;
  }
  .ds-sitekop__merk:hover { color: var(--ds-color-mark-on-ink); }

  /* HET MENU STAAT PLAT VANAF 970px EN NIET VANAF breekpunt.breed, EN DAT IS ERNSTS BESLUIT VAN
     13 SEPTEMBER 2026. Met de vijf items die hij die dag koos past de balk pas vanaf 970; tussen
     901 en 969 liep hij over zichzelf. Vier wegen zijn gemeten (`design/meting/menupoort.mjs`) en
     geen enkele haalde 901 alleen: het merkteken kleiner tot aan de ondergrens van het merkspoor
     zelf haalt 933, beide opschriften inkorten haalt 913, en een item eruit haalt 901 maar kost
     een item.

     Wat deze weg kost is dat de band van 901 tot 969 een uitklapmenu krijgt waar hij een platte
     balk had. Wat hij niet kost is een woord, een item of een kleiner merkteken, en hij is terug
     te draaien zonder dat er ooit iets aan tekst of merk is veranderd. Dat laatste gaf de
     doorslag.

     En wat die band vandaag KRIJGT is geen nette balk: daar staat het merkteken op 18 tot 67
     procent van zijn breedte, ook in de merkbron met vier items. Een net ingeklapt menu is beter
     dan dat.

     De maat staat als getal en niet als var(): een mediavraag kan geen custom property lezen. Het
     token `sitekop.menu.breekpunt` draagt hem wel, zodat hij een naam en een herkomst heeft en
     `menupoort.mjs` hem kan uitlezen.

     DEZE 970 GELDT VOOR DEZE KOP, EN HET MERKSPOOR MEET 1010 VOOR DE ZIJNE. Dat lijkt een
     tegenspraak en het is er geen: het zijn twee koppen. Hun nav staat in `--t-klein`, de
     LEESletter op regelhoogte 1,65, met hun eigen gap; deze staat in `type.navigatie`, de
     displayletter op korps 15 met regelhoogte 1 en half gewicht, met een eigen maat tussen de
     items. Dat is precies de wijziging die op 13 september 2026 in deze kop landde, en een
     andere letter geeft een andere breedte.

     Allebei de getallen zijn juist voor hun eigen oppervlak. Wat er straks live gaat is DEZE
     kop, want Ernst heeft gekozen voor eerst omzetten en dan live; hun 1010 verdwijnt bij de
     omzetting. Deze noot staat er zodat een volgende sessie die 1010 in hun bundel ziet en niet
     concludeert dat een van de twee fout is. */
  .ds-sitekop__nav { display: none; }
  @media (width > 969px) {
    .ds-sitekop__nav {
      display: flex;
      align-items: center;
      /* EEN EIGEN MAAT EN NIET space.blok, sinds 13 september 2026. `space.blok` is boven 900px
         32px, en dat is precies wat Modern Delft tot 12 september tussen zijn menu-items zette.
         Het merkspoor heeft die maat die dag op 24 gezet om ruimte te maken voor het vijfde
         item, en dat getal hoort dus bij DIT onderdeel en niet bij de ruimtetrap: wie
         `space.blok` verandert, mag het hoofdmenu niet meeverschuiven. */
      gap: var(--ds-sitekop-nav-ruimte);
    }
  }

  /* Een link in de kop staat op zichzelf en is dus een doel en geen woord in een zin: hij
     groeit met lucht en niet met letters, zodat het beeld niet verandert. */
  /* DE MENULINKS STAAN IN type.navigatie EN NIET IN type.klein, sinds 13 september 2026.
     Modern Delft zet ze als `font: 600 var(--t-klein)/1 'Archivo'` (stijl.css:203): de
     displayletter, halfvet, regelhoogte 1. `type.klein` is de LEESletter op regelhoogte 1,65, en
     dat is een andere letter en een andere hoogte. Het verschil is niet cosmetisch: de
     regelhoogte telt mee in de hoogte van de kop, en de breedte van een menu-item hangt volledig
     aan de letter waarin het gezet is.

     `type.navigatie` bestond al (korps.15, regelhoogte 1, letter.display, gewicht.half) en had
     tot vandaag NUL gebruikers; hij is met de merkrichting in de tokenlaag gezet en nooit
     aangesloten. Gevonden doordat `menupoort.mjs` weigerde te meten: dat harnas eist dat de kop
     in Archivo staat voordat het een breedte opschrijft, en het meldde Atkinson. Een breedte in
     de verkeerde letter is geen meting. */
  .ds-sitekop__link,
  .ds-sitekop__zoek {
    display: inline-flex;
    align-items: center;
    min-block-size: var(--ds-maat-raakvlak);
    color: var(--ds-color-text-body);
    font: var(--ds-type-navigatie);
    text-decoration: none;
    white-space: nowrap;
  }
  .ds-sitekop__link:hover,
  .ds-sitekop__zoek:hover { color: var(--ds-color-text-accent); }
  .ds-sitekop__link[aria-current='page'] { color: var(--ds-color-text-accent); }

  /* Op een kobalten of doorzichtige kop draagt de navigatie wit. `text.on-brand` haalt daar 8,31;
     `wassing` zou er 3,81 halen en die hoort bij de voet, waar hij op diep 5,88 haalt. Twee
     donkere gronden, twee zachte tekstkleuren; zie ds/opening en ds/sitevoet.

     ALLEEN DE PLATTE RIJ, en dat is de reparatie van 14 september 2026. Deze regel stond op
     `.ds-sitekop__link` zonder meer, en de kop draagt diezelfde link TWEE keer: een keer in de
     platte rij, die op de grond van de kop staat, en een keer in het uitklapmenu, dat een eigen
     grond draagt. Wat op de ene grond klopt, klopt op de andere niet. */
  .ds-sitekop--merk:not([data-stand="voorbij"]) .ds-sitekop__nav .ds-sitekop__link,
  .ds-sitekop--merk:not([data-stand="voorbij"]) .ds-sitekop__nav .ds-sitekop__zoek {
    color: var(--ds-color-text-on-brand);
  }
  .ds-sitekop--merk:not([data-stand="voorbij"]) .ds-sitekop__nav .ds-sitekop__link:hover,
  .ds-sitekop--merk:not([data-stand="voorbij"]) .ds-sitekop__nav .ds-sitekop__zoek:hover,
  .ds-sitekop--merk:not([data-stand="voorbij"]) .ds-sitekop__nav .ds-sitekop__link[aria-current='page'] {
    color: var(--ds-color-mark-on-ink);
  }

  /* HET UITKLAPMENU IS EEN DONKER VLAK, DUS DE NAVIGATIE ERIN STAAT LICHT. Dat is niet dezelfde
     vraag als de grond van de kop en het hangt er ook niet van af: `.ds-sitekop__uit` zet zelf
     `surface.inverse` neer, op elke pagina en in elke stand.

     HIER STOND HET OMGEKEERDE, EN DAT WAS FOUT. Op 14 september 2026 stond hier een regel die de
     links in het open menu op `text.body` zette, met als toelichting "het opengeklapte menu staat
     op papier". Dat was een aanname over het etiket en niet een meting van de eigenschap: het
     menu staat op `surface.inverse`. Gemeten in Chromium op 900px breed: de link kwam uit op
     oklch(0.422 0.067 255.3) en zijn eerste dekkende voorouder op oklch(0.318 0.084 256.4), twee
     donkerblauwen op elkaar. Dat gold op elk van de 27 omgezette pagina's en niet alleen op de
     voorpagina, want de basisregel zet `text.body` en die was nergens weersproken.

     Dit is de vierde keer op een dag dat een grond hier aan een naam is afgelezen in plaats van
     gemeten, en de reden dat afspraak 16 in docs/HOE-WIJ-WERKEN.md staat. */
  .ds-sitekop__uit .ds-sitekop__link,
  .ds-sitekop__uit .ds-sitekop__zoek {
    color: var(--ds-color-text-on-ink);
  }
  .ds-sitekop__uit .ds-sitekop__link:hover,
  .ds-sitekop__uit .ds-sitekop__zoek:hover,
  .ds-sitekop__uit .ds-sitekop__link[aria-current='page'] {
    color: var(--ds-color-mark-on-ink);
  }

  /* De oproep in de kop staat op het merkvlak, met wit erop: 8,311. Hij stond op
     color.surface.accent, de okeren grond, met de regel van Ernst van 10 september 2026 erbij
     dat tekst op oker altijd wit is. Die grond bestaat sinds 12 september 2026 niet meer: Modern
     Delft zet oker twaalf keer neer als merkteken en nooit als grond met tekst erop, en wit op de
     merkoker haalt 4,15 tegen de 4,5 die geldt. De regel van Ernst blijft dus gelden en er is
     alleen geen okeren grond meer om hem op toe te passen. Zweven verandert alleen de grond,
     zoals bij Knop. */
  .ds-sitekop__knop {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-block-size: var(--ds-maat-raakvlak);
    padding-inline: var(--ds-space-kop-tekst);
    border-radius: var(--ds-radius-control);
    background: var(--ds-color-surface-brand);
    color: var(--ds-color-text-on-brand);
    /* type.knop en niet type.klein met een gewicht erbij. Modern Delft zet deze knop als
       `font: 700 var(--t-knop)/1 'Atkinson Hyperlegible'` (stijl.css:147), en dat IS type.knop:
       korps 16, regelhoogte 1, leesletter, vet. Twee rollen die samen hetzelfde zeggen als een
       rol die bestaat, is precies de vorm waar de tokenlaag voor is. */
    font: var(--ds-type-knop);
    text-decoration: none;
    white-space: nowrap;
  }
  /* color.text.accent als grond, want er is geen token surface.accent.hover en de waarde is
     precies de donkerder oker die de kop vandaag bij zweven zet (#855924). Staat als afwijking
     in het bouwverslag. */
  .ds-sitekop__knop:hover { background: var(--ds-color-text-accent); }

  /* Dezelfde grens als hierboven, en met opzet exact dezelfde: op een breedte waar allebei
     zichtbaar zijn staan er twee menu's, en op een breedte waar geen van beide het is staat er
     geen. Dat zijn twee toestanden die niemand kan bedoelen. */
  .ds-sitekop__meer { display: block; }
  @media (width > 969px) {
    .ds-sitekop__meer { display: none; }
  }
  .ds-sitekop__menuknop {
    display: inline-flex;
    align-items: center;
    min-block-size: var(--ds-maat-raakvlak);
    list-style: none;
    cursor: pointer;
    /* DE KNOP STAAT OP DE GROND VAN DE KOP, EN DIE IS PAPIER. Hier stond
       `text.on-ink-muted`, de wassing van de voet, en dat klopte zolang de kop donker was.
       Sinds hij papier is, is dat lichtblauw op bijna wit: gemeten 14 september 2026 op
       /producten, 900px breed, 2,0 tegen de 4,5 die geldt. Het is het ENIGE wat op een
       telefoon van het menu te zien is voordat je erop drukt. */
    color: var(--ds-color-text-body);
    font: var(--ds-type-etiket);
    letter-spacing: var(--ds-type-etiket-spatiering);
    text-transform: var(--ds-type-etiket-kapitaal);
  }
  .ds-sitekop--merk:not([data-stand="voorbij"]) .ds-sitekop__menuknop {
    color: var(--ds-color-text-on-brand);
  }
  .ds-sitekop__menuknop::-webkit-details-marker { display: none; }
  /* Open: de okeren merkkleur op de donkere kop, en de donkere oker op papier. Twee gronden,
     twee kleuren, en `mark.on.ink` haalt op papier 1,83. */
  .ds-sitekop__meer[open] > .ds-sitekop__menuknop { color: var(--ds-color-text-accent); }
  .ds-sitekop--merk:not([data-stand="voorbij"]) .ds-sitekop__meer[open] > .ds-sitekop__menuknop {
    color: var(--ds-color-mark-on-ink);
  }

  /* Het uitgeklapte menu hangt onder de kop en dekt de pagina af, dus het draagt een eigen
     grond en elevation.overlay: zo is te zien dat er iets overheen ligt. */
  .ds-sitekop__uit {
    position: absolute;
    inset-inline: 0;
    z-index: var(--ds-layer-sticky);
    display: flex;
    flex-direction: column;
    gap: var(--ds-space-kop-tekst);
    background: var(--ds-color-surface-inverse);
    padding: var(--ds-space-tussen) var(--ds-space-blok) var(--ds-space-blok);
    box-shadow: var(--ds-elevation-overlay);
  }

  /* HOGE CONTRASTMODUS. De pagina waar de bezoeker nu is, staat hier in mark.on.ink en verder
     nergens in: kleur draagt die betekenis alleen. In die modus krijgt elke link dezelfde
     LinkText, dus de huidige plek was niet meer aan te wijzen. Gemeten in Chromium op 12
     september 2026: 0 van de 4860 pixels verschilden tussen de huidige pagina en een andere,
     buiten die modus 372.

     Link lost hetzelfde probleem al op met gewicht.vet, en dat overleeft de modus wel. Dit is
     dus geen nieuwe vorm maar het antwoord dat het systeem er al voor heeft, hier ook gezet.
     Buiten deze modus verandert er niets: daar blijft de kleur het verschil.

     Het uitklapmenu krijgt in deze modus een rand. Zijn grond en zijn schaduw zijn het enige wat
     zegt dat er iets over de pagina heen ligt, en beide vallen daar weg. */
  @media (forced-colors: active) {
    .ds-sitekop__link[aria-current='page'] {
      font-weight: var(--ds-type-nadruk);
    }
    .ds-sitekop__uit {
      border: var(--ds-border-hairline) solid;
    }
  }
}

/* === sitevoet === */
/* Sitevoet. Twee dichtheden van een patroon.
 *
 * Canoniek: design/system/css/publiek.css:201-233 (footer.ev-voet), want die vorm staat op 27
 * van de 38 routes met een sitekader. De smalle vorm is .ev-fijndruk uit site.css:1200, de
 * vier wettelijke links onder aan een flowscherm.
 *
 * De twee vormen liggen vandaag twaalf gemeten eigenschappen uit elkaar, waaronder display
 * block tegen flex en box-sizing border-box tegen content-box. Die laatste verdwijnt zodra de
 * reset in @layer reset staat; wat overblijft is een verschil in dichtheid en geen tweede
 * onderdeel.
 *
 * De naam .ev-voet blijft bij dit patroon (B15). De vastgezette knoppenbalk van de flow, die
 * in site.css dezelfde naam draagt, heet Actiebalk.
 */

@layer patronen {
  .ds-sitevoet--vol { background: var(--ds-color-surface-sunken); }

  /* De ruimte tussen de kolommen komt uit gap en niet uit een marge op elke kolom: dan hebben
     de eerste en de laatste geen uitzondering nodig. Onder breekpunt.breed staan ze onder
     elkaar, erboven naast elkaar, met dezelfde stap. */
  .ds-sitevoet__in {
    display: flex;
    flex-direction: column;
    gap: var(--ds-space-blok-groot);
    max-inline-size: var(--ds-maat-kolom);
    margin-inline: auto;
    padding-block: var(--ds-space-sectie);
    padding-inline: var(--ds-space-blok);
  }
  /* 900px is --ds-breekpunt-breed; een mediavraag kan geen custom property lezen, dus het getal staat hier letterlijk. Strikt groter dan en niet vanaf: Modern Delft zet zijn smalle waarden in `@media (max-width: 900px)`, dus op precies 900px is het merk smal. Met `min-width: 900px` was het systeem daar breed en het merk smal, en dat verschil van een pixel viel nergens op omdat geen enkele meting op de rand zelf keek. */
  @media (width > 900px) {
    .ds-sitevoet__in {
      display: grid;
      grid-template-columns: repeat(4, 1fr);
      max-inline-size: var(--ds-maat-document);
    }
  }

  /* De kolom draagt zelf geen maat. Hij staat er als de plek waar een kop en een lijst bij
     elkaar horen, en als de naam die het register hem geeft. */
  .ds-sitevoet__kol { min-inline-size: 0; }

  /* color.text.muted en niet een lichtere trede: een kapitaaltje is ook tekst. De lichtste inkt
     van de oude stijlbladen haalde op deze grond 2,64:1. */
  .ds-sitevoet__t {
    margin-block-end: var(--ds-space-binnen-blok);
    color: var(--ds-color-text-muted);
    font: var(--ds-type-etiket);
    letter-spacing: var(--ds-type-etiket-spatiering);
    text-transform: var(--ds-type-etiket-kapitaal);
  }

  .ds-sitevoet__lijst {
    list-style: none;
    margin: 0;
    padding: 0;
  }
  /* GEEN STREEP IN EEN LIJST WAAR ALLES EEN LINK IS. De streep onder een link in een zin staat
     er omdat kleur daar het enige verschil zou zijn; in deze lijst is elk item een link en valt
     er niets te onderscheiden. Bij zweven komt de streep terug, zodat de aanwijzer nog steeds
     zegt wat aanklikbaar is. Het raakdoel is maat.raakvlak-min en komt uit lucht en niet uit
     letters, zodat het beeld niet verandert. */
  .ds-sitevoet__lijst a {
    display: inline-flex;
    align-items: center;
    min-block-size: var(--ds-maat-raakvlak-min);
    color: var(--ds-color-text-body);
    font: var(--ds-type-klein);
    text-decoration: none;
  }
  .ds-sitevoet__lijst a:hover {
    color: var(--ds-color-text-accent);
    text-decoration: underline;
    text-underline-offset: var(--ds-link-streep-afstand);
  }

  .ds-sitevoet__melden {
    max-inline-size: var(--ds-maat-kolom);
    margin-inline: auto;
    padding-inline: var(--ds-space-blok);
    padding-block-end: var(--ds-space-sectie);
  }
  @media (width > 900px) {
    .ds-sitevoet__melden { max-inline-size: var(--ds-maat-document); }
  }

  /* De uitgeversregel. Een bezoeker hoort te kunnen zien met wie hij zaken doet. */
  .ds-sitevoet__slot {
    max-inline-size: var(--ds-maat-kolom);
    margin-inline: auto;
    padding-inline: var(--ds-space-blok);
    padding-block-end: var(--ds-space-sectie);
    color: var(--ds-color-text-muted);
    font: var(--ds-type-etiket);
    letter-spacing: var(--ds-type-etiket-spatiering);
    text-transform: var(--ds-type-etiket-kapitaal);
  }
  @media (width > 900px) {
    .ds-sitevoet__slot { max-inline-size: var(--ds-maat-document); }
  }

  /* Smal: vier wettelijke links onder de tekst van een flowscherm. Geen eigen grond, want hij
     staat in de leeskolom en niet onder de pagina; de scheiding is een haarlijn in
     color.border.subtle en geen vlak. */
  .ds-sitevoet__wettelijk {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ds-space-tussen) var(--ds-space-blok);
    max-inline-size: var(--ds-maat-kolom);
    margin-inline: auto;
    padding-block-start: var(--ds-space-kop-tekst);
    padding-inline: var(--ds-space-blok);
    border-block-start: var(--ds-border-hairline) solid var(--ds-color-border-subtle);
    font: var(--ds-type-fijn);
  }
  @media (width > 900px) {
    .ds-sitevoet__wettelijk { max-inline-size: var(--ds-maat-kolom-breed); }
  }
  /* Op een telefoon staan deze vier naast elkaar, en een link van elf en een halve punt is
     zonder een eigen hoogte niet te raken. */
  .ds-sitevoet__wettelijk a {
    display: inline-flex;
    align-items: center;
    min-block-size: var(--ds-maat-raakvlak-min);
    color: var(--ds-color-text-muted);
  }
  .ds-sitevoet__wettelijk a:hover { color: var(--ds-color-text-accent); }

  /* DE DONKERE VOET. In de merkbron is dit `<footer class="voet op-blauw">` op alle 29 publieke
     bladen; bij ons stond hij op surface.sunken en dus licht op alle 28. Geteld op 14 september
     2026, en bijna gemist omdat een voet geen sectie is; zie de kop van dit onderdeel.

     ELKE KLEUR HIERONDER BESTOND AL. `text.on-ink`, `text.on-ink-muted`, `text.accent.on-ink` en
     `border.accent.on-ink` staan sinds 11 september in de tokens, met hun verhoudingen nagerekend
     per grond waarop ze werkelijk staan. Er komt voor deze hele omkering geen enkele nieuwe kleur
     bij, en dat is het bewijs dat die rollen goed geknipt zijn: een grond omkeren is dan een
     kwestie van de andere helft van elk paar pakken.

     LET OP DE OKER. `text.accent` haalt op een donkere grond 4,16 en dat is onder de eis voor
     kleine tekst; daarom staat hier `text.accent.on-ink`, dat naar een lichtere trede wijst. Die
     meting komt uit de merkbron zelf, bij hun `.op-blauw .kicker`, en `kleurpoort.mjs` weegt hem
     na op de gemaakte pagina. */
  .ds-sitevoet--inkt {
    background: var(--ds-color-surface-inverse);
    color: var(--ds-color-text-on-ink);
  }
  .ds-sitevoet--inkt .ds-sitevoet__t,
  .ds-sitevoet--inkt .ds-sitevoet__slot,
  .ds-sitevoet--inkt .ds-sitevoet__wettelijk,
  .ds-sitevoet--inkt .ds-sitevoet__wettelijk a {
    color: var(--ds-color-text-on-ink-muted);
  }
  .ds-sitevoet--inkt .ds-sitevoet__lijst a {
    color: var(--ds-color-text-on-ink);
  }
  .ds-sitevoet--inkt .ds-sitevoet__lijst a:hover,
  .ds-sitevoet--inkt .ds-sitevoet__wettelijk a:hover {
    color: var(--ds-color-text-accent-on-ink);
  }

  /* HET AANMELDBLOK KRIJGT ZIJN EIGEN LICHTE VLAK BINNEN DE DONKERE VOET, en dat is de keuze
     van 13 september 2026. De omkering hierboven raakt `__t`, `__slot`, `__wettelijk` en
     `__lijst a`, en dat zijn alle vier eigen delen van dit onderdeel. In `__melden` staat iets
     anders: een heel aanmeldformulier dat uit VREEMDE onderdelen is opgebouwd, en die stonden
     daardoor donker op donker. Gemeten met `node design/meting/kleuretalage.mjs`: 216 paar
     onder de WCAG-eis over 25 pagina's en 4.085 tekstelementen, allemaal hier, met 1,53 waar
     4,5 geldt op /privacy bij 1200 en 2,27 elders.

     WAAROM EEN LICHT VLAK EN NIET EEN `--op-inkt`-VARIANT PER ONDERDEEL. Drie redenen, en de
     eerste is doorslaggevend. (1) Een variant per onderdeel vraagt een klasse erbij in de
     opmaak, en die opmaak komt uit `web/publiek/sjablonen/ds-schil.html`, dat van het
     stagingspoor is en niet van dit spoor. Een oplossing die een ander spoor nodig heeft, is
     hier geen oplossing. (2) De rij die je dan zou omkeren is langer dan hij lijkt: naast
     `ds-tekst`, `ds-veldgroep`, `ds-veld` en `ds-knop` staan er drie `ds-melding`-blokken in
     hetzelfde vak (twee fout, een neutraal), waarvan er twee pas na een verkeerde invoer
     zichtbaar worden en dus door geen enkele meting op een stille pagina gewogen worden. Een
     licht vlak vangt ook die drie. (3) Elk van die onderdelen is nagerekend op surface.page.
     Hier blijven ze op surface.page staan, dus hun verhoudingen blijven gelden en er hoeft
     niets opnieuw nagerekend te worden.

     GEEN NIEUWE KLEUR. `surface.page` is de grond van elk schermoppervlak op alle 53 routes;
     het vlak leent hem en brengt niets nieuws mee. De hoek is `radius.vlak`, de rol voor een
     groot vlak, en de ruimte eromheen is `space.blok`, zodat het vlak niet tegen de kolommen
     erboven en de uitgeversregel eronder aan ligt.

     DE GOOT KOMT UIT DE BREEDTE EN NIET UIT PADDING. De basisregel zet de zijruimte met
     `padding-inline`, en dat kan hier niet: met een grond eronder wordt die gootruimte wit en
     loopt het vlak op een telefoon tot tegen de schermrand, met een afgesneden hoek. box-sizing
     is border-box (ds-basis.css:66), dus de binnenruimte telt in die breedte mee. */
  .ds-sitevoet--inkt .ds-sitevoet__melden {
    background: var(--ds-color-surface-page);
    border-radius: var(--ds-radius-vlak);
    color: var(--ds-color-text-body);
    inline-size: calc(100% - 2 * var(--ds-space-blok));
    padding: var(--ds-space-blok);
    margin-block-end: var(--ds-space-sectie);
  }
}

/* === sleutelrij === */
/* Sleutelrij. Een etiket en zijn waarde op een regel, links en rechts uit elkaar.
 *
 * Canoniek: design/system/css/site.css:122 (.ev-row), gekozen op criterium 1 als enige vorm met
 * beide ruimtematen uit de tokens. Criterium 2 wees de andere kant op (1.156 om 260), maar
 * criterium 1 gaat voor, en de zwaardere vorm zet 10px en 5px, allebei buiten de trap.
 *
 * Wat hier samenkomt: .ev-row en .ev-track__i zijn woord voor woord gelijk tot en met hun
 * nth-child(even)-blok, en .ev-person, .ev-pick__top en .ev-bar bouwen dezelfde rij nog eens met
 * andere ruimtematen. Daarnaast staat hij vijf keer met de hand getypt in vier flowsjablonen,
 * terwijl pipeline/site.py:61 design/system/onderdelen/ al als tweede sjabloonmap laadt. De twee
 * plaatselijke overschrijvingen (.ev-keuze__uit .ev-row en .ev-bon .ev-row) worden dichtheid.
 *
 * Dit onderdeel schrijft zijn eigen flex en gebruikt Rij niet. Rij is de goede keus voor twee
 * dingen naast elkaar, maar zijn ruimtetrap gaat van 12px naar 22px en de gemeten goot van deze
 * rij is 16px. Bovendien gaat dit onderdeel zelf over die ene regel: dat is precies het geval
 * waarin een component zijn eigen indeling mag schrijven.
 */

@layer componenten {
  .ds-sleutelrij {
    display: flex;
    flex-direction: column;
    margin: 0;
  }

  .ds-sleutelrij__rij {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: var(--ds-space-kop-tekst);
    padding-block: var(--sleutelrij-ruimte, var(--ds-space-binnen-blok));
  }
  .ds-sleutelrij--ruim  { --sleutelrij-ruimte: var(--ds-space-binnen-blok); }
  .ds-sleutelrij--dicht { --sleutelrij-ruimte: var(--ds-space-tussen); }

  .ds-sleutelrij__sleutel {
    font: var(--ds-type-klein);
    color: var(--ds-color-text-body);
  }

  /* De waarde in de displayletter. De gemeten maat is 24px en er is geen tokentrede op 24 in de
     displayletter; type.sectie (19px) is de dichtstbijzijnde die er wel is. */
  .ds-sleutelrij__waarde {
    margin: 0;
    text-align: end;
    color: var(--ds-color-text-default);
  }
  .ds-sleutelrij--display .ds-sleutelrij__waarde { font: var(--ds-type-sectie);
    letter-spacing: var(--ds-type-sectie-spatiering); }
  .ds-sleutelrij--tekst .ds-sleutelrij__waarde { font: var(--ds-type-brood); }

  /* De zebratint. De gemeten zijruimte is 14px en ligt buiten de trap; space.binnen-blok (12px)
     is de dichtstbijzijnde stap. De negatieve marge is even groot als de binnenruimte, zodat de
     tint buiten de tekst uitsteekt en de tekst zelf op zijn lijn blijft staan. */
  .ds-sleutelrij--zebra > .ds-sleutelrij__rij:nth-child(even) {
    background: var(--ds-color-surface-sunken);
    padding-inline: var(--ds-space-binnen-blok);
    margin-inline: calc(-1 * var(--ds-space-binnen-blok));
  }
}

/* === sluitblok === */
/* Sluitblok. Het blok onderaan een publieke pagina dat naar de flow leidt.
 *
 * Canoniek: etalage/index.html:183 en :214 (f3e9150aa539) voor nadrukkelijk en 526d8320a2b2
 * (.ev-slot) voor stil.
 *
 * Wat hier anders is dan vandaag: 85 ingangen op 27 pagina's staan in vijf markupvormen met
 * vier tot vijf verschillende sluitblokken eronder, terwijl de knop zelf al een vorm is. Twee
 * varianten van een blok volstaan, en het verschil tussen die twee is de grond en verder niets.
 *
 * De plaatsing komt van Stapel. Geen straal op het vlak: radius.control is voor knoppen en
 * invoervelden, een paneel krijgt er geen.
 */

@layer componenten {
  /* stil: doorzichtig, geen binnenruimte. Vijftien pagina's sluiten zo. */
  .ds-sluitblok--stil {
    background: none;
    padding: 0;
  }

  /* nadrukkelijk: het getinte vlak met een eigen kop. Twee keer op de voorpagina. */
  .ds-sluitblok--nadrukkelijk {
    background: var(--ds-color-surface-sunken);
    padding: var(--ds-space-blok);
  }

  .ds-sluitblok__fijndruk {
    font: var(--ds-type-fijn);
    color: var(--ds-color-text-muted);
    max-inline-size: var(--ds-maat-regel);
  }
}

/* === staafrij === */
/* Staafrij. Een rij plaatsen met een staaf en een getal ernaast: waar de akten liggen.
 *
 * Canoniek: de merkbron, `bundel/stijl.css` regel 548 tot 551, op de jaargang die het
 * merkspoor op 12 september 2026 stempelde (`origin/ontwerp/modern-delft`, `7ab18dc`,
 * jaargang `423fc022`). Tien voorkomens, op de voorpagina en op scherm 1 van de flow.
 *
 * DRIE KOLOMMEN EN NIET EEN FLEXRIJ. De naam, de staaf en het getal staan in een raster met
 * vaste buitenkolommen, want alleen dan liggen de staven van alle regels op dezelfde x. Met
 * een flexrij begint elke staaf waar zijn naam ophoudt, en dan is de rij geen vergelijking
 * meer maar een reeks losse regels.
 *
 * DE LENGTE VAN DE STAAF IS DE VERHOUDING ZELF EN GEEN DELER. De merkbron schrijft
 * `width: calc(100% / var(--i, 1))` met `--i` als geheel getal in de opmaak: 1, 2, 3, 5 bij de
 * getallen 46, 21, 15 en 9. Dat is de grootste gedeeld door de waarde, afgerond, en dus een
 * benadering: 21 van 46 is 46 procent en wordt zo op 50 getekend.
 *
 * Hier staat de verhouding zelf. Reden, en het is geen netheid: dit onderdeel zet de staaf
 * NAAST het getal. Een staaf die niet bij het getal ernaast past, is een tekening die tegen
 * zijn eigen bijschrift in spreekt, en dat is precies de vorm die dit project elders bestrijdt.
 * De macro rekent de verhouding uit de waarde en het maximum; in de opmaak staat een percentage
 * en geen deler. Terug te draaien door in `staafrij.html` de deling om te keren.
 */

@layer componenten {
  .ds-staafrij {
    display: flex;
    flex-direction: column;
    gap: var(--ds-space-tussen);
    max-inline-size: var(--ds-staafrij-maat);
  }

  .ds-staafrij__regel {
    display: grid;
    grid-template-columns: var(--ds-staafrij-naam) minmax(0, 1fr) var(--ds-staafrij-getal);
    align-items: center;
    gap: var(--ds-space-binnen-blok);
    font: var(--ds-type-klein);
  }

  .ds-staafrij__staaf {
    display: block;
    block-size: var(--ds-staafrij-dikte);
    border-radius: var(--ds-radius-fijn);
    background: var(--ds-color-surface-brand);
    /* De verhouding komt binnen als een percentage van 0 tot 100. Nul is een geldige uitkomst
       en hoort een streepje te blijven en geen niets: een plaats met nul akten staat er, en een
       staaf die verdwijnt leest als een regel die ontbreekt. */
    inline-size: max(var(--ds-staafrij-dikte), var(--ds-staafrij-deel, 0%));
  }

  /* Het getal rechts, in de cijferletter. De merkbron zet hem op de voorpagina in oker-tekst en
     binnen de flowkaart in mono met zachte inkt (`stijl.css:751`). Dat tweede is een regel van
     de kaart die in dit onderdeel reikt; hier is het een variant, zodat de kaart niets over
     deze staafrij hoeft te weten. */
  .ds-staafrij__getal {
    text-align: end;
    font-variant-numeric: tabular-nums;
    color: var(--ds-color-text-accent);
  }
  .ds-staafrij--stil .ds-staafrij__getal {
    font: var(--ds-type-code);
    color: var(--ds-color-text-muted);
  }

  /* In hoog contrast dwingt het systeem elke grond af en verdwijnt de staaf. Hij krijgt hier de
     rand die hem terugbrengt; de lengte blijft het verschil dragen. */
  @media (forced-colors: active) {
    .ds-staafrij__staaf {
      border: var(--ds-border-hairline) solid CanvasText;
      background: CanvasText;
    }
  }
}

/* === stapbalk === */
/* Stapbalk. De voortgangslijn boven in een flowkaart: hoe ver de koper is.
 *
 * Canoniek: de merkbron, `bundel/stijl.css` regel 712 tot 714, op de jaargang die het merkspoor
 * op 12 september 2026 stempelde (`origin/ontwerp/modern-delft`, `7ab18dc`, jaargang
 * `423fc022`). Vijftig voorkomens.
 *
 * HIJ VERVANGT PADWIJZER OP DE FLOW EN NERGENS ANDERS. Het sjabloon `Flow/Scherm` draagt vandaag
 * een Padwijzer in modus stap; die valt hier weg zodra dat sjabloon omgaat. Padwijzer zelf
 * verdwijnt NIET uit het systeem: hij draagt het kruimelpad op de publieke pagina's en dat blijft.
 *
 * DE BAAN IS DE HAARLIJN EN DE VULLING HET MERKVLAK. Drie pixels hoog, dus hij is een tekening
 * en geen bediening: er valt niets op te klikken en hij zegt alleen waar je bent.
 */

@layer componenten {
  .ds-stapbalk {
    position: relative;
    block-size: var(--ds-stapbalk-dikte);
    background: var(--ds-color-border-subtle);
  }

  /* De vulling begint links en loopt over de hele hoogte. Een percentage en geen som met twee
     custom properties: de macro rekent stap gedeeld door stappen uit, om dezelfde reden als bij
     Staafrij. Een balk die niet bij zijn eigen bijschrift past, spreekt tegen zichzelf in, en het
     bijschrift staat er bij dit onderdeel altijd ("Stap 3 van 7"). */
  .ds-stapbalk__vol {
    position: absolute;
    inset-block: 0;
    inset-inline-start: 0;
    display: block;
    inline-size: var(--ds-stapbalk-deel, 0%);
    background: var(--ds-color-surface-brand);
  }

  /* In hoog contrast dwingt het systeem elke grond af en zijn baan en vulling niet meer te
     onderscheiden. De vulling krijgt daar een rand; de baan blijft leeg. */
  @media (forced-colors: active) {
    .ds-stapbalk__vol {
      background: Highlight;
      border-inline-end: var(--ds-border-hairline) solid CanvasText;
    }
  }
}

/* === staprij === */
/* Staprij. Een genummerde volgorde van stappen, met per stap een titel en een uitleg.
 *
 * Canoniek: de merkbron, `bundel/stijl.css` regel 420 tot 425 (`.stappen` en `.stap`) en 519 tot
 * 520 (`.drie-stappen`), op de jaargang die het merkspoor op 12 september 2026 stempelde
 * (`origin/ontwerp/modern-delft`, `7ab18dc`, jaargang `423fc022`). Hij staat daar op drie
 * oppervlakken: de voorpagina en `_publiceer` met vier stappen onder elkaar, en `cadeau` met drie
 * naast elkaar. Geteld op 14 september 2026 met `klassentelling.py`: `stappen` 3, `stap` 11,
 * `cijfer` 11.
 *
 * DE LIJN BOVEN EEN STAP IS DE HAARLIJN EN GEEN RAND. In de merkbron is dat `.boven-lijn` met
 * `.lijn` erin, en die twee zijn Haarlijn. Dit blad tekent hem daarom zelf niet als `border`
 * maar zet een eigen element neer met dezelfde rol, want een onderdeel schrijft niet in de
 * klassen van een ander en `ds-haarlijn` is van Haarlijn. Wat hier staat is de PLAATS van die
 * lijn binnen de stap; de kleur komt van dezelfde rol als daar.
 *
 * WAAROM HET NUMMER EN DE TITEL SAMEN IN EEN DOOS ZITTEN. In de kolomvorm staan ze links en de
 * uitleg rechts; in de rijvorm staan ze boven de uitleg. Zonder die doos zou de kolomvorm drie
 * cellen hebben en de rijvorm twee, en dan is het twee rasters in plaats van een.
 *
 * DE OMSLAG IS EEN CONTAINERVRAAG EN GEEN MEDIAVRAAG. De merkbron doet het op 900px met het
 * venster, en dat is daar goed genoeg omdat deze rij er altijd in de volle breedte staat. Bij ons
 * staat hij op /cadeau in de leeskolom van een overzicht en straks mogelijk in een smaller
 * oppervlak, en dan is het venster het verkeerde ding om te meten.
 */

@layer componenten {
  /* DE BUITENSTE DOOS IS DE CONTAINER EN DE LIJST STAAT ERIN. Een element dat `container-type`
     draagt, is een container voor zijn KINDEREN en niet voor zichzelf; een `@container`-regel op
     dezelfde doos komt dus nooit uit en de smalle stand zou stil niets doen. Daarom deze twee
     lagen, net als bij Opening. */
  .ds-staprij {
    container: ds-staprij / inline-size;
  }

  .ds-staprij__lijst {
    display: flex;
    flex-direction: column;
    gap: var(--ds-staprij-ruimte);
    margin: 0;
    padding: 0;
    list-style: none;
  }

  .ds-staprij__stap {
    display: grid;
    grid-template-columns: minmax(0, 2fr) minmax(0, 3fr);
    column-gap: var(--ds-staprij-kolomgat);
    row-gap: var(--ds-space-binnen-blok);
    align-items: start;
  }

  /* De lijn loopt over de hele breedte van de stap en staat erboven, dus hij pakt beide kolommen.
     Hij is een eigen element en geen `border-block-start` op de stap, omdat de merkbron hem zo
     zet en omdat een rand op de stap in de rijvorm per kolom zou breken. */
  .ds-staprij__lijn {
    grid-column: 1 / -1;
    block-size: var(--ds-border-hairline);
    background: var(--ds-color-border-subtle);
  }

  .ds-staprij__kop {
    display: flex;
    flex-direction: column;
    gap: var(--ds-space-inline);
  }

  /* HET NUMMER IS TEKST EN DRAAGT DUS color.text.accent EN NIET color.mark. Die twee zijn allebei
     oker en ze lijken op elkaar; het verschil is dat het ene een TEKEN verft (de rasterstip, het
     vinkje, de streep onder een link) en het andere letters. Hier stond eerst color.mark, en
     `kleurpoort.mjs` wees hem af: 3,81 op surface.page tegen een eis van 4,5, negen keer. Dat
     staat met zoveel woorden in de toelichting van dat token ("Het teken en nooit de tekst") en de
     merkbron zegt het ook: `.cijfer` draagt daar `--oker-tekst` en niet `--oker`. */
  .ds-staprij__nummer {
    font: var(--ds-type-stapnummer);
    letter-spacing: var(--ds-type-stapnummer-spatiering);
    color: var(--ds-color-text-accent);
    font-variant-numeric: tabular-nums;
  }

  .ds-staprij__titel {
    font: var(--ds-type-sectie);
    letter-spacing: var(--ds-type-sectie-spatiering);
    color: var(--ds-color-text-default);
    text-wrap: balance;
    margin: 0;
  }

  .ds-staprij__uitleg {
    font: var(--ds-type-klein);
    color: var(--ds-color-text-default);
    margin: 0;
  }

  /* ONDER 900 STAAT ELKE STAP IN EEN KOLOM, en die 900 komt uit de merkbron en is niet gekozen.
     Daar staat de omslag op een mediavraag van 900px (regel 425), en daarnaast zet
     `.twee .kolom .stap` de stap altijd op een kolom zodra hij in de smalle helft van een sectie
     staat (regel 423). Die twee zeggen hetzelfde ding op twee manieren; als CONTAINERvraag op de
     rij zelf valt het samen. Nagemeten op 14 september 2026: op de voorpagina staat de rij daar in
     de volle breedte (1180px) en dan is de stap twee kolommen, en op /cadeau in de halve sectie
     (660px) en dan is hij er een. Bij ons is die rij op /cadeau 656px breed in de leeskolom, dus
     hij komt op dezelfde stand uit als de bron, en straks op de voorpagina op de andere.

     De stappen gaan daar bovendien verder uit elkaar staan, want zodra de uitleg onder de titel
     komt, lopen twee stappen anders in elkaar over. */
  @container ds-staprij (width < 900px) {
    .ds-staprij__lijst {
      gap: var(--ds-staprij-ruimte-smal);
    }
    .ds-staprij__stap {
      grid-template-columns: minmax(0, 1fr);
    }
  }
}

/* === tabel === */
/* Tabel. Rijen en kolommen met een zichtbaar onderschrift.
 *
 * Canoniek: etalage/de-kwartierstaat.html:146 (5f25af42ffec), gekozen op criterium 1: border-box,
 * 13px uit --ev-t-small en een regelhoogte van 20,15px, de enige gemeten rij met alle drie. De
 * handgezette 14px van report.css:141 en :187 valt op type.klein, en 13 maal 1,55 is exact die
 * 20,15px. De canonieke rij heet vandaag tr.ev-wij terwijl maar een van de vier bronregels die
 * klasse draagt; overgenomen is de vorm en niet de klassenaam.
 *
 * Geen enkele rand. De wisselende rijtint doet het werk dat elders een streep zou doen; dat is de
 * vorm die op beide schermoppervlakken al staat.
 *
 * F14 is de rommeligste familie van de meting: 49 varianten, 17 verloop, 14 zonder eigen vorm, en
 * een pariteit van rijen (372 tegen 324 gewogen) die geen ontwerpkeuze is. Hier is de pariteit
 * een prop met een standaard en geen toeval.
 */

@layer componenten {
  .ds-tabel {
    border-collapse: collapse;
    inline-size: 100%;
  }
  .ds-tabel--ruim  { font: var(--ds-type-klein); }
  .ds-tabel--dicht { font: var(--ds-type-fijn); }

  /* Het onderschrift is zichtbaar. Vandaag staat het op negen routes volledig verborgen achter
     .ev-visually-hidden, en dat is een tabel die alleen bestaat voor wie hem al ziet. */
  .ds-tabel__onderschrift {
    text-align: start;
    font: var(--ds-type-klein);
    font-weight: var(--ds-type-nadruk);
    color: var(--ds-color-text-default);
    padding-block-end: var(--ds-space-binnen-blok);
  }

  .ds-tabel th,
  .ds-tabel td {
    text-align: start;
    vertical-align: top;
    font-weight: var(--ds-type-gewoon);
    padding-block: var(--ds-space-binnen-blok);
    padding-inline: 0 var(--ds-space-kop-tekst);
    color: var(--ds-color-text-body);
  }

  /* De kopregel is een kapitaaletiket, en elke kopcel is een th met scope. De meting draagt
     empty-table-header als eigen regel met tien knopen: een kopcel zonder tekst is geen kopcel. */
  /* `.ds-tabel` staat ervoor omdat `.ds-tabel th, .ds-tabel td` hierboven twee stukken heeft en
     deze regel er een had. Twee declaraties kwamen daardoor nooit aan: het gewicht bleef 400 waar
     de rol een zwaardere stand vraagt, en de kleur bleef text.body waar hier text.muted staat.
     Het gewicht staat sinds 12 september 2026 in type.etiket zelf en niet meer op deze regel, maar
     de twee klassen blijven nodig: de kortschrijfwijze `font` moet ook winnen. Gemeten op de stijlgids
     op 12 september 2026: fontWeight 400 en oklch(0.387 0.042 250.2), en dat is inkt-700 en niet
     inkt-500. De verhouding van de bedoelde kleur is nagerekend voordat hij aangezet werd: 5,181
     op surface.page en 4,507 op surface.sunken, dus de zebrarij haalt hem ook. */
  .ds-tabel .ds-tabel__kop {
    font: var(--ds-type-etiket);
    letter-spacing: var(--ds-type-etiket-spatiering);
    text-transform: var(--ds-type-etiket-kapitaal);
    color: var(--ds-color-text-muted);
  }

  /* De specificatie is twee kolommen: het etiket links, de waarde rechts. */
  .ds-tabel--specificatie .ds-tabel__cel {
    text-align: end;
    padding-inline-end: 0;
    color: var(--ds-color-text-default);
  }

  /* De soort van een kolom, en niet zijn uitlijning. Een getalkolom is vijf dingen tegelijk,
     gemeten op report/erfverhaal-positie-en-economie.html op 12 september 2026 op 1280px: rechts,
     tabellencijfers, de leesletter display, de volle inkt in plaats van de zachte, en geen
     ondergrens voor zijn breedte. Ze horen bij elkaar, dus ze staan hier bij elkaar.

     De ondergrens zit op de tekstkolom en niet op de getalkolom. Dat is de omgekeerde vorm van wat
     je zou verwachten en het is de reden dat de regel bestaat: zonder hem krijgt een kolom met vier
     tekens data de breedte van zijn kop, en de prozakolom ernaast wordt een snipper.

     Een tabel zonder de prop krijgt geen van deze regels. De tien tabellen die in fase 4a al om
     zijn dragen geen getalkolom, en die mogen niet verschuiven omdat er een prop bij komt. */
  /* DE SELECTOREN DRAGEN TWEE KLASSEN EN DAT IS GEEN VERSIERING. `.ds-tabel th, .ds-tabel td`
     hierboven zet text-align en color met een selector van twee stukken; een kale
     `.ds-tabel__kolom--getal` heeft er een en verliest dus, en dan komt de uitlijning nooit aan.
     Precies die fout staat opgeschreven in report.css:241 en :247, waar hij twee keer gemaakt is.
     Met de celklasse erbij zijn het er twee en wint hij, en bij gelijkspel met
     `.ds-tabel--specificatie .ds-tabel__cel` wint deze omdat hij er in dit blad onder staat.

     DE KOPCEL KRIJGT WAT OVER CIJFERS EN LETTERS GAAT, EN NIET DE KLEUR. Uitlijning en
     tabellencijfers wel, want die gaan over hoe de cijfers eronder uitlijnen en de kop draagt zelf
     cijfers ("25% print", "Share KD <= 20"). De letter niet, en dat is gemeten en niet gekozen: in
     `report.css` heeft `.ev-tab thead th { font-family: var(--ev-mono) }` een kiezer van drie
     stukken en `.ev-num { font-family: var(--ev-display) }` van een, dus de kop van een getalkolom
     staat daar gewoon in mono. De kleur niet, en dat IS een keuze: `.ev-tab th.ev-num` zet daar wel
     `--ev-ink` en wint van `.ev-tab thead th`, dus de bron kleurt de getalkop wel degelijk donkerder.
     Hier niet, omdat een kopregel waarvan de ene kop donkerder is dan de andere uit elkaar valt als
     regel. Dat is een oordeel over de kopregel en geen meting; het staat hier zodat het na te lezen
     is en niet als vondst terugkomt. */
  .ds-tabel__kop.ds-tabel__kolom--getal,
  .ds-tabel__sleutel.ds-tabel__kolom--getal,
  .ds-tabel__cel.ds-tabel__kolom--getal {
    text-align: end;
  }
  /* De kop krijgt ook de tabellencijfers, en dat is de zesde eigenschap. In `report.css` staat
     `font-variant-numeric: tabular-nums` op `.ev-num` zonder onderscheid tussen `th` en `td`, dus
     de kop draagt hem daar ook. Dat is niet leeg: koppen in deze rapporten heten "25% print",
     "12% buy" en "Share KD <= 20". Hij staat hier apart en na `font: var(--ds-type-etiket)`, want
     de `font`-verkorting zet `font-variant` terug op normaal. */
  .ds-tabel__kop.ds-tabel__kolom--getal {
    font-variant-numeric: tabular-nums;
  }
  /* Een getal houdt de leesletter en krijgt cijfers van gelijke breedte, zodat een kolom getallen
     recht onder elkaar staat. Hier stond `font-family: var(--ds-letter-display)`, en dat was de
     laag overslaan: zolang de displayletter Libre Caslon was viel het niet op, en sinds hij op
     12 september 2026 Archivo werd stonden veertig cellen in de merkletter. Modern Delft doet het
     omgekeerde: `.rij-feit b`, `.balk b` en `.prijs-getal` houden alle drie de leesletter en zetten
     alleen `font-variant-numeric: tabular-nums` en een okeren kleur. */
  .ds-tabel__sleutel.ds-tabel__kolom--getal,
  .ds-tabel__cel.ds-tabel__kolom--getal {
    font-variant-numeric: tabular-nums;
    color: var(--ds-color-text-accent);
  }

  /* Een term of een code. Mono zet hem apart van het proza ernaast zonder hem zwaarder te maken;
     type.code is dezelfde trede als type.klein, want mono leest op dezelfde px groter. */
  .ds-tabel__kop.ds-tabel__kolom--sleutelwoord {
    font-family: var(--ds-type-term);
  }
  .ds-tabel__sleutel.ds-tabel__kolom--sleutelwoord,
  .ds-tabel__cel.ds-tabel__kolom--sleutelwoord {
    font: var(--ds-type-code);
  }

  /* De ondergrens zit op de tekstkolom en niet op de getalkolom. Dat is de omgekeerde vorm van wat
     je zou verwachten en het is de reden dat de regel bestaat: zonder hem krijgt een kolom met vier
     tekens data de breedte van zijn kop, want een kop van 19 tot 22 tekens in kapitaal met
     letterspatiering is breder dan elk getal eronder, en de prozakolom ernaast wordt een snipper.
     Dat de tabel daardoor breder wordt dan zijn gebied is de bedoeling: hij staat in een Schuifbak
     en schuift daarbinnen. */
  .ds-tabel__kop.ds-tabel__kolom--tekst,
  .ds-tabel__sleutel.ds-tabel__kolom--tekst,
  .ds-tabel__cel.ds-tabel__kolom--tekst {
    min-inline-size: var(--ds-maat-tabelkolom-min);
  }

  /* En de andere helft van diezelfde breedte: een getal- of sleutelwoordkolom krimpt tot wat zijn
     inhoud nodig heeft. `inline-size: 1%` is daarvoor de vorm die werkt: een tabel verdeelt wat
     overblijft over de kolommen die geen breedte opgeven, en dat zijn precies de prozakolommen.
     Zonder deze regel krijgt een kolom met vier tekens data de breedte van zijn kop, want de kop
     staat in kapitaal met letterspatiering.

     EEN GETALCEL MAG NIET OP NOWRAP. Dat stond in report.css eerst wel en het was daar de
     eigenlijke fout: een kolom met de kop CPA bevat niet alleen "15" maar ook "150
     (partnerships)". Op nowrap wordt zo'n langste waarde de ondergrens van de hele kolom en is er
     geen ruimte meer voor de tekst ernaast. Gemeten in dezelfde tabel, in pixels: de rolkolom van
     99 tekens ging van 111 naar 233 toen nowrap eraf ging, CPA van 163 naar 67 en Cap van 144 naar
     73. Een sleutelwoord blijft wel op een regel: dat wordt opgezocht en vergeleken, en
     "stamboom zoeken op achternaam gratis" halverwege afbreken helpt niemand. De kop mag in beide
     gevallen afbreken, ook waar de cellen eronder dat niet mogen. */
  .ds-tabel__kop.ds-tabel__kolom--getal,
  .ds-tabel__sleutel.ds-tabel__kolom--getal,
  .ds-tabel__cel.ds-tabel__kolom--getal,
  .ds-tabel__kop.ds-tabel__kolom--sleutelwoord,
  .ds-tabel__sleutel.ds-tabel__kolom--sleutelwoord,
  .ds-tabel__cel.ds-tabel__kolom--sleutelwoord {
    inline-size: 1%;
  }
  .ds-tabel__sleutel.ds-tabel__kolom--sleutelwoord,
  .ds-tabel__cel.ds-tabel__kolom--sleutelwoord {
    white-space: nowrap;
  }
  .ds-tabel__kop.ds-tabel__kolom--getal,
  .ds-tabel__kop.ds-tabel__kolom--sleutelwoord {
    white-space: normal;
  }

  /* EEN RIJ MET NADRUK IS VET EN NIET GEKLEURD. Negen rapporttabellen doen dit vandaag met
     `color: var(--ev-accent)` en verder niets. Gemeten op
     report/erfverhaal-positie-en-economie.html op 12 september 2026: 3,806:1 op de grond en
     3,311:1 op de zebrarij, bij 13px met gewicht 400. Beide onder de 4,5 die 1.4.3 voor tekst van
     die maat vraagt, en kleur staat er alleen, dus ook 1.4.1. Het tokenbestand zegt het zelf over
     die kleur: nooit als tekst.

     Gewicht is geen kleur en de tekst blijft op de gewone inkt staan, dus met vet gaan allebei die
     deuren dicht. De twee klassen staan er weer om de cascade: `.ds-tabel th, .ds-tabel td` zet
     `font-weight` met twee stukken, dus een regel met een stuk zou verliezen. Dat is dezelfde
     fout die `.ds-tabel__kop` maakte. */
  .ds-tabel__rij--nadruk > .ds-tabel__sleutel,
  .ds-tabel__rij--nadruk > .ds-tabel__cel {
    font-weight: var(--ds-type-nadruk);
  }

  /* EEN TABEL DIE UITSTAPT KRIJGT EEN BOVENGRENS PER CEL. Buiten zijn kolom is er meer ruimte, en
     zonder grens neemt een prozacel die gewoon. Gemeten op de breedste cel van
     report/erfverhaal-markets.html: zonder grens 653px op een venster van 1280 en 886px op 1920, met
     grens 586 en 795, en de oude `.ev-tab--wide` deed daar 564 en 739.

     DAT LAATSTE VERSCHIL HEEFT TWEE OORZAKEN EN NIET EEN. Op 1280 is de tabel in beide standen
     1.236px en zijn de zeven vaste kolommen samen 672px oud tegen 650px nieuw, dus de restkolom
     groeit van 564 naar 586 en die 22px komt volledig uit de kopcellen: nieuw Atkinson Hyperlegible
     700 met letterafstand 1,54px en binnenruimte 0/16, oud IBM Plex Mono 500 met 0,88px en 12/12.
     Smallere kopcellen geven smallere vaste kolommen en dus een bredere restkolom. Op 1920 komt daar
     de tabelbreedte bij (1.475 oud tegen 1.516 nieuw), en die 41px komt van de derde regel van
     `.ev-tab--wide` die hier niet is overgenomen: `width: max-content` met `max-width: 100%` op de
     tabel zelf. Teruggezet brengt die 795 naar 751 op 1920 en verandert hij niets op 1280.

     WAT DE GRENS ZELF NIET DOET: klemmen. `max-inline-size` op een tabelcel bindt niet zoals op een blok, want
     het tabelalgoritme mag hem overrulen als de inhoud anders niet past. Ook met de grens erin
     meten twaalf cellen van markets meer dan 352px, en dat deden ze in de oude stand ook. Hij duwt,
     en dat is genoeg: de tabel blijft leesbaar zonder dat een kolom onmogelijk wordt. */
  .ds-tabel--uitgestapt th,
  .ds-tabel--uitgestapt td {
    max-inline-size: var(--ds-maat-tabelcel-max);
  }

  .ds-tabel--zebra tbody tr:nth-child(odd) { background: var(--ds-color-surface-sunken); }
  .ds-tabel--zebra tbody tr > :first-child { padding-inline-start: var(--ds-space-binnen-blok); }
  .ds-tabel--zebra tbody tr > :last-child  { padding-inline-end: var(--ds-space-binnen-blok); }
}

/* === tegelwand === */
/* Tegelwand. De kwartierstaat als wand van tegels, waarvan er een omdraait zodra een voorouder
 * vaststaat.
 *
 * Canoniek: de merkbron, `bundel/stijl.css` regel 383 tot 402, op de jaargang die het merkspoor
 * op 12 september 2026 stempelde (`origin/ontwerp/modern-delft`, `7ab18dc`, jaargang
 * `423fc022`). Honderdeenennegentig voorkomens, de tweede van de drie waarin het register
 * `Veldraster` uiteenvalt.
 *
 * DE GEVONDEN KANT IS DE STANDAARD, EN DAT IS DE HELE VEILIGHEID VAN DIT ONDERDEEL.
 *
 * Een tegel heeft twee kanten: een lege achterkant met een sierrand, en een voorkant met de foto
 * en de naam van de voorouder. De voorkant is de INHOUD. Blijft een tegel op zijn achterkant
 * staan, dan is die inhoud weg, en wel op de stilste manier die er is: geen foutmelding, geen gat
 * in de wand, een tegel die er gewoon is en niets zegt.
 *
 * Daarom draait `--gevonden` de tegel naar zijn voorkant, en doet de kale klasse dat niet. Er is
 * geen script nodig om een gevonden tegel te laten zien: de server weet wie er gevonden is en
 * zet die klasse. **Een tegel kan dus niet op zijn achterkant blijven staan doordat een script
 * niet draait, want geen enkel script draait hem daarheen.**
 *
 * De merkbron doet het andersom: daar is de achterkant de standaard, draait een script gevonden
 * tegels om, en vangt `.no-js` op de wortel het geval op waarin dat script er niet is. Dat werkt
 * bij hen omdat een inline script die wortelklasse omzet voordat er geverfd is; onze CSP staat
 * dat niet toe, en een onderdeel mag hier geen wortelklasse schrijven. Dezelfde afweging als bij
 * Onthuller, met dezelfde uitkomst.
 *
 * WAT HIER MET OPZET NIET STAAT: DE ONTHULLENDE LUS, EN HIJ IS BETER DAN HIJ LIJKT. `beweging.js`
 * zet in de merkbron de gevonden tegels één voor één om en telt de teller van nul naar acht: het
 * is de zoekactie in beeld en geen versiering. Hier stond dat hij inhoud verbergt, en dat is te
 * kort door de bocht; nagemeten op 13 september 2026.
 *
 * Waarom hij hier toch niet staat. Elke vorm ervan begint met het VERBERGEN van tegels die al
 * gevonden zijn, en dan is er een venster waarin een stervend script ze blank laat. De merkbron
 * dekt dat af met `.no-js` op de wortel; wij mogen geen wortelklasse zetten en onze CSP staat het
 * inline script niet toe dat hem vóór het verven omzet. Onthuller kon dit oplossen doordat het
 * wapenen in de terugroep van zijn eigen waarnemer zit, en dat bewijs is hier niet beschikbaar.
 *
 * De mechaniek staat er wel: `--om` draait een tegel, dus een script dat hem ooit wil laten
 * rondgaan hoeft alleen die klasse te zetten. Of de animatie terugkomt is een afweging tussen
 * beleving en zekerheid op een verkooppagina, en dat is een besluit van Ernst en niet van dit
 * onderdeel. Het ligt bij de manager.
 *
 * EN DE MERKBRON HEEFT DAAR EEN GAT DAT WIJ NIET HEBBEN. `.no-js` beschermt tegen "geen
 * javascript", niet tegen "javascript werkt en dit script niet". Staat `js` op de wortel terwijl
 * `beweging.js` uitblijft, dan staan alle veertien tegels leeg en zegt de teller `8 / 14`: acht
 * gevonden en niets te zien. Gemeld aan het merkspoor op 13 september 2026.
 */

@layer componenten {
  .ds-tegelwand {
    padding: var(--ds-tegelwand-binnenruimte);
    border-radius: var(--ds-radius-vlak);
    background: var(--ds-color-surface-brand);
  }

  /* Het kopje boven een rij, in de cijferletter. Een stap zachter dan de tegels zelf, want het
     benoemt de rij en is niet de inhoud ervan. */
  .ds-tegelwand__rijnaam {
    margin-block: var(--ds-space-binnen-blok) var(--ds-space-tussen);
    font: var(--ds-type-kaft-etiket);
    letter-spacing: var(--ds-type-kaft-etiket-spatiering);
    text-transform: uppercase;
    color: var(--ds-color-text-on-brand-muted);
  }
  .ds-tegelwand__rijnaam:first-child { margin-block-start: 0; }

  /* Een generatie is een rij van gelijke kolommen. Het aantal komt als getal binnen en niet als
     variant per aantal: de kwartierstaat verdubbelt per generatie, dus er zijn er straks
     zestien en tweeendertig, en dan is een klasse per aantal een lijst die niet afloopt. */
  .ds-tegelwand__rij {
    display: grid;
    grid-template-columns: repeat(var(--ds-tegelwand-kolommen, 1), minmax(0, 1fr));
    gap: var(--ds-tegelwand-ruimte);
  }

  /* De tegel is een container, want de vraag of zijn naam past gaat over ZIJN breedte. Zie de
     regel over de naam verderop; daar staat waarom dat niet het aantal kolommen is. */
  .ds-tegelwand__kaart {
    position: relative;
    aspect-ratio: 1;
    container: ds-tegelwand-tegel / inline-size;
    perspective: var(--ds-tegelwand-diepte);
  }

  .ds-tegelwand__zijden {
    position: absolute;
    inset: 0;
    transform-style: preserve-3d;
    transition: transform var(--ds-tegelwand-omslag) var(--ds-motion-onthul-kromme);
  }

  .ds-tegelwand__zijde {
    position: absolute;
    inset: 0;
    overflow: hidden;
    border-radius: var(--ds-radius-tegel);
    backface-visibility: hidden;
  }

  /* De voorkant ligt een halve slag gedraaid, zodat hij pas in beeld komt als de tegel zelf een
     halve slag draait. Zonder die twee draaiingen zou hij door de achterkant heen schijnen. */
  .ds-tegelwand__voor { transform: rotateY(180deg); }

  .ds-tegelwand__kaart--gevonden > .ds-tegelwand__zijden,
  .ds-tegelwand__kaart--om > .ds-tegelwand__zijden { transform: rotateY(180deg); }

  /* DE ONTHULLING, EN HIJ HEEFT GEEN SCRIPT NODIG. De merkbron draait de gevonden tegels een voor
     een om en telt de teller op: de zoekactie in beeld, en geen versiering. Dat is te goed om te
     laten vallen, en het mag geen script worden, want een script kan uitblijven en dan staan er
     veertien lege tegels met "acht gevonden" eronder. Zo staat het vandaag in de merkbron.

     Een animatie met `animation-fill-mode: backwards` doet hetzelfde werk zonder dat gat. De
     RUSTSTAND blijft `rotateY(180deg)`, de waarheid, en die staat er ook als er geen animatie
     draait; `backwards` laat een tegel alleen TIJDENS ZIJN WACHTTIJD op zijn achterkant staan. Er
     is geen bestand dat kan uitblijven, geen terugroep die niet komt, en geen toestand waarin een
     tegel blank blijft omdat de code stierf: css blijft niet halverwege hangen, ook niet als het
     tabblad op de achtergrond staat, want een animatie loopt op de klok.

     EEN KEER EN GEEN LUS. De merkbron herhaalt na vijf seconden, want het is daar een demo op een
     pagina met vaste inhoud. Een herhaling gaat elke ronde terug naar "niets gevonden", en dat is
     precies de onwaarheid die dit onderdeel uitsluit.

     EN DE TUSSENPOOS IS VAN DEZE WAND EN VAN GEEN ANDER ONDERDEEL. Hij stond eerst op
     `motion.onthul.tussenpoos` (90ms), de tussenpoos van Onthuller, en dat is gemeten te snel:
     een tegel draait 1100ms, dus met 90ms ertussen staan alle acht binnen 630ms TEGELIJK te
     draaien en ziet een bezoeker een wand die in een keer kantelt. De zin eronder zegt dat een
     tegel omdraait zodra een naam vaststaat, enkelvoud en achter elkaar, en een groep die samen
     kantelt vertelt dat niet.

     `tegelwand.tussenpoos` is 360ms, ongeveer een derde van de draaiduur: een tegel is
     herkenbaar begonnen voordat de volgende aanzet, en het geheel is klaar op ongeveer 2,5
     seconde. Dat derde is een oordeel; de grens eromheen is gemeten door het merkspoor op
     13 september 2026: onder ongeveer 150ms wordt het een beweging, boven ongeveer 700ms is het
     een wachttijd.

     EN DE PLAATS IS EEN GETAL EN GEEN TIJD. `--ds-tegelwand-beurt` draagt de plaats van de tegel
     in de reeks; de vermenigvuldiging staat hier. Hij droeg eerst een tijd die de macro uitrekende
     met een 90 in zijn eigen sjabloon, en dat is een tweede kopie van een tokenwaarde op de plek
     waar niemand hem zoekt. Zelfde vorm als `--ds-onthuller-volgorde`.

     `design/meting/wandpoort.mjs` meet de draaiing in graden uit de matrix die de browser
     uitrekent, en hij is zien weigeren met de val van de merkbron erin gebouwd. */
  @keyframes ds-tegelwand-onthul {
    from { transform: rotateY(0); }
    to { transform: rotateY(180deg); }
  }
  .ds-tegelwand__kaart--gevonden > .ds-tegelwand__zijden {
    animation: ds-tegelwand-onthul var(--ds-tegelwand-omslag) var(--ds-motion-onthul-kromme)
               backwards;
    animation-delay: calc(var(--ds-tegelwand-beurt, 0) * var(--ds-tegelwand-tussenpoos));
  }

  /* Het beeld en het lege vlak vullen hun kant helemaal, EN VERDER NIETS OP DIE KANT.
     Dit stond als `.ds-tegelwand__zijde > *` en dat is een kind te veel: de naam is ook een
     rechtstreeks kind, dus die kreeg `block-size: 100%` en groeide uit tot de hele tegel plus zijn
     eigen binnenruimte. Gemeten op 13 september 2026 met de stijlgids op 900px: tegel 377px hoog,
     naamdoos 425px, en de tekst stond 24px onder de BOVENkant van de tegel in plaats van onderaan,
     op het doorzichtige deel van het verloop en over het gezicht op de foto. `overlooppoort.mjs`
     zag hetzelfde van de andere kant: op 320 en 360px viel er tekst weg binnen een doos die klipt.

     Een `> *` beschrijft een plaats en niet een ding, en dan hangt hij aan wie er later een kind
     bij zet. Deze twee staan bij naam. */
  .ds-tegelwand__zijde > img,
  .ds-tegelwand__leeg {
    inline-size: 100%;
    block-size: 100%;
    border-radius: var(--ds-radius-tegel);
  }

  /* De naam onder de foto, op een verloop zodat hij leesbaar blijft op elk beeld. Hij staat OP
     het beeld en niet eronder, want een wand van veertien tegels met een bijschrift eronder is
     twee keer zo hoog en leest niet meer als een wand.

     EN HIJ WORDT NIET AFGEKAPT. Een naam is hier de inhoud en geen etiket: "Willem · timmerman"
     inkorten tot "Willem · tim..." haalt het beroep weg waar de tegel voor staat. Hij mag dus
     afbreken over twee regels, en dat past: gemeten op 13 september 2026 is de strook 48px bij
     een regel en 70px bij twee, en de smalste tegel die nog een naam draagt is 96px. */
  .ds-tegelwand__naam {
    position: absolute;
    inset-inline: 0;
    inset-block-end: 0;
    padding: var(--ds-space-kop-tekst) var(--ds-space-binnen-blok) var(--ds-space-tussen);
    border-end-start-radius: var(--ds-radius-tegel);
    border-end-end-radius: var(--ds-radius-tegel);
    background: linear-gradient(transparent,
      color-mix(in oklch, var(--ds-color-surface-inverse) 92%, transparent));
    color: var(--ds-color-text-on-ink);
    font: var(--ds-type-fijn);
    font-weight: var(--ds-type-nadruk);
  }

  /* ONDER DE 96px IS EEN TEGEL TE SMAL VOOR ZIJN NAAM EN WORDT HIJ EEN VLEK, en dat is een vraag
     aan de TEGEL en niet aan het venster of aan het aantal kolommen.

     Hier stond `.ds-tegelwand__rij--dicht`, gezet vanaf zes kolommen. De redenering klopte half:
     een vensterbreedte zegt inderdaad niets, want dezelfde wand op een breed scherm heeft even
     smalle tegels als op een smal scherm met minder kolommen. Maar het aantal kolommen zegt het
     ook niet. Gemeten op 13 september 2026: bij vier kolommen op 320px is een tegel 45px, en daar
     stond de naam gewoon; bij acht kolommen op 1280px is hij 119px en daar viel hij weg. Twee keer
     het verkeerde antwoord, van allebei de kanten. `overlooppoort.mjs` vond de eerste.

     WAT ER GEMETEN IS EN WAT EEN OORDEEL IS. Gemeten: de strook is 48px bij een regel, dus onder
     de 48px wordt hij hoe dan ook afgesneden. Oordeel: een naam die meer dan de helft van zijn
     tegel inneemt is een band en geen bijschrift, en daarom staat de grens op het dubbele, 96px.
     Op 320px houdt een rij van twee tegels (95px) daardoor net geen naam; dat is de smalste
     breedte die de brief noemt en het is de kant waarop deze grens hoort te vallen. */
  @container ds-tegelwand-tegel (width < 96px) {
    .ds-tegelwand__naam { display: none; }
  }

  /* Wie beweging uitzet, krijgt de tegel in zijn stand en niet de weg ernaartoe. De animatie gaat
     daar helemaal uit, en dan staat de ruststand er meteen: gevonden is gevonden. Dat is geen
     terugval maar dezelfde waarheid zonder de onthulling, en het is de weging waar
     `wandpoort.mjs` om draait. */
  @media (prefers-reduced-motion: reduce) {
    .ds-tegelwand__zijden { transition: none; }
    .ds-tegelwand__kaart--gevonden > .ds-tegelwand__zijden { animation: none; }
  }

  /* In hoog contrast verdwijnt elke grond, dus ook het verschil tussen de wand en de pagina en
     tussen een tegel en zijn buur. Randen houden de wand een wand. */
  @media (forced-colors: active) {
    .ds-tegelwand { border: var(--ds-border-hairline) solid CanvasText; }
    .ds-tegelwand__zijde { border: var(--ds-border-hairline) solid CanvasText; }
  }
}

/* === tekst === */
/* Tekst. Alle lopende en inline tekst, en het enige onderdeel dat de maat, de regelhoogte en
 * de kleur van gewone tekst zet.
 *
 * Canoniek: design/system/css/publiek.css:65-73 (7c1409f52c4e, 2.656 gewogen, 17px/1,5) voor de
 * toon lead, design/system/css/tokens.css:116 (--ev-t-body) voor brood, en
 * pipeline/templates/site/maak.html:144 (03ceeedfc30f) voor fijn. Criterium gebruik.
 *
 * Dit is de zwaarste samenvouwing van het voorstel: vijf auditfamilies met samen 276 varianten
 * worden vijf tonen maal zeven kleuren, omdat vrijwel elk gemeten verschil daarbinnen een maat
 * of een kleur is en geen andere soort tekst.
 *
 * Drie dingen die hier anders zijn dan vandaag:
 *
 * 1. De regellengte staat in deze laag. De meting vond 205 alinea's met een mediaan van 90,7ch
 *    waar de brief er ongeveer 75 vraagt; maat.regel is 75ch en staat hier een keer.
 * 2. De kleur komt uit een gesloten verzameling en niet uit het stijlblad dat toevallig laatst
 *    laadt. De twee paren die samen 903 van de 1.009 contrastknopen dragen bestaan hier niet
 *    meer: color.text.muted vervangt elke tekstrol van --ev-ink-faint (2,912 op papier), en
 *    kleur="accent" wijst altijd naar color.text.accent (5,303) en nooit naar color.mark (3,806).
 * 3. nadruk is <strong> en geen font-weight op een <span>. Nadruk die je alleen ziet is voor de
 *    helft van de ontvangers geen nadruk.
 *
 * Wat dit bestand NIET kan zien: de grond waar de tekst op staat. Op color.surface.warm zijn
 * kleur="gedempt" (4,285) en kleur="accent" (4,386) verboden; kleur="fout" mag daar sinds de
 * merkwissel wel (4,636, was 4,636). Die twee zijn op 12 september 2026 van plaats gewisseld,
 * want de nieuwe okertekst is lichter en de nieuwe foutkleur een trede donkerder. De regel hangt
 * aan Vlak en aan het paginasjabloon, en staat in tekst.md opgeschreven.
 */

@layer componenten {
  .ds-tekst {
    /* De enige plek in het systeem waar een regellengte staat. Hij doet niets aan een inline
       als (span, small, code) en dat is goed: een regel is een blok. */
    max-inline-size: var(--ds-maat-regel);
  }

  /* De toon bepaalt de maat; er is geen aparte maat-as. */
  .ds-tekst--lead  { font: var(--ds-type-lead); }
  .ds-tekst--brood { font: var(--ds-type-brood); }
  .ds-tekst--klein { font: var(--ds-type-klein); }
  .ds-tekst--fijn  { font: var(--ds-type-fijn); }
  .ds-tekst--code  { font: var(--ds-type-code); }

  /* De kleuren. Zeven, en geen achtste: wie een kleur mist, mist een rol en niet een waarde. */
  .ds-tekst--kleur-standaard       { color: var(--ds-color-text-default); }
  .ds-tekst--kleur-body            { color: var(--ds-color-text-body); }
  .ds-tekst--kleur-gedempt         { color: var(--ds-color-text-muted); }
  .ds-tekst--kleur-accent          { color: var(--ds-color-text-accent); }
  .ds-tekst--kleur-fout            { color: var(--ds-color-text-danger); }
  .ds-tekst--kleur-op-inkt         { color: var(--ds-color-text-on-ink); }
  .ds-tekst--kleur-op-inkt-gedempt { color: var(--ds-color-text-on-ink-muted); }

  /* Nadruk verandert het gewicht en nooit de kleur: kleur="op-inkt" moet op de donkere grond
     kunnen blijven staan als de zin nadruk draagt. */
  .ds-tekst__nadruk { font-weight: var(--ds-type-nadruk); }
}

/* === tekstvak === */
/* Tekstvak. Een tekstinvoer van meer regels: het eigen voorwoord en het correctiebericht.
 *
 * Canoniek: design/system/css/site.css:450 (.ev-opdracht textarea), gemeten als 679aea2f98f0.
 * design/system/correctie.html:103 is verloop en verdwijnt hierin.
 *
 * De vorm is die van Veld en staat hier een tweede keer, want een onderdeel schrijft alleen zijn
 * eigen klassen; ds-tekstvak mag niet uit ds-veld erven. De waarden komen uit dezelfde tokens,
 * dus ze kunnen niet uiteenlopen zonder dat het token verschuift.
 *
 * Het aantal regels staat als rows-attribuut en niet als hoogte in css. Een hoogte in px breekt
 * zodra de bezoeker de letter groter zet; rows rekent in regels mee.
 */

@layer componenten {
  .ds-tekstvak {
    inline-size: 100%;
    min-block-size: calc(var(--ds-maat-raakvlak) * 2);
    padding: var(--ds-space-kop-tekst);
    border: 0;
    border-radius: var(--ds-radius-control);
    /* WIT EN NIET DE TINT. Ernst koos op 12 september 2026 dat het merk voorgaat: Modern Delft zet
       een veld, een tegel, een kaart en de kaft van het boek op `--wit` en dit systeem zette ze op
       de tint. De tint blijft waar hij iets werkelijk verzonken maakt (een zebrarij, een uitstand,
       een blok dat inhoud groepeert); wit is de grond van wat OP de pagina ligt. Zie besluit B59. */
    background: var(--ds-color-surface-raised);
    /* type.veld en niet de losse letterfamilie. Tot 12 september 2026 stond hier
       `font-family: var(--ds-letter-display)` met de toelichting dat het veld de enige bediening
       met de displayletter is. Dat klopte zolang de displayletter Libre Caslon was; sinds hij
       Archivo is, zette die regel elk invoerveld in de merkletter, en Modern Delft zet zijn velden
       juist in de leesletter. Een onderdeel dat een primitief aanraakt in plaats van een rol merkt
       een merkwissel op de verkeerde manier. */
    font: var(--ds-type-veld);
    color: var(--ds-color-text-body);
    /* Alleen hoger en nooit breder: breder dan zijn kolom is horizontaal schuiven op 320px. */
    resize: vertical;
    transition: box-shadow var(--ds-motion-feedback), color var(--ds-motion-feedback);
  }

  .ds-tekstvak::placeholder { color: var(--ds-color-text-muted); }

  /* gevuld: er staat iets in, en dan draagt het vak de volle inkt. */
  .ds-tekstvak:not(:placeholder-shown) { color: var(--ds-color-text-default); }

  .ds-tekstvak:focus-visible {
    outline: var(--ds-control-focus-breedte) solid var(--ds-color-focus);
    outline-offset: var(--ds-control-focus-afstand);
  }

  .ds-tekstvak[aria-invalid='true'] {
    box-shadow: inset 0 0 0 var(--ds-border-hairline) var(--ds-color-border-danger);
  }

  .ds-tekstvak:disabled {
    background: var(--ds-color-surface-sunken);
    box-shadow: none;
    color: var(--ds-color-text-muted);
    cursor: not-allowed;
  }

  /* De teller staat onder het vak, is een status en geen alert, en draagt de maat van het kleine
     lettertje. */
  .ds-tekstvak__teller {
    font: var(--ds-type-fijn);
    color: var(--ds-color-text-muted);
    text-align: end;
  }

  /* HOGE CONTRASTMODUS, en het is dezelfde vorm als Veld dus dezelfde reparatie; zie veld.css
     voor de afweging. Gemeten in Chromium op 12 september 2026 verschilden geldig en ongeldig
     hier 0 van de 113344 pixels, waar dat buiten die modus 2242 is. Een rand overleeft de modus,
     dus er is geen forced-color-adjust nodig; de stand komt uit de stijl van de lijn en niet uit
     zijn kleur, want in deze modus is er maar een inkt. */
  @media (forced-colors: active) {
    .ds-tekstvak {
      border: var(--ds-border-hairline) solid;
    }
    .ds-tekstvak[aria-invalid='true'] {
      border-style: dashed;
    }
    .ds-tekstvak:read-only {
      border-style: dotted;
    }
    .ds-tekstvak:disabled {
      border-style: solid;
    }
    .ds-tekstvak:focus-visible {
      outline-color: Highlight;
    }
  }
}

/* === toestemmingsbalk === */
/* Toestemmingsbalk. De overlay bij het eerste bezoek, 116 voorkomens op 27 routes.
 *
 * Canoniek: etalage/index.html:278 (72f35cb9f714, 324 gewogen) met de regel in
 * design/system/css/publiek.css:161-170. Gekozen op standaarden en niet op gebruik.
 *
 * Wat er verandert:
 *
 * 1. DE WEIGERKNOP KRIJGT EEN ZICHTBARE BEGRENZING. Hij is vandaag papier op tint: 1,150:1,
 *    waar WCAG 1.4.11 om 3:1 vraagt voor de grens van een bediening. Hij wordt Knop vorm stil,
 *    met de inzetring in color.border (4,507 op de tint van deze balk). Dat gebeurt in Knop en
 *    niet hier; deze balk zet alleen de grond waar die ring op staat.
 * 2. BEIDE KNOPPEN HALEN maat.raakvlak. Ook dat komt uit Knop.
 * 3. HIJ IS GEEN DIALOOG MEER. Hij vangt de focus niet af, dus hij is een gebied met een naam.
 *
 * Hij valt vandaag binnen het kader van main en telde daardoor in het meetscript overal als
 * sectie mee, wat drie paginatypes verzon die niet bestaan (B13). Hier staat hij buiten de
 * stroom: fixed, op layer.overlay, boven de plakkende kop.
 */

@layer patronen {
  .ds-toestemmingsbalk {
    position: fixed;
    inset-inline: 0;
    inset-block-end: 0;
    z-index: var(--ds-layer-overlay);
    background: var(--ds-color-surface-sunken);
    box-shadow: var(--ds-elevation-overlay);
  }

  /* weg is een echt attribuut en geen klasse. Zonder deze regel wint de display hierboven van
     de standaardstijl van de browser en blijft een gekozen balk staan. */
  .ds-toestemmingsbalk[hidden] { display: none; }

  .ds-toestemmingsbalk__in {
    max-inline-size: var(--ds-maat-kolom);
    margin-inline: auto;
    padding-block: var(--ds-space-kop-tekst) var(--ds-space-blok);
    padding-inline: var(--ds-space-blok);
  }
  /* 900px is --ds-breekpunt-breed; een mediavraag kan geen custom property lezen, dus het getal staat hier letterlijk. Strikt groter dan en niet vanaf: Modern Delft zet zijn smalle waarden in `@media (max-width: 900px)`, dus op precies 900px is het merk smal. Met `min-width: 900px` was het systeem daar breed en het merk smal, en dat verschil van een pixel viel nergens op omdat geen enkele meting op de rand zelf keek. */
  @media (width > 900px) {
    .ds-toestemmingsbalk__in {
      max-inline-size: var(--ds-maat-kolom-breed);
      padding-block: var(--ds-space-blok);
    }
  }

  .ds-toestemmingsbalk__t {
    margin-block-end: var(--ds-space-inline);
    color: var(--ds-color-text-default);
    font: var(--ds-type-sectie);
    letter-spacing: var(--ds-type-sectie-spatiering);
  }

  .ds-toestemmingsbalk__p {
    margin-block-end: var(--ds-space-binnen-blok);
    max-inline-size: var(--ds-maat-regel);
    color: var(--ds-color-text-body);
    font: var(--ds-type-fijn);
  }

  /* Ze staan naast elkaar en breken af in plaats van de balk breder te maken. Weigeren staat
     niet verder weg dan aanvaarden: even groot, even ver, even makkelijk. */
  .ds-toestemmingsbalk__knoppen {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ds-space-binnen-blok);
  }
}

/* === veld === */
/* Veld. Een tekstinvoer van een regel.
 *
 * Canoniek: design/system/css/site.css:63-67 (.ev-field), gemeten als 221b6e5eda32 op
 * pipeline/templates/site/maak.html:50. Het veld is een vlak en geen omlijning: tint, geen rand,
 * radius.control.
 *
 * Drie dingen die hier anders zijn dan vandaag:
 *
 * 1. De plaatshouder gaat van --ev-ink-faint (2,912:1) naar color.text.muted (5,181:1). Hij draagt
 *    nooit de veldnaam; die staat in het label van de Veldgroep.
 * 2. :focus wordt :focus-visible, uit color.focus en de twee focustokens. Een muisklik in een veld
 *    laat de ring achterwege, een tabaanslag niet.
 * 3. Ongeldig is een echt attribuut, aria-invalid, en geen klasse. De haarlijn in
 *    color.border.danger hangt eraan, en kleur staat daar niet alleen: de Veldgroep zet er een
 *    teken en een zin bij.
 *
 * De twee kopieen verschilden alleen in lettermaat, 24px in site.css en 22px in publiek.css. Dat
 * verschil is verloop met een gedateerde oorzaak en niet twee maten; veld.korps is 24.
 */

@layer componenten {
  .ds-veld {
    inline-size: 100%;
    min-block-size: var(--ds-maat-raakvlak);
    /* Iets minder binnenruimte dan een knop: de veldtekst is een punt groter dan een
       knoplabel, en zonder die correctie komt het veld hoger uit dan de knop ernaast. De maat is
       in de browser gemeten en niet gerekend; een invoerveld van Chrome telt zijn
       eigen regelbox mee. Beide landen zo op 52px. */
    padding: calc(var(--ds-space-kop-tekst) - var(--ds-veld-hoogtecorrectie)) var(--ds-space-kop-tekst);
    border: 0;
    border-radius: var(--ds-radius-control);
    /* WIT EN NIET DE TINT. Ernst koos op 12 september 2026 dat het merk voorgaat: Modern Delft zet
       een veld, een tegel, een kaart en de kaft van het boek op `--wit` en dit systeem zette ze op
       de tint. De tint blijft waar hij iets werkelijk verzonken maakt (een zebrarij, een uitstand,
       een blok dat inhoud groepeert); wit is de grond van wat OP de pagina ligt. Zie besluit B59. */
    background: var(--ds-color-surface-raised);
    /* type.veld en niet de losse letterfamilie. Tot 12 september 2026 stond hier
       `font-family: var(--ds-letter-display)` met de toelichting dat het veld de enige bediening
       met de displayletter is. Dat klopte zolang de displayletter Libre Caslon was; sinds hij
       Archivo is, zette die regel elk invoerveld in de merkletter, en Modern Delft zet zijn velden
       juist in de leesletter. Een onderdeel dat een primitief aanraakt in plaats van een rol merkt
       een merkwissel op de verkeerde manier. */
    font: var(--ds-type-veld);
    color: var(--ds-color-text-body);
    transition: box-shadow var(--ds-motion-feedback), color var(--ds-motion-feedback);
  }

  /* De plaatshouder is een voorbeeld en nooit de naam van het veld. Van --ev-ink-faint naar
     color.text.muted, die 4,507 haalt op surface.sunken, de tint waarop een veld staat. Hier stond
     5,181 en dat is diezelfde kleur op surface.page; een veld staat daar niet op. */
  .ds-veld::placeholder { color: var(--ds-color-text-muted); }


  .ds-veld--breedte-vol   { inline-size: 100%; }
  .ds-veld--breedte-kort  { inline-size: 100%; max-inline-size: var(--ds-maat-knop-max); }
  /* Vier cijfers plus de binnenruimte. Er is geen breedtetoken voor een jaarveld; twee maal het
     raakvlak is 88px en dat is de kleinste maat uit de tokens waar 1892 in de displayletter van
     24px in past. */
  .ds-veld--breedte-jaar  { inline-size: calc(var(--ds-maat-raakvlak) * 2); max-inline-size: 100%; }

  /* gevuld: er staat iets in, en dan draagt het veld de volle inkt. Leeg draagt het de gedempte
     plaatshouder en de gedempte inkt. Een veld zonder plaatshouder is altijd gevuld in deze zin. */
  .ds-veld:not(:placeholder-shown) { color: var(--ds-color-text-default); }

  .ds-veld:focus-visible {
    outline: var(--ds-control-focus-breedte) solid var(--ds-color-focus);
    outline-offset: var(--ds-control-focus-afstand);
  }

  .ds-veld[aria-invalid='true'] {
    box-shadow: inset 0 0 0 var(--ds-border-hairline) var(--ds-color-border-danger);
  }

  /* alleen-lezen: er valt niets te typen, dus het is geen vlak meer maar een omtrek. Hij staat
     boven :disabled, want een uitgeschakeld veld voldoet ook aan :read-only. */
  .ds-veld:read-only {
    background: var(--ds-color-surface-page);
    box-shadow: inset 0 0 0 var(--ds-border-hairline) var(--ds-color-border-subtle);
    cursor: default;
  }

  /* Uit met tokens en niet met doorzichtigheid, net als bij Knop: color.text.muted op
     color.surface.sunken is 4,507:1, en dat paar is nagerekend. */
  .ds-veld:disabled {
    background: var(--ds-color-surface-sunken);
    box-shadow: none;
    color: var(--ds-color-text-muted);
    cursor: not-allowed;
  }

  /* HOGE CONTRASTMODUS. Dit veld is een vlak zonder rand: border is 0 en de grens tegen het
     papier is de tint van de grond. In die modus wordt elke grond Canvas en elke box-shadow
     weggegooid, dus er bleef van dit veld niets over dan de letters erin. Gemeten in Chromium op
     12 september 2026: tussen geldig en ongeldig verschilden 0 van de 21063 pixels, en tussen
     schrijfbaar en alleen-lezen ook 0. Buiten die modus is dat 826 en 834.

     Hier is geen forced-color-adjust nodig en dus staat hij er niet. Een rand overleeft de modus
     gewoon; alleen de kleur ervan wordt overgenomen, en dat is precies de bedoeling. Wat niet
     overleeft is een tweede kleur: in deze modus is er een inkt, dus color.border.danger en
     color.border.subtle vallen op dezelfde waarde. De stand moet daarom uit de lijn zelf komen
     en niet uit zijn kleur:

       in rust        een doorlopende haarlijn, zodat het veld uberhaupt een grens heeft. Dat is
                      WCAG 1.4.11: de grens van een bediening moet te zien zijn
       ongeldig       gestreept, de luidste onderbreking die een lijn kent
       alleen-lezen   gestippeld, de zachtste, want alleen-lezen is geen fout maar een mededeling

     Waarom de stand in de STIJL van de lijn zit en niet in zijn dikte. De hoogte van een veld
     volgt uit de regel plus de binnenruimte plus de rand; border-box verandert daar niets aan
     zolang er geen vaste hoogte staat. Met de dikte als teken sprong het veld van 61 naar 63
     pixels zodra de foutmelding kwam, gemeten op 12 september 2026. Een stijlwissel kost geen
     pixel, dus het veld blijft staan waar het staat.

     Dat het veld in deze modus eenmalig van 59 naar 61 pixels gaat, is er de prijs van: zonder
     rand is er geen grens. Buiten de modus verschuift er niets. */
  @media (forced-colors: active) {
    .ds-veld {
      border: var(--ds-border-hairline) solid;
    }
    .ds-veld[aria-invalid='true'] {
      border-style: dashed;
    }
    /* Dezelfde volgorde als hierboven: alleen-lezen staat boven uit, want een uitgeschakeld veld
       voldoet ook aan :read-only. */
    .ds-veld:read-only {
      border-style: dotted;
    }
    .ds-veld:disabled {
      border-style: solid;
    }
    .ds-veld:focus-visible {
      outline-color: Highlight;
    }
  }
}

/* === veldgroep === */
/* Veldgroep. Label, bediening, hulptekst en foutmelding als een ding.
 *
 * Canoniek: web/publiek/sjablonen/basis.html:196 en :202, het enige paar in de repo waar een
 * label met `for` aan een veld hangt, plus etalage/methode.html:174 voor de fieldset.
 *
 * Wat hier anders is dan vandaag, en waarom:
 *
 * 1. Het label is een echt <label for> en nooit een plaatshouder. maak.html:177 en :178 leunen
 *    vandaag op de plaatshouder als toegankelijke naam (B088). In dit onderdeel is `label` een
 *    parameter zonder standaardwaarde, dus een veld zonder label kan niet renderen.
 * 2. De foutmelding staat in een gebied met role="alert", en de bediening krijgt aria-invalid en
 *    aria-describedby. Die drie attributen komen vandaag nul keer voor in beide sjabloonmappen.
 * 3. Een groep rendert <fieldset><legend>. Dat is de reparatie van labels-or-instructions op de
 *    rij naamvelden van scherm 2, waar nu een p.ev-label boven de groep staat en het veld alleen
 *    een aria-label draagt.
 * 4. Kleur draagt de fout nooit alleen: er staat een teken voor en er staat een zin.
 *
 * De plaatsing komt van Stapel. Dit blad zet geen flex en geen grid.
 */

@layer componenten {
  /* Ook een fieldset, en die brengt een rand, een marge en een minimumbreedte mee die niemand
     vroeg. De minimumbreedte is de reden dat een fieldset op 320px buiten zijn kolom kan steken. */
  .ds-veldgroep {
    margin: 0;
    padding: 0;
    border: 0;
    min-inline-size: 0;
  }

  .ds-veldgroep__label {
    font: var(--ds-type-brood);
    font-weight: var(--ds-type-nadruk);
    color: var(--ds-color-text-body);
    transition: color var(--ds-motion-feedback);
  }
  /* Een legend uit zichzelf staat ingesprongen en boven de rand; die twee zijn hier weg. */
  .ds-veldgroep--groep > .ds-veldgroep__label {
    padding-inline: 0;
    inline-size: 100%;
  }

  /* focus-binnen: zolang de bediening de focus heeft, draagt het label de volle inkt. */
  .ds-veldgroep:focus-within > .ds-veldgroep__label { color: var(--ds-color-text-default); }

  /* Verborgen voor het oog en nooit voor een schermlezer. display:none of hidden zou hem uit de
     toegankelijkheidsboom halen, en dan is het label weg in plaats van onzichtbaar.

     De selector draagt .ds-veldgroep__label mee en niet omdat het mooier leest: de regel erboven
     zet op een legend inline-size 100% met twee klassen, en die won van deze met een. Gevolg: een
     verborgen legenda was 1px hoog en zo breed als het venster, absoluut gepositioneerd zonder
     gepositioneerde voorouder, en hij telde mee in de schuifbreedte van het document. Gemeten op
     11 september 2026 in de stijlgids op 1280px: 1280 bij 1, tot x=1414. */
  .ds-veldgroep__label.ds-veldgroep__verborgen,
  .ds-veldgroep__verborgen {
    position: absolute;
    inline-size: var(--ds-border-hairline);
    block-size: var(--ds-border-hairline);
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  .ds-veldgroep__verplicht {
    font: var(--ds-type-fijn);
    font-weight: var(--ds-type-gewoon);
    color: var(--ds-color-text-muted);
  }

  .ds-veldgroep__hulp {
    font: var(--ds-type-klein);
    color: var(--ds-color-text-muted);
    max-inline-size: var(--ds-maat-regel);
  }

  .ds-veldgroep__fout {
    font: var(--ds-type-klein);
    color: var(--ds-color-text-danger);
    max-inline-size: var(--ds-maat-regel);
  }
  /* Het teken staat er omdat kleur de betekenis nooit alleen draagt. Het is aria-hidden, want de
     zin ernaast zegt het al. */
  .ds-veldgroep__teken {
    font-weight: var(--ds-type-nadruk);
  }

  /* ongeldig: de foutkleur landt op de groep als geheel, met een haarlijn aan de aanloopkant.
     Hij staat als inzetschaduw en niet als rand, zodat er bij een fout geen pixel verschuift. */
  .ds-veldgroep--ongeldig {
    box-shadow: inset var(--ds-border-hairline) 0 0 0 var(--ds-color-border-danger);
  }

  /* uit: bij vorm=groep is dit een echt disabled op de fieldset, en bij vorm=veld draagt de
     bediening het echte attribuut. Deze klasse doet alleen het label. */
  .ds-veldgroep--uit > .ds-veldgroep__label { color: var(--ds-color-text-muted); }
  .ds-veldgroep--uit > .ds-veldgroep__hulp { color: var(--ds-color-text-muted); }
}

/* === vinkje === */
/* Vinkje. Een aan-uitkeuze die niet exclusief is: de toestemming, de bijverkoop.
 *
 * Canoniek: design/system/css/site.css:363 (.ev-opt met .ev-opt__mark), de vorm die vier keer
 * letterlijk gelijk gebouwd staat: .ev-opt__mark, .ev-keuze__mark, .ev-stem__mark en
 * .ev-kaart__mark. Een stip in een vierkant vakje met een inzetring van border.hairline in
 * color.mark, op papierkleur.
 *
 * DIT IS DE WORTEL VAN B007. Vijf bedieningen in de flow zetten hun eigen invoerveld op
 * opacity 0 en tekenen er een span naast; met echte tabaanslagen gemeten op flow/vier en
 * flow/kies verandert er bij focus niets. Hier is het invoerveld zelf het zichtbare vakje:
 * appearance: none haalt het browservinkje weg en laat de bediening staan. De focusring valt dus
 * om het zichtbare deel, en de toegankelijkheidsboom weet wat er aan staat.
 *
 * De uit-stand wordt nooit met opacity 0 gemaakt. Dat is de stand die een koper het eerst ziet,
 * en de meting sloeg hem daardoor over, zodat van elk tweestandsonderdeel precies de helft geteld
 * is (G027).
 *
 * Het vinkje is geen pseudo-element maar een verloop op de achtergrond. Een ::before op een
 * invoerveld is buiten appearance: none niet afgesproken; een achtergrond is dat wel.
 */

@layer componenten {
  /* De rij is het tikdoel en staat op maat.raakvlak. Het vakje zelf is 24px, de ondergrens uit
     WCAG 2.2 SC 2.5.8, en staat binnen dat raakvlak. De plaatsing komt van Rij. */
  .ds-vinkje {
    min-block-size: var(--ds-maat-raakvlak);
    cursor: pointer;
  }

  .ds-vinkje__vak {
    appearance: none;
    flex: none;
    inline-size: var(--ds-maat-raakvlak-min);
    block-size: var(--ds-maat-raakvlak-min);
    margin: 0;
    border-radius: var(--ds-radius-control);
    background-color: var(--ds-color-surface-raised);
    background-position: center;
    background-repeat: no-repeat;
    /* Het vakje is het enige in dit systeem waar een lijn iets omsluit: zonder rand is het geen
       bediening maar een gat in het papier. Ernst, 10 september 2026. */
    box-shadow: inset 0 0 0 var(--ds-border-hairline) var(--ds-color-mark);
    cursor: pointer;
    transition: background-color var(--ds-motion-feedback);
  }

  /* aan: de stip, half zo breed als het vakje. */
  .ds-vinkje__vak:checked {
    background-image: radial-gradient(closest-side, var(--ds-color-mark) 100%, transparent 100%);
    background-size: 50% 50%;
  }

  /* onbepaald: een streep in plaats van een stip.

     Hier stond `[aria-checked='mixed']` als haak, en dat was op twee manieren fout. ARIA in HTML
     verbiedt aria-checked op een native checkbox, en axe meldt het ook (aria-conditional-attr,
     serious, op de stijlgids gemeten op 11 september 2026): een schermlezer leest de echte
     checked-eigenschap en die kent maar twee standen. De halve stand van een checkbox is de
     eigenschap `indeterminate`, en die staat alleen in de dom; een server kan hem niet zetten.
     Vandaar twee haken: de klasse die de macro rendert, zodat de streep er meteen staat, en
     :indeterminate, zodat hij blijft staan zodra een script de eigenschap zet. Alleen die tweede
     bereikt de toegankelijkheidsboom, en dat staat in vinkje.md. */
  .ds-vinkje--onbepaald .ds-vinkje__vak,
  .ds-vinkje__vak:indeterminate {
    background-image: linear-gradient(var(--ds-color-mark), var(--ds-color-mark));
    background-size: 50% var(--ds-border-focus);
  }

  .ds-vinkje__vak:focus-visible {
    outline: var(--ds-control-focus-breedte) solid var(--ds-color-focus);
    outline-offset: var(--ds-control-focus-afstand);
  }

  .ds-vinkje__tekst {
    font: var(--ds-type-brood);
    color: var(--ds-color-text-body);
    max-inline-size: var(--ds-maat-regel);
  }

  /* uitgeschakeld met tokens en niet met doorzichtigheid. De ring gaat van color.mark naar
     color.border, dus kleur is niet het enige verschil: de cursor en het echte disabled staan er
     ook. */
  .ds-vinkje__vak:disabled {
    background-color: var(--ds-color-surface-sunken);
    box-shadow: inset 0 0 0 var(--ds-border-hairline) var(--ds-color-border);
    cursor: not-allowed;
  }
  .ds-vinkje__vak:disabled:checked {
    background-image: radial-gradient(closest-side, var(--ds-color-text-muted) 100%, transparent 100%);
  }
  .ds-vinkje:has(.ds-vinkje__vak:disabled) {
    cursor: not-allowed;
  }
  .ds-vinkje:has(.ds-vinkje__vak:disabled) .ds-vinkje__tekst {
    color: var(--ds-color-text-muted);
  }

  /* HOGE CONTRASTMODUS. In die modus gooit de browser elke background-image weg en zet hij
     grond en inkt op de kleuren die de gebruiker zelf koos. De stip hierboven is een
     background-image, dus een aangevinkt vakje was daar niet van een leeg vakje te
     onderscheiden: 0 van de 600 pixels verschilden, gemeten in Chromium op 12 september 2026,
     en de streep van de onbepaalde stand viel op dezelfde manier weg.

     Kleur is hier niet het probleem. currentColor lost niets op, want het beeld verdwijnt
     ongeacht welke kleur erin staat.

     Waarom dit blok forced-color-adjust zet en geen ::after tekent. Het zichtbare vakje IS het
     invoerveld, en dat is de reparatie van B007: zet je de stip in een pseudo-element, dan moet
     dat pseudo-element op een input staan, en dat is buiten appearance: none niet afgesproken.
     De enige andere uitweg was het vakje weer naast het invoerveld zetten, en dat is precies de
     fout die dit onderdeel repareert. forced-color-adjust: none haalt dit ene element uit de
     overname, en daarom staan hieronder uitsluitend systeemkleuren: Canvas en CanvasText zijn de
     grond en de inkt die de gebruiker koos, GrayText zijn uitgeschakelde inkt en Highlight zijn
     selectiekleur. Het is dus geen uitzetten van de modus maar het tekenen in zijn palet.

     Wat niet in dit blok staat, staat er met opzet niet: de maten, de plaatsing en
     background-size komen uit de regels hierboven en zijn geen kleur, dus die overleven. */
  @media (forced-colors: active) {
    .ds-vinkje__vak {
      forced-color-adjust: none;
      background-color: Canvas;
      box-shadow: inset 0 0 0 var(--ds-border-hairline) CanvasText;
    }
    .ds-vinkje__vak:checked {
      background-image: radial-gradient(closest-side, CanvasText 100%, transparent 100%);
    }
    .ds-vinkje--onbepaald .ds-vinkje__vak,
    .ds-vinkje__vak:indeterminate {
      background-image: linear-gradient(CanvasText, CanvasText);
    }
    .ds-vinkje__vak:focus-visible {
      outline-color: Highlight;
    }
    .ds-vinkje__vak:disabled {
      background-color: Canvas;
      box-shadow: inset 0 0 0 var(--ds-border-hairline) GrayText;
    }
    .ds-vinkje__vak:disabled:checked {
      background-image: radial-gradient(closest-side, GrayText 100%, transparent 100%);
    }
  }
}

/* === vlak === */
/* Vlak. Een getint of gekleurd blok met binnenruimte, en de enige manier waarop iets in dit
 * systeem van de pagina wordt afgezet.
 *
 * Canoniek: pipeline/templates/site/vier.html:166 (ced0739d2376, de cta-vorm), met zijn regel in
 * design/system/css/site.css:180: geen rand, geen straal, 22px binnenruimte uit --ev-s5. Die 22px
 * is space.blok en staat hier als token.
 *
 * Drie dingen die hier vastliggen:
 *
 * 1. Geen straal en geen rand. Een vlak dat een straal krijgt, wordt een kaart, en tokens.css:125
 *    bindt de enige gemeten straal aan knoppen en velden. De zwaardere vlakvarianten vielen in de
 *    audit precies hierop af: 3px straal op een paneel.
 * 2. Elke grond zet zijn eigen tekstkleur. Een grond zonder tekstkleur laat de kleur van de ouder
 *    binnen, en dat is hoe papierkleur op papierkleur ontstaat. Op de warme grond staat tekst.body
 *    en niet tekst.muted: dat paar haalt daar 4,285 en zakt door de eis.
 * 3. Het vlak is geen bediening. Er staat hier geen zweefstand, geen focusregel en geen cursor,
 *    want er valt niets te raken.
 *
 * De twee gemeten vormen die vandaag dezelfde zes declaraties onder twee namen dragen (B173)
 * komen hier samen in de grond gedempt.
 */

@layer componenten {
  .ds-vlak {
    display: block;
    padding: var(--vlak-ruimte, var(--ds-space-blok));
    background: var(--ds-color-surface-sunken);
    color: var(--ds-color-text-body);
    /* Met opzet nul, en niet weggelaten: dit is de regel die een vlak geen kaart laat worden. */
    border: 0;
    border-radius: 0;
  }

  /* De binnenruimte is een stap uit de ruimtetrap en geen vrij getal. */
  .ds-vlak--ruimte-binnen-blok { --vlak-ruimte: var(--ds-space-binnen-blok); }
  .ds-vlak--ruimte-kop-tekst   { --vlak-ruimte: var(--ds-space-kop-tekst); }
  .ds-vlak--ruimte-blok        { --vlak-ruimte: var(--ds-space-blok); }

  /* gedempt: de tint die in dit systeem elke lijn en elk kader vervangt. */
  .ds-vlak--gedempt {
    background: var(--ds-color-surface-sunken);
    color: var(--ds-color-text-body);
  }

  /* omgekeerd: het inktvlak. Hij zet ook de stipkleur van een rasterband die erin staat, want
     color.mark.on-ink haalt 6,417 op surface.inverse en color.mark haalt 3,806 op surface.page,
     dus de stip is op inkt een andere oker dan op papier. Die doorgifte loopt
     via een plaatselijke variabele en niet via een selector van een ander onderdeel. */
  .ds-vlak--omgekeerd {
    background: var(--ds-color-surface-inverse);
    color: var(--ds-color-text-on-ink);
    --band-stip: var(--ds-color-mark-on-ink);
  }

  /* merk: het kobaltvlak. Heette accent tot 12 september 2026 en stond toen op oker. Modern Delft
     zet `--oker` twaalf keer neer: acht keer als tekstkleur en vier keer als grond, en die vier
     zijn een streep van 2px, twee staven van 1px en een bolletje van 8px. Nooit als grond met
     tekst erop, en de reden is te meten: wit op #A8712A haalt 4,15 waar 4,5 geldt. De kleurpoort
     wees dat aan zodra de rol op de merkoker kwam te staan.

     Deze grond draagt dezelfde stipdoorgifte als het inktvlak, en om dezelfde reden: op kobalt
     haalt color.mark 2,003 waar 3 geldt voor een teken, dus een rasterband zonder doorgifte is
     hier niet te zien. Er staat vandaag geen band in een merkvlak; de regel staat er zodat de
     eerste die er een neerzet de goede kleur krijgt.

     Wat hier NIET staat is een doorgifte voor gedempte tekst. color.text.on-ink.muted haalt op
     kobalt 3,807 tegen de 4,5 die geldt, dus die tekst mag hier niet staan, en dat is een
     plaatsingsregel en geen kleurwissel. Hij hangt aan de grond en niet aan de tekstkleur, precies
     zoals bij surface.warm, en hij staat in het token color.surface.brand opgeschreven. Een
     plaatselijke variabele zou hier niet helpen: er is geen onderdeel dat hem uitleest, en een
     variabele die niemand leest belooft een oplossing die er niet is. */
  .ds-vlak--merk {
    background: var(--ds-color-surface-brand);
    color: var(--ds-color-text-on-brand);
    --band-stip: var(--ds-color-mark-on-ink);
  }

  /* warm: de drukvoorvertoning en de mailkaart. Tekst.body (6,353) en niet tekst.muted (4,285). */
  .ds-vlak--warm {
    background: var(--ds-color-surface-warm);
    color: var(--ds-color-text-body);
  }

  /* verhoogd: van de pagina af, maar er niet overheen. Een schaduw zonder straal, want de straal
     is wat een vlak tot kaart zou maken. */
  .ds-vlak--verhoogd { box-shadow: var(--ds-elevation-raised); }
}

/* === wachtblok === */
/* Wachtblok. Laten zien dat er iets loopt dat tijd kost, met wat er gebeurt en hoe lang het al
 * duurt.
 *
 * Canoniek: pipeline/templates/site/boom.html met de wisselblokken uit
 * design/system/css/site.css. De visual staat woordelijk in drie flowsjablonen en de code weet
 * het zelf: boom.html schrijft erbij dat het dezelfde visual is als op scherm 3 en 5, en om
 * dezelfde reden (B117).
 *
 * Drie dingen die hier anders zijn dan vandaag:
 *
 * 1. De animatie loopt op wacht.puls.duur en staat daarmee onder prefers-reduced-motion, want
 *    die regel staat een keer in ds-basis.css. Vandaag lopen twee van deze animaties dertig
 *    seconden zonder die dekking (B034, B053).
 * 2. De curve is motion.voortgang en niet de standaardcurve: voortgang mag niet versnellen.
 * 3. De stand staat er als woord en niet alleen als kleur.
 *
 * De plaatsing komt van Stapel.
 */

@layer componenten {
  .ds-wachtblok {
    background: var(--ds-color-surface-sunken);
    padding: var(--ds-space-blok);
  }

  .ds-wachtblok__stand {
    display: flex;
    align-items: baseline;
    gap: var(--ds-space-inline);
    font: var(--ds-type-etiket);
    letter-spacing: var(--ds-type-etiket-spatiering);
    text-transform: var(--ds-type-etiket-kapitaal);
    color: var(--ds-color-text-muted);
  }

  .ds-wachtblok__kop {
    font: var(--ds-type-sectie);
    letter-spacing: var(--ds-type-sectie-spatiering);
    color: var(--ds-color-text-default);
    max-inline-size: var(--ds-maat-regel);
  }

  /* De baan van de voortgang. space.inline is 4px en de kleinste stap die er is; er is geen
     maattoken voor de dikte van een balk. */
  .ds-wachtblok__puls {
    block-size: var(--ds-space-inline);
    background: var(--ds-color-border-subtle);
    overflow: hidden;
  }

  .ds-wachtblok__balk {
    display: block;
    block-size: 100%;
    inline-size: 100%;
    background: var(--ds-color-mark);
    transform: scaleX(0);
    transform-origin: left center;
  }

  .ds-wachtblok__regels {
    color: var(--ds-color-text-body);
    font: var(--ds-type-klein);
  }

  .ds-wachtblok__verstreken {
    font: var(--ds-type-code);
    color: var(--ds-color-text-muted);
  }

  /* bezig: de balk loopt een keer vol in wacht.puls.duur, lineair, en blijft daarna staan. De
     wachtschermen wachten werkelijk dertig seconden (B034); dat is inhoud en geen versiering. */
  @keyframes ds-wachtblok-vullen {
    from { transform: scaleX(0); }
    to   { transform: scaleX(1); }
  }
  .ds-wachtblok--bezig .ds-wachtblok__balk {
    animation: ds-wachtblok-vullen var(--ds-wacht-puls-duur) var(--ds-motion-voortgang) forwards;
  }

  .ds-wachtblok--klaar .ds-wachtblok__balk {
    transform: scaleX(1);
  }

  /* fout: kleur draagt de betekenis niet alleen. Er staat een teken en er staat een woord.
     color.text.danger haalt 4,877 op color.surface.sunken, de grond van dit blok. */
  .ds-wachtblok--fout .ds-wachtblok__stand {
    color: var(--ds-color-text-danger);
  }
  .ds-wachtblok--fout .ds-wachtblok__balk {
    transform: scaleX(1);
    background: var(--ds-color-border-danger);
  }
}

/* === zoekrij === */
/* Zoekrij. Een veld met een knop ernaast, in de kop, op /zoeken en op de vier
 * gelegenheidspagina's.
 *
 * Canoniek: design/system/css/publiek.css (.ev-zoekvak), met de overschrijving
 * .ev-zoekvak .ev-btn die vervalt.
 *
 * Twee dingen die hier anders zijn dan vandaag:
 *
 * 1. De knop wordt niet van buitenaf overschreven. Dit blad schrijft geen enkele regel die met
 *    ds-knop begint; design/system/onderdelen/bouw.py valt om als dat wel gebeurt.
 * 2. De rij stapelt onder een containerbreedte in plaats van te knijpen. Op 360px levert de
 *    huidige rij een veld van 94px naast een knop van drie regels op, en dat is de gemeten
 *    drift die deze rij oplost.
 *
 * Waarom hier wel flex staat en geen Rij: Rij slaat om en laat de knop onder het veld
 * uitlijnen op zijn eigen breedte. Hier moeten beide over de volle breedte staan zodra het
 * smal wordt, en dat is een andere beweging. Het schakelen zelf gaat dit onderdeel aan.
 *
 * De drempel is 440px en dat is maat.kolom, de leeskolom. De regel erachter: zodra de container
 * smaller is dan een leeskolom, staat er geen ruimte meer voor een veld naast een knop. Hier stond
 * 26rem met als reden dat het dezelfde drempel was als in ds-primitieven.css, en dat klopte tot
 * besluit B21: Raster kreeg de omslagprop uit het voorstel en gebruikt sindsdien 600, 700 en 900px.
 * 26rem was daarmee een getal zonder bron, uit geen token en uit geen ander blad.
 *
 * Een containervraag kan geen custom property lezen, dus het getal staat hier letterlijk met het
 * token ernaast, precies zoals ds-primitieven.css dat voor zijn drie drempels doet.
 */

@layer componenten {
  .ds-zoekrij {
    container-type: inline-size;
  }

  .ds-zoekrij__rij {
    display: flex;
    flex-direction: column;
    gap: var(--ds-space-tussen);
  }

  /* Het veld mag krimpen tot nul en de knop niet; zo houdt de knop zijn tekst op een regel. */
  .ds-zoekrij__veld {
    min-inline-size: 0;
  }

  /* De focusring van veld en knop komt uit ds-basis.css en staat control.focus.afstand buiten
     het element. Niets hier mag hem afsnijden. */
  .ds-zoekrij__rij,
  .ds-zoekrij__veld,
  .ds-zoekrij__knop {
    overflow: visible;
  }

  @container (min-width: 440px) {
    .ds-zoekrij__rij {
      flex-direction: row;
      align-items: flex-end;
    }
    .ds-zoekrij__veld {
      flex: 1 1 auto;
    }
    .ds-zoekrij__knop {
      flex: 0 0 auto;
    }
  }

  .ds-zoekrij[aria-busy='true'] {
    cursor: progress;
  }
}

