/* Declaraties-app — app-specifieke styling boven op /huisstijl/huisstijl.css.
   Houd dit bestand zo dun mogelijk: alleen wat de huisstijl niet biedt
   of wat afwijkt voor deze app. Gebruik altijd de huisstijl-tokens. */

/* ─── Spacing-schaal (4px-basis) ─────────────────────────────────────────
   De huisstijl levert kleur-, radius- en schaduw-tokens, maar geen
   spacing-schaal. We definiëren er hier één zodat alle marges en padding
   in deze app hetzelfde ritme volgen i.p.v. losse, net-niet-passende
   getallen. Dat is wat de layout rustig en consistent maakt. */
:root {
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 20px;
  --space-6: 24px;
  --space-7: 32px;
  --space-8: 40px;
  --space-9: 48px;
  --space-10: 64px;

  /* App-ritme: afgeleide tokens voor de twee meest herhaalde afstanden. */
  --gap-card: var(--space-5);  /* verticale afstand tussen kaarten/secties */
  --pad-card: var(--space-6);  /* binnenruimte van een kaart (desktop)     */
}

/* Tekst die alleen voor schermlezers bestaat. Bijvoorbeeld de kop van een
   kolom die visueel leeg hoort te blijven (de actiekolom in het
   betaaloverzicht): een lege <th> laat een schermlezer de kolom naamloos
   aankondigen. display:none of visibility:hidden kan niet — dan valt de tekst
   ook voor de schermlezer weg. */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Een <a class="btn ..."> (bijv. "Beoordelen" in de inbox) is een link die
   als knop oogt — huisstijl.css reset text-decoration niet op .btn zelf,
   dus zonder dit blijft de standaard link-underline onder de knoptekst
   staan. Geldt voor alle a.btn-varianten in de hele app. */
a.btn { text-decoration: none; }

/* ─── Layout: topbar + main ─────────────────────────────────────────── */

main#app {
  max-width: 1100px;
  margin: 0 auto;
  padding: var(--space-7) var(--space-6) var(--space-10);
}

/* .tabs (huisstijl.css) is een niet-wrappende flexrij zonder eigen
   scrollgedrag. Op desktop passen de 7 Beheer-tabs naast elkaar, maar op een
   telefoon (390px) niet — zonder overflow-x hier duwt de rij dan de hele
   pagina horizontaal open, net als een <table> zonder .table-scroll om zich
   heen. Deze regel laat de tabbalk zelf scrollen i.p.v. de pagina. */
.tabs { overflow-x: auto; overflow-y: hidden; }
.tab { flex-shrink: 0; }

/* Login-mode: geen content-marges, full bleed. .login-screen (huisstijl.css)
   tekent zijn eigen volle achtergrond (het clubblauw) en dekt de viewport
   altijd af; deze regel is alleen nog de rand-situatie (bv. iOS-overscroll-
   bounce) waarbij er heel even niets anders onder zit — vandaar dezelfde
   blauwe ondergrond i.p.v. de oude creme gradient. */
body.login-mode {
  background: var(--blauw);
}

/* #login-overlay is een losstaand element (zie index.html), geen onderdeel
   van #app. Het inlogscherm ("niet ingelogd" én "sessie verlopen") rendert
   altijd hierin, nooit in #app. body.login-mode verbergt #app volledig via
   CSS en toont de overlay — puur declaratief, dus onafhankelijk van de
   volgorde/timing waarin een pagina zijn eigen (async) foutafhandeling
   afrondt. Zolang #app display:none heeft, kan geen render() daarin het
   inlogscherm nog zichtbaar overschrijven. */
#login-overlay { display: none; }
body.login-mode #app { display: none; }
body.login-mode #login-overlay { display: block; min-height: 100vh; }

/* v3.0: de topbar is nu een vol clubblauw vlak (was donker ink) met een gele
   bies eronder — de "trim" van het tenue. Alle tekst/iconen in de topbar
   worden hieronder wit (met transparantie voor niet-actieve staat) i.p.v. de
   oude crème-tint: dat was afgestemd op de bijna-zwarte ink-achtergrond en
   verloor contrast op blauw (zie huisstijl-wit-report.md voor de gemeten
   ratio's). */
header#topbar {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: max(env(safe-area-inset-top, 0px), 16px) max(env(safe-area-inset-right, 0px), 24px) 16px max(env(safe-area-inset-left, 0px), 24px);
  background: var(--blauw);
  border-bottom: 4px solid var(--geel);
  position: sticky;
  top: 0;
  z-index: 10;
}
/* Focusring voor alle interactieve elementen in de topbar: geel, want dat is
   het enige accent dat op vol clubblauw ruim boven de 3:1-norm voor
   interface-elementen uitkomt (6,1:1 gemeten) — de standaard browser-
   focusring is vaak zelf blauw en zou op deze achtergrond nauwelijks
   opvallen. */
header#topbar a:focus-visible,
header#topbar button:focus-visible {
  outline: 2px solid var(--geel);
  outline-offset: 2px;
  border-radius: 6px;
}
/* Zonder deze regel wint `display: flex` hierboven het altijd van het
   [hidden]-attribuut (dat zit in de UA-stylesheet, dus elke auteursregel
   verslaat 'm — ongeacht specificiteit). app.js zet topbar.hidden = true
   zolang niemand is ingelogd; dat bleef onopgemerkt zolang een 401 meteen
   naar een aparte SSO-inlogpagina wegnavigeerde. Nu het inlogscherm van de
   app zelf op het scherm blijft staan, moet de topbar ook echt verdwijnen. */
header#topbar[hidden] { display: none; }

header#topbar .brand-mark {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: var(--wit);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  overflow: hidden;
  box-shadow: 0 2px 8px rgba(22, 32, 43, .25);
  text-decoration: none;
}

header#topbar .brand-mark img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

header#topbar .brand {
  font-weight: 700;
  color: var(--wit);
  text-decoration: none;
  font-size: 1.25rem;
  letter-spacing: -0.01em;
}

header#topbar nav {
  display: flex;
  gap: 4px;
  flex: 1;
  overflow-x: auto;
}

header#topbar nav a {
  color: rgba(255, 255, 255, 0.82);
  text-decoration: none;
  padding: 8px 14px;
  border-radius: 8px;
  white-space: nowrap;
  font-weight: 600;
  font-size: 14px;
  transition: color .15s var(--ease), background .15s var(--ease), box-shadow .15s var(--ease);
}

header#topbar nav a:hover { color: var(--wit); background: rgba(255, 255, 255,.10); }

/* Actieve pagina: wit label + een gele onderstreping (dezelfde "hier moet je
   zijn"-taal als de actieve tab in de beheerschermen, zie .tab.active in
   huisstijl.css) i.p.v. het oude blauwe blok — dat zou nu tegen de eveneens
   blauwe topbar-achtergrond wegvallen. */
header#topbar nav a.active {
  color: var(--wit);
  background: rgba(255, 255, 255, 0.14);
  box-shadow: inset 0 -3px 0 0 var(--geel);
}

/* ─── Linklike-knop (link-look, button-element) ─────────────────────── */
.linklike {
  background: none;
  border: 0;
  cursor: pointer;
  font-size: .95rem;
  font-family: inherit;
  font-weight: 600;
  padding: 4px 6px;
  color: var(--ink-2);
  border-radius: 6px;
  transition: color .15s var(--ease), background .15s var(--ease);
}
.linklike:hover { color: var(--ink); background: rgba(22, 32, 43,.06); }

/* In de topbar (blauwe achtergrond) is .linklike licht */
header#topbar .linklike { color: rgba(255, 255, 255, 0.82); }
header#topbar .linklike:hover { color: var(--wit); background: rgba(255, 255, 255,.10); }

/* ─── Card-helpers (declaraties-specifiek) ──────────────────────────── */
/* Standaard "page card": gewone .card maar met inhoud-padding ingebakken,
   zodat we niet bij elke pagina .card-body hoeven uit te schrijven. */
.card.card-padded { padding: var(--pad-card); }
.card.card-padded > h2:first-child,
.card.card-padded > h3:first-child { margin-top: 0; }

/* Marge tussen meerdere kaarten op één pagina */
.card + .card { margin-top: var(--gap-card); }

/* "Let-op card" — een toon lichter dan .card-danger: voor een impactvolle
   maar omkeerbare actie (bijv. Instellingen → Handmatig afsluiten, dat nieuwe
   indieningen blokkeert over de gekozen periode, maar zonder typ-ter-
   bevestiging weer teruggedraaid kan worden). Zelfde geel-tinten als
   .status-aandacht/.correctie-blok, alleen als linkerrand i.p.v. volle
   achtergrond — anders oogt een grotendeels neutraal instellingenblok als
   permanente foutmelding. */
.card.card-let-op {
  border-left: 4px solid var(--geel-donker);
}
.card.card-let-op h2,
.card.card-let-op h3 { color: var(--geel-donker); margin-top: 0; }

/* "Danger card" — voor onomkeerbare acties (zie admin-reset). */
.card.card-danger {
  background: var(--rood-licht);
  border-color: rgba(179, 38, 30, .35);
  padding: var(--pad-card);
}
.card.card-danger h2,
.card.card-danger h3 { color: var(--rood); margin-top: 0; }
.card.card-danger code {
  background: var(--wit);
  border: 1px solid rgba(179, 38, 30,.25);
  border-radius: 6px;
  padding: 1px 6px;
  font-size: 13px;
}

/* ─── Tabellen — app-conventie .table ───────────────────────────────── */
/* De huisstijl styled <table> direct, maar de app zet 'm graag in een
   witte kaart-achtige container. Daar geven we 'm hier een card-look. */
.table {
  background: var(--wit);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-xs);
  border: 1px solid var(--rule);
  overflow: hidden;
}
.table th, .table td { padding: 12px 16px; }
.table th { font-size: 11px; }
.table td { font-size: 14px; }

/* ─── Forms — kleine app-specifieke helpers ─────────────────────────── */
.row-actions { display: flex; gap: 8px; flex-wrap: wrap; }

/* Pagina-titel boven aan een view + verticaal ritme voor sectiekoppen.
   De paginatitel krijgt altijd dezelfde ademruimte naar de content eronder,
   in alle drie de varianten: losse <h1>, een <h1> ná een .eyebrow-kicker,
   en de .topline (kop + actieknop op één regel). */
main#app > h1:first-child { margin: 0 0 var(--space-7) 0; }
main#app > .eyebrow:first-child + h1 { margin: 0 0 var(--space-7); }
.topline { margin-bottom: var(--space-7); }
main#app h2 { margin: var(--space-7) 0 var(--space-3); }
main#app h3 { margin: var(--space-6) 0 var(--space-2); }

/* ─── Toast — centered onderaan (afwijking van huisstijl) ───────────── */
#toast.toast {
  left: 50%;
  right: auto;
  transform: translateX(-50%);
  bottom: 24px;
  opacity: 0;
  transition: opacity .2s var(--ease);
  animation: none;
}
#toast.toast.show { opacity: 1; }

/* ─── Empty / loading-tekstjes (app-conventie .empty) ───────────────── */
.empty {
  padding: 32px;
  text-align: center;
  color: var(--ink-3);
  background: var(--wit);
  border: 1.5px dashed var(--rule);
  border-radius: var(--r-md);
}

/* ─── Tekst-utilities ───────────────────────────────────────────────── */
.text-danger { color: var(--rood); }
.text-right  { text-align: right; }

/* ─── Wizard (declaratie-nieuw) ─────────────────────────────────────── */
.wizard-stepper {
  display: flex;
  gap: var(--space-2);
  flex-wrap: wrap;
  margin-bottom: var(--gap-card);
  font-size: 13px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.wizard-step {
  padding: 6px 12px;
  border-radius: 999px;
  background: var(--wit);
  border: 1.5px solid var(--rule);
  color: var(--ink-3);
}
.wizard-step.active {
  background: var(--ink);
  color: var(--wit);
  border-color: var(--ink);
}
.wizard-step.done {
  background: var(--lichtgroen);
  color: var(--ink);
  border-color: var(--lichtgroen);
}
.wizard-card { min-height: 240px; }
.wizard-nav {
  display: flex;
  justify-content: space-between;
  gap: var(--space-3);
  margin-top: var(--gap-card);
}

/* ─── Bestand-grid (foto's / PDF tegels) ───────────────────────────── */
.file-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
  gap: 10px;
}
.file-tile {
  position: relative;
  aspect-ratio: 1 / 1;
  border-radius: var(--r-md);
  overflow: hidden;
  background: var(--wit);
  border: 1.5px solid var(--rule);
  display: flex;
  align-items: center;
  justify-content: center;
}
.file-tile img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.file-tile-pdf {
  text-align: center;
  font-size: 12px;
  color: var(--ink-3);
  padding: 8px;
  word-break: break-all;
}
.file-tile-pdf small { display: block; font-size: 10px; margin-top: 4px; }
.file-tile-add {
  cursor: pointer;
  color: var(--ink-3);
  border-style: dashed;
  font-size: 13px;
  flex-direction: column;
  gap: 4px;
}
.file-tile-add:hover { background: var(--grijs-50); }
.file-tile-add-icon {
  font-size: 32px;
  font-weight: 300;
  line-height: 1;
}
/* "Foto maken" (camera) alleen op apparaten mét aanraakscherm (telefoon/tablet,
   incl. iPad met trackpad). Op een gewone desktop (alleen muis) verschijnt enkel
   "Bestand kiezen". any-pointer:coarse = er is minstens één touch-invoer. */
.file-tile-camera { display: none; }
@media (any-pointer: coarse) {
  .file-tile-camera { display: flex; }
}
.file-tile-remove {
  position: absolute;
  top: 4px; right: 4px;
  width: 24px; height: 24px;
  border-radius: 50%;
  background: rgba(22, 32, 43, 0.85);
  color: var(--wit);
  border: 0;
  font-size: 18px;
  line-height: 22px;
  cursor: pointer;
  padding: 0;
}
.file-tile-link {
  text-decoration: none;
  cursor: pointer;
  background: transparent;
  padding: 0;
  font: inherit;
}
.file-tile-link:hover { border-color: var(--ink); }

.file-tile-zoom {
  position: absolute;
  bottom: 4px;
  right: 4px;
  width: 22px;
  height: 22px;
  border-radius: 4px;
  background: rgba(22, 32, 43, 0.78);
  color: var(--wit);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  pointer-events: none;
}

.file-grid-compact {
  grid-template-columns: repeat(auto-fill, minmax(80px, 1fr));
  gap: 6px;
}

/* ─── Review-lijst (controle-stap, detail-pagina) ──────────────────── */
.review-list {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: var(--space-2) var(--space-5);
  margin: 0;
}
.review-list dt {
  font-weight: 600;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--ink-3);
  align-self: center;
}
.review-list dd { margin: 0; align-self: center; }

/* ─── Audit/actie-log op detail-pagina ──────────────────────────────── */
.actie-log {
  list-style: none;
  padding: 0;
  margin: 0;
}
.actie-log li {
  padding: 8px 0;
  border-bottom: 1px solid var(--rule);
}
.actie-log li:last-child { border-bottom: 0; }

/* ─── Preview-overlay (fullscreen foto-viewer) ──────────────────────── */
.preview-overlay {
  position: fixed;
  inset: 0;
  background: rgba(10, 14, 19, 0.94);
  z-index: 1000;
  display: flex;
  align-items: stretch;
  justify-content: stretch;
  padding: max(env(safe-area-inset-top, 0px), 12px) 12px max(env(safe-area-inset-bottom, 0px), 12px) 12px;
  -webkit-tap-highlight-color: transparent;
  animation: preview-fade-in .15s ease-out;
}
@keyframes preview-fade-in { from { opacity: 0 } to { opacity: 1 } }

.preview-scroll {
  flex: 1;
  overflow: auto;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Pinch-zoom + pannen op mobile (native browser gesture) */
  touch-action: pinch-zoom pan-x pan-y;
  -webkit-overflow-scrolling: touch;
}

.preview-image {
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  display: block;
  user-select: none;
  -webkit-user-drag: none;
  cursor: zoom-in;
}
.preview-image.zoomed {
  cursor: zoom-out;
}
.preview-scroll:has(.preview-image.zoomed) { cursor: grab; }

.preview-toolbar {
  position: absolute;
  bottom: max(env(safe-area-inset-bottom, 0px), 14px);
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 6px;
  background: rgba(255, 255, 255, 0.14);
  backdrop-filter: blur(10px);
  border-radius: 999px;
  z-index: 1001;
}
.preview-btn {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: transparent;
  color: var(--wit);
  border: 0;
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}
.preview-btn:hover { background: rgba(255, 255, 255, 0.18); }
.preview-btn:active { background: rgba(255, 255, 255, 0.28); }
.preview-btn:focus-visible { outline: 2px solid var(--wit); outline-offset: 2px; }

.preview-level {
  color: var(--wit);
  font-size: 13px;
  font-weight: 600;
  min-width: 48px;
  text-align: center;
  padding: 0 4px;
  user-select: none;
}

.preview-close {
  position: absolute;
  top: max(env(safe-area-inset-top, 0px), 12px);
  right: 12px;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.18);
  backdrop-filter: blur(8px);
  color: var(--wit);
  border: 0;
  font-size: 28px;
  line-height: 1;
  cursor: pointer;
  z-index: 1001;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}
.preview-close:hover { background: rgba(255, 255, 255, 0.28); }
.preview-close:focus-visible { outline: 2px solid var(--wit); outline-offset: 2px; }

.preview-caption {
  position: absolute;
  top: max(env(safe-area-inset-top, 0px), 18px);
  left: 12px;
  color: rgba(255, 255, 255, 0.72);
  font-size: 13px;
  font-weight: 500;
  max-width: calc(100% - 80px);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  z-index: 1001;
  pointer-events: none;
}

/* ─── Mobile bijregelen (huisstijl pakt sidebar; topbar moet zelf) ──── */
@media (max-width: 640px) {
  header#topbar { padding: max(env(safe-area-inset-top, 0px), var(--space-3)) max(env(safe-area-inset-right, 0px), var(--space-4)) var(--space-3) max(env(safe-area-inset-left, 0px), var(--space-4)); gap: var(--space-2); }
  /* De logo-tekst verbergen we op mobiel: het oranje logo-icoon (brand-mark)
     is er nog én is ook een home-link. Zo past de topbar-rij (hamburger +
     icoon + help-boei + Uitloggen) binnen het scherm i.p.v. dat "Uitloggen"
     en de content door horizontale overflow buiten beeld vallen. */
  header#topbar .brand { display: none; }
  header#topbar nav a { padding: 6px 10px; font-size: 0.95rem; }
  /* Iets ruimere, gelijke zijmarges; kaart-padding juist terug zodat de
     content op smalle schermen niet klem komt te zitten. */
  main#app { padding: var(--space-5) var(--space-4) var(--space-9); }
  .card.card-padded,
  .card.card-danger { padding: var(--space-5); }
  .table th, .table td { padding: 10px 12px; }
  .table th { font-size: 10px; }
  .table td { font-size: 13px; }
  .review-list { grid-template-columns: 1fr; gap: 2px 0; }
  .review-list dt { margin-top: var(--space-2); }
  .file-grid { grid-template-columns: repeat(auto-fill, minmax(90px, 1fr)); }
}

/* === Install prompt =================================================== */

.install-banner {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  background: var(--ink);
  color: var(--geel-zacht);
  padding: 12px 16px;
  display: flex;
  align-items: center;
  gap: 12px;
  border-radius: 12px 12px 0 0;
  box-shadow: 0 -4px 12px rgba(0, 0, 0, 0.15);
  z-index: 1000;
  transform: translateY(100%);
  transition: transform 300ms ease-out;
  font-size: 14px;
}

.install-banner.visible {
  transform: translateY(0);
}

.install-banner-text {
  flex: 1 1 auto;
  min-width: 0;
}

.install-banner-cta {
  background: var(--geel);
  color: var(--ink);
  border: 0;
  border-radius: 6px;
  padding: 8px 14px;
  font-weight: 600;
  font-size: 14px;
  cursor: pointer;
  flex: 0 0 auto;
}
.install-banner-cta:hover { background: var(--wit); }
.install-banner-cta:focus-visible {
  outline: 2px solid var(--wit);
  outline-offset: 2px;
}

.install-banner-later {
  background: transparent;
  color: var(--geel-zacht);
  border: 0;
  text-decoration: underline;
  font-size: 13px;
  padding: 8px 4px;
  cursor: pointer;
  flex: 0 0 auto;
  opacity: 0.85;
}
.install-banner-later:hover { opacity: 1; }
.install-banner-later:focus-visible {
  outline: 2px solid var(--geel-zacht);
  outline-offset: 2px;
}

.install-banner-close {
  background: transparent;
  color: var(--geel-zacht);
  border: 0;
  font-size: 22px;
  line-height: 1;
  padding: 4px 8px;
  cursor: pointer;
  flex: 0 0 auto;
  opacity: 0.7;
}
.install-banner-close:hover { opacity: 1; }
.install-banner-close:focus-visible {
  outline: 2px solid var(--geel-zacht);
  outline-offset: 2px;
}

@media (max-width: 380px) {
  .install-banner-text { font-size: 13px; }
  .install-banner-cta { padding: 6px 10px; font-size: 13px; }
  .install-banner-later { display: none; }
}

/* iOS-instructie-overlay */
.install-ios-overlay {
  position: fixed;
  inset: 0;
  background: rgba(22, 32, 43, 0.92);
  color: var(--geel-zacht);
  z-index: 1100;
  padding: 24px 20px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  text-align: center;
  font-size: 15px;
}

.install-ios-close {
  align-self: flex-end;
  background: rgba(255, 255, 255, 0.15);
  color: var(--geel-zacht);
  border: 0;
  padding: 6px 14px;
  border-radius: 6px;
  font-size: 14px;
  cursor: pointer;
}
.install-ios-close:focus-visible {
  outline: 2px solid var(--geel-zacht);
  outline-offset: 2px;
}

.install-ios-content { margin-top: 24px; }

.install-ios-content h2 {
  font-size: 20px;
  margin: 0 0 16px;
}

.install-ios-steps {
  text-align: left;
  background: rgba(255, 255, 255, 0.08);
  border-radius: 12px;
  padding: 16px 16px 16px 40px;
  font-size: 15px;
  line-height: 1.6;
}
.install-ios-steps li { margin-bottom: 8px; }
.install-ios-steps li:last-child { margin-bottom: 0; }
.install-ios-steps small {
  display: block;
  opacity: 0.75;
  font-size: 12px;
  margin-top: 4px;
}

.install-ios-arrow-hint { padding-bottom: 60px; }

.install-ios-arrow {
  font-size: 40px;
  color: var(--geel);
  animation: install-bounce 1s infinite;
  margin-bottom: 4px;
}

.install-ios-arrow-hint small {
  opacity: 0.85;
  font-size: 13px;
}

@keyframes install-bounce {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(8px); }
}

body.install-overlay-open { overflow: hidden; }

@media (prefers-reduced-motion: reduce) {
  .install-banner { transition: none; }
  .install-ios-arrow { animation: none; }
}

/* === Dropzone (file upload) ============================================ */

/* v3.0: was een halfdoorzichtig wit vlak (rgba(255,255,255,.5)) — dat werkte
   op de oude crème pagina-achtergrond, maar valt op een witte pagina/kaart
   samen met zijn omgeving. Een effen lichte neutrale ondergrond (--grijs-50)
   blijft zichtbaar, ongeacht wat erachter zit. */
.dropzone {
  position: relative;
  border: 2px dashed var(--lichtgroen);
  border-radius: 12px;
  padding: 28px 20px;
  text-align: center;
  cursor: pointer;
  transition: background 180ms ease, border-color 180ms ease, transform 180ms ease;
  background: var(--grijs-50);
}

.dropzone:hover {
  background: var(--wit);
  border-color: var(--ink);
}

.dropzone:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}

.dropzone.drag-over {
  border-style: solid;
  border-color: var(--ink);
  background: rgba(22, 32, 43, 0.06);
  transform: scale(1.005);
}

.dropzone .dropzone-icon {
  font-size: 32px;
  line-height: 1;
  margin-bottom: 8px;
}

.dropzone .dropzone-empty strong {
  display: block;
  margin-bottom: 4px;
  color: var(--ink);
  font-size: 16px;
}

.dropzone .dropzone-sub {
  color: var(--ink-3);
  font-size: 14px;
}

.dropzone .dropzone-filled {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  flex-wrap: wrap;
}

.dropzone .dropzone-filled .dropzone-icon {
  margin-bottom: 0;
  font-size: 24px;
}

.dropzone .dropzone-filename {
  flex: 0 1 auto;
  max-width: 70%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-weight: 500;
  color: var(--ink);
}

.dropzone .dropzone-remove {
  background: transparent;
  border: 1px solid var(--ink-3);
  color: var(--ink);
  border-radius: 999px;
  width: 28px;
  height: 28px;
  cursor: pointer;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 14px;
  line-height: 1;
}

.dropzone .dropzone-remove:hover {
  background: rgba(0, 0, 0, 0.05);
  border-color: var(--ink);
}

.dropzone .dropzone-remove:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  .dropzone { transition: none; }
  .dropzone.drag-over { transform: none; }
}

/* Gevonden tijdens de UX-check van het vervangen-formulier (taak 9), maar ook
   al aanwezig op het bestaande invoerformulier: het HTML-attribuut [hidden]
   verbergt hier niets, terwijl de JS (emptyView.hidden = true) het attribuut
   wél netjes zet. De oorzaak is geen specificiteitsstrijd maar de cascade-
   *oorsprong*: `[hidden] { display: none }` komt uit het browser-eigen (UA)
   stijlblad, en een auteursregel wint altijd van een UA-regel, ongeacht
   specificiteit. `.dropzone .dropzone-filled` (auteur, display:flex) wint dus
   hoe dan ook van het browserdefault, en de "gevuld"-weergave (bestandsnaam +
   kruisje) bleef zichtbaar náást de lege dropzone zodra er een PDF gekozen
   was. Zodra we zelf een auteursregel voor [hidden] toevoegen, spelen beide
   regels in dezelfde oorsprong en beslist specificiteit alsnog normaal — vandaar
   dat een net iets specifiekere regel hier wél werkt, zonder de bestaande JS
   (die alleen het attribuut toggelt) te hoeven aanpassen.
   Zie /js/pages/inkoopfactuur-nieuw.js en vervangFormulierHtml() in
   inkoopfactuur-detail.js — allebei gebruiken hetzelfde dropzone-patroon. */
.dropzone .dropzone-empty[hidden],
.dropzone .dropzone-filled[hidden] {
  display: none;
}

/* .correctie-blok: het gele attentieblok bovenaan de rechterkolom van de
   factuurdetailpagina (correctieBlok() in inkoopfactuur-detail.js) — dezelfde
   geel-tinten als .status-aandacht in huisstijl.css, maar dan als
   paneelachtergrond met een linker accentrand i.p.v. een pil.
   .vervang-form: kleine correctie op de standaard form-marge zodat het
   formulier direct onder de knop "Factuur vervangen" aansluit, zonder het
   dubbele tussenruimte-gevoel van de generieke .form-group-marges erboven. */
.correctie-blok {
  background: var(--geel-licht);
  border-left: 4px solid var(--geel-donker);
}
.vervang-form {
  margin-top: 2px;
}

/* ─── Tabellen op smalle schermen: horizontaal scrollbaar ────────────────
   Op een smal scherm kan een tabel breder worden dan het scherm (bijv. door
   een lange naam of veel kolommen); overflow-x op de <table> zelf werkt
   daar niet voor (een table met width:auto negeert de container en duwt 'm
   juist uit elkaar) — de scroll-grens moet op een omringende <div> staan
   die zelf wél normaal binnen zijn container blijft. Gebruikt door alle
   admin-tabellen en de betalingenlijst. */
.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }

/* Status-kolom (gebruikerstabel): badge + Activeren/Deactiveren-knop.
   Gestapeld (badge boven knop) i.p.v. naast elkaar voor een compacte kolom. */
.users-table .status-cel {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
}
.users-table .status-cel .status { align-self: flex-start; }
/* Inline bevestiging bij deactiveren (i.p.v. confirm(), die de pagina
   blokkeert): naam + uitleg dat dit alleen de toegang tot deze app raakt,
   plus Ja/Annuleren. max-width houdt de kolom — en dus de tabel — ongeveer
   even breed als in de normale stand. */
.users-table .status-cel-bevestig { max-width: 220px; }
.users-table .deactiveer-vraag {
  font-size: 13px;
  font-weight: 600;
  margin: 0;
}
.users-table .deactiveer-uitleg {
  font-size: 12px;
  margin: 0;
}
.users-table .deactiveer-acties {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  margin-top: 2px;
}

/* Generieke inline bevestiging (i.p.v. confirm(), die de pagina blokkeert) —
   vraag + korte uitleg + Ja/Annuleren, als kaartje ná de actie die 'm veroorzaakt.
   Zelfde gedachte als .users-table .status-cel-bevestig hierboven, maar zonder
   de tabelkolom-beperking (max-width) — gebruikt door beheerschermen buiten een
   tabel, zoals Instellingen (afsluitdag/handmatig afsluiten). */
.confirm-inline {
  background: var(--grijs-50);
  border-radius: 8px;
  padding: 14px;
  margin-top: 12px;
}
.confirm-inline .confirm-vraag {
  font-weight: 600;
  margin: 0 0 4px;
}
.confirm-inline .confirm-uitleg {
  margin: 0;
}
.confirm-inline .confirm-acties {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  margin-top: 10px;
}

/* Uitgeklapte detail-rij in tabel — grijze tint zodat het visueel bij elkaar hoort.
   Generiek: wordt ook gebruikt door de leveranciers-tabel (.lev-row.is-expanded). */
tr.expanded-detail { display: none; }
tr.expanded-detail.is-open { display: table-row; }
tr.expanded-detail > td {
  padding: 0 16px 16px;
  background: var(--grijs-50);
  border-top: 0;
}
tr.is-expanded > td { background: var(--grijs-50); }

/* ─── Draft-strip: onverzonden concept teruggevonden ─────────────────── */
.draft-strip {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  margin-bottom: var(--gap-card);
  background: var(--oranje-50);
  border: 1px solid var(--oranje);
  border-radius: 8px;
}
.draft-strip-text {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.draft-strip-text strong { color: var(--ink); font-weight: 700; }
.draft-strip-text .muted { font-size: 13px; }
.draft-strip-actions {
  display: flex;
  gap: 8px;
  flex-shrink: 0;
}
@media (max-width: 600px) {
  .draft-strip {
    flex-direction: column;
    align-items: stretch;
  }
  .draft-strip-actions {
    justify-content: flex-end;
  }
}

/* ─── Hamburger + slide-in drawer (mobile ≤640px) ───────────────────── */

/* Zit in de blauwe topbar → wit i.p.v. het oude crème-fallback. */
.hamburger { display: none; background: none; border: 0; color: var(--wit, #ffffff); cursor: pointer; padding: 8px; margin-right: 4px; }
.hamburger svg { display: block; }

.drawer-overlay { position: fixed; inset: 0; background: rgba(22, 32, 43,.45); opacity: 0; transition: opacity .2s ease; z-index: 150; }
.drawer-overlay.open { opacity: 1; }

/* De drawer is een eigen wit paneel (was crème) — sluit aan bij de witte
   pagina-achtergrond van v3.0 i.p.v. de oude crème ondergrondkleur. */
.drawer {
  position: fixed; top: 0; left: 0; bottom: 0; width: 80%; max-width: 300px;
  background: var(--wit, #ffffff); border-right: 1px solid rgba(22, 32, 43,.12);
  transform: translateX(-100%); visibility: hidden;
  transition: transform .2s ease, visibility .2s ease; z-index: 160; overflow-y: auto; padding: 12px 0;
}
.drawer.open { transform: translateX(0); visibility: visible; }
.drawer-link { display: block; padding: 11px 18px; color: var(--ink, #16202B); text-decoration: none; font-weight: 600; font-size: 15px; }
.drawer-link:hover { background: rgba(30, 115, 190,.08); }
.drawer-link.active { color: var(--groen, #1B47C1); background: rgba(231, 239, 247,.25); box-shadow: inset 3px 0 0 var(--oranje, #1B47C1); }
.drawer-group { margin-top: 6px; }
.drawer-group-label { font-size: 11px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase; color: rgba(22, 32, 43,.55); padding: 12px 18px 4px; }
.drawer-group .drawer-link { padding-left: 30px; }

@media (max-width: 640px) {
  header#topbar nav { display: none; }
  .hamburger { display: inline-flex; align-items: center; }
}

/* ─── Help-boei + rondleiding ─────────────────────────────────────────── */
/* v3.0: wit i.p.v. het oude lichtgroen (--blauw-zacht, #E7EFF7) — dat pale
   blauw stak nauwelijks af tegen de eveneens blauwe topbar. Focusring geel:
   dezelfde reden als de topbar-brede focusregel hierboven. */
.help-boei {
  width: 38px; height: 38px; flex: 0 0 auto; margin-left: auto;
  border-radius: 50%; border: 1.5px solid rgba(255, 255, 255, .55);
  background: rgba(255, 255, 255, .14); color: var(--wit);
  display: inline-flex; align-items: center; justify-content: center;
  cursor: pointer; padding: 0;
  transition: background .15s var(--ease), border-color .15s var(--ease), transform .15s var(--ease);
}
.help-boei:hover { background: rgba(255, 255, 255, .28); border-color: var(--wit); color: var(--wit); transform: translateY(-1px); }
.help-boei:focus-visible { outline: 3px solid var(--geel); outline-offset: 2px; }
.help-boei svg { width: 20px; height: 20px; }

#rl-blocker { position: fixed; inset: 0; z-index: 2100; display: none; }
#rl-blocker.dim { background: rgba(22, 32, 43, .74); }

#rl-spotlight {
  position: fixed; z-index: 2101; pointer-events: none; display: none;
  border-radius: 14px; outline: 3px solid var(--lichtgroen);
  box-shadow: 0 0 0 9999px rgba(22, 32, 43, .74);
  transition: top .3s cubic-bezier(.3, .7, .3, 1), left .3s cubic-bezier(.3, .7, .3, 1), width .3s, height .3s;
}

#rl-callout {
  position: fixed; z-index: 2102; display: none;
  width: min(340px, calc(100vw - 24px));
  background: var(--wit); border-radius: var(--r-md); box-shadow: var(--shadow-lg);
  padding: 20px 20px 16px;
}
#rl-callout .rl-top { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 8px; }
#rl-callout .rl-count { font-size: 12px; font-weight: 800; letter-spacing: .05em; text-transform: uppercase; color: var(--oranje-donker); }
#rl-callout .rl-x { width: 28px; height: 28px; border: none; cursor: pointer; background: var(--groen-50); color: var(--ink-2); border-radius: 50%; font-size: 15px; line-height: 1; display: inline-flex; align-items: center; justify-content: center; }
#rl-callout .rl-x:hover { background: var(--groen-100); }
#rl-callout h3 { margin: 0 0 6px; font-size: 17px; font-weight: 800; letter-spacing: -.01em; }
#rl-callout p { margin: 0 0 16px; font-size: 14px; line-height: 1.5; color: var(--ink-2); }
#rl-callout .rl-dots { display: flex; gap: 6px; margin-bottom: 14px; flex-wrap: wrap; }
#rl-callout .rl-dots i { width: 7px; height: 7px; border-radius: 50%; background: rgba(22, 32, 43, .15); }
#rl-callout .rl-dots i.on { width: 20px; border-radius: var(--r-pill); background: var(--oranje); }
#rl-callout .rl-actions { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
#rl-callout .rl-ghost { background: transparent; border: none; cursor: pointer; font-family: inherit; font-weight: 700; font-size: 14px; color: var(--ink-2); padding: 8px 4px; }
#rl-callout .rl-ghost:hover { color: var(--ink); }
#rl-callout .rl-next { background: var(--groen); color: var(--wit); border: none; cursor: pointer; font-family: inherit; font-weight: 800; font-size: 14px; padding: 11px 22px; border-radius: var(--r-pill); }
#rl-callout .rl-next:hover { background: var(--blauw-diep); }
/* Incidentele meegenomen fix: dit paneel staat op wit (--wit), en het oude
   --lichtgroen (#E7EFF7) als focusring daar meet slechts ~1,05:1 — vrijwel
   onzichtbaar. Blauw, net als de andere focusringen op een witte ondergrond
   in deze app. */
#rl-callout button:focus-visible { outline: 3px solid var(--blauw); outline-offset: 2px; }

@media (prefers-reduced-motion: reduce) {
  #rl-spotlight { transition: none; }
}

/* ─── Maand-herinnering (bovenaan "Mijn declaraties") ─────────────────── */
.maand-reminder {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  background: var(--groen-50);
  border: 1px solid var(--groen-100);
  border-left: 4px solid var(--lichtgroen);
  border-radius: var(--r-sm);
  padding: 14px 16px;
  margin-bottom: var(--gap-card);
}
.maand-reminder-icon {
  width: 22px; height: 22px; flex-shrink: 0;
  color: var(--groen); margin-top: 1px;
}
.maand-reminder-tekst { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.maand-reminder-tekst p { margin: 0; font-size: 14px; line-height: 1.45; color: var(--ink); }
.maand-reminder-tekst strong { color: var(--groen); font-weight: 800; }

/* ─── Tabellen → kaarten op mobiel (Mijn declaraties · Inbox · Goedgekeurd) ──
   Gedeelde basis (.cards-mobile): maakt van elke <tr> een kaart en styleert de
   cel-rollen via data-col (zelfde betekenis op elke pagina). Per pagina bepaalt
   een eigen class alléén de grid-indeling. Scope-classes houden andere .table's
   (admin) ongemoeid. Desktop verandert niet: alles zit in de mobiele query. */
@media (max-width: 640px) {
  .table.cards-mobile { background: transparent; border: none; box-shadow: none; border-radius: 0; overflow: visible; }
  .table.cards-mobile thead { display: none; }
  .table.cards-mobile tbody { display: flex; flex-direction: column; gap: 10px; }
  .table.cards-mobile tr {
    display: grid;
    grid-template-columns: auto 1fr auto;
    align-items: center;
    column-gap: 8px; row-gap: 3px;
    background: var(--wit);
    border: 1px solid rgba(22, 32, 43, .06);
    border-radius: var(--r-md);
    box-shadow: var(--shadow-xs);
    padding: 14px 16px;
  }
  .table.cards-mobile td { border: none; padding: 0; font-size: 13px; }

  /* Gedeelde cel-rollen (zelfde data-col-betekenis op elke pagina) */
  .table.cards-mobile td[data-col="categorie"] { font-size: 15.5px; font-weight: 800; letter-spacing: -.01em; color: var(--ink); }
  .table.cards-mobile td[data-col="bedrag"]    { font-size: 16px; font-weight: 800; color: var(--ink); font-variant-numeric: tabular-nums; margin-top: 2px; }
  .table.cards-mobile td[data-col="bedrag"] .muted { font-size: 11px; font-weight: 700; color: var(--oranje-donker); }
  .table.cards-mobile td[data-col="status"]    { justify-self: end; }
  .table.cards-mobile td[data-col="datum"]     { color: var(--ink-3); }
  /* Deze cel houdt vrije tekst die iemand zelf intypt: een indienernaam of een
     leveranciersnaam. Zit daar één lang woord zonder spatie in
     ("Energieleverancier"), dan is dát woord de min-content-breedte van de
     grid-kolom waarin de cel staat — de middelste (`1fr`) bij betalingen, de
     eerste (`auto`) bij inbox en goedgekeurd. Een grid-item heeft standaard een
     automatische minimumbreedte gelijk aan zijn min-content, ongeacht de
     track-sizing, dus de kaart werd breder dan zijn scrollcontainer en die ging
     horizontaal scrollen — op elke schermbreedte, want de kaart kan niet
     krimpen. `min-width: 0` haalt die automatische ondergrens weg (zelfde truc
     als bij vestiging hieronder); daarna moet de tekst zélf nog kunnen breken,
     anders loopt het woord gewoon over de buurkolom heen.

     Gemeten min-content van "Energieleveranciersmaatschappij" op 15,5px:

       kaal                        228px
       overflow-wrap: break-word   228px   (telt NIET mee, dus nutteloos hier)
       hyphens: auto                47px   (breekt op lettergrepen)
       overflow-wrap: anywhere      13px   (breekt overal)

     Vandaar allebei. `hyphens: auto` werkt omdat het document `lang="nl"` heeft
     (index.html) en levert een leesbare breuk mét koppelteken — leveranciers-
     namen zijn vrijwel altijd samenstellingen. Maar het garandeert niets: een
     woord zonder geldige afbreekpunten, of een kolom smaller dan de langste
     lettergreep, loopt er alsnog uit. `anywhere` is het vangnet; de browser
     gebruikt de nette afbreekpunten zolang die er zijn. */
  .table.cards-mobile td[data-col="indiener"]  {
    color: var(--ink-3); min-width: 0;
    overflow-wrap: anywhere; -webkit-hyphens: auto; hyphens: auto;
  }
  .table.cards-mobile td[data-col="indiener"] strong { font-weight: 700; }
  .table.cards-mobile td[data-col="bonnen"]    { justify-self: end; color: var(--ink-3); display: inline-flex; align-items: center; gap: 5px; }
  .table.cards-mobile td[data-col="bonnen"]::before {
    content: ""; width: 14px; height: 14px; flex: none; background: currentColor; opacity: .7;
    -webkit-mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48'/></svg>") center / contain no-repeat;
            mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48'/></svg>") center / contain no-repeat;
  }

  /* Mijn declaraties: datum · bedrag · bonnen als meta-regel (één vestiging
     in deze club, dus geen aparte vestigingkolom meer). */
  .table.declaraties-cards tr { grid-template-areas: "categorie categorie status" "datum bedrag bonnen"; }
  .table.declaraties-cards td[data-col="categorie"] { grid-area: categorie; }
  .table.declaraties-cards td[data-col="status"]    { grid-area: status; }
  .table.declaraties-cards td[data-col="datum"]     { grid-area: datum; }
  .table.declaraties-cards td[data-col="bedrag"]    { grid-area: bedrag; }
  .table.declaraties-cards td[data-col="bonnen"]    { grid-area: bonnen; }

  /* Inbox: categorie + datum boven, indiener · bedrag · bonnen; knop weg */
  .table.inbox-cards tr { grid-template-areas: "categorie categorie datum" "indiener bedrag bonnen"; }
  .table.inbox-cards td[data-col="categorie"] { grid-area: categorie; }
  .table.inbox-cards td[data-col="datum"]     { grid-area: datum; justify-self: end; text-align: right; }
  .table.inbox-cards td[data-col="indiener"]  { grid-area: indiener; }
  .table.inbox-cards td[data-col="bedrag"]    { grid-area: bedrag; }
  .table.inbox-cards td[data-col="bonnen"]    { grid-area: bonnen; }
  .table.inbox-cards td[data-col="actie"]     { display: none; }

  /* Goedgekeurd: categorie + status, indiener, goedgekeurd op (+ door), bedrag; aankoopdatum weg */
  .table.goedgekeurd-cards tr { grid-template-areas: "categorie categorie status" "indiener indiener indiener" "akkoord akkoord door" "bedrag bedrag bedrag"; }
  .table.goedgekeurd-cards td[data-col="categorie"] { grid-area: categorie; }
  .table.goedgekeurd-cards td[data-col="status"]    { grid-area: status; }
  .table.goedgekeurd-cards td[data-col="indiener"]  { grid-area: indiener; }
  .table.goedgekeurd-cards td[data-col="akkoord"]   { grid-area: akkoord; color: var(--ink-3); font-size: 12.5px; }
  .table.goedgekeurd-cards td[data-col="akkoord"]::before { content: "Goedgekeurd op "; }
  .table.goedgekeurd-cards td[data-col="door"]      { grid-area: door; justify-self: end; color: var(--ink-3); font-size: 12.5px; }
  .table.goedgekeurd-cards td[data-col="door"]::before { content: "door "; }
  .table.goedgekeurd-cards td[data-col="bedrag"]    { grid-area: bedrag; }
  .table.goedgekeurd-cards td[data-col="datum"]     { display: none; }

  /* Betalingen: kies + naam + status boven, datum · soort, bedrag, bon.
     Categorie/omschrijving/ingediend/goedgekeurd blijven op mobiel
     verborgen — wie moet corrigeren doet dat op desktop. */
  .table.betalingen-cards tr {
    grid-template-areas:
      "kies indiener status"
      "datum soort soort"
      "bedrag bonnen bonnen"
      "acties acties acties";
    /* Kolom 3 (status) krijgt hier een harde bovengrens i.p.v. het gedeelde
       'auto' van .table.cards-mobile hierboven: een correctiebadge plus reden
       ("Correctie gevraagd op 20 aug 2026 — Verkeerde tenaamstelling…") is véél
       breder dan een korte statuspil, en 'auto' rekt een kolom uit tot de
       ongebroken breedte van zijn breedste inhoud. white-space:normal op
       .status (zie .cards-mobile hierboven) helpt dan niet: dat bepaalt alleen
       of de tekst mag afbreken bij een gegeven breedte, niet hoe breed de
       kolom eerst wordt. Met een vaste bovengrens moet die tekst wél binnen
       140px passen en afbreken — en houdt de Naam-kolom (1fr) ernaast altijd
       een redelijk aandeel over.

       Kolom 1 (kies/datum/bedrag) had exact hetzelfde lek, alleen minder
       opvallend: 'auto' zit hier ook op een <select>-vrije checkboxcel, een
       datum ("30 aug 2026") én — bij een inkoopfactuur zonder bedrag — de pil
       "Bedrag ontbreekt" (.status.status-aandacht). Die pil heeft geen eigen
       white-space:nowrap, dus hij mag best afbreken, maar dat maakt voor de
       kolombreedte niets uit: 'auto' meet zijn max-content-bijdrage, en dat is
       per definitie de ongebroken breedte (alsof er nooit wordt afgebroken),
       ongeacht white-space. Met een lange datum ernaast in dezelfde kolom werd
       kolom 1 zo tot ~130px opgerekt; samen met kolom 3's 140px bleef er voor
       de Naam-kolom (1fr) nog maar een paar pixels over, en brak elke letter
       van de naam op zijn eigen regel. Zelfde geneesmiddel: een harde
       bovengrens dwingt "Bedrag ontbreekt" om binnen 96px af te breken (ruim
       genoeg voor een datum als "30 aug 2026" op één regel), en laat de
       Naam-kolom altijd het merendeel van de kaart houden. */
    grid-template-columns: minmax(0, 96px) 1fr minmax(0, 140px);
  }
  .table.betalingen-cards td[data-col="kies"]     { grid-area: kies; justify-self: start; }
  .table.betalingen-cards td[data-col="indiener"] { grid-area: indiener; font-weight: 800; color: var(--ink); font-size: 15.5px; }
  .table.betalingen-cards td[data-col="status"]   { grid-area: status; justify-self: end; text-align: right; }
  .table.betalingen-cards td[data-col="datum"]    { grid-area: datum; }
  .table.betalingen-cards td[data-col="soort"]    { grid-area: soort; color: var(--ink-3); }
  .table.betalingen-cards td[data-col="bedrag"]   { grid-area: bedrag; }
  .table.betalingen-cards td[data-col="bonnen"]   { grid-area: bonnen; justify-self: end; }
  /* Het potlood (en op een inkoopfactuur de correctieknop) staat op desktop in
     een eigen kolom achteraan; in de kaart krijgt die actie een eigen volle
     regel onderaan i.p.v. de derde (status-)kolom te delen. Eerst stond acties
     in dezelfde kolom als status (net als op desktop, waar het gewoon de
     laatste kolom is) — maar "Correctie vragen"/"Verzoek intrekken" is een
     tekstknop, geen los icoontje, en een grid-kolom rekt zich uit tot de
     ongebroken breedte van zijn breedste cel. Gedeeld met de status-kolom duwde
     die kolom zo breed dat de Naam-kolom (1fr, ernaast) bijna geen ruimte meer
     overhield en letter voor letter ging afbreken. Een eigen rij die alle drie
     de kolommen overspant raakt de kolombreedtes niet op dezelfde manier. */
  .table.betalingen-cards td[data-col="acties"] {
    grid-area: acties; justify-self: end;
    display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 6px;
    margin-top: 2px;
  }
  .table.betalingen-cards td[data-col="acties"] .btn-correctie-vragen,
  .table.betalingen-cards td[data-col="acties"] .btn-correctie-intrekken { margin-left: 0; }
  /* Op desktop staat de statusbadge op één regel om de rijhoogte gelijk te
     houden; in een kaart van 390px past "Betaald 14 aug 2026" niet op één
     regel en zou de kaart horizontaal gaan scrollen. Hier mag hij dus wél
     afbreken — verticale ruimte is in een kaart geen probleem. */
  .table.betalingen-cards td[data-col="status"] .status { white-space: normal; }
  /* Afgehandelde kaart: dezelfde demping als de tabelrij, plus een rustiger
     rand — op mobiel is elke rij een eigen kaartje en valt kleurverschil in de
     tekst minder op dan in een tabel. De tint hoort hier op de kaart en niet
     op de cellen: een kaart is een grid mét kolom- en rijtussenruimte, dus
     losse celachtergronden laten witte gaten open en maken er een gevlekt
     kaartje van. Vandaar de reset op de td's, óók voor hover. */
  .table.betalingen-cards tr.is-afgehandeld { background: var(--grijs-200); box-shadow: none; }
  .table.betalingen-cards tr.is-afgehandeld td,
  .table.betalingen-cards tr.is-afgehandeld:hover td,
  .table.betalingen-cards tr.is-open:hover td { background: transparent; }
  /* Hover bestaat op touch niet, maar wel in een smal desktopvenster — dus ook
     de hoverkleuren horen hier op de kaart en niet op de cellen. */
  .table.betalingen-cards tr.is-afgehandeld:hover { background: var(--grijs-200); }
  .table.betalingen-cards tr.is-open:hover { background: var(--oranje-50); }
  /* Openstaande kaart: dezelfde accentrail als in de tabel, hier als inset
     langs de linkerrand van het kaartje. De eigen schaduw blijft staan — een
     losse `box-shadow` zou die vervangen en de kaart plat maken. */
  .table.betalingen-cards tr.is-open { box-shadow: inset 4px 0 0 var(--oranje), var(--shadow-xs); }
  .table.betalingen-cards tr.is-open td[data-col="kies"] { box-shadow: none; }
  /* Het bedrag staat in elke kaart al op 16px/800 (zie .cards-mobile
     hierboven); in een afgehandelde kaart mag het een maatje kleiner. */
  .table.betalingen-cards tr.is-afgehandeld td[data-col="bedrag"] { font-size: 15px; font-weight: 700; color: var(--ink-2); }
  /* Op desktop is 700 een lift boven de normale rij; in een kaart is 800 juist
     de norm voor naam en bedrag (`.table.cards-mobile td[data-col="bedrag"]` en
     `.table.betalingen-cards td[data-col="indiener"]` hierboven) en is 700 dus
     een demping. Die kaartregels hebben specificiteit (0,3,1) en verliezen van
     de desktopregel `tbody tr.is-open td[…]` (0,3,3), die niet in een
     media-query zit en hier dus gewoon meedoet. Zonder de twee regels hieronder
     drukte die desktopregel de openstaande kaart terug naar 700 terwijl de
     afgehandelde op 800 bleef — precies de omgekeerde hiërarchie. */
  .table.betalingen-cards tr.is-open td[data-col="indiener"],
  .table.betalingen-cards tr.is-open td[data-col="bedrag"] { font-weight: 800; }
  .table.betalingen-cards tr.is-afgehandeld td[data-col="indiener"] { font-weight: 700; }
  /* Blokkop tussen de kaarten: geen kaart, maar een kopje op de pagina. */
  .table.betalingen-cards tr.betalingen-blokkop {
    display: block; background: transparent; border: none;
    box-shadow: none; padding: var(--space-3) 2px 0;
  }
  .table.betalingen-cards tr.betalingen-blokkop:first-child { padding-top: 0; }
  .table.betalingen-cards tr.betalingen-blokkop td { display: block; padding: 0; }
  .table.betalingen-cards td[data-col="categorie"],
  .table.betalingen-cards td[data-col="omschrijving"],
  .table.betalingen-cards td[data-col="ingediend"],
  .table.betalingen-cards td[data-col="akkoord"] { display: none; }
}

/* ─── Betaalkeuze: verplichte of/of-keuze (voorgeschoten vs. bedrijfspas) ── */
.betaal-keuze {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-3);
}

.betaal-optie {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  text-align: left;
  padding: var(--space-4);
  padding-right: var(--space-8);   /* ruimte voor het vinkje rechtsboven */
  position: relative;
  background: var(--wit);
  border: 2px solid var(--groen-100);
  border-radius: var(--r-md);
  font-family: inherit;
  cursor: pointer;
  transition: border-color .15s ease, background-color .15s ease, box-shadow .15s ease;
}

.betaal-optie:hover { border-color: var(--lichtgroen); }

.betaal-optie:focus-visible {
  outline: 2px solid var(--groen);
  outline-offset: 2px;
}

.betaal-optie-titel {
  font-weight: 800;
  font-size: 15px;
  color: var(--ink);
}

.betaal-optie-sub {
  font-size: 13px;
  color: var(--ink-2);
}

.betaal-optie.is-selected {
  border-color: var(--groen);
  background: var(--groen-50);
  box-shadow: inset 0 0 0 1px var(--groen);
}

/* Vinkje rechtsboven bij de gekozen optie */
.betaal-optie.is-selected::after {
  content: "✓";
  position: absolute;
  top: var(--space-3);
  right: var(--space-3);
  width: 22px;
  height: 22px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--groen);
  color: var(--wit);
  font-size: 13px;
  font-weight: 800;
  line-height: 1;
}

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

/* ——— Betaaloverzicht ——— */

/* Dit scherm mag breder dan de standaard 1100px-contentbreedte van main#app:
   dertien kolommen (zie .betalingen-cards hieronder) hebben de ruimte nodig die
   op een 1440/1920-scherm toch al onbenut ligt. Alleen deze pagina zet de
   `betalingen-breed`-class (public/js/pages/betalingen.js) — elk ander scherm
   houdt de normale 1100px-cap. min(…, 96vw) i.p.v. een kale 1600px: op een
   ultrawide monitor blijft er dan nog steeds lucht aan weerszijden i.p.v. een
   tabel die de volle breedte van het scherm claimt. Alleen vanaf 641px: onder
   die breedte schakelt de tabel al om naar de kaartweergave (zie
   .table.cards-mobile hierboven) en zou 96vw juist smaller zijn dan de
   gewone 1100px-cap. */
@media (min-width: 641px) {
  main#app.betalingen-breed { max-width: min(1600px, 96vw); }
}

.betalingen-filters {
  /* Gelijke rij- en kolomruimte (i.p.v. een bredere kolom-gap): met de
     BV-select erbij passen Periode/BV/Soort/Status weer samen op de eerste
     regel van de contentbreedte — bij de ruimere gap brak die rij na vier
     velden in een onevenwichtige 4+3-verdeling. */
  display: flex; flex-wrap: wrap; gap: var(--space-3); align-items: flex-end; margin: var(--space-4) 0;
}
.betalingen-filters label { display: flex; flex-direction: column; gap: var(--space-1); font-size: 13px; color: var(--ink-3); }
/* Vaste/gemin. breedtes i.p.v. losjes content-breed: anders springen de velden
   op een smallere desktop-breedte (of tijdens het wrappen) willekeurig van
   grootte t.o.v. elkaar. Zoek mag als enige meegroeien met de resterende ruimte. */
.betalingen-filters label:has(input[type="date"]) { flex: 0 0 auto; }
.betalingen-filters label:has(select) { flex: 0 0 auto; min-width: 160px; }
.betalingen-filters label:has(input[type="search"]) { flex: 1 1 200px; min-width: 160px; }

/* ─── Maandstapper: de primaire periode-control ──────────────────────────
   ◀ Augustus 2026 ▶ · vrije periode. Vervangt de losse Van/Tot-velden voor
   het gewone geval ("blader een maand terug/vooruit"); die velden blijven
   achter de hand voor het uitzonderingsgeval (kwartaal, losse week). */
.betalingen-periode { display: flex; align-items: center; gap: var(--space-3); flex: 0 0 auto; }
.maand-stepper { display: flex; align-items: center; gap: var(--space-2); }
.maand-stap-knop {
  width: 32px; height: 32px; flex: none; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 50%; border: 1.5px solid var(--rule-strong);
  background: var(--wit); color: var(--ink); font-size: 12px; cursor: pointer;
  transition: background .15s var(--ease), border-color .15s var(--ease);
}
.maand-stap-knop:hover { background: var(--grijs-50); border-color: var(--ink); }
.maand-stap-knop:focus-visible { outline: 2px solid var(--oranje); outline-offset: 2px; }
.maand-stepper-label {
  min-width: 132px; text-align: center;
  font-weight: 700; font-size: 15px; color: var(--ink);
}
/* label.vrije-periode-toggle (met type-selector) i.p.v. kaal .vrije-periode-toggle:
   dit is óók een <label> binnen .betalingen-filters, en de generieke
   `.betalingen-filters label { flex-direction: column }` hierboven heeft
   specificiteit (0,1,1) — daar verliest een kale `.vrije-periode-toggle` (0,1,0)
   van. Mét de type-selector komt deze regel op diezelfde (0,1,1) uit en beslist
   de bronvolgorde: hij staat later in dit bestand en wint dus. Zonder die gelijke
   specificiteit zou de kolom-richting blijven staan — met precies hetzelfde
   "·"-bolletje dat dan los boven het vinkje kwam i.p.v. ervoor. */
label.vrije-periode-toggle {
  display: flex; flex-direction: row; align-items: center; gap: 6px;
  font-size: 13px; color: var(--ink-3); cursor: pointer; white-space: nowrap;
}
.vrije-periode-toggle::before {
  content: "·"; margin-right: 6px; color: var(--rule-strong); font-weight: 700;
}
.vrije-periode-toggle input { width: auto; margin: 0; cursor: pointer; }
/* :not([hidden]) i.p.v. kaal `display:flex`: het verbergen komt van
   `[hidden] { display: none }` uit het UA-stijlblad, en de cascade zet de
   auteurs-origin altijd boven de UA-origin — dat gaat vóór specificiteit en
   bronvolgorde. Een kale `.vrije-periode-velden { display: flex }` zou het dus
   hoe dan ook winnen en de velden zichtbaar houden terwijl de maandstapper
   actief hoort te zijn. Met :not([hidden]) geldt de regel alleen zolang het
   attribuut er niet staat. */
.vrije-periode-velden:not([hidden]) { display: flex; gap: var(--space-3); }
.vrije-periode-velden label { display: flex; flex-direction: column; gap: var(--space-1); font-size: 13px; color: var(--ink-3); }

/* Los boolean-vinkje naast het statusfilter: de correctievlag is geen
   betaalstatus (zie filterbalk() in betalingen.js) en moet dus tegelijk met bv.
   betaalstatus=open aan te zetten zijn — vandaar een eigen checkbox i.p.v. een
   extra <option>. Zelfde type-selector-truc als bij .vrije-periode-toggle
   hierboven: label.correctie-filter-toggle (0,1,1) wint zo op bronvolgorde van
   de generieke `.betalingen-filters label { flex-direction: column }` met
   gelijke specificiteit. */
label.correctie-filter-toggle {
  display: flex; flex-direction: row; align-items: center; gap: 6px;
  font-size: 13px; color: var(--ink-3); cursor: pointer; white-space: nowrap;
}
.correctie-filter-toggle input { width: auto; margin: 0; cursor: pointer; }

@media (max-width: 640px) {
  /* Op een telefoon duwde dit blok de hele pagina horizontaal open zodra
     "vrije periode" aanstond (462px content in een viewport van 375px). Twee
     dingen samen: het periodeblok is in .betalingen-filters een flex-item met
     `flex: 0 0 auto` en kreeg dus zijn max-content-breedte — die niet afhing
     van het scherm maar van de twee datumvelden erin — en die velden zelf
     mochten óók niet krimpen, doordat de `label:has(input[type="date"])`-regel
     hierboven een descendant-selector is en dus net zo goed op de labels bínnen
     dit blok slaat. Vandaar hier allebei terugdraaien: het blok pakt een volle
     regel en mag krimpen, de velden verdelen die regel. */
  .betalingen-periode { flex: 1 1 100%; min-width: 0; flex-wrap: wrap; row-gap: var(--space-2); }
  .vrije-periode-velden { flex-wrap: wrap; width: 100%; }
  .betalingen-filters label:has(input[type="date"]) { flex: 1 1 140px; min-width: 0; }

  /* Op smal scherm valt "Correctie gevraagd" (rij, content-breed, geen eigen
     label erboven) alleen op een eigen regel tussen kolom-labels (Status
     erboven, Zoek erna) die wél een label + veld onder elkaar hebben. Met
     `align-items: flex-end` op .betalingen-filters komt het vinkje daardoor
     boven zijn regel te zweven i.p.v. op één lijn met de andere velden. Een
     volle rij voor zichzelf voorkomt dat het naast een hoger flex-item
     bottom-uitlijnt. */
  .betalingen-filters label.correctie-filter-toggle { flex: 1 1 100%; }
}
.betalingen-totaal { display: flex; flex-wrap: wrap; gap: var(--space-6); margin-bottom: var(--space-5); }
.betalingen-totaal div { display: flex; flex-direction: column; gap: 2px; }
.betalingen-totaal strong { font-size: 18px; font-variant-numeric: tabular-nums; }
/* Ruimte tussen BV-groepen: een marge alléén is bij twee opeenvolgende koppen
   te weinig rust — een lijntje ertussen maakt de knip tussen BV's duidelijk. */
.betalingen-groep { margin-bottom: var(--space-8); }
.betalingen-groep + .betalingen-groep { padding-top: var(--space-6); border-top: 1px solid var(--rule); }
.betalingen-groep-kop { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-3); margin-bottom: var(--space-3); }
.betalingen-groep-kop h2 { font-size: 17px; margin: 0; }
/* Twaalf kolommen passen niet altijd binnen de 1100px-contentbreedte (main#app).
   Eerder stond hier `.table.betalingen-cards { overflow-x: auto }` (overflow
   direct op de <table>), maar dat bleek empirisch niet te werken: een <table>
   met width:auto negeert zo'n beperking op zichzelf en duwt gewoon main#app uit
   elkaar (computed overflow-x blijft "visible", ook met !important of inline
   style) — precies hetzelfde probleem als bij de gebruikers-tabel hierboven, en
   dezelfde oplossing: de scroll-grens staat nu op de omringende
   `.table-scroll`-div in groepBlok() (public/js/pages/betalingen.js), die zelf
   wél normaal binnen main#app blijft. De sticky actiebalk (`.betalingen-actiebalk`)
   is in de DOM een sibling van de secties, niet genest in de tabel, en blijft dus
   buiten deze scroll-container. */
/* Dertien kolommen: de standaard .table-celpadding (12px 16px, zie huisstijl.css)
   is royaal genoeg bedoeld voor tabellen met een handvol kolommen. Op déze
   tabel duwt dat de tabel net over de beschikbare breedte heen (zie de
   .betalingen-breed-toelichting hierboven) — iets kleinere celpadding wint
   precies genoeg terug om op 1440px zonder horizontale scroll te passen. De
   mobiele kaartweergave (.table.cards-mobile) zet z'n eigen padding:0 met een
   hogere specificiteit (twee classes) en overschrijft dit dus vanzelf. */
.betalingen-cards th, .betalingen-cards td { padding: 10px var(--space-3); }
.betalingen-cards th[data-sorteer] { cursor: pointer; user-select: none; }
.betalingen-cards th[data-col="kies"],
.betalingen-cards td[data-col="kies"] { width: 36px; text-align: center; padding-left: var(--space-3); padding-right: 0; }
/* Actiekolom (potlood, en op een inkoopfactuur ook de correctieknop) helemaal
   rechts. Stond eerder in de Naam-cel, waar het knopje bij een langere naam op
   een tweede regel viel en elke rij een andere hoogte gaf. Geen vaste breedte
   meer zoals hiervoor (44px, toen alleen het potlood): de correctieknop heeft
   een label ("Correctie vragen" / "Verzoek intrekken") en die breedte varieert
   per rij — table-layout:auto (zie elders in dit bestand) mag die kolom dus
   gewoon naar de langste knoptekst laten meegroeien. */
.betalingen-cards th[data-col="acties"],
.betalingen-cards td[data-col="acties"] { text-align: right; padding-left: 0; white-space: nowrap; }
.betalingen-cards td[data-col="acties"] .btn-bewerk-post,
.betalingen-cards td[data-col="acties"] .btn-correctie-vragen,
.betalingen-cards td[data-col="acties"] .btn-correctie-intrekken {
  padding: 2px 7px; font-size: 13px; line-height: 1.4;
}
/* Ruimte tussen het potlood en de correctieknop — die twee staan zonder deze
   marge tegen elkaar aan, want de template plakt ze zonder spatie aan elkaar. */
.betalingen-cards td[data-col="acties"] .btn-correctie-vragen,
.betalingen-cards td[data-col="acties"] .btn-correctie-intrekken { margin-left: 6px; }

/* ─── Kopieerknoppen bij betaalgegevens ──────────────────────────────────
   De betaler zet bedrag en kenmerk over in de bankomgeving. De knop
   staat in de cel maar is onzichtbaar tot je met de muis over de rij gaat:
   vier zichtbare knoppen per rij maken van deze twaalfkolomstabel een
   knoppenveld. De ruimte wordt wél altijd gereserveerd (opacity, geen
   display) — anders verspringt de tekst onder je muis zodra de knop
   verschijnt. Toetsenbordfocus maakt hem ook zichtbaar, anders is hij wel
   tabbaar maar niet te zien. */
.kopieer-veld { display: inline-flex; align-items: center; gap: var(--space-1); max-width: 100%; }
.kopieer-knop {
  flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; padding: 0;
  border: none; border-radius: 6px;
  background: transparent; color: var(--ink-3);
  cursor: pointer; opacity: 0;
  transition: opacity .12s ease, background-color .12s ease, color .12s ease;
}
.kopieer-knop svg { width: 13px; height: 13px; }
.betalingen-cards tbody tr:hover .kopieer-knop,
.kopieer-knop:focus-visible { opacity: 1; }
.kopieer-knop:hover { background: rgba(22, 32, 43,.08); color: var(--ink); }
.kopieer-knop:focus-visible { outline: 2px solid var(--groen); outline-offset: 1px; }
/* Op touch bestaat hover niet: daar altijd zichtbaar, anders is de knop
   onbereikbaar. */
@media (hover: none) {
  .kopieer-knop { opacity: 1; }
}

/* De pil blijft op desktop één regel. "Betaald 14 aug 2026" brak anders binnen
   de pil alsnog over twee regels en maakte de rij hoger dan zijn buren, ook nu
   "door wie" er niet meer in staat. De statuskolom wordt hierdoor ~30px breder;
   die ruimte gaat af van de kolommen die wél mogen afbreken. De kaartweergave
   op mobiel zet dit terug op normal (zie .cards-mobile hierboven) — daar zou
   nowrap de kaart juist horizontaal laten scrollen. */
.betalingen-cards td[data-col="status"] .status { white-space: nowrap; }

/* Toelichting onder de badge ("door Marleen", "geen betaling nodig"). Buiten de
   pil gehouden: een volgezette badge brak in de smalle statuskolom over drie
   regels. Volgt de uitlijning van de cel, dus rechts in de mobiele kaart en
   links in de tabel. */
.betalingen-cards td[data-col="status"] .betaal-toelichting {
  display: block;
  margin-top: 3px;
  font-size: 11.5px;
  line-height: 1.35;
  color: var(--ink-3);
}

/* ─── Openstaand vs. afgehandeld ─────────────────────────────────────────
   Betaald, bedrijfspas en incasso blijven in beeld staan (het overzicht opent
   op álle statussen) maar zakken naar onderen — de sortering gebeurt
   server-side, zie sorteerPosten in services/betaalposten.js.

   Eerder leunde het verschil volledig op het dempen van die afgehandelde
   rijen: openstaand kreeg zélf geen enkel signaal en was gewoon de standaard
   tabelopmaak. Zodra afgehandeld de meerderheid werd — en dat wordt het,
   want alle statussen staan in beeld — viel het werk dat nog moet daardoor
   niet meer op. Nu duwen beide kanten mee: afgehandeld krijgt een getinte
   achtergrond en zakt in de pagina weg, openstaand blijft wit, staat op vol
   contrast en krijgt links een accentrail die de openstaande rijen tot één
   doorlopend blok maakt. */
/* De tint zit bewust tussen --grijs-50 en --grijs-100 in: op --grijs-50 was het
   verschil met wit op een gemiddeld kantoorscherm niet te zien, op --grijs-100
   viel de rij samen met de paginakleur (--creme) en leek de tabel er een gat in
   te hebben. Warm i.p.v. de koelere rgba(22, 32, 43,…)-overlay die elders in dit
   bestand staat: over een hele rij leest die als grijsblauw naast het crème van
   de pagina. */
.betalingen-cards tbody tr.is-afgehandeld td { color: var(--ink-3); background: var(--grijs-200); }
/* Bedrag en statusbadge blijven leesbaar: juist "Betaald 3 juli door Marleen"
   is wat je hier komt terugzien, en dat wegdrukken haalt de reden weg om de
   rij te laten staan. De badges brengen hun eigen kleur mee (huisstijl.css
   .status-*) en staan dus vanzelf op sterkte. */
.betalingen-cards tbody tr.is-afgehandeld td[data-col="bedrag"],
.betalingen-cards tbody tr.is-afgehandeld td[data-col="indiener"] { color: var(--ink-2); }
.betalingen-cards tbody tr.is-afgehandeld td[data-col="bedrag"] { font-variant-numeric: tabular-nums; }
/* De achtergrond hierboven is specifieker (twee classes) dan de gedeelde
   `tr:hover td`-regel in huisstijl.css en zou de hover-terugkoppeling op deze
   rijen anders stilzwijgend uitzetten. Niet --creme (de standaard hover): dat
   ligt te dicht op de tint hierboven om nog als hover te lezen. */
.betalingen-cards tbody tr.is-afgehandeld:hover td { background: var(--grijs-200); }
/* Een openstaande rij hoverde naar --creme (de gedeelde `tr:hover td` uit
   huisstijl.css) — en --creme ligt zo dicht op de tint van een afgehandelde rij
   hierboven dat de rij bij hover juist zijn "nog te doen"-signaal verloor.
   --oranje-50 hoort bij de accentrail hieronder en houdt hem warm. */
.betalingen-cards tbody tr.is-open:hover td { background: var(--oranje-50); }

/* Openstaand: de accentrail. Als inset box-shadow op de eerste cel i.p.v. een
   border — een border-left zou in deze table-layout:auto-tabel de kolombreedte
   veranderen en dus de vastgezette Naam-kolom (zie hieronder) laten
   verspringen. 4px, niet 3: op 3px viel de rail in de tabel weg tegen de
   celrand ernaast. */
.betalingen-cards tbody tr.is-open td[data-col="kies"] { box-shadow: inset 4px 0 0 var(--oranje); }
/* Naam en bedrag zijn waarop je scant; in een openstaande rij staan ze op vol
   gewicht en volle inkt, in een afgehandelde niet. */
.betalingen-cards tbody tr.is-open td[data-col="indiener"],
.betalingen-cards tbody tr.is-open td[data-col="bedrag"] { font-weight: 700; color: var(--ink); }

/* ─── Kopregel boven een blok ────────────────────────────────────────────
   Label links, aantal + bedrag rechts, hairline ertussen. Deze rij is geen
   post: geen hover, geen celrand, en een transparante achtergrond zodat hij
   op de pagina staat en niet in de tabel. */
.betalingen-cards tbody tr.betalingen-blokkop td {
  padding: var(--space-5) var(--space-3) 6px;
  border-bottom: none;
  background: transparent;
}
.betalingen-cards tbody tr.betalingen-blokkop:first-child td { padding-top: var(--space-2); }
.betalingen-cards tbody tr.betalingen-blokkop:hover td { background: transparent; }
/* De flexbox staat in een <div> ín de cel, niet op de <td> zelf: een td met
   display:flex is geen tabelcel meer, waarmee de colspan vervalt en de rij
   in de kolomindeling van de tabel terugvalt. */
.blokkop-inhoud { display: flex; align-items: center; gap: var(--space-3); }
.blokkop-label { font-size: 11px; font-weight: 800; letter-spacing: .16em; text-transform: uppercase; }
.blok-openstaand .blokkop-label { color: var(--oranje-donker); }
.blok-afgehandeld .blokkop-label { color: var(--ink-3); }
.blokkop-lijn { flex: 1; height: 1px; background: var(--rule); }
.blok-openstaand .blokkop-lijn { background: rgba(27, 71, 193,.35); }
.blokkop-cijfers { font-size: 12.5px; color: var(--ink-2); font-variant-numeric: tabular-nums; white-space: nowrap; }
.blok-openstaand .blokkop-cijfers { font-weight: 700; color: var(--ink); }
/* Bedragen rechts uitgelijnd en tabular-nums: anders lopen de cijfers van rij
   tot rij niet onder elkaar en oogt de kolom rommelig. */
.betalingen-cards th[data-sorteer="bedrag"],
.betalingen-cards td[data-col="bedrag"] { text-align: right; font-variant-numeric: tabular-nums; }

/* ─── Vastgezette kolommen tijdens horizontaal scrollen ──────────────────
   Ook op een breed scherm (zie .betalingen-breed hierboven) past de tabel
   soms niet op een smallere laptopbreedte — dan blijft .table-scroll
   horizontaal scrollen. Datum en Naam zijn de kolommen waarmee je een rij
   herkent, dus die blijven zichtbaar: position:sticky, plus een eigen
   achtergrond zodat scrollende cellen er niet doorheen schemeren. Alleen
   vanaf 641px — de mobiele kaartweergave (.table.cards-mobile) kent geen
   horizontale scroll. z-index blijft onder de sticky actiebalk (z-index 5,
   zie .betalingen-actiebalk) en de rij-eigen cellen (auto) staan er weer
   onder.
   Naam's linker-offset (--sticky-naam-left) is bewust geen hardcoded getal:
   deze tabel gebruikt table-layout:auto (content bepaalt de kolombreedte,
   met opzet — zie de toelichting verderop over natuurlijke breedte/overflow),
   en de browser respecteert een expliciete `width` op de Datum-kolom daarin
   niet betrouwbaar zodra andere kolommen om dezelfde ruimte concurreren. Een
   hardcoded offset klopte daardoor niet meer zodra de content varieerde,
   en liet net-niet-gedekte content van de Soort-kolom er tussendoor schijnen.
   public/js/pages/betalingen.js meet daarom ná elke render de echte breedte
   van de Datum-kolom (per BV-tabel, want elke groep heeft z'n eigen
   auto-layout-uitkomst) en zet 'm als custom property op die <table>. */
@media (min-width: 641px) {
  /* position:sticky rekent z'n containing block uit als de dichtstbijzijnde
     voorouder met overflow != visible — dat hóeft geen scrollende voorouder
     te zijn. .table (de gedeelde kaart-look, zie hierboven) zet zelf al
     overflow:hidden om de afgeronde hoeken te clippen, en die zit dichter bij
     de cel dan .table-scroll (die pas erómheen zit) — daardoor "wint" de
     tabel zelf en werkt sticky niet meer tegen de écht scrollende voorouder.
     Fix: de tabel geeft de clip-taak door aan .table-scroll (zelfde
     afronding, alleen op de verticale as — horizontaal moet juist blijven
     scrollen), zodat .table-scroll weer de sticky-referentie is. Scope tot
     déze pagina (.betalingen-groep), niet de gedeelde .table-scroll-regel
     hierboven: die wordt ook door de gebruikers-/leveranciers-tabel gebruikt. */
  .betalingen-cards { overflow: visible; }
  .betalingen-groep .table-scroll { border-radius: var(--r-md); overflow-y: hidden; }

  .betalingen-cards th[data-col="datum"],
  .betalingen-cards td[data-col="datum"] { min-width: 92px; }
  .betalingen-cards th[data-col="datum"],
  .betalingen-cards td[data-col="datum"],
  .betalingen-cards th[data-col="indiener"],
  .betalingen-cards td[data-col="indiener"] {
    position: sticky;
  }
  /* Datum plakt tegen de linkerrand van de scrollcontainer (kies zelf is
     bewust niet vastgezet — alleen datum en naam identificeren een rij) en
     naam sluit er direct op aan, op de door JS gemeten breedte. */
  .betalingen-cards td[data-col="datum"],
  .betalingen-cards td[data-col="indiener"] { left: 0; background: var(--wit); z-index: 2; }
  .betalingen-cards th[data-col="datum"],
  .betalingen-cards th[data-col="indiener"] { left: 0; background: var(--groen-50); z-index: 3; }
  .betalingen-cards td[data-col="indiener"],
  .betalingen-cards th[data-col="indiener"] { left: var(--sticky-naam-left, 100px); }
  /* Lichte schaduw aan de rechterkant van de vastgezette kolommen: het enige
     visuele signaal dat hier de scrollende inhoud begint. */
  .betalingen-cards td[data-col="indiener"],
  .betalingen-cards th[data-col="indiener"] { box-shadow: 2px 0 4px rgba(22, 32, 43,.08); }
  .betalingen-cards tbody tr:hover td[data-col="datum"],
  .betalingen-cards tbody tr:hover td[data-col="indiener"] { background: var(--creme); }
  /* Openstaand en afgehandeld hebben elk hun eigen hoverkleur (zie "Openstaand
     vs. afgehandeld" hierboven). Die twee regels zijn precies even specifiek
     als de --creme-regel hierboven — allebei (0,3,3) — en verliezen dus op
     bronvolgorde, want de --creme-regel staat later in dit bestand. Zonder
     deze uitzonderingen kleurt een rij bij hover tweekleurig: --creme op de
     vastgezette Datum en Naam, de eigen kleur op de rest. */
  .betalingen-cards tbody tr.is-afgehandeld:hover td[data-col="datum"],
  .betalingen-cards tbody tr.is-afgehandeld:hover td[data-col="indiener"] { background: var(--grijs-200); }
  .betalingen-cards tbody tr.is-open:hover td[data-col="datum"],
  .betalingen-cards tbody tr.is-open:hover td[data-col="indiener"] { background: var(--oranje-50); }
}

.betalingen-actiebalk {
  position: sticky; bottom: 0; z-index: 5;
  padding: var(--space-3) var(--space-4); margin-top: var(--space-4);
  background: var(--wit); border: 1px solid rgba(22, 32, 43, .10);
  border-radius: var(--r-md); box-shadow: var(--shadow-md);
}
/* De telling, betaaldatum, herkomst en de drie knoppen zitten in een eigen rij
   binnen .betalingen-actiebalk (zie actiebalk() in betalingen.js) i.p.v. los
   in de balk zelf: het afdoen-venster moet als tweede kind van dezelfde div
   kunnen staan, anders wordt het bij bijwerkenActiebalk() (die precies één
   .betalingen-actiebalk-element vervangt) niet opgeruimd en stapelt het zich
   op. De flex-opmaak die vroeger op .betalingen-actiebalk zelf stond, mikte op
   die directe kinderen en is daarom mee verhuisd naar de rij. */
.betalingen-actiebalk-rij { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); }
.betalingen-actiebalk label { display: flex; align-items: center; gap: var(--space-2); font-size: 13px; color: var(--ink-3); }
.betalingen-actiebalk-rij > span { font-size: 14px; font-variant-numeric: tabular-nums; }

/* De actiebalk is de laatste child en plakt aan de onderkant van het scherm
   (position: sticky) zodra er iets geselecteerd is. Zonder deze reserve-ruimte
   schuift hij tijdens het laatste stukje scrollen over de onderste rij(en)
   van de laatste BV-groep heen — precies het stuk dat je op dat moment wilt
   zien/aanvinken. :has() reserveert de ruimte alléén als de balk er ook echt is. */
main#app:has(.betalingen-actiebalk) .betalingen-groep:last-of-type { margin-bottom: 88px; }
/* Met het afdoen-venster open is de balk een stuk hoger — extra reserve, anders
   schuift de balk alsnog over de onderste rijen heen zodra het venster openstaat. */
main#app:has(.betalingen-actiebalk .betalingen-afdoen-venster) .betalingen-groep:last-of-type { margin-bottom: 220px; }

/* ─── Afdoen-venster: reden + toelichting, geen betaling ────────────────
   Zelfde opzet als .betalingen-bewerk-form (velden naast elkaar op desktop,
   gestapeld op mobiel) maar met een eigen class: dit venster hangt in de
   actiebalk, niet in een tabelrij. */
.betalingen-afdoen-venster {
  display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--space-3);
  margin-top: var(--space-3);
}
/* align-items: center komt binnen via .betalingen-actiebalk label (gelijke
   specificiteit — één klasse + één type-selector — dus wint bronvolgorde per
   eigenschap); deze regel overschrijft 'm expliciet, anders staan Reden en
   Toelichting gecentreerd i.p.v. links zoals bij .betalingen-bewerk-form. */
.betalingen-afdoen-venster label { display: flex; flex-direction: column; align-items: flex-start; gap: var(--space-1); font-size: 13px; color: var(--ink-3); }
.betalingen-afdoen-venster select,
.betalingen-afdoen-venster input[type="text"] { min-width: 200px; }
.betalingen-afdoen-venster p.muted { flex: 1 1 100%; margin: 0; font-size: 12px; }
.betalingen-afdoen-knoppen { display: flex; gap: var(--space-2); flex: 1 1 100%; justify-content: flex-end; }

.betalingen-bewerk-rij td { background: rgba(22, 32, 43,.03); padding: var(--space-3) var(--space-4); }
.betalingen-bewerk-form { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--space-3); }
.betalingen-bewerk-form label { display: flex; flex-direction: column; gap: var(--space-1); font-size: 13px; color: var(--ink-3); }
.betalingen-bewerk-form select,
.betalingen-bewerk-form input[type="text"] { min-width: 180px; }
/* Eigen regel onder de velden (flex-basis 100%), niet ernaast: het is een
   toelichting bij het hele venster, geen label bij één veld. */
.betalingen-bewerk-form .bewerk-toelichting {
  flex: 1 1 100%; margin: 0; font-size: 12px; color: var(--ink-3);
}

/* ─── Correctievenster: verplicht redenveld + bevestigknop ───────────────
   Zelfde opzet als .betalingen-bewerk-form hierboven (velden naast elkaar op
   desktop, gestapeld op mobiel) — dit venster hangt op precies dezelfde manier
   als eigen <tr> onder de bewerkte regel, alleen met een eigen class omdat het
   z'n eigen invoerveld en knoppen heeft. */
.betalingen-correctie-rij td { background: rgba(22, 32, 43,.03); padding: var(--space-3) var(--space-4); }
.betalingen-correctie-form { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--space-3); }
.betalingen-correctie-form label { display: flex; flex-direction: column; gap: var(--space-1); font-size: 13px; color: var(--ink-3); }
.betalingen-correctie-form input[type="text"] { min-width: 320px; }

@media (max-width: 640px) {
  .betalingen-filters label:has(select),
  .betalingen-filters label:has(input[type="search"]) { flex: 1 1 auto; min-width: 0; }
  .betalingen-actiebalk-rij { flex-direction: column; align-items: stretch; gap: var(--space-2); }
  .betalingen-actiebalk button { width: 100%; }
  .betalingen-afdoen-venster { flex-direction: column; align-items: stretch; }
  .betalingen-afdoen-venster select,
  .betalingen-afdoen-venster input[type="text"] { min-width: 0; width: 100%; }
  /* Zonder dit blijven Annuleren/Afdoen op één rij: twee flex-items met elk
     width:100% (uit de regel hierboven) krimpen dan naar hun eigen inhoud
     i.p.v. te stapelen, want flex-shrink staat standaard aan. */
  .betalingen-afdoen-knoppen { flex-direction: column; }
  .betalingen-bewerk-form { flex-direction: column; align-items: stretch; }
  .betalingen-bewerk-form select,
  .betalingen-bewerk-form input[type="text"] { min-width: 0; width: 100%; }
  .betalingen-correctie-form { flex-direction: column; align-items: stretch; }
  .betalingen-correctie-form input[type="text"] { min-width: 0; width: 100%; }
  /* Op mobiel is de actiebalk kolomsgewijs gestapeld (telling + datum + herkomst
     + 3 knoppen) en dus veel hoger dan op desktop — meer reserve-ruimte nodig. */
  main#app:has(.betalingen-actiebalk) .betalingen-groep:last-of-type { margin-bottom: 320px; }
  /* En met het afdoen-venster ook nog open (reden + toelichting + knoppen erbij)
     nog een stuk hoger. */
  main#app:has(.betalingen-actiebalk .betalingen-afdoen-venster) .betalingen-groep:last-of-type { margin-bottom: 700px; }
}

/* Een link ín een .error-msg. Noch de huisstijl noch deze stylesheet zet ooit een
   kleur op een kale <a>, dus tot nu toe viel zo'n link terug op het browserdefault:
   #0000EE onderstreept, paars na bezoek. Op de rozerode meldingsachtergrond met
   rode tekst is dat een zichtbare naad — en de eerste plek waar dit optreedt is een
   foutmelding met een link erin, bijvoorbeeld op een formulier.
   De link hoort onderdeel van de zin te zijn: dezelfde rode inkt, herkenbaar als
   link door de onderstreping, niet door een afwijkende kleur. */
.error-msg a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-thickness: 1px;
  font-weight: 600;
  border-radius: 3px;
}
.error-msg a:hover { text-decoration-thickness: 2px; }
.error-msg a:focus-visible {
  outline: 2px solid var(--rood);
  outline-offset: 2px;
}

/* Losse toelichting onder een veld of boven de actieknoppen: één regel uitleg in
   dezelfde maat als een form-label, met de -8px die 'm optrekt uit de 18px
   ondermarge van de .form-group erboven. Stond eerder als inline-stijl op twee
   plekken in het factuurformulier. */
.form-hint {
  margin: -8px 0 0;
  font-size: 13px;
  line-height: 1.5;
}
/* Volgt de hint op een kaart in plaats van op een veld, dan is er geen
   form-group-ondermarge om uit op te trekken en hoort de normale kaartafstand. */
.card + .form-hint { margin-top: var(--gap-card); }

/* Label/waarde-lijst op het factuurdetail. Stond als inline <style> in
   inkoopfactuur-detail.js; hier staat 'ie omdat de smalle variant hieronder anders
   verliest van die later-in-het-document geïnjecteerde regel. */
.kv { display: grid; grid-template-columns: auto 1fr; gap: 8px 14px; margin: 0; }
.kv dt { font-weight: 600; color: var(--ink-2); font-size: 13px; }
.kv dd { margin: 0; word-break: break-word; }

/* Op een telefoon eist de langste term ("Geüpload door") zoveel van de labelkolom
   dat de wáárde ernaast overblijft met een strook van een paar woorden breed —
   "SC Muiderberg" en een datum vallen dan alle twee uit elkaar. Onder elkaar
   krijgt elke waarde de volle breedte en is de kolom weer één kolom. */
@media (max-width: 640px) {
  .kv { grid-template-columns: 1fr; gap: 2px; }
  .kv dt { margin-top: 10px; }
  .kv dt:first-of-type { margin-top: 0; }
}

/* Automatische export — statusblok op het exports-scherm.
   Bewust géén .card: dit is context bóven "Nieuwe export", niet een gelijk-
   waardig blok ernaast. Een getinte, schaduwloze strook (--grijs-50, v3.0:
   was --creme — die is sinds de koerswijziging naar een witte pagina
   voorbehouden aan de gele rijhover, niet meer een generieke zachte tint) en
   een h3 in plaats van h2 houden het duidelijk lichter dan de witte kaart
   met schaduw eronder. De tabel zelf behoudt haar eigen witte kaart-look
   (zie .table hierboven), wat er als geheel netjes uitziet. */
.auto-export-blok {
  margin-bottom: var(--space-6);
  padding: var(--space-5);
  background: var(--grijs-50);
  border-radius: var(--r-md);
}
.auto-export-blok h3 { margin-top: 0; font-size: 16px; }
.auto-export-blok .table-scroll { margin-top: var(--space-3); }

/* Foutmelding onder een statuslabel: opslagfoutteksten kunnen lang
   en zonder spaties zijn (bv. een pad). Zonder begrenzing zou zo'n regel de
   rijhoogte van de hele statustabel opblazen — twee regels met ellipsis via
   line-clamp, plus title-attribuut in de markup voor de volledige tekst. */
.auto-export-fout {
  margin-top: 4px;
  font-size: 13px;
  color: var(--ink-2);
  max-width: 260px;
  word-break: break-word;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
