/* styles.css — designsysteem van de ISMS-registratie-app.
   Bron van de tokens: docs/design-tokens.md, gedeeld met de facturatie-app (..\Facturatie\styles.css).
   Eén indigo-accent (--primary), één type-/spacing-/radiusschaal, licht én donker thema.

   Stond eerder als <style> in index.html. Nu een eigen bestand omdat (a) de tokens daarmee één bron
   krijgen die met de facturatie-app te vergelijken is, en (b) de stylesheet dezelfde immutable-cache met
   ?v=<APP_VERSIE> kan krijgen als app/*. Gebruik ALTIJD een token, nooit een losse hex — dat is precies
   waar deze twee apps eerder uit elkaar liepen. */

/* ── tokens ─────────────────────────────────────────────────────────────────────────────────────── */
:root{
  --canvas:#eceef4; --surface:#fff; --surface-2:#f5f6fb; --surface-3:#eef0f7;
  --ink:#14161d; --ink-soft:#3c4150; --muted:#646b7a; --line:#e7e9f1; --line-strong:#d4d8e4;
  --primary:#5b5bd6; --on-primary:#fff; --primary-soft:#ececfa; --primary-strong:#4a4ac4;
  --green:#0f9d6b; --green-soft:#e7f6ef; --on-green-soft:#0a6b49;
  --red:#e0364f; --red-soft:#fdecef; --on-red-soft:#b0142c;
  --amber:#9a5b00; --amber-soft:#fdf1e0; --on-amber-soft:#7c4700;
  --orange-soft:#fbe3d3; --on-orange-soft:#8a3c00;   /* risicoscore 9–14, tussen amber en rood in */
  /* Meldingen: bewust vaste, donkere waarden in BEIDE thema's — zie de toelichting bij .toast. */
  --toast-info:#4a4ac4; --toast-goed:#0a6b49; --toast-fout:#b0142c;
  --shadow-sm:0 1px 2px rgba(18,20,40,.04),0 2px 7px rgba(18,20,40,.05);
  --shadow-md:0 6px 22px rgba(18,20,40,.09);
  --shadow-lg:0 20px 54px rgba(18,20,40,.18);
  --r-lg:16px; --r-md:11px; --r-sm:8px; --r-pill:999px;
  --text-xs:12px; --text-sm:13px; --text-base:14px; --text-lg:16px; --text-xl:20px; --text-2xl:26px;
  --space-1:4px; --space-2:8px; --space-3:12px; --space-4:16px; --space-6:24px;
  color-scheme:light;
}
html[data-theme="dark"]{
  --canvas:#0f1117; --surface:#171a22; --surface-2:#1d212b; --surface-3:#242833;
  --ink:#eceef4; --ink-soft:#c3c8d4; --muted:#98a0b0; --line:#2a2f3b; --line-strong:#39404f;
  --primary:#7b7bea; --primary-soft:#262a44; --primary-strong:#9a9af2;
  --green-soft:#12291f; --on-green-soft:#5ed6a4; --red-soft:#2d1519; --on-red-soft:#ff8fa0;
  --amber-soft:#2c2011; --on-amber-soft:#e0a75c;
  --orange-soft:#33200f; --on-orange-soft:#e8a06a;
  color-scheme:dark;
}
*{box-sizing:border-box}
body{margin:0;font:var(--text-base)/1.45 "Segoe UI",system-ui,sans-serif;background:var(--canvas);color:var(--ink)}
.num,td.num,.mono{font-variant-numeric:tabular-nums}
h2,h3{font-size:var(--text-lg);margin:0 0 var(--space-2)}
h4{font-size:var(--text-base);margin:var(--space-4) 0 var(--space-1)}
.mut{color:var(--muted)}
.mb{margin-bottom:var(--space-2)}
.mt{margin-top:var(--space-3)}
.right{margin-left:auto}
.links{text-align:left}
/* Een lege lijst is een antwoord, geen gat: zonder omhulsel valt "er is niets" weg in de pagina en leest
   het als een laadfout. Gestippelde rand = "hier hóórt inhoud te staan", in tegenstelling tot de doorlopende
   rand van een kaart met inhoud. */
.leeg{padding:22px;text-align:center;color:var(--muted);border:1px dashed var(--line);
  border-radius:var(--r-md);background:var(--surface-2)}
/* `hidden` moet altijd winnen: een eigen `display` (zoals .login) overschrijft anders het
   hidden-attribuut uit de browser-stylesheet, en dan blijft het aanmeldscherm ná aanmelden staan. */
[hidden]{display:none !important}

/* ── toegankelijkheid ───────────────────────────────────────────────────────────────────────────── */
/* Alleen voor schermlezers: labels die op het scherm overbodig zijn maar hardop wél nodig. */
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0,0,0,0);white-space:nowrap;border:0}
/* Overslaan-naar-inhoud: de zijbalk heeft bij 40 registraties tientallen links; zonder deze koppeling
   moet iemand die met het toetsenbord werkt daar elke keer langs. Alleen zichtbaar bij focus. */
.skip-link{position:absolute;left:var(--space-2);top:-40px;z-index:500;background:var(--primary);
  color:var(--on-primary);padding:7px 13px;border-radius:var(--r-sm);text-decoration:none;font-weight:600}
.skip-link:focus{top:var(--space-2)}

/* ── kop ────────────────────────────────────────────────────────────────────────────────────────── */
header{background:var(--surface);border-bottom:1px solid var(--line);padding:var(--space-3) var(--space-4);
  display:flex;gap:var(--space-4);align-items:center;flex-wrap:wrap;box-shadow:var(--shadow-sm)}
header h1{font-size:var(--text-lg);margin:0;font-weight:650;letter-spacing:-.01em}
header .sub{font-size:var(--text-xs);color:var(--muted)}
header .spacer{flex:1}
/* ── merkblok ──
   Bovenin de zijbalk, met de maten van `.brand` in de facturatie-app: logovak van 34px met ronding 9,
   titel 16px/650, ondertitel 10px/500. Stond tot 2.43 in de globale header; daar concurreerde het met de
   identiteit rechtsboven, en had de zijbalk zelf geen kop — die begon meteen met een categoriekopje.
   ⚠ Onder 900px bestaat de zijbalk niet. Het merk moet dan zichtbaar blijven; dat regelt de mediaquery
   verderop door de aside als strook boven de inhoud te tonen. Géén tweede kopie in de DOM, want dan staat
   de <h1> twee keer in de documentstructuur. */
.merk{display:flex;gap:11px;align-items:center;padding:20px 18px 14px}
.merk-vak{width:34px;height:34px;flex:none;border-radius:9px;background:var(--surface);display:grid;
  place-items:center;overflow:hidden;box-shadow:0 4px 12px var(--primary-soft)}
.merk-vak img{width:100%;height:100%;object-fit:contain;padding:2px}
.merk-tekst{min-width:0}
.merk-tekst h1{margin:0;font-size:var(--text-lg);font-weight:650;letter-spacing:-.2px;line-height:1.15}
.merk-tekst p{margin:2px 0 0;color:var(--muted);font-size:10px;font-weight:500;line-height:1.2;
  letter-spacing:.1px}
/* Rechterkant van de kop, gelijk aan `.top-actions` in de facturatie-app: één rij met 10px ertussen,
   in plaats van de 16px die de header zelf hanteert. Zoeken, thema, instellingen, wie u bent en de
   avatar horen bij elkaar en moeten dichter op elkaar staan dan op de rest van de kop. */
.top-acties{display:flex;align-items:center;gap:10px}
/* Vaste bovengrens, zodat een lange naam de knoppen ernaast niet wegduwt. Maten gelijk aan
   `.top-identity` in de facturatie-app: naam 13px/650 met ellips, rol 11.5px in de gedempte kleur. */
.wie{display:flex;flex-direction:column;align-items:flex-end;justify-content:center;
  line-height:1.25;white-space:nowrap;max-width:220px}
.wie b{font-size:var(--text-sm);font-weight:650;max-width:200px;overflow:hidden;text-overflow:ellipsis}
.wie span{display:block;font-size:11.5px;color:var(--muted)}
/* Ronde profielfoto uit Entra, met de initialen als terugval. Dezelfde plek en maten als in de
   facturatie-app (`.top-avatar .avatar`): 34px, rond, 12px initialen, géén rand. */
.avatar{width:34px;height:34px;border-radius:var(--r-pill);background:var(--primary-soft);
  color:var(--primary-strong);display:flex;align-items:center;justify-content:center;font-size:12px;
  font-weight:650;overflow:hidden;flex:none}
.avatar img{width:100%;height:100%;object-fit:cover;display:block}

/* Snelzoeken als pil in plaats van als icoonknop: een vergrootglas alléén wordt gelezen als decoratie,
   dus niemand vond Ctrl+K. De vorm van een zoekveld (rand, ronding, grijze tekst) belooft wat de knop
   doet. Het is bewust géén <input>: er wordt hier niet getypt, dat gebeurt in het zoekvenster zelf.
   Onder 900px valt de header samen met de .regbar-strook en is de ruimte op; daar blijven alleen het
   icoon en de vorm over — de sneltoets bestaat op een aanraakapparaat toch niet. */
button.zoekpil{display:inline-flex;gap:var(--space-2);align-items:center;min-height:36px;padding:5px 11px;
  font-weight:400;
  border:1px solid var(--line-strong);border-radius:var(--r-pill);background:var(--surface);
  color:var(--muted);font-size:var(--text-sm);white-space:nowrap}
button.zoekpil svg{flex:none}
/* 5px heeft geen token: het is de kleinere binnenronding van een label bínnen een pil, niet --r-sm. */
.zoekpil-toets{font-size:11px;border:1px solid var(--line);border-radius:5px;padding:1px 5px;
  color:var(--muted)}
@media (max-width:900px){
  /* De toets is decoratie en mag weg; de tekst "Zoeken" is de toegankelijke naam van de knop en wordt
     daarom wél verborgen maar niet verwijderd — met display:none zou de knop naamloos worden. */
  .zoekpil-toets{display:none}
  .zoekpil-tekst{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);
    white-space:nowrap}
  button.zoekpil{padding:5px 8px}
}

/* Opslagstatus in plaats van een opslaanknop: de app slaat zelf op, dus de vraag is niet "heb ik
   geklikt?" maar "staat het erin, en waar?". */
.syncpil{display:inline-flex;gap:6px;align-items:center;padding:3px 11px;border-radius:var(--r-pill);
  background:var(--green-soft);color:var(--on-green-soft);font-size:var(--text-xs);font-weight:600;
  border:1px solid transparent;white-space:nowrap}
.syncpil .dot{width:7px;height:7px;border-radius:var(--r-pill);background:currentColor;flex:none}
.syncpil.bezig{background:var(--primary-soft);color:var(--primary-strong)}
.syncpil.bezig .dot{animation:pols 1s ease-in-out infinite}
.syncpil.fout{background:var(--red-soft);color:var(--on-red-soft)}
.syncpil.lokaal{background:var(--amber-soft);color:var(--on-amber-soft)}
@keyframes pols{0%,100%{opacity:1}50%{opacity:.25}}
@media (prefers-reduced-motion:reduce){.syncpil.bezig .dot{animation:none}}

/* ── formulierelementen ─────────────────────────────────────────────────────────────────────────── */
/* 36px is de raakvlakmaat van de hele app: knop, veld en icoonknop zijn even hoog, zodat ze in één
   actiebalk op dezelfde lijn staan zonder dat er ergens een hoogte bij hoeft. Overgenomen uit de
   facturatie-app; 8px/11px binnenruimte hoort bij die hoogte en staat daarom niet op de ruimteschaal. */
select,input[type=text],input[type=date],input[type=search],input[type=number],textarea{font:inherit;
  min-height:36px;padding:8px 11px;border:1px solid var(--line-strong);border-radius:var(--r-sm);
  background:var(--surface);color:var(--ink);max-width:100%}
/* Focus op een INVOERVELD is een ring in de veldkleur, geen outline: de outline lag over de rand heen en
   was in een dichte werkbalk niet te onderscheiden van de rand van het buurveld. De ring van 3px staat
   erbuiten én de rand wisselt van kleur — twee signalen in plaats van één. */
select:focus,input:focus,textarea:focus{outline:none;border-color:var(--primary);
  box-shadow:0 0 0 3px var(--primary-soft)}
/* Alles wat géén invoerveld is houdt de outline. `[data-action]` en `[tabindex]` staan er expliciet bij:
   de app maakt klikbare tabelrijen en matrixcellen die geen <button> zijn en anders geen ring krijgen. */
a:focus-visible,button:focus-visible,summary:focus-visible,
[data-action]:focus-visible,[tabindex]:focus-visible{outline:2px solid var(--primary);
  outline-offset:2px;border-radius:6px}
textarea{min-height:58px;resize:vertical}
button{font:inherit;min-height:36px;padding:0 13px;font-size:13.5px;font-weight:600;
  border:1px solid var(--muted);border-radius:var(--r-sm);background:var(--surface);color:var(--ink);
  cursor:pointer}
button:hover{background:var(--surface-3);border-color:var(--ink-soft)}
button.primary{background:var(--primary);border-color:transparent;color:var(--on-primary);
  box-shadow:0 4px 14px var(--primary-soft)}
button.primary:hover{background:var(--primary-strong);border-color:transparent}
/* .accent = een belangrijke maar niet-onomkeerbare nevenactie (terugzetten, herstellen): indigo in rand
   en tekst, niet gevuld, zodat er per scherm één gevulde primaire knop blijft. */
button.accent{background:var(--surface);border-color:var(--primary);color:var(--primary)}
button.accent:hover{background:var(--primary-soft);border-color:var(--primary)}
button.ghost{border-color:transparent;background:transparent}
button.ghost:hover{background:var(--surface-3);border-color:transparent}
/* --red is een signaalkleur voor vlakken en randen, niet voor tekst: als tekstkleur haalt hij 4,37:1 in
   licht en 3,98:1 in donker, onder de eis van 4,5:1. Deze knop zit op élke onomkeerbare bevestiging
   (FDialogen bij gevaarlijk:true), dus juist daar moet de tekst leesbaar zijn. --on-red-soft haalt 7,04:1
   en 8,03:1.
   ⚠ Bewuste afwijking van het ontwerpblad: dáár staat `--red` op `--red-soft`, en dat meet 3,74:1. De
   vórm van het blad is wél overgenomen — gevuld met --red-soft en zonder rand, in plaats van alleen
   tekst en een rand — want een onomkeerbare actie hoort een vlak te zijn, geen omtrek. */
button.danger{color:var(--on-red-soft);border-color:transparent;background:var(--red-soft)}
button.danger:hover{background:var(--red-soft);border-color:var(--red)}
/* .mini is voor rij-acties in een tabel: een knop van 36px maakt elke rij een halve regel hoger dan de
   tekst erin nodig heeft, en dat kost over 649 regels een half scherm. */
button.mini{min-height:30px;padding:0 11px;font-size:var(--text-xs)}
button:disabled{opacity:.45;cursor:not-allowed}
/* Vierkante icoonknop: één maat voor alles wat alléén een SVG draagt (thema, tandwiel, verversen), zodat
   de kop niet uit knoppen van wisselende breedte bestaat. Altijd met aria-label — er staat geen tekst in. */
button.icon-btn{width:36px;height:36px;min-height:36px;padding:0;border-radius:9px;
  border:1px solid var(--line);box-shadow:var(--shadow-sm);display:inline-flex;align-items:center;
  justify-content:center;flex:none}
/* Hover gelijk aan `.icon-btn:hover` in de facturatie-app: alleen de vulling verdiept. De generieke
   knophover verdiept óók de rand (--ink-soft) en dat maakt een icoonknop in de kop onrustig. */
button.icon-btn:hover{background:var(--surface-2);border-color:var(--line)}
button.icon-btn.mini{width:30px;height:30px;min-height:30px;border-radius:var(--r-sm);
  border-color:var(--muted);box-shadow:none}
/* De oude losse icoonknop. Blijft bestaan tot élke aanroep op .icon-btn staat; hij mag de nieuwe
   knopmaten niet erven, anders wordt een 3px-knopje ineens 36px hoog. */
button.icon{padding:3px 7px;line-height:1.1;min-height:0;font-size:inherit;font-weight:inherit}
button.plat{border:none;background:none;color:var(--muted);min-height:0;font-weight:400;
  font-size:inherit;padding:6px 4px}
button.plat:hover{color:var(--primary);background:none;border-color:transparent}
button.let-op{box-shadow:0 0 0 3px var(--primary-soft)}
/* Uitklapchevron: ÉÉN tekening die draait, in plaats van twee glyphs (▸/▾) die per lettertype anders
   uitvallen en niet mee te animeren zijn. Dicht wijst hij naar rechts, open naar beneden. */
button .uitklap-svg,button.uitklap svg{transition:transform .18s ease}
button.uitklap svg{transform:rotate(-90deg)}
button.uitklap.open svg{transform:none}
@media (prefers-reduced-motion:reduce){button.uitklap svg{transition:none}}
label.checkbox{display:inline-flex;gap:5px;align-items:center;font-size:var(--text-sm);margin-right:var(--space-3)}

/* ── navigatie ──────────────────────────────────────────────────────────────────────────────────── */
.regbar{background:var(--surface-2);border-bottom:1px solid var(--line);padding:var(--space-2) var(--space-4);
  display:flex;gap:var(--space-2);align-items:center;flex-wrap:wrap}
.regbar .lbl{font-size:var(--text-xs);text-transform:uppercase;letter-spacing:.07em;color:var(--muted)}
.regbar select{min-width:300px}
/* De tabbladenrij staat sinds 2.57.0 ín de paginakop (onder de titel, boven de onderregel) en niet meer als
   eigen strook over de volle breedte boven `main`. Daarom géén eigen achtergrond en géén eigen zijruimte
   meer: de rij ligt op het canvas van de pagina en erft de binnenruimte van `main`. Wat overblijft is de
   raillijn eronder — die maakt de rij herkenbaar als tabbladen in plaats van als een reeks losse knopjes,
   en de actieve knop zet er zijn 2px inktstreep in. */
nav.tabs{display:flex;gap:2px;border-bottom:1px solid var(--line-strong);flex-wrap:wrap;
  margin:0 0 var(--space-3)}
nav.tabs button{border:none;border-radius:0;background:none;min-height:0;padding:9px 13px;font-weight:400;
  color:var(--muted);border-bottom:2px solid transparent;margin-bottom:-1px}
nav.tabs button:hover{background:transparent;color:var(--ink)}
nav.tabs button.active{color:var(--ink);font-weight:650;border-bottom-color:var(--ink)}
nav.tabs .sep{width:1px;background:var(--line);margin:8px var(--space-2)}
/* ── paginakop ──
   Eén koparchitectuur voor élk scherm: kruimel, titel, tabbladen, één regel eronder. Vervangt twee dingen
   tegelijk — de losse `.terugweg`/`.schermkop` boven de tabbladenrij (2.32) en de inleidende `.card` met een
   `h2` van 16px waarmee elk ander scherm opende. Die twee deden hetzelfde werk op twee plekken en met twee
   maten. Staat ín `main` en dus binnen dezelfde kolom als de inhoud, gelijk aan het ontwerpblad
   (docs/ontwerp-componenten-en-schermen.html, scherm 1 t/m 3): de kop hoort bij de pagina, niet bij de schil.
   25px/760 is de enige plek in de app met deze maat; daarmee is de paginatitel op elk scherm het zwaarste
   element en concurreert geen enkele `h2` of `h3` ermee.
   De kruimel draagt sinds 2.57.0 alléén nog het menublok *Beheer*; op een registratie is hij leeg en dus
   verborgen (app/app.js, kop()). */
.paginakop{margin:0 0 var(--space-4)}
.paginakop .kruimel{display:flex;align-items:center;gap:var(--space-2);flex-wrap:wrap;
  font-size:var(--text-xs);font-weight:600;color:var(--muted);letter-spacing:.3px;text-transform:uppercase}
/* Dicht op de tabbladenrij eronder: titel en tabbladen horen bij elkaar, de onderregel hangt onder de rij
   en telt wat het gekozen tabblad laat zien. */
.paginakop h1{margin:2px 0 var(--space-2);font-size:25px;font-weight:760;letter-spacing:-.02em;
  line-height:1.15}
.paginakop .onder{margin:0;font-size:var(--text-sm);color:var(--muted)}
/* ── actiebalk ──
   Alles waarmee je de lijst op het scherm bijstelt in één omhulsel: links zoeken en filteren, rechts de
   telling, de export en de primaire actie. Stond eerder als een losse `.zoekbalk` bóven een transparante
   `.toolbar` — twee rijen bedieningselementen zonder rand, waardoor ze als inhoud lazen in plaats van als
   gereedschap. De witte kaart zet ze samen apart van de tabel eronder. */
.actiebalk{display:flex;align-items:center;gap:11px;flex-wrap:wrap;padding:10px 12px;
  background:var(--surface);border:1px solid var(--line);border-radius:12px;box-shadow:var(--shadow-sm);
  margin-bottom:var(--space-3)}
.actiebalk .acties{display:flex;align-items:center;gap:var(--space-2);margin-left:auto;flex-wrap:wrap}
/* Het zoekveld neemt de ruimte die overblijft, maar krimpt niet onder een leesbare breedte: dan wikkelt
   de balk liever naar een tweede regel dan dat er een veld van 60px overblijft. */
.actiebalk input[type=search]{flex:1 1 220px;min-width:160px}
/* Breedte van de inhoud. 2.40.0 zette hier 1200px, daarna 1800px (zie git-historie) — in beide gevallen
   bleef er op een breed scherm een lege rand naast de tabel staan terwijl het risicoregister met zijn
   dertien kolommen juist ruimte nodig heeft. Op verzoek van de eigenaar (13-08-2026) is de bovengrens
   daarom helemaal weg: de inhoud vult altijd de volle breedte van het venster.
   De binnenruimte (24/28/44) komt uit het ontwerpblad. */
main{padding:24px 28px 44px;width:100%}

/* ── zijbalk met de registraties ──
   Er komen 30–50 registraties (CLAUDE.md regel 12); een keuzelijst laat dan niet zien wát er is en waar
   u bent. De zijbalk groepeert op `registratie.categorie` — die staat al in het datamodel. De indeling is
   een grid OP #appShell, zodat de bestaande markup (kop, regbar, main) op zijn plaats blijft en de
   zijbalk er als extra kind bij komt. Onder 900px is er geen ruimte: dan verdwijnt de zijbalk en neemt de
   keuzelijst het weer over. */
#appShell{min-height:100vh}
#zijbalk{display:none}
@media (min-width:900px){
  /* 236px komt uit het goedgekeurde ontwerp (docs/ontwerp-menu-iso.html, variant 1A). Het menu is een
     vaste set van ~9 regels geworden en heeft de breedte van een registratielijst niet meer nodig; de
     gewonnen ruimte gaat naar de brede grids. De gridkolom is de enige plek waar de breedte staat, dus
     de rest van de indeling schuift vanzelf mee. */
  /* De rijen staan in de volgorde van de markup (index.html): kop, regbar, main. De paginakop is sinds
     2.39 géén eigen rij meer (hij staat ín main, binnen dezelfde kolom als de inhoud) en de tabbladenrij
     sinds 2.57.0 óók niet: die hoort onder de paginatitel en boven de onderregel die het gekozen tabblad
     telt, dus staat hij ín de paginakop.
     ⚠ Twee dingen horen bij elkaar: elke nieuwe rij krijgt `auto` in grid-template-rows én `zij` in de
     eerste kolom van grid-template-areas — anders houdt de zijbalk op bij de laatste rij die hem noemt en
     staat hij half zo hoog als het venster. `auto` klapt naar 0 als het element `hidden` is (regel 51:
     `[hidden]{display:none!important}`), dus een verborgen rij laat geen gat achter. */
  /* De zijbalk begint bóven de kop, gelijk aan `.sidebar` in de facturatie-app: het merkblok staat daar
     linksboven in het venster en niet onder een balk die over de volle breedte loopt. De kop hoort dus bij
     de hoofdkolom (`"zij kop"`), niet over beide kolommen. */
  #appShell{display:grid;grid-template-columns:236px minmax(0,1fr);
    grid-template-rows:auto auto minmax(0,1fr);
    grid-template-areas:"zij kop" "zij reg" "zij main"}
  #appShell > header{grid-area:kop}
  #appShell > .regbar{grid-area:reg}
  /* main scrollt zelf, zodat de zijbalk blijft staan. De tabbladenrij scrollt sinds 2.57.0 mee met de
     paginakop: hij hoort bij de kop van de pagina, en de kopregel van de tabel blijft bij het scrollen
     hoe dan ook staan (`thead th{position:sticky}`), dus je verliest niet waar je in de tabel bent. */
  #appShell > main{grid-area:main;overflow-y:auto}
  /* De aside scrollt zelf niet meer: dat doet #zijbalkNav, zodat de voet (opslagstatus) blijft staan. */
  /* Geen binnenruimte bovenaan meer: het merkblok brengt sinds 2.44 zijn eigen kop mee. */
  #zijbalk{grid-area:zij;display:block;background:var(--surface);border-right:1px solid var(--line);
    padding:0;overflow:hidden}
  /* De hele regbar is dan dubbelop met de zijbalk; app.js zet hem op hidden (zetNavigatieZichtbaar). */
}
/* Groepskopjes in het menu ("Werk", "Beheer"). 11px en .4px letterafstand zijn dezelfde maten
   als .menu .kop in het tandwielmenu: het zijn dezelfde soort kopjes en ze horen er niet anders uit te
   zien. Ze staan bewust niet op --text-xs (12px) — dat is de maat van leesbare bijzaak, en dit is een
   labeltje. */
.zij-groep{font-size:11px;font-weight:650;color:var(--muted);text-transform:uppercase;letter-spacing:.4px;
  padding:var(--space-2) 11px var(--space-1);margin:0}
/* De pilvorm van een menu-item. 9px ronding heeft geen token (tussen --r-sm 8 en --r-md 11 in) en is
   overgenomen uit de facturatie-app; 11px binnenruimte hoort bij die pil en niet bij de ruimteschaal. */
.zij-item{display:flex;gap:11px;align-items:center;padding:9px 11px;margin-bottom:2px;
  border-radius:9px;color:var(--ink);text-decoration:none;font-size:var(--text-base);font-weight:550;
  line-height:1.25}
.zij-item:hover{background:var(--surface-2)}
/* ⚠ Tekst op --primary-soft is ALTIJD --primary-strong, nooit --primary: in het donkere thema haalt
   #7b7bea op #262a44 maar 3,92:1 en dat zakt onder de WCAG AA-eis van 4,5:1 (axe: color-contrast,
   serious). Met --primary-strong is het 5,53:1 donker en 5,85:1 licht. Zelfde afspraak als .badge.paars,
   .chips .chip en .balk-filter. */
.zij-item.active{background:var(--primary-soft);color:var(--primary-strong);font-weight:650}
.zij-icoon{display:flex;flex:none}
/* Labels mogen afbreken met een ellipsis; de volledige titel staat op het scherm Registraties. */
.zij-label{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* De teller blijft grijs, óók in de actieve staat: hij is bijzaak naast het label en zou anders als
   tweede accent meelezen. */
.zij-tel,.zij-item.active .zij-tel{margin-left:auto;font-size:var(--text-xs);color:var(--muted);
  font-variant-numeric:tabular-nums}
/* Eén scheiding, niet twee: deze regel stond eerder dubbel (ook onderin het tandwielmenu-blok). */
.zij-sep{height:1px;background:var(--line);margin:var(--space-3) 6px}

/* Hier stonden tot 2.46 een `#zijbalk .cat`-regel en een compleet `#zijbalk a`-blok. Beide waren dood:
   sinds de zijbalk een vaste set bestemmingen is (2.32) krijgt elke link in `renderZijbalk()` de klasse
   `.zij-item` of `.zij-recent`, en die regels hierboven doen het werk al. `.cat` werd nergens meer gezet.
   De vormgeving zelf is niet gewijzigd — alleen de tweede, ongebruikte definitie ervan is weg. */

/* ── voet van de zijbalk: opslagstatus en verversen ──
   Staat in de zijbalk en niet in de kop, gelijk aan #syncBar in de facturatie-app (index.html daar:
   brand → adminNav → syncBar). De status hoort bij "waar staan mijn gegevens", en dat is navigatie-
   context; in de kop stond hij tussen de actieknoppen en las hij als nóg een knop.
   Onder 900px is er geen zijbalk. De status mag dan niet verdwijnen — "werk ik gedeeld of lokaal?" is
   precies op een klein scherm de vraag die je stelt — dus dan blijft de voet als strook boven de inhoud. */
#zijbalk{display:flex;flex-direction:column}
/* De zijruimte staat op het scrollgebied en niet op de aside: anders scrollen de pillen tegen de rand
   van de balk aan en loopt de scrollbalk dwars door de binnenruimte. */
#zijbalkNav{flex:1 1 auto;min-height:0;overflow-y:auto;padding:0 var(--space-3)}
#zijbalkVoet{flex:none;display:flex;flex-wrap:wrap;gap:var(--space-2);align-items:center;
  padding:var(--space-3) 11px 0;margin-top:var(--space-2);border-top:1px solid var(--line)}
#zijbalkVoet button{font-size:var(--text-xs)}
/* Versie en opslagmoment: de stilste regel van de app, op een volle regel onder de statuspil zodat hij de
   pil en de verversknop niet uit elkaar duwt. */
#zijbalkVoet .sub{flex-basis:100%;font-size:11px;color:var(--muted);line-height:1.3}
@media (max-width:899px){
  /* De aside zelf weer zichtbaar, maar alleen het merk en de voet: de navigatie zit dan in de keuzelijst.
     Het merkblok staat daarmee als strook bóven de kop in plaats van erin — dat is de plek die op een smal
     scherm overblijft, en het scheelt een tweede <h1> in de DOM. */
  #zijbalk{display:block;background:var(--surface);border:0;border-bottom:1px solid var(--line);
    padding:0;overflow:visible}
  #zijbalkNav{display:none}
  .merk{padding:var(--space-2) var(--space-4)}
  #zijbalkVoet{padding:var(--space-2) var(--space-4);margin:0;border-top:0;
    border-bottom:1px solid var(--line);background:var(--surface-2)}
}

/* ── tandwielmenu ──
   Overgenomen uit de facturatie-app (.menu-overlay + .data-menu): een popover onder het tandwiel met
   groepskopjes en volle-breedte items, in plaats van meteen een dialoog. De overlay eronder vangt de klik
   buiten het menu; dat is betrouwbaarder dan een document-listener die met de openende klik in de knoop raakt. */
.menu-overlay{position:fixed;inset:0;z-index:40}
.menu{position:absolute;top:56px;right:16px;width:262px;background:var(--surface);
  border:1px solid var(--line);border-radius:14px;box-shadow:var(--shadow-lg);padding:6px;z-index:41;
  max-height:calc(100vh - 76px);overflow-y:auto}
.menu .kop{font-size:11px;font-weight:650;color:var(--muted);text-transform:uppercase;
  letter-spacing:.4px;padding:8px 10px 4px;margin:0}
.menu button{width:100%;display:flex;align-items:center;gap:10px;border:none;background:transparent;
  color:var(--ink);padding:9px 10px;border-radius:9px;font-size:var(--text-base);text-align:left;
  font-weight:500}
.menu button:hover{background:var(--surface-2)}
.menu button .teken{width:18px;flex:none;text-align:center;color:var(--muted)}
.menu button .bij{margin-left:auto;font-size:var(--text-xs);color:var(--muted);font-weight:400}
.menu .sep{height:1px;background:var(--line);margin:6px 8px}

/* ── kaarten, zoekbalk, werkbalk ────────────────────────────────────────────────────────────────── */
.card{background:var(--surface);border:1px solid var(--line);border-radius:var(--r-lg);box-shadow:var(--shadow-sm);
  padding:var(--space-3) var(--space-4);margin-bottom:var(--space-4)}
/* ── sectie ──
   Een kaart MET een kop, uit het ontwerpblad. Bewust een eigen klasse naast `.card` en geen wijziging van
   `.card` zelf: die wordt op tientallen plekken gebruikt met inhoud er rechtstreeks in, en die zouden hun
   binnenruimte verliezen zodra die naar een body-element verhuist.
   `overflow:hidden` is wat het verschil maakt bij een tabel: die loopt dan netjes tot ín de afgeronde hoek
   in plaats van er met een rechte rand overheen. */
.sectie{background:var(--surface);border:1px solid var(--line);border-radius:var(--r-lg);
  box-shadow:var(--shadow-sm);overflow:hidden;margin-bottom:var(--space-3)}
.sectie-kop{display:flex;justify-content:space-between;align-items:center;gap:var(--space-3);
  padding:14px 16px;border-bottom:1px solid var(--line)}
.sectie-kop h3{margin:0;font-size:var(--text-lg);font-weight:650;letter-spacing:-.2px}
.sectie-kop .bij{font-size:var(--text-xs);color:var(--muted);font-weight:400;white-space:nowrap}
/* De body is een grid met vaste tussenruimte: elk kind staat daarmee op dezelfde ritmiek zonder eigen
   marges, en een tabel als enig kind vult de sectie zonder rand eromheen. */
.sectie-body{padding:14px 16px;display:grid;gap:var(--space-3)}
.sectie>table,.sectie>.grid-wrap{border:0;border-radius:0;box-shadow:none}

/* ── segmented control ──
   Vervangt een keuzelijst met twee of drie vaste opties. Een <select> verbergt zijn opties tot je hem
   opent; bij drie mogelijkheden is dat één klik te veel én zie je niet wat de keuze ís. Bij méér opties
   blijft de keuzelijst beter (#oCat, #logFilter) — daar zou dit een balk van dertig knoppen worden. */
.seg{display:inline-flex;background:var(--surface-3);border-radius:9px;padding:3px;gap:2px}
.seg button{min-height:30px;padding:0 12px;border:none;border-radius:7px;background:transparent;
  color:var(--muted);font-size:12.5px;font-weight:600;box-shadow:none}
.seg button:hover{background:transparent;color:var(--ink);border-color:transparent}
/* ⚠ Tekst op --surface is --primary; de actieve knop is een wít vlak met schaduw, niet een gekleurd vlak.
   Zo blijft het contrast in beide thema's ruim boven AA zonder een extra token. */
.seg button.actief{background:var(--surface);color:var(--primary);font-weight:650;
  box-shadow:var(--shadow-sm)}

/* Accordeonchevron: in de MARKUP en niet als `content:`-glyph in ::before. Een glyph is niet te kleuren,
   niet op maat te zetten en niet te animeren, en valt per lettertype anders uit. Staat rechts, ná de
   telling, gelijk aan het ontwerpblad. */
.acc-chevron{margin-left:auto;display:flex;flex:none;color:var(--muted);transition:transform .18s ease}
details:not([open])>summary .acc-chevron,.filterpaneel:not([open])>summary .acc-chevron{transform:rotate(-90deg)}
@media (prefers-reduced-motion:reduce){.acc-chevron{transition:none}}
.zoekbalk{margin-bottom:var(--space-2)}
.zoekbalk input{width:100%;padding:9px 13px;border-radius:var(--r-md);font-size:var(--text-base)}
.filterpaneel{display:inline-block;position:relative}
.filterpaneel>summary{cursor:pointer;list-style:none;display:inline-flex;align-items:center;gap:6px;
  min-height:36px;padding:0 13px;font-size:13.5px;font-weight:600;border:1px solid var(--muted);
  border-radius:var(--r-sm);background:var(--surface);white-space:nowrap}
.filterpaneel>summary::-webkit-details-marker{display:none}
.filterpaneel[open]>summary{background:var(--surface-3);border-color:var(--primary)}
.filterpaneel>summary.actief{border-color:var(--primary);color:var(--primary-strong);font-weight:600}
.filterpaneel .filterinhoud{position:absolute;z-index:20;top:calc(100% + 4px);left:0;min-width:320px;
  background:var(--surface);border:1px solid var(--line-strong);border-radius:var(--r-md);
  box-shadow:var(--shadow-md);padding:var(--space-3);display:flex;flex-direction:column;gap:var(--space-2)}
.filterpaneel .filterinhoud select{width:100%}
.filterpaneel #gridFilters{display:flex;flex-direction:column;gap:var(--space-2)}
.verborgen{display:none}
.chips{display:flex;gap:var(--space-1);flex-wrap:wrap;align-items:center}
.chips .chip{background:var(--primary-soft);color:var(--primary-strong);cursor:pointer}
.chips .chip:hover{text-decoration:line-through}
/* ── Inzichten: risicomatrix 5x5 en balken ──
   Geen grafiekbibliotheek: de matrix is een tabel en een balk is een gekleurde div met een breedte. Dat houdt
   de CSP (`script-src 'self'`) en de vendor-checksumgate ongemoeid. De kleuren zijn dezelfde als de
   scorebadges in de tabellen (.sc), zodat een cel en een regel dezelfde taal spreken. */
.matrixwrap{overflow-x:auto}
table.rmatrix{border-collapse:separate;border-spacing:3px;table-layout:fixed;width:auto;min-width:0}
table.rmatrix th.hoek{font-size:var(--text-xs);color:var(--muted);font-weight:600;text-align:left;
  white-space:normal;width:150px;background:none;position:static}
table.rmatrix th.as{width:64px;text-align:center;font-size:var(--text-sm);color:var(--muted);
  background:none;position:static;border:0}
table.rmatrix td.mcel{width:64px;height:52px;text-align:center;vertical-align:middle;border:0;
  border-radius:var(--r-sm);position:relative;cursor:default}
table.rmatrix td.mcel b{display:block;font-size:var(--text-lg);font-weight:650;line-height:1.1}
table.rmatrix td.mcel .sco{position:absolute;right:4px;bottom:2px;font-size:10px;opacity:.65;
  font-variant-numeric:tabular-nums}
table.rmatrix td.mcel.l{background:var(--green-soft);color:var(--on-green-soft)}
table.rmatrix td.mcel.m{background:var(--amber-soft);color:var(--on-amber-soft)}
table.rmatrix td.mcel.h{background:var(--orange-soft);color:var(--on-orange-soft)}
table.rmatrix td.mcel.x{background:var(--red-soft);color:var(--on-red-soft)}
table.rmatrix td.mcel.leegcel{opacity:.42}
table.rmatrix td.mcel .inzknop{width:100%;height:100%;padding:0}

/* ── Inzichten: de kruistabel ──
   De matrixvorm van een onderdeel dat uit een matrixtabblad komt. Anders dan de risicomatrix is dit geen
   vaste 5x5 maar een tabel die met de data meegroeit, dus GEEN table-layout:fixed en wél sticky rij- en
   kolomkoppen: bij twintig kolommen ben je de naam van de rij anders kwijt zodra je opzij scrollt.
   .matrixwrap eromheen doet het horizontale scrollen, zodat de pagina zelf nooit meescrollt. */
table.ktabel{border-collapse:separate;border-spacing:2px;width:auto}
table.ktabel th.hoek{font-size:var(--text-xs);color:var(--muted);font-weight:600;text-align:left;
  white-space:normal;background:var(--surface);position:sticky;left:0;z-index:3;vertical-align:bottom}
table.ktabel th.hoek span{display:inline-block;max-width:200px}
table.ktabel th.kkol{vertical-align:bottom;text-align:left;background:none;position:static;border:0;
  font-size:var(--text-xs);color:var(--muted);font-weight:600;padding:0 2px var(--space-1)}
/* Kolomkoppen staan gekanteld: twintig groepsnamen naast elkaar passen anders alleen bij kolommen die zo
   breed zijn dat de tabel niet meer te overzien is. */
table.ktabel th.kkol .inzknop{writing-mode:vertical-rl;transform:rotate(180deg);max-height:190px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;padding:2px 1px}
table.ktabel th.krij{text-align:left;font-weight:500;font-size:var(--text-sm);white-space:nowrap;
  background:var(--surface);position:sticky;left:0;z-index:2;border:0;padding-right:var(--space-2)}
table.ktabel th.krij .inzknop{max-width:280px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
table.ktabel td.kctx{font-size:var(--text-xs);color:var(--muted);white-space:nowrap;
  padding-right:var(--space-3);max-width:220px;overflow:hidden;text-overflow:ellipsis}
table.ktabel td.kcel{width:28px;min-width:28px;text-align:center;vertical-align:middle;border:0;
  border-radius:var(--r-sm);background:var(--primary-soft);color:var(--primary-strong)}
table.ktabel td.kcel b{font-size:var(--text-sm);font-weight:650;line-height:1.6}
table.ktabel td.kcel .inzknop{width:100%;padding:0}
table.ktabel td.kcel.kleeg{background:var(--surface-2);opacity:.5}

/* Doorklikken vanuit Inzichten: elk getal is een knop die het bijbehorende filter zet en het onderdeel opent.
   De knop mag niet als knop opvallen — hij moet lezen als het getal zelf — maar wél reageren op hover en
   zichtbaar focusbaar zijn, want dit is de enige weg van een cijfer naar de regels erachter. */
.inzknop{appearance:none;background:none;border:0;color:inherit;font:inherit;min-height:0;cursor:pointer;
  border-radius:var(--r-sm);display:block}
.inzknop:hover{background:rgba(0,0,0,.06)}
.inzknop:focus-visible{outline:2px solid var(--primary);outline-offset:1px}
.inzknop.plat{padding:2px 6px;margin:-2px -6px}
.inzknop.balkrij:hover .balkspoor{filter:brightness(.97)}
.inzknop.dood{cursor:default;width:100%;height:100%}
.inzknop.dood:hover{background:none}
html[data-theme="dark"] .inzknop:hover{background:rgba(255,255,255,.08)}
.chips .chip.inz{background:var(--amber-soft);color:var(--on-amber-soft)}
.inzkop{font-size:var(--text-lg);margin:var(--space-4) 0 var(--space-2)}
.inzkop:first-child{margin-top:0}

.balken{display:grid;gap:6px}
.balkrij{display:grid;grid-template-columns:minmax(120px,220px) 1fr 44px;gap:var(--space-2);align-items:center;
  width:100%;text-align:left}
.balklabel{font-size:var(--text-sm);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.balkspoor{background:var(--surface-3);border-radius:var(--r-pill);height:12px;overflow:hidden}
.balk{display:block;height:100%;background:var(--primary);border-radius:var(--r-pill)}
.balk.rood{background:var(--red)}
.balkn{text-align:right;font-size:var(--text-sm);font-variant-numeric:tabular-nums;color:var(--ink-soft)}
.card h3 .telling{margin-left:auto;font-size:var(--text-xs);color:var(--muted);font-weight:400;font-style:italic}

/* ── KPI-dashboard ──
   Eén blok per categorie, ONDER elkaar en over de volle breedte. Naast elkaar (auto-fit-kolommen van
   minimaal 520px) leverde met de zijbalk erbij smalle kolommen op waarin de KPI-naam werd afgekapt; een
   dashboard dat je moet aanwijzen om te kunnen lezen is geen dashboard.
   De KPI-kolom mag afbreken, de getalkolommen niet — vandaar table-layout:fixed met vaste breedtes voor de
   cijfers en de rest van de ruimte voor de naam. */
/* Exporteren staat op élk scherm op dezelfde plek: rechts in de werkbalk, met de telling ervoor en altijd
   in dezelfde volgorde (Excel, dan PDF). Eén vaste plek betekent dat niemand hoeft te zoeken. */
.exportgroep{display:flex;align-items:center;gap:var(--space-2)}

.kpi-grid{display:block}
/* Een categorieblok is sinds 2.42 een .sectie: kop en body zitten in het component, dus hier blijft alleen
   wat écht eigen is aan het KPI-dashboard. De h3 met een handmatig getrokken onderlijn is vervallen. */
.kpi-cat{margin-bottom:var(--space-3)}
.kpi-cat .bij{font-style:italic}
/* De tabel vult de sectie tot de rand: geen eigen kaartrand meer eromheen, want die zit al om de sectie. */
.kpi-cat .grid-wrap{max-height:none;overflow:visible;border:0;border-radius:0;box-shadow:none}
.kpi-cat table{table-layout:fixed;width:100%;min-width:0}
.kpi-cat td.kpi-naam{white-space:normal;word-break:break-word}
.kpi-cat td.kpi-naam b{font-weight:600}
/* Alles wat geen kerngegeven is, staat cursief: de omschrijving onder de KPI-naam en de tellingen. Zo is in
   één oogopslag duidelijk wat de meetwaarde is en wat toelichting. */
.kpi-cat td.kpi-naam .toel{display:block;color:var(--muted);font-size:var(--text-xs);font-style:italic;
  margin-top:2px;line-height:1.35}
.kpi-cat tbody tr.arch td{opacity:1;color:var(--muted);font-style:italic}
/* Ook de losse toelichtende teksten in de KPI-blokken ("niet ingevuld", tellingen): cursief, zodat de
   getallen en statussen het beeld bepalen. Kerngegevens blijven rechtop. */
.kpi-cat .mut{font-style:italic}
.kpi-cat .badge,.kpi-cat .sc,.kpi-cat td.num b{font-style:normal}
.kpi-cat tbody tr.arch td.kpi-naam b{color:var(--ink-soft);font-style:normal}
.voortgangsbalk{display:inline-block;width:70px;height:7px;border-radius:var(--r-pill);background:var(--surface-3);
  overflow:hidden;vertical-align:middle;margin-right:5px}
.voortgangsbalk>span{display:block;height:100%;background:var(--primary)}
.wiz-kop{display:flex;justify-content:space-between;align-items:center;gap:var(--space-3);
  padding-bottom:var(--space-2);border-bottom:1px solid var(--line);margin-bottom:var(--space-3)}
.voortgangsbalk.breed{width:220px;height:9px}
.wiz-kpi h3{font-size:var(--text-xl);margin:0 0 var(--space-1);letter-spacing:-.01em}
.wiz-feiten{display:flex;gap:var(--space-6);flex-wrap:wrap;margin:var(--space-3) 0;padding:var(--space-3);
  background:var(--surface-2);border-radius:var(--r-md)}
.wiz-feiten>div{display:flex;flex-direction:column}
.wiz-feiten span{font-size:var(--text-xs)}
.wiz-invoer{display:flex;gap:var(--space-2);align-items:center;flex-wrap:wrap}
.wiz-invoer input{font-size:var(--text-xl);padding:8px 12px;width:170px;font-variant-numeric:tabular-nums}
.wiz-nav{display:flex;gap:var(--space-2);align-items:center;flex-wrap:wrap;margin-top:var(--space-4);
  padding-top:var(--space-3);border-top:1px solid var(--line)}
.toolbar{display:flex;gap:var(--space-2);align-items:center;flex-wrap:wrap;margin-bottom:var(--space-3)}
.stat{display:flex;gap:var(--space-6);flex-wrap:wrap}
.stat div{min-width:84px}
.stat b{display:block;font-size:var(--text-2xl);font-weight:650;letter-spacing:-.02em;line-height:1.1}
.stat span{font-size:var(--text-xs);color:var(--muted)}

/* ── statusbalken (app/banners.js) ──
   Eén vorm voor alles wat over de HUIDIGE inhoud gaat: filter actief, alleen lezen, let op, archief.
   Zonder deze gedeelde vorm krijgt elk scherm zijn eigen losse HTML en lopen kleur en plaatsing uiteen. */
.statusbalk{display:flex;gap:var(--space-2);align-items:center;padding:7px 11px;border-radius:var(--r-sm);
  font-size:var(--text-sm);margin-bottom:var(--space-2);background:var(--surface-3);color:var(--ink-soft)}
.statusbalk>span{flex:1}
.statusbalk svg{flex:none}
.statusbalk button{flex:none}
.balk-filter{background:var(--primary-soft);color:var(--primary-strong)}
.balk-filter button.plat{color:var(--primary-strong);text-decoration:underline}
.balk-lezen{background:var(--amber-soft);color:var(--on-amber-soft)}
.balk-letop{background:var(--red-soft);color:var(--on-red-soft)}
.balk-archief{background:var(--surface-3);color:var(--ink-soft)}

/* ── tabellen ───────────────────────────────────────────────────────────────────────────────────── */
/* `overflow-x:auto` en niet `scroll`: een schuifbalk hoort er te staan als er iets te schuiven valt en
   anders niet. Met `scroll` (plus een gereserveerde goot) stond er onder élke tabel een balk, ook onder een
   tabel van vier kolommen die ruim paste — dat leest als "er staat hier meer" terwijl dat niet zo is. */
.grid-wrap{overflow-x:auto;overflow-y:auto;max-height:min(62vh,calc(100vh - 300px));
  background:var(--surface);border:1px solid var(--line);border-radius:var(--r-lg);box-shadow:var(--shadow-sm)}
.grid-wrap.kort{max-height:420px;overflow-x:auto}
/* Medewerkers heeft, anders dan een registratiegrid, geen filterbalk of groepering erboven die ruimte
   inneemt — de generieke 62vh/(100vh-300px)-cap houdt dan te veel over en de tabel gaat al bij een
   handvol medewerkers intern schuiven terwijl de pagina zelf nog leeg is. Net als .regtabel (scherm
   Registraties) laat deze tabel de pagina zelf scrollen in plaats van zichzelf. */
#kaartMedewerkers .grid-wrap{max-height:none}
.grid-wrap::-webkit-scrollbar{height:14px;width:12px}
.grid-wrap::-webkit-scrollbar-track{background:var(--surface-3);border-radius:var(--r-pill)}
.grid-wrap::-webkit-scrollbar-thumb{background:var(--line-strong);border-radius:var(--r-pill);border:3px solid var(--surface-3)}
.grid-wrap::-webkit-scrollbar-thumb:hover{background:var(--muted)}
table{border-collapse:separate;border-spacing:0;width:auto;min-width:100%;font-size:var(--text-sm)}
th,td{border-bottom:1px solid var(--line);padding:10px 12px;text-align:left;vertical-align:middle}
/* De laatste rij heeft geen onderrand nodig: de kaartrand eromheen sluit de tabel al af, en twee lijnen
   over elkaar leest als een dubbele streep. */
tbody tr:last-child td{border-bottom:none}
/* ⚠ Uitzondering op `td{padding:10px 12px}`: het registratiegrid en het logboek zijn de twee tabellen
   waar het om de hoeveelheid regels in beeld gaat (649 risico's, duizenden logregels). Op 10/12 passen
   er ~40% minder regels op een scherm, en dan is het geen werklijst meer maar een leesbladzijde. Alle
   overige tabellen — overzicht, KPI, beheer, keuzelijsten — volgen wél de nieuwe maat. */
#gridTable td,#logTable td{padding:8px 11px}
/* Meerregelige inhoud hoort bovenaan te beginnen, niet in het midden: de uitklapregel bevat hele
   alinea's en de KPI-naam heeft een toelichting onder zich. */
tr.detail td,.kpi-cat td.kpi-naam{vertical-align:top}
thead th{position:sticky;top:0;background:var(--surface-2);z-index:2;font-size:var(--text-xs);white-space:nowrap;
  color:var(--ink-soft);font-weight:650;letter-spacing:.2px;border-bottom:1px solid var(--line-strong)}
th.sorteerbaar{cursor:pointer;user-select:none}
th.sorteerbaar:hover,th.sorteerbaar.actief{color:var(--primary)}
tr.groep td{background:var(--primary-soft);font-weight:650;position:sticky;top:38px;z-index:1}
tbody tr:hover td{background:var(--surface-2)}
tbody tr.groep:hover td{background:var(--primary-soft)}
tbody tr.arch td{opacity:.6}
tr.detail td{background:var(--surface-2);font-size:var(--text-sm);white-space:pre-wrap}
.detail-veld{margin:3px 0}
td.num{text-align:center;white-space:nowrap}
th.kleef-r,td.kleef-r{position:sticky;right:0;background:var(--surface);border-left:1px solid var(--line-strong);z-index:3}
/* De kolom Gewijzigd is bij élke registratie even breed. Zonder vaste breedte bepaalt de langste naam in
   de kolom hoe breed hij wordt, en dan staat de sticky kolomrand per registratie ergens anders — met een
   bewerkknop die bij de ene registratie wél en bij de andere niet op dezelfde plek staat. De naam wordt
   afgekapt; de volledige tekst staat in de tooltip van de cel. */
th.kleef-2,td.kleef-2{right:76px;border-left:1px solid var(--line);width:150px;min-width:150px;max-width:150px}
td.kleef-2 .gew-door{display:block;max-width:138px;margin:0 auto;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
thead th.kleef-r{background:var(--surface-2);z-index:4}
tbody tr:hover td.kleef-r{background:var(--surface-2)}
tr.groep td.kleef-r{background:var(--primary-soft)}
.w-uitklap{width:26px}.w-actie{width:76px}.w-90{width:90px}.w-120{width:120px}.w-150{width:150px}.w-190{width:190px}.w-200{width:200px}
/* table-layout:fixed + een vaste breedte op de .links-kolom: zonder dit sized elke categorie haar eigen
   <table class="matrix"> onafhankelijk op haar eigen inhoud, en schuiven de rolkolommen tussen de
   categorie-accordeons ten opzichte van elkaar op. `width:100%` laat de rolkolommen de resterende ruimte
   gelijk verdelen; `scrollbar-gutter:stable` op de wrapper zorgt dat die resterende ruimte niet 15px
   kleiner wordt zodra één categorie toevallig een verticale schuifbalk krijgt en een andere niet. */
.grid-wrap:has(table.matrix){scrollbar-gutter:stable}
.matrix{width:100%;table-layout:fixed}
.matrix td,.matrix th{text-align:center}
.matrix td.links,.matrix th.links{width:260px;text-align:left}

/* ── Beheer › Rollen en rechten: rij per registratie, rollen-grid pas op klik ──
   Acht rolkolommen per rij was op 30-50 registraties niet meer in één blik te overzien; de rij toont nu
   alleen titel, toegangsprofiel en een knop met het aantal afwijkingen. table-layout:fixed + vaste breedtes
   op .links/.profielcel houden elke categorietabel even breed, dezelfde reden als bij .matrix hierboven. */
table.rolindex{width:100%;table-layout:fixed}
table.rolindex td.links,table.rolindex th.links{width:50%;text-align:left}
table.rolindex td.profielcel{width:35%}
tr.regrij-auth{cursor:pointer}
tr.regrij-auth:hover td{background:var(--surface-2)}
.toon-rollen{white-space:nowrap}
.toon-rollen:not(.open) .acc-chevron{transform:rotate(-90deg)}
/* De grid met acht losse rol-velden in de uitgeklapte rij; auto-fit zodat hij op een smal scherm terugvalt
   naar één kolom in plaats van dichtgeknepen selects. */
.rolgrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:var(--space-2) var(--space-4)}
.rolveld{display:flex;flex-direction:column;gap:2px}
.rolveld-label{font-size:var(--text-xs);color:var(--muted)}

/* ── scherm Registraties (het overzicht als tabel) ──
   Een eigen tabelvorm naast .grid-wrap: dit is geen datagrid maar een keuzelijst met 31–50 regels die in
   één blik te overzien moet zijn. Vandaar de kaartvorm eromheen (zelfde vorm als .card, maar zonder
   binnenruimte zodat de tabel tot de rand loopt) en vaste kolombreedtes, zodat de titel de enige kolom is
   die meebeweegt. De maten hieronder overschrijven bewust de generieke `table`-regels hierboven. */
.tabelkaart{background:var(--surface);border:1px solid var(--line);border-radius:var(--r-lg);
  overflow:hidden;box-shadow:var(--shadow-sm)}
.regtabel{width:100%;border-collapse:collapse;font-size:var(--text-sm)}
.regtabel thead th{position:static;background:var(--surface-2);text-align:left;padding:9px 14px;
  font-size:var(--text-sm);font-weight:650;color:var(--ink-soft);border-bottom:1px solid var(--line);
  white-space:nowrap}
.regtabel th.k-nr{width:56px}
.regtabel th.k-cat{width:210px}
.regtabel th.k-regels{width:90px;text-align:right}
.regtabel th.k-recht{width:110px}
.regtabel th.k-gew{width:190px}
.regtabel td{padding:10px 14px;border-bottom:1px solid var(--line);vertical-align:top}
.regtabel tbody tr:last-child td{border-bottom:none}
.regtabel .c-nr{font-variant-numeric:tabular-nums;color:var(--muted);white-space:nowrap}
.regtabel .c-titel{font-weight:600}
.regtabel .c-regels{text-align:right;font-variant-numeric:tabular-nums}
.regtabel .c-gew{color:var(--muted)}
/* De rij is klikbaar én met het toetsenbord te bereiken (tabindex=0). Een <tr> krijgt geen bruikbare
   standaardfocusring, dus hier een eigen omranding binnen de rij — outline op een tabelrij wordt door
   border-collapse deels weggeknipt. */
.regtabel tr.regrij{cursor:pointer}
.regtabel tr.regrij:hover td{background:var(--surface-2)}
.regtabel tr.regrij.actief td{background:var(--surface-2)}
.regtabel tr.regrij:focus{outline:none}
.regtabel tr.regrij:focus-visible td{background:var(--primary-soft);
  box-shadow:inset 0 2px 0 var(--primary),inset 0 -2px 0 var(--primary)}
.regtabel tr.regrij:focus-visible td:first-child{box-shadow:inset 2px 0 0 var(--primary),
  inset 0 2px 0 var(--primary),inset 0 -2px 0 var(--primary)}
.regtabel tr.regrij:focus-visible td:last-child{box-shadow:inset -2px 0 0 var(--primary),
  inset 0 2px 0 var(--primary),inset 0 -2px 0 var(--primary)}
/* Kleur is nooit het enige signaal: de badge draagt de tekst "Lezen" of "Bewerken" zelf. */
.recht-badge{display:inline-block;font-size:var(--text-xs);font-weight:600;padding:2px 9px;
  border-radius:var(--r-pill);white-space:nowrap}
.recht-lezen{background:var(--surface-3);color:var(--muted)}
.recht-schrijven{background:var(--green-soft);color:var(--on-green-soft)}

/* De actiekolom van de registratietabel: potlood en archiefdoosje, dezelfde `icon-btn mini` als op een
   rij in het grid. Rechts uitgelijnd (`.num`) zodat de knoppen op één lijn staan ongeacht de rijhoogte. */
.regtabel th.k-actie{width:96px;text-align:right}
.regtabel td.c-actie{padding:6px 14px;white-space:nowrap}

/* ── prullenbak ──
   Kopje per categorie boven de accordeons, in dezelfde toon als de groepskopjes in de zijbalk: het is een
   ordening, geen sectietitel die met de paginakop concurreert. */
.pb-cat{margin:22px 0 8px;font-size:var(--text-xs);font-weight:700;letter-spacing:.06em;
  text-transform:uppercase;color:var(--muted)}
.pb-cat:first-child{margin-top:4px}
.pb-onderdeel h4{display:flex;align-items:center;gap:10px;margin:14px 0 6px;font-size:var(--text-sm)}
.pb-onderdeel:first-child h4{margin-top:0}
.pb-onderdeel h4 .telling{font-weight:400;color:var(--muted);font-size:var(--text-xs);font-style:italic}
/* Een gearchiveerde registratie draagt dat in haar eigen kop uit; de regel eronder zegt wat het betekent en
   biedt meteen de weg terug. */
.pb-regarch{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:12px;padding:10px 12px;
  border:1px solid var(--line);border-radius:8px;background:var(--surface-2)}
details.acc.pb-gearchiveerd > summary{color:var(--muted)}

/* ── beheerscherm Categorieën ──
   Zelfde tabelvorm als .regtabel hierboven (kaartrand, koprij op --surface-2, regel per rij): het is
   dezelfde soort lijst en hoort er niet anders uit te zien. Alleen de naamkolom is lager van binnen,
   omdat daar een invoerveld in staat dat zelf al hoogte meebrengt. */
.cattabel{width:100%;border-collapse:collapse;font-size:var(--text-sm)}
.cattabel thead th{position:static;background:var(--surface-2);text-align:left;padding:9px 14px;
  font-size:var(--text-sm);font-weight:650;color:var(--ink-soft);border-bottom:1px solid var(--line);
  white-space:nowrap}
.cattabel th.k-volg{width:70px}
.cattabel th.k-aantal{width:120px;text-align:right}
.cattabel th.k-del{width:120px}
.cattabel td{padding:8px 14px;border-bottom:1px solid var(--line);vertical-align:middle}
.cattabel tbody tr:last-child td{border-bottom:none}
.cattabel td.c-naam{padding:6px 14px}
.cattabel td.c-aantal{text-align:right;font-variant-numeric:tabular-nums}
.volgknoppen{display:flex;gap:var(--space-1)}
/* 24px is bewust klein: deze twee knoppen staan naast elkaar in een smalle kolom en verplaatsen één regel.
   De volgorde is ook zonder muis te wijzigen omdat de knoppen gewone <button>-elementen zijn. */
.volgknoppen button{width:24px;height:24px;min-height:0;padding:0;border:1px solid var(--line-strong);border-radius:6px;
  background:var(--surface);color:var(--muted);line-height:1}
.cat-naam{width:100%;max-width:420px;padding:6px 9px;border:1px solid var(--line-strong);
  border-radius:var(--r-sm);background:var(--surface);font-size:var(--text-sm);font-weight:600}
/* Verwijderen is onomkeerbaar en leest daarom rood, met dezelfde tokens als button.danger (de knop achter
   `gevaarlijk: true` in FDialogen) — geen eigen rood erbij.
   ⚠ Tekst is --on-red-soft en niet --red: --red op --surface haalt 4,37:1 licht en 3,98:1 donker en zakt
   daarmee onder de 4,5:1 van WCAG AA. Als rand mag --red wél (niet-tekst, eis 3:1). */
.cat-del{min-height:30px;padding:5px 11px;border:1px solid var(--red);border-radius:var(--r-sm);background:var(--surface);
  color:var(--on-red-soft);font-size:var(--text-xs);font-weight:600}
.cat-del:hover{background:var(--red-soft)}
/* Geblokkeerd (categorie nog in gebruik) is méér dan lichter: de globale `opacity:.45` maakt de tekst
   onleesbaar (1,90:1) en dooft alleen. Hier dus drie signalen naast elkaar — het rood is wég, de rand is
   gestreept en de vulling is gedempt — zodat "niet nu" ook zonder kleurwaarneming leesbaar blijft. */
.cat-del:disabled{opacity:1;background:var(--surface-2);border:1px dashed var(--line-strong);
  color:var(--muted);font-weight:500}
.cat-del:disabled:hover{background:var(--surface-2)}
/* Toevoegen staat ónder de tabel, niet als lege regel erin: een nieuwe categorie is een aparte handeling
   en hoort niet tussen de bestaande te staan. 280px is de breedte waarop een categorienaam volledig past. */
.cat-toevoegen{display:flex;gap:var(--space-2);align-items:center;flex-wrap:wrap;margin-top:var(--space-3)}
.cat-toevoegen input{min-width:280px;padding:8px 11px;border:1px solid var(--line-strong);
  border-radius:var(--r-sm)}

/* ── badges en scores ───────────────────────────────────────────────────────────────────────────── */
.badge{display:inline-flex;align-items:center;min-height:22px;padding:2px 9px;border-radius:var(--r-pill);
  font-size:11.5px;font-weight:700;border:1px solid var(--line-strong);background:var(--surface-3);
  color:var(--ink-soft)}
/* Een badge zonder tekst is géén badge. Met `display:inline-block` en een binnenruimte van 1px viel een
   leeg exemplaar (#permBadge staat leeg zodra u geen bijzonder recht hebt) niet op; met een vaste hoogte
   van 22px is het ineens een lege pil in de kop. Verbergen in plaats van elke aanroepplek laten opruimen. */
.badge:empty{display:none}
.badge.groen{background:var(--green-soft);color:var(--on-green-soft);border-color:transparent}
.badge.rood{background:var(--red-soft);color:var(--on-red-soft);border-color:transparent}
.badge.amber{background:var(--amber-soft);color:var(--on-amber-soft);border-color:transparent}
.badge.paars{background:var(--primary-soft);color:var(--primary-strong);border-color:transparent}
.chip{display:inline-block;font-size:var(--text-xs);padding:1px 7px;border-radius:var(--r-sm);background:var(--surface-3);margin:1px 2px 1px 0}
/* "Extern" staat in de rollenkolom maar is geen ISMS-rol: omlijnd in plaats van gevuld, zodat het oog het
   onderscheidt van een rol die wél rechten geeft. */
.chip.extern{background:transparent;border:1px dashed var(--line-strong);color:var(--muted)}
.sc{display:inline-block;min-width:26px;text-align:center;padding:1px 7px;border-radius:var(--r-sm);font-weight:650;font-variant-numeric:tabular-nums}
.sc.l{background:var(--green-soft);color:var(--on-green-soft)}
.sc.m{background:var(--amber-soft);color:var(--on-amber-soft)}
.sc.h{background:var(--orange-soft);color:var(--on-orange-soft)}
.sc.x{background:var(--red-soft);color:var(--on-red-soft)}

/* ── accordeon + overzichtskaarten ──────────────────────────────────────────────────────────────── */
details.acc{background:var(--surface);border:1px solid var(--line);border-radius:var(--r-md);margin-bottom:var(--space-2);box-shadow:var(--shadow-sm)}
details.acc>summary{cursor:pointer;padding:9px var(--space-3);display:flex;gap:var(--space-2);align-items:center;
  font-weight:600;font-size:var(--text-sm);border-radius:var(--r-md);list-style:none}
details.acc>summary::-webkit-details-marker{display:none}
details.acc[open]>summary{border-bottom:1px solid var(--line);border-radius:var(--r-md) var(--r-md) 0 0}
details.acc>summary:hover{background:var(--surface-2)}
details.acc .acc-body{padding:var(--space-3)}
details.acc .telling{font-weight:400;color:var(--muted);font-size:var(--text-xs)}
.regkaart{display:grid;grid-template-columns:1fr auto auto auto auto;gap:var(--space-3);align-items:center;
  padding:9px var(--space-3);border-top:1px solid var(--line)}
.regkaart:first-child{border-top:none}

/* ── dialogen ───────────────────────────────────────────────────────────────────────────────────── */
dialog{border:none;border-radius:var(--r-lg);padding:0;width:min(960px,96vw);box-shadow:var(--shadow-lg);
  background:var(--surface);color:var(--ink)}
dialog.breed{width:min(1200px,97vw)}
dialog.smal{width:min(520px,94vw)}
dialog::backdrop{background:rgba(15,17,23,.5);backdrop-filter:blur(2px)}
.dlg-h{padding:var(--space-3) var(--space-4);border-bottom:1px solid var(--line);display:flex;align-items:center;gap:var(--space-3)}
.dlg-b{padding:var(--space-4);max-height:72vh;overflow:auto}
.dlg-b p{margin:0 0 var(--space-2)}
.dlg-f{padding:var(--space-3) var(--space-4);border-top:1px solid var(--line);display:flex;gap:var(--space-2);
  justify-content:flex-end;background:var(--surface-2)}
/* ── formulieren ──
   Label BOVEN het veld, niet links in een kolom van 210px. Besluit B-006 (12-08-2026): de ISMS-app volgt
   hierin de facturatie-app en het ontwerpblad, zodat er één designsysteem is en niet twee. Links was
   compacter — de bewerkdialoog van een risico wordt ruim de helft langer — maar één kolombreedte moet voor
   álle 31 registraties werken, en bij een lang label liep die vol; onder 900px werd hij bovendien krap.

   ⚠ De markup is ONGEWIJZIGD gebleven: label en veld zijn nog steeds twee zusters in dezelfde grid, op
   acht plekken in vijf modules. De stapeling komt hier uit de marges van het label en niet uit een tweede
   grid-niveau, zodat er geen enkele dialoog verbouwd hoefde te worden. `gap:0` is daarvoor nodig: de
   ruimte tussen een veld en het vólgende label zit in `margin-top` van dat label, en met een rij-gap
   erbovenop zou die twee keer meetellen. */
.form{display:grid;grid-template-columns:1fr;gap:0}
.form>label{font-size:12.5px;font-weight:600;color:var(--muted);margin:var(--space-3) 0 6px}
.form>label:first-child{margin-top:0}
.form .full{grid-column:1/-1}
.form.sub{padding:var(--space-2) var(--space-3);border-top:1px solid var(--line)}
.sub-rij{display:flex;gap:6px;align-items:flex-start}
fieldset{border:1px solid var(--line);border-radius:var(--r-md);margin:var(--space-3) 0 0;padding:var(--space-2)}
legend{font-size:var(--text-xs);color:var(--muted);padding:0 var(--space-1)}
.fs-actie{padding:var(--space-2);display:flex;gap:var(--space-2);flex-wrap:wrap;align-items:center}
.rec-acties{margin-top:var(--space-3);display:flex;gap:var(--space-2);flex-wrap:wrap;align-items:center}
.regel-meta{margin:0 0 var(--space-3)}
.ro{background:var(--amber-soft);color:var(--on-amber-soft);padding:7px 11px;border-radius:var(--r-sm);
  font-size:var(--text-sm);margin-bottom:var(--space-3)}
.fouten{background:var(--red-soft);color:var(--on-red-soft);padding:7px 11px;border-radius:var(--r-sm);
  font-size:var(--text-sm);margin-bottom:var(--space-3)}
.fouten ul{margin:4px 0 0 18px}
.rol-keuze{display:flex;flex-wrap:wrap;gap:2px}
.paneel-nav{display:flex;gap:2px;border-bottom:1px solid var(--line);margin-bottom:var(--space-3);flex-wrap:wrap}
.paneel-nav button{border:none;background:none;border-bottom:2px solid transparent;border-radius:0;
  min-height:0;font-weight:400;color:var(--muted);padding:7px 11px}
.paneel-nav button.active{color:var(--ink);font-weight:650;border-bottom-color:var(--primary)}
ul.wi,ol.wi{margin:var(--space-2) 0 0 18px}
ul.wi li,ol.wi li{margin:4px 0}
.log{font-size:var(--text-xs);font-variant-numeric:tabular-nums}

/* ── meldingen (toast) ──────────────────────────────────────────────────────────────────────────── */
.toast{position:fixed;bottom:20px;left:50%;transform:translateX(-50%);background:var(--ink);color:var(--canvas);
  padding:10px 18px;border-radius:var(--r-pill);box-shadow:var(--shadow-md);z-index:99;font-size:var(--text-sm);
  max-width:80vw;display:flex;align-items:center;gap:var(--space-3)}
/* ⚠ De achtergrond van een gekleurde melding is NIET `--primary`/`--green`/`--red`: op die waarden haalt
   witte tekst van 13px de 4.5:1 van WCAG AA niet (gemeten met axe: 3.58:1 voor indigo in het donkere thema,
   3.47:1 voor groen, en 2.6:1 voor de actieknop erin). Daarom eigen, donkerder tokens die in béide thema's
   dezelfde waarde houden — een melding is een gekleurde chip en leest ook op een donkere pagina goed.
   Gemeten contrast met wit: indigo 6.8:1 · groen 6.5:1 · rood 7.0:1. */
.toast.fout{background:var(--toast-fout);color:#fff}
/* Soorten en actieknop gelijk aan de facturatie-app (.app-toast daar): een melding met een knop is een
   rechthoek met afgeronde hoeken, geen pil, en `info` is indigo — dat onderscheidt een "er is iets voor u
   te doen"-melding van een gewone bevestiging. */
.toast.info{background:var(--toast-info);color:#fff}
.toast.goed{background:var(--toast-goed);color:#fff}
.toast:has(button){border-radius:12px;padding:11px 16px}
/* Donkerder maken en niet lichter: op een gekleurde achtergrond haalt witte tekst op een
   opgelichte vlek de contrasteis niet (2.6:1 gemeten). */
.toast button{background:rgba(0,0,0,.25);border:0;color:#fff;border-radius:var(--r-sm);min-height:0;
  padding:5px 12px;font-size:var(--text-sm);font-weight:600;cursor:pointer;flex:none;white-space:nowrap}
.toast button:hover{background:rgba(0,0,0,.38)}
/* Sluitknop op een melding die niet vanzelf verdwijnt: rond, smal, en visueel ondergeschikt aan de
   actieknop ernaast — wegklikken is de uitweg, niet de bedoelde handeling. 28px blijft binnen de
   toucheis omdat de hele melding onderaan het scherm vrij staat. */
/* ⚠ Dekking niet onder .9 zetten: wit op .75 over het indigo van een info-melding meet 4,4:1 en haalt
   daarmee de 4.5:1 van WCAG AA niet (× is 18px en telt niet als grote tekst). Op .9 is het 5,6:1. */
.toast button.sluit{background:transparent;padding:0;width:28px;height:28px;min-height:0;border-radius:50%;
  font-size:18px;line-height:1;opacity:.9;margin-left:calc(var(--space-3) * -1 + 2px)}
.toast button.sluit:hover{background:rgba(0,0,0,.28);opacity:1}

/* ── dekkende lagen: versiegate, slot, laden ────────────────────────────────────────────────────── */
.gate{position:fixed;inset:0;z-index:400;background:var(--canvas);display:flex;align-items:center;
  justify-content:center;padding:var(--space-4)}
/* Dezelfde kaart als het aanmeldscherm, en dus dezelfde als `.login-card` in de facturatie-app: 24px
   binnenruimte, 400px breed, 12px ertussen, de titel op --text-2xl en een knop over de volle breedte. Het
   slot en het aanmeldscherm zijn dezelfde soort onderbreking en hoorden er nooit anders uit te zien; de kop
   viel hier terug op de globale h2 (18px) en de knop op zijn inhoudsbreedte. */
.gate .card{padding:var(--space-6);width:100%;max-width:400px;display:grid;gap:var(--space-3);
  box-shadow:var(--shadow-md)}
.gate .card h2{font-size:var(--text-2xl);font-weight:700;margin:0;letter-spacing:-.02em}
.gate .card p{margin:0;font-size:var(--text-sm)}
.gate .card button.primary{width:100%;justify-content:center}
.gate .card .schakel{background:none;border:0;color:var(--primary);font-size:var(--text-sm);cursor:pointer;
  min-height:0;font-weight:400;padding:0;justify-self:start;text-decoration:underline}
/* Laadscherm tijdens het lezen uit de gedeelde opslag. Dat duurt seconden, en zonder deze laag kijkt de
   gebruiker naar een leeg scherm en weet hij niet of de app hangt. */
#laadOverlay{position:fixed;inset:0;z-index:350;background:var(--canvas);display:flex;align-items:center;
  justify-content:center;padding:var(--space-4)}
.laad-kaart{background:var(--surface);border:1px solid var(--line);border-radius:var(--r-lg);
  box-shadow:var(--shadow-md);padding:var(--space-6);width:min(360px,92vw);display:grid;
  gap:var(--space-3);justify-items:center;text-align:center}
.spinner{width:26px;height:26px;border-radius:var(--r-pill);border:3px solid var(--primary-soft);
  border-top-color:var(--primary);animation:draai .8s linear infinite}
@keyframes draai{to{transform:rotate(360deg)}}
.laad-spoor{width:100%;height:5px;border-radius:var(--r-pill);background:var(--surface-3);overflow:hidden}
.laad-balk{height:100%;width:35%;background:var(--primary);border-radius:var(--r-pill);
  animation:schuif 1.4s ease-in-out infinite}
@keyframes schuif{0%{margin-left:-35%}100%{margin-left:100%}}
@media (prefers-reduced-motion:reduce){
  .spinner{animation:none}
  .laad-balk{animation:none;width:100%}
}
.laad-detail{font-size:var(--text-xs);color:var(--muted)}

/* ── snelzoeken (Ctrl+K, app/zoeken.js) ─────────────────────────────────────────────────────────── */
#zoekOverlay{position:fixed;inset:0;z-index:380;background:rgba(15,17,23,.45);backdrop-filter:blur(2px);
  display:flex;align-items:flex-start;justify-content:center;padding:10vh var(--space-4) var(--space-4)}
.zoek-kaart{background:var(--surface);border:1px solid var(--line);border-radius:var(--r-lg);
  box-shadow:var(--shadow-lg);width:min(620px,96vw);overflow:hidden}
.zoek-kaart input{width:100%;border:0;border-bottom:1px solid var(--line);border-radius:0;
  padding:var(--space-4);font-size:var(--text-lg);background:var(--surface)}
.zoek-kaart input:focus-visible{outline:none;border-bottom-color:var(--primary)}
.zoek-uitslag{max-height:52vh;overflow:auto}
.zoek-groep{font-size:var(--text-xs);text-transform:uppercase;letter-spacing:.07em;color:var(--muted);
  padding:var(--space-3) var(--space-4) var(--space-1)}
.zoek-regel{display:flex;flex-direction:column;align-items:flex-start;gap:1px;width:100%;border:0;font-weight:400;
  border-radius:0;background:none;text-align:left;padding:7px var(--space-4);cursor:pointer}
.zoek-regel:hover,.zoek-regel.actief{background:var(--primary-soft)}
.zoek-titel{font-size:var(--text-base);color:var(--ink)}
.zoek-onder{font-size:var(--text-xs)}
.zoek-hint{padding:var(--space-2) var(--space-4);border-top:1px solid var(--line);font-size:var(--text-xs);
  background:var(--surface-2)}
.zoek-leeg{padding:var(--space-4)}

/* ── aanmeldscherm ──────────────────────────────────────────────────────────────────────────────── */
/* Eén compacte kaart, zelfde opzet als de facturatie-app (.login-card daar): appnaam, één regel uitleg,
   één knop. Geen procesuitleg op een aanmeldscherm. */
.login{min-height:100vh;display:flex;align-items:center;justify-content:center;padding:var(--space-4);
  background-image:radial-gradient(120% 120% at 50% 0%,var(--primary-soft) 0%,transparent 55%)}
.login .card{padding:var(--space-6);width:100%;max-width:400px;box-shadow:var(--shadow-md);
  display:grid;gap:var(--space-3)}
.login h1{font-size:var(--text-2xl);margin:0;letter-spacing:-.02em}
.login .sub{color:var(--muted);font-size:var(--text-sm);margin:0}
.login #loginBody{display:grid;gap:var(--space-3)}
.login #loginBody p{margin:0;color:var(--ink-soft)}
.login button{width:100%;justify-content:center}
.login .schakel{background:none;border:0;color:var(--primary);font-size:var(--text-sm);cursor:pointer;min-height:0;font-weight:400;
  padding:0;width:auto;justify-self:start;text-decoration:underline}
.login-fout{color:var(--on-red-soft);background:var(--red-soft);padding:7px 11px;border-radius:var(--r-sm);
  font-size:var(--text-sm)}

/* Meervoudige verwijzing (bijv. twee verantwoordelijken): een aankruislijst in plaats van een
   <select multiple>, die ctrl-klikken vraagt en maar een paar regels tegelijk toont. Scrollt bij een
   lange lijst, zodat de dialoog zelf niet uitrekt. */
.meerkeuze{display:flex;flex-direction:column;gap:2px;max-height:190px;overflow-y:auto;
  border:1px solid var(--line);border-radius:var(--r-sm);padding:var(--space-2);margin:0;background:var(--bg)}
.meerkeuze-optie{display:flex;align-items:center;gap:var(--space-2);font-size:var(--text-sm);
  padding:3px 4px;border-radius:var(--r-sm);cursor:pointer}
.meerkeuze-optie:hover{background:var(--bg-soft)}
.meerkeuze input{width:auto;margin:0}
.meerkeuze:focus-within{outline:2px solid var(--primary);outline-offset:1px}
