/* =================================================================
   CareCoach — Telefooncentrale-beheer voor artsen
   Sober monochroom met een klinische teal als accent.
   ================================================================= */

:root {
    /* Inkt & oppervlak */
    --ink:        #14171f;
    --ink-soft:   #3a4150;
    --muted:      #6b7280;
    --line:       #e7e9ee;
    --line-soft:  #f0f1f4;
    --surface:    #ffffff;
    --canvas:     #f6f7f9;

    /* Accent — klinische teal */
    --accent:        #0e8a7d;
    --accent-strong: #0b6f64;
    --accent-soft:   #e7f4f2;
    --accent-line:   #b9e0db;

    /* Statussen — elke kleur twee keer: de heldere voor een bolletje of een schakelaar,
       de donkere voor waar ze tekst wordt. Groen en oker halen op hun eigen zachte grond
       geen 4.5:1; met deze twee blijft de badge dezelfde kleur en wordt ze wél leesbaar. */
    --ok:       #1f9d57;
    --ok-ink:   #0f7a43;
    --ok-soft:  #e6f5ec;
    --warn:     #b7791f;
    --warn-ink: #8a5a12;
    --warn-soft:#fbf2e3;
    --danger:   #c0392b;
    --danger-soft:#fbe9e7;
    --info:     #2563a8;
    --info-soft:#e8f0fa;
    /* En een randje per kleur, dezelfde tint een paar stappen donkerder. Een gekleurd
       vlak zonder rand zweeft boven de kaarten eromheen — die hebben er wel een — en
       leest daardoor luider dan de melding bedoelt. Met de rand krijgt ze een kant,
       en mag het vlak zelf juist zacht blijven. */
    --ok-line:    #b7dac7;
    --warn-line:  #e2d1b5;
    --danger-line:#eec2be;
    --info-line:  #bdd1e8;

    /* Grafiekvlakken — één tint in vier gewichten, en verder niets.
       Twee kleuren naast elkaar in een grafiek gaan vechten zodra de vlakken
       groot worden, en teal tegenover rood is zo'n beetje het hardste paar dat
       er bestaat: die liggen tegenover elkaar op de kleurcirkel. Dus draagt hier
       niet de kleur de betekenis maar het gewicht — hoe donkerder, hoe meer het
       om aandacht vraagt. Dat leest rustiger, het blijft bij het monochrome
       uitgangspunt van dit scherm, en het werkt ook voor wie kleuren niet uit
       elkaar houdt: lichter en donkerder ziet iedereen. */
    --chart-ink:  #3f746d;
    --chart-mid:  #6f9f99;
    --chart-soft: #a9c9c4;
    --chart-pale: #dbe8e6;
    --chart-grey: #d3d7dd;

    --radius:    10px;
    --radius-sm: 7px;
    --shadow:    0 1px 2px rgba(20, 23, 31, .04), 0 4px 16px rgba(20, 23, 31, .05);
    --shadow-sm: 0 1px 2px rgba(20, 23, 31, .06);
    /* Wat je vastpakt hangt bóven de rij; dat vraagt meer dan de schaduw van een kaart
       die gewoon op het scherm ligt. Zie .is-dragging. */
    --shadow-lift: 0 2px 4px rgba(20, 23, 31, .06), 0 12px 28px rgba(20, 23, 31, .14);

    --sidebar-w: 256px;
    /* Ademruimte rond de inhoud en de hoogte van de topbalk. Ze krimpen mee met
       het scherm; de waarden per breedte staan onderaan bij "Responsief". */
    --pad-x:    32px;
    --pad-y:    28px;
    --topbar-h: 64px;
    /* De balk tijdens een overname; zie .impersonation. Staat hier omdat de zijbalk en
       de topbalk eronder moeten blijven hangen, en die afstand van deze waarde afhangt. */
    --impersonation-h: 42px;
    /* En de balk van de testomgeving, om dezelfde reden; zie .envbar. */
    --envbar-h: 32px;
    /* Het oranje van de testomgeving. Staat los van de statuskleuren hierboven: dit is
       geen waarschuwing over iets op het scherm, het is een uitspraak over het scherm
       zelf. Dezelfde kleur zit in het icoon en in het manifest van de testomgeving. */
    --test: #b45309;
    /* Ondergrens voor de letter in een invoerveld. Safari op iOS zoomt het hele scherm in
       zodra de cursor landt in een veld waarvan de letter kleiner is dan 16px, en zoomt
       daarna niet vanzelf terug uit. Elk veld hieronder zet zijn maat als max(eigen, deze):
       met de muis blijft deze 0 en verandert er niets, op een aanraakscherm wordt ze 16px
       en heeft Safari niets meer in te zoomen. Zie "Aanraakschermen" onderaan.
       De andere uitweg — maximum-scale=1 in de viewport-meta — zet de zoom ook vast voor
       wie hem nodig heeft om te kunnen lezen; die staat er dus bewust niet. */
    --field-min: 0px;

    --font: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

* { box-sizing: border-box; }

html, body { margin: 0; padding: 0; }

/* Safari op de telefoon vergroot anders de tekst zodra het toestel gedraaid wordt. */
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }

body {
    font-family: var(--font);
    color: var(--ink);
    background: var(--canvas);
    font-size: 15px;
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
}

a { color: var(--accent-strong); text-decoration: none; }
a:hover { text-decoration: underline; }

h1, h2, h3 { margin: 0; font-weight: 600; letter-spacing: -.01em; }

/* ===================== Toetsenbord =====================
   Wie met Tab werkt moet kunnen zien waar hij staat. De browser tekent zelf een ring,
   maar die is zwart: op de donkere zijbalk valt ze weg, en over de app heen ziet ze er
   op elke knop weer anders uit. Vandaar één ring voor alles wat te bereiken is —
   teal op het licht, wit op het donker. :focus-visible, dus alleen bij het toetsenbord;
   een muisklik laat geen ring achter. */

.btn:focus-visible,
.icon-btn:focus-visible,
.chip:focus-visible,
.drag:focus-visible,
.cf-fold:focus-visible,
.impersonation__exit:focus-visible,
.switcher__option:focus-visible,
.backlink:focus-visible,
.login__forgot:focus-visible,
.q-panel__cb:focus-visible ~ .q-panel__head .q-panel__toggle,
table.data a:focus-visible,
.content a:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
    border-radius: var(--radius-sm);
}

.nav__item:focus-visible,
.sidebar__foot .me:focus-visible,
.sidebar__foot .foot-btn:focus-visible,
.brand__name:focus-visible {
    outline: 2px solid #fff;
    outline-offset: -2px;
}

/* Voorbij de zijbalk in één toets: die telt tien links voor de inhoud begint. Uit beeld
   tot hij de focus krijgt — dan schuift hij linksboven naar binnen. */
.skip {
    position: fixed;
    top: 10px; left: 10px; z-index: 100;
    padding: 10px 16px;
    border: 1px solid var(--accent);
    border-radius: 8px;
    background: var(--surface);
    color: var(--accent-strong);
    font-size: 14px; font-weight: 600;
    box-shadow: var(--shadow);
    transform: translateY(-200%);
    transition: transform .14s ease;
}
.skip:focus { transform: none; text-decoration: none; }

/* De inhoud krijgt de focus na de sprong; een ring eromheen zou het halve scherm omlijnen. */
.content:focus { outline: none; }

@media (prefers-reduced-motion: reduce) {
    .skip { transition: none; }
}

/* ===================== App-shell ===================== */

/* ---------- Testomgeving ----------
   De balk die zegt dat dit niet de echte omgeving is. Ze staat boven alles, ook boven de
   overnamebalk, want ze gaat over een grotere vergissing: bij een overname doe je het
   goede werk op de verkeerde naam, hier doe je het op de verkeerde machine.

   Oranje en vol, waar de rest van dit scherm zacht en monochroom is. Dat is opzet. Een
   balk die zich netjes gedraagt, wordt na twee dagen niet meer gezien — en dan is ze
   nutteloos. Ze verdwijnt vanzelf zodra de code op het echte adres draait; zie
   App\Environment\CurrentDeployment. */
.envbar {
    height: var(--envbar-h);
    background: var(--test);
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 0 var(--pad-x);
    font-size: 12.5px;
    letter-spacing: .01em;
    /* Boven de overnamebalk (45), de zijbalk (40) en de sluier (35). */
    position: sticky; top: 0; z-index: 46;
}
.envbar__mark { display: flex; }
.envbar__mark svg { width: 15px; height: 15px; }
.envbar__text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.envbar__text b { font-weight: 700; text-transform: uppercase; letter-spacing: .06em; }
.envbar__note { opacity: .85; }

/* Alles onder de balk schuift een balkhoogte op — dezelfde broertje-selectoren als bij de
   overname hieronder, zodat er op de echte omgeving geen enkele regel van overblijft. */
.envbar ~ .app { min-height: calc(100dvh - var(--envbar-h)); }
.envbar ~ .app .sidebar {
    top: var(--envbar-h);
    height: calc(100dvh - var(--envbar-h));
}
.envbar ~ .app .topbar { top: var(--envbar-h); }
.envbar ~ .app .switcher__menu {
    max-height: calc(100dvh - var(--topbar-h) - var(--envbar-h) - 24px);
}
/* Het aanmeldscherm hangt niet in de app-shell en meet zichzelf tegen het venster. */
.envbar ~ .login { min-height: calc(100dvh - var(--envbar-h)); }

/* Krap: de uitleg wijkt, het woord "Testomgeving" blijft — daar gaat de balk over. */
@media (max-width: 620px) {
    .envbar__note { display: none; }
}

/* ---------- Overname ----------
   De balk die een platformbeheerder eraan herinnert dat hij iemand anders is. Blauw, in
   dezelfde taal als de info-badges elders: dit is geen fout en geen waarschuwing, het is
   een stand van zaken. Ze staat buiten de app-shell en loopt dus over de volledige
   breedte — ook over de zijbalk, want die toont vanaf nu ook een andere naam.

   Ze blijft plakken. Een balk die wegscrolt is waardeloos: net wanneer je een lange lijst
   doorloopt en vergeet wie je bent, is ze nergens meer te zien. */
.impersonation {
    height: var(--impersonation-h);
    background: var(--info-soft);
    color: var(--info);
    border-bottom: 1px solid var(--info-line);
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 0 var(--pad-x);
    font-size: 13px;
    /* Boven de zijbalk (40) en de sluier van de lade (35), onder de sprongverwijzing. */
    position: sticky; top: 0; z-index: 45;
}

/* Alles onder de balk schuift een balkhoogte op. Broertje-selectoren, zodat er zonder
   overname geen enkele regel van deze verschuiving overblijft. */
.impersonation ~ .app { min-height: calc(100dvh - var(--impersonation-h)); }
.impersonation ~ .app .sidebar {
    top: var(--impersonation-h);
    height: calc(100dvh - var(--impersonation-h));
}
.impersonation ~ .app .topbar { top: var(--impersonation-h); }
/* De praktijkwisselaar hangt onder de topbalk en heeft dus ook een balk minder ruimte. */
.impersonation ~ .app .switcher__menu {
    max-height: calc(100dvh - var(--topbar-h) - var(--impersonation-h) - 24px);
}

/* Staan beide balken er, dan schuift alles de som van de twee op en gaat de overnamebalk
   onder die van de testomgeving hangen. Deze selectoren zijn een klasse specifieker dan de
   twee reeksen hierboven en winnen dus vanzelf. */
.envbar ~ .impersonation { top: var(--envbar-h); }
.envbar ~ .impersonation ~ .app { min-height: calc(100dvh - var(--envbar-h) - var(--impersonation-h)); }
.envbar ~ .impersonation ~ .app .sidebar {
    top: calc(var(--envbar-h) + var(--impersonation-h));
    height: calc(100dvh - var(--envbar-h) - var(--impersonation-h));
}
.envbar ~ .impersonation ~ .app .topbar { top: calc(var(--envbar-h) + var(--impersonation-h)); }
.envbar ~ .impersonation ~ .app .switcher__menu {
    max-height: calc(100dvh - var(--topbar-h) - var(--envbar-h) - var(--impersonation-h) - 24px);
}

.impersonation__mark { display: flex; }
.impersonation__mark svg { width: 17px; height: 17px; }
.impersonation__text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.impersonation__text b { font-weight: 600; }
.impersonation__note { color: var(--ink-soft); }

/* De weg terug is het enige waarop hier geklikt wordt: vol blauw, zodat ze niet in de
   zachte grond van de balk verdwijnt. */
.impersonation__exit {
    margin-left: auto;
    flex: 0 0 auto;
    display: inline-flex; align-items: center; gap: 6px;
    padding: 5px 12px;
    border-radius: 999px;
    background: var(--info);
    color: #fff;
    font-weight: 600;
    text-decoration: none;
    white-space: nowrap;
    transition: background .12s;
}
.impersonation__exit:hover { background: #1d4f88; }
.impersonation__exit svg { width: 15px; height: 15px; }

/* Krap wordt het snel: de uitleg is het eerste dat mag wijken, de naam en de weg terug
   blijven staan — dat zijn de twee dingen waar de balk voor bestaat. */
@media (max-width: 820px) {
    .impersonation__note { display: none; }
}

.app { display: flex; min-height: 100vh; min-height: 100dvh; }

.sidebar {
    width: var(--sidebar-w);
    flex: 0 0 var(--sidebar-w);
    background: var(--ink);
    color: #cdd2dc;
    display: flex;
    flex-direction: column;
    position: sticky;
    top: 0;
    height: 100vh;
    height: 100dvh;
    z-index: 40;
}

/* Sluitkruis in de zijbalk en de hamburger in de topbalk horen bij dezelfde lade:
   ze bestaan alleen zolang de zijbalk uitschuift. Zie "Responsief" onderaan. */
.sidebar__close, .topbar__burger { display: none; }

/* Sluier onder de uitgeschoven lade. Buiten de lade-breedte bestaat hij niet. */
.nav-scrim {
    display: none;
    position: fixed; inset: 0; z-index: 35;
    background: rgba(20, 23, 31, .48);
    opacity: 0; visibility: hidden;
    transition: opacity .2s ease, visibility .2s;
    -webkit-tap-highlight-color: transparent;
}

.brand {
    display: flex;
    align-items: center;
    gap: 11px;
    padding: 22px 22px 18px;
}
.brand__mark {
    width: 34px; height: 34px;
    color: #fff;
    display: grid; place-items: center;
    flex: 0 0 34px;
}
.brand__mark .logo { width: 32px; height: 32px; display: block; }

/* Beeldmerk — schaalt mee met de omliggende doos, kleurt via currentColor. */
.logo { width: 1em; height: 1em; }
.brand__name { color: #fff; font-weight: 600; font-size: 16px; line-height: 1.1; }
.brand__sub  { color: #8b93a3; font-size: 11.5px; letter-spacing: .04em; text-transform: uppercase; }

.nav { padding: 8px 12px; flex: 1; overflow-y: auto; display: flex; flex-direction: column; }
.nav > * { flex: 0 0 auto; }
/* Blijft onderaan hangen zolang de nav niet volloopt. */
.nav__group--bottom { margin-top: auto; }
.nav__group--bottom .nav__label { padding-top: 18px; }
.nav__label {
    color: #707888;
    font-size: 11px;
    letter-spacing: .07em;
    text-transform: uppercase;
    padding: 14px 12px 6px;
}
.nav__item {
    display: flex;
    align-items: center;
    gap: 11px;
    padding: 9px 12px;
    margin: 2px 0;
    border-radius: 8px;
    color: #cdd2dc;
    font-size: 14.5px;
    font-weight: 500;
}
.nav__item:hover { background: rgba(255,255,255,.05); color: #fff; text-decoration: none; }

/* Waar je staat. Actief en hover zijn hier allebei een lichter vlak, dus zit het verschil
   niet in de kleur maar in het gewicht: de actieve pil is ruim twee keer zo licht als de
   hover, de tekst wordt wit en een graadje zwaarder, en het icoon is het enige dat kleur
   krijgt. Teal als vlak is hier geprobeerd en het werd een waas — op bijna zwart wordt de
   tint modderig lang voor ze opvalt. Als klein, vol vlakje van 18 pixels leest dezelfde
   kleur wél meteen. */
.nav__item.is-active {
    background: rgba(255, 255, 255, .12);
    color: #fff;
    font-weight: 600;
}
.nav__item svg { width: 18px; height: 18px; flex: 0 0 18px; opacity: .85; }
.nav__item.is-active svg { color: var(--accent); opacity: 1; }

/* Labeltje achter een module die al werkt maar nog kan schuiven. Rechts uitgelijnd en
   gedempt: het hoort te lezen wanneer je ernaar kijkt, en niet mee te schreeuwen telkens
   je de zijbalk voorbijloopt. De gewone .badge kan hier niet — die is gemaakt voor de
   lichte inhoud rechts en valt op dit donker uiteen. */
.nav__tag {
    margin-left: auto;
    padding: 2px 6px;
    border-radius: 999px;
    background: rgba(255, 255, 255, .10);
    color: #aab1bf;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
}
.nav__item.is-active .nav__tag { background: rgba(255, 255, 255, .16); color: #fff; }
.nav__badge {
    margin-left: auto;
    background: rgba(255,255,255,.12);
    color: #e6e9ef;
    font-size: 11px;
    font-weight: 600;
    padding: 1px 7px;
    border-radius: 999px;
}

.sidebar__foot {
    border-top: 1px solid rgba(255,255,255,.08);
    padding: 14px 16px;
    display: flex;
    align-items: center;
    gap: 11px;
}
.avatar {
    width: 34px; height: 34px;
    border-radius: 50%;
    background: var(--accent-soft);
    color: var(--accent-strong);
    display: grid; place-items: center;
    font-weight: 600; font-size: 13px;
    flex: 0 0 34px;
}
/* Naam en adres zijn samen de link naar het eigen account. min-width: 0 op allebei, anders
   duwt een lang e-mailadres zich buiten de zijbalk en loopt het onder de afmeldknop door. */
.sidebar__foot .me { display: flex; align-items: center; gap: 11px; min-width: 0; flex: 1 1 auto; padding: 4px; margin: -4px; border-radius: 10px; }
.sidebar__foot .me:hover { background: rgba(255,255,255,.06); text-decoration: none; }
.sidebar__foot .me.is-active { background: rgba(255,255,255,.1); }
.sidebar__foot .who { line-height: 1.2; min-width: 0; }
.sidebar__foot .who b { color: #fff; font-size: 13.5px; font-weight: 600; display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sidebar__foot .who span { color: #8b93a3; font-size: 12px; display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sidebar__foot .foot-btn { margin-left: auto; color: #8b93a3; display: grid; place-items: center; width: 32px; height: 32px; flex: 0 0 32px; border-radius: 8px; }
.sidebar__foot .foot-btn svg { width: 18px; height: 18px; }
.sidebar__foot .foot-btn:hover { color: #fff; background: rgba(255,255,255,.06); text-decoration: none; }

/* ===================== Main ===================== */

.main { flex: 1; min-width: 0; display: flex; flex-direction: column; }

.topbar {
    height: var(--topbar-h);
    background: var(--surface);
    border-bottom: 1px solid var(--line);
    display: flex;
    align-items: center;
    padding: 0 var(--pad-x);
    gap: 16px;
    position: sticky; top: 0; z-index: 5;
}
/* De titel geeft mee zodra de wisselaar ernaast krap komt te zitten. */
.topbar__title { font-size: 17px; font-weight: 600; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.topbar__crumb { color: var(--muted); font-size: 13px; }
.topbar__right { margin-left: auto; display: flex; align-items: center; gap: 14px; min-width: 0; }
.dot-ok { width: 8px; height: 8px; border-radius: 50%; background: var(--ok); display: inline-block; }

.content { padding: var(--pad-y) var(--pad-x) 56px; flex: 1; min-width: 0; }
.content__head { display: flex; align-items: flex-end; flex-wrap: wrap; gap: 16px; margin-bottom: 22px; }
.content__head h1 { font-size: 22px; }
.content__head p { color: var(--muted); margin: 4px 0 0; font-size: 14px; }
.content__head .actions { margin-left: auto; display: flex; gap: 10px; }

/* ===================== Cards & grids ===================== */

.card {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
}
.card__head { padding: 16px 20px; border-bottom: 1px solid var(--line-soft); display: flex; align-items: center; flex-wrap: wrap; gap: 12px; }
.card__head h3 { font-size: 15px; }
.card__head .actions { margin-left: auto; }
.card__body { padding: 20px; }

.grid { display: grid; gap: 18px; }
/* auto-fit: valt een cijfer weg omdat een module uitstaat, dan vullen de andere de rij.
   De min() houdt de kolom binnen het scherm — zonder haar duwt 210px een smalle
   telefoon zijwaarts uit beeld. */
.grid--stats { grid-template-columns: repeat(auto-fit, minmax(min(200px, 100%), 1fr)); }
.grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid--1 { grid-template-columns: minmax(0, 1fr); }
.grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
@media (max-width: 1100px) { .grid--3 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 820px)  { .grid--3 { grid-template-columns: minmax(0, 1fr); } }

@media (max-width: 820px)  { .grid--2 { grid-template-columns: minmax(0, 1fr); } }

/* De tellers boven het gesprekslogboek. Hoeveel het er zijn hangt van het filter af — op
   één afloop vallen beantwoord en gemist weg, zonder beantwoord gesprek valt de gemiddelde
   duur weg — dus rekent de breedte mee met --tiles uit het sjabloon. Breder laten worden dan
   de tegels zelf maakt de cijfers alleen maar leger. */
.stats--calllog { max-width: calc(var(--tiles, 3) * 232px + (var(--tiles, 3) - 1) * 18px); margin-bottom: 22px; }

.stat {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    padding: 18px 20px;
    box-shadow: var(--shadow-sm);
}
/* Een cijfer dat doorklikt naar zijn module; de kaart blijft een kaart, geen link-blauw. */
a.stat { display: block; color: inherit; transition: border-color .12s, box-shadow .12s; }
a.stat:hover { text-decoration: none; border-color: var(--accent-line); box-shadow: var(--shadow); }
a.stat:hover .stat__value { color: var(--accent-strong); }
a.stat:focus-visible { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.stat__label { color: var(--muted); font-size: 13px; font-weight: 500; display: flex; align-items: center; gap: 8px; }
.stat__label svg { width: 16px; height: 16px; color: var(--accent); }
.stat__value { font-size: 28px; font-weight: 700; letter-spacing: -.02em; margin-top: 8px; }
.stat__hint { color: var(--muted); font-size: 12.5px; margin-top: 2px; }

/* ===================== Tables ===================== */

/* Boven de kaartgrens (zie "Responsief") schuift een brede tabel zijwaarts;
   -webkit-overflow-scrolling houdt dat soepel op iOS. */
.table-wrap { width: 100%; overflow-x: auto; -webkit-overflow-scrolling: touch; }

/* Een schaduw aan de rand waar nog tabel achter zit. De twee dekkende verlopen
   schuiven mee (background-attachment: local) en dekken de schaduw af zodra dat
   uiteinde in beeld komt — zo verschijnt en verdwijnt het teken vanzelf, zonder
   javascript en zonder een balk die er altijd staat. */
.table-wrap {
    background:
        linear-gradient(to right, var(--surface) 40%, rgba(255, 255, 255, 0)) left center,
        linear-gradient(to left,  var(--surface) 40%, rgba(255, 255, 255, 0)) right center,
        radial-gradient(farthest-side at 0 50%,   rgba(20, 23, 31, .18), rgba(20, 23, 31, 0)) left center,
        radial-gradient(farthest-side at 100% 50%, rgba(20, 23, 31, .18), rgba(20, 23, 31, 0)) right center;
    background-repeat: no-repeat;
    background-size: 36px 100%, 36px 100%, 16px 100%, 16px 100%;
    background-attachment: local, local, scroll, scroll;
}

/* Een tabel loopt tot tegen de rand van haar kaart. Zonder eigen ronding steken
   de kopregel, de hoverkleur van de eerste of laatste rij en de schaduw hierboven
   buiten de afgeronde hoek uit. De ronding is er één minder dan die van de kaart:
   de kaart rondt haar buitenrand af, de tabel begint een pixel naar binnen.
   Klemmen hoeft niet apart — overflow-x maakt van de wrap al een schuifvlak,
   en dat knipt op zijn afgeronde hoeken. */
.card > .table-wrap:first-child {
    border-top-left-radius: calc(var(--radius) - 1px);
    border-top-right-radius: calc(var(--radius) - 1px);
}
.card > .table-wrap:last-child {
    border-bottom-left-radius: calc(var(--radius) - 1px);
    border-bottom-right-radius: calc(var(--radius) - 1px);
}
table.data { width: 100%; border-collapse: collapse; font-size: 14px; }
table.data thead th {
    text-align: left;
    color: var(--muted);
    font-weight: 600;
    font-size: 12px;
    letter-spacing: .03em;
    text-transform: uppercase;
    padding: 11px 20px;
    border-bottom: 1px solid var(--line);
    white-space: nowrap;
}
table.data tbody td { padding: 13px 20px; border-bottom: 1px solid var(--line-soft); vertical-align: middle; }
table.data tbody tr:last-child td { border-bottom: 0; }
table.data tbody tr:hover { background: var(--canvas); }
table.data .num { font-variant-numeric: tabular-nums; }
table.data .row-actions { text-align: right; white-space: nowrap; }
.mono { font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace; font-size: 13px; }
.t-strong { font-weight: 600; color: var(--ink); }
.t-muted { color: var(--muted); }
/* Tweede regel onder een tabelcel, bv. de naam die bij een nummer hoort. */
.cell-sub { display: block; font-size: 12px; color: var(--muted); }

/* Eén veld dat veranderde: de naam, de oude waarde, de nieuwe. Onder elkaar in de cel,
   zodat een rij waarin vijf velden wijzigden nog te overzien blijft. */
.diff { display: block; font-size: 12.5px; color: var(--muted); margin-top: 3px; overflow-wrap: anywhere; }
.diff__field { color: var(--ink-soft); font-weight: 600; margin-right: 4px; }
.diff__field::after { content: ":"; }
.diff__old { text-decoration: line-through; text-decoration-color: var(--muted); }
.diff__new { color: var(--ink); }
.diff__arrow { padding: 0 3px; }
/* Een waarde die er niet was of niet meer is: het streepje mag geen oude of nieuwe waarde
   lijken, dus geen doorhaling en geen inkt. */
.diff__nil { color: var(--muted); }

/* ===================== Badges & pills ===================== */

.badge {
    display: inline-flex; align-items: center; gap: 5px;
    font-size: 12px; font-weight: 600;
    padding: 2px 9px; border-radius: 999px;
    background: var(--line-soft); color: var(--ink-soft);
    border: 1px solid var(--line);
}
.badge--ok     { background: var(--ok-soft); color: var(--ok-ink); border-color: transparent; }
.badge--warn   { background: var(--warn-soft); color: var(--warn-ink); border-color: transparent; }
.badge--danger { background: var(--danger-soft); color: var(--danger); border-color: transparent; }
.badge--info   { background: var(--info-soft); color: var(--info); border-color: transparent; }
.badge--accent { background: var(--accent-soft); color: var(--accent-strong); border-color: transparent; }
.badge--muted  { background: var(--line-soft); color: var(--muted); }
.badge i { width: 6px; height: 6px; border-radius: 50%; background: currentColor; display: inline-block; }
/* Zonder maat rekt een svg in een inline-flex-badge tot niets: expliciet zetten. */
.badge svg { width: 13px; height: 13px; flex: 0 0 13px; }
/* Badge zonder tekst: het pictogram draagt de betekenis, de titel legt ze uit. */
.badge--icon { padding: 3px; gap: 0; vertical-align: middle; }

/* Wat het oog uit het pictogram leest, moet de schermlezer voorgelezen krijgen. */
.sr-only {
    position: absolute; width: 1px; height: 1px;
    margin: -1px; padding: 0; border: 0;
    overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}

/* ===================== Buttons ===================== */

.btn {
    display: inline-flex; align-items: center; gap: 8px;
    font-family: inherit; font-size: 14px; font-weight: 600;
    padding: 9px 16px; border-radius: 8px;
    border: 1px solid var(--line);
    background: var(--surface); color: var(--ink);
    cursor: pointer; transition: all .12s ease;
    text-decoration: none; white-space: nowrap;
}
/* Een knop die JavaScript pas tevoorschijn haalt. Zonder deze regel wint de display hierboven
   van het hidden-attribuut, en staat de knop er toch — ook waar hij niets kan doen. */
.btn[hidden] { display: none; }
.btn:hover { border-color: #d4d8e0; background: #fcfcfd; text-decoration: none; }
.btn svg { width: 16px; height: 16px; }
.btn--primary { background: var(--accent); border-color: var(--accent); color: #fff; }
.btn--primary:hover { background: var(--accent-strong); border-color: var(--accent-strong); }
.btn--ghost { border-color: transparent; background: transparent; color: var(--ink-soft); }
.btn--ghost:hover { background: var(--line-soft); }
.btn--danger { color: var(--danger); border-color: var(--line); }
.btn--danger:hover { background: var(--danger-soft); border-color: var(--danger-soft); }
.btn--sm { padding: 6px 11px; font-size: 13px; }
.btn--icon { padding: 7px; }

/* Een knop die op de centrale staat te wachten: het icoontje maakt plaats voor een
   draaiend ringetje. Zonder dat lijkt er na de klik niets te gebeuren — de centrale
   doet er soms een seconde of twee over. Geldt ook voor .icon-btn (zie Queues). */
.btn.is-busy,
.icon-btn.is-busy { position: relative; cursor: progress; }
.btn.is-busy > *,
.icon-btn.is-busy > * { visibility: hidden; }
.btn.is-busy::after,
.icon-btn.is-busy::after {
    content: '';
    position: absolute; top: 50%; left: 50%;
    width: 14px; height: 14px; margin: -7px 0 0 -7px;
    border: 2px solid currentColor; border-top-color: transparent;
    border-radius: 50%; opacity: .85;
    animation: knop-draai .6s linear infinite;
}

@keyframes knop-draai {
    to { transform: rotate(360deg); }
}

@media (prefers-reduced-motion: reduce) {
    .btn.is-busy::after,
    .icon-btn.is-busy::after { animation: none; border-top-color: currentColor; opacity: .5; }
}

/* ===================== Callflow-groepen ===================== */

.card__head .badge { margin-left: 0; }
.cf-access { display: inline-flex; align-items: center; gap: 5px; color: var(--muted); font-size: 13px; font-weight: 500; }
.cf-access svg { width: 15px; height: 15px; }

/* De greep om een groep te verslepen. Alleen zichtbaar voor wie de praktijk beheert;
   zonder muis doen de pijltjestoetsen hetzelfde, vandaar een knop en geen icoontje. */
.drag {
    display: inline-flex; align-items: center; justify-content: center;
    padding: 4px; margin: -4px 2px -4px -4px;
    border: 0; border-radius: 6px; background: none; color: var(--muted);
    cursor: grab; touch-action: none;
    /* Slepen met de vinger houdt de greep vast; zonder dit selecteert het scherm hem, of
       komt na een tel het knip-en-plakmenu over de lijst heen staan. */
    user-select: none; -webkit-user-select: none; -webkit-touch-callout: none;
}
.drag:hover { background: var(--line-soft); color: var(--ink-soft); }
.drag:active { cursor: grabbing; }
.drag svg { width: 16px; height: 16px; }
/* Er is geen sleepbeeld dat de browser voor ons tekent: wat versleept wordt, is het blokje
   zelf. Het hangt onder de aanwijzer op de pixel waar je het aanraakte — een transform per
   beeldje, uit sortable_controller.js. Hieronder staat wat het van de rij lostilt: een
   schaduw, een eigen achtergrond en een plek bóven de buren, die er intussen onderuit
   schuiven. Zonder dat laatste voelt het niet alsof je iets vasthebt, maar alsof de lijst
   onder je handen omklapt. */
[data-sortable-id] {
    /* Alleen de schaduw en de achtergrond gaan met een overgang. De verplaatsing komt van
       een transform die per beeldje gezet wordt, en die mag niet nálopen — anders sleept het
       blokje achter de vinger aan die het vasthoudt. */
    transition: box-shadow .18s ease, background-color .18s ease;

    /* Altijd relatief, ook wanneer er niets gesleept wordt, en dat is geen opsmuk: de
       controller rekent op `offsetTop`, en die wordt geteld vanaf het eerste blok erboven
       dat zelf een plaats heeft. Zet je dit pas áán bij het slepen, dan verspringt die
       teller middenin de sleep — bij een tabelrij van de tabel naar de pagina, ruim
       driehonderd pixels ineens — en schiet het blokje naar de verkeerde plek. Zo blijft
       de maat de hele sleep dezelfde. Zie sortable_controller.js. */
    position: relative;
}
.is-dragging {
    /* Bovenop de buren waar het overheen hangt. Werkt alleen op iets met een plaats,
       vandaar de regel hierboven. */
    z-index: 2;
    cursor: grabbing;
    /* Wat beweegt mag de browser apart tekenen; anders schokt een lange lijst mee. */
    will-change: transform;
}
.card.is-dragging,
.cf-item.is-dragging {
    background: var(--surface);
    box-shadow: var(--shadow-lift);
}
/* Bij de bestemmingen is het blokje een tabelrij, en die tilt anders op. Een `box-shadow`
   op de rij of op haar cellen schildert een tabel met samengevouwen randen simpelweg niet —
   ook een knalrode schaduw blijft onzichtbaar. Een `drop-shadow` als filter tekent hij wel,
   en die volgt de vorm van de hele rij in plaats van van elke cel apart. De cellen krijgen
   er hun eigen achtergrond bij, want een doorzichtige rij laat zien wat eronder ligt. */
table.data tbody tr.is-dragging {
    filter: drop-shadow(0 1px 2px rgba(20, 23, 31, .10)) drop-shadow(0 4px 10px rgba(20, 23, 31, .20));
}
table.data tbody tr.is-dragging td { background: var(--surface); }
/* De greep blijft de greep, ook wanneer de aanwijzer er tijdens het slepen naast komt. */
.is-dragging .drag { cursor: grabbing; }

/* Wie beweging op zijn scherm heeft afgezet, krijgt de sprong in plaats van de schuif; de
   controller slaat zijn animaties dan over. Het blokje blijft wél de aanwijzer volgen — dat
   is geen versiering maar het slepen zelf. */
@media (prefers-reduced-motion: reduce) {
    [data-sortable-id] { transition: none; }
}
/* De greep staat vóór de naam, in de cel zelf en niet in een kolom ernaast: onder de 860px
   wordt de rij een kaartje, en die kolom zou daar een lege regel worden. */
td.cell-title .drag { vertical-align: middle; }

/* Het pijltje dat een groep dicht- en openklapt. Zelfde maat en plek als de greep ernaast,
   zodat de twee samen één kolom vormen in plaats van twee losse knopjes. */
.cf-fold {
    display: inline-flex; align-items: center; justify-content: center;
    padding: 4px; margin: -4px 0 -4px -8px;
    border: 0; border-radius: 6px; background: none; color: var(--muted);
    cursor: pointer;
}
/* Zonder greep ernaast — een medewerker versleept niets — is er niets om tegenaan te
   schuiven en staat het pijltje gewoon in de marge van de kaart. */
.card__head > .cf-fold:first-child { margin-left: 0; }
.cf-fold:hover { background: var(--line-soft); color: var(--ink-soft); }
.cf-fold svg { width: 16px; height: 16px; transition: transform .15s ease; }
/* Dicht wijst het pijltje naar de kant waar de inhoud heen is; open naar beneden. */
.cf-fold[aria-expanded="false"] svg { transform: rotate(-90deg); }
/* Onder de kop van een dichtgeklapte groep komt niets meer; een streep eronder zou een
   rand van de kaart nabootsen die er niet is. */
.card.is-collapsed .card__head { border-bottom: 0; }

@media (prefers-reduced-motion: reduce) {
    .cf-fold svg { transition: none; }
}

.cf-list { list-style: none; margin: 0; padding: 0; }
.cf-item { display: flex; align-items: center; gap: 12px; padding: 12px 20px; border-top: 1px solid var(--line-soft); }
.cf-item:first-child { border-top: 0; }
/* De naam staat links, de schakelaar rechts, en daartussen ligt op een breed scherm een
   halve meter niets. Een rij die oplicht onder de aanwijzer houdt die twee bij elkaar —
   dezelfde hulp die een tabelrij al krijgt. */
.cf-item:hover:not(.is-dragging) { background: var(--canvas); }
.cf-item__name { font-weight: 600; display: flex; align-items: center; flex-wrap: wrap; gap: 4px 9px; min-width: 0; }
.cf-item__since { font-weight: 400; font-size: 12.5px; color: var(--muted); white-space: nowrap; }
.cf-item__actions { margin-left: auto; display: flex; align-items: center; gap: 8px; }
/* De greep van een regel staat vóór het stipje. Iets minder ruimte dan de kaartgreep krijgt:
   het stipje ernaast is klein, en 12px ertussen laat de twee uit elkaar vallen. */
.cf-item .drag { margin-right: -4px; }
.cf-item__actions form { display: inline; }

/* Handige codes gebruiken dezelfde regel, zonder schakelaar: de code links, waar ze voor
   dient ernaast. Een vaste kolom voor de code zet de omschrijvingen onder elkaar; anders
   begint elke regel op een andere plek en valt de lijst niet meer af te lezen. */
.fc-item__code { flex: 0 0 auto; min-width: 118px; }
.fc-item__what { flex: 1 1 auto; min-width: 0; font-weight: 400; color: var(--ink-soft); }

.cf-dot { width: 9px; height: 9px; border-radius: 50%; background: var(--line); flex: 0 0 9px; }
.cf-dot.is-on { background: var(--ok); box-shadow: 0 0 0 3px var(--ok-soft); }

/* Schakelaar — de stand van een callflow is de knop zelf. */
.switch {
    display: inline-flex; align-items: center; gap: 9px;
    font-family: inherit; padding: 3px; border: 0; border-radius: 999px;
    background: none; cursor: pointer;
}
.switch__track {
    position: relative; width: 38px; height: 22px; flex: 0 0 38px;
    border-radius: 999px; background: var(--line);
    transition: background .14s ease;
}
.switch__knob {
    position: absolute; top: 3px; left: 3px; width: 16px; height: 16px;
    border-radius: 50%; background: var(--surface); box-shadow: var(--shadow-sm);
    transition: transform .14s ease;
}
.switch__label { font-size: 13px; font-weight: 600; color: var(--muted); min-width: 22px; text-align: left; }

.switch:hover .switch__track { background: #d4d8e0; }
.switch.is-on .switch__track { background: var(--ok); }
.switch.is-on:hover .switch__track { filter: brightness(.94); }
/* Terwijl de centrale antwoordt: zichtbaar bezig, en niet nog eens aan te klikken.
   pointer-events houdt :hover erbuiten, zodat de stand niet even van kleur verschiet. */
.switch:disabled { opacity: .55; pointer-events: none; }
.switch.is-on .switch__knob { transform: translateX(16px); }
.switch.is-on .switch__label { color: var(--ok-ink); }
.switch:focus-visible { outline: none; }
.switch:focus-visible .switch__track { box-shadow: 0 0 0 3px var(--accent-soft); }

/* ===================== Forms ===================== */

.form { max-width: 720px; }
.form__row { margin-bottom: 18px; }
.form__row--split { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px; }
@media (max-width: 640px) { .form__row--split { grid-template-columns: minmax(0, 1fr); } }

/* Twee kaarten naast elkaar, voor een formulier dat er breed genoeg voor is: het beheerscherm
   van een microsite. Links wie de praktijk is en waar ze op draait, rechts wat ze mag
   gebruiken — zie templates/admin/microsite/form.html.twig.

   Pas vanaf 1360px, en dat is met opzet streng. Daaronder houdt een halve kaart minder dan
   470px over, en dan worden de vakjes van de modules smaller dan hun eigen omschrijving: twee
   kolommen die allebei te nauw zijn, lezen slechter dan één die klopt. Tot daar staan de
   kaarten onder elkaar, elk zo breed als dit formulier altijd was. */
.form--wide { max-width: 720px; }
.form__cards { display: grid; gap: 18px; grid-template-columns: minmax(0, 1fr); }
/* De laatste rij in een kaart houdt geen marge over; de kaart zet er zelf lucht onder. */
.form__cards .card__body > :last-child { margin-bottom: 0; }
/* Elk bewerkscherm heeft dezelfde opbouw: het <form> om één of meer kaarten, elk met een kop,
   en de knoppen eronder buiten de kaarten, op de achtergrond van de pagina. Daar hoort geen
   streep meer boven: de onderrand van de kaarten is er al een. Een kaart die op zichzelf een
   handeling is (wachtwoord wijzigen, verwijderen) houdt zijn knop wél binnen de kaart. */
.form > .card .card__body > :last-child { margin-bottom: 0; }
.form__cards + .form__actions,
.form > .card + .form__actions { border-top: 0; padding-top: 0; margin-top: 18px; }

@media (min-width: 1360px) {
    .form--wide { max-width: 1280px; }
    /* Elk de helft; de kaarten houden hun eigen hoogte, ze rekken niet naar de langste. */
    .form__cards { grid-template-columns: repeat(2, minmax(0, 1fr)); align-items: start; }

    /* Naast elkaar binnen een halve kaart is te smal: naam en code, tenant en sleutel gaan er
       onder elkaar. De kaart is de splitsing al. Alleen wat rechtstreeks in de kaart staat —
       het instellingenvenster is 560px breed en houdt zijn twee kolommen. */
    .form__cards > .card > .card__body > .form__row--split { grid-template-columns: minmax(0, 1fr); }
}

/* .form__label is hetzelfde kopje voor wat géén label kan zijn: het kopje boven een
   reeks vinkjes, of boven een waarde die vastligt. Een <label> zonder veld eronder
   hoort nergens bij en wordt door een schermlezer overgeslagen; het groepje eronder
   draagt zijn naam via aria-labelledby. */
.form label, .form .form__label { display: block; font-size: 13.5px; font-weight: 600; color: var(--ink-soft); margin-bottom: 6px; }
.form .help { color: var(--muted); font-size: 12.5px; margin-top: 6px; }

.form input[type="text"],
.form input[type="email"],
.form input[type="password"],
.form input[type="number"],
.form input[type="tel"],
.form input[type="datetime-local"],
.form select,
.form textarea {
    width: 100%;
    font-family: inherit; font-size: max(14.5px, var(--field-min));
    color: var(--ink);
    padding: 10px 12px;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--surface);
    transition: border-color .12s, box-shadow .12s;
}
.form textarea { resize: vertical; min-height: 90px; }
/* Een veld dat vaststaat: leesbaar, maar duidelijk niet van deze gebruiker. */
.form input:disabled, .form select:disabled, .form textarea:disabled {
    background: var(--line-soft); color: var(--ink-soft); cursor: not-allowed;
}
.form input:focus,
.form select:focus,
.form textarea:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-soft);
}
.form .checkbox { display: flex; align-items: center; gap: 10px; }
.form .checkbox input { width: 18px; height: 18px; accent-color: var(--accent); }
.form .checkbox label { margin: 0; font-weight: 500; color: var(--ink); }

.checklist { border: 1px solid var(--line); border-radius: 8px; padding: 6px 14px; max-height: 260px; overflow-y: auto; background: var(--surface); }
.checklist .check { display: flex; align-items: center; gap: 10px; padding: 8px 0; margin: 0; font-weight: 500; color: var(--ink); cursor: pointer; }
/* Een streepje tussen twee regels die allebei te zien zijn: filtert de gebruiker, dan
   hoort de bovenste van het resultaat er geen te krijgen. */
.checklist .check:not([hidden]) ~ .check:not([hidden]) { border-top: 1px solid var(--line-soft); }
.checklist .check[hidden] { display: none; }
.checklist .check--empty { color: var(--muted); cursor: default; }
.checklist .check input { width: 16px; height: 16px; accent-color: var(--accent); margin: 0; flex: 0 0 16px; }

/* Het zoekveld erboven en de voet eronder: samen met de lijst één kader. Ze staan
   verborgen zolang JavaScript ze niet toont — zie checklist_controller.js. */
.checklist-search, .checklist-foot {
    padding: 9px 14px;
    border: 1px solid var(--line);
    background: var(--canvas);
}
.checklist-search[hidden], .checklist-foot[hidden] { display: none; }

.checklist-search { position: relative; border-bottom: 0; border-radius: 8px 8px 0 0; }
.checklist-search:not([hidden]) + .checklist { border-top-left-radius: 0; border-top-right-radius: 0; }
.checklist-search svg {
    position: absolute; left: 23px; top: 50%; transform: translateY(-50%);
    width: 15px; height: 15px; color: var(--muted); pointer-events: none;
}
.checklist-search input {
    width: 100%;
    font-family: inherit; font-size: max(13.5px, var(--field-min));
    color: var(--ink);
    padding: 7px 10px 7px 30px;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--surface);
    transition: border-color .12s, box-shadow .12s;
}
.checklist-search input:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-soft);
}

.checklist-foot {
    display: flex; align-items: center; justify-content: space-between; gap: 12px;
    border-top: 0; border-radius: 0 0 8px 8px;
}
.checklist:has(+ .checklist-foot:not([hidden])) { border-bottom-left-radius: 0; border-bottom-right-radius: 0; }
.checklist-foot .check {
    display: flex; align-items: center; gap: 10px; margin: 0;
    font-size: 13px; font-weight: 600; color: var(--ink-soft); cursor: pointer;
}
.checklist-foot .check:has(input:disabled) { color: var(--muted); cursor: default; }
.checklist-foot .check input { width: 16px; height: 16px; accent-color: var(--accent); margin: 0; flex: 0 0 16px; }
.checklist-foot__count { font-size: 12.5px; color: var(--muted); text-align: right; }

.form__actions { display: flex; gap: 10px; padding-top: 8px; border-top: 1px solid var(--line-soft); margin-top: 24px; }

.field-error { color: var(--danger); font-size: 12.5px; margin-top: 6px; }
.form .is-invalid input, .form .is-invalid select, .form .is-invalid textarea { border-color: var(--danger); }

/* ===================== Flash & empty ===================== */

.flash { display: flex; align-items: center; gap: 10px; padding: 12px 16px; border: 1px solid transparent; border-radius: 8px; margin-bottom: 18px; font-size: 14px; font-weight: 500; }
.flash--success { background: var(--ok-soft); color: var(--ok-ink); border-color: var(--ok-line); }
.flash--error   { background: var(--danger-soft); color: var(--danger); border-color: var(--danger-line); }
.flash svg { width: 18px; height: 18px; }

.empty { text-align: center; padding: 56px 20px; color: var(--muted); }
/* Alleen het tekenicoon van de lege staat, niet elk svg'tje dat er verder in staat:
   een knop met een plusje eronder kreeg anders diezelfde 40px mee. */
.empty > svg { width: 40px; height: 40px; color: var(--line); margin-bottom: 12px; }
.empty h3 { color: var(--ink-soft); font-size: 16px; margin-bottom: 4px; }
/* Staat er een voor de hand liggende eerste stap, dan hoort de knop hier en niet alleen
   rechtsboven: dit is waar de gebruiker kijkt als er nog niets is. */
.empty .btn { margin-top: 18px; }

/* Melding bij een scherm, rustiger dan een flash: die verdwijnt, deze hoort erbij. */
.notice {
    display: flex; align-items: flex-start; gap: 10px;
    background: var(--warn-soft); color: var(--warn-ink);
    border: 1px solid var(--warn-line);
    padding: 12px 16px; border-radius: 8px; margin-bottom: 18px;
    font-size: 13.5px; line-height: 1.45;
}
.notice svg { width: 18px; height: 18px; flex: 0 0 18px; margin-top: 1px; }
.notice__actions { margin-top: 8px; }
/* Niet elke melding is een waarschuwing. Oker betekent hier "let op, dit geldt niet voor
   iedereen"; een verwijzing naar een ander scherm hoort die kleur niet te lenen, anders
   went het oog eraan en valt de echte waarschuwing ernaast weg. */
.notice--info { background: var(--info-soft); color: var(--info); border-color: var(--info-line); }

/* ===================== Teksteditor ===================== */
/* Zie assets/controllers/rich_text_controller.js. Het kader is dat van een gewoon veld; de
   werkbalk hangt er bovenaan in, zodat het één veld blijft en geen los paneel. */
.rte { border: 1px solid var(--line); border-radius: 8px; background: var(--surface); transition: border-color .12s, box-shadow .12s; }
.rte:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.is-invalid .rte { border-color: var(--danger); }
.rte__bar { display: flex; align-items: center; gap: 2px; padding: 4px; border-bottom: 1px solid var(--line-soft); }
.rte__bar[hidden] { display: none; }
.rte__btn {
    display: inline-grid; place-items: center; width: 30px; height: 30px;
    border: 0; border-radius: 6px; background: transparent; color: var(--ink-soft);
    font: inherit; font-size: 14px; cursor: pointer;
}
.rte__btn svg { width: 16px; height: 16px; }
.rte__btn:hover { background: var(--line-soft); color: var(--ink); }
.rte__btn[aria-pressed="true"] { background: var(--accent-soft); color: var(--accent-strong); }
.rte__sep { width: 1px; height: 18px; margin: 0 4px; background: var(--line); }
.rte__link { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; padding: 6px; border-bottom: 1px solid var(--line-soft); background: var(--line-soft); }
.rte__link[hidden] { display: none; }
.form .rte__link input { flex: 1 1 200px; width: auto; padding: 6px 10px; }
.rte__content { min-height: 110px; padding: 10px 12px; font-size: max(14.5px, var(--field-min)); line-height: 1.5; color: var(--ink); outline: none; }
.rte__content > :first-child { margin-top: 0; }
.rte__content p { margin: 0 0 8px; }
.rte__content ul, .rte__content ol { margin: 0 0 8px; padding-left: 22px; }
.rte__content a { color: var(--accent-strong); text-decoration: underline; }
/* Zonder JavaScript blijft de textarea over; binnen het kader heeft ze geen eigen rand nodig. */
.form .rte textarea { border: 0; box-shadow: none; }

/* ===================== Filterbalk ===================== */

.filters {
    display: flex; flex-wrap: wrap; align-items: flex-end; gap: 14px;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
    padding: 16px 20px;
    margin-bottom: 18px;
}
.filters__field { display: flex; flex-direction: column; gap: 6px; }
.filters__field label { font-size: 12px; font-weight: 600; letter-spacing: .03em; text-transform: uppercase; color: var(--muted); }
.filters__field input,
.filters__field select {
    width: 100%;
    padding: 8px 11px;
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    font-family: inherit;
    font-size: max(14px, var(--field-min));
    color: var(--ink);
    background: var(--surface);
}
/* Even hoog als de invoervelden ernaast, ook met de eigen pijl van de browser erbij. */
.filters__field select { min-width: 160px; height: 37px; }
/* Een tekstveld krimpt anders tot zijn standaardmaat en kapt zijn eigen uitleg af — juist
   het zoekveld, dat op het logboek en het auditspoor de belangrijkste knop van het scherm is.
   De balk heeft de breedte: rechts stond alleen de knop. */
.filters__field input[type="text"],
.filters__field input[type="search"] { min-width: 260px; }
.filters__field input:focus,
.filters__field select:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.filters__actions { display: flex; gap: 8px; margin-left: auto; }

/* Datum en uur horen bij elkaar en staan dus onder één label naast elkaar. */
.filters__pair { display: flex; gap: 6px; }
.filters__pair input[type="date"] { flex: 1 1 auto; min-width: 140px; }
.filters__pair input[type="time"] { flex: 0 0 auto; width: auto; min-width: 104px; }
/* Tweede regel van de balk: snelkeuzes links, de uitleg over het uur rechts. */
.filters__second {
    flex: 1 0 100%;
    display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
    border-top: 1px solid var(--line-soft);
    padding-top: 12px;
    margin-top: 2px;
}
.filters__note { margin: 0 0 0 auto; color: var(--muted); font-size: 12.5px; }
/* Een waarde die vaststaat waar anders een veld zou staan: één vast nummer is geen keuze,
   maar de lezer hoort wel te zien over welke lijn de cijfers gaan. Zelfde hoogte als de
   velden ernaast, zodat de balk niet gaat hangen. */
.filters__fixed {
    margin: 0; padding: 8px 0;
    font-size: 14px; color: var(--ink-soft); white-space: nowrap;
}
/* Naam vóór een rij snelkeuzes, in dezelfde vorm als de labels boven de velden erboven:
   zonder opschrift is een rij namen niet te lezen als "hier kies je je telefoonboek". */
.filters__label {
    font-size: 12px; font-weight: 600; letter-spacing: .03em; text-transform: uppercase;
    color: var(--muted);
}

.chip {
    display: inline-flex; align-items: center;
    padding: 4px 11px;
    border: 1px solid var(--line); border-radius: 999px;
    background: var(--surface);
    color: var(--ink-soft); font-size: 12.5px; font-weight: 500;
}
.chip:hover { border-color: #d4d8e0; background: #fcfcfd; text-decoration: none; }
.chip.is-active {
    background: var(--accent-soft); border-color: var(--accent-line); color: var(--accent-strong);
}
/* Het aantal gesprekken achter een vast filter, klein naast de naam. */
.chip__count {
    margin-left: 6px; padding: 0 6px;
    border-radius: 999px; background: var(--line-soft);
    color: var(--muted); font-size: 11.5px; font-variant-numeric: tabular-nums;
}
.chip.is-active .chip__count { background: var(--surface); color: var(--accent-strong); }

@media (max-width: 820px) {
    .filters__field { flex: 1 1 160px; }
    .filters__actions { margin-left: 0; }
    .filters__note { margin-left: 0; }
}

/* ---------- Gestapelde filterbalk ----------
   Voor een balk met meer dan een handvol velden. In één flex-wrap breekt die waar hij
   toevallig niet meer past: één veld blijft alleen achter en de knoppen gaan zweven.
   Hier krijgt elke regel één betekenis — wanneer, en dan wat — en een vast raster. */

.filters--stacked { display: block; padding: 0; }
.filters--stacked .filters__row { display: grid; align-items: end; gap: 12px 14px; padding: 16px 20px; }
.filters--stacked .filters__row + .filters__row { border-top: 1px solid var(--line-soft); }
.filters__row--period { grid-template-columns: auto minmax(0, 1fr) auto minmax(0, 1fr); background: #fbfbfc; border-radius: var(--radius) var(--radius) 0 0; }
.filters__row--criteria { grid-template-columns: repeat(2, minmax(130px, .8fr)) repeat(2, minmax(150px, 1fr)) auto; }
/* Een regel waarvan het aantal velden per praktijk verschilt (één nummer is geen keuze):
   geen vast raster, anders blijft er een lege kolom staan. De knoppen schuiven naar rechts. */
.filters--stacked .filters__row--compact { display: flex; flex-wrap: wrap; align-items: flex-end; }
.filters__row--compact .filters__field { flex: 0 1 240px; }
.filters--stacked .filters__row--compact .filters__actions { margin-left: auto; }
/* Alles in de balk even hoog, ook de datum- en uurvelden die anders hun eigen maat kiezen. */
.filters--stacked .filters__field input,
.filters--stacked .filters__field select { height: 38px; min-width: 0; }
.filters--stacked .filters__pair input[type="date"] { min-width: 0; }
.filters--stacked .filters__actions { margin-left: 0; }
.filters__dash { padding-bottom: 9px; color: var(--muted); }

/* Snelkeuzes als één schakelaar: ze sluiten elkaar uit, dus horen ze aan elkaar vast. */
.segmented {
    display: inline-flex; height: 38px; padding: 3px; gap: 2px;
    background: var(--line-soft); border-radius: var(--radius-sm);
}
.segmented .chip {
    border: 0; border-radius: 5px; background: transparent;
    padding: 0 12px; font-size: 13px; white-space: nowrap; color: var(--ink-soft);
}
.segmented .chip:hover { background: rgba(255, 255, 255, .6); }
.segmented .chip.is-active {
    background: var(--surface); color: var(--ink);
    box-shadow: 0 1px 2px rgba(20, 23, 31, .08), 0 0 0 1px rgba(20, 23, 31, .04);
}

/* Vaste filters: een derde regel in de balk, als pills met hun teller. Ze sluiten elkaar
   uit, net als de snelkeuzes, maar het zijn er per microsite meer of minder — dus geen
   aaneengesloten schakelaar maar losse knoppen die mogen doorlopen op een volgende regel. */
.filters--stacked .filters__row--views {
    display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
    padding-top: 12px; padding-bottom: 12px;
}
.filters__row--views .filters__label { margin-right: 6px; }
.views__tab {
    display: inline-flex; align-items: center; gap: 7px;
    height: 30px; padding: 0 12px;
    border: 1px solid var(--line); border-radius: 999px;
    background: var(--surface);
    color: var(--ink-soft); font-size: 13px; font-weight: 500; white-space: nowrap;
}
.views__tab:hover { border-color: #d4d8e0; background: #fcfcfd; text-decoration: none; }
.views__tab.is-active { background: var(--accent-soft); border-color: var(--accent-line); color: var(--accent-strong); }
.views__count {
    padding: 0 6px; border-radius: 999px;
    background: var(--line-soft); color: var(--muted);
    font-size: 11.5px; font-variant-numeric: tabular-nums;
}
.views__tab.is-active .views__count { background: var(--surface); color: var(--accent-strong); }

/* De breedte komt van de inhoudskolom, niet van het scherm — met de zijbalk erbij scheelt
   dat zo'n 260px — dus breekt de balk op haar eigen maat. */
.filters--stacked { container-type: inline-size; }
@container (max-width: 1000px) {
    .filters__row--period { grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); }
    .filters__row--period > .filters__field:first-child { grid-column: 1 / -1; align-items: flex-start; }
}
@container (max-width: 760px) {
    .filters__row--criteria { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .filters__row--criteria .filters__actions { grid-column: 1 / -1; justify-content: flex-end; }
}
@container (max-width: 520px) {
    .filters--stacked .filters__row { padding: 14px 16px; }
    .filters__row--period,
    .filters__row--criteria { grid-template-columns: minmax(0, 1fr); }
    .filters__row--compact .filters__field { flex: 1 1 100%; }
    .filters--stacked .filters__row--compact .filters__actions { width: 100%; margin-left: 0; }
    .filters__row--compact .filters__actions .btn { flex: 1; justify-content: center; }
    .filters__dash { display: none; }
    /* Vier snelkeuzes passen hier niet naast elkaar: twee aan twee, zonder scrollen. */
    .filters__row--period > .filters__field:first-child { align-items: stretch; }
    .segmented { display: grid; grid-template-columns: 1fr 1fr; height: auto; }
    .segmented .chip { justify-content: center; height: 34px; }
    .filters__row--criteria .filters__actions .btn { flex: 1; justify-content: center; }
}

/* ===================== Datum- en uurkiezer =====================
   flatpickr (zie date_range_controller.js), hier ingekleurd naar de rest van het scherm.
   Enkel met een muis: op een aanraakscherm blijft de kiezer van het toestel staan. */

.filters__pair .date-input { flex: 1 1 auto; min-width: 0; }
.date-input { cursor: pointer; font-variant-numeric: tabular-nums; }

.flatpickr-calendar {
    font-family: var(--font);
    width: 296px; padding: 8px;
    border: 1px solid var(--line); border-radius: var(--radius);
    box-shadow: 0 10px 30px rgba(20, 23, 31, .12), 0 2px 6px rgba(20, 23, 31, .06);
}
.flatpickr-calendar.arrowTop::before,
.flatpickr-calendar.arrowTop::after,
.flatpickr-calendar.arrowBottom::before,
.flatpickr-calendar.arrowBottom::after { display: none; }
.flatpickr-calendar.open { margin-top: 4px; }
.flatpickr-innerContainer,
.flatpickr-rContainer,
.flatpickr-days,
.dayContainer { width: 278px; min-width: 278px; max-width: 278px; }

.flatpickr-months { align-items: center; padding-bottom: 6px; }
.flatpickr-months .flatpickr-month { height: 36px; color: var(--ink); }
.flatpickr-current-month { font-size: 14.5px; font-weight: 600; padding-top: 9px; }
.flatpickr-current-month span.cur-month { font-weight: 600; }
.flatpickr-current-month input.cur-year { font-weight: 600; }
.flatpickr-current-month span.cur-month:hover,
.numInputWrapper:hover { background: transparent; }
.flatpickr-months .flatpickr-prev-month,
.flatpickr-months .flatpickr-next-month {
    top: 8px; height: 34px; width: 34px; padding: 10px;
    border-radius: var(--radius-sm); color: var(--muted); fill: var(--muted);
}
.flatpickr-months .flatpickr-prev-month { left: 8px; }
.flatpickr-months .flatpickr-next-month { right: 8px; }
.flatpickr-months .flatpickr-prev-month:hover,
.flatpickr-months .flatpickr-next-month:hover { background: var(--line-soft); }
.flatpickr-months .flatpickr-prev-month:hover svg,
.flatpickr-months .flatpickr-next-month:hover svg { fill: var(--ink); }
.flatpickr-months .flatpickr-disabled { opacity: .3; }

span.flatpickr-weekday {
    color: var(--muted); font-size: 11.5px; font-weight: 600;
    text-transform: uppercase; letter-spacing: .03em;
}

.flatpickr-day {
    max-width: 38px; height: 36px; line-height: 34px;
    border-radius: var(--radius-sm); color: var(--ink-soft); font-size: 13.5px;
    font-variant-numeric: tabular-nums;
}
.flatpickr-day:hover,
.flatpickr-day:focus { background: var(--line-soft); border-color: transparent; }
.flatpickr-day.today { border-color: var(--line); font-weight: 600; }
.flatpickr-day.today:hover { background: var(--line-soft); color: var(--ink); border-color: var(--line); }
.flatpickr-day.prevMonthDay,
.flatpickr-day.nextMonthDay { color: #b6bbc4; }
.flatpickr-day.flatpickr-disabled,
.flatpickr-day.flatpickr-disabled:hover { color: #cfd3da; background: transparent; cursor: default; }

/* Het uur onder de kalender: twee keuzelijsten met "Uur" ervoor. De draaivakjes van
   flatpickr blijven verborgen bestaan; zie addTimeSelects() in date_range_controller.js. */
.flatpickr-calendar.has-time-select .flatpickr-time { display: none; }
.time-select {
    display: flex; align-items: center; gap: 6px;
    margin-top: 6px; padding: 10px 6px 4px;
    border-top: 1px solid var(--line-soft);
}
.time-select__label {
    margin-right: auto;
    font-size: 12px; font-weight: 600; letter-spacing: .03em; text-transform: uppercase; color: var(--muted);
}
.time-select__field {
    height: 36px; padding: 0 28px 0 12px;
    border: 1px solid var(--line); border-radius: var(--radius-sm);
    background: var(--surface) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%236b7280' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") no-repeat right 10px center;
    appearance: none; -webkit-appearance: none;
    font-family: inherit; font-size: 14.5px; font-weight: 600; color: var(--ink);
    font-variant-numeric: tabular-nums; cursor: pointer;
}
.time-select__field:hover { border-color: #d4d8e0; }
.time-select__field:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.time-select__separator { color: var(--muted); font-weight: 600; }

/* De gekozen periode, in beide kalenders: begin en einde vol, de dagen ertussen licht. */
.flatpickr-day.is-in-range {
    background: var(--accent-soft); border-color: transparent; border-radius: 0;
    box-shadow: -3px 0 0 var(--accent-soft), 3px 0 0 var(--accent-soft);
    color: var(--accent-strong);
}
.flatpickr-day.is-range-start,
.flatpickr-day.is-range-end { background: var(--accent-soft); color: var(--accent-strong); border-color: var(--accent-line); }
.flatpickr-day.selected,
.flatpickr-day.selected:hover,
.flatpickr-day.selected:focus {
    background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 600;
}

/* ===================== Bladeren ===================== */

.pager {
    display: flex; align-items: center; gap: 16px;
    padding: 14px 20px;
    border-top: 1px solid var(--line-soft);
    font-size: 13.5px;
}
.pager__count { color: var(--muted); }
.pager__nav { display: flex; align-items: center; gap: 10px; margin-left: auto; }
.pager__page { color: var(--muted); white-space: nowrap; }
.btn.is-disabled { color: var(--line); border-color: var(--line-soft); cursor: default; }

/* ===================== Login ===================== */

.login {
    min-height: 100vh;
    min-height: 100dvh;
    display: grid;
    grid-template-columns: 1fr 1fr;
}
.login__aside {
    background: var(--ink);
    color: #cdd2dc;
    padding: 56px;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    position: relative;
    overflow: hidden;
}
.login__aside::after {
    content: "";
    position: absolute; right: -120px; bottom: -120px;
    width: 360px; height: 360px; border-radius: 50%;
    background: radial-gradient(circle, rgba(14,138,125,.35), transparent 70%);
}
.login__aside .brand { padding: 0; position: relative; z-index: 1; }
.login__aside .brand__mark { width: 42px; height: 42px; flex: 0 0 42px; }
.login__aside .brand__mark .logo { width: 40px; height: 40px; }
.login__aside .brand__name { font-size: 19px; }
.login__lead { font-size: 26px; font-weight: 600; color: #fff; line-height: 1.3; letter-spacing: -.01em; max-width: 380px; }
.login__lead span { color: var(--accent); }
.login__points { list-style: none; padding: 0; margin: 24px 0 0; display: grid; gap: 12px; }
.login__points li { display: flex; gap: 10px; align-items: center; font-size: 14.5px; }
.login__points svg { width: 18px; height: 18px; color: var(--accent); flex: 0 0 18px; }

.login__main { display: grid; place-items: center; padding: 40px; background: var(--surface); }
.login__box { width: 100%; max-width: 380px; }
.login__box h1 { font-size: 24px; margin-bottom: 6px; }
.login__box .sub { color: var(--muted); margin-bottom: 28px; }
/* De boodschap van platformbeheer, bovenaan het aanmeldvak — ook op een smal scherm, waar de
   zijkolom grotendeels wegvalt. In de eigen teal en niet in het blauw van een melding: het is
   een bericht van het team, geen waarschuwing. De gloed rechtsboven is die van de zijkolom. */
.login__message {
    position: relative; overflow: hidden;
    display: flex; align-items: flex-start; gap: 12px;
    margin-bottom: 32px; padding: 14px 18px 14px 14px;
    background:
        radial-gradient(circle at 100% 0, rgba(14,138,125,.16), transparent 55%),
        var(--accent-soft);
    border: 1px solid var(--accent-line);
    border-radius: 12px;
    color: var(--ink-soft); font-size: 14px; line-height: 1.5;
    overflow-wrap: anywhere;
    animation: login-bericht .5s cubic-bezier(.2, .8, .2, 1) .15s both;
}
.login__message-icon {
    display: inline-grid; place-items: center; width: 28px; height: 28px; flex: 0 0 28px;
    border-radius: 50%; background: var(--accent); color: #fff;
    box-shadow: 0 0 0 4px rgba(14,138,125,.12);
}
.login__message-icon svg { width: 15px; height: 15px; transform: rotate(-12deg); }
.login__message-body { flex: 1; min-width: 0; padding-top: 3px; color: var(--ink); }
.login__message-body > :last-child { margin-bottom: 0; }
.login__message-body p { margin: 0 0 6px; }
.login__message-body ul, .login__message-body ol { margin: 0 0 6px; padding-left: 18px; }
.login__message-body a {
    color: var(--accent-strong); font-weight: 600;
    text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 3px;
}
.login__message-body a:hover { color: var(--accent); }
@keyframes login-bericht {
    from { opacity: 0; transform: translateY(-6px); }
    to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
    .login__message { animation: none; }
}
.login__box .demo {
    margin-top: 22px; padding: 12px 14px;
    background: var(--canvas); border: 1px dashed var(--line);
    border-radius: 8px; font-size: 12.5px; color: var(--muted);
}
.login__box .demo b { color: var(--ink-soft); }

/* Onopvallend onder de knop: wie zijn wachtwoord kwijt is zoekt ernaar, wie dat niet is
   heeft er niets aan en hoort er niet over te struikelen. */
.login__forgot {
    display: block; margin-top: 16px; text-align: center;
    font-size: 13px; color: var(--muted); text-decoration: none;
}
.login__forgot:hover { color: var(--accent-strong); text-decoration: underline; }

/* ===================== Utilities ===================== */

.stack > * + * { margin-top: 14px; }
.inline { display: flex; align-items: center; gap: 8px; }
.section-gap { margin-top: 22px; }
.text-c { text-align: center; }
.w-full { width: 100%; }

/* ===================== Gebruikers per praktijk ===================== */

/* Twee weergaven van hetzelfde overzicht. Links en geen knoppen: elke weergave heeft haar
   eigen URL, zodat terugkeren na een bewerking op dezelfde plek uitkomt. */
.view-tabs { display: flex; gap: 4px; margin-bottom: 18px; border-bottom: 1px solid var(--line); }
.view-tabs__tab {
    display: inline-flex; align-items: center; gap: 7px;
    padding: 9px 14px; margin-bottom: -1px;
    border-bottom: 2px solid transparent;
    color: var(--muted); font-size: 14px; font-weight: 600; text-decoration: none;
}
.view-tabs__tab svg { width: 16px; height: 16px; }
.view-tabs__tab:hover { color: var(--ink); }
.view-tabs__tab.is-active { color: var(--accent-strong); border-bottom-color: var(--accent); }

/* Elke praktijk is een <details>: dicht toont ze haar tellingen, open haar gebruikers. */
.user-groups > .user-group + .user-group { border-top: 1px solid var(--line-soft); }
/* Het team boven en de accounts zonder praktijk onder de lijst: even ver van de lijst. */
.card.user-group { margin-block: 18px; }
.user-group__head {
    display: flex; align-items: center; flex-wrap: wrap; gap: 8px 12px;
    padding: 14px 20px; cursor: pointer; list-style: none;
}
.user-group__head::-webkit-details-marker { display: none; }
.user-group__head:hover { background: var(--canvas); }
.user-group__head:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.user-group__chevron { display: inline-flex; color: var(--muted); transition: transform .15s ease; transform: rotate(-90deg); }
.user-group__chevron svg { width: 16px; height: 16px; }
.user-group[open] > .user-group__head .user-group__chevron { transform: none; }
.user-group__name { font-weight: 600; color: var(--ink); }
.user-group__note { color: var(--muted); font-size: 13px; }
.user-group__counts { display: flex; flex-wrap: wrap; gap: 5px; margin-left: auto; font-size: 13px; }
.user-group[open] > .user-group__head { border-bottom: 1px solid var(--line-soft); }

/* Open moet je zien zonder naar het pijltje te zoeken: de naam kleurt groen en de kop
   krijgt de grijze tint van erover gaan. */
.user-group[open] > .user-group__head,
.user-group[open] > .user-group__head:hover { background: var(--canvas); }
.user-group[open] > .user-group__head .user-group__name { color: var(--accent-strong); }
.user-group[open] > .user-group__head .user-group__chevron { color: var(--accent); }
/* Na een open groep begint de volgende met een duidelijke rand, niet met de zachte lijn
   tussen twee dichte. */
.user-groups > .user-group[open] + .user-group { border-top-color: var(--line); }
/* De grijze kop volgt de ronding van de kaart. */
.user-groups, .card.user-group { overflow: hidden; }
.user-groups { border-radius: calc(var(--radius) - 1px); }
.user-group__empty { margin: 0; padding: 16px 20px; color: var(--muted); font-size: 14px; }
.user-group__foot { display: flex; flex-wrap: wrap; gap: 8px; padding: 12px 20px; border-top: 1px solid var(--line-soft); background: var(--canvas); }
.user-group turbo-frame { display: block; }
/* De laatste open groep in de kaart volgt haar ronding. */
.user-groups > .user-group:last-child .user-group__foot { border-radius: 0 0 var(--radius) var(--radius); }

/* Elke groep is een eigen tabel. Met de breedtes van de inhoud schoven de kolommen per groep
   op, en wie er twee openklapte zag twee rasters onder elkaar. Vaste breedtes houden ze op
   één lijn, en de lijst met alle accounts in dezelfde vorm. Pas op een breed scherm: smaller
   heeft de kolom met praktijken de ruimte nodig die de inhoud vraagt. */
@media (min-width: 1600px) {
    table.users { table-layout: fixed; }
    table.users .users__name { width: 18%; }
    table.users .users__email { width: 25%; }
    table.users .users__role { width: 140px; }
    table.users .users__login { width: 172px; }
    table.users .users__actions { width: 176px; }
    table.users td.mono { overflow-wrap: anywhere; }
    /* Een uitzonderlijk lange praktijknaam kort in plaats van over de volgende kolom te lopen;
       de volledige naam staat in de title. */
    table.users .site-tags .badge { display: inline-block; max-width: 100%; overflow: hidden; text-overflow: ellipsis; }
}
/* Een praktijknaam in een tag hoort bij elkaar; liever een tag op de volgende regel. */
table.users .site-tags .badge { white-space: nowrap; }
/* Datum en uur op één regel: gebroken leest het als twee waarden. */
table.users td.num { white-space: nowrap; }

/* ===================== Queues ===================== */

/* De volledige toestellenlijst staat dicht: ze hoort erbij als naslag, maar mag de
   wachtrijen niet van het scherm duwen. Zie templates/queue/index.html.twig. */
.ext-panel > summary { cursor: pointer; list-style: none; }
.ext-panel > summary::-webkit-details-marker { display: none; }
/* Dicht is er niets meer om van te scheiden. */
.ext-panel:not([open]) > summary { border-bottom: 0; }
.ext-panel > summary:hover { background: var(--canvas); border-radius: var(--radius) var(--radius) 0 0; }
.ext-panel > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; border-radius: var(--radius); }
.ext-panel__toggle { margin-left: auto; font-size: 13px; font-weight: 600; color: var(--accent-strong); }
.ext-panel[open] .ext-panel__closed,
.ext-panel:not([open]) .ext-panel__open { display: none; }

.ext-list { list-style: none; margin: 0; padding: 0; }
.ext-list__item { display: flex; align-items: center; flex-wrap: wrap; gap: 4px 10px; padding: 11px 20px; border-top: 1px solid var(--line-soft); font-size: 14px; }
.ext-list__item:first-child { border-top: 0; }

/* Eén toestel, waar het ook staat: de macro in queue/_extension.html.twig zet dit neer. */
.ext-label { display: inline-flex; align-items: center; flex-wrap: wrap; gap: 4px 10px; min-width: 0; }
.ext-label__num { color: var(--ink); font-weight: 600; }
.ext-label__sep { color: var(--muted); }
.ext-label__name { font-weight: 600; }

.q-panel__head { display: flex; align-items: center; gap: 10px; padding: 16px 20px; border-bottom: 1px solid var(--line-soft); flex-wrap: wrap; }
.q-panel__head h3 { font-size: 15px; }
.q-panel__actions { margin-left: auto; display: flex; align-items: center; gap: 8px; }
.q-panel__actions form { display: inline; }

/* De checkbox stuurt het open- en dichtklappen. Hij staat uit beeld, maar niet met het
   `hidden`-attribuut: dat haalt hem ook uit de tabvolgorde, en dan gaat een rij alleen
   met de muis open. Zo blijft hij met Tab te bereiken en met de spatiebalk om te zetten;
   de ring komt op het woord ernaast te staan. */
.q-panel { position: relative; }
.q-panel__cb {
    position: absolute; top: 0; left: 0;
    width: 1px; height: 1px; margin: 0; padding: 0;
    opacity: 0; pointer-events: none;
}

.q-panel__toggle { cursor: pointer; font-size: 13px; font-weight: 600; color: var(--accent-strong); padding: 6px 4px; user-select: none; }
.q-panel__toggle:hover { text-decoration: underline; }
.q-panel__toggle-closed { display: none; }
.q-panel__cb:not(:checked) ~ .q-panel__head .q-panel__toggle-open { display: none; }
.q-panel__cb:not(:checked) ~ .q-panel__head .q-panel__toggle-closed { display: inline; }
.q-panel__cb:not(:checked) ~ .q-panel__body { display: none; }

.q-panel__body { padding: 20px; }
.q-layout { display: grid; grid-template-columns: 320px minmax(0, 1fr); gap: 18px; align-items: start; }
@media (max-width: 980px) { .q-layout { grid-template-columns: minmax(0, 1fr); } }

.q-linked { box-shadow: none; }
.q-linked__add { display: flex; gap: 8px; margin-bottom: 14px; }
.q-linked__add select {
    flex: 1; min-width: 0;
    font-family: inherit; font-size: max(14px, var(--field-min)); color: var(--ink);
    padding: 9px 11px; border: 1px solid var(--line); border-radius: 8px; background: var(--surface);
}
.q-linked__add select:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.q-linked__add .btn { flex: 0 0 auto; }

.q-linked__list { list-style: none; margin: 0; padding: 0; }
.q-linked__item { display: flex; align-items: center; flex-wrap: wrap; gap: 6px 10px; padding: 9px 0; border-top: 1px solid var(--line-soft); }
.q-linked__item:first-child { border-top: 0; }
.q-linked__label { font-size: 14px; min-width: 0; }
.q-linked__item form { display: inline; margin-left: auto; }
.q-linked__empty { padding: 10px 0; color: var(--muted); font-size: 13.5px; }
.q-linked__note { margin-top: 10px; color: var(--muted); font-size: 12.5px; }

/* Terwijl een koppeling wordt doorgegeven staat de rest van de lijst even stil: de regel
   waarop geduwd is houdt zijn kleur (daar draait het ringetje), de andere doen een stap
   terug zodat duidelijk is dat er niets anders te klikken valt tot de centrale antwoordt. */
.q-linked.is-busy { pointer-events: none; }
.q-linked.is-busy .q-linked__add:not(:has(.is-busy)),
.q-linked.is-busy .q-linked__item:not(:has(.is-busy)),
.q-linked.is-busy .q-linked__empty { opacity: .45; }
.q-linked__add,
.q-linked__item,
.q-linked__empty { transition: opacity .12s ease; }

.icon-btn {
    display: inline-flex; align-items: center; justify-content: center;
    width: 30px; height: 30px; padding: 0;
    border: 1px solid var(--line); border-radius: 7px; background: var(--surface);
    color: var(--muted); cursor: pointer; transition: all .12s ease;
}
.icon-btn svg { width: 16px; height: 16px; }
.icon-btn--danger:hover { color: var(--danger); border-color: var(--danger-soft); background: var(--danger-soft); }

/* De cijfers naast een wachtrij zijn twee soorten: een momentopname en optellers sinds
   middernacht. Ze staan daarom in twee groepen met een kop, elk met hun eigen periode erbij —
   in één raster leest "Beantwoord" als iets van nu, net als "In wacht" ernaast. */
.q-stats { display: grid; gap: 20px; align-content: start; }
.q-stats__title { display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 8px; margin: 0 0 10px; font-size: 15px; }
.q-stats__period { font-size: 12.5px; font-weight: 500; letter-spacing: 0; color: var(--muted); }
.q-stats__grid { gap: 14px; }
.q-stats .stat__value { font-size: 24px; margin-top: 6px; }

.q-panel__note { display: flex; align-items: center; gap: 8px; margin-top: 16px; color: var(--muted); font-size: 12.5px; }
.q-panel__note svg { width: 15px; height: 15px; flex: 0 0 15px; color: var(--muted); }

/* ===================== Monitoring ===================== */

/* De statusregel bovenaan: het oordeel links, het tijdstip rechts. Dat tijdstip hoort erbij —
   de cijfers eronder zijn een momentopname en verversen zichzelf, en zonder stempel valt niet
   te zien of je naar iets van nu of van vijf minuten geleden kijkt. */
.mon-state { display: flex; align-items: center; flex-wrap: wrap; gap: 10px 16px; padding: 16px 20px; }
.mon-state__line { display: flex; align-items: center; flex-wrap: wrap; gap: 6px 12px; min-width: 0; }
.mon-state__line p { margin: 0; color: var(--muted); font-size: 13.5px; }
.mon-state__stamp { display: flex; align-items: center; gap: 8px; margin: 0 0 0 auto; color: var(--muted); font-size: 12.5px; }
.mon-state__stamp svg { width: 15px; height: 15px; flex: 0 0 15px; }

/* "8/9": de noemer hoort bij het cijfer, maar mag het niet even zwaar wegen. */
.stat__of { font-size: 18px; font-weight: 600; color: var(--muted); }

/* Een ronde langs de centrale kost een vraag per toestel en heeft een tijdsbudget, dus staat
   het scherm geregeld met een halve lijst te wachten op de rest (zie App\Monitoring\ExtensionMonitor).
   Zonder teken dat er gewerkt wordt, leest zo'n lijst als een storing. Vandaar het draaiende
   ringetje: bij het stempel zolang een ronde loopt, en bij elk toestel dat nog moet komen. */
.mon-spin {
    display: inline-block; flex: 0 0 auto;
    width: 11px; height: 11px;
    border: 2px solid currentColor; border-top-color: transparent;
    border-radius: 50%; opacity: .8;
    animation: knop-draai .7s linear infinite;
}

/* Twee stempels, één tegelijk: "bezig" zolang de omhulling `is-busy` draagt, anders het
   tijdstip. Zie assets/controllers/monitoring_controller.js. */
.mon-state__busy { display: none; }
.mon-state__idle { display: inline-flex; align-items: center; gap: 8px; }
.mon-live.is-busy .mon-state__busy { display: inline-flex; align-items: center; gap: 8px; color: var(--accent-strong); }
.mon-live.is-busy .mon-state__idle { display: none; }

/* Hoever de ronde staat, naast de kop van de toestellenlijst. */
.mon-progress { gap: 7px; }

/* Stand en "niet storen" staan naast elkaar in dezelfde cel: het zijn twee dingen tegelijk en
   geen keuze tussen twee. Wordt de tabel een kaart, dan zakt het tweede onder het eerste in
   plaats van de cel uit te rekken. */
.mon-flags { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 6px; min-width: 0; }

/* De toestellen die nog aan de beurt moeten komen, blijven leesbaar maar trekken de aandacht
   niet weg van de standen die wél vastgesteld zijn. */
.mon-row--pending td { color: var(--muted); }
.mon-row--pending .mono { opacity: .75; }

@media (prefers-reduced-motion: reduce) {
    /* Zonder draaiing blijft het ringetje staan als open cirkel: nog altijd zichtbaar anders
       dan het bolletje van een vastgestelde stand. */
    .mon-spin { animation: none; border-top-color: currentColor; opacity: .45; }
}

/* ===================== Platformbeheer (microsites) ===================== */

.backlink {
    display: inline-flex; align-items: center; gap: 6px;
    color: var(--muted); font-size: 13px; font-weight: 500;
    margin-bottom: 6px;
}
.backlink:hover { color: var(--accent-strong); text-decoration: none; }
.backlink svg { width: 15px; height: 15px; }

/* Kerngegevens van een microsite, twee kolommen naam/waarde. */
.detail { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px 28px; margin: 0; }
.detail > div { min-width: 0; }
.detail dt { color: var(--muted); font-size: 12.5px; font-weight: 500; margin-bottom: 3px; }
.detail dd { margin: 0; font-size: 14.5px; overflow-wrap: anywhere; }
@media (max-width: 640px) { .detail { grid-template-columns: minmax(0, 1fr); } }

.form__legend {
    font-size: 12.5px; font-weight: 600; text-transform: uppercase; letter-spacing: .06em;
    color: var(--muted);
    padding-bottom: 8px; margin-bottom: 18px;
    border-bottom: 1px solid var(--line-soft);
}
.form__legend + .form__row, .form__legend + .form__row--split { margin-top: 0; }
/* Eén zin onder een kopje, voor een groep velden die samen iets doen wat hun eigen labels
   niet vertellen. */
.form__note { margin: -6px 0 14px; color: var(--muted); font-size: 12.5px; }
.form .form__legend:not(:first-child) { margin-top: 10px; }

.form input[type="url"] {
    width: 100%;
    font-family: inherit; font-size: max(14.5px, var(--field-min));
    color: var(--ink);
    padding: 10px 12px;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--surface);
    transition: border-color .12s, box-shadow .12s;
}

/* Uitgeklapte keuzelijst (rechten van een gebruiker). */
.form__row > div > div:has(> input[type="checkbox"]) {
    display: flex; align-items: center; gap: 10px;
    padding: 10px 12px;
    border: 1px solid var(--line); border-radius: 8px;
    background: var(--surface);
}
.form__row > div > div > input[type="checkbox"] { width: 17px; height: 17px; accent-color: var(--accent); flex: 0 0 17px; }
.form__row > div > div > label { margin: 0; font-weight: 500; color: var(--ink); }

/* Modules aan- of uitzetten per microsite. */
.modules-pick { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
.form .module-pick {
    display: flex; align-items: center; gap: 11px; margin: 0; cursor: pointer;
    padding: 12px 14px;
    border: 1px solid var(--line); border-radius: 8px; background: var(--surface);
    font-weight: 500;
    transition: border-color .12s, background .12s;
}
.form .module-pick:hover { border-color: #d4d8e0; }
.form .module-pick:has(input:checked) { border-color: var(--accent); background: var(--accent-soft); }
.form .module-pick input[type="checkbox"] { width: 17px; height: 17px; flex: 0 0 17px; accent-color: var(--accent); margin: 0; }
.module-pick__icon { display: grid; place-items: center; color: var(--muted); }
.module-pick__icon svg { width: 18px; height: 18px; }
.form .module-pick:has(input:checked) .module-pick__icon { color: var(--accent-strong); }
.module-pick__text { min-width: 0; line-height: 1.35; overflow-wrap: anywhere; }
.module-pick__text b { display: block; font-size: 14px; color: var(--ink); }
.module-pick__text span { color: var(--muted); font-size: 12.5px; font-weight: 400; }
.module-pick .badge { margin-left: auto; flex: 0 0 auto; }

@media (max-width: 820px) { .modules-pick { grid-template-columns: minmax(0, 1fr); } }

/* De modules van een microsite, als leeslijst op het detailscherm. */
.module-tags { display: flex; flex-wrap: wrap; gap: 6px; }

/* ===================== Praktijkwisselaar in de topbalk ===================== */

.switcher { position: relative; min-width: 0; }

.switcher__none {
    display: flex; align-items: center; gap: 8px;
    padding: 7px 11px; border-radius: 999px;
    border: 1px dashed var(--line);
    color: var(--muted); font-size: 13px;
}
.switcher__none svg { width: 16px; height: 16px; flex: 0 0 16px; }

.switcher__current {
    display: flex; align-items: center; gap: 9px;
    padding: 7px 11px; border-radius: 999px;
    border: 1px solid transparent;
    font-size: 13px; color: var(--ink-soft);
    cursor: default;
    /* Het bolletje en de chevron houden hun maat; de naam ertussen geeft mee.
       Zonder deze twee regels duwt een lange praktijknaam de topbalk uit beeld. */
    min-width: 0;
}
.switcher__current > .dot-ok, .switcher__current > .switcher__chev { flex: 0 0 auto; }
.switcher__box > .switcher__current {
    cursor: pointer; list-style: none;
    border-color: var(--line);
    background: var(--surface);
    transition: background .12s, border-color .12s;
}
.switcher__box > .switcher__current:hover { background: var(--canvas); border-color: var(--accent-line); }
.switcher__box > .switcher__current::-webkit-details-marker { display: none; }
.switcher__box[open] > .switcher__current { background: var(--canvas); }

.switcher__mark {
    display: inline-flex; align-items: center; justify-content: center;
    width: 28px; height: 28px; flex: 0 0 28px;
    border-radius: 7px;
    background: var(--accent-soft); color: var(--accent-strong);
    /* Twee letters moeten in hetzelfde vierkantje passen als voorheen één. */
    font-size: 12px; font-weight: 700; letter-spacing: .01em;
}

.switcher__text { flex: 0 1 auto; min-width: 0; line-height: 1.25; }
.switcher__text b { display: block; color: var(--ink); font-size: 13px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.switcher__text span { display: block; color: var(--muted); font-size: 11.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ===================== Op het beginscherm zetten ===================== */

/* De knop staat verborgen in de topbalk en komt alleen tevoorschijn waar installeren
   ook echt kan; zie assets/controllers/pwa_install_controller.js. Vandaar :not([hidden])
   en niet een kaal display:flex — dat laatste wint van [hidden] en zou de knop overal
   laten staan, ook waar er niets te installeren valt. */
.install:not([hidden]) { display: flex; align-items: center; }

/* Het Deel-teken staat middenin een zin en moet dus met de tekst meelopen. */
.confirm__text p svg { width: 15px; height: 15px; vertical-align: -3px; color: var(--ink-soft); }

.switcher__meta { color: var(--muted); font-size: 12.5px; white-space: nowrap; }
.switcher__meta::before { content: "· "; }

.switcher__chev { color: var(--muted); display: flex; }
.switcher__chev svg { width: 16px; height: 16px; transition: transform .12s ease; }
.switcher__box[open] .switcher__chev svg { transform: rotate(180deg); }

.switcher__menu {
    position: absolute; top: calc(100% + 8px); right: 0; z-index: 20;
    min-width: 280px;
    /* Blijft binnen de vensterrand op een telefoon; --pad-x is de marge ernaast. */
    max-width: min(340px, calc(100vw - var(--pad-x) * 2));
    padding: 6px;
    border-radius: var(--radius);
    background: var(--surface);
    border: 1px solid var(--line);
    box-shadow: var(--shadow);
    /* Bij veel praktijken past de lijst niet meer op het scherm: begrens de hoogte. */
    display: flex; flex-direction: column;
    max-height: calc(100dvh - var(--topbar-h) - 24px);
}
/* Alleen de praktijken scrollen; kopje en zoekveld blijven staan. */
.switcher__list { overflow-y: auto; overscroll-behavior: contain; }

.switcher__search {
    flex: 0 0 auto;
    position: relative;
    margin: 0 3px 6px;
}
.switcher__search svg {
    position: absolute; left: 9px; top: 50%; transform: translateY(-50%);
    width: 15px; height: 15px; color: var(--muted); pointer-events: none;
}
.switcher__search input {
    width: 100%;
    font-family: inherit; font-size: max(13.5px, var(--field-min));
    color: var(--ink);
    padding: 7px 10px 7px 30px;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--surface);
    transition: border-color .12s, box-shadow .12s;
}
.switcher__search input:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-soft);
}
.switcher__search input::-webkit-search-decoration,
.switcher__search input::-webkit-search-cancel-button { -webkit-appearance: none; }

.switcher__empty { color: var(--muted); font-size: 13px; padding: 8px 9px; }
.switcher__menu form { margin: 0; }
.switcher__menu-label {
    flex: 0 0 auto;
    color: var(--muted);
    font-size: 11px; letter-spacing: .07em; text-transform: uppercase;
    padding: 7px 9px 6px;
}

.switcher__option {
    display: flex; align-items: center; gap: 10px; width: 100%;
    padding: 8px; border: 0; border-radius: var(--radius-sm);
    background: transparent; color: inherit;
    font-family: inherit; text-align: left; cursor: pointer;
    transition: background .12s;
}
.switcher__option:hover { background: var(--canvas); }
.switcher__option.is-active { background: var(--accent-soft); }
/* Waar de pijltjes staan: een randje erbij, want de actieve praktijk kleurt al. */
.switcher__option.is-highlighted {
    background: var(--canvas);
    box-shadow: inset 0 0 0 1px var(--accent);
}
.switcher__option.is-active.is-highlighted { background: var(--accent-soft); }
.switcher__option .switcher__mark { background: var(--canvas); color: var(--ink-soft); }
.switcher__option.is-active .switcher__mark { background: var(--accent); color: #fff; }
.switcher__check { margin-left: auto; color: var(--accent-strong); display: flex; }
.switcher__check svg { width: 15px; height: 15px; }

/* Toegang van één gebruiker tot meerdere praktijken. */
.site-tags { display: flex; flex-wrap: wrap; gap: 5px; }

.grant { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; padding: 14px 20px; border-top: 1px solid var(--line-soft); }
.grant select { font-family: inherit; font-size: max(14px, var(--field-min)); padding: 8px 11px; border: 1px solid var(--line); border-radius: 8px; background: var(--surface); color: var(--ink); flex: 1 1 240px; min-width: 0; max-width: 380px; }
.grant select:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.grant__label { color: var(--muted); font-size: 13px; font-weight: 500; }

/* ===================== Paginalader =====================
   Twee lagen die samen verschijnen: Turbo's eigen streepje bovenaan het
   venster, en een sluier over het hele scherm. De streep toont voortgang,
   de sluier maakt duidelijk dat er even niets aan te klikken valt.
   Het moment van tonen staat in assets/pageloader.js. */

/* Turbo's voortgangsbalk is standaard felblauw en 3px dik; hier een dunne
   teal streep. Turbo geeft hem de hoogst mogelijke z-index, dus hij blijft
   boven de sluier zichtbaar. */
.turbo-progress-bar {
    height: 2px;
    background: linear-gradient(90deg, var(--accent) 0%, var(--accent-strong) 100%);
    box-shadow: 0 0 8px rgba(14, 138, 125, .45);
}

.pageloader {
    position: fixed; inset: 0; z-index: 90;
    display: grid; place-items: center;
    background: rgba(246, 247, 249, .78);
    -webkit-backdrop-filter: blur(3px);
    backdrop-filter: blur(3px);
    /* Onzichtbaar én onbereikbaar in rust: visibility houdt hem uit de
       tabvolgorde, opacity verzorgt het invloeien. */
    opacity: 0; visibility: hidden;
    transition: opacity .18s ease, visibility .18s;
}
.pageloader.is-active { opacity: 1; visibility: visible; }

/* Iets boven het midden: optisch gecentreerd leest rustiger dan wiskundig. */
.pageloader__box { display: grid; justify-items: center; gap: 18px; transform: translateY(-5%); }

.pageloader__mark { color: var(--accent); display: flex; }
.pageloader__mark .logo { width: 46px; height: 46px; }

.pageloader__track {
    position: relative; overflow: hidden;
    width: 148px; height: 3px;
    border-radius: 999px;
    background: var(--accent-line);
}
.pageloader__track span {
    position: absolute; top: 0; bottom: 0; left: 0;
    width: 38%;
    border-radius: inherit;
    background: linear-gradient(90deg, var(--accent) 0%, var(--accent-strong) 100%);
}

/* Uit beeld, maar niet uit de toegankelijkheidsboom: display:none zou de tekst
   ook voor schermlezers wegnemen. */
.pageloader__text {
    position: absolute;
    width: 1px; height: 1px;
    margin: -1px; padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* De animaties draaien alleen zolang de lader in beeld is. */
.pageloader.is-active .pageloader__mark { animation: pageloader-adem 1.9s ease-in-out infinite; }
.pageloader.is-active .pageloader__track span { animation: pageloader-schuif 1.15s ease-in-out infinite; }

@keyframes pageloader-adem {
    0%, 100% { opacity: 1; }
    50%      { opacity: .4; }
}
@keyframes pageloader-schuif {
    0%   { transform: translateX(-105%); }
    100% { transform: translateX(368%); }
}

@media (prefers-reduced-motion: reduce) {
    .pageloader.is-active .pageloader__mark,
    .pageloader.is-active .pageloader__track span { animation: none; }
    .pageloader__track span { width: 100%; opacity: .55; }
}

/* ===================== Bevestigen =====================
   De vraag voor een onomkeerbare actie. <dialog> zet zichzelf in de bovenste laag
   en tekent zijn eigen sluier, dus hier geen z-index en geen scrollslot. */

.confirm {
    width: min(440px, calc(100vw - 32px));
    padding: 0;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--surface);
    color: var(--ink);
    box-shadow: 0 16px 48px rgba(20, 23, 31, .18);
}

.confirm::backdrop {
    background: rgba(20, 23, 31, .38);
    -webkit-backdrop-filter: blur(2px);
    backdrop-filter: blur(2px);
}

/* Het waarschuwingsteken naast de tekst, de knoppen eronder in dezelfde kolom als
   de tekst — zo staat er niets onder het icoon. */
.confirm__box {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    gap: 0 14px;
    margin: 0;
    padding: 22px;
}

.confirm__icon {
    width: 34px; height: 34px;
    border-radius: 999px;
    display: grid; place-items: center;
    background: var(--danger-soft);
    color: var(--danger);
}
.confirm__icon svg { width: 18px; height: 18px; }
/* Het rood hierboven hoort bij de vraag "weet u het zeker" voor iets onomkeerbaars.
   Dit venster legt alleen iets uit, en dat mag er niet uitzien als een waarschuwing. */
.confirm__icon--neutraal { background: var(--accent-soft); color: var(--accent-strong); }

.confirm__text h2 { font-size: 16px; line-height: 34px; }
.confirm__text p { margin: 4px 0 0; color: var(--ink-soft); font-size: 14px; }

.confirm__actions {
    grid-column: 2;
    display: flex; justify-content: flex-end; gap: 8px;
    margin-top: 20px;
}

/* Wat er gaat gebeuren staat op de knop, niet alleen in de vraag ernaast. */
.btn--danger-solid { background: var(--danger); border-color: var(--danger); color: #fff; }
.btn--danger-solid:hover { background: #a53225; border-color: #a53225; }

.confirm[open] { animation: confirm-op .16s ease-out; }
.confirm[open]::backdrop { animation: confirm-sluier .16s ease-out; }

@keyframes confirm-op {
    from { opacity: 0; transform: translateY(8px) scale(.98); }
}
@keyframes confirm-sluier {
    from { opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
    .confirm[open], .confirm[open]::backdrop { animation: none; }
}

/* Op een telefoon staan de knoppen onder elkaar en over de volle breedte: naast
   elkaar worden ze daar te smal om zeker te raken. */
@media (max-width: 480px) {
    .confirm__box { grid-template-columns: minmax(0, 1fr); padding: 20px; }
    .confirm__icon { margin-bottom: 12px; }
    .confirm__text h2 { line-height: 1.3; }
    .confirm__actions { grid-column: 1; flex-direction: column-reverse; }
    .confirm__actions .btn { justify-content: center; }
}

/* ===================== Instellingen van een module =====================
   Het tandwiel op het vakje van een module, en het venster dat eraan hangt. Wat erin
   staat geldt voor één module en voor een handvol praktijken; het hoort niet in de rij
   met alles wat elke praktijk invult. Zie assets/controllers/module_settings_controller.js. */

.module-pick__gear {
    position: relative;
    margin-left: auto; flex: 0 0 auto;
    display: grid; place-items: center;
    width: 28px; height: 28px; padding: 0;
    border: 1px solid transparent; border-radius: 7px;
    background: transparent; color: var(--muted);
    cursor: pointer;
    transition: background .12s, color .12s, border-color .12s;
}
.module-pick__gear svg { width: 16px; height: 16px; }
.module-pick__gear:hover { background: var(--surface); border-color: var(--line); color: var(--accent-strong); }
.module-pick__gear:focus-visible { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
/* Een badge duwt het tandwiel niet weg: dan staan ze naast elkaar, badge eerst. */
.module-pick .badge + .module-pick__gear { margin-left: 8px; }

/* Zolang de koppeling niet volledig ingevuld is. Het bolletje draagt geen tekst — wat er
   scheelt staat in de `title` en de aria-label van de knop eronder. */
.module-pick__dot {
    position: absolute; top: 2px; right: 2px;
    width: 7px; height: 7px; border-radius: 999px;
    background: var(--warn); box-shadow: 0 0 0 2px var(--accent-soft);
}
.form .module-pick:not(:has(input:checked)) .module-pick__dot { box-shadow: 0 0 0 2px var(--surface); }

/* Het venster zelf. Net als bij .confirm zet <dialog> zichzelf in de bovenste laag en
   tekent hij zijn eigen sluier, dus hier geen z-index en geen scrollslot. */
.sheet {
    width: min(560px, calc(100vw - 32px));
    max-height: calc(100dvh - 48px);
    padding: 0;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--surface);
    color: var(--ink);
    box-shadow: 0 16px 48px rgba(20, 23, 31, .18);
    /* Kop en voet blijven staan; alleen de velden ertussen schuiven. */
    flex-direction: column;
}
.sheet[open] { display: flex; }

.sheet::backdrop {
    background: rgba(20, 23, 31, .38);
    -webkit-backdrop-filter: blur(2px);
    backdrop-filter: blur(2px);
}

.sheet__head {
    display: flex; align-items: flex-start; gap: 12px;
    padding: 18px 20px;
    border-bottom: 1px solid var(--line-soft);
}
.sheet__title { display: flex; align-items: flex-start; gap: 12px; min-width: 0; }
.sheet__icon {
    width: 34px; height: 34px; flex: 0 0 34px;
    border-radius: 999px;
    display: grid; place-items: center;
    background: var(--accent-soft); color: var(--accent-strong);
}
.sheet__icon svg { width: 18px; height: 18px; }
.sheet__head h2 { font-size: 16px; margin: 4px 0 0; }
.sheet__head p { margin: 4px 0 0; color: var(--ink-soft); font-size: 13px; line-height: 1.4; }

.sheet__close {
    margin-left: auto; flex: 0 0 auto;
    display: grid; place-items: center;
    width: 30px; height: 30px; padding: 0;
    border: 1px solid transparent; border-radius: 7px;
    background: transparent; color: var(--muted);
    cursor: pointer;
    transition: background .12s, color .12s, border-color .12s;
}
.sheet__close svg { width: 17px; height: 17px; }
.sheet__close:hover { background: var(--canvas); border-color: var(--line); color: var(--ink); }
.sheet__close:focus-visible { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }

.sheet__body { padding: 20px; overflow-y: auto; overscroll-behavior: contain; }
/* De laatste rij houdt geen marge over: de voet zet er zelf lucht onder. */
.sheet__body > :last-child { margin-bottom: 0; }

.sheet__foot {
    display: flex; align-items: center; justify-content: space-between; gap: 12px;
    padding: 14px 20px;
    border-top: 1px solid var(--line-soft);
    background: var(--canvas);
    border-radius: 0 0 var(--radius) var(--radius);
}
.sheet__hint { color: var(--muted); font-size: 12.5px; }

.sheet[open] { animation: confirm-op .16s ease-out; }
.sheet[open]::backdrop { animation: confirm-sluier .16s ease-out; }

@media (prefers-reduced-motion: reduce) {
    .sheet[open], .sheet[open]::backdrop { animation: none; }
}

@media (max-width: 480px) {
    .sheet__head, .sheet__body { padding: 16px; }
    .sheet__foot { flex-direction: column-reverse; align-items: stretch; padding: 14px 16px; }
    .sheet__foot .btn { justify-content: center; }
    .sheet__hint { text-align: center; }
}

/* ===================== Statistieken =====================
   Grafiekjes zonder bibliotheek. Een staafje is een doosje met een hoogte, en die
   hoogte volgt uit de gegevens — dus staat ze als custom property op het element
   zelf (--h, --m, --w) in plaats van in een klasse die haar niet kan kennen.
   Zie templates/statistics/_chart.html.twig. */

/* Zes cijfers boven de grafieken. Vast op drie kolommen: auto-fit zet er op een
   breed scherm vijf naast elkaar en laat de zesde er verweesd onder hangen. */
.stats--statistics { grid-template-columns: repeat(3, minmax(0, 1fr)); }
@media (max-width: 1100px) { .stats--statistics { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px)  { .stats--statistics { grid-template-columns: minmax(0, 1fr); } }

/* Een terzijde in een kaartkop: waar het cijfer ernaast vandaan komt, of het
   drukste moment. Rechts uitgelijnd, en op een smal scherm onder de titel. */
.card__note { margin-left: auto; color: var(--muted); font-size: 12.5px; }
.card__foot { padding: 0 20px 16px; }

/* De grafiek: de schaal links, de staafjes ernaast. */
.chart { display: flex; gap: 10px; }
.chart__axis {
    display: flex; flex-direction: column; justify-content: space-between;
    height: 180px; padding-bottom: 18px;
    color: var(--muted); font-size: 11px; font-variant-numeric: tabular-nums;
    text-align: right; min-width: 22px;
}
/* De laatste twee schaalstreepjes staan op hun lijn en niet erboven: een halve
   regelhoogte omhoog zet het cijfer naast de lijn waar het voor staat. */
.chart__axis span { line-height: 1; transform: translateY(50%); }
.chart__axis span:first-child { transform: none; }

.chart__bars {
    flex: 1; display: flex; align-items: flex-end; gap: 4px;
    margin: 0; padding: 0; list-style: none; min-width: 0;
}
/* Positie en stapelvolgorde: de aangewezen kolom komt bovenop, anders schildert
   het staafje ernaast over het label dat eroverheen hangt. */
.chart__col { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; position: relative; }
.chart__col:hover { z-index: 4; }
/* Het vak waar het staafje in staat. De twee lijnen op nul en de helft komen uit
   een verloop: geen extra elementen, en ze schuiven vanzelf mee met de hoogte. */
.chart__slot {
    position: relative;
    height: 180px; display: flex; align-items: flex-end;
    background:
        linear-gradient(var(--line), var(--line)) 0 50% / 100% 1px no-repeat,
        linear-gradient(var(--line), var(--line)) 0 100% / 100% 1px no-repeat;
}
/* De hele kolom is het doelwit, niet alleen het staafje: een stil uur is tien pixel hoog en
   daar valt niet op te mikken. Een link als het staafje ergens heen gaat, een div als de
   grafiek enkel iets laat zien — dezelfde vorm, zodat de opmaak van beide niet uiteenloopt. */
.chart__hit {
    flex: 1; display: flex; flex-direction: column;
    color: inherit; text-decoration: none; border-radius: 4px;
}
a.chart__hit { cursor: pointer; }
a.chart__hit:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.chart__bar {
    width: 100%; height: var(--h); min-height: 0;
    background: var(--chart-soft); border-radius: 3px 3px 0 0;
    position: relative; overflow: hidden;
    transition: filter .12s;
}
/* Lichter kan niet meer bij een gedempte vulling; donkerder wel. */
.chart__slot:hover .chart__bar { filter: brightness(.93); }
a.chart__hit:hover .chart__bar { filter: brightness(.86); }
a.chart__hit:hover .chart__tick { color: var(--ink-soft); }

/* Het staafje waar het filter nu op staat. Het draagt de accentkleur in plaats van de
   gedempte vulling: van de vierentwintig uren is dit het enige waar nog iets in staat, en
   zonder dat verschil lijkt de grafiek stuk in plaats van gefilterd. */
.chart__col.is-active .chart__bar { background: var(--accent); }
.chart__col.is-active .chart__tick { color: var(--accent); font-weight: 600; }
/* Het gemiste deel zit bovenaan het staafje: dat is waar het gesprek strandde.
   Donkerder dan de rest van de staaf, want dat is het stuk waar iemand naar kijkt. */
.chart__miss { position: absolute; inset: 0 0 auto 0; height: var(--m); background: var(--chart-ink); }
/* Wie enkel een boodschap hoorde, zit onder het gemiste deel in grijs: geen gesprek, maar
   ook niemand die het liet rinkelen. */
.chart__ann { position: absolute; inset: var(--m, 0%) 0 auto 0; height: var(--a); background: var(--chart-grey); }

/* Het label bij het aanwijzen — een eigen doosje in plaats van de title-tekst van
   de browser. Die komt pas na een seconde, verdwijnt daarna uit zichzelf weer, en
   is niet op te maken; op een staafje van veertig pixel breed is dat het verschil
   tussen "een cijfer opvragen" en "een cijfer aflezen".

   Het hangt boven het staafje en gaat er dus mee omhoog: --h staat op het vak,
   niet op het staafje. Alleen waar er een muis is (zie de media-query eronder). */
.chart__tip {
    position: absolute; z-index: 3;
    left: 50%; bottom: calc(var(--h, 0%) + 10px);
    transform: translate(-50%, 4px);
    width: max-content; max-width: 220px;
    padding: 7px 10px; border-radius: var(--radius-sm);
    background: var(--ink); color: #fff;
    font-size: 12px; line-height: 1.45;
    box-shadow: var(--shadow);
    opacity: 0; pointer-events: none;
    transition: opacity .12s, transform .12s;
}
.chart__tip b { display: block; font-weight: 600; }
.chart__tip span { display: block; color: rgba(255, 255, 255, .68); }
/* Het pijltje dat het doosje aan zijn staafje vastmaakt. */
.chart__tip::after {
    content: ''; position: absolute; top: 100%; left: 50%; margin-left: -5px;
    border: 5px solid transparent; border-top-color: var(--ink);
}
.chart__slot:hover .chart__tip { opacity: 1; transform: translate(-50%, 0); }

/* Aan de twee uiteinden zou een gecentreerd doosje naast de kaart hangen; daar
   lijnt het uit met de rand van zijn eigen kolom en verschuift het pijltje mee. */
.chart__col:first-child .chart__tip { left: 0; transform: translate(0, 4px); }
.chart__col:first-child .chart__slot:hover .chart__tip { transform: translate(0, 0); }
.chart__col:first-child .chart__tip::after { left: 12px; margin-left: 0; }
.chart__col:last-child .chart__tip { left: auto; right: 0; transform: translate(0, 4px); }
.chart__col:last-child .chart__slot:hover .chart__tip { transform: translate(0, 0); }
.chart__col:last-child .chart__tip::after { left: auto; right: 7px; margin-left: 0; }

/* Zonder muis bestaat aanwijzen niet: een tik zou het doosje laten hangen tot je
   ergens anders tikt. De sr-only-regel in elke kolom houdt de cijfers wél bereikbaar. */
@media (hover: none) {
    .chart__tip { display: none; }
}

.chart__tick {
    padding-top: 6px; text-align: center;
    color: var(--muted); font-size: 10.5px; font-variant-numeric: tabular-nums;
    white-space: nowrap; overflow: hidden; text-overflow: clip;
}
/* Veel staafjes: de datums passen alleen nog schuin. */
.chart--dense .chart__bars { gap: 2px; }
.chart--dense .chart__tick { font-size: 9.5px; }

.chart__legend { display: flex; align-items: center; gap: 6px; margin: 14px 0 0; color: var(--muted); font-size: 12.5px; }
.chart__legend .chart__key:not(:first-child) { margin-left: 10px; }
.chart__key { width: 10px; height: 10px; border-radius: 3px; display: inline-block; }
.chart__key--ok { background: var(--chart-soft); }
.chart__key--miss { background: var(--chart-ink); }
.chart__key--ann { background: var(--chart-grey); }

/* Wat onder een grafiek of een tabel hoort te staan om ze goed te lezen. */
.chart__note { margin: 14px 0 0; color: var(--muted); font-size: 12.5px; line-height: 1.55; }
.chart__note svg { width: 14px; height: 14px; vertical-align: -2px; color: var(--ok); }
.card__body > .chart__note:first-child { margin-top: 0; }

/* Een liggende balk: naam, balk, cijfer. Voor verdelingen waar de namen te lang
   zijn om onder een staafje te passen. */
.meter { display: grid; grid-template-columns: 92px minmax(0, 1fr) auto; align-items: center; gap: 12px; }
.meter + .meter { margin-top: 10px; }
.meter__label { color: var(--ink-soft); font-size: 13px; font-weight: 500; }
.meter__track { height: 8px; border-radius: 999px; background: var(--chart-pale); overflow: hidden; }
.meter__fill { height: 100%; width: var(--w); border-radius: 999px; min-width: 2px; }
/* Nul is nul: een streepje van twee pixels zou "bijna niets" betekenen. */
.meter__fill--none { min-width: 0; }
/* Dezelfde ladder: --heavy voor de trede die opvalt, --muted voor wat er
   alleen staat om het geheel kloppend te maken. */
.meter__fill--accent { background: var(--chart-mid); }
.meter__fill--soft   { background: var(--chart-soft); }
.meter__fill--heavy  { background: var(--chart-ink); }
.meter__fill--muted  { background: var(--chart-grey); }
.meter__value { font-size: 13px; font-weight: 600; font-variant-numeric: tabular-nums; white-space: nowrap; }
.meter__value span { color: var(--muted); font-weight: 500; }

/* Dezelfde balk in een tabelcel: daar is de naam de rij zelf. */
.meter--inline { grid-template-columns: minmax(60px, 1fr) auto; gap: 8px; }
.meter--inline .meter__value { font-size: 12.5px; }

/* De tooltip bij een knop of een greep — hetzelfde doosje als bij de grafiek, maar
   ergens anders om dezelfde reden: de title-tekst van de browser komt pas na een
   seconde, en dat is precies de tijd waarin iemand die twijfelt over een prullenbakje
   zijn muis alweer heeft weggehaald. Zie assets/controllers/tooltip_controller.js.

   Vast aan het scherm en niet in de kaart eronder: de knopjes in een tabelrij zitten
   in een .table-wrap die horizontaal schuift, en daar zou het doosje tegen de rand aan
   afgeknipt worden. Onder de pageloader (z-index 90) en de skip-link (100) door: die
   twee horen bovenop te blijven. */
.tip {
    position: fixed; z-index: 80;
    max-width: 260px;
    padding: 7px 10px; border-radius: var(--radius-sm);
    background: var(--ink); color: #fff;
    font-size: 12px; line-height: 1.45;
    box-shadow: var(--shadow);
    /* Nooit onder de aanwijzer: het doosje staat naast de knop en zou anders het
       weggaan van de muis melden zodra het onder haar opduikt. */
    pointer-events: none;
    opacity: 0; transform: translateY(2px);
    transition: opacity .1s, transform .1s;
}
.tip.is-shown { opacity: 1; transform: translateY(0); }
.tip--below { transform: translateY(-2px); }

/* Het pijltje dat het doosje aan zijn knop vastmaakt. Onderaan wanneer het erboven
   hangt, bovenaan wanneer het eronder moest. Waar het staat, rekent de controller uit:
   bij een knop tegen de rand van het scherm schuift het doosje opzij, en een pijltje
   dat dan in het midden blijft steken wijst naar niets. */
.tip::after {
    content: ''; position: absolute; top: 100%; left: var(--arrow, 50%); margin-left: -5px;
    border: 5px solid transparent; border-top-color: var(--ink);
}
.tip--below::after {
    top: auto; bottom: 100%;
    border-top-color: transparent; border-bottom-color: var(--ink);
}

/* Zonder muis bestaat aanwijzen niet: een tik zou het doosje laten hangen tot je
   ergens anders tikt. De controller haakt daar dan ook niet aan; dit is de vangnetregel. */
@media (hover: none) {
    .tip { display: none; }
}

/* ---------- Aanmelden in twee stappen ----------
   Het instelscherm: de QR-code naast wat er te doen staat. De herstelcodes eronder
   in twee kolommen, in het monospace van de rest van de app, zodat een 8 en een B
   uit elkaar te houden zijn wanneer ze op papier staan. */

.totp { display: grid; grid-template-columns: auto 1fr; gap: 24px; align-items: start; }
.totp__qr {
    background: #fff;
    padding: 12px;
    border: 1px solid var(--line);
    border-radius: 12px;
    line-height: 0;
}
.totp__steps { margin: 0 0 18px; padding-left: 18px; color: var(--ink-soft); display: grid; gap: 8px; }
.totp__secret {
    background: var(--line-soft);
    border-radius: 8px;
    padding: 8px 11px;
    display: inline-block;
    user-select: all;
    word-break: break-all;
}

.codes { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; }
.codes li {
    background: var(--line-soft);
    border-radius: 8px;
    padding: 9px 12px;
    text-align: center;
    user-select: all;
}

/* ---------- Wachtdiensten ----------
   Het rooster is een gewone tabel: een rij per dag, en in de tweede cel de beurten
   van die dag onder elkaar. Vandaar dat hier bijna niets staat — de tabel, de kaart
   en het bladeren eronder zijn dezelfde als bij de andere overzichten. */

/* Eén beurt binnen een dagcel: uur, arts, nummer op één regel, en netjes onder
   elkaar wanneer er die dag meer dan één is. */
/* De beurten van één dag onder elkaar. Een eigen wikkel en niet los in de cel: onder de
   860px wordt die cel een flexrij, en dan zouden twee beurten naast elkaar belanden. */
.oncall-slots { display: grid; gap: 8px; min-width: 0; }
.oncall-slot { display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 12px; }
.oncall-slot + .oncall-slot { padding-top: 8px; border-top: 1px dashed var(--line-soft); }
/* De beurt die nu loopt: dezelfde regel, alleen zwaarder. Een kleurvlak zou hem tot
   waarschuwing maken, en dit is de gewone gang van zaken. */
.oncall-slot--now { font-weight: 600; }
.oncall-slot__time { color: var(--muted); white-space: nowrap; font-variant-numeric: tabular-nums; }
.oncall-slot--now .oncall-slot__time { color: var(--accent-strong); }

/* De dagnaam komt uit de ICU-opmaak en begint daar met een kleine letter. */
.oncall-day { text-transform: capitalize; }

/* Aan een dagnaam heeft de eerste kolom genoeg. Zonder maat verdeelt de tabel het
   overschot evenredig en staat er een handbreedte wit naast "Maandag". Boven de
   860px, want daaronder wordt elke rij een kaartje en vervalt de kolom. */
@media (min-width: 861px) {
    .oncall-schedule th:first-child,
    .oncall-schedule td:first-child { width: 200px; }
}

/* Het tijdelijke nummer hangt aan de lopende beurt erboven, niet aan de kaart:
   een streep ertussen scheelt de vraag waar het formulier over gaat. */
.oncall-override { margin-top: 20px; padding-top: 4px; border-top: 1px solid var(--line-soft); }

/* =================================================================
   Responsief
   -----------------------------------------------------------------
   Grenzen, elk met één duidelijke opdracht:

     1200px  de zijbalk wordt smaller, de marges krimpen
     1024px  de zijbalk wordt een lade achter een hamburger
      860px  brede tabellen worden kaarten met een label per waarde
      880px  aanmelden wordt één kolom
      720px  de grafieken krimpen, hun schaalstreepjes verdwijnen
      560px  telefoon: alles onder elkaar, knoppen over de volle breedte

   Wat hierboven staat is het bureaubladbeeld; hieronder staat enkel wat
   daarvan afwijkt. Zo blijft te zien wat de vorm eigenlijk is.
   ================================================================= */

/* ---------- 1200px — smallere zijbalk, minder marge ---------- */

@media (max-width: 1200px) {
    :root { --sidebar-w: 224px; --pad-x: 24px; --pad-y: 24px; }
}

/* ---------- 1024px — de zijbalk wordt een lade ---------- */

@media (max-width: 1024px) {
    :root { --pad-x: 20px; --topbar-h: 60px; }

    /* Uit het raster van de app-shell: de lade zweeft over de inhoud in plaats
       van er een kolom naast af te snoepen. */
    .sidebar {
        position: fixed;
        top: 0; left: 0; bottom: 0;
        width: min(300px, 85vw);
        flex: 0 0 auto;
        height: 100%;
        transform: translateX(-100%);
        box-shadow: 0 0 40px rgba(20, 23, 31, .3);
        /* Dicht is de lade niet aan te klikken en niet met Tab te bereiken:
           visibility haalt hem uit de tabvolgorde, een transform alleen niet.
           Ze staat in de overgang, anders springt hij weg vóór hij uitgeschoven is. */
        visibility: hidden;
        transition: transform .22s ease, visibility .22s;
    }
    .app.is-nav-open .sidebar { transform: none; visibility: visible; }

    .nav-scrim { display: block; }
    .app.is-nav-open .nav-scrim { opacity: 1; visibility: visible; }

    /* De hamburger opent, het kruis in de zijbalk sluit. */
    .topbar__burger {
        display: inline-flex; align-items: center; justify-content: center;
        width: 38px; height: 38px; flex: 0 0 38px;
        margin-left: -6px;
        padding: 0;
        border: 1px solid var(--line); border-radius: 9px;
        background: var(--surface); color: var(--ink-soft);
        cursor: pointer; transition: background .12s, border-color .12s;
    }
    .topbar__burger:hover { background: var(--canvas); border-color: #d4d8e0; }
    .topbar__burger:focus-visible { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
    .topbar__burger svg { width: 20px; height: 20px; }

    .sidebar__close {
        display: grid; place-items: center;
        margin-left: auto;
        width: 34px; height: 34px; flex: 0 0 34px;
        padding: 0;
        border: 0; border-radius: 8px;
        background: rgba(255,255,255,.08); color: #cdd2dc;
        cursor: pointer;
    }
    .sidebar__close:hover { background: rgba(255,255,255,.16); color: #fff; }
    .sidebar__close:focus-visible { outline: none; box-shadow: 0 0 0 3px rgba(14,138,125,.5); }
    .sidebar__close svg { width: 18px; height: 18px; }

    /* Zolang de lade openstaat scrollt de pagina eronder niet mee. */
    body.has-nav-open { overflow: hidden; }
}

@media (prefers-reduced-motion: reduce) {
    .sidebar, .nav-scrim { transition: none; }
}

/* ---------- 1024px — de rest van het scherm ---------- */

@media (max-width: 1024px) {
    /* De praktijknaam kort in met een beletselteken zodra de topbalk krap wordt;
       "centrale actief" is dan de eerste die wijkt. */
    .switcher__meta { display: none; }

    .content__head .actions { margin-left: auto; }

    /* Tien cijfers naast een ledenlijst wordt krap; de lijst gaat bovenaan. */
    .q-layout { grid-template-columns: minmax(0, 1fr); }
}

/* ---------- 860px — tabellen worden kaarten ----------
   Een tabel van zeven kolommen laat zich niet indikken; zijwaarts schuiven
   kapt hem middenin een cel af en verbergt juist wat je zoekt. Elke rij wordt
   daarom een blokje met het kolomhoofd (data-label) vóór zijn waarde. De cel
   die de rij benoemt draagt .cell-title en staat er zonder label bovenaan.

   De grens ligt boven de 820px van een tablet in portret: dáár is de tabel het
   vaakst net te breed. Daarboven blijft ze een tabel en schuift ze, met de
   schaduw aan de rand als teken dat er meer achter zit. */

@media (max-width: 860px) {
    .table-wrap { overflow-x: visible; background: none; }

    table.data { display: block; font-size: 14px; }
    table.data thead { display: none; }
    table.data tbody { display: block; }

    table.data tbody tr {
        display: block;
        padding: 12px 16px;
        border-bottom: 1px solid var(--line);
    }
    table.data tbody tr:last-child { border-bottom: 0; }
    table.data tbody tr:hover { background: transparent; }

    table.data tbody td {
        display: flex;
        align-items: baseline;
        gap: 12px;
        padding: 3px 0;
        border: 0;
        /* Een e-mailadres of nummer is één woord; hier mag het breken. */
        min-width: 0;
        overflow-wrap: anywhere;
    }
    table.data tbody td::before {
        content: attr(data-label);
        flex: 0 0 38%;
        max-width: 130px;
        color: var(--muted);
        font-size: 11.5px; font-weight: 600;
        letter-spacing: .04em; text-transform: uppercase;
        line-height: 1.6;
    }
    /* Een cel zonder kolomhoofd zou een lege inspringing achterlaten. */
    table.data tbody td:not([data-label])::before { content: none; }

    table.data tbody td.cell-title {
        display: block;
        padding: 0 0 6px;
        font-size: 15px; font-weight: 600;
        overflow-wrap: anywhere;
    }
    table.data tbody td.cell-title::before { content: none; }
    /* De ondertitel van zo'n kopregel (praktijknaam, code) hangt eronder. */
    table.data tbody td.cell-title .t-muted { font-size: 12.5px; }

    /* Acties horen bij de rij, niet in de rechtermarge van een tabel die er niet meer is. */
    table.data .row-actions { text-align: left; white-space: normal; }
    table.data tbody td.row-actions { padding-top: 8px; }

    /* Een tweede regel in een cel (de naam bij een nummer) staat naast het label
       ingesprongen in plaats van eronder. */
    .cell-sub { display: inline; }
    .cell-sub::before { content: " · "; }
}

/* ---------- 880px — aanmelden wordt één kolom ----------
   Het donkere paneel is een tweede kolom, en die is er niet meer. Wat ervan
   overblijft is een strook boven het formulier: het beeldmerk en de belofte.
   De opsomming en de voetregel vallen weg — die vragen breedte die er niet is,
   en het formulier hoort hier bovenaan te staan, niet onder een folder. */

@media (max-width: 880px) {
    .login { grid-template-columns: minmax(0, 1fr); grid-template-rows: auto 1fr; }

    .login__aside {
        padding: 24px var(--pad-x) 28px;
        justify-content: flex-start;
        gap: 16px;
    }
    .login__aside::after { right: -170px; bottom: -230px; }
    .login__lead { font-size: 19px; max-width: none; }
    /* De opsomming en de voetregel ("Veilig platform …"). */
    .login__points, .login__aside > div:last-child { display: none; }

    .login__main { align-items: start; padding-top: 36px; }
}

/* ---------- 720px — de grafieken krimpen mee ---------- */

@media (max-width: 720px) {
    /* Het terzijde in een kaartkop past niet meer naast de titel. */
    .card__note { margin-left: 0; width: 100%; }
    .chart__axis, .chart__slot { height: 140px; }
    /* Onder de dertig staafjes past een datum nog rechtop; daarboven niet meer,
       en dan is de titel bij het aanwijzen wat overblijft. */
    .chart--dense .chart__tick { font-size: 0; }
    .meter { grid-template-columns: 80px minmax(0, 1fr) auto; gap: 8px; }
    .meter__label { font-size: 12.5px; }
}

/* ---------- 560px — telefoon ---------- */

@media (max-width: 560px) {
    :root { --pad-x: 14px; --pad-y: 18px; }

    /* De QR-code boven de uitleg in plaats van ernaast, herstelcodes onder elkaar. */
    .totp { grid-template-columns: 1fr; gap: 18px; }
    .codes { grid-template-columns: 1fr; }

    /* De topbalk draagt hier al een titel en de praktijknaam; het icoon zegt genoeg. */
    .install__label { display: none; }
    .install .btn { padding: 6px; }

    body { font-size: 14.5px; }

    /* Titel en knoppen onder elkaar; de knoppen delen de breedte. */
    .content__head { flex-direction: column; align-items: stretch; gap: 14px; }
    .content__head h1 { font-size: 20px; }
    .content__head .actions { margin-left: 0; flex-wrap: wrap; }
    .content__head .actions .btn { flex: 1 1 auto; justify-content: center; }

    .card__head { padding: 14px 16px; }
    .card__body { padding: 16px; }
    .mon-state { padding: 14px 16px; }
    .cf-item, .ext-list__item { padding: 12px 16px; }
    .card__head .actions { margin-left: auto; }

    /* Filterbalk: elk veld op zijn eigen regel, filteren en wissen naast elkaar. */
    .filters { padding: 14px 16px; gap: 12px; }
    .filters__field { flex: 1 1 100%; }
    .filters__field select,
    .filters__field input[type="text"],
    .filters__field input[type="search"] { min-width: 0; }
    .filters__actions { width: 100%; margin-left: 0; }
    .filters__actions .btn { flex: 1; justify-content: center; }
    .filters__note { flex: 1 1 100%; margin: 0; }
    .filters--stacked { padding: 0; }

    /* Bladeren: de telling boven, vorige en volgende links en rechts eronder. */
    .pager { flex-wrap: wrap; gap: 10px; padding: 14px 16px; }
    .pager__nav { margin-left: 0; width: 100%; justify-content: space-between; }

    /* Toegang geven: label boven, keuzelijst en knop eronder. */
    .grant { padding: 14px 16px; }
    .grant__label { flex: 1 1 100%; }
    .grant select { max-width: none; }

    /* Formulieren en knoppenrijen over de volle breedte. */
    .form__actions { flex-wrap: wrap; }
    .form__actions .btn { flex: 1 1 auto; justify-content: center; }

    /* Aanmelden: het paneel links is al verborgen, hier alleen nog wat lucht weg. */
    .login__main { padding: 32px 18px; }
    .login__box h1 { font-size: 21px; }

    .empty { padding: 40px 16px; }

    /* Cijfers twee aan twee: een overzicht waar je vijf keer voor moet scrollen
       is geen overzicht meer. Onder ~340px past er nog maar één naast elkaar en
       vouwt auto-fit ze vanzelf terug op één kolom. */
    .grid--stats { grid-template-columns: repeat(auto-fit, minmax(min(150px, 100%), 1fr)); gap: 12px; }
    .stat { padding: 14px 16px; }
    .stat__value { font-size: 24px; margin-top: 6px; }
    .stat__label { font-size: 12.5px; }
    .stat__hint { font-size: 12px; }

    .switcher__menu { max-width: calc(100vw - var(--pad-x) * 2); }
}

/* ---------- Aanraakschermen ----------
   Een muisaanwijzer landt op een pixel, een vinger op ongeveer een vierkante
   centimeter. Vandaar wat ruimer klikvlak waar er met de vinger gewerkt wordt. */

@media (pointer: coarse) {
    /* De ondergrens uit :root: geen enkel veld nog onder de 16px, en dus geen inzoomende
       telefoon meer zodra iemand een veld aanraakt. */
    :root { --field-min: 16px; }
    /* De filterbalk zet de hoogte van haar keuzelijst vast om gelijk te lopen met het
       invoerveld ernaast; met de grotere letter erin past die 37px niet meer. Allebei
       even hoog houden ze gelijk, en 40px is meteen een vinger waard. */
    .filters__field input,
    .filters__field select { height: 40px; }

    .btn { padding: 11px 16px; }
    .btn--sm { padding: 9px 12px; }
    .btn--icon { padding: 10px; }
    .icon-btn { width: 38px; height: 38px; }
    .nav__item { padding: 11px 12px; }
    .chip { padding: 7px 13px; }
    .switch { padding: 6px; }
    .q-panel__toggle { padding: 8px 4px; }
    .sidebar__foot .foot-btn { width: 38px; height: 38px; flex: 0 0 38px; }

    /* De greep is het enige waarmee gesleept wordt, en een vinger die ernaast landt sleept
       niets. Het icoontje blijft even groot; de negatieve marge houdt de kaart erbuiten
       precies zoals ze stond, zodat alleen het grijpvlak groeit. */
    .drag { padding: 10px; margin: -10px -4px -10px -10px; }
    .cf-item .drag { margin-right: -10px; }
}
