/* GEGENEREERD — bron: codegen/src/main/resources/mock-generic/app.css. Niet hier wijzigen; fix de bron en draai ./generate. */
/* ==========================================================================
   Generieke basis-mock — app.css
   --------------------------------------------------------------------------
   Leunt volledig op de design-systeem-tokens (style-guide.css + components.css)
   die per project meegekopieerd worden: --color-*, --space-*, --radius-*,
   --text-*, --font-*, --shadow-*. Geen project-kennis; werkt op ELK van de
   triad-design-systemen.

   TWEE LAGEN (F6/H8, 10-10). De laadvolgorde is design-systeem → app.css → opmaak-laag (cms.css).
   Zonder lagen won app.css daardoor bij gelijke specificiteit altijd van het design-systeem, terwijl
   het commentaar bij `.btn` en `.form-control` "val terug op het DS" beloofde: de pill-knop van een
   systeem kwam nooit in beeld. Nu:
   - `@layer renderer` — de TERUGVAL: de token-defaults hieronder en de renderer-versie van wat het
     class-contract van het design-systeem is (knop, formulier, tabel, detail-lijst, lege staat, de
     focusring). Een gelaagde regel verliest van elke ongelaagde, dus het design-systeem wint hier
     altijd, ongeacht de specificiteit.
   - ongelaagd — wat van de RENDERER is: de chrome (kop, menu, lade, toasts), de eigen componenten
     en de invarianten (mobiel, aanraakdoelen, de donkere omkering, foutstaten). Die mogen niet
     wijken voor een kale `a {}` of `h1 {}` uit een design-systeem.
   Het design-systeem en de opmaak-laag zijn ongelaagd en blijven dat (een `@layer` in de opmaak-laag
   valt in `scopeCss` weg, met een waarschuwing). Een nieuwe regel hoort in de terugval als een
   design-systeem 'm mag overnemen, anders niet.

   DRIE BREEKPUNTEN (M20), in rem zodat ze meeschalen met de lettergrootte van de bezoeker:
     smal   30rem  — een telefoon staand (de kleinste kaart, de inlogpagina)
     midden 48rem  — telefoon en kleine tablet tegenover de rest: hier gelden de mobiele invarianten
     breed  60rem  — ruimte voor twee kolommen (kaart naast lijst, de werkplekken van de editor)
   Een media query kan geen custom property lezen, dus de waarden staan er letterlijk;
   `css-architectuur.test.js` weigert elke andere waarde (ook in de CSS van het skelet).
   ========================================================================== */
@layer renderer {
/* ── Token-defaults: één keer, en daarna overal een kale var() ──────────────
   Elke token die de renderer leest heeft hier z'n terugval, in plaats van een eigen terugval per
   gebruik (op 10-10 stonden er voor `--color-text-muted` tien verschillende grijzen in dit bestand).
   `:where()` + de laag: specificiteit 0 in de laagste laag, dus élke `:root` van een design-systeem
   wint. `DesignSystemContract.rendererFallback` leest de terugval hier. De `--mock-*`-tokens zijn
   van de renderer zelf (het DS-contract slaat ze over); `--focus-ring` en `--tap-target` zijn de
   twee optionele knoppen die een design-systeem mag zetten. */
:where(:root) {
  --color-bg: #f6f8fb;
  --color-bg-subtle: #f3f5f9;
  --color-bg-muted: #eef2f7;
  --color-bg-surface: #fff;
  --color-bg-surface-hover: #f4f6f8;
  --color-border: #dfe4ec;
  --color-border-subtle: #eef1f6;
  --color-border-strong: #c2cad6;
  --color-border-focus: var(--color-primary);
  --color-primary: #3a7ca5;
  /* Letterlijk, geen `var(--color-primary)`: de donkere omkering leidt `--color-primary` af uit deze
     token, en een verwijzing terug gaf dan een kring (beide tokens ongeldig, geen kleur). */
  --color-primary-bright: #2f6a8e;
  --color-primary-soft: #e3eef5;
  --color-primary-glow: rgba(58, 124, 165, .15);
  --color-text: #1a2230;
  --color-text-heading: var(--color-text);
  --color-text-secondary: #4a5666;
  --color-text-muted: #6b7684;
  --color-text-on-primary: #fff;
  --color-success: #2e7d47;
  --color-success-bg: #e6f6ec;
  --color-error: #c0392b;
  --color-error-bg: #fdecec;
  --color-error-soft: #fdecea;
  --color-error-glow: rgba(192, 57, 43, .15);
  --color-danger: var(--color-error);
  --color-danger-soft: var(--color-error-bg);
  --color-warning: #b8791a;
  --font-body: system-ui, sans-serif;
  --font-heading: var(--font-body);
  --font-mono: ui-monospace, monospace;
  --leading-snug: 1.3;
  --leading-normal: 1.5;
  --leading-relaxed: 1.65;
  --space-1: .25rem;
  --space-2: .5rem;
  --space-3: .75rem;
  --space-4: 1rem;
  --space-5: 1.25rem;
  --space-6: 1.5rem;
  --space-8: 2rem;
  --space-16: 4rem;
  --text-xs: .75rem;
  --text-sm: .875rem;
  --text-base: 1rem;
  --text-lg: 1.125rem;
  --text-xl: 1.25rem;
  --text-2xl: 1.5rem;
  --radius-sm: .375rem;
  --radius-md: .625rem;
  --radius-lg: .75rem;
  --radius-pill: 999px;
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, .05);
  --shadow-md: 0 4px 12px rgba(0, 0, 0, .1);
  --shadow-lg: 0 12px 32px rgba(0, 0, 0, .16);
  /* Valt naar LINKS: dit is de schaduw van de lade, die rechts staat. */
  --shadow-xl: -8px 0 30px rgba(0, 0, 0, .18);
  --container-max: 1280px;

  /* PRIMAIR ALS TEKSTKLEUR. Een merkkleur die als VLAK werkt (oranje knop met donkere tekst) haalt
     als tekst op wit vaak geen AA (#FF6B35 = 2,8:1). Daarom leest alle tekst-in-primair deze ene
     variabele; een design-systeem met zo'n merkkleur zet hier een donkerdere tint. */
  --mock-primary-ink: var(--color-primary);
  /* DE TOAST is altijd een donker vlak met witte tekst. Hij leende eerst `--color-text-heading`, maar
     dat is een TEKST-kleur: een systeem met lichte koppen gaf wit op wit (enervisie 10-03). */
  --mock-toast-bg: #1a2230;
  /* De hoogte van de plakkende kop; app.js zet 'm zodra die bekend is (de filterbalk plakt eronder). */
  --mock-kop-hoogte: 0px;
  /* Vaste kleuren die NIET meedraaien met licht/donker: een sluier achter een dialoog of lade, een
     label of knop óp een foto, en wit op een gekleurd vlak (een foutteken, de toast). */
  --mock-sluier: rgba(15, 23, 35, .5);
  --mock-op-beeld: rgba(15, 23, 35, .62);
  --mock-op-beeld-sterk: rgba(15, 23, 35, .82);
  --mock-op-kleur: #fff;
  /* Onder `--text-xs`: het label onder een icoon in de onderbalk, en de bronvermelding op een kaart. */
  --mock-text-2xs: .6875rem;
  --mock-text-3xs: .625rem;

  /* De focusring (WCAG 2.4.7): één regel voor de hele renderer, hieronder bij `:focus-visible`. */
  --focus-ring: 2px solid var(--color-border-focus);
  /* Aanraakdoelen (WCAG 2.5.8): minstens 24px, en 44px waar je met een vinger tikt (zie onder). */
  --tap-target: 1.5rem;

  /* Wat boven wat ligt. Eén schaal in plaats van losse getallen per regel. */
  --mock-z-plakt: 15;
  --mock-z-kop: 20;
  --mock-z-onderbalk: 30;
  --mock-z-scrim: 40;
  --mock-z-lade: 50;
  --mock-z-dialoog: 60;
  --mock-z-toast: 70;
  --mock-z-menu: 80;
  --mock-z-zwevend: 90;
  /* Boven de panes van Leaflet (die tot 1000 gaan): de gebaar-hint en de zoekopties van een kaart. */
  --mock-z-kaart: 1000;
  --mock-z-kaart-opties: 1100;
}
/* Een vinger is geen muispijl. Ook een smal venster telt mee: daar is de kans op een vinger het
   grootst, en een telefoon die zich als muis meldt (sommige Android-browsers) valt er dan ook onder. */
@media (pointer: coarse), (max-width: 48rem) {
  :where(:root) { --tap-target: 2.75rem; }
}

* { box-sizing: border-box; }
body {
  margin: 0;
  background: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: var(--leading-normal);
  -webkit-font-smoothing: antialiased;
}
/* Eén focusring voor alles wat de renderer tekent (M21/M22). Een echte `outline`, geen schaduw of
   tint: die verdwijnen in Windows' hoogcontrast-stand (forced-colors). Een design-systeem met een
   eigen `:focus-visible` wint (de laag), of zet alleen `--focus-ring`. */
:focus-visible { outline: var(--focus-ring); outline-offset: 2px; }
}
/* Hoogcontrast (Windows, forced-colors): de browser haalt schaduwen en achtergrondtinten weg en geeft
   een outline z'n eigen systeemkleur. Een focus die op een schaduw leunt (een invoerveld, het
   zoekveld, de dag-knoppen) is dan onzichtbaar, tenzij er een echte outline staat (WCAG 2.4.7).
   `!important`: hier wint de instelling van de gebruiker, ook van een design-systeem dat z'n
   focusring als schaduw tekent. */
@media (forced-colors: active) {
  :focus-visible, .form-control:focus, .search-field:focus-within, .login-input:focus {
    outline: 2px solid Highlight !important; outline-offset: 2px;
  }
}

/* ── Header ─────────────────────────────────────────────────────────────── */
.app-header {
  position: sticky; top: 0; z-index: var(--mock-z-kop);
  background: var(--color-bg-surface);
  border-bottom: 1px solid var(--color-border);
  box-shadow: var(--shadow-sm);
}
/* De paginabreedte komt uit het DESIGN-SYSTEEM (`--container-max`), niet uit een hardcode hier.
   Stond hier `1280px`, terwijl de content-container het token volgde: header en content lijnden dan
   niet uit — het logo en de Inloggen-knop stonden tientallen pixels naast de inhoud eronder. Eén
   token stuurt nu de hele pagina; de fallback geldt alleen voor een DS zonder dat token. */
.app-header-inner {
  display: flex; align-items: center; gap: var(--space-4);
  padding: var(--space-4) var(--space-6);
  max-width: var(--container-max); margin: 0 auto; flex-wrap: wrap;
}
.brand { display: flex; align-items: center; gap: var(--space-3); text-decoration: none; color: inherit; }
.brand-mark {
  display: grid; place-items: center; width: 40px; height: 40px; flex: 0 0 auto;
  border-radius: var(--radius-md); font-size: 1.3rem;
  background: var(--color-primary); color: var(--color-text-on-primary);
}
.brand-text { display: flex; flex-direction: column; }
.wordmark { font-family: var(--font-heading); font-weight: 700; font-size: var(--text-lg); color: var(--color-text-heading); }
.tagline { font-size: var(--text-xs); color: var(--color-text-muted); }
.chapters { display: flex; gap: var(--space-2); margin-left: auto; flex-wrap: wrap; }
/* App-weergave verbergt de model-/bouw-chrome: chapters, tagline, de Formulieren-tab. */
.mode-app #chapters, .mode-app .tagline, .mode-app .hub-tab[data-kind="forms"] { display: none; }
/* De tagline beschrijft de mock, niet de app: standaard weg, alleen in de model-weergave van de
   editor. Zo staat 'ie ook niet in beeld zolang het script nog laadt (gebruiker, 01-10). */
body:not(.mode-model) .tagline { display: none; }

/* `type="search"` tekent in Chromium z'n EIGEN wis-kruisje; naast onze `.search-clear` stonden er
   dus twee wis-knoppen in één veld. De onze blijft (die zit in de DS-taal en heeft een label). */
.search-input::-webkit-search-cancel-button,
.search-input::-webkit-search-decoration { -webkit-appearance: none; appearance: none; }

/* ── Hub-nav (tabs) ─────────────────────────────────────────────────────── */
.hub-nav {
  position: relative; display: flex; gap: var(--space-1);
  padding: 0 var(--space-6); max-width: var(--container-max); margin: 0 auto;
  overflow-x: auto; scrollbar-width: thin;
  /* Past het menu niet, dan werd het laatste label midden in een woord afgekapt ("Admin
     registrere") — dat leest als een fout, niet als "er is meer". Een uitvloeiende rand zegt
     dat je verder kunt scrollen; is er niets meer, dan vervaagt er lege ruimte en zie je niets. */
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 2.5rem), transparent);
  mask-image: linear-gradient(to right, #000 calc(100% - 2.5rem), transparent);
}
.hub-tab {
  display: inline-flex; align-items: center; gap: var(--space-2);
  padding: var(--space-3) var(--space-4);
  background: none; border: none; cursor: pointer; white-space: nowrap;
  /* SECONDARY, niet muted. `--color-text-muted` is de DECORATIEVE grijstint; een menu-label
     draagt betekenis en moet AA halen. Gemeten 09-02 over twee design-systemen: muted gaf
     4,31:1 en 2,88:1 op wit (beide onder 4,5), secondary 6,78:1 en 5,74:1. Zelfde reden voor
     `.persona-label` en `.vh-count` hieronder. */
  color: var(--color-text-secondary); font-size: var(--text-sm); font-weight: 600;
  border-bottom: 2px solid transparent;
}
.hub-tab:hover { color: var(--color-text); }
.hub-tab[aria-current] { color: var(--mock-primary-ink); }
.ht-glyph { width: 16px; height: 16px; display: inline-flex; }
.ht-glyph svg { width: 16px; height: 16px; }
.ht-count {
  font-size: var(--text-xs); font-weight: 700; min-width: 18px; text-align: center;
  padding: 0 6px; border-radius: var(--radius-pill);
  background: var(--color-bg-muted); color: var(--color-text-secondary);
}
.hub-tab[aria-current] .ht-count { background: var(--color-primary-soft); color: var(--mock-primary-ink); }
.hub-indicator {
  position: absolute; bottom: 0; left: 0; height: 2px; width: 0; opacity: 0;
  background: var(--color-primary); transition: transform .2s ease, width .2s ease;
}

/* ── Shell + view ───────────────────────────────────────────────────────── */
.app-shell { max-width: var(--container-max); margin: 0 auto; padding: var(--space-6); }
.view { display: flex; flex-direction: column; gap: var(--space-4); }
/* Kop en toolbar lijnen op DEZELFDE as. Stonden op `flex-end` en `center`, met gaps uit twee
   reeksen door elkaar — twee ritmes onder elkaar, en dat zie je zonder het te kunnen benoemen
   (gebruiker, 21-09: "de margins en paddings kunnen beter"). */
.view-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); flex-wrap: wrap; }
.vh-title { display: flex; align-items: baseline; gap: var(--space-3); flex-wrap: wrap; }
.vh-title h1 { margin: 0; font-family: var(--font-heading); font-size: var(--text-2xl); color: var(--color-text-heading); }
.vh-count { font-size: var(--text-xs); font-weight: 600; line-height: 1; color: var(--color-text-secondary);
  background: var(--color-bg-muted); border-radius: 999px; padding: .3em .6em; align-self: center;
  font-variant-numeric: tabular-nums; }
.vh-count:empty { display: none; }

/* ── Toolbar (filter + zoek) ────────────────────────────────────────────── */
/* Chips links, zoek rechts — ook als er géén chips zijn. Met `space-between` en één kind
   plakte het zoekveld links onder de titel, wat leest als een tweede kop in plaats van een
   gereedschap. */
.toolbar { display: flex; align-items: center; justify-content: flex-end; gap: var(--space-3); flex-wrap: wrap; }
.toolbar > .chips { margin-right: auto; }
/* Het omgezette component hangt z'n zoekveld in een neutrale houder; die moet meerekken, anders
   krijgt het veld z'n min-breedte niet en kapt de placeholder alsnog af. */
.toolbar > [data-bind-search] { display: flex; flex: 1 1 14rem; min-width: 0; max-width: 24rem; justify-content: flex-end; }
.toolbar > [data-bind-search] .search-field { width: 100%; }
.toolbar > [data-bind-filter] { margin-right: auto; }
.chips { display: flex; gap: var(--space-2); flex-wrap: wrap; }
.chip {
  /* Tokens, geen losse pixels: een chip hoort dezelfde verticale maat te hebben als een veld. */
  padding: var(--space-2) var(--space-3); border-radius: var(--radius-pill); cursor: pointer;
  line-height: 1.2;
  font-size: var(--text-sm); font-weight: 600;
  background: var(--color-bg-surface); color: var(--color-text-secondary);
  border: 1px solid var(--color-border);
}
.chip:hover { border-color: var(--color-border-strong); }
.chip.is-active { background: var(--color-primary); color: var(--color-text-on-primary); border-color: var(--color-primary); }
/* Het zoekveld IS een invoerveld en hoort dus de maat van `.form-control` te dragen: dezelfde
   padding, dezelfde radius, dezelfde focus-ring. Het had een hardgecodeerde `4px` en alleen een
   randkleur bij focus — een andere hoogte en een andere focus-taal dan elk ander veld op het
   scherm. En `min-width: 240px` kón niet krimpen, dus in een smalle kolom kapte de placeholder
   af midden in een woord ("Zoek in aangemelde bezoe"). Nu krimpt en groeit 'ie mee. */
.search-field {
  display: flex; align-items: center; gap: var(--space-2);
  background: var(--color-bg-surface); border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: var(--space-2) var(--space-3);
  flex: 1 1 14rem; min-width: 0; max-width: 24rem;
}
.search-field:focus-within {
  border-color: var(--color-border-focus);
  box-shadow: 0 0 0 3px var(--color-primary-glow);
}
.search-ico { display: inline-flex; color: var(--color-text-muted); }
.search-ico svg { width: 16px; height: 16px; }
.search-input { border: none; outline: 2px solid transparent; background: none; flex: 1; font-size: var(--text-sm); color: inherit; min-width: 0; }
.search-clear { border: none; background: none; cursor: pointer; color: var(--color-text-muted); display: inline-flex; padding: 2px; }
.search-clear svg { width: 14px; height: 14px; }
/* Alleen zichtbaar als er GEFILTERD wordt ("3 van 8"). Het totaal staat al naast de titel;
   twee keer hetzelfde getal op één rij leest als een fout. */
.search-count { font-size: var(--text-xs); color: var(--color-text-muted);
  white-space: nowrap; font-variant-numeric: tabular-nums; }

/* ── Tabel ──────────────────────────────────────────────────────────────── */
/* De look van de tabel is de terugval (`.table`/`.data-table` staan in het class-contract van het
   design-systeem); wat de tabel DOET (scrollen in plaats van knijpen, de uitlijning per soort cel, de
   actie-kolom) staat ongelaagd eronder. */
@layer renderer {
.table-wrap {
  overflow-x: auto; border: 1px solid var(--color-border);
  border-radius: var(--radius-lg); background: var(--color-bg-surface);
  box-shadow: var(--shadow-sm);
}
.data-table { width: 100%; border-collapse: collapse; font-size: var(--text-sm); }
.data-table thead th {
  text-align: left; font-weight: 700; font-size: var(--text-xs); letter-spacing: .01em;
  color: var(--mock-muted-op-vlak); padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--color-border); white-space: nowrap;
}
.data-table th.th-num, .data-table td.cell-num { text-align: right; }
.data-table tbody td {
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--color-border); vertical-align: middle;
}
.data-table tbody tr:last-child td { border-bottom: none; }
.data-table tbody tr:hover { background: var(--color-bg-surface-hover); }
.cell-primary { font-weight: 600; color: var(--color-text-heading); }
.cell-num, .mono { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
}
/* Gegroepeerde DETAIL_LIST: master-kop boven elke rij-sub-tabel. */
.group-header {
  display: flex; flex-wrap: wrap; gap: var(--space-3);
  margin: var(--space-3) 0 calc(var(--space-2) * -1) 0;
  padding-bottom: var(--space-2);
  border-bottom: 2px solid var(--color-border);
}
.group-header:first-child { margin-top: 0; }
.group-key { font-size: var(--text-sm); }
.group-key-label { color: var(--color-text-muted); }
.group-key-val { font-weight: 700; color: var(--color-text); }
/* width:auto + min-width:100% => smalle tabellen vullen de breedte, brede tabellen
   (bv. de diepste drill-laag met veel kolommen + rij-acties) scrollen i.p.v. te knijpen. */
.data-table td, .data-table th { white-space: nowrap; }
/* De kolomkop is tekst die je moet LEZEN: de afgeleide grijs van de renderer haalt 4,5:1 (zie
   `--mock-muted`), ook als het design-systeem de kop een mooiere, lichtere tint geeft (rogers-legacy:
   3,2:1). Daarom staat deze kleur buiten de laag; de rest van de kop is van het systeem. */
.data-table thead th { color: var(--mock-muted-op-vlak); }
/* Getallen lijnen op plaatswaarde ook zonder mono-font (canon §2/§5: tabulaire cijfers). */
.data-table td.cell-num, .data-table th.th-num { font-variant-numeric: tabular-nums; }
.row-clickable { cursor: pointer; }
.row-clickable:focus-visible { outline-offset: -2px; }
/* Actie-kolom: krimp tot inhoud (width:1% → alle slack naar de data-kolommen) MAAR de knoppen
   zélf mogen NIET krimpen (flex:0 0 auto). Zonder dat laat de flex de knoppen inkrimpen, valt de
   min-content van de cel weg en knijpt de tabel de knop-cel dood → knop puilt over de laatste
   tekst-cel (de overlap-bug, erger bij veel kolommen). */
.data-table th.th-actions, .data-table td.cell-actions { width: 1%; text-align: right; white-space: nowrap; min-width: max-content; }
/* De knoppen zeggen zelf wat ze doen: "ACTIES" als kop is ruis. Onzichtbaar, maar een schermlezer
   leest de kolomnaam nog (ook in oudere artefacten, die de tekst letterlijk dragen). */
.data-table th.th-actions { font-size: 0; }
/* Een design-systeem mag niet aannemen dat de LAATSTE kolom de actiekolom is (`td:last-child
   { text-align: right }`): een lijst met één kolom zette z'n namen dan rechts (Bestaande rollen,
   23-09). Uitlijning volgt de soort cel — acties en getallen rechts, de rest links. */
.data-table td:last-child:not(.cell-actions):not(.cell-num),
.data-table th:last-child:not(.th-actions):not(.th-num) { text-align: left; width: auto; white-space: normal; }
/* De kop "Acties" is er voor de schermlezer, niet voor het oog (font-size 0 hierboven). Transparant,
   niet muted: axe meet onzichtbare tekst anders gewoon op contrast (3,2:1 in rogers-legacy, 24-09). */
.data-table th.th-actions { color: transparent; }
.row-actions { display: inline-flex; flex-wrap: nowrap; gap: var(--space-2); align-items: center; justify-content: flex-end; }
.row-actions .btn { flex: 0 0 auto; white-space: nowrap; }
.btn.has-menu { display: inline-flex; align-items: center; gap: .35rem; }
.btn.has-menu .menu-caret { display: inline-flex; opacity: .6; }
.btn.has-menu .menu-caret svg { width: 13px; height: 13px; }
/* Rij-actie-chooser (DETAIL-hub) — klein, rustig kaartje; canon §9 (restraint) + §1 (spacing). */
.row-menu {
  position: absolute; z-index: var(--mock-z-menu); min-width: 180px; padding: var(--space-1);
  background: var(--color-bg-surface); border: 1px solid var(--color-border);
  border-radius: var(--radius-md); box-shadow: var(--shadow-lg);
  display: flex; flex-direction: column; gap: 1px;
}
.row-menu-item {
  appearance: none; border: 0; background: none; text-align: left; cursor: pointer;
  padding: var(--space-2) var(--space-3); border-radius: var(--radius-sm);
  font: inherit; color: var(--color-text); white-space: nowrap;
}
.row-menu-item:hover, .row-menu-item:focus-visible { background: var(--color-bg-surface-hover); }
.row-menu-item:focus-visible { outline-offset: -2px; }
/* ── Status: te ZIEN, niet te lezen ────────────────────────────────────────
   Een statuskolom waarin elke waarde dezelfde kleur heeft, is een kolom die je moet lezen. De
   renderer kent de woorden van een project niet, maar wél de FAMILIE waartoe een status hoort —
   `statusToon()` (app.js) normaliseert de waarde naar `data-toon="ok|wacht|stop|neutraal"`. Zo
   krijgt élk project meteen betekenis, en blijft `data-v` beschikbaar voor de bespoke-laag die
   één specifieke waarde wil bijkleuren. Onbekend → neutraal; nooit een verzonnen kleur. */
.status-tag {
  display: inline-flex; align-items: center; gap: .4em;
  padding: 2px var(--space-2); border-radius: var(--radius-sm);
  font-size: var(--text-xs); font-weight: 600;
  background: var(--color-bg-muted); color: var(--color-text-secondary);
}
/* Het stipje draagt de kleur; de tekst blijft leesbaar zwart-op-licht (contrast > kleurcode —
   WCAG 1.4.1: kleur mag nooit de enige drager zijn, dus het WOORD blijft de bron van waarheid). */
.status-tag::before {
  content: ''; width: .5em; height: .5em; border-radius: 50%; flex: 0 0 auto;
  background: var(--color-text-muted);
}
/* De familie-kleur bepaalt de TINT, niet de leesbaarheid: het vlak is een lichte menging met de
   ondergrond, de tekst een menging met de TEKSTKLEUR van het palet. Dat laatste is het verschil
   tussen een formule die alleen in lichte thema's werkt en één die overal werkt: op een licht palet
   mengt 'ie naar donker, op een donker palet naar licht — precies wat leesbaarheid vraagt.
   Zonder `color-mix` (Safari < 16.2) eerst de gewone vlak- en tekstkleur van het palet (M19). */
.status-tag[data-toon="ok"] {
  background: var(--color-success-bg); color: var(--color-text);
  background: color-mix(in srgb, var(--color-success) 14%, var(--color-bg-surface));
  color: color-mix(in srgb, var(--color-success) 42%, var(--color-text));
}
.status-tag[data-toon="ok"]::before { background: var(--color-success); }
.status-tag[data-toon="wacht"] {
  background: var(--color-bg-muted); color: var(--color-text);
  background: color-mix(in srgb, var(--color-warning) 14%, var(--color-bg-surface));
  color: color-mix(in srgb, var(--color-warning) 38%, var(--color-text));
}
.status-tag[data-toon="wacht"]::before { background: var(--color-warning); }
.status-tag[data-toon="stop"] {
  background: var(--color-error-bg); color: var(--color-text);
  background: color-mix(in srgb, var(--color-error) 12%, var(--color-bg-surface));
  color: color-mix(in srgb, var(--color-error) 42%, var(--color-text));
}
.status-tag[data-toon="stop"]::before { background: var(--color-error); }
.pill { display: inline-block; padding: 2px var(--space-2); border-radius: var(--radius-pill); font-size: var(--text-xs); font-weight: 600; }
.pill-on { background: var(--color-success-bg); color: var(--color-success); }
.pill-off { background: var(--color-bg-muted); color: var(--color-text-muted); }

/* ── Buttons ────────────────────────────────────────────────────────────────
   De knop zelf is van het design-systeem (class-contract); dit is de terugval voor wie er geen
   heeft. De varianten van de renderer (rij-actie, ghost, destructief) staan ongelaagd eronder. */
@layer renderer {
.btn {
  display: inline-flex; align-items: center; gap: var(--space-2); cursor: pointer;
  padding: var(--space-2) var(--space-4); border-radius: var(--radius-md);
  font-size: var(--text-sm); font-weight: 600; border: 1px solid transparent; font-family: inherit;
  text-decoration: none; line-height: 1;
}
.btn-sm { padding: var(--space-1) var(--space-3); font-size: var(--text-xs); }
.btn-primary { background: var(--color-primary); color: var(--color-text-on-primary); }
.btn-primary:hover { background: var(--color-primary-bright); }
.btn-secondary { background: var(--color-bg-surface); color: var(--color-text); border-color: var(--color-border); }
.btn-secondary:hover { border-color: var(--color-border-strong); }
.btn-danger { background: var(--color-error); color: var(--mock-op-kleur); border-color: var(--color-error); }
.btn-danger:hover { filter: brightness(.94); }
}
/* Rij-actie: stil van zichzelf. Binnen een rij bestaat geen primaire knop — `intent` stuurt
   alléén de tekstkleur, nooit een vlak. Zo blijft de zwaarste vorm op het scherm gereserveerd voor
   de ENE scherm-actie bovenaan, en verdwijnt de knoppenmuur uit de tabel. (canon §3) */
/* STIL, maar niet onzichtbaar. Een rij-actie mag nooit de zwaarste knop op het scherm zijn (dat
   is de scherm-actie bovenaan), maar zónder rand las "Afmelden" als gewone tekst aan de
   rechterrand — je kon niet zien dat het een knop was (gebruiker, 21-09). Een dunne rand op het
   oppervlak is genoeg affordance en houdt de hiërarchie intact. */
.btn-row {
  background: var(--color-bg-surface);
  border-color: var(--color-border);
  font-weight: 500;
  color: var(--color-text-secondary);
}
/* Een destructieve knop in een knoppenrij: stil van gewicht, duidelijk van kleur. Nooit gevuld —
   dan zou de zwaarste knop op het scherm de handeling zijn die je zelden wilt. */
.btn.is-danger { color: var(--color-danger);
  border-color: var(--color-danger-soft); background: var(--color-bg-surface); }
.btn.is-danger:hover { background: var(--color-danger-soft);
  border-color: var(--color-danger); }
.btn-row:hover { background: var(--color-bg-muted); color: var(--color-text);
  border-color: var(--color-border-strong); }
.btn-row:focus-visible { outline-offset: 1px; }
.btn-row.is-accent { color: var(--mock-primary-ink); }
.btn-row.is-accent:hover { background: var(--color-primary-soft); color: var(--mock-primary-ink); }
.btn-row.is-danger { color: var(--color-danger); }
.btn-row.is-danger:hover { background: var(--color-danger-soft); color: var(--color-danger); }
/* De ⋯-overloop: even stil, maar altijd even breed zodat de actie-kolom niet per rij verspringt. */
.row-actions .btn-row.has-menu { min-width: 2rem; justify-content: center; letter-spacing: .08em; }
.row-menu-item.is-accent { color: var(--mock-primary-ink); }
.row-menu-item.is-danger { color: var(--color-danger); }
.row-menu-item.is-danger:hover, .row-menu-item.is-danger:focus-visible { background: var(--color-danger-soft); }
.btn-ghost { background: none; color: var(--color-text-muted); padding: 4px; }
.btn-ghost:hover { color: var(--mock-primary-ink); }
.btn-ico svg, .btn-ghost svg { width: 16px; height: 16px; }

/* Refresh-icoon bij een `reload`-mode stateview-component (lijst/detail) — subtiel, huisstijl
   (leunt op .btn-ghost: muted → hover primary). Spint kort tijdens het her-fetchen. */
.vh-actions, .head-actions { display: inline-flex; align-items: center; gap: var(--space-2); }
.refresh-btn svg { width: 16px; height: 16px; display: block; }
.refresh-btn.is-spinning svg { animation: refresh-spin .6s linear infinite; transform-origin: 50% 50%; }
@keyframes refresh-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .refresh-btn.is-spinning svg { animation: none; } }

/* ── Toestanden: leeg · gefilterd-leeg · ladend · mislukt ──────────────────
   Een scherm dat alleen in de gelukkige toestand klopt, is niet af. Vier vormen, één huis: een
   ladende lijst toont de VORM die komt (skeleton, geen spinner), een lege lijst toont wat je kunt
   doen, een leeg filter zegt dat het aan het filter ligt, en een mislukte fetch geeft het toe. */
.state-actions { display: flex; gap: var(--space-2); justify-content: center; margin-top: var(--space-4); flex-wrap: wrap; }
.empty-state.is-error p { color: var(--color-error); }
/* Skeleton: dezelfde rijhoogte als de echte tabel, zodat er niets verspringt zodra de data er is. */
.skeleton-table { padding: var(--space-2) 0; }
.skeleton-row {
  display: flex; gap: var(--space-4); align-items: center;
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--color-border-subtle);
}
.skeleton-row:last-child { border-bottom: none; }
.skeleton-cell {
  height: .75rem; border-radius: var(--radius-sm); flex: 1 1 auto;
  background: linear-gradient(90deg,
    var(--color-bg-muted) 0%, var(--color-bg-subtle) 50%, var(--color-bg-muted) 100%);
  background-size: 200% 100%; animation: skel 1.2s ease-in-out infinite;
}
.skeleton-cell.is-kort { flex: 0 0 18%; }
@keyframes skel { to { background-position: -200% 0; } }
@media (prefers-reduced-motion: reduce) { .skeleton-cell { animation: none; } }

/* ── De bodem ──────────────────────────────────────────────────────────────
   Zonder footer houdt een pagina onder de tabel gewoon op — dat leest als een half geladen scherm.
   Stil, informatief, geen decoratie: waar je bent, met welke rol je kijkt, en de weg terug. */
.app-footer {
  color: var(--mock-muted);
  margin-top: var(--space-16); padding: var(--space-5) 0 var(--space-8);
  border-top: 1px solid var(--color-border-subtle);
  display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-2) var(--space-4);
  font-size: var(--text-xs); color: var(--mock-muted);
}
.app-footer .af-brand { font-weight: 600; color: var(--color-text-secondary); }
.app-footer .af-sep { opacity: .5; }
.app-footer a { color: var(--color-text-secondary); text-decoration: none; }
.app-footer a:hover { color: var(--mock-primary-ink); text-decoration: underline; }

/* Een verrijkt component zonder eigen kop: alleen de ververs-knop, rechts. */
.view-head.is-alleen-actie { justify-content: flex-end; margin-bottom: var(--space-2); }

/* ── Empty state ────────────────────────────────────────────────────────── */
@layer renderer {
.empty-state { text-align: center; padding: var(--space-8) var(--space-4); color: var(--color-text-muted); }
}
/* Design-systemen geven lopende tekst een leesbreedte (`p { max-width }`). In een gecentreerd blok
   plakt die alinea dan links; auto-marges houden 'm in het midden. */
.empty-state p { max-width: 44ch; margin-left: auto; margin-right: auto; }
.empty-state .state-actions { display: flex; justify-content: center; gap: var(--space-2); margin-top: var(--space-4); }
.muted { color: var(--color-text-muted); }

/* ── Breadcrumb ─────────────────────────────────────────────────────────── */
.crumbs { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; font-size: var(--text-sm); }
.crumb {
  display: inline-flex; align-items: center; gap: 4px; border: none; background: none; cursor: pointer;
  color: var(--mock-primary-ink); font-weight: 600; padding: 2px 4px; font-family: inherit; font-size: inherit;
}
.crumb:hover { text-decoration: underline; }
.crumb-glyph svg { width: 15px; height: 15px; }
.crumb-sep { color: var(--color-text-muted); }
.crumb.is-current { color: var(--color-text-heading); font-weight: 700; }

/* ── Formulieren-hub ────────────────────────────────────────────────────── */
.form-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: var(--space-3); }
.form-card {
  display: flex; align-items: center; gap: var(--space-3); text-align: left; cursor: pointer;
  padding: var(--space-4); border-radius: var(--radius-lg);
  background: var(--color-bg-surface); border: 1px solid var(--color-border); font-family: inherit;
}
.form-card:hover { border-color: var(--color-primary); box-shadow: var(--shadow-sm); }
.fc-glyph { display: grid; place-items: center; width: 36px; height: 36px; flex: 0 0 auto; border-radius: var(--radius-md); background: var(--color-primary-soft); color: var(--mock-primary-ink); }
.fc-glyph svg { width: 18px; height: 18px; }
.fc-body { display: flex; flex-direction: column; flex: 1; min-width: 0; }
.fc-title { font-weight: 600; color: var(--color-text-heading); }
.fc-sub { font-size: var(--text-xs); color: var(--color-text-muted); }
.fc-go { color: var(--color-text-muted); display: inline-flex; }
.fc-go svg { width: 18px; height: 18px; }

/* ── Drawer ─────────────────────────────────────────────────────────────── */
.scrim { position: fixed; inset: 0; background: var(--mock-sluier); opacity: 0; visibility: hidden; transition: opacity .2s ease; z-index: var(--mock-z-scrim); }
.scrim.open { opacity: 1; visibility: visible; }
.drawer {
  position: fixed; top: 0; right: 0; height: 100%; width: min(440px, 100%); z-index: var(--mock-z-lade);
  background: var(--color-bg-surface); box-shadow: var(--shadow-xl);
  display: flex; flex-direction: column; transform: translateX(100%); transition: transform .24s ease;
}
.drawer.open { transform: translateX(0); }
/* Dicht = weg. Buiten beeld geschoven viel de schaduw (−8px, 30px blur) nog als grijze strook langs
   de rechterrand van élke mock-pagina, en de knoppen erin waren met Tab bereikbaar. */
.drawer:not(.open) { box-shadow: none; visibility: hidden; transition: transform .24s ease, visibility 0s linear .24s; }
.drawer-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); padding: var(--space-5) var(--space-6); border-bottom: 1px solid var(--color-border); }
.dh-title { display: flex; align-items: center; gap: var(--space-3); }
.dh-title h3 { margin: 0; font-family: var(--font-heading); font-size: var(--text-lg); }
.dh-glyph { display: grid; place-items: center; width: 34px; height: 34px; border-radius: var(--radius-md); background: var(--color-primary-soft); color: var(--mock-primary-ink); }
.dh-glyph svg { width: 18px; height: 18px; }
.drawer-close { border: none; background: none; cursor: pointer; color: var(--color-text-muted); padding: 4px; display: inline-flex; }
.drawer-close svg { width: 20px; height: 20px; }
.drawer-body { flex: 1; overflow-y: auto; padding: var(--space-6); }

/* Read-only detail-inzage (openDetail). De gewone rij is de terugval (`.detail-list` hoort bij het
   class-contract); de bijzondere vormen eronder (één getal, een record-lijst) zijn van de renderer. */
@layer renderer {
.detail-list { display: flex; flex-direction: column; gap: 0; }
.detail-row {
  display: grid; grid-template-columns: minmax(7rem, 34%) 1fr; gap: var(--space-4);
  padding: var(--space-3) 0; border-bottom: 1px solid var(--color-border);
}
.detail-row:last-child { border-bottom: none; }
.detail-row dt { color: var(--color-text-muted); font-size: var(--text-xs); font-weight: 700; letter-spacing: .01em; align-self: center; overflow-wrap: anywhere; }
.detail-row dd { margin: 0; color: var(--color-text-heading); font-weight: 500; overflow-wrap: anywhere; }
.detail-row dd.mono { font-family: var(--font-mono); }
}
/* Eén waarde is een getalkaart, geen formulier-regel: het getal groot, het label eronder. Stond
   als "Huidig tegoed (minuten)" links en "320" ver rechts — het belangrijkste getal van de app
   las als een voetnoot (23-09). */
.detail-list:has(> .detail-row:only-child) > .detail-row {
  display: flex; flex-direction: column-reverse; align-items: flex-start; gap: var(--space-1);
  padding: var(--space-2) 0 0;
}
.detail-list:has(> .detail-row:only-child) > .detail-row dd {
  font-size: calc(var(--text-2xl) * 1.6); line-height: 1.1; font-weight: 650;
  font-variant-numeric: tabular-nums;
}
.detail-list:has(> .detail-row:only-child) > .detail-row dt {
  font-size: var(--text-xs); text-transform: uppercase; letter-spacing: .04em;
}
.detail-list:has(> .detail-row:only-child) > .detail-row > * { text-align: left; align-self: flex-start; }
/* Een record-lijst in een detail (`deelnemers: List<Deelnemer>`): het label erboven en de tabel over
   de volle breedte, want naast een label van 34% is een tabel met drie kolommen onleesbaar smal. Op
   een telefoon scrolt alleen de tabel horizontaal, niet de pagina. */
.detail-row:has(.detail-tabel-wrap, .detail-tabel-leeg) { grid-template-columns: minmax(0, 1fr); gap: var(--space-2); }
.detail-row:has(.detail-tabel-wrap) dd { min-width: 0; }
.detail-row:has(.detail-tabel-wrap) dt { align-self: start; }
.detail-tabel-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; max-width: 100%; }
.detail-tabel { width: 100%; border-collapse: collapse; font-size: var(--text-sm); font-weight: 400; }
.detail-tabel th {
  text-align: left; padding: var(--space-2) var(--space-3);
  color: var(--color-text-muted); font-size: var(--text-xs); font-weight: 700;
  background: var(--color-bg-subtle); border-bottom: 1px solid var(--color-border); white-space: nowrap;
}
.detail-tabel td {
  padding: var(--space-2) var(--space-3); border-bottom: 1px solid var(--color-border-subtle);
  color: var(--color-text); white-space: nowrap;
}
.detail-tabel tbody tr:last-child td { border-bottom: none; }
.detail-tabel-leeg { color: var(--color-text-muted); font-weight: 400; font-style: italic; }
.detail-kids { margin-top: var(--space-5); padding: var(--space-3) var(--space-4); border-radius: var(--radius-md); background: var(--color-bg-muted); color: var(--color-text-secondary); font-size: var(--text-sm); }
.drawer-foot { display: flex; justify-content: flex-end; gap: var(--space-2); padding: var(--space-5) var(--space-6); border-top: 1px solid var(--color-border); }

/* ── Bevestig-dialoog (design-systeem modal, gecentreerd) ──────────────────── */
.confirm-overlay { position: fixed; inset: 0; z-index: var(--mock-z-dialoog); display: flex; align-items: center; justify-content: center;
  padding: var(--space-4); background: var(--mock-sluier); opacity: 0; transition: opacity .16s ease; }
.confirm-overlay.open { opacity: 1; }
/* De overlay is een <dialog> (`showModal`): de browser legt 'm in de bovenste laag en maakt de rest
   van de pagina inert. Zijn eigen kader en marges vallen weg; de overlay zelf is het vlak. */
dialog.confirm-overlay { width: 100%; height: 100%; max-width: none; max-height: none; margin: 0; border: 0; color: inherit; }
dialog.confirm-overlay::backdrop { background: transparent; }
.confirm-modal { width: 100%; max-width: 420px; background: var(--color-bg-surface);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-lg); overflow: hidden;
  transform: translateY(8px) scale(.98); opacity: 0; transition: transform .18s ease, opacity .18s ease; }
.confirm-overlay.open .confirm-modal { transform: none; opacity: 1; }
.confirm-body { display: flex; gap: var(--space-4); padding: var(--space-6) var(--space-6) var(--space-5); }
/* Een vraag zonder uitleg-regel: compact, de kop is de hele boodschap. */
.confirm-body.is-vraag { padding-bottom: var(--space-4); }
.confirm-body.is-vraag .confirm-title { margin: 0; }
.confirm-ico { flex: none; width: 40px; height: 40px; border-radius: var(--radius-pill);
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--color-error-soft); color: var(--color-error); }
.confirm-ico svg { width: 22px; height: 22px; }
.confirm-text { flex: 1; min-width: 0; }
.confirm-title { margin: 2px 0 var(--space-2); font-family: var(--font-heading);
  font-size: var(--text-lg); font-weight: 700; color: var(--color-text-heading); }
.confirm-msg { margin: 0; font-size: var(--text-sm); line-height: 1.5; color: var(--color-text-secondary); }
.confirm-foot { display: flex; justify-content: flex-end; gap: var(--space-2);
  padding: var(--space-4) var(--space-6) var(--space-6); }
@media (prefers-reduced-motion: reduce) {
  .confirm-overlay, .confirm-modal { transition: none; }
  .confirm-overlay .confirm-modal { transform: none; }
}

/* Het formulier is van het design-systeem (class-contract); dit is de terugval. */
@layer renderer {
.form-wrapper { display: flex; flex-direction: column; gap: var(--space-4); }
.form-group { display: flex; flex-direction: column; gap: var(--space-2); }
.form-label { font-size: var(--text-sm); font-weight: 600; color: var(--color-text-secondary); }
.form-control {
  padding: var(--space-2) var(--space-3); border-radius: var(--radius-md);
  border: 1px solid var(--color-border); background: var(--color-bg); color: inherit;
  font-family: inherit; font-size: var(--text-sm);
}
/* De ring is hier de schaduw; de doorzichtige outline is er voor de hoogcontrast-stand, die
   schaduwen weghaalt en een outline een systeemkleur geeft (M22). */
.form-control:focus { outline: 2px solid transparent; border-color: var(--color-border-focus); box-shadow: 0 0 0 3px var(--color-primary-glow); }
}
/* Een label is een zin, geen kop: ook een design-systeem dat labels in kapitalen zet, krijgt hier
   gewone zinsletters (de copy-conventie van de tool, geen smaak van het systeem). */
.form-label { text-transform: none; letter-spacing: normal; }
/* Empty-state van een 0-of-1 singleton-DETAIL_FORM: de melding staat bovenaan, de form-velden
 * blijven zichtbaar maar uitgegrijsd/disabled tot de bron een record heeft. */
.form-wrapper.is-empty-singleton .form-group { opacity: .55; }
.form-wrapper.is-empty-singleton :is(input, select, textarea):disabled { cursor: not-allowed; background: var(--color-bg-muted); }
.checkbox-set { display: flex; flex-direction: column; gap: var(--space-2); }
.checkbox-item { display: flex; align-items: center; gap: var(--space-2); font-size: var(--text-sm); cursor: pointer; }
/* Foutmelding bij een veld — ONDER het veld, en hij blijft staan tot je 'm oplost.
   Waarom niet (alleen) een toast: die verdwijnt na 2,6s en staat ver van de handeling. NN/g +
   Baymard: inline, aangrenzend, persistent. WCAG 3.3.1 eist de fout IN TEKST (een shake + rode
   rand is geen tekst) en 1.4.1 verbiedt kleur als enige drager — vandaar het glyph én de tekst.
   Het veld verwijst ernaar met aria-describedby (ARIA21/G85), dus een schermlezer leest 'm
   voor bij focus. Kleur = de bestaande --color-error-token, geen nieuwe. */
.field-error { display: flex; align-items: flex-start; gap: var(--space-2);
  font-size: var(--text-xs); color: var(--color-error); }
.field-error::before { content: "!"; flex: none; width: 14px; height: 14px; border-radius: 50%;
  background: var(--color-error); color: var(--mock-op-kleur); font-size: var(--mock-text-3xs); font-weight: 700;
  line-height: 14px; text-align: center; }
.form-control[aria-invalid="true"] { border-color: var(--color-error); }
.form-control[aria-invalid="true"]:focus { border-color: var(--color-error);
  box-shadow: 0 0 0 3px var(--color-error-glow); }
/* Globale melding (server-/domeinfout) — ONDER het formulier, bij de knop waar je drukte.
   role=alert + aria-live: WCAG 4.1.3 wil een statusmelding programmatisch bereikbaar hebben
   zónder dat 'ie focus steelt. */
.form-alert { display: flex; align-items: flex-start; gap: var(--space-2);
  padding: var(--space-3); border-radius: var(--radius-md);
  border: 1px solid var(--color-error);
  background: var(--color-error-bg);
  color: var(--color-error); font-size: var(--text-sm); }
.form-alert::before { content: "!"; flex: none; width: 16px; height: 16px; border-radius: 50%;
  background: var(--color-error); color: var(--mock-op-kleur); font-size: var(--mock-text-2xs); font-weight: 700;
  line-height: 16px; text-align: center; }
/* ── Wachtwoord: eisen + live voortgang ──────────────────────────────────────
   De eisen staan er vóórdat je typt (NN/g: vertel de regel, straf 'm niet af) en vinken live af.
   Kleur draagt niets alleen: elke regel heeft een ✓/○-glyph én tekst (WCAG 1.4.1), en het verschil
   tussen "voldaan" en "nog niet" zit óók in gewicht en glyph. Alle waarden komen uit de project-
   tokens met een neutrale fallback, zodat dit meekleurt met elk design-systeem. */
.pw-row { display: flex; align-items: stretch; gap: var(--space-2); }
.pw-row .form-control { flex: 1 1 auto; min-width: 0; }
.pw-toggle { flex: none; padding: 0 var(--space-3);
  border: 1px solid var(--color-border); border-radius: var(--radius-md);
  background: var(--color-bg-surface); color: var(--color-text-muted);
  font-size: var(--text-xs); font-weight: 600; cursor: pointer; }
.pw-toggle:hover { color: var(--color-text); border-color: var(--color-text-muted); }
.pw-affordance { margin-top: var(--space-2); }
.pw-rules { list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: 2px var(--space-3); }
.pw-rule { display: flex; align-items: center; gap: var(--space-2);
  font-size: var(--text-xs); color: var(--color-text-muted); }
.pw-rule-mark { flex: none; width: 1rem; text-align: center; font-weight: 700; }
.pw-rule.is-met { color: var(--color-success); font-weight: 600; }
/* Alleen de overgang naar "voldaan" is een kleine bevestiging — geen beweging bij elke toets. */
.pw-rule.is-met .pw-rule-mark { animation: pw-tick .18s ease-out; }
@keyframes pw-tick { from { transform: scale(.6); opacity: .4; } to { transform: scale(1); opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .pw-rule.is-met .pw-rule-mark { animation: none; } }
.pw-status { margin: var(--space-2) 0 0; min-height: 1em;
  font-size: var(--text-xs); color: var(--color-text-muted); }

/* Geslaagde registratie — dezelfde vorm als .form-alert, maar bevestigend. */
.form-success { display: flex; align-items: flex-start; gap: var(--space-3);
  padding: var(--space-4); border-radius: var(--radius-md);
  border: 1px solid var(--color-success);
  background: var(--color-success-bg);
  color: var(--color-success); font-size: var(--text-sm); }
.form-success p { margin: 0; }
.form-success-mark { flex: none; width: 20px; height: 20px; border-radius: 50%;
  background: var(--color-success); color: var(--mock-op-kleur); font-size: var(--text-xs); font-weight: 700;
  line-height: 20px; text-align: center; }

.shake { animation: shake .35s ease; }
@media (prefers-reduced-motion: reduce) { .shake { animation: none; } }
@keyframes shake { 0%,100% { transform: translateX(0); } 25% { transform: translateX(-5px); } 75% { transform: translateX(5px); } }

/* ── Toast ──────────────────────────────────────────────────────────────── */
.toast-stack { position: fixed; bottom: var(--space-6); left: 50%; transform: translateX(-50%); display: flex; flex-direction: column; gap: var(--space-2); z-index: var(--mock-z-toast); }
.toast {
  display: flex; align-items: center; gap: var(--space-2); padding: var(--space-3) var(--space-4);
  background: var(--mock-toast-bg); color: var(--mock-op-kleur); border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg); font-size: var(--text-sm);
  animation: toast-in .2s ease; max-width: 90vw;
}
.toast.is-error { background: var(--color-error); }
.toast.leaving { opacity: 0; transform: translateY(8px); transition: opacity .2s ease, transform .2s ease; }
/* "Nieuwe versie beschikbaar": blijft staan, met een knop die je ook met het toetsenbord bereikt. */
.toast-knop {
  font: inherit; color: inherit; background: transparent; border: 1px solid currentColor;
  border-radius: var(--radius-md); padding: var(--space-2) var(--space-3); min-height: 44px; cursor: pointer;
}
/* Op het donkere vlak van de toast: de ring in de tekstkleur (wit), niet in de focuskleur van het palet. */
.toast-knop:focus-visible { outline-color: currentColor; }
.t-glyph { display: inline-flex; font-weight: 700; }
.t-glyph svg { width: 16px; height: 16px; }
@keyframes toast-in { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }

/* ── CMS-laag — vrije mensenlaag-blokken (tekst + beeld), tussen de model-widgets ─
   Redactionele content, geen data-widget: rustig, leesbaar, leunt op de DS-tokens.
   Zichtbaar in app- én model-weergave (het is product-content, geen build-chrome). */
.cms-block { margin-bottom: var(--space-5); max-width: 72ch; }
.cms-block:last-child { margin-bottom: 0; }
.cms-richtext {
  color: var(--color-text-secondary);
  font-size: var(--text-base); line-height: var(--leading-relaxed);
}
.cms-richtext > :first-child { margin-top: 0; }
.cms-richtext > :last-child { margin-bottom: 0; }
.cms-richtext h1, .cms-richtext h2, .cms-richtext h3 {
  font-family: var(--font-heading); color: var(--color-text-heading);
  line-height: var(--leading-snug); margin: var(--space-4) 0 var(--space-2);
}
.cms-richtext h2 { font-size: var(--text-xl); }
.cms-richtext h3 { font-size: var(--text-lg); }
.cms-richtext p { margin: 0 0 var(--space-3); }
.cms-richtext a { color: var(--mock-primary-ink); }
.cms-richtext ul, .cms-richtext ol { margin: 0 0 var(--space-3); padding-left: 1.4em; }
.cms-richtext strong { color: var(--color-text); }
/* Een "callout"-variant: wikkel content in <div class="cms-note"> voor een intro-kaartje. */
.cms-richtext .cms-note, .cms-block.cms-note {
  background: var(--color-bg-muted); border: 1px solid var(--color-border);
  border-left: 3px solid var(--color-primary);
  border-radius: var(--radius-md); padding: var(--space-4) var(--space-5);
}
.cms-image { margin: 0 0 var(--space-5); }
.cms-image img {
  display: block; max-width: 100%; height: auto;
  border-radius: var(--radius-md); border: 1px solid var(--color-border);
}
.cms-image figcaption {
  margin-top: var(--space-2); font-size: var(--text-xs);
  color: var(--color-text-muted);
}

/* ── In-mock content-editor (page-builder-chrome) ───────────────────────────
   Alleen zichtbaar in bewerk-modus (body.cms-editing) — de editor-geserveerde mock. */
.cms-zone { display: flex; flex-direction: column; }

/* Bewerkbaar blok: omlijst, met een zwevende toolbar erboven. */
.cms-edit-wrap {
  position: relative; margin-bottom: var(--space-5);
  border: 1px dashed var(--color-border); border-radius: var(--radius-md);
  padding: var(--space-4); transition: border-color .15s ease;
}
.cms-edit-wrap:hover, .cms-edit-wrap:focus-within { border-color: var(--color-primary); }
.cms-edit-wrap > .cms-block { margin-bottom: 0; }

/* Add-balk: dashed strook met + Tekst / + Afbeelding. */
.cms-add {
  display: flex; gap: var(--space-2); justify-content: center;
  margin-bottom: var(--space-5); padding: var(--space-3);
  border: 1px dashed var(--color-border); border-radius: var(--radius-md);
  background: var(--color-bg-muted);
}

@media (max-width: 48rem) {
  .chapters { width: 100%; margin-left: 0; }
  .vh-title h1 { font-size: var(--text-xl); }
}

/* Canon §9 / WCAG 2.3.3 — respecteer een verlaagd-motion-voorkeur: schakel niet-essentiële
   transities + animaties uit. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .001ms !important; animation-iteration-count: 1 !important; transition-duration: .001ms !important; scroll-behavior: auto !important; }
}


/* ══ PAGE-VIEW (F1) — landing/chrome + page-block layout ═══════════════════ */
.page-block.layout-stack { display: flex; flex-direction: column; gap: var(--space-5); }
.page-block.layout-row { display: flex; gap: var(--space-4); flex-wrap: wrap; }
.page-hero {
  display: grid; grid-template-columns: 1.1fr .9fr; gap: var(--space-6); align-items: center;
  padding: clamp(1.5rem, 4vw, 3.5rem) var(--space-6) var(--space-4);
}
.page-hero-body h1 { font-size: clamp(2rem, 5vw, 3.2rem); line-height: 1.05; letter-spacing: -.02em; margin: 0 0 var(--space-3); color: var(--color-text-heading); }
/* Lopende tekst → secondary, niet muted (zie de toelichting bij `.hub-tab`). */
.page-hero-sub { font-size: var(--text-lg); line-height: 1.5; color: var(--color-text-secondary); max-width: 46ch; margin: 0; }
.page-hero-media { aspect-ratio: 4 / 3; border-radius: var(--radius-lg); display: flex; align-items: center; justify-content: center;
  background: linear-gradient(135deg, var(--color-bg-surface-hover), var(--color-border)); }
.ph-note { color: var(--color-text-muted); font-size: var(--text-sm); }
/* Losse CTA-knop in de landing-stack lijnt met de hero-padding uit. */
.page-block > a.btn { align-self: flex-start; margin: 0 var(--space-6); }
/* Geen ruimte opzij: de kop lijnt uit met de schermen eronder, die staan ook tegen de kantlijn (08-10). */
.page-section { padding: var(--space-4) 0 var(--space-6); max-width: 72ch; }
.page-section h2 { font-size: var(--text-xl); margin: 0 0 var(--space-2); color: var(--color-text-heading); }
.page-section p { color: var(--color-text-secondary); margin: 0; line-height: 1.6; }
.page-chrome { padding: var(--space-3) var(--space-6); color: var(--color-text-muted); }
@media (max-width: 48rem) { .page-hero { grid-template-columns: 1fr; } .page-hero-media { order: -1; } }

/* ══ LOGO (add-logo-skill) — header-beeldmerk (subtiel) + landing-banner (groter) ═══ */
.brand-mark.has-logo { background: none; color: inherit; width: auto; min-width: 40px; height: 40px; padding: 0; }
.brand-mark.has-logo svg { height: 100%; width: auto; display: block; }
.landing-logo-banner { display: flex; justify-content: center; padding: clamp(1rem, 3vw, 2.5rem) var(--space-6) 0; }
.landing-logo-banner svg { max-width: min(420px, 62%); height: auto; }

/* ══ Composeerbare AI-landing — de wrapper om de vrije auteur-HTML. De auteur gebruikt DS-klassen
   (page-hero, page-section, …) die hierboven al gestyled zijn; dit geeft alleen de container-breedte
   + ademruimte en de slot-hooks een minimale plek. ═══ */
/* GEEN horizontale padding: deze wrapper zit ín `.app-shell`, en die levert de zijmarge al. Deed
   'ie het wél, dan kreeg de landing een dubbele goot en stond de hero-kaart 24px verder naar binnen
   dan het logo in de header — precies de scheve uitlijning die je op productie zag. */
.mock-landing-artifact { max-width: var(--container-max); margin: 0 auto; padding: 0 0 var(--space-8); }
.mock-landing-artifact .mock-landing-screen { margin: var(--space-6) 0; }
.mock-landing-artifact .cms-zone { margin: var(--space-5) 0; }
/* Een verrijkte vorm die z'n eigen kaart meebrengt (`.inline-form` in het artefact): de omhulling
   (`.form-wrapper`) tekent dan geen tweede kaart eromheen. Gaf een witte rand met 24px opvulling
   rond het profiel en het registratieformulier, en liet het paneel ernaast niet uitlijnen (10-06). */
.form-wrapper:has(> .inline-form) { padding: 0; border: 0; box-shadow: none; background: transparent; }

/* Detail met acties: het formulier verschijnt náást het detail (openPopup). */
.naast { display: grid; grid-template-columns: minmax(0, max-content) minmax(320px, 440px); gap: var(--space-6);
  align-items: start; }
.naast-paneel { position: relative; position: sticky; top: var(--space-6);
  animation: naast-in .16s ease-out; }
.naast-paneel .inline-form { position: relative; }
.naast-paneel .inline-form-title { padding-right: var(--space-8); }
.naast-paneel .naast-sluit { position: absolute; top: var(--space-4); right: var(--space-4); z-index: 1; }
@keyframes naast-in { from { opacity: 0; transform: translateX(8px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .naast-paneel { animation: none; } }
/* Een landing-component zonder slot in de opmaak (bv. het registratieformulier): onder de opmaak, zelfde breedte. */
.mock-landing-los { max-width: var(--container-max); margin: 0 auto; padding: 0 var(--space-4) var(--space-8); }
/* Een geplaatst-maar-niet-geslot component (fallback) lijnt LINKS uit met de tekstkolom
 * i.p.v. te centreren — anders "zweeft" een inline-form (max-width + margin:auto) rechts
 * naast de links-uitgelijnde tekst. */
.mock-landing-artifact .mock-landing-placed { margin: var(--space-6) 0; }
.mock-landing-artifact .mock-landing-placed .inline-form { margin-left: 0; margin-right: auto; }

/* ═══ RBAC — persona-login (§5b). CL-niveau: DS-tokens, heldere hiërarchie, toetsenbord + focus. ═══ */
/* Topbar: de ingelogde rol + uitloggen (of een inlog-knop). */
.persona-bar { display: inline-flex; align-items: center; gap: var(--space-3);
  margin-left: auto; min-width: 0; flex-wrap: wrap; }
.persona-chip { display: inline-flex; align-items: center; gap: var(--space-2);
  padding: var(--space-1) var(--space-3); border-radius: var(--radius-pill);
  background: var(--color-bg-muted); color: var(--color-text-secondary);
  font-size: var(--text-sm); font-weight: 600; white-space: nowrap; min-width: 0; }
/* De rollenlijst is de enige buigzame kant van de chip: met meerdere rollen (en zeker in de
   ontwerp-stand "alle rollen") groeide 'ie ongelimiteerd en duwde de héle header breder dan het
   scherm — waarna de telefoon de pagina uitzoomde in plaats van te stapelen. Gemeten 09-02:
   1288px chip → 1379px layout-viewport op een toestel van 390. Afkappen dus; de titel draagt
   de volledige tekst. */
.persona-roles { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.persona-dot { width: .5rem; height: .5rem; border-radius: 50%; background: var(--color-success);
  box-shadow: 0 0 0 3px var(--color-success-bg); flex: none; }
.persona-label { color: var(--color-text-secondary); font-weight: 500; }
.persona-name { color: var(--color-text-heading); }
.persona-login { cursor: pointer; font-family: inherit; font-size: var(--text-sm);
  font-weight: 600; border-radius: var(--radius-md); padding: var(--space-2) var(--space-3);
  border: 1px solid transparent; background: var(--color-primary); color: var(--color-text-on-primary);
  display: inline-flex; align-items: center; text-decoration: none;
  transition: background .12s, border-color .12s, color .12s; }
.persona-login:hover { background: var(--color-primary-bright); }

/* Het accountmenu: je naam (de chip) is een knop; eronder je gegevens, je wachtwoord, en Uitloggen. */
.account-menu { position: relative; display: inline-flex; min-width: 0; }
.account-menu-knop { cursor: pointer; border: 1px solid transparent; font-family: inherit; }
.account-menu-knop:hover { border-color: var(--color-border); }
.account-menu-pijl { display: inline-flex; width: 1rem; height: 1rem; flex: none; transform: rotate(90deg);
  transition: transform .12s; color: var(--color-text-secondary); }
.account-menu-knop[aria-expanded="true"] .account-menu-pijl { transform: rotate(-90deg); }
.account-menu-lijst { position: absolute; right: 0; top: calc(100% + var(--space-2)); z-index: var(--mock-z-menu);
  min-width: 14rem; max-width: calc(100vw - 2rem); padding: var(--space-1);
  background: var(--color-bg-surface); border: 1px solid var(--color-border);
  border-radius: var(--radius-md); box-shadow: var(--shadow-md);
  display: flex; flex-direction: column; }
.account-menu-lijst[hidden] { display: none; }
.account-menu-lijst .persona-logout-form { display: flex; }
.account-menu-item { display: block; width: 100%; text-align: left; cursor: pointer; font-family: inherit;
  font-size: var(--text-sm); font-weight: 500; color: var(--color-text); text-decoration: none;
  padding: var(--space-2) var(--space-3); border: 0; border-radius: var(--radius-sm);
  background: transparent; min-height: max(2.5rem, var(--tap-target)); }
.account-menu-item:hover, .account-menu-item:focus-visible { background: var(--color-bg-surface-hover); }
.account-menu-item:focus-visible { outline-offset: -2px; }
.account-menu-scheiding { height: 1px; margin: var(--space-1) 0; background: var(--color-border); }

/* De login-poort: een gecentreerde kaart met rol-keuzes (multi-select) + de god-view-optie. */
.login-gate { display: flex; align-items: flex-start; justify-content: center;
  padding: var(--space-16) var(--space-6); min-height: 60vh; }
.login-card { width: 100%; max-width: 26rem; background: var(--color-bg-surface);
  border: 1px solid var(--color-border); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg); padding: var(--space-8) var(--space-6);
  text-align: center; }
.login-brand { max-width: 8rem; margin: 0 auto var(--space-5); }
.login-brand svg { max-width: 100%; height: auto; }
.login-title { font-family: var(--font-heading); font-size: var(--text-2xl);
  color: var(--color-text-heading); margin: 0 0 var(--space-2); }
.login-sub { font-size: var(--text-sm); color: var(--color-text-muted);
  line-height: var(--leading-relaxed); margin: 0 0 var(--space-6); }
.login-roles { display: flex; flex-direction: column; gap: var(--space-2); margin-bottom: var(--space-5); }
.login-role { display: flex; align-items: center; gap: var(--space-3); width: 100%;
  padding: var(--space-3) var(--space-4); cursor: pointer; font-family: inherit;
  font-size: var(--text-base); font-weight: 600; text-align: left;
  color: var(--color-text); background: var(--color-bg-surface);
  border: 1px solid var(--color-border); border-radius: var(--radius-md);
  transition: border-color .12s, background .12s, box-shadow .12s; }
.login-role:hover { border-color: var(--color-border-strong); background: var(--color-bg-surface-hover); }
.login-role-check { display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 1.25rem; height: 1.25rem; border-radius: var(--radius-sm); font-size: .75rem;
  color: transparent; border: 1.5px solid var(--color-border-strong); background: transparent; transition: all .12s; }
.login-role.on { border-color: var(--color-primary); background: var(--color-primary-soft); box-shadow: 0 0 0 1px var(--color-primary) inset; }
.login-role.on .login-role-check { color: var(--color-text-on-primary); background: var(--color-primary); border-color: var(--color-primary); }
.login-submit { width: 100%; padding: var(--space-3); cursor: pointer; font-family: inherit;
  font-size: var(--text-base); font-weight: 700; color: var(--color-text-on-primary);
  background: var(--color-primary); border: none; border-radius: var(--radius-md); transition: background .12s, opacity .12s; }
.login-submit:hover:not(:disabled) { background: var(--color-primary-bright); }
.login-submit:disabled { opacity: .45; cursor: not-allowed; }
.login-divider { height: 1px; background: var(--color-border); margin: var(--space-5) 0; }
.login-all { background: none; border: none; cursor: pointer; font-family: inherit; font-weight: 600;
  font-size: var(--text-sm); color: var(--color-text-muted); text-decoration: underline; text-underline-offset: 3px; }
.login-all:hover { color: var(--mock-primary-ink); }
.login-all:focus-visible { outline-offset: 2px; border-radius: var(--radius-sm); }

/* ═══ ECHT login-formulier (crate) — de velden op de inlogpagina en in de poort. DS-tokens; één
   kolom, labels boven de velden, ruime raakvlakken (WCAG 2.2 2.5.8). ═══ */
.login-field { display: flex; flex-direction: column; gap: var(--space-2); margin-bottom: var(--space-4); }
.login-label { font-size: var(--text-sm); font-weight: 600; color: var(--color-text-heading); }
.login-input { width: 100%; box-sizing: border-box; min-height: 2.75rem; padding: var(--space-3);
  font-family: inherit; font-size: var(--text-base); color: var(--color-text);
  background: var(--color-bg-surface); border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-md); transition: border-color .15s ease, box-shadow .15s ease; }
.login-input:focus { outline: 2px solid transparent; border-color: var(--color-primary);
  box-shadow: 0 0 0 3px var(--color-primary-soft); }
.login-field.has-toggle { position: relative; }
.login-field.has-toggle .login-input { padding-right: 4.5rem; }
.login-pw-toggle { position: absolute; right: var(--space-2); bottom: .45rem; min-height: 1.9rem;
  padding: 0 var(--space-2); cursor: pointer; font-family: inherit; font-size: var(--text-xs);
  font-weight: 600; color: var(--color-text-muted); background: none; border: none;
  border-radius: var(--radius-sm); }
.login-pw-toggle:hover { color: var(--mock-primary-ink); }
.login-pw-toggle:focus-visible { outline-offset: 1px; }
.login-error { margin-bottom: var(--space-4); padding: var(--space-3);
  font-size: var(--text-sm); color: var(--color-danger);
  background: var(--color-danger-soft); border: 1px solid var(--color-danger);
  border-radius: var(--radius-md); }
.persona-logout-form { display: inline-flex; margin: 0; }

/* De inlogpagina (`/login`): de kaart op een rustig vlak tussen header en footer, iets boven het
   optische midden. Merk, titel en uitleg gecentreerd; de velden links uitgelijnd, want een
   gecentreerd label leest slecht. */
.login-page { display: flex; flex-direction: column; align-items: center;
  min-height: calc(100vh - 16rem); min-height: calc(100dvh - 16rem); padding: clamp(2rem, 8vh, 5rem) 0; }
.login-page .login-card { box-shadow: var(--shadow-md); }
.login-alt { margin: var(--space-5) 0 0; padding-top: var(--space-5);
  border-top: 1px solid var(--color-border);
  font-size: var(--text-sm); color: var(--color-text-muted); }
.login-alt a { color: var(--mock-primary-ink); font-weight: 600; text-underline-offset: 3px; }
.login-alt a:focus-visible { outline-offset: 2px; border-radius: var(--radius-sm); }
.login-card .login-form { text-align: left; }
.login-card .login-submit { margin-top: var(--space-2); min-height: 2.75rem; }
.login-notice { margin: 0 0 var(--space-5); padding: var(--space-3); text-align: left;
  font-size: var(--text-sm); color: var(--color-success);
  background: var(--color-success-bg); border: 1px solid var(--color-success);
  border-radius: var(--radius-md); }
@media (max-width: 30rem) {
  .login-page { padding: var(--space-6) var(--space-4); }
  .login-card { padding: var(--space-6) var(--space-5); }
}

/* Geen-toegang: als je ingelogd een pagina buiten je rol opent. */
.no-access { display: flex; flex-direction: column; align-items: center; text-align: center;
  padding: var(--space-16) var(--space-6); gap: var(--space-3); }
.no-access-glyph { width: 3rem; height: 3rem; display: inline-grid; place-items: center; border-radius: 999px;
  background: var(--color-bg-muted); color: var(--color-text-secondary); }
.no-access-glyph svg { width: 1.4rem; height: 1.4rem; }
.no-access-title { font-family: var(--font-heading); font-size: var(--text-2xl); color: var(--color-text-heading); margin: 0; }
.no-access-text { font-size: var(--text-sm); color: var(--color-text-muted); margin: 0; max-width: 24rem; }
.no-access-actions { display: flex; gap: var(--space-3); margin-top: var(--space-4); }
.no-access-btn { cursor: pointer; font-family: inherit; font-weight: 600; font-size: var(--text-sm);
  padding: var(--space-2) var(--space-4); border-radius: var(--radius-md);
  border: none; background: var(--color-primary); color: var(--color-text-on-primary); transition: background .12s; }
.no-access-btn.ghost { background: var(--color-bg-surface); border: 1px solid var(--color-border); color: var(--color-text-secondary); }
.no-access-btn:hover { background: var(--color-primary-bright); }
.no-access-btn.ghost:hover { background: var(--color-bg-surface-hover); }


/* ═══ Fase 4 — inline form (registratie boven de vouw, in de composeerbare landing). ═══ */
.inline-form { max-width: 30rem; margin: var(--space-6) 0; padding: var(--space-6);
  background: var(--color-bg-surface); border: 1px solid var(--color-border);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-md); }
.inline-form-title { font-family: var(--font-heading); font-size: var(--text-lg);
  color: var(--color-text-heading); margin: 0 0 var(--space-4); }
/* `.form-wrapper` is een flex-kolom MET gap; een marge eronder komt daar bovenop en gaf dubbele
   tussenruimte (32px tussen velden, 40px voor de knop) — ongelijk ritme in één kaart. */
.inline-form .form-group { margin-bottom: 0; }
/* De velden van een OMGEZET formulier. Eén kolom, met dezelfde tussenruimte als de generieke
   render — een omzetting verandert het design, niet de indeling. (Stond op `.form-grid`, de grid
   van de formulieren-hub: kaarten van 260px, dus tegelden de velden in kolommen.) */
.form-fields { display: flex; flex-direction: column; gap: var(--space-4); }
.form-fields > [data-bind-field] { display: flex; flex-direction: column; }
/* Een formulier BINNEN een kaart is geen tweede kaart. Sommige design-systemen stylen een kale
   `form` als oppervlak (rand + schaduw); binnen `.inline-form` levert dat een doos in een doos op
   — het eerste wat je ziet op een detail- of registratiescherm (gemeten 21-09). */
.inline-form .form-wrapper { border: 0; box-shadow: none; background: none; padding: 0; }
/* De knoppenrij is een RIJ. Twee knoppen onder elkaar over de volle breedte lezen als twee even
   zware hoofdhandelingen; naast elkaar leest de hiërarchie (destructief krimpt, hoofdknop groeit). */
.inline-form-foot { margin-top: var(--space-5); display: flex; gap: var(--space-3); flex-wrap: wrap; }
.inline-form-foot .btn { flex: 1 1 auto; justify-content: center; }
.inline-form-foot .btn.is-danger { flex: 0 1 auto; }
/* `.form-wrapper` heeft zelf al een gap; de marge van de voet kwam daar bovenop en gaf een gat
   van ~80px tussen het laatste veld en de knop. */
.inline-form .form-wrapper > .inline-form-foot { margin-top: var(--space-2); }
.inline-form-missing { max-width: 30rem; margin: var(--space-6) 0; padding: var(--space-4);
  border: 1px dashed var(--color-error); border-radius: var(--radius-md); color: var(--color-error); text-align: center; }

/* ══ AANRAAKDOELEN (WCAG 2.2 AA 2.5.8, M23) ════════════════════════════════
   Eén maat, `--tap-target`: 24px met een muis, 44px op een aanraakscherm of in een smal venster (zie
   de token-defaults). Tot 10-10 gold dit alleen onder 48rem, met losse getallen per component (36, 40,
   44px), en een tablet met een vinger kreeg de muismaat. Gemeten vóór de eerste versie van deze regel:
   chips 25px, kruimels 22px, knoppen 32-37px, velden 34px (axe: 18 target-size-schendingen op één
   lijstpagina). Een doel dat altijd 44px is (de filterbalk, de dagknoppen) zegt dat zelf. */
.btn, .btn-sm, .chip, .crumb, .persona-login, .form-control, .search-box { min-height: var(--tap-target); }
.btn, .btn-sm, .chip, .crumb, .persona-login { display: inline-flex; align-items: center; }
.search-clear, .drawer-close, .pw-toggle, .tag-weg, .rating-star {
  min-width: var(--tap-target); min-height: var(--tap-target);
  display: inline-flex; align-items: center; justify-content: center;
}

/* ══ MOBIEL — de invarianten van de GENERIEKE laag ═══════════════════════════
   Tot 2026-09-02 leefde het stapelen van een worklist ALLEEN in de per-project
   `components.css`. 9 van de 22 design-systemen in dit repo hadden die regel niet:
   daar was de lijst op 390px **636px breed in een 340px kolom** — status én rij-acties
   achter een onaangekondigde swipe. En zelfs mét een stapelend DS lekte de `nowrap` +
   `min-width:max-content` hierboven erdoorheen (gemeten: 367px kaart in een 340px wrap,
   27px afgeknipt zodra een rij drie acties had).

   Mobiel-fatsoen hoort een GARANTIE van de codegen te zijn, niet een eigenschap van
   het toevallige design-systeem — zelfde lat als "niets in de codegen kent een
   projectnaam". Het DS mag dit hierna nog mooier maken; het mag het niet langer
   *mogelijk* maken.

   Meting + achtergrond: docs/plan-2026-09-02-mobiel-en-native.md
   ─────────────────────────────────────────────────────────────────────────── */
@media (max-width: 48rem) {

  /* ── 1. Worklist: van tabel naar kaartjes ────────────────────────────────
     `display:block` op de TABEL zelf is de kern. Zonder dat blijft het
     table-layout-algoritme actief en bepaalt de breedste rij (de actie-rij) de
     min-content-breedte — dan stapelen de cellen wél, maar puilt de kaart alsnog
     buiten de container. Dát was het 27px-lek. */
  .table-wrap { overflow-x: visible; border: 0; background: none; box-shadow: none; border-radius: 0; }
  .data-table { display: block; width: 100%; }
  .data-table thead {
    position: absolute; width: 1px; height: 1px; overflow: hidden;
    clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
  }
  .data-table tbody { display: block; }
  .data-table tbody tr {
    display: block; width: 100%;
    padding: var(--space-2) var(--space-4);
    margin-bottom: var(--space-3);
    background: var(--color-bg-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
  }
  .data-table tbody tr:last-child { margin-bottom: 0; }
  .data-table tbody td {
    display: flex; align-items: baseline; justify-content: space-between;
    gap: var(--space-4);
    width: auto; min-width: 0; padding: var(--space-2) 0;
    white-space: normal; overflow-wrap: anywhere;
    border-bottom: 1px solid var(--color-border-subtle);
  }
  /* Het kolomlabel dat in de thead stond. De renderer zet `data-label` al op elke
     cel (renderTable) — dit is dus puur CSS. */
  .data-table tbody td::before {
    content: attr(data-label);
    flex: 0 0 auto; margin-right: auto;
    font-size: var(--text-xs); font-weight: 700; letter-spacing: .02em;
    text-transform: uppercase; color: var(--color-text-muted);
  }
  /* De eerste kolom is de IDENTITEIT van de rij — op een kaart is dat de titel, niet een waarde
     achter een label. "NAAM · Sanne de Jong" rechts uitgelijnd leest als een veld; "Sanne de Jong"
     als kop leest als een kaart. Canon §2: één stabiele linker-scan-rand. */
  .data-table tbody td.cell-primary {
    display: block; font-size: var(--text-lg); font-weight: 650;
    color: var(--color-text-heading);
    padding-top: var(--space-3); padding-bottom: var(--space-2);
  }
  .data-table tbody td.cell-primary::before { content: none; }
  /* Een design-systeem dat cellen rechts zet (`td { text-align: right }`) zette ook de KOP van het
     kaartje rechts. De kop is de linker-scan-rand. */
  .data-table tbody td.cell-primary { text-align: left; }
  /* Eén kolom (en geen acties): een gewone lijst, geen stapel kaartjes. "Beheerder" en
     "Gebruiker" als twee losse kaarten in een paneel las als kaart-in-kaart (23-09). */
  .data-table tbody tr:has(> td:only-child) {
    background: none; border: 0; border-radius: 0; box-shadow: none; margin: 0; padding: 0;
    border-bottom: 1px solid var(--color-border-subtle);
  }
  .data-table tbody tr:has(> td:only-child):last-child { border-bottom: 0; }
  .data-table tbody tr:has(> td:only-child) > td.cell-primary {
    font-size: var(--text-base); font-weight: 500; border-bottom: 0;
    padding: var(--space-3) var(--space-4);
  }

  /* ── 2. Rij-acties: eigen regel, volle breedte, mogen afbreken ──────────
     Op desktop krimpt de actie-kolom tot z'n inhoud en mogen de knoppen niet
     krimpen (zie de overlap-bug hierboven). In een gestapelde kaart is precies
     dat de bodem die de kaart te breed maakt — hier dus het omgekeerde. */
  .data-table td.cell-actions, .data-table th.th-actions {
    width: auto; min-width: 0; text-align: left; white-space: normal;
    border-bottom: 0; padding-top: var(--space-3);
  }
  .data-table td.cell-actions::before { content: none; }
  .row-actions { display: flex; flex-wrap: wrap; width: 100%; justify-content: stretch; }
  .row-actions .btn { flex: 1 1 8rem; justify-content: center; }
  /* De "Openen"-knop is in een gestapelde kaart de primaire actie — geef 'm z'n naam terug
     (op desktop blijft het een chevron in de actie-kolom). */
  .row-actions .btn-ghost[data-open] { gap: .4rem; }
  .row-actions .btn-ghost[data-open]::after { content: attr(data-open); }

  /* ── 3. Aanraakdoelen: de maat staat bij AANRAAKDOELEN hierboven (`--tap-target` is hier 44px). */
  .btn, .btn-sm { justify-content: center; }
  /* Chip + uitloggen op ÉÉN regel. `flex-wrap: nowrap` + overal `min-width: 0` is wat een
     flex-kind laat krimpen; zonder die nul duwt de langste tekst (een gebruikersnaam, of de
     rollenlijst in de ontwerp-stand) de knop naar een eigen regel. De naam kapt af; de titel draagt
     'm voluit. Waar de balk staat (naast het merk) zegt het accountmenu verderop (P7). */
  .persona-bar { justify-content: space-between; flex-wrap: nowrap; }
  .persona-chip { flex: 0 1 auto; min-width: 0; overflow: hidden; }
  .account-menu { flex: 0 1 auto; min-width: 0; margin-left: auto; }
  /* "Ingelogd als" verdwijnt op een klein scherm: de groene stip zegt hetzelfde en de naam heeft
     de ruimte harder nodig. Liet 'm eerst staan mét krimp — toen liep de tekst over de naam heen,
     want een gekrompen inline-element kapt niet vanzelf af. */
  .persona-label { display: none; }
  .persona-dot { flex: 0 0 auto; }
  .persona-name, .persona-roles {
    flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .persona-roles { max-width: 8rem; }
  /* In de echte-auth-tak zit de uitlog-knop in een <form> — DAT is het flex-kind, niet de knop.
     Zonder deze regel krimpt de chip niet en valt "Uitloggen" alsnog op een eigen regel. */
  .persona-login, .persona-logout-form { flex: 0 0 auto; }
  /* Het zoekveld ZELF vullen: de doos was al 44px hoog, maar het kale input erin 18px — tikken
     naast de tekst deed dan niets. */
  .search-box .search-input { align-self: stretch; }

  /* ── 4. Invoer: 16px ondergrens ──────────────────────────────────────────
     Onder 16px zoomt iOS Safari in zodra een veld focus krijgt en verspringt de
     hele pagina. Gold vóór deze regel voor élk formulier (13,6px). */
  .form-control, .search-input, input:not([type="checkbox"]):not([type="radio"]), select, textarea {
    font-size: max(16px, var(--text-sm));
  }
  textarea.form-control { min-height: 5.5rem; }

  /* ── 5. Chrome: minder scherm opeten ─────────────────────────────────────
     De sticky header was 170px van 844px — een vijfde van het scherm, permanent. */
  .app-header-inner { padding: var(--space-3) var(--space-4); gap: var(--space-3); }
  .tagline { display: none; }
  .app-shell { padding: var(--space-4); }
  .hub-nav { padding: 0 var(--space-4); scroll-snap-type: x proximity; }
  .hub-tab { scroll-snap-align: start; padding-left: var(--space-3); padding-right: var(--space-3); }
  /* Scroll-affordance: de rechterrand vervaagt, zodat zichtbaar is dat er meer
     tabs zijn. Zonder dit is de nav een STILLE scroller — 13 items, 4 in beeld. */
  .hub-nav {
    -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 2rem), transparent);
    mask-image: linear-gradient(90deg, #000 calc(100% - 2rem), transparent);
  }

  /* ── 6. Detail-inzage: label boven waarde i.p.v. twee kolommen ───────────
     Ook als het design-systeem de lijst zelf als raster tekent (`.detail-list` twee kolommen,
     `.detail-row { display: contents }`): op een telefoon is dat een label van 130px naast een
     e-mailadres dat midden in een woord afbreekt. Dus hier ook de `display`. */
  .detail-list { display: flex; flex-direction: column; }
  .detail-row { display: grid; grid-template-columns: 1fr; gap: var(--space-1); }
}

/* ══════════════════════════════════════════════════════════════════════════
   VERRIJKTE SCHERM-COMPONENTEN + WIDGET-CATALOGUS (Component Studio)
   --------------------------------------------------------------------------
   Structuur, geen smaak: het artefact brengt z'n eigen opmaak mee (design-systeem-
   tokens), deze regels zorgen alleen dat de door de RENDERER geplaatste onderdelen
   (widgets, ingevulde slots, de terugval-velden) er verzorgd bij staan.
   ══════════════════════════════════════════════════════════════════════════ */
.screen-artifact { display: block; }
/* Niet-gebonden verplichte velden vallen nooit stil weg — ze staan hier, zichtbaar apart. */
.artifact-rest {
  display: grid; gap: var(--space-4);
  margin-top: var(--space-5); padding-top: var(--space-4);
  border-top: 1px dashed var(--color-border);
}

/* ── slider ─────────────────────────────────────────────────────────────── */
.slider-row { display: flex; align-items: center; gap: var(--space-3); }
.slider-input { flex: 1 1 auto; padding: 0; height: 1.5rem; accent-color: var(--color-primary); }
.slider-value {
  flex: 0 0 auto; min-width: 3.5rem; text-align: right;
  font-family: var(--font-mono); font-size: var(--text-sm);
  color: var(--color-text-secondary);
}

/* ── stepper ────────────────────────────────────────────────────────────── */
.stepper-row { display: flex; align-items: center; gap: var(--space-2); }
.stepper-row .stepper-input { flex: 1 1 auto; text-align: center; }

/* ── segmented (keuzeknoppen i.p.v. dropdown) ───────────────────────────── */
.segmented { display: inline-flex; flex-wrap: wrap; gap: 0; border: 1px solid var(--color-border); border-radius: var(--radius-md); overflow: hidden; }
.seg-btn {
  appearance: none; border: 0; cursor: pointer;
  padding: var(--space-2) var(--space-4);
  font: inherit; font-size: var(--text-sm);
  background: var(--color-bg-surface); color: var(--color-text);
  border-right: 1px solid var(--color-border-subtle);
}
.seg-btn:last-child { border-right: 0; }
.seg-btn:hover { background: var(--color-bg-surface-hover); }
.seg-btn.is-on { background: var(--color-primary); color: var(--color-text-on-primary); }

/* ── switch ─────────────────────────────────────────────────────────────── */
.switch { display: inline-flex; align-items: center; cursor: pointer; }
.switch .switch-input { position: absolute; opacity: 0; width: 0; height: 0; }
.switch-track {
  width: 2.75rem; height: 1.5rem; border-radius: var(--radius-pill);
  background: var(--color-border-strong); position: relative; transition: background .15s ease;
}
.switch-track::after {
  content: ''; position: absolute; top: 2px; left: 2px; width: 1.25rem; height: 1.25rem;
  border-radius: 50%; background: var(--mock-op-kleur); box-shadow: var(--shadow-sm);
  transition: transform .15s ease;
}
.switch .switch-input:checked + .switch-track { background: var(--color-primary); }
.switch .switch-input:checked + .switch-track::after { transform: translateX(1.25rem); }
.switch .switch-input:focus-visible + .switch-track { outline: var(--focus-ring); outline-offset: 2px; }

/* ── rating ─────────────────────────────────────────────────────────────── */
.rating { display: inline-flex; gap: var(--space-1); }
.rating-star {
  appearance: none; border: 0; background: none; cursor: pointer; padding: 0 .1rem;
  font-size: var(--text-xl); line-height: 1; color: var(--color-border-strong);
}
.rating-star.is-on { color: var(--mock-primary-ink); }

/* ── chips (multiselect) ────────────────────────────────────────────────── */
.chip-set { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.tag-veld { display: flex; flex-direction: column; gap: var(--space-2); }
.tag-set:empty { display: none; }
.chip.tag { display: inline-flex; align-items: center; gap: 4px; cursor: default; }
.tag-weg { border: 0; background: transparent; color: inherit; font: inherit; font-size: 1.1em; line-height: 1; padding: 0 2px; cursor: pointer; opacity: .8; }
.tag-weg:hover, .tag-weg:focus-visible { opacity: 1; }


/* De eigen-tekst-zone van een pagina: een benoemde plek in plaats van een losse "+"-balk. */
.page-cms-zone { margin-top: var(--space-6); }

/* ── "alleen dit component" (…/mock/screen-preview) ──────────────────────────
   Het scherm zonder chrome, om ingebed te worden (bv. op een SCREEN-sticky in het
   model-venster). Alles wat om het component heen zit valt weg; het component zelf
   blijft exact zoals de mock 'm tekent. */
/* Een knop wees naar een component op DEZE pagina: even oplichten zodat je ziet waar 'ie staat. */
.component-aangewezen { outline: 2px solid var(--color-primary); outline-offset: 4px;
  border-radius: var(--radius-md); }


/* Kolom-discipline: wat we uit de tabel lieten, zeggen we eronder — stil weglaten is liegen. */
.kolom-noot {
  margin: var(--space-3) 0 0; font-size: var(--text-xs);
  color: var(--mock-muted);
}

/* ══════════════════════════════════════════════════════════════════════════
   DONKER — één palet-omkering, alle design-systemen tegelijk
   --------------------------------------------------------------------------
   De renderer keert de STRUCTURELE tokens om (grond, vlak, rand, tekst) en laat de MERK-tokens staan;
   die worden alleen opgelicht zodat ze op een donkere grond hun contrast halen. Zo is elk project
   meteen donker-waardig zonder z'n identiteit te verliezen, zonder dat elk design-systeem eerst z'n
   eigen donkere palet moet meebrengen.

   EÉN blok, op `data-theme="dark"` (M24, 10-10). Het attribuut staat er altijd: de keuze "volg mijn
   systeem" zet de renderer om naar de stand van het systeem (`thema.js`, in de app al vóór de eerste
   paint door `/js/mock-boot.js`). Tot 10-10 stond het palet er twee keer, één keer voor de
   systeemstand (`prefers-color-scheme`) en één keer voor de expliciete keuze, en dat liep uit elkaar:
   beelden werden alleen bij de expliciete keuze getemperd.

   Een design-systeem met een eigen donker palet zet dat op `:root:root[data-theme="dark"]`: dat is
   specifieker dan het blok hieronder en wint, ook al laadt het eerder. */
/* ── Afgeleide, gegarandeerd leesbare tinten ────────────────────────────────
   Veel design-systemen kiezen een `--color-text-muted` die er mooi uitziet en 3,2:1 haalt. Voor
   decoratie is dat prima, voor tekst die je moet LEZEN (kolomkoppen, tellingen, de voettekst) niet:
   WCAG eist 4,5:1. In plaats van elk systeem te corrigeren, leidt de renderer z'n eigen stille grijs
   af uit de tekstkleur die het systeem al heeft: op-merk, en het haalt de norm. Zonder `color-mix`
   (Safari < 16.2) de secundaire tekstkleur van het systeem; een custom property met een `color-mix`
   die de browser niet kent, is bij gebruik `unset`, dus de menging staat achter `@supports` (M19). */
:root {
  color-scheme: light;
  --mock-muted: var(--color-text-secondary);
  --mock-muted-op-vlak: var(--color-text-secondary);
}
@supports (color: color-mix(in srgb, red, blue)) {
  :root {
    --mock-muted: color-mix(in srgb, var(--color-text) 80%, var(--color-bg));
    --mock-muted-op-vlak: color-mix(in srgb, var(--color-text) 80%, var(--color-bg-subtle));
  }
}

:root[data-theme="dark"] {
  color-scheme: dark;
  --color-bg: #12161c;
  --color-bg-subtle: #171c24;
  --color-bg-muted: #1d2430;
  --color-bg-surface: #181e26;
  --color-bg-surface-hover: #212a35;
  --color-surface-2: #1d2430;
  --color-border: #2b3440;
  --color-border-subtle: #232b36;
  --color-border-strong: #3a4553;
  --color-text: #e6eaf0;
  --color-text-heading: #f3f6fa;
  --color-text-secondary: #b8c1cd;
  --color-text-muted: #8b96a5;
  /* Merk-tokens: dezelfde kleur, opgelicht tot ze op donker leesbaar zijn (de menging staat
     hieronder achter @supports; zonder `color-mix` de heldere variant van het merk zelf). */
  --color-primary: var(--color-primary-bright);
  --color-primary-soft: var(--color-bg-muted);
  /* Semantische kleuren krijgen in donker VASTE waarden. Ze afleiden uit de lichte token gaat niet:
     `--color-danger: color-mix(… var(--color-danger) …)` verwijst naar zichzelf, en dan valt de hele
     declaratie terug op de lichte waarde (donkerrood op bijna-zwart, 2,56:1). Het hoeft ook niet:
     rood-is-gevaar is een conventie, geen merk-eigenschap. De vlakken zijn de kleur voor 24% gemengd
     met de grond (#12161c), uitgerekend, zodat er geen `color-mix` voor nodig is. */
  --color-success: #5fd08a;
  --color-success-bg: #244336;
  --color-error: #ff7a6e;
  --color-error-bg: #4b2e30;
  --color-danger: #ff7a6e;
  --color-danger-soft: #4b2e30;
  --color-warning: #efc05f;
  --color-warning-bg: #473f2c;
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, .5);
  --shadow-md: 0 4px 12px rgba(0, 0, 0, .5);
  --shadow-lg: 0 12px 32px rgba(0, 0, 0, .55);
  --shadow-xl: 0 24px 64px rgba(0, 0, 0, .6);
}
@supports (color: color-mix(in srgb, red, blue)) {
  :root[data-theme="dark"] {
    --color-primary: color-mix(in srgb, var(--color-primary-bright) 72%, #fff);
    --color-primary-soft: color-mix(in srgb, var(--color-primary-bright) 22%, #12161c);
  }
}
/* Beeld en logo's zijn voor licht ontworpen; op donker temperen we ze een tik. De kaart wordt
   omgekeerd, anders is 'ie het felste vlak van het scherm. */
:root[data-theme="dark"] img, :root[data-theme="dark"] .brand-mark svg { filter: brightness(.92); }
:root[data-theme="dark"] .geo-kaart .leaflet-tile-pane { filter: invert(1) hue-rotate(180deg) brightness(.85) contrast(.9); }

/* De dag/nacht-schakelaar — PRODUCT-chrome (de eindgebruiker wil 'm ook), dus in de app-header
   en niet in de bouw-strip. */
.theme-toggle {
  appearance: none; cursor: pointer; display: inline-flex; align-items: center; justify-content: center;
  min-width: var(--tap-target); min-height: var(--tap-target); width: 2rem; height: 2rem; padding: 0;
  border-radius: var(--radius-pill);
  border: 1px solid var(--color-border); background: var(--color-bg-surface);
  color: var(--color-text-secondary); font-size: var(--text-sm); line-height: 1;
}
.theme-toggle:hover { border-color: var(--color-border-strong); color: var(--color-text); }

/* ── Donker: de renderer neemt z'n eigen componenten terug ──────────────────
   De token-omkering hierboven werkt voor alles wat een token LEEST. Maar een design-systeem dat
   z'n nav-tabs of chips met een letterlijke kleur opmaakt (`color: #4b5563`) volgt niet mee — en
   dan staat er donkergrijs op bijna-zwart. Deze regels zijn specifieker dan een kale class-regel
   uit het DS, dus in donker wint de renderer op de hooks die van hem zijn. Alleen op renderer-
   eigen classes; de vrije CMS-laag en de landing blijven van de auteur.

   Merk je hier iets missen: dat is een DS dat z'n kleuren hardcodeert. De echte oplossing is dat
   dát systeem tokens gebruikt — dit is het vangnet, niet de norm. Tekst op het opgelichte merk is
   de donkere grond: dat haalt het contrast, wit niet. */
:root[data-theme="dark"] .hub-tab,
:root[data-theme="dark"] .crumb,
:root[data-theme="dark"] .vh-count,
:root[data-theme="dark"] .search-input,
:root[data-theme="dark"] .form-label { color: var(--color-text-secondary); }
:root[data-theme="dark"] .hub-tab[aria-current] { color: var(--mock-primary-ink); }
:root[data-theme="dark"] .view-head h1,
:root[data-theme="dark"] .drawer h2,
:root[data-theme="dark"] .wordmark,
:root[data-theme="dark"] .inline-form-title,
:root[data-theme="dark"] h1, :root[data-theme="dark"] h2, :root[data-theme="dark"] h3 { color: var(--color-text-heading); }
:root[data-theme="dark"] .data-table thead th { color: var(--color-text-muted); background: var(--color-bg-subtle); }
:root[data-theme="dark"] .cell-primary { color: var(--color-text-heading); }
:root[data-theme="dark"] .chip { background: var(--color-bg-muted); color: var(--color-text-secondary); border-color: var(--color-border); }
:root[data-theme="dark"] .chip.is-active { background: var(--color-primary); color: var(--color-bg); border-color: transparent; }
:root[data-theme="dark"] .btn-primary { background: var(--color-primary); color: var(--color-bg); }
:root[data-theme="dark"] .btn-secondary { background: var(--color-bg-surface); color: var(--color-text); border-color: var(--color-border); }
:root[data-theme="dark"] .form-control { background: var(--color-bg-surface); color: var(--color-text); border-color: var(--color-border); }
:root[data-theme="dark"] .table-wrap, :root[data-theme="dark"] .drawer,
:root[data-theme="dark"] .form-card { background: var(--color-bg-surface); border-color: var(--color-border); }
:root[data-theme="dark"] body, :root[data-theme="dark"] .app-shell { background: var(--color-bg); color: var(--color-text); }
/* Een sfeerlaag onder de pagina (`body::before` met een verloop) schildert het DS met z'n LICHTE
   palet (`--cyan-50` e.d.): die tokens keert niemand om, dus in donker stond er een lichte baan
   langs de rand (de `.app-shell` hierboven dekt de rest af, dus alleen de marge liet 'm zien).
   In donker vervalt die laag: de grond is de sfeer. */
:root[data-theme="dark"] body::before { background: none; }

/* De kruimel op het eerste niveau zegt hetzelfde als de H1 eronder — `hidden` moet daar dan ook
   écht verbergen; `.crumbs { display:flex }` won anders van `[hidden]`. */
.crumbs[hidden] { display: none; }

/* ── De start (route `/` voor wie ingelogd is) ──────────────────────────────
   Oriëntatie boven overtuiging: waar ben ik, wat is er, wat is de volgende stap. Geen nieuwe
   componenten — de pagina's die deze rol tóch al mag zien, met hun eigen telling. */
.start-head { margin-bottom: var(--space-6); }
.start-head h1 { margin: 0 0 var(--space-2); }
.start-sub { margin: 0; color: var(--color-text-secondary); }
.start-grid {
  display: grid; gap: var(--space-4);
  grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
}
/* `/start` — een tab per rol (plan 2026-10-01, F5). Alleen design-systeem-tokens: elk project krijgt
   de tabs in z'n eigen look. Op smalle schermen scrollen de tabs horizontaal in plaats van te breken. */
.start-tabs-pagina { display: flex; flex-direction: column; gap: var(--space-6); }
.start-tabs {
  display: flex; gap: var(--space-1); overflow-x: auto; scrollbar-width: thin;
  border-bottom: 1px solid var(--color-border-subtle);
}
.start-tab {
  flex: none; padding: var(--space-3) var(--space-4); min-height: 44px;
  background: none; border: 0; border-bottom: 2px solid transparent; margin-bottom: -1px;
  font: inherit; font-weight: 600; color: var(--color-text-secondary); cursor: pointer;
}
.start-tab:hover { color: var(--color-text-heading); }
.start-tab.is-actief { color: var(--color-primary); border-bottom-color: var(--color-primary); }
.start-tab:focus-visible { outline-offset: 2px; border-radius: var(--radius-sm); }
.start-tab-admin { display: flex; flex-direction: column; gap: var(--space-4); align-items: flex-start; max-width: 40rem; }
.start-tab-admin p { margin: 0; color: var(--color-text-secondary); }

.start-kaart {
  appearance: none; cursor: pointer; text-align: left; font: inherit;
  display: flex; align-items: baseline; gap: var(--space-2);
  padding: var(--space-4) var(--space-5);
  background: var(--color-bg-surface); color: var(--color-text);
  border: 1px solid var(--color-border); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
}
.start-kaart:hover { border-color: var(--color-primary); }
.sk-naam { font-weight: 650; color: var(--color-text-heading); }
.sk-telling { font-size: var(--text-sm); color: var(--color-text-muted); }
.sk-pijl { margin-left: auto; color: var(--color-text-muted); display: inline-flex; }
.sk-pijl svg { width: 16px; height: 16px; }
.start-kop {
  margin: var(--space-8) 0 var(--space-3); font-size: var(--text-sm);
  text-transform: uppercase; letter-spacing: .06em; color: var(--color-text-muted);
}
.start-taken { display: flex; flex-wrap: wrap; gap: var(--space-2); }


/* ══════════════════════════════════════════════════════════════════════════
   KAART — LOCATION-velden en -kolommen (Leaflet + PDOK; gedrag in app.js, blok KAART)
   Alleen bestaande tokens: een design-systeem hoeft voor de kaart niets nieuws te leveren. De
   tegelstijl kiest het DS met `--map-tiles` (grijs · pastel · standaard · water) — die leest app.js,
   niet deze CSS, dus hij telt niet mee in het token-contract.
   Tinten: pinnen kleuren per soort (status/categorie) uit vijf tokens die elk DS al heeft.
   ══════════════════════════════════════════════════════════════════════════ */
.geo-kaart {
  position: relative; width: 100%; overflow: hidden; isolation: isolate;
  border: 1px solid var(--color-border); border-radius: var(--radius-lg);
  background: var(--color-bg-muted); font-family: inherit;
}
/* `vh` eerst: een browser zonder `svh` (vóór Safari 15.4) laat die regel vallen en houdt deze. */
.geo-kaart-kiezer { height: clamp(220px, 38vh, 320px); height: clamp(220px, 38svh, 320px); }
.geo-kaart-lijst { height: clamp(260px, 46vh, 440px); height: clamp(260px, 46svh, 440px); }
.geo-sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }

/* Leaflet-chrome in de taal van het DS. */
.geo-kaart .leaflet-bar { border: 1px solid var(--color-border); border-radius: var(--radius-md); box-shadow: var(--shadow-sm); overflow: hidden; }
.geo-kaart .leaflet-bar a { background: var(--color-bg-surface); color: var(--color-text); border-bottom-color: var(--color-border); }
.geo-kaart .leaflet-bar a:hover { background: var(--color-bg-surface-hover); }
.geo-kaart .leaflet-control-attribution { font-size: var(--mock-text-3xs); background: var(--color-bg-surface); background: color-mix(in srgb, var(--color-bg-surface) 80%, transparent); color: var(--color-text-secondary); }
.geo-kaart .leaflet-control-attribution a { color: inherit; }
/* Duimvriendelijk: op touch zijn de zoomknoppen een echt tikdoel (WCAG 2.5.8, NN/g 44px). */
@media (pointer: coarse) {
  .geo-kaart .leaflet-bar a { width: 44px; height: 44px; line-height: 44px; font-size: 1.375rem; }
}
/* De twee-vingers-hint: verschijnt alleen als je met één vinger over de kaart sleept. */
.geo-gebaar {
  position: absolute; inset: 0; z-index: var(--mock-z-kaart); display: grid; place-items: center; padding: var(--space-6);
  background: var(--mock-op-beeld); color: var(--mock-op-kleur); font-weight: 600; font-size: var(--text-sm); text-align: center;
  opacity: 0; pointer-events: none; transition: opacity .2s ease;
}
.geo-gebaar.is-zichtbaar { opacity: 1; }

/* ── Het form-veld ── */
.geo-veld { gap: var(--space-2); }
.geo-zoek { position: relative; }
.geo-zoek-ico { position: absolute; left: var(--space-3); top: 50%; transform: translateY(-50%); display: inline-flex; color: var(--mock-muted); pointer-events: none; }
.geo-zoek-ico svg { width: 16px; height: 16px; }
.geo-zoek-input { width: 100%; padding-left: calc(var(--space-3) + 22px); }
.geo-zoek-input { padding-right: 44px; }
/* De native webkit-X is blauw en niet te stylen; we hebben een eigen wis-knop. */
.geo-zoek-input::-webkit-search-cancel-button, .geo-zoek-input::-webkit-search-decoration { -webkit-appearance: none; appearance: none; display: none; }
.geo-zoek-wis {
  position: absolute; right: 4px; top: 50%; transform: translateY(-50%); width: 36px; height: 36px;
  display: inline-flex; align-items: center; justify-content: center; padding: 0; border: 0; cursor: pointer;
  border-radius: var(--radius-pill); background: none; color: var(--mock-muted);
}
.geo-zoek-wis:hover { background: var(--color-bg-muted); color: var(--color-text); }
.geo-zoek-wis:focus-visible { outline-offset: 1px; }
.geo-zoek-wis svg { width: 16px; height: 16px; }
.geo-zoek-wis[hidden] { display: none; }
.geo-opties {
  position: absolute; z-index: var(--mock-z-kaart-opties); left: 0; right: 0; top: calc(100% + 4px); margin: 0; padding: var(--space-1);
  list-style: none; max-height: min(50vh, 320px); max-height: min(50svh, 320px); overflow-y: auto; overscroll-behavior: contain;
  background: var(--color-bg-surface); border: 1px solid var(--color-border);
  border-radius: var(--radius-md); box-shadow: var(--shadow-lg);
}
.geo-optie {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-3);
  min-height: 44px; padding: var(--space-2) var(--space-3); border-radius: var(--radius-sm);
  cursor: pointer; font-size: var(--text-sm); color: var(--color-text);
}
.geo-optie:hover, .geo-optie[aria-selected="true"] { background: var(--color-primary-soft); }
.geo-optie[aria-selected="true"] { box-shadow: inset 3px 0 0 var(--color-primary); }
.geo-optie-naam { min-width: 0; overflow-wrap: anywhere; }
.geo-optie-soort { flex: none; font-size: var(--text-xs); color: var(--mock-muted); }
.geo-hint { margin: 0; font-size: var(--text-xs); color: var(--mock-muted); }
.geo-voet { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3); }
.geo-coord-label { font-size: var(--text-xs); font-weight: 600; color: var(--color-text-secondary); }
.geo-coord { flex: 0 1 13.5rem; min-width: 0; font-family: var(--font-mono); font-size: var(--text-xs); font-variant-numeric: tabular-nums; }
.geo-plek { flex: 1 1 12rem; min-width: 0; font-size: var(--text-xs); color: var(--mock-muted); overflow-wrap: anywhere; }
.geo-plek:empty { display: none; }
.geo-mijn { margin-left: auto; }
.geo-mijn[aria-busy="true"] { opacity: .6; cursor: progress; }
.geo-status { margin: 0; font-size: var(--text-xs); color: var(--color-text-secondary); min-height: 1em; }
.geo-status:empty { min-height: 0; }
@media (pointer: coarse) { .geo-mijn { min-height: 44px; } }

/* De kiespin: een druppel in de merkkleur, 44×44 tikdoel, de punt op de plek. */
.geo-kiespin-host { background: none; border: 0; }
.geo-kiespin {
  position: absolute; left: 50%; top: 4px; width: 28px; height: 28px; margin-left: -14px; box-sizing: border-box;
  border-radius: 50% 50% 50% 0; transform: rotate(-45deg);
  background: var(--color-primary); border: 3px solid var(--color-bg-surface);
  box-shadow: var(--shadow-md);
}
.geo-kiespin::after { content: ""; position: absolute; inset: 6px; border-radius: 50%; background: var(--color-bg-surface); }
.leaflet-dragging .geo-kiespin { box-shadow: var(--shadow-lg); }

/* ── De lijst met kaart ── */
.geo-lijst { display: grid; gap: var(--space-4); }
.geo-lijst-kaart { display: flex; flex-direction: column; gap: var(--space-2); min-width: 0; }
.geo-lijst-tabel { min-width: 0; }
.geo-lijst .geo-kolom-weg { display: none; }
.geo-noot { margin: 0; font-size: var(--text-xs); color: var(--mock-muted); }
.geo-legenda { display: flex; flex-wrap: wrap; gap: var(--space-1) var(--space-3); margin: 0; padding: 0; list-style: none; font-size: var(--text-xs); color: var(--color-text-secondary); }
.geo-legenda li { display: inline-flex; align-items: center; gap: 6px; }
.geo-stip { width: 10px; height: 10px; border-radius: 50%; background: var(--mock-geo-tint); }
@media (min-width: 60rem) {
  .geo-lijst { grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr); align-items: start; }
  .geo-lijst-kaart { order: 2; position: sticky; top: var(--space-4); }
  .geo-kaart-lijst { height: min(70vh, 620px); }
}
.data-table tbody tr.is-geo-actief { background: var(--color-primary-soft); }
.data-table tbody tr.is-geo-actief .cell-primary { box-shadow: inset 3px 0 0 var(--color-primary); }
@media (max-width: 48rem) {
  .data-table tbody tr.is-geo-actief { border-color: var(--color-primary); }
  .data-table tbody tr.is-geo-actief .cell-primary { box-shadow: none; }
}
.geo-cel { font-size: var(--text-xs); white-space: nowrap; }
/* Een map-cel: per sleutel een regel, de sleutel als klein opschrift ervoor ("crm: beheerder, lezer"). */
.map-cel { display: inline-flex; flex-direction: column; gap: var(--space-1); }
.map-regel { white-space: nowrap; }
.map-sleutel { font-weight: 600; color: var(--color-text-secondary); margin-right: var(--space-1); }
.map-sleutel::after { content: ':'; }

/* Tinten per soort — vijf tokens die elk DS heeft. `--mock-*` = renderer-intern (buiten het DS-contract). */
.geo-tint-0 { --mock-geo-tint: var(--color-primary); }
.geo-tint-1 { --mock-geo-tint: var(--color-warning); }
.geo-tint-2 { --mock-geo-tint: var(--color-success); }
.geo-tint-3 { --mock-geo-tint: var(--color-primary-bright); }
.geo-tint-4 { --mock-geo-tint: var(--color-text-secondary); }

/* De pin van een rij: een compacte bubbel met de naam, een rand in de tint van z'n soort en een
   punt eronder op de exacte plek. Geen standaard-marker: de plek zelf is de inhoud. */
.geo-pin-host { background: none; border: 0; overflow: visible; }
.geo-pin-host:focus { outline: 2px solid transparent; }
.geo-pin {
  position: absolute; left: 0; top: 0; transform: translate(-50%, calc(-100% - 9px));
  display: inline-flex; align-items: center; min-height: 32px; max-width: 12rem; padding: 0 var(--space-3);
  background: var(--color-bg-surface); color: var(--color-text-heading);
  border: 2px solid var(--mock-geo-tint); border-radius: var(--radius-pill);
  box-shadow: var(--shadow-md);
  font: 700 var(--text-xs)/1.1 var(--font-heading); white-space: nowrap; cursor: pointer;
  transition: transform .15s ease, box-shadow .15s ease;
}
/* Onzichtbare rand: het tikdoel is groter dan wat je ziet. */
.geo-pin::before { content: ""; position: absolute; inset: -6px; }
/* Het puntje onder de bubbel + de stip op de plek. */
.geo-pin::after {
  content: ""; position: absolute; left: 50%; bottom: -9px; width: 10px; height: 10px; margin-left: -5px;
  border-radius: 50%; background: var(--mock-geo-tint); border: 2px solid var(--color-bg-surface);
  box-shadow: 0 1px 3px rgba(0,0,0,.3);
}
.geo-pin-label { overflow: hidden; text-overflow: ellipsis; }
.geo-pin-host.is-actief .geo-pin, .geo-pin-host:hover .geo-pin, .geo-pin-host:focus-visible .geo-pin {
  transform: translate(-50%, calc(-100% - 9px)) scale(1.08);
  background: var(--mock-geo-tint); color: var(--color-text-on-primary); box-shadow: var(--shadow-lg);
}
.geo-pin-host:focus-visible .geo-pin { outline: var(--focus-ring); outline-offset: 2px; }
/* Veel pinnen: alleen de stip; het label komt bij aanwijzen/focus/actief. */
.geo-pin.is-compact { min-height: 0; padding: 0; border: 0; background: none; box-shadow: none; transform: translate(-50%, -50%); }
.geo-pin.is-compact .geo-pin-label { display: none; }
.geo-pin.is-compact::after { position: static; display: block; width: 16px; height: 16px; margin: 0; }
.geo-pin.is-compact::before { inset: -14px; }
.geo-pin-host.is-actief .geo-pin.is-compact, .geo-pin-host:hover .geo-pin.is-compact, .geo-pin-host:focus-visible .geo-pin.is-compact {
  min-height: 32px; padding: 0 var(--space-3); border: 2px solid var(--mock-geo-tint); transform: translate(-50%, calc(-100% - 9px));
}
.geo-pin-host.is-actief .geo-pin.is-compact .geo-pin-label, .geo-pin-host:hover .geo-pin.is-compact .geo-pin-label,
.geo-pin-host:focus-visible .geo-pin.is-compact .geo-pin-label { display: inline; }
.geo-pin-host.is-actief .geo-pin.is-compact::after, .geo-pin-host:hover .geo-pin.is-compact::after,
.geo-pin-host:focus-visible .geo-pin.is-compact::after { position: absolute; width: 10px; height: 10px; margin-left: -5px; }
@media (prefers-reduced-motion: reduce) { .geo-pin { transition: none; } }

/* De popup: een kaartje in het DS, niet Leaflet's standaardballon. */
.geo-popup-host .leaflet-popup-content-wrapper {
  padding: 0; overflow: hidden; border-radius: var(--radius-lg);
  background: var(--color-bg-surface); color: var(--color-text); box-shadow: var(--shadow-lg);
}
.geo-popup-host .leaflet-popup-tip { background: var(--color-bg-surface); }
.geo-popup-host .leaflet-popup-content { margin: 0; font-family: inherit; font-size: var(--text-sm); line-height: 1.4; }
.geo-popup-host a.leaflet-popup-close-button { width: 32px; height: 32px; font-size: 1.375rem; line-height: 30px; color: var(--color-text-secondary); }
.geo-popup { display: flex; flex-direction: column; gap: var(--space-2); padding: var(--space-4); }
.geo-popup-foto { display: block; width: calc(100% + 2 * var(--space-4)); max-width: none; height: 132px; object-fit: cover; margin: calc(-1 * var(--space-4)) calc(-1 * var(--space-4)) 0; }
.geo-popup-titel { margin: 0; padding-right: var(--space-6); font: 700 var(--text-base)/1.25 var(--font-heading); color: var(--color-text-heading); }
.geo-popup-velden { display: grid; gap: 2px; margin: 0; font-size: var(--text-xs); }
.geo-popup-velden > div { display: flex; gap: var(--space-2); }
.geo-popup-velden dt { flex: none; min-width: 5.5rem; color: var(--mock-muted); }
.geo-popup-velden dd { margin: 0; min-width: 0; overflow-wrap: anywhere; color: var(--color-text); }
.geo-popup-meer { align-self: flex-start; margin-top: var(--space-1); }
@media (max-width: 48rem) { .geo-popup-foto { height: 88px; } }
/* Smal scherm: het kaartje van een pin onder de kaart, op volle breedte (de ballon paste er niet op). */
.geo-kaartje {
  position: relative; margin-top: var(--space-3); overflow: hidden;
  border: 1px solid var(--color-border); border-radius: var(--radius-lg);
  background: var(--color-bg-surface); color: var(--color-text); box-shadow: var(--shadow-md);
  font-size: var(--text-sm); line-height: 1.4;
}
.geo-kaartje[hidden] { display: none; }
.geo-kaartje-sluit {
  position: absolute; top: 4px; right: 4px; z-index: 1; width: 44px; height: 44px;
  border: 0; background: none; cursor: pointer; font: 1.5rem/1 system-ui, sans-serif; color: var(--color-text-secondary);
}
.geo-kaartje .geo-popup-titel { padding-right: 44px; }
@media (pointer: coarse) { .geo-popup-meer { min-height: 44px; } }

/* Foto-miniatuur in een cel (IMAGE-kolom). */
.cel-thumb { display: block; width: 40px; height: 40px; object-fit: cover; border-radius: var(--radius-sm); background: var(--color-bg-muted); }
.cel-thumbs { display: inline-flex; align-items: center; gap: 6px; }
.cel-thumb-meer { font-size: var(--text-xs); color: var(--mock-muted); }
.detail-row dd .cel-thumb { width: 96px; height: 72px; }


/* ══════════════════════════════════════════════════════════════════════════
   FOTO'S, ENUM-CHIPS, LEGE BEELDEN (gedrag in app.js, blokken FOTO'S / Beelden / Enums)
   ══════════════════════════════════════════════════════════════════════════ */
/* Een lege beeldplek: een rustige tegel met een beeld-icoon — nooit een bestandsnaam. */
.beeld-leeg {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  background: repeating-linear-gradient(135deg, var(--color-bg-muted) 0 8px, var(--color-bg-subtle) 8px 16px);
  color: var(--mock-muted); border: 1px solid var(--color-border-subtle);
}
.beeld-leeg svg { width: 45%; height: 45%; max-width: 28px; max-height: 28px; opacity: .7; }
.geo-popup-foto.beeld-leeg { display: flex; height: 56px; }
.detail-foto.beeld-leeg { width: 96px; height: 72px; border-radius: var(--radius-md); }
.detail-fotos { display: flex; flex-wrap: wrap; gap: var(--space-2); justify-content: flex-end; }
.detail-fotos .detail-foto { width: 96px; height: 72px; object-fit: cover; border-radius: var(--radius-md); background: var(--color-bg-muted); }
.detail-fotos .detail-foto:first-child:not(:only-child) { width: 100%; height: auto; aspect-ratio: 16 / 9; }

/* Enum-lijst als chips; de stip draagt de kleur van de waarde (`--cat-<code>` of de rotatie). */
.cat-chips { display: inline-flex; flex-wrap: wrap; gap: 4px; justify-content: inherit; }
.cat-chip {
  display: inline-flex; align-items: center; gap: 6px; padding: 2px 10px 2px 8px; white-space: nowrap;
  border-radius: var(--radius-pill); border: 1px solid var(--color-border);
  background: var(--color-bg-surface); color: var(--color-text);
  font-size: var(--text-xs); font-weight: 600; line-height: 1.5;
}
.cat-chip::before { content: ""; width: 8px; height: 8px; border-radius: 50%; background: var(--mock-geo-tint); }

/* Foto-cel in de tabel: een vierkante duimnagel, de kolom zo smal als de foto. */
.data-table td.cell-image { width: 1%; padding-top: var(--space-2); padding-bottom: var(--space-2); }
.data-table td.cell-image .cel-thumb { width: 48px; height: 48px; }
@media (max-width: 48rem) {
  /* Op een telefoon is de foto de kop-afbeelding van het kaartje, bovenaan en van rand tot rand. */
  .data-table tbody tr:has(> td.cell-image) { display: flex; flex-direction: column; overflow: hidden; padding-top: 0; }
  .data-table tbody td.cell-image {
    order: -1; display: block; width: auto; padding: 0; border-bottom: 0;
    margin: 0 calc(-1 * var(--space-4)) var(--space-1);
  }
  .data-table tbody td.cell-image::before { content: none; }
  .data-table tbody td.cell-image .cel-thumb, .data-table tbody td.cell-image .cel-thumbs {
    display: flex; width: 100%; height: auto; aspect-ratio: 16 / 9; border-radius: 0; object-fit: cover; border: 0;
  }
  .data-table tbody td.cell-image .cel-thumbs { position: relative; }
  .data-table tbody td.cell-image .cel-thumbs .cel-thumb { width: 100%; height: 100%; aspect-ratio: auto; }
  .data-table tbody td.cell-image .cel-thumb-meer {
    position: absolute; right: var(--space-3); bottom: var(--space-3); padding: 2px 8px;
    border-radius: var(--radius-pill); background: var(--mock-op-beeld); color: var(--mock-op-kleur); font-weight: 600;
  }
  /* Een lege foto is op een kaartje een smalle band, geen halve scherm-hoogte grijs. */
  .data-table tbody td.cell-image .beeld-leeg { aspect-ratio: auto; height: 56px; border: 0; }
  .data-table tbody td .cat-chips { justify-content: flex-end; }
}

/* ── Het foto-veld ── */
.foto-hint { margin: 0; font-size: var(--text-xs); color: var(--mock-muted); }
.foto-invoer { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.foto-tegels {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); gap: var(--space-2);
  margin: 0; padding: 0; list-style: none; border-radius: var(--radius-lg);
}
.foto-tegels.is-doel { outline: 2px dashed var(--color-primary); outline-offset: 4px; }
.foto-tegel {
  position: relative; aspect-ratio: 1; overflow: hidden; border-radius: var(--radius-md);
  background: var(--color-bg-muted); border: 1px solid var(--color-border);
}
.foto-tegels.is-multi .foto-tegel.is-omslag { grid-column: span 2; grid-row: span 2; }
.foto-tegel img { display: block; width: 100%; height: 100%; object-fit: cover; }
.foto-tegel[draggable="true"] { cursor: grab; }
.foto-tegel.is-slepend { opacity: .45; }
.foto-tegel.is-doel { outline: 3px solid var(--color-primary); outline-offset: -3px; }
.foto-omslag {
  position: absolute; left: var(--space-2); top: var(--space-2); padding: 2px 8px;
  border-radius: var(--radius-pill); background: var(--color-primary); color: var(--color-text-on-primary);
  font-size: var(--text-xs); font-weight: 700; letter-spacing: .02em;
}
.foto-knop {
  display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; padding: 0;
  border: 0; border-radius: var(--radius-pill); cursor: pointer;
  background: var(--mock-op-beeld); color: var(--mock-op-kleur); -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px);
}
.foto-knop svg { width: 16px; height: 16px; }
.foto-knop:hover { background: var(--mock-op-beeld-sterk); }
.foto-knop:focus-visible { outline-offset: 1px; }
.foto-knop:disabled { opacity: .35; cursor: default; }
.foto-knop::before { content: ""; position: absolute; inset: -6px; }
.foto-knop { position: relative; }
.foto-weg { position: absolute; right: 6px; top: 6px; }
.foto-volgorde { position: absolute; left: 6px; right: 6px; bottom: 6px; display: flex; justify-content: space-between; }
.foto-tegel.is-bezig { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--space-2);
  font-size: var(--text-xs); color: var(--color-text-secondary); }
.foto-spinner { width: 22px; height: 22px; border-radius: 50%; border: 3px solid var(--color-border); border-top-color: var(--color-primary); animation: foto-draai .8s linear infinite; }
@keyframes foto-draai { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .foto-spinner { animation-duration: 2.4s; } }
.foto-plus { border-style: dashed; background: var(--color-bg-surface); }
.foto-toevoegen {
  width: 100%; height: 100%; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px;
  padding: var(--space-2); border: 0; background: none; cursor: pointer; font: inherit;
  font-size: var(--text-xs); font-weight: 600; color: var(--mock-primary-ink); text-align: center;
}
.foto-toevoegen:hover { background: var(--color-primary-soft); }
.foto-toevoegen:focus-visible { outline-offset: -3px; }
.foto-toevoegen[aria-invalid="true"] { box-shadow: inset 0 0 0 2px var(--color-error); }
.foto-toevoegen-ico svg { width: 28px; height: 28px; }
.foto-status { margin: 0; font-size: var(--text-xs); color: var(--color-text-secondary); }
.foto-status:empty { display: none; }

/* Ronde 2 (09-30), mobiel-polish rond kaart, foto's en de lade. */
.geo-lijst { margin-top: var(--space-3); }
/* In de lade IS de lade de kaart — een formulier-kaart daarbinnen is kaart-in-kaart en kost op een
   telefoon twee keer de binnenmarge (zelfde regel als `.inline-form .form-wrapper`). */
.drawer .form-wrapper { border: 0; box-shadow: none; background: none; padding: 0; }
@media (max-width: 48rem) {
  .drawer-body { padding: var(--space-4); }
  .drawer-foot { padding-bottom: max(var(--space-4), env(safe-area-inset-bottom)); }
  .geo-pin { max-width: 9.5rem; }
}
@media (max-width: 48rem) {
  /* Naast een kaart zegt een coördinaat op een kaartje niets wat de pin niet beter zegt. */
  .geo-lijst .data-table tbody td:has(> .geo-cel) { display: none; }
}

/* ── Foto-upload (app): voortgang en fout op de tegel ─────────────────────────────────────
   In de gegenereerde app gaat elke foto meteen naar `POST /upload`; zolang dat loopt of mislukt
   staat hij als tegel met een balk of een melding + "Opnieuw" (app.js, renderFotoVeld → stuur). */
.foto-tegel.is-upload img { opacity: .6; }
.foto-voortgang { position: absolute; left: 8px; right: 8px; bottom: 8px; height: 6px; border-radius: 3px;
  background: var(--color-bg-surface); background: color-mix(in srgb, var(--color-bg-surface) 80%, transparent); overflow: hidden; }
.foto-voortgang > span { display: block; height: 100%; width: 0; background: var(--color-primary); transition: width .2s ease; }
.foto-tegel.is-fout { outline: 2px solid var(--color-error); outline-offset: -2px; }
.foto-uploadfout { position: absolute; inset: auto 6px 6px 6px; display: flex; flex-direction: column; gap: 4px;
  padding: 6px; border-radius: var(--radius-sm); font-size: var(--text-xs); line-height: 1.3;
  background: var(--color-bg-surface); color: var(--color-error); }
@media (prefers-reduced-motion: reduce) { .foto-voortgang > span { transition: none; } }

/* ── KAART-LIJST: naast een kaart is de lijst een medialijst ──────────────────────────────
   Naast de kaart is er de ruimte niet voor een tabel: een foto-, naam-, sporten- en ondergrond-
   kolom in een halve breedte gaf een horizontale scrollbalk, en informatie achter een scroll is
   informatie die je niet ziet (gebruiker, 30-09). Dus op élke breedte: per plek één regel met
   een vierkante foto links en daarnaast naam, chips en de rest — zoals je het van een
   kaart-app kent. De thead blijft voor schermlezers in de DOM.
   Alles hangt onder `.geo-lijst .geo-lijst-tabel`: de mobiele kaartjes-regels hierboven
   (`.data-table tbody tr:has(> td.cell-image)`) wegen anders zwaarder en winnen. */
.geo-lijst .geo-lijst-tabel .table-wrap { overflow: visible; border: 0; background: none; box-shadow: none; border-radius: 0; }
.geo-lijst .geo-lijst-tabel .data-table { display: block; width: 100%; border: 0; background: none; }
.geo-lijst .geo-lijst-tabel .data-table thead {
  position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}
.geo-lijst .geo-lijst-tabel .data-table tbody { display: flex; flex-direction: column; gap: var(--space-2); }
.geo-lijst .geo-lijst-tabel .data-table tbody tr {
  display: grid; grid-template-columns: minmax(0, 1fr); column-gap: var(--space-4); row-gap: 4px;
  align-content: start; margin: 0; padding: var(--space-3);
  background: var(--color-bg-surface); border: 1px solid var(--color-border-subtle);
  border-radius: var(--radius-lg); box-shadow: none; overflow: visible;
  transition: border-color .15s, box-shadow .15s;
}
.geo-lijst .geo-lijst-tabel .data-table tbody tr:has(> td.cell-image) { grid-template-columns: 72px minmax(0, 1fr); }
.geo-lijst .geo-lijst-tabel .data-table tbody tr.row-clickable { cursor: pointer; }
.geo-lijst .geo-lijst-tabel .data-table tbody tr.row-clickable:hover,
.geo-lijst .geo-lijst-tabel .data-table tbody tr.is-geo-actief { border-color: var(--color-primary); box-shadow: var(--shadow-sm); }
.geo-lijst .geo-lijst-tabel .data-table tbody td {
  display: block; grid-column: -2; width: auto; min-width: 0; margin: 0; padding: 0; border: 0;
  text-align: left; white-space: normal; overflow-wrap: anywhere; background: none;
  font-size: var(--text-sm); color: var(--color-text-secondary);
}
.geo-lijst .geo-lijst-tabel .data-table tbody td::before {
  content: attr(data-label) " "; display: inline; margin: 0; font-size: inherit; font-weight: 600;
  letter-spacing: 0; text-transform: none; color: var(--color-text-muted);
}
.geo-lijst .geo-lijst-tabel .data-table tbody td.cell-image,
.geo-lijst .geo-lijst-tabel .data-table tbody td.cell-actions,
.geo-lijst .geo-lijst-tabel .data-table tbody td:has(.cat-chips) { font-size: inherit; }
.geo-lijst .geo-lijst-tabel .data-table tbody td.cell-primary::before,
.geo-lijst .geo-lijst-tabel .data-table tbody td.cell-image::before,
.geo-lijst .geo-lijst-tabel .data-table tbody td.cell-actions::before,
.geo-lijst .geo-lijst-tabel .data-table tbody td:has(.cat-chips)::before { content: none; }
.geo-lijst .geo-lijst-tabel .data-table tbody td.cell-primary {
  font-size: var(--text-base); font-weight: 650; line-height: var(--leading-snug);
  color: var(--color-text-heading);
}
.geo-lijst .geo-lijst-tabel .data-table tbody td .cat-chips { justify-content: flex-start; }
.geo-lijst .geo-lijst-tabel .data-table tbody td.cell-image { grid-column: 1; grid-row: 1 / span 4; align-self: start; order: 0; }
.geo-lijst .geo-lijst-tabel .data-table tbody td.cell-image .cel-thumb,
.geo-lijst .geo-lijst-tabel .data-table tbody td.cell-image .cel-thumbs,
.geo-lijst .geo-lijst-tabel .data-table tbody td.cell-image .beeld-leeg {
  position: relative; width: 72px; height: 72px; aspect-ratio: 1; margin: 0;
  border-radius: var(--radius-md); object-fit: cover; overflow: hidden; border: 0;
}
.geo-lijst .geo-lijst-tabel .data-table tbody td.cell-image .cel-thumb,
.geo-lijst .geo-lijst-tabel .data-table tbody td.cell-image .cel-thumbs { display: block; }
.geo-lijst .geo-lijst-tabel .data-table tbody td.cell-image .cel-thumbs .cel-thumb { width: 100%; height: 100%; border-radius: 0; }
.geo-lijst .geo-lijst-tabel .data-table tbody td.cell-image .cel-thumb-meer {
  position: absolute; right: 4px; bottom: 4px; padding: 0 6px; font-size: var(--text-xs); font-weight: 700;
  border-radius: var(--radius-pill); background: var(--mock-op-beeld); color: var(--mock-op-kleur);
}
/* De coördinatenkolom naast de kaart (renderKaartLijst zet `geo-kolom-weg`) — zwaarder dan de
   td-regel hierboven, anders toont die 'm weer. */
.geo-lijst .geo-lijst-tabel .data-table tr > .geo-kolom-weg { display: none; }
.geo-lijst .geo-lijst-tabel .data-table tbody td.cell-image .beeld-leeg { display: grid; place-items: center; }

/* ══ QUERY — de filterbalk uit het model (gedrag in app.js, blok QUERY) ══════════════════════════
   Een lijst die haar readmodel bevraagt: chips (enum), een segment (vaste keuzes), een zoekveld
   (zoektIn) en de locatie-knoppen. Mobiel eerst: één horizontaal scrollbare rij die onder de kop
   blijft plakken terwijl je door kaart en lijst scrollt; elk doel minstens 44px hoog.
   Alleen tokens die de renderer al leest (plus eigen --mock-*): een design-systeem hoeft voor
   filters niets nieuws te leveren. ─────────────────────────────────────────────────────────── */
.q-plakt {
  position: sticky; top: var(--mock-kop-hoogte); z-index: var(--mock-z-plakt);
  background: var(--color-bg);
}
.toolbar.q-plakt { padding-top: var(--space-2); padding-bottom: var(--space-2); }
.toolbar > .q-balk { flex: 1 1 100%; min-width: 0; margin-bottom: 0; }
.q-balk {
  display: flex; flex-direction: column; gap: var(--space-2);
  padding: var(--space-2) 0; margin-bottom: var(--space-3); min-width: 0;
}
.q-rij {
  display: flex; align-items: center; gap: var(--space-3);
  overflow-x: auto; overscroll-behavior-x: contain; scrollbar-width: none;
  /* Ruimte voor de focusring: een scrollende rij knipt anders de buitenkant van de ring af. */
  padding: 4px; margin: -4px;
}
.q-rij::-webkit-scrollbar { display: none; }
/* Er staat nog meer rechts: de rand vervaagt tot je aan het eind bent (app.js zet `is-eind`). */
.q-rij:not(.is-eind) { -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 2rem), transparent); mask-image: linear-gradient(to right, #000 calc(100% - 2rem), transparent); }
.q-groep { display: flex; align-items: center; gap: var(--space-2); flex: none; margin: 0; }
.q-groep + .q-groep { padding-left: var(--space-3); border-left: 1px solid var(--color-border-subtle); }
/* De locatie-regel scrollt niet en vervaagt niet: twee knoppen passen altijd. */
.q-rij-locatie { overflow: visible; }
.q-rij-locatie:not(.is-eind) { -webkit-mask-image: none; mask-image: none; }
.q-label {
  font-size: var(--text-xs); font-weight: 700; letter-spacing: .02em; text-transform: uppercase;
  color: var(--color-text-muted); white-space: nowrap;
}
.q-chips { flex-wrap: nowrap; }
.q-balk .chip { min-height: 44px; white-space: nowrap; display: inline-flex; align-items: center; gap: 6px; }
.q-balk .chip[aria-busy="true"] { opacity: .7; cursor: progress; }
.q-ico { display: inline-flex; }
.q-ico svg { width: 16px; height: 16px; }
.q-segment {
  display: inline-flex; gap: 2px; padding: 2px;
  background: var(--color-bg-muted); border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
}
.q-seg {
  min-height: 44px; min-width: 44px; padding: 0 var(--space-3);
  border: 0; border-radius: var(--radius-pill); background: none; cursor: pointer;
  font: inherit; font-size: var(--text-sm); font-weight: 600; white-space: nowrap;
  color: var(--color-text-secondary); font-variant-numeric: tabular-nums;
}
.q-seg:hover { color: var(--color-text); }
.q-seg.is-active {
  background: var(--color-bg-surface); color: var(--mock-primary-ink);
  box-shadow: var(--shadow-sm);
}
.q-zoek { flex: 0 1 16rem; min-width: 12rem; min-height: 44px; }
.q-keuze { min-height: 44px; width: auto; }
.q-sub { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-3); }
.q-adres { flex: 1 1 100%; max-width: 32rem; }
.q-adres .geo-zoek-input { min-height: 44px; }
.q-noot { margin: 0; flex: 1 1 16rem; font-size: var(--text-xs); color: var(--mock-muted); }
.q-noot.is-let-op { color: var(--color-text-secondary); font-weight: 600; }
.q-status:empty { display: none; }
.q-telling {
  margin: 0 0 0 auto; font-size: var(--text-sm); font-weight: 600; white-space: nowrap;
  color: var(--color-text-secondary); font-variant-numeric: tabular-nums;
}
/* De afstand bij de naam ("0,2 km"): het antwoord op de vraag waarom deze plek hier staat. */
.q-berekend {
  display: inline-block; margin-left: var(--space-2);
  font-size: var(--text-sm); font-weight: 600; white-space: nowrap;
  color: var(--mock-primary-ink); font-variant-numeric: tabular-nums;
}
.q-berekend-cel { white-space: nowrap; color: var(--mock-primary-ink); font-weight: 600; }
/* De straal op de kaart: een rustig vlak met een stippelrand, en "hier ben jij" in het midden. */
.q-straal {
  fill: var(--color-primary); fill-opacity: .08;
  stroke: var(--color-primary); stroke-opacity: .55; stroke-width: 2; stroke-dasharray: 6 6;
}
.q-hier-host { background: none; border: 0; }
.q-hier {
  display: block; width: 22px; height: 22px; border-radius: 50%;
  background: var(--color-primary); border: 3px solid var(--color-bg-surface);
  box-shadow: 0 0 0 6px var(--color-primary-glow), var(--shadow-md);
}
/* Breed genoeg: de filters mogen afbreken in plaats van te scrollen. */
@media (min-width: 60rem) {
  .q-rij { flex-wrap: wrap; overflow: visible; }
  .q-rij:not(.is-eind) { -webkit-mask-image: none; mask-image: none; }
  /* Afgebroken regels beginnen anders met een scheidingslijn. */
  .q-groep + .q-groep { padding-left: 0; border-left: 0; }
}

/* Een straal zonder positie: zichtbaar, maar uit (de query filtert dan niet op afstand). */
.q-groep.is-uit { opacity: .45; }
.q-groep.is-uit .q-seg.is-active { background: transparent; box-shadow: none; }

/* "Filters wissen": een stille tekstknop naast de telling. */
.q-wis {
  border: 0; background: none; padding: 0 var(--space-1); min-height: 44px; cursor: pointer;
  font: inherit; font-size: var(--text-sm); font-weight: 600; color: var(--mock-primary-ink);
  text-decoration: underline; text-underline-offset: 2px;
}
/* Het beheer (pagina's onder /admin) is altijd donker; de dag/nacht-keuze geldt in de app. */
.beheer-schil .theme-toggle { display: none; }

/* ── Een knop per item (ScreenButton.perItemVan): chips in een lijst-cel ─────────────────── */
.item-chips { display: flex; flex-wrap: wrap; gap: var(--space-1); }
.item-chip {
  display: inline-flex; align-items: center; gap: 4px; min-height: 28px;
  padding: 2px var(--space-2); border-radius: var(--radius-pill);
  font: inherit; font-size: var(--text-xs); cursor: pointer;
  border: 1px solid var(--color-border); background: var(--color-bg-surface); color: var(--color-text);
  transition: background .15s ease, border-color .15s ease;
}
.item-chip:hover { background: var(--color-bg-surface-hover); border-color: var(--color-border-strong); }
.item-chip.is-weg { background: var(--color-primary-soft); border-color: transparent; }
.item-chip.is-weg:hover { background: var(--color-danger-soft); color: var(--color-danger); }
.item-chip.is-erbij { border-style: dashed; color: var(--color-text-secondary); }
.item-chip.is-erbij:hover { border-style: solid; color: var(--mock-primary-ink); }
.item-chip-teken { font-weight: 700; line-height: 1; }

/* De kop van een DETAIL_LIST-niveau: de velden van de aangeklikte ouder, boven de tabel. */
.detail-list.drill-kop { display: grid; grid-template-columns: max-content 1fr; gap: var(--space-1) var(--space-6);
  margin: 0 0 var(--space-4); font-size: var(--text-sm); }
.detail-list.drill-kop dt { color: var(--color-text-muted); }
.detail-list.drill-kop dd { margin: 0; color: var(--color-text-heading); font-weight: 500; }


/* ══════════════════════════════════════════════════════════════════════════
   UX-ronde 08-10 (journey-review buurtsporten): generieke renderer-defaults
   ══════════════════════════════════════════════════════════════════════════ */
/* Een datum is tekst om te lezen ("do 9 okt · 19:00"), geen code: de letter van de pagina, wel
   cijfers van gelijke breedte zodat tijden onder elkaar lijnen (P14). */
time.datum { font-family: inherit; font-variant-numeric: tabular-nums; }

/* Een pin met meer rijen op één plek: de popup noemt ze allemaal (P22). */
.geo-pin-aantal { flex: none; display: inline-grid; place-items: center; min-width: 1.25rem; height: 1.25rem;
  margin-left: var(--space-2); margin-right: calc(-1 * var(--space-1)); padding: 0 4px; border-radius: 999px;
  background: var(--mock-geo-tint); color: var(--color-text-on-primary); font-size: .6875rem; }
.geo-pin.is-compact .geo-pin-aantal { display: none; }
.geo-popup-lijst { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-1); }
.geo-popup-lijst .geo-popup-meer { width: 100%; justify-content: flex-start; text-align: left; margin-top: 0; }

/* Breed: het menu blijft de tabrij; icoon, "Meer", avatar en menukop zijn er alleen op de telefoon. */
.ht-icoon, .hub-meer, .persona-avatar, .account-menu-kop { display: none; }
.account-menu-kop { flex-direction: column; gap: 2px; padding: var(--space-2) var(--space-3);
  border-bottom: 1px solid var(--color-border); margin-bottom: var(--space-1); }
.account-menu-naam { font-weight: 600; color: var(--color-text-heading); overflow-wrap: anywhere; }
.account-menu-rol { font-size: var(--text-xs); color: var(--color-text-secondary); }

@media (max-width: 48rem) {
  /* ── Het hoofdmenu als onderbalk (P7) ── */
  .hub-nav.is-onderbalk {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: var(--mock-z-onderbalk); max-width: none; margin: 0;
    display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: 0;
    padding: 0 0 env(safe-area-inset-bottom); overflow: visible; scroll-snap-type: none;
    background: var(--color-bg-surface); border-top: 1px solid var(--color-border);
    box-shadow: 0 -2px 10px rgba(16, 24, 40, .06);
    -webkit-mask-image: none; mask-image: none;
  }
  .hub-nav.is-onderbalk.heeft-meer { right: 20%; }
  .hub-nav.is-onderbalk .hub-tab, .hub-meer-knop {
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
    min-width: 0; min-height: 56px; padding: 6px 2px; margin: 0;
    font-family: inherit; font-size: var(--mock-text-2xs); font-weight: 600; line-height: 1.15; text-align: center; white-space: normal; text-decoration: none;
    color: var(--color-text-secondary); background: none; border: 0;
    border-top: 2px solid transparent; border-bottom: 0; cursor: pointer;
  }
  .hub-nav.is-onderbalk .ht-label, .hub-meer-knop .ht-label {
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
    max-width: 100%; overflow-wrap: anywhere;
  }
  .hub-nav.is-onderbalk .ht-icoon, .hub-meer-knop .ht-icoon { display: inline-flex; width: 22px; height: 22px; }
  .ht-icoon svg { width: 100%; height: 100%; }
  .hub-nav.is-onderbalk .hub-tab[aria-current], .hub-meer.is-actief .hub-meer-knop {
    color: var(--mock-primary-ink); border-top-color: var(--color-primary);
  }
  .hub-nav.is-onderbalk .hub-indicator, .hub-nav.is-onderbalk .hub-tab.is-over { display: none; }
  .hub-meer { display: block; position: fixed; right: 0; bottom: 0; width: 20%; z-index: var(--mock-z-onderbalk);
    padding-bottom: env(safe-area-inset-bottom); background: var(--color-bg-surface);
    border-top: 1px solid var(--color-border); }
  .hub-meer-knop { width: 100%; }
  .hub-meer-lijst { position: absolute; right: var(--space-2); bottom: calc(100% + var(--space-2));
    min-width: 12rem; max-width: calc(100vw - 1rem); padding: var(--space-1); display: flex; flex-direction: column;
    background: var(--color-bg-surface); border: 1px solid var(--color-border);
    border-radius: var(--radius-md); box-shadow: var(--shadow-md); }
  .hub-meer-lijst[hidden] { display: none; }
  .hub-meer-item { display: flex; align-items: center; gap: var(--space-3); min-height: 44px;
    padding: var(--space-2) var(--space-3); border: 0; border-radius: var(--radius-sm);
    background: none; font-family: inherit; font-size: var(--text-sm); font-weight: 500; color: var(--color-text);
    text-align: left; text-decoration: none; cursor: pointer; }
  .hub-meer-item .ht-icoon { display: inline-flex; width: 20px; height: 20px; }
  .hub-meer-item:hover, .hub-meer-item:focus-visible { background: var(--color-bg-surface-hover); }
  /* De inhoud houdt z'n onderkant vrij van de balk; toasts staan erboven. */
  body.heeft-onderbalk { padding-bottom: calc(57px + env(safe-area-inset-bottom)); }
  body.heeft-onderbalk .toast-stack { bottom: calc(57px + var(--space-4) + env(safe-area-inset-bottom)); }

  /* ── Het accountmenu als rondje (P7) ── */
  .persona-bar { flex: 0 0 auto; margin-left: auto; }
  .account-menu-knop { padding: 2px; gap: 0; background: none; }
  .account-menu-knop .persona-dot, .account-menu-knop .persona-label, .account-menu-knop .persona-name,
  .account-menu-knop .persona-roles, .account-menu-knop .account-menu-pijl { display: none; }
  .persona-avatar { display: inline-grid; place-items: center; width: 40px; height: 40px; border-radius: 50%;
    background: var(--color-primary); color: var(--color-text-on-primary);
    font: 700 var(--text-sm)/1 var(--font-heading); letter-spacing: .02em; }
  .account-menu-kop { display: flex; }

  /* ── De kaart naast een lijst: lager, zodat het eerste item boven de vouw staat (P22) ── */
  .geo-kaart-lijst { height: clamp(170px, 26vh, 240px); height: clamp(170px, 26svh, 240px); }
}

/* ── Tijdkiezer (P8, 09-10): dagknoppen + tijd per kwartier boven het tekstveld ───────────────── */
.tijdkiezer { display: flex; flex-direction: column; gap: var(--space-2); min-width: 0; }
/* Eén rij die horizontaal schuift: veertien dagen passen niet naast elkaar, en op een telefoon veeg je. */
.tk-dagen {
  display: flex; gap: var(--space-2); overflow-x: auto; scroll-snap-type: x proximity;
  padding-bottom: var(--space-1); scrollbar-width: thin;
}
.tk-dag {
  flex: 0 0 auto; scroll-snap-align: start; min-width: 4.5rem; min-height: 44px;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
  padding: var(--space-2) var(--space-3); border-radius: var(--radius-md); cursor: pointer;
  background: var(--color-bg-surface); color: var(--color-text);
  border: 1px solid var(--color-border); font: inherit; line-height: 1.15;
}
.tk-dag:hover { border-color: var(--color-border-strong); }
.tk-dag:focus-visible { outline-offset: 1px; }
.tk-dag-naam { font-size: var(--text-xs); font-weight: 700; text-transform: lowercase; color: var(--color-text-secondary); }
.tk-dag-datum { font-size: var(--text-sm); font-weight: 600; white-space: nowrap; }
.tk-dag[aria-pressed="true"] { background: var(--color-primary); border-color: var(--color-primary); color: var(--color-text-on-primary); }
.tk-dag[aria-pressed="true"] .tk-dag-naam { color: inherit; }
.tk-onder { display: grid; grid-template-columns: minmax(6.5rem, 8rem) minmax(0, 1fr); gap: var(--space-2); align-items: center; }

