/* app.css — base layout + the fixed component vocabulary (STYLE.md §5, D-110):
 * list · table · form · badge · card · button · panel (overlay) · signaalregel.
 * Tokens come from tokens.css (generated from STYLE.md — never restyle ad hoc).
 * Laptop-first ~1366×768 (D-112); fluid grid + container queries + two
 * content-driven breakpoints (~640 / ~1024). */

* { box-sizing: border-box; }

html { height: 100%; }

body {
  margin: 0;
  min-height: 100%;
  font-family: var(--font-basis);
  font-size: var(--maat-14);
  line-height: var(--regelhoogte-basis);
  color: var(--tekst);
  background: var(--wit);
}

/* ---- Typography --------------------------------------------------------- */

h1, h2, h3 {
  font-family: var(--font-kop);
  color: var(--kleur-kop);
  margin: 0 0 var(--ruimte-12);
}
h1 { font-size: var(--maat-20); font-weight: 600; }
h2 { font-size: var(--maat-16); font-weight: 600; }
h3 { font-size: var(--maat-14); font-weight: 600; }

a { color: var(--kleur-primair); }
a:hover { text-decoration-thickness: 2px; }

.gedempt { color: var(--tekst-gedempt); }
.klein { font-size: var(--maat-12); }

/* Times, counts, money. */
.numeriek { font-variant-numeric: tabular-nums; }

/* Merk-regel: letter-spaced caps, Montserrat SemiBold 12px, primair. */
.merkregel {
  font-family: var(--font-kop);
  font-weight: 600;
  font-size: var(--maat-12);
  letter-spacing: var(--letterafstand-merk);
  text-transform: uppercase;
  color: var(--kleur-primair);
}

/* Dotted-line motif (from the logo) as a section divider — sparing. */
.stippellijn {
  border: none;
  border-top: 3px dotted var(--kleur-merk-rood);
  margin: var(--ruimte-24) 0;
}
.stippellijn-primair { border-top-color: var(--kleur-primair); }

/* ---- Focus (the only shadow in the app) --------------------------------- */

:focus-visible {
  outline: 2px solid var(--kleur-primair);
  outline-offset: 1px;
  box-shadow: var(--focusring);
}

/* ---- Header & nav: fixed shallow bar (D-103, D-112 vertical economy) ---- */

.kop-balk {
  position: sticky;
  top: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  gap: var(--ruimte-24);
  padding: 0 var(--ruimte-16);
  min-height: 48px;
  background: var(--wit);
  border-bottom: 1px solid var(--rand);
}

/* Archief-modus (W-050, D-033): the unmistakable visual shift — muted panel
 * fill instead of white, plus a merk-rood baseline (the same "editie marker"
 * use of merk-rood as .badge-editie, D-119) — existing tokens only. */
.kop-balk--archief {
  background: var(--vlak);
  border-bottom: 1px solid var(--kleur-merk-rood);
}

.merk {
  font-family: var(--font-kop);
  font-weight: 600;
  font-size: var(--maat-12);
  letter-spacing: var(--letterafstand-merk);
  text-transform: uppercase;
  color: var(--kleur-primair);
  text-decoration: none;
  white-space: nowrap;
}

/* Actieve persoon in de kop (W-171, D-101). Rechts uitgelijnd omdat de
 * persoonsschil daar niets anders heeft staan (geen hoofdnav, geen kop-acties);
 * de bestuursschil krijgt dit blok niet, dus het botst niet met .uitloggen dat
 * dezelfde margin-left gebruikt. Bestaande tokens, geen nieuwe kleuren.
 * De naam wordt nooit afgekapt — hem onleesbaar maken haalt de hele reden weg —
 * dus hij mag afbreken en de kop meegroeien (min-height, geen height). */
.kop-persoon {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: var(--ruimte-8);
  min-width: 0;
  padding: var(--ruimte-4) 0;
  font-size: var(--maat-12);
  line-height: 1.3;
}

.kop-persoon-label { color: var(--tekst-gedempt); }
.kop-persoon strong { color: var(--kleur-kop); overflow-wrap: anywhere; }

.kop-avatar {
  width: 28px;
  height: 28px;
  flex: none;
  border-radius: 50%;
  object-fit: cover;
  border: 1px solid var(--rand);
}

.hoofdnav {
  display: flex;
  gap: var(--ruimte-4);
  overflow-x: auto;              /* nav never wraps to a second row */
  -webkit-overflow-scrolling: touch;
}

.hoofdnav a {
  font-family: var(--font-kop);
  font-weight: 500;
  font-size: 15px;
  color: var(--tekst);
  text-decoration: none;
  padding: 13px var(--ruimte-8) 11px;
  border-bottom: 2px solid transparent;
  white-space: nowrap;
}

.hoofdnav a:hover { color: var(--kleur-primair); background: var(--kleur-selectie); }

.hoofdnav a.actief {
  color: var(--kleur-primair);
  font-weight: 600;
  border-bottom-color: var(--kleur-primair);
}

/* ---- Page shell --------------------------------------------------------- */

main {
  max-width: var(--inhoud-max); /* line-length ceiling, fluid below it */
  margin: 0 auto;
  padding: var(--ruimte-24) var(--ruimte-16);
}

.pagina-kop {
  display: flex;
  align-items: baseline;
  gap: var(--ruimte-12);
  flex-wrap: wrap;
  margin-bottom: var(--ruimte-16);
}
.pagina-kop h1 { margin-bottom: 0; }

section + section { margin-top: var(--ruimte-24); }

/* Fluid grid: columns reflow by available space, no breakpoint soup. */
.grid-fluid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr));
  gap: var(--ruimte-16);
}

/* ---- Buttons: two variants only (STYLE.md §5) --------------------------- */

.knop {
  display: inline-flex;
  align-items: center;
  gap: var(--ruimte-8);
  padding: var(--knopvulling);
  font-family: var(--font-basis);
  font-size: var(--maat-14);
  line-height: 1.2;
  border-radius: var(--radius-knop);
  cursor: pointer;
  text-decoration: none;
}

/* Primair: blauw gevuld. */
.knop-primair {
  background: var(--kleur-primair);
  color: var(--wit);
  border: 1px solid var(--kleur-primair);
}
.knop-primair:hover { background: var(--kleur-kop); border-color: var(--kleur-kop); }

/* Secundair: wit, blauwe rand. */
.knop-secundair {
  background: var(--wit);
  color: var(--kleur-primair);
  border: 1px solid var(--kleur-primair);
}
.knop-secundair:hover { background: var(--kleur-selectie); }

/* Destructief = secundair met signaalrood tekst. */
.knop-destructief {
  background: var(--wit);
  color: var(--signaalrood);
  border: 1px solid var(--signaalrood);
}
.knop-destructief:hover { background: var(--sein-rood-vlak); }

.knop:disabled, .knop[aria-disabled="true"] {
  opacity: 0.5;
  cursor: not-allowed;
}

@media (pointer: coarse) {
  .knop { min-height: var(--aanraakdoel); } /* D-092 touch targets */
}

/* ---- Badges: pill (STYLE.md §3) ----------------------------------------- */

.badge {
  display: inline-block;
  padding: 1px 10px;
  border-radius: var(--radius-pil);
  font-size: var(--maat-12);
  line-height: 1.6;
  background: var(--vlak);
  color: var(--tekst-gedempt);
  border: 1px solid var(--rand);
}
.badge-groen { background: var(--sein-groen-vlak); color: var(--sein-groen-tekst); border-color: transparent; }
.badge-amber { background: var(--sein-amber-vlak); color: var(--sein-amber-tekst); border-color: transparent; }
.badge-rood  { background: var(--sein-rood-vlak);  color: var(--sein-rood-tekst);  border-color: transparent; }
/* Editie marker: merk-rood is identity, never error (D-119). */
.badge-editie { background: var(--wit); color: var(--kleur-merk-rood); border-color: var(--kleur-merk-rood); }

/* ---- Cards -------------------------------------------------------------- */

.kaart {
  background: var(--wit);
  border: 1px solid var(--rand);
  border-radius: var(--radius-kaart);
  padding: var(--ruimte-16);
}

.kaart h2, .kaart h3 { margin-bottom: var(--ruimte-8); }

/* Container queries: cards adapt to their container, which makes D-112's
 * overlay side panels cheap. */
.kaart-houder { container-type: inline-size; }

.persoon-kaart {
  display: flex;
  gap: var(--ruimte-12);
  align-items: center;
}
.persoon-kaart .avatar {
  width: 40px;
  height: 40px;
  flex: none;
  border-radius: 50%;
  background: var(--kleur-selectie);
  color: var(--kleur-primair);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-kop);
  font-weight: 600;
}
@container (max-width: 240px) {
  .persoon-kaart { flex-direction: column; align-items: flex-start; }
}

/* ---- Lists (dense, in-list references clickable — D-092) ---------------- */

.lijst {
  list-style: none;
  margin: 0;
  padding: 0;
  border: 1px solid var(--rand);
  border-radius: var(--radius-knop);
}

.lijst li {
  display: flex;
  align-items: center;
  gap: var(--ruimte-12);
  padding: var(--ruimte-8) var(--ruimte-12);
  font-size: var(--maat-13);
  line-height: var(--regelhoogte-dicht);
}
.lijst li + li { border-top: 1px solid var(--rand); }
.lijst li:hover { background: var(--kleur-selectie); }
.lijst .meta { margin-left: auto; color: var(--tekst-gedempt); font-size: var(--maat-12); }

/* ---- Tables (dense UI, column priority — D-112/D-113) ------------------- */

.tabel-houder { overflow-x: auto; } /* horizontal scroll is last resort, never strategy */

table.tabel {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--maat-13);
  line-height: var(--regelhoogte-dicht);
}

.tabel th {
  text-align: left;
  font-family: var(--font-kop);
  font-weight: 600;
  font-size: var(--maat-12);
  color: var(--kleur-kop);
  background: var(--vlak);
  padding: var(--celvulling);
  border-bottom: 1px solid var(--rand);
}

.tabel td {
  padding: var(--celvulling);
  border-bottom: 1px solid var(--rand);
}

.tabel tbody tr:hover { background: var(--kleur-selectie); }
.tabel tr.actief { background: var(--kleur-selectie); }

/* Column priority: essential columns always survive; useful ones drop below
 * ~1024px, nice-to-have below ~640px. Detail stays one click away. */
@media (max-width: 1023px) { .kol-extra  { display: none; } }
@media (max-width: 639px)  { .kol-nuttig { display: none; } }

/* Coverage cells (rooster family). Vier standen, D-232(5): leeg rood, deels
 * amber, vol-maar-iets-nog-concept blauw, vol-en-gepubliceerd groen. Blauw zit
 * tussen compleet en gepubliceerd in — bemenst, maar nog niet iedereen weet
 * het — dus groen betekent "af". Kleur is nooit het enige kanaal: de teller en
 * het woord "(concept)" staan er als tekst naast. */
.cel-vol     { background: var(--sein-groen-vlak); color: var(--sein-groen-tekst); }
.cel-concept { background: var(--sein-blauw-vlak); color: var(--sein-blauw-tekst); }
.cel-deels   { background: var(--sein-amber-vlak); color: var(--sein-amber-tekst); }
.cel-leeg    { background: var(--sein-rood-vlak);  color: var(--sein-rood-tekst); }

/* ---- Forms -------------------------------------------------------------- */

.formulier { display: grid; gap: var(--ruimte-12); max-width: 560px; }

.veld { display: grid; gap: var(--ruimte-4); }

.veld label {
  font-family: var(--font-kop);
  font-weight: 500;
  font-size: var(--maat-13);
  color: var(--kleur-kop);
}

.veld input[type="text"],
.veld input[type="search"],
.veld input[type="email"],
.veld input[type="number"],
.veld input[type="date"],
.veld input[type="time"],
.veld select,
.veld textarea {
  font-family: var(--font-basis);
  font-size: var(--maat-14);
  padding: var(--invoervulling);
  border: 1px solid var(--rand-invoer);
  border-radius: var(--radius-knop);
  background: var(--wit);
  color: var(--tekst);
  width: 100%;
}

.veld .hulp { font-size: var(--maat-12); color: var(--tekst-gedempt); }

/* Error state: calmer semantic red, never merk-rood. */
.veld.fout input, .veld.fout select, .veld.fout textarea { border-color: var(--signaalrood); }
.veld .foutmelding { font-size: var(--maat-12); color: var(--signaalrood); }

.keuze { display: flex; align-items: center; gap: var(--ruimte-8); font-size: var(--maat-14); }
.keuze label { font-family: var(--font-basis); font-weight: 400; color: var(--tekst); }

.formulier-acties { display: flex; gap: var(--ruimte-8); margin-top: var(--ruimte-4); }

/* Wider variant for forms that carry a map pane. */
.formulier-breed { max-width: 760px; }

/* Fieldsets group without chrome; the legend is the section head. */
.formulier fieldset {
  border: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: var(--ruimte-8);
}
.formulier legend {
  font-family: var(--font-kop);
  font-weight: 600;
  font-size: var(--maat-14);
  color: var(--kleur-kop);
  padding: 0;
  margin-bottom: var(--ruimte-4);
}
.formulier fieldset + fieldset { margin-top: var(--ruimte-16); }

/* Short fields side by side, reflowing by available space. */
.veldgroep {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: var(--ruimte-12);
}

/* Label look for grouped controls that have no single <label>. */
.veldlabel {
  font-family: var(--font-kop);
  font-weight: 500;
  font-size: var(--maat-13);
  color: var(--kleur-kop);
}

@media (pointer: coarse) {
  .veld input, .veld select { min-height: var(--aanraakdoel); }
}

/* ---- Panel (overlay side panel — D-112: overlay, never squeeze) --------- */

.paneel {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  width: min(420px, 100%);
  z-index: 20;
  background: var(--wit);
  border-left: 1px solid var(--rand);
  padding: var(--ruimte-16);
  overflow-y: auto;
}

.paneel-kop {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--ruimte-12);
  margin-bottom: var(--ruimte-12);
}
.paneel-kop h2 { margin: 0; }

@media (max-width: 639px) {
  .paneel { width: 100%; border-left: none; } /* single column below ~640 */
}

/* ---- Signaalregel (⚠ count → click, D-093 anti-dashboard shape) --------- */

.signaalregel {
  display: flex;
  align-items: center;
  gap: var(--ruimte-8);
  padding: var(--ruimte-8) var(--ruimte-12);
  border: 1px solid var(--rand);
  border-left: 3px solid var(--signaalrood);
  border-radius: var(--radius-knop);
  font-size: var(--maat-13);
  color: var(--tekst);
  text-decoration: none;
}
.signaalregel:hover { background: var(--kleur-selectie); }
.signaalregel .aantal {
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  color: var(--signaalrood);
}
.signaalregel .pijl { margin-left: auto; color: var(--kleur-primair); }
.signaalregels { display: grid; gap: var(--ruimte-8); }

/* ---- Empty state (skyline illustrations, STYLE.md §6) ------------------- */

.leegstand {
  display: grid;
  justify-items: center;
  gap: var(--ruimte-12);
  padding: var(--ruimte-24);
  text-align: center;
  color: var(--tekst-gedempt);
}
.leegstand img { max-width: 100%; height: 96px; }
.leegstand p { margin: 0; }

/* ---- Global search (home front door, D-104) ----------------------------- */

.zoek-groot { max-width: 560px; margin: 0 auto; }
.zoek-groot input[type="search"] {
  width: 100%;
  font-size: var(--maat-16);
  padding: var(--ruimte-8) var(--ruimte-12);
  border: 1px solid var(--rand-invoer);
  border-radius: var(--radius-knop);
}
#zoekresultaten { max-width: 560px; margin: var(--ruimte-8) auto 0; }

/* ---- Utilities ---------------------------------------------------------- */

img { max-width: 100%; }

/* Full-width readonly field (e.g. the enrollment link to copy). */
.veld-breed { width: 100%; box-sizing: border-box; }

.rij { display: flex; align-items: center; gap: var(--ruimte-8); flex-wrap: wrap; }

.mt-16 { margin-top: var(--ruimte-16); }
.mb-16 { margin-bottom: var(--ruimte-16); }

.persoon-kaart p { margin: 0; }

/* Color swatches (stijlgids). Inline style= is blocked by the CSP
 * (style-src 'self'), so every swatch is a class. */
.staal {
  display: inline-block;
  width: 28px;
  height: 28px;
  border-radius: var(--radius-knop);
  border: 1px solid var(--rand);
  vertical-align: middle;
}
.staal-primair       { background: var(--kleur-primair); }
.staal-kop           { background: var(--kleur-kop); }
.staal-selectie      { background: var(--kleur-selectie); }
.staal-selectie-rand { background: var(--kleur-selectie-rand); }
.staal-merk-rood     { background: var(--kleur-merk-rood); }
.staal-signaalrood   { background: var(--signaalrood); }

/* Plain text with whitespace preserved — migrated long text is plain text by
 * design (D-118) and renders escaped with line breaks kept. */
.preline { white-space: pre-line; }

/* ---- List equipment (filter/sort/search toolbar — D-113) ---------------- */

.filterbalk {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--ruimte-12);
  margin-bottom: var(--ruimte-12);
}
.filterbalk .veld { min-width: 140px; }
.filterbalk .veld-zoek { flex: 1 1 220px; }

/* Filterpaneel (W-203): het scherm achter de Filter-knop. De vorm komt van de
 * bestaande .paneel-klasse hierboven — lade op breed, volledig scherm onder
 * ~640 (D-112's tweede breekpunt). Dat is met opzet CSS en geen Go-tak: de
 * viewport is server-side niet bekend bij het eerste verzoek, dus één partial
 * en één render-pad. Hieronder alleen wat .paneel nog niet had. */
.filterpaneel { z-index: 30; display: flex; flex-direction: column; }
.filterpaneel-form { max-width: none; overflow-y: auto; }

/* De acties blijven in beeld: op een telefoon vult het paneel het hele scherm
 * en zou Toepassen anders onder de vouw verdwijnen. */
.filterpaneel-acties {
  position: sticky;
  bottom: 0;
  align-items: center;
  flex-wrap: wrap;
  background: var(--wit);
  border-top: 1px solid var(--rand);
  padding-top: var(--ruimte-12);
  margin-top: var(--ruimte-8);
}

.filterpaneel-sluit {
  border: none;
  background: none;
  color: var(--tekst-gedempt);
  font-size: var(--maat-20);
  line-height: 1;
  padding: var(--ruimte-4);
  cursor: pointer;
}
.filterpaneel-sluit:hover { color: var(--tekst); }

/* De lege houder mag geen ruimte innemen zolang het paneel dicht is. */
.filterpaneel-houder:empty { display: none; }

/* W-204: hetzelfde paneel als pil-editor in Beheer. Daar staat het IN de
 * pagina, dus zonder de position:fixed-lade van .paneel — een editor die als
 * overlay over het beheerscherm valt zou de lijst met bestaande pillen
 * bedekken, precies wat je bij het samenstellen naast je wilt hebben. Verder
 * niets eigens: dezelfde velden, dezelfde .veld/.knop-vormgeving. */
.filterpaneel-ingebed {
  border: 1px solid var(--rand);
  border-radius: var(--radius-knop);
  padding: var(--ruimte-16);
  margin-top: var(--ruimte-12);
}
.filterpaneel-ingebed .filterpaneel-acties { position: static; }

/* Count + export row above a table. */
.toolbalk {
  display: flex;
  align-items: baseline;
  gap: var(--ruimte-12);
  margin-bottom: var(--ruimte-8);
}
.toolbalk .rechts { margin-left: auto; }

/* Sortable column headers: the link inherits the header look; the active
 * sort direction is a text arrow, not an icon font. */
.tabel th a { color: inherit; text-decoration: none; }
.tabel th a:hover { color: var(--kleur-primair); }
.tabel th .sorteer { color: var(--kleur-primair); }

/* ---- Key-value pairs on detail pages ------------------------------------ */

.gegevens {
  display: grid;
  grid-template-columns: minmax(120px, max-content) 1fr;
  gap: var(--ruimte-4) var(--ruimte-16);
  margin: 0;
  font-size: var(--maat-13);
  line-height: var(--regelhoogte-dicht);
}
.gegevens dt { color: var(--tekst-gedempt); }
.gegevens dd { margin: 0; }

/* ---- Map pane (Leaflet, D-098) ------------------------------------------ */

.kaart-vlak {
  height: 320px;
  border: 1px solid var(--rand);
  border-radius: var(--radius-knop);
}
.kaart-vlak-klein { height: 240px; }
.kaart-hulp { margin-top: var(--ruimte-4); }
.kaart-fout { margin-top: var(--ruimte-8); }

/* HTMX request feedback (class names unchanged in htmx 4). */
.htmx-indicator { display: none; }
.htmx-request .htmx-indicator { display: inline-block; }
.htmx-request.htmx-indicator { display: inline-block; }

/* ---- Uitloggen (kop-balk, auth package) ---------------------------------- */
.uitloggen { margin-left: auto; }
.uitloggen .knop { font-size: var(--maat-12); }

/* ---- Mijn Toneelroute (journey 1) — mobile-first personal page (D-112) ---- */

.mijn {
  max-width: 640px;
  margin: 0 auto;
  display: grid;
  gap: var(--ruimte-24, 24px);
}

.mijn-kop h1 { margin: var(--ruimte-4) 0 0; }

.mijn-sectie h2 {
  font-size: var(--maat-14);
  color: var(--tekst-gedempt);
  margin-bottom: var(--ruimte-8);
}

.mijn-lijst li { align-items: flex-start; }
.mijn-regel p { margin: 0; }
.mijn-regel { display: grid; gap: var(--ruimte-4); }

.eerstvolgende {
  background: var(--kleur-selectie);
  border-color: var(--kleur-selectie-rand);
}
.eerstvolgende p { margin: 0 0 var(--ruimte-4); }
.eerstvolgende-titel { font-weight: 600; color: var(--kleur-kop); }

.rsvp-acties { display: flex; gap: var(--ruimte-8); margin-top: var(--ruimte-8); }
.rsvp-acties .knop { flex: 1 1 auto; }

.avatar-groot {
  width: 96px;
  height: 96px;
  border-radius: 50%;
  object-fit: cover;
  border: 1px solid var(--rand);
}

.melding-ok {
  background: var(--sein-groen-vlak);
  color: var(--sein-groen-tekst);
  border-color: transparent;
}

/* Degraded state: something could not be determined. Deliberately amber and
   not green — "niet gemeten" mag nooit lezen als "in orde" (W-147). */
.melding-amber {
  background: var(--sein-amber-vlak);
  color: var(--sein-amber-tekst);
  border-color: transparent;
}

.mijn-voet {
  display: grid;
  gap: var(--ruimte-12);
  justify-items: center;
  padding-bottom: var(--ruimte-24, 24px);
}

.mijn-rol details summary { cursor: pointer; color: var(--kleur-primair); }

/* ===== Dienstenrooster (journey 2, package 7) =====================   Board + fill panel + beheer. Reuses the fixed vocabulary (card, badge,
   knop, tabel, filterbalk); the additions below are all board-specific
   (rooster-*) plus three generic utilities the vocabulary lacked
   (.inline, .destructief, .visueel-verborgen). MERGE NOTE: promote the three
   utilities into the shared vocabulary if another package needs them. */

.inline { display: inline-block; margin: 0; }
.destructief { color: var(--sein-rood-tekst); border-color: var(--rand-invoer); }
.visueel-verborgen {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* W-101 blok B: de dagkop van de eendaagse kalender — pijl, datum, pijl. */
.rooster-dagkop { display: flex; align-items: center; gap: var(--ruimte-12); margin-bottom: var(--ruimte-16); }
.rooster-dagtitel { font-size: var(--maat-20); margin: 0; }
.rooster-pijl {
  display: inline-flex; align-items: center; justify-content: center;
  width: 2.25rem; height: 2.25rem; border: 1px solid var(--rand); border-radius: 99px;
  color: var(--kleur-primair); text-decoration: none; font-size: var(--maat-20); line-height: 1;
}
.rooster-pijl:hover { background: var(--vlak); }
.rooster-pijl.uit { color: var(--tekst-gedempt); border-color: var(--rand-invoer); cursor: default; }
/* W-101 blok D: de dagbrede publiceerknop staat rechts in de dagkop, tegenover
   de pijlen. Geen waarschuwingstekst op de knop — de bevestigingsdialoog
   erachter is de rem (D-232(6)). */
.rooster-dagknop { margin-left: auto; }

.rooster-sectie { margin-bottom: var(--ruimte-24); }
.rooster-sectie-kop { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--ruimte-8); margin-bottom: var(--ruimte-8); }
.rooster-sectie-titel { font-size: var(--maat-16); margin: 0; }
.rooster-sectie-teller { font-size: var(--maat-13); color: var(--tekst-gedempt); font-variant-numeric: tabular-nums; }
.rooster-sectie-teller.open { color: var(--sein-rood-tekst); font-weight: 600; }

.rooster-werkblad { display: grid; grid-template-columns: 1fr; gap: var(--ruimte-16); }
@media (min-width: 1024px) { .rooster-werkblad { grid-template-columns: minmax(0, 2fr) minmax(280px, 1fr); align-items: start; } }

/* Hoogstens drie tegelkolommen (W-101 blok B). Expliciete breakpoints in plaats
   van auto-fit: dat laatste vult de breedte met zoveel kolommen als er passen,
   dus vier of vijf op een breed scherm. Bij één kolom voegt de tegel zich naar
   de volle breedte in plaats van een smal geworden kolomopmaak te houden.
   Bewaakt door TestRoosterTegelsHoogstensDrieKolommen. */
.rooster-kolommen { display: grid; grid-template-columns: 1fr; gap: var(--ruimte-12); }
@media (min-width: 640px) { .rooster-kolommen { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1280px) { .rooster-kolommen { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.rooster-kolom { border: 1px solid var(--rand); border-radius: 12px; overflow: hidden; }
.rooster-kolom-kop { padding: var(--ruimte-8); background: var(--vlak); border-bottom: 1px solid var(--rand); display: grid; gap: 2px; }
.rooster-locatie { font-weight: 600; color: var(--kleur-kop); }

/* W-101 blok C (D-232(5)): de tegel draagt de dekkingsklasse van zijn
 * SLECHTSTE slot, zodat een locatie met een gat vindbaar is terwijl je scrollt.
 * De kop wordt doorzichtig zodat de kleur van de tegel er doorheen komt — de
 * .cel-*-regel hierboven zet de vulling en de tekstkleur al — en de slotbanden
 * eronder houden hun eigen kleur, zodat je ziet wélk slot het gat is. */
.rooster-kolom.cel-vol > .rooster-kolom-kop,
.rooster-kolom.cel-concept > .rooster-kolom-kop,
.rooster-kolom.cel-deels > .rooster-kolom-kop,
.rooster-kolom.cel-leeg > .rooster-kolom-kop { background: transparent; }
.rooster-kolom.cel-vol .rooster-locatie,
.rooster-kolom.cel-concept .rooster-locatie,
.rooster-kolom.cel-deels .rooster-locatie,
.rooster-kolom.cel-leeg .rooster-locatie { color: inherit; }

.rooster-slot {
  display: grid; gap: 2px; width: 100%; text-align: left; cursor: pointer;
  padding: var(--ruimte-8); border: none; border-bottom: 1px solid var(--rand);
  font: inherit;
}
.rooster-slot:last-child { border-bottom: none; }
.rooster-slot:hover { filter: brightness(0.97); }
.rooster-slot.actief { outline: 3px solid var(--kleur-primair); outline-offset: -3px; }
.rooster-slot-tijd { font-weight: 600; }
.rooster-slot-teller { font-variant-numeric: tabular-nums; }
.rooster-slot-namen { font-size: var(--maat-12); }

.rooster-panel { border: 1px solid var(--rand); border-radius: 12px; padding: var(--ruimte-16); background: var(--wit); }
.rooster-panel h2 { font-size: var(--maat-16); margin: 0 0 var(--ruimte-4); }
.rooster-toegewezen, .rooster-kandidaten { list-style: none; margin: var(--ruimte-12) 0; padding: 0; display: grid; gap: var(--ruimte-8); }
.rooster-toegewezen li { display: flex; flex-wrap: wrap; align-items: center; gap: var(--ruimte-8); }
.rooster-toegewezen-naam { font-weight: 600; }
.rooster-kandidaat { border-top: 1px solid var(--rand); padding-top: var(--ruimte-8); display: grid; gap: var(--ruimte-4); }
.rooster-kandidaat-info { display: flex; flex-wrap: wrap; align-items: center; gap: var(--ruimte-8); }
.rooster-kandidaat-acties { display: flex; flex-wrap: wrap; gap: var(--ruimte-4); }
.rooster-conflict { color: var(--sein-rood-tekst); font-size: var(--maat-12); width: 100%; }
.rooster-zoek { margin: var(--ruimte-12) 0; }
.rooster-clone-blok { margin-top: var(--ruimte-16); }
.rooster-clone-blok summary { cursor: pointer; color: var(--kleur-primair); }
.rooster-beheer { display: grid; gap: var(--ruimte-16); }

/* ── Producties & casting board (journey 4) ─────────────────────────────────
   Generic, reusable additions to the component vocabulary: a content section
   (blok), small button variants, an inline form that sits next to text, and
   the casting-board / picker layout. */

.blok { margin: var(--ruimte-24) 0; }
.blok > h2 { margin-bottom: var(--ruimte-8); }

.knop-klein { padding: 4px var(--ruimte-8); font-size: var(--maat-12); }
.knop-mini {
  padding: 0 6px;
  font-size: var(--maat-12);
  line-height: 1.6;
  border-radius: var(--rond-4, 4px);
}

/* A form that reads as part of a line of text (quick-set, delete buttons). */
.inline-form { display: inline-flex; align-items: center; gap: var(--ruimte-8); margin: 0; }

.casting-board { display: flex; flex-direction: column; gap: var(--ruimte-12); }

.casting-rol {
  border: 1px solid var(--rand);
  border-radius: var(--rond-8, 8px);
  padding: var(--ruimte-12) var(--ruimte-16);
  background: var(--wit);
}
.casting-rol.waarschuwing { border-color: var(--sein-amber-tekst); background: var(--sein-amber-vlak); }

.rol-kop { display: flex; align-items: center; gap: var(--ruimte-8); }
.rol-kop .rechts { margin-left: auto; display: inline-flex; align-items: center; gap: var(--ruimte-8); }

.rol-bezetting { display: flex; flex-wrap: wrap; gap: var(--ruimte-8); margin: var(--ruimte-8) 0; }

.cast-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--ruimte-4);
  padding: 2px var(--ruimte-8);
  background: var(--sein-groen-vlak);
  border-radius: 999px;
}

.kiezer { margin-top: var(--ruimte-8); }
.kiezer-resultaten { display: flex; flex-wrap: wrap; gap: var(--ruimte-4); margin-top: var(--ruimte-4); }
.kiezer-optie { display: inline; margin: 0; }

.upload-form { display: flex; flex-wrap: wrap; align-items: center; gap: var(--ruimte-8); margin-top: var(--ruimte-12); }

/* Content-photo thumbnail (kledingstuk/rekwisiet foto, K2/R2 — D-094). Bounded
   so a large source never blows out the card; served from /bestanden/{id}. */
.foto-thumb { max-width: 100%; max-height: 240px; height: auto; border-radius: var(--radius, 6px); display: block; }

/* ===== Kleding & kledingtas (journey 5, package 9) ================   Inventory + tassen + intake scanner + controle. Reuses the fixed vocabulary
   (tabel, badge, knop, filterbalk, toolbalk, kaart, gegevens, leegstand) plus
   the generic .blok/.inline-form/.knop-klein the producties block above already
   defines (deduped on the package-8 merge). .mt-8 and the kleding-/tas-/scan-
   rules below are this package's own. */

.mt-8 { margin-top: var(--ruimte-8); }

/* Controle checklist — inline conditie radios per piece (D-076). */
.conditie-keuze { display: flex; flex-wrap: wrap; gap: var(--ruimte-12); }
.keuze-inline { display: inline-flex; align-items: center; gap: var(--ruimte-4); white-space: nowrap; }

.tas-acties { display: flex; flex-wrap: wrap; gap: var(--ruimte-8); margin-top: var(--ruimte-12); }

/* Delete-confirm disclosure on tas-detail (samengesteld only): a no-JS,
   CSP-safe <details> whose <summary> is styled as a destructive button. */
.tas-verwijderen summary { cursor: pointer; list-style: none; display: inline-block; }
.tas-verwijderen summary::-webkit-details-marker { display: none; }
.tas-verwijderen[open] summary { margin-bottom: var(--ruimte-8); }

/* Printable tag (D-055/D-013): code + QR + naam. */
.tas-tag {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--ruimte-24);
  border: 2px solid var(--rand); border-radius: var(--rond-8, 8px);
  padding: var(--ruimte-24); background: var(--wit); max-width: 640px;
}
.tas-tag-code { display: grid; gap: var(--ruimte-4); }
.tas-tag-label { font-weight: 600; color: var(--kleur-primair); }
.tas-tag-code strong { font-size: var(--maat-24, 1.5rem); }
.tas-tag-slug { font-size: var(--maat-16); letter-spacing: 0.1em; }
.tas-tag-qr { width: 256px; height: 256px; }

/* Intake scanner (K5) — mobile capture page. */
.scan-kop { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--ruimte-12); margin-bottom: var(--ruimte-16); }
.scan-teller {
  margin-left: auto; font-weight: 600; font-size: var(--maat-18, 1.125rem);
  padding: var(--ruimte-4) var(--ruimte-12); background: var(--vlak); border-radius: 99px;
}
.scan-camera {
  position: relative; border: 2px dashed var(--rand); border-radius: var(--rond-8, 8px);
  background: #000; overflow: hidden; margin-bottom: var(--ruimte-16); min-height: 200px;
  display: flex; align-items: center; justify-content: center;
}
.scan-video { width: 100%; max-height: 60vh; display: block; }
.scan-camera-uit { background: var(--vlak); }
.scan-camera-uit .scan-video { display: none; }
.scan-camera-status {
  position: absolute; left: 0; right: 0; bottom: 0; margin: 0;
  padding: var(--ruimte-8); text-align: center; font-size: var(--maat-13);
  color: var(--wit); background: rgba(0, 0, 0, 0.55);
}
.scan-camera-uit .scan-camera-status { position: static; color: var(--tekst-gedempt); background: transparent; }

.scan-form { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--ruimte-8); margin-bottom: var(--ruimte-16); }
.scan-form .veld-zoek { flex: 1 1 220px; }

.scan-lijst { display: grid; gap: var(--ruimte-8); }
.scan-kaart { padding: var(--ruimte-8) var(--ruimte-12); border-radius: var(--rond-4, 4px); border: 1px solid var(--rand); }
.scan-kaart-terug { background: var(--sein-groen-vlak); border-color: transparent; }
.scan-kaart-al { background: var(--sein-amber-vlak); border-color: transparent; }
.scan-kaart-onbekend { background: var(--sein-rood-vlak); border-color: transparent; }

@media print {
  .nietprint, .kop-balk, .hoofdnav { display: none !important; }
}

/* ===== Financiën (journey 6, package 10) ================================
   Geld: boekjaar switcher + staat van baten en lasten + uitgaven/inkomsten
   lists + quick-add + begroting + categoriebeheer. Reuses the fixed
   vocabulary (card, badge, knop, tabel, filterbalk, toolbalk); the additions
   below are finance-specific plus one generic utility (.formulier-smal) and a
   print face for the staat. MERGE NOTE: promote .formulier-smal, .rij-acties
   and .cursief to the shared vocabulary if another package needs them. */

.formulier-smal { max-width: 32rem; display: grid; gap: var(--ruimte-16); }
.cursief { font-style: italic; }
.rij-acties { text-align: right; white-space: nowrap; }

.boekjaar-balk { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--ruimte-12); margin: var(--ruimte-12) 0 var(--ruimte-16); }
.boekjaar-label { font-weight: 600; color: var(--kleur-kop); }
.boekjaar-pillen { display: flex; flex-wrap: wrap; gap: var(--ruimte-4); }
.boekjaar-pil { padding: var(--ruimte-4) var(--ruimte-8); border: 1px solid var(--rand); border-radius: 99px; color: var(--kleur-primair); text-decoration: none; font-size: var(--maat-13); font-variant-numeric: tabular-nums; }
.boekjaar-pil.actief { background: var(--kleur-primair); color: var(--wit); border-color: var(--kleur-primair); }

.staat { display: grid; gap: var(--ruimte-24); max-width: 46rem; }
.staat-blok h2 { font-size: var(--maat-16); color: var(--kleur-kop); margin: 0 0 var(--ruimte-8); }
.staat-tabel td.numeriek, .staat-tabel th.numeriek { text-align: right; font-variant-numeric: tabular-nums; }
.staat-totaal th, .staat-totaal td { font-weight: 700; border-top: 2px solid var(--rand); }
.bedrag-negatief { color: var(--sein-rood-tekst); font-weight: 600; }

.staat-saldo { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: var(--ruimte-12); padding: var(--ruimte-16); }
.staat-saldo-label { font-weight: 600; color: var(--kleur-kop); }
.staat-saldo-bedrag { font-size: var(--maat-24, 1.5rem); font-weight: 700; color: var(--kleur-kop); font-variant-numeric: tabular-nums; }
.staat-acties { margin-top: var(--ruimte-16); }

.bon-blok { margin-top: var(--ruimte-24); max-width: 32rem; display: grid; gap: var(--ruimte-12); }
.bon-blok h2 { font-size: var(--maat-16); color: var(--kleur-kop); margin: 0; }
.bon-huidig { margin: 0; }
.bon-upload { display: grid; gap: var(--ruimte-8); }


.begroting-rij { display: flex; flex-wrap: wrap; gap: var(--ruimte-8); align-items: center; margin: 0; }
.begroting-rij input[type="text"] { max-width: 10rem; }
.categorie-nieuw { margin-bottom: var(--ruimte-16); }
.categorie-nieuw .rij, .categorie-hernoem { display: flex; gap: var(--ruimte-8); align-items: center; }
.categorie-hernoem { margin: 0; }
.categorie-hernoem input[type="text"] { max-width: 18rem; }

@media print {
  .kop-balk, .boekjaar-balk, .toolbalk, .staat-acties, .hoofdnav, #meldingen { display: none !important; }
  .staat { max-width: none; }
  .staat-tabel { border-collapse: collapse; }
  .staat-tabel td, .staat-tabel th { border: 1px solid #999; }
  a[href]:after { content: ""; }
}

/* ── Journey 7 — generales (package 5). Generic, reusable pieces the fixed
      component vocabulary lacked: a text-only button, a status message bar, the
      planner day-sequence, and the schema print face. Reuses the shared
      .inline-form and .destructief utilities from the rooster/casting block. ── */

.knop-tekst {
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  color: var(--kleur-primair);
  cursor: pointer;
}
.knop-tekst:hover { text-decoration: underline; }

.melding-balk {
  background: var(--kleur-selectie);
  border: 1px solid var(--kleur-selectie-rand);
  border-radius: var(--radius, 8px);
  padding: var(--ruimte-12) var(--ruimte-16);
  margin-bottom: var(--ruimte-16);
}

.conflicten {
  border: 1px solid var(--rand);
  border-radius: var(--radius, 8px);
  padding: var(--ruimte-12) var(--ruimte-16);
  margin-bottom: var(--ruimte-16);
}
.conflicten h2 { margin-top: 0; }
.signaal-lijst { list-style: none; margin: var(--ruimte-8) 0 0; padding: 0; display: grid; gap: var(--ruimte-4, 4px); }
.signaal-regel { color: var(--sein-rood-tekst); }

.dag-blok { margin-bottom: var(--ruimte-24, 24px); }
.sequentie { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--ruimte-8); }
.sequentie-item {
  display: grid;
  grid-template-columns: 8rem 1fr;
  gap: var(--ruimte-4, 4px) var(--ruimte-16);
  padding: var(--ruimte-12);
  border: 1px solid var(--rand);
  border-radius: var(--radius, 8px);
  background: var(--wit);
}
.sequentie-tijd { color: var(--kleur-kop); font-weight: 600; }
.sequentie-titel { margin: 0; font-weight: 500; }
.sequentie-acties { margin-top: var(--ruimte-4, 4px); display: flex; gap: var(--ruimte-16); align-items: center; }
.sequentie-item.waarschuwing { border-color: var(--sein-rood-vlak); background: #fdf7f7; }
.sequentie-item.pauze { background: var(--vlak); }

@media (max-width: 640px) {
  .sequentie-item { grid-template-columns: 1fr; }
}

/* Print face for the generale-schema (A4): drop the chrome, keep the schedule. */
@media print {
  .kop-balk, .filterbalk, .toolbalk, .formulier-acties, .conflicten,
  .pagina-kop .knop, .melding-balk, #meldingen { display: none !important; }
  body { background: #fff; color: #000; }
  main { max-width: none; }
  .dag-blok, .mijn-sectie, li { break-inside: avoid; }
  a { color: #000; text-decoration: none; }
}

/* ===== Draaiboek & rekwisieten (journey 3, package 11a) =================
   S4 editor + S5 master timeline (draaiboek items interleaved with diensten,
   a "Nu" strip, and a print face) + R1/R2 rekwisieten. Reuses the fixed
   vocabulary (tabel, badge, knop, filterbalk, toolbalk, veldgroep, fieldset,
   leegstand); the additions below are timeline-specific plus one generic
   utility (.tijd, .geen-print). MERGE NOTE: promote .tijd and .geen-print to
   the shared vocabulary if another package needs them. */

.tijd { font-variant-numeric: tabular-nums; white-space: nowrap; }

/* "Nu" strip (S5 beat 4): active + next timeline rows, highlighted. */
.nu-strip {
  border: 1px solid var(--kleur-primair); border-radius: var(--rond-8, 8px);
  padding: var(--ruimte-16); margin-bottom: var(--ruimte-24); background: var(--vlak);
}
.nu-strip .lijst li { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--ruimte-8); }

.tijdlijn-dag { margin-top: var(--ruimte-24); }
.tijdlijn-titel { font-weight: 600; color: var(--kleur-kop); }

/* Timeline rows: the active row stands out, past rows recede. */
.tabel.tijdlijn tr.nu-actief > td { background: var(--sein-groen-vlak); }
.tabel.tijdlijn tr.verleden > td { color: var(--tekst-gedempt); }

/* ── UX-ronde 2026-07-25 (D-163..D-173) — de gedeelde generieken ─────────────
   Sectietabs vervangen .rooster-tab (pills lazen als knoppen, D-164). De rest
   is nieuw vocabulaire uit STYLE.md §5a-§5g; schermen bouwen hier alleen mee,
   nooit een eigen variant (D-170). */

/* §5a Sectietabs — naamwoorden navigeren. Underline, nooit pill. */
.sectietabs {
  display: flex; gap: var(--ruimte-16); margin: var(--ruimte-16) 0 var(--ruimte-12);
  padding: 0 0 2px; border-bottom: 1px solid var(--rand);
  overflow-x: auto; scrollbar-width: thin;
}
.sectietab {
  flex: 0 0 auto; padding: var(--ruimte-8) 2px; margin-bottom: -3px;
  color: var(--tekst-gedempt); text-decoration: none; white-space: nowrap;
  border-bottom: 3px solid transparent;
}
.sectietab:hover { color: var(--tekst); border-bottom-color: var(--kleur-selectie-rand); }
.sectietab.actief { color: var(--kleur-primair); font-weight: 600; border-bottom-color: var(--kleur-primair); }
.tabtelling {
  display: inline-block; margin-left: var(--ruimte-4); padding: 0 var(--ruimte-8);
  border-radius: 99px; background: var(--vlak); color: var(--tekst-gedempt);
  font-size: var(--maat-12); font-variant-numeric: tabular-nums;
}
.sectietab.actief .tabtelling { background: var(--kleur-selectie); color: var(--kleur-primair); }

/* §5a flow-variant (W-114, D-164) — een decoratieve pijl tussen tabs die een
 * causale volgorde tonen (Kleding: Voorraad → Toewijzing → Samenstellen →
 * Tassen → Inname). `.sectietabs-stroom` is een modifier op de bestaande
 * `.sectietabs`, geen nieuw component: dezelfde flex-rij, dezelfde
 * horizontal-scroll. De pijl zelf (`.sectietab-pijl`) is een los <span
 * aria-hidden="true">, geen ::after op de tab: pseudo-elementinhoud
 * (`content:`) kan in sommige browser/schermlezer-combinaties toch in de
 * accessibility-tree belanden, en `aria-hidden` is op een pseudo-element niet
 * te zetten — een los element is de enige manier om "nooit als inhoud
 * voorgelezen" hard te garanderen. Small en gedempt (`--rand`, dezelfde tint
 * als de tabstrip-baseline): D-164 waarschuwt dat een tabstrip navigatie
 * blijft, geen wizard, dus de pijl mag nooit meer contrast trekken dan de
 * tabs zelf. Geen pijl vóór een tab die geen stap in de keten is (Kleding:
 * Reparatie/Vermist) — die twee zijn uitzonderingen, geen zesde/zevende
 * stap; de bestaande `gap` van de flex-rij scheidt ze zonder een pijl die een
 * keten claimt die er niet is. */
.sectietabs-stroom .sectietab-pijl {
  flex: 0 0 auto; align-self: center; white-space: nowrap;
  color: var(--rand); font-size: var(--maat-14); line-height: 1;
  user-select: none;
}

/* §5b Weergavebalk + filterchips — filters zijn zichtbaar, nooit verborgen staat. */
.weergavebalk {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--ruimte-8);
  margin-bottom: var(--ruimte-12);
}
.chips { display: flex; flex-wrap: wrap; align-items: center; gap: var(--ruimte-4); }
.chip {
  display: inline-flex; align-items: center; gap: var(--ruimte-4);
  padding: var(--ruimte-4) var(--ruimte-8); border-radius: 99px;
  background: var(--kleur-selectie); border: 1px solid var(--kleur-selectie-rand);
  color: var(--kleur-kop); font-size: var(--maat-13);
}
/* A chip that is itself the clickable control (W-092 functie switcher: a
 * single-select filter rendered as chips, no × per chip) is an <a>, not a
 * <span> + button — drop the browser's default link underline so it still
 * reads as a pill. */
a.chip { text-decoration: none; }
a.chip:hover { background: var(--kleur-selectie-rand); }
/* Een standaardscope ziet er anders uit dan een zelf gekozen filter: gestippeld. */
.chip-scope { background: var(--vlak); border-style: dashed; }
.chip-wis {
  background: none; border: none; padding: var(--ruimte-4);
  color: var(--kleur-primair); font: inherit; font-size: var(--maat-13); cursor: pointer;
  text-decoration: underline;
}
.chip-af {
  display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 18px; border: none; border-radius: 99px;
  background: none; color: var(--kleur-kop); font: inherit; line-height: 1; cursor: pointer;
}
.chip-af:hover { background: var(--kleur-selectie-rand); }
@media (pointer: coarse) { .chip-af { width: var(--aanraakdoel); height: var(--aanraakdoel); } }

/* W-205: chip = stand (klik zet een filter UIT), pil = ingang (klik zet een
 * filter AAN, blijft --kleur-selectie blauw hierboven) — twee verschillende
 * handelingen mogen niet identiek ogen, en stonden hier allebei in hetzelfde
 * pale blue direct tegen elkaar aan. Bestaande badge-groentint hergebruikt
 * (D-170: geen nieuwe kleur), dezelfde tint als .badge-groen/.cel-vol, die al
 * "actief/vol" betekent — een amber- of roodtint zou hier ten onrechte een
 * waarschuwing suggereren. .chip-scope (de niet-afneembare standaardscope,
 * gestippeld grijs) blijft bewust buiten deze regel: die onderscheiding
 * bestond al en is geen deel van dit probleem. Contrast #EAF3DE/#27500A
 * gemeten (WCAG-formule, relatieve luminantie): ~8.2:1, ruim boven de 4.5:1
 * die AA voor 13px tekst eist. Deze stijlsheet heeft geen dark-theme variant
 * (tokens.css: "Light theme only"), dus één richting is de volledige proef. */
.chips-filters .chip:not(.chip-scope) {
  background: var(--sein-groen-vlak); border-color: transparent; color: var(--sein-groen-tekst);
}
.chips-filters a.chip:not(.chip-scope):hover,
.chips-filters button.chip:not(.chip-scope):hover {
  border-color: var(--sein-groen-tekst);
}
.chips-filters .chip:not(.chip-scope) .chip-af { color: var(--sein-groen-tekst); }
.chips-filters .chip:not(.chip-scope) .chip-af:hover {
  background: color-mix(in srgb, var(--sein-groen-tekst) 20%, transparent);
}
/* Een chip is niet altijd een <span>: als filterlink is hij een <a>, als
   éénklikactie een submit-<button> (actielijst, D-182d). Dezelfde vorm, dus
   dezelfde regels — knoppen erven het pagina-lettertype niet vanzelf en links
   zijn standaard onderstreept. */
a.chip, button.chip { font-family: inherit; text-decoration: none; cursor: pointer; }
a.chip:hover, button.chip:hover { border-color: var(--kleur-primair); }
a.chip[aria-current], button.chip:disabled { cursor: default; }
a.chip-af { text-decoration: none; }

/* W-107: chip as a CHOOSER (one-owner assign, single-select filter, status)
 * needs on/off contrast, not the removable-filter look .chip owns — the
 * actielijst reused .chip/.chip-scope for this and both states read as the
 * same pale blue. Modifier, not a redefinition of .chip (D-170): redefining
 * would silently restyle every removable filter chip in the app. Unselected
 * = white fill + --rand-invoer border (measured ~15:1 text contrast, tekst
 * on wit); selected = --kleur-primair fill + white text (measured ~6.9:1,
 * passes AA). Combine with .chip for shape: class="chip chip-keuze", add
 * chip-keuze-actief for the chosen one. */
.chip-keuze { background: var(--wit); border-color: var(--rand-invoer); color: var(--tekst); }
a.chip-keuze:hover, button.chip-keuze:hover { background: var(--kleur-selectie); }
.chip-keuze-actief,
a.chip-keuze-actief:hover, button.chip-keuze-actief:hover {
  background: var(--kleur-primair); border-color: var(--kleur-primair); color: var(--wit);
}

/* §5c Selectie + bulkbalk. */
.rij-geselecteerd > td { background: var(--kleur-selectie); }
.bulkbalk {
  position: sticky; bottom: var(--ruimte-12); z-index: 5;
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--ruimte-12);
  padding: var(--ruimte-8) var(--ruimte-12); border-radius: 12px;
  background: var(--kleur-kop); color: var(--wit);
}
.bulkbalk .knop-secundair { background: transparent; color: var(--wit); border-color: var(--wit); }
.bulkbalk-teller { font-weight: 600; font-variant-numeric: tabular-nums; }
.bulkbalk-uitsluiting { color: var(--kleur-selectie-rand); font-size: var(--maat-13); }
.bulkbalk a, .bulkbalk button.tekstknop { color: var(--wit); }
/* De balk draagt twee echte formulieren (GET voor exporteren/mailen, POST voor
   magic links/Laposta — gescheiden zodat het CSRF-token nooit in een
   querystring belandt). display:contents laat hun knoppen gewoon meedoen in de
   flexrij, alsof de formulieren er niet tussen zitten. */
.bulkbalk form { display: contents; }
/* Selectiekolom: zo smal mogelijk, want de essenti&euml;le kolommen moeten op
   1366px blijven passen (D-112). */
.kol-selectie { width: 1%; white-space: nowrap; }
.kol-selectie input[type="checkbox"] { width: 18px; height: 18px; cursor: pointer; }
/* Preset-chips (W-036) zetten een filter in plaats van het weg te halen, dus
   ze lezen als knoppen, niet als "actieve toestand". */
.chips-preset { display: flex; flex-wrap: wrap; align-items: center; gap: var(--ruimte-8); }
.chip-preset { background: var(--vlak); }

/* §5d Lege staat die bekent: nooit een blanco tabel zonder uitleg. */
.leegstand-uitleg {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: center;
  gap: var(--ruimte-8); color: var(--tekst-gedempt); font-size: var(--maat-13);
}

/* §5e Impact-dialoog — wat hangt hieraan, vóór het verwijderen. */
.impact {
  width: min(560px, calc(100vw - var(--ruimte-24)));
  padding: var(--ruimte-16); border: 1px solid var(--rand); border-radius: 12px;
  color: var(--tekst); background: var(--wit);
}
dialog.impact::backdrop { background: rgb(29 48 86 / 45%); }
.impact-kop { margin: 0 0 var(--ruimte-8); font-family: var(--font-kop); color: var(--kleur-kop); }
.impact-lijst { margin: 0 0 var(--ruimte-16); padding-left: var(--ruimte-16); }
.impact-lijst li { margin-bottom: var(--ruimte-4); }
.impact-lijst li .gedempt { margin-left: var(--ruimte-8); }
.impact-acties { display: flex; flex-wrap: wrap; gap: var(--ruimte-8); justify-content: flex-end; }
/* Eén groep per soort, geteld — nooit één ongesorteerde hoop afhankelijkheden. */
.impact-groep { margin-bottom: var(--ruimte-16); }
.impact-groep-kop {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--ruimte-8); margin: 0 0 var(--ruimte-4);
}
/* Het beleid van W-030 staat er letterlijk bij: de gebruiker hoort te zien of
   iets blokkeert of gewoon blijft staan, niet te moeten raden. */
.impact-beleid {
  padding: 1px var(--ruimte-8); border-radius: 999px;
  font-size: var(--maat-12); color: var(--tekst-gedempt); background: var(--vlak);
}
.impact-beleid-blokkeren { color: var(--sein-rood-tekst); background: var(--sein-rood-vlak); }
/* Volle-paginavariant (geen JavaScript): een <dialog> zonder `open` is
   display:none, dus daar wordt hij een gewoon blok. Zelfde markup, zelfde
   tekst — alleen niet modaal. */
.impact-pagina dialog.impact { display: block; margin-inline: auto; }

/* §5f ⌘K-palet — resultaten gegroepeerd per soort, nooit één gemengde ranglijst. */
.palet {
  width: min(640px, calc(100vw - var(--ruimte-24)));
  padding: 0; border: 1px solid var(--rand); border-radius: 12px; background: var(--wit);
}
.palet-invoer { width: 100%; padding: var(--ruimte-12); border: none; border-bottom: 1px solid var(--rand); font: inherit; font-size: var(--maat-16); }
.palet-groep { padding: var(--ruimte-8) var(--ruimte-12) var(--ruimte-4); color: var(--tekst-gedempt); font-size: var(--maat-12); text-transform: uppercase; letter-spacing: 1px; }
.palet-rij { display: flex; align-items: center; justify-content: space-between; gap: var(--ruimte-8); padding: var(--ruimte-8) var(--ruimte-12); color: var(--tekst); text-decoration: none; }
.palet-rij:hover, .palet-rij.actief { background: var(--kleur-selectie); }
.palet-meer { display: block; padding: var(--ruimte-4) var(--ruimte-12) var(--ruimte-8); color: var(--kleur-primair); font-size: var(--maat-13); }
.palet-toets { padding: 1px var(--ruimte-4); border: 1px solid var(--rand); border-radius: 4px; color: var(--tekst-gedempt); font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: var(--maat-12); }
.palet-titel { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* De uitslag zit óók op de home-pagina (één partial, twee ingangen); in de
   dialoog begrenst dit de hoogte, op de pagina groeit het gewoon mee. */
.palet-uitslag { overflow-y: auto; }
dialog.palet .palet-uitslag { max-height: min(60vh, 480px); }
.palet-melding { padding: var(--ruimte-12); margin: 0; color: var(--tekst-gedempt); font-size: var(--maat-13); }
.palet-voet { display: flex; flex-wrap: wrap; align-items: center; gap: var(--ruimte-4); margin: 0; padding: var(--ruimte-8) var(--ruimte-12); border-top: 1px solid var(--rand); color: var(--tekst-gedempt); font-size: var(--maat-12); }
/* <dialog> centreert standaard verticaal; een palet hoort bovenin te staan. */
dialog.palet { margin-top: 10vh; margin-bottom: auto; }
dialog.palet::backdrop { background: rgb(29 48 86 / 45%); }
/* Kopbalk-ingang naast de sneltoets — nooit alleen een sneltoets (D-113). */
.kop-acties { display: flex; align-items: center; gap: var(--ruimte-8); margin-left: auto; }
.palet-knop {
  display: inline-flex; align-items: center; gap: var(--ruimte-4);
  padding: var(--ruimte-4) var(--ruimte-8); border: 1px solid var(--rand); border-radius: 8px;
  color: var(--tekst-gedempt); text-decoration: none; font-size: var(--maat-12); white-space: nowrap;
}
.palet-knop:hover { color: var(--kleur-primair); border-color: var(--kleur-primair); }

/* §5g Undo-melding — vervangt de bevestigingsdialoog voor alles wat omkeerbaar is. */
.melding-undo {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--ruimte-12);
  padding: var(--ruimte-8) var(--ruimte-12); border: 1px solid var(--rand);
  border-radius: 8px; background: var(--vlak);
}

/* ---- Actielijst: rollende lijst gegroepeerd op onderwerp (W-041, D-182) --- */
.actiegroep + .actiegroep { margin-top: var(--ruimte-16); }
.actiegroep-kop {
  margin-bottom: var(--ruimte-8);
  font-size: var(--maat-16); color: var(--kleur-kop);
}
.actiepunt + .actiepunt { margin-top: var(--ruimte-8); }
/* De twee éénklikbalken (wie / status) staan onder de tekst en lezen als één
   regel: label, dan de chips. */
.actiepunt-wie, .actiepunt-status { margin-top: var(--ruimte-8); }
.actiepunt details { margin-top: var(--ruimte-8); }
.actiepunt summary { cursor: pointer; color: var(--kleur-primair); }

@media print {
  /* Print face (D-035): the wall-poster / pocket version — paper survives wifi. */
  .geen-print, .kop-balk, .hoofdnav, .toolbalk, #meldingen,
  .sectietabs, .weergavebalk, .bulkbalk,
  .actiepunt-wie, .actiepunt-status { display: none !important; }
  .tijdlijn-dag { break-inside: avoid; }
  .tabel.tijdlijn { border-collapse: collapse; }
  .tabel.tijdlijn td, .tabel.tijdlijn th { border: 1px solid #999; }
  .tabel.tijdlijn tr.nu-actief > td { background: transparent; }
  a[href]:after { content: ""; }
}

/* ── W-040 Timetable — de meerjarenplanning (D-183) ──────────────────────────
   Twee gezichten op één dataset (D-035): de matrix (rubriek × maand, een balk
   per taak) en de lijst per verantwoordelijke. De lijst gebruikt uitsluitend de
   bestaande generieken (tabel · badge · chip · toolbalk · filterbalk ·
   leegstand); alleen de matrix heeft eigen vocabulaire nodig — een tabel met
   één cel per maand bestaat nog nergens anders.

   D-112 (1366px, `main` biedt 1168px): table-layout:fixed met een taakkolom van
   240px en maandkolommen van 40px. 21 maanden = 240 + 840 = 1080px en past dus
   zonder schuiven. Groeit de as verder (een derde jaar), dan schuift alleen
   .tt-houder horizontaal terwijl de taakkolom links vastgeplakt blijft — de
   pagina zelf schuift nooit mee. */

/* De matrix is een eigen schuifvlak, geen stuk pagina dat meeschuift. Reden:
   `overflow-x: auto` maakt de houder sowieso al een scroll-container (CSS laat
   `overflow-y: visible` dan naar `auto` verspringen), dus een `position: sticky`
   maandkop zou tegen de PAGINA-scroll nooit blijven plakken. Met een begrensde
   hoogte klopt het wél: 81 taken schuiven binnen dit vlak langs een maandkop en
   een taakkolom die allebei staan blijven, en de pagina eromheen staat stil. */
.tt-houder {
  max-width: 100%;
  max-height: calc(100vh - 260px);
  min-height: 220px;
  overflow: auto;
}

.tt-matrix {
  table-layout: fixed;
  width: max-content;
  max-width: none;
  border-collapse: collapse;
  font-size: var(--maat-12);
  line-height: var(--regelhoogte-dicht);
}

/* De maandkoppen plakken bovenaan het schuifvlak van .tt-houder (top: 0 is
   daarom relatief aan die houder, niet aan de pagina). z-index blijft ruim
   onder die van .kop-balk, zodat de hoofdnav er altijd overheen ligt. */
.tt-matrix thead th {
  position: sticky;
  top: 0;
  z-index: 3;
  background: var(--vlak);
  padding: var(--ruimte-4);
  text-align: center;
  white-space: nowrap;
}
.tt-matrix .tt-hoek,
.tt-matrix .tt-taak {
  width: 240px;
  min-width: 240px;
  position: sticky;
  left: 0;
  background: var(--wit);
  text-align: left;
}
.tt-matrix .tt-hoek { z-index: 4; background: var(--vlak); }
.tt-matrix .tt-taak { z-index: 1; font-weight: 400; padding: var(--ruimte-4) var(--ruimte-8); }
.tt-matrix tbody tr:hover .tt-taak { background: var(--kleur-selectie); }
.tt-matrix .tt-taak a { font-weight: 600; }
.tt-meta { display: block; }

.tt-jaar {
  font-family: var(--font-kop);
  color: var(--kleur-kop);
  border-left: 2px solid var(--rand);
}
.tt-maandkop { width: 40px; min-width: 40px; color: var(--tekst-gedempt); }
.tt-maandkop abbr { text-decoration: none; }
.tt-jaargrens { border-left: 2px solid var(--rand); }
/* De lopende maand: één verticale lijn door de hele matrix. */
.tt-matrix .tt-nu { color: var(--kleur-primair); font-weight: 600; }

.tt-categorie-kop {
  padding: var(--ruimte-8);
  background: var(--vlak);
  font-family: var(--font-kop);
  color: var(--kleur-kop);
  text-align: left;
}
/* De rubriekband loopt over de hele breedte, dus `sticky` op de cel zelf doet
   niets — de tekst erbinnen moet plakken, anders schuift de rubrieknaam uit
   beeld zodra de maandas breder is dan het venster. */
.tt-categorie-plak { position: sticky; left: var(--ruimte-8); display: inline-block; }
.tt-categorie-nieuw { margin-left: var(--ruimte-8); font-weight: 400; }

.tt-cel {
  width: 40px;
  min-width: 40px;
  height: 22px;
  padding: 0;
  border-left: 1px solid var(--rand);
}
/* De balk: aaneengesloten cellen met dezelfde vulling lezen als één streep,
   de uiteinden krijgen een ronding zodat begin en einde zichtbaar zijn. Loopt
   een taak door buiten de zichtbare as, dan blijft dat uiteinde recht. */
.tt-balk { border-left-color: transparent; }
.tt-balk-start { border-top-left-radius: 99px; border-bottom-left-radius: 99px; }
.tt-balk-eind { border-top-right-radius: 99px; border-bottom-right-radius: 99px; }
.tt-open  { background: var(--kleur-selectie-rand); }
.tt-loopt { background: var(--sein-amber-vlak); box-shadow: inset 0 0 0 1px var(--sein-amber-tekst); }
.tt-klaar { background: var(--sein-groen-vlak); box-shadow: inset 0 0 0 1px var(--sein-groen-tekst); }

.tt-legenda { color: var(--tekst-gedempt); font-size: var(--maat-12); }
.tt-legenda-vlak {
  display: inline-block; width: 20px; height: 12px; border-radius: 99px;
  vertical-align: middle;
}

/* Een chip die naar een andere scope linkt (de jaarchips boven de matrix). */
.chip-link { text-decoration: none; }
.chip-link:hover { background: var(--kleur-selectie-rand); }

/* Lijst per verantwoordelijke: de groepskop is de enige toevoeging, de tabel
   eronder is de gewone .tabel. */
.tt-groep + .tt-groep { margin-top: var(--ruimte-24); }
.tt-groep-kop { display: flex; align-items: center; gap: var(--ruimte-8); margin-bottom: var(--ruimte-8); }

@media print {
  /* De matrix is precies het overzicht dat aan de muur hangt tijdens een
     bestuursvergadering: laat hem uitschuiven in plaats van afkappen. */
  .tt-houder { max-height: none; min-height: 0; overflow: visible; }
  .tt-matrix { width: 100%; font-size: 9px; }
  .tt-matrix thead th { position: static; }
  .tt-matrix .tt-hoek, .tt-matrix .tt-taak, .tt-categorie-plak { position: static; }
  .tt-cel, .tt-matrix th { border: 1px solid #999; }
  .tt-legenda { display: none !important; }
}

/* W-081 — compacte redenenlijst in een tabelcel: waarom staat dit paar hier?
   Generiek gehouden (geen dubbelen-prefix): elke lijst die per rij een handvol
   korte verantwoordingsregels toont, kan hem gebruiken. */
.redenen {
  list-style: none;
  margin: 0;
  padding: 0;
}
.redenen li + li {
  margin-top: 0.15rem;
}
