/* ============================================================================
   Vitalytics — gedeeld design-system (shell.css)
   ----------------------------------------------------------------------------
   Wordt geïmporteerd door zowel frontend/style.css als backend/style.css zodat
   de app-shell (sidebar, topbar, kaarten, charts, tabellen) één bron heeft.
   Merkkleuren afgeleid van het Vitalytics-logo: navy + soundwave blauw→teal→groen.
   ========================================================================== */

:root
{
	/* Merkkleuren */
	--vit-navy:      #0c2340;
	--vit-navy-800:  #0f2a4d;
	--vit-navy-700:  #16386a;
	--vit-blue:      #1f6fc4;
	--vit-teal:      #16a6a6;
	--vit-green:     #5cb85c;
	--vit-purple:    #7c5cbf;

	/* Neutraal */
	--vit-ink:       #1c2b33;
	--vit-muted:     #64727b;
	--vit-faint:     #93a1a9;
	--vit-bg:        #f4f6f8;
	--vit-card:      #ffffff;
	--vit-border:    #e4e9ee;
	--vit-border-2:  #eef2f5;

	/* Status */
	--vit-up:        #2e9e5b;
	--vit-down:      #d64545;
	--vit-warn:      #e08b1e;

	/* Sidebar */
	--vit-side-w:    244px;

	/* Vorm */
	--vit-radius:    14px;
	--vit-radius-sm: 10px;
	--vit-shadow:    0 1px 2px rgba(12,35,64,.04), 0 4px 16px rgba(12,35,64,.06);

	/* Actieknop-verloop: zelfde blauw->teal-verloop als de soundwave in het
	   logo (zie login-kaart), i.p.v. platte --vit-blue. */
	--vit-gradient:       linear-gradient(135deg, var(--vit-blue) 0%, var(--vit-teal) 100%);
	--vit-gradient-hover: linear-gradient(135deg, #2a7bd4 0%, #1bb8b8 100%);
}

/* ============================================================================
   Responsive — drie breakpoint-tiers, van breed naar smal. CSS kent geen
   variabelen in @media-condities, dus dit zijn platte px-waarden; elke plek
   die een tier gebruikt heeft een "TIER: ..."-commentaar erboven zodat
   een grens later op te zoeken/aan te passen is met één zoekactie op het
   getal. Volgorde van gedrag, breed -> smal:

   1. Desktop  (> 1100px) — huidige layout ongewijzigd: kaarten/panelen naast
      elkaar, labels links van het veld, sidebar altijd zichtbaar (het
      bestaande in-/uitklap-mechanisme via de hamburger blijft hier een
      breedte-toggle, geen overlay).
   2. TIER 1 — BP_STACK    = 1100px: kaarten/panelen die naast elkaar stonden
      (hoofdscherm-blokken, meetstation-lijst+formulier, hoofdstukken-nav,
      profiel-formuliergrid) gaan onder elkaar. Labels blijven links.
   3. TIER 2 — BP_LABELS   =  780px: labels verhuizen boven het veld i.p.v.
      ernaast, met extra ruimte tussen de rijen tot het volgende label.
   4. TIER 3 — BP_MOBILE   =  600px: sidebar verdwijnt automatisch (off-canvas)
      en schuift bij het openen via de hamburger als overlay (met verduisterde
      achtergrond) over de content heen i.p.v. de content aan de zijkant te
      duwen.
   ========================================================================== */

* { box-sizing: border-box; }

body
{
	margin: 0;
	font-family: "Segoe UI", system-ui, -apple-system, Roboto, "Helvetica Neue", Arial, sans-serif;
	color: var(--vit-ink);
	background: var(--vit-bg);
	line-height: 1.5;
	-webkit-font-smoothing: antialiased;
}

.material-icons { font-size: 20px; line-height: 1; vertical-align: middle; }

/* ------------------------------------------------------------ Select2 (algemeen)
   Feedback: de select2-doos berekent zijn breedte bij init uit de op dat
   moment gerenderde breedte van de originele <select> — in een tabel/grid-cel
   waarvan de kolombreedte nog niet is "gezet" (bv. de veld/operator/waarde-
   rijen van de relevantie-/validatie-builder) kan dat een te brede, vaste
   pixelwaarde vastleggen die over aangrenzende velden heen hangt. Geldt op
   meerdere plekken in de app, dus hier algemeen afgevangen i.p.v. per scherm:
   de dichte doos volgt altijd zijn eigen kolom/container (nooit breder dan
   100% daarvan); de open lijst mag wél breder worden dan de doos, anders
   lopen lange operator-labels ("is kleiner of gelijk aan") op meerdere
   regels uiteen (zie ook dropdownAutoWidth in frontend/script.js). */
.select2-container { max-width: 100%; box-sizing: border-box; }

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

.vit-shell { display: flex; min-height: 100vh; }

.vit-sidebar
{
	width: var(--vit-side-w);
	flex: 0 0 var(--vit-side-w);
	background: var(--vit-navy);
	color: #cdd7e4;
	display: flex;
	flex-direction: column;
	position: sticky;
	top: 0;
	height: 100vh;
}

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

/* -------------------------------------------------------------------- Logo */

.vit-logo
{
	display: inline-flex;
	align-items: center;
	text-decoration: none;
}
.vit-logo-img { display: block; width: auto; height: auto; }

/* Feedback: het logo boven de online vragenlijst (vragenlijst.post.php,
   stap 2 "invullen") rendert zonder deze regel op zijn natuurlijke
   PNG-formaat (véél groter dan de rest van de kaart) — .vit-online-card
   heeft, i.t.t. .vit-login (frontend/style.css, het inlog-/TFA-scherm),
   geen eigen logo-maat/centrering. Zelfde 172px + gecentreerde weergave
   als .vit-login hieronder overnemen, alleen hier scoped op
   .vit-online-card zodat de "link ongeldig"/"bedankt"-varianten (die geen
   logo tonen) ongemoeid blijven. */
.vit-online-card .vit-logo { display: flex; justify-content: center; margin-bottom: 14px; }
.vit-online-card .vit-logo-img { width: 172px; }

/* Witte variant op donkere achtergronden. */
.vit-logo--sidebar .vit-logo-img,
.vit-logo--public .vit-logo-img { filter: brightness(0) invert(1); }

/* Sidebar-brand */
.vit-side-brand
{
	display: block;
	padding: 22px 20px 18px;
	border-bottom: 1px solid rgba(255,255,255,.08);
	text-align: center;
	text-decoration: none;
	color: inherit;
}
.vit-side-brand .vit-logo-img { width: 150px; margin: 0 auto; }
.vit-side-sub
{
	display: block;
	margin: 10px 0 0;
	font-size: 11px;
	letter-spacing: .14em;
	text-transform: uppercase;
	color: #7f93ad;
	text-align: center;
}

/* ---------------------------------------------------------------- Sidebar-nav */

.vit-side-nav { padding: 14px 12px; flex: 1 1 auto; overflow-y: auto; }
.vit-side-nav ul { list-style: none; margin: 0; padding: 0; }
.vit-side-nav li { margin: 2px 0; }

/* Subtiele scheiding tussen Dashboard | Gebruik (Klanten..Rapportages) |
   Beheer (Templates..Instellingen). */
.vit-side-nav li.vit-nav-divider { height: 1px; margin: 10px 14px; padding: 0; background: rgba(255,255,255,.1); }

.vit-side-nav a
{
	display: flex;
	align-items: center;
	gap: 14px;
	padding: 11px 14px;
	border-radius: var(--vit-radius-sm);
	color: #c2cede;
	text-decoration: none;
	font-size: 15px;
	font-weight: 500;
	transition: background .15s, color .15s;
}
.vit-side-nav a .material-icons { font-size: 21px; color: #8aa0bd; transition: color .15s; }
.vit-side-nav a:hover { background: rgba(255,255,255,.06); color: #fff; }
.vit-side-nav a:hover .material-icons { color: #cdd7e4; }

.vit-side-nav a.is-active
{
	background: var(--vit-blue);
	color: #fff;
	box-shadow: 0 6px 16px rgba(31,111,196,.35);
}
.vit-side-nav a.is-active .material-icons { color: #fff; }

/* Sidebar-voet: AVG-badge + gebruiker */
.vit-side-foot
{
	border-top: 1px solid rgba(255,255,255,.08);
	padding: 16px 18px;
}
.vit-side-avg
{
	display: flex;
	align-items: center;
	gap: 9px;
	font-size: 12.5px;
	color: #9fb2c9;
}
.vit-side-avg .material-icons { font-size: 18px; color: var(--vit-green); }

.vit-side-user
{
	display: flex;
	align-items: center;
	gap: 10px;
	margin-top: 14px;
	padding-top: 14px;
	border-top: 1px solid rgba(255,255,255,.08);
	color: #e5ecf4;
}
.vit-side-user .material-icons.avatar { font-size: 34px; color: #6f86a6; }
.vit-side-user .naam { font-size: 14px; font-weight: 600; }
.vit-side-user .rol  { font-size: 11.5px; color: #8aa0bd; }
.vit-side-user .chev { margin-left: auto; color: #6f86a6; }
.vit-side-user a { color: inherit; text-decoration: none; display: flex; align-items: center; gap: 10px; width: 100%; }

/* -------------------------------------------------------------------- Topbar */

.vit-topbar
{
	display: flex;
	align-items: center;
	gap: 16px;
	height: 68px;
	padding: 0 26px;
	background: var(--vit-card);
	border-bottom: 1px solid var(--vit-border);
	/* Blijft in beeld bij het scrollen, net als de sidebar hiernaast (die
	   staat al op sticky). Sticky i.p.v. fixed: de balk blijft zo in de
	   flow van .vit-shell-main staan, dus hij houdt vanzelf de breedte van
	   de contentkolom naast de sidebar — bij fixed zou dat handmatig
	   uitgerekend moeten worden. De z-index houdt 'm boven de meescrollende
	   content, maar ruim onder de zwevende panelen (formule-autocomplete,
	   select2-dropdown, AVG-modal) die zelf hoger zitten. */
	position: sticky;
	top: 0;
	z-index: 20;
}

.vit-icon-btn
{
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 40px;
	height: 40px;
	border: 0;
	background: transparent;
	border-radius: 10px;
	color: var(--vit-muted);
	cursor: pointer;
	text-decoration: none;
	transition: background .15s, color .15s;
}
.vit-icon-btn:hover { background: var(--vit-bg); color: var(--vit-ink); }

.vit-topbar-title { font-size: 20px; font-weight: 700; color: var(--vit-ink); }
.vit-topbar-spacer { flex: 1 1 auto; }
.vit-topbar-actions { display: flex; align-items: center; gap: 4px; }

/* ------------------------------------------------------------------- Content */

.vit-content { padding: 26px; }
.vit-content > .vit-page-head { margin: 2px 4px 22px; }
.vit-page-head h1 { margin: 0; font-size: 24px; font-weight: 700; letter-spacing: -.01em; }
.vit-page-head p  { margin: 6px 0 0; color: var(--vit-muted); }

/* ------------------------------------------------------------------ KPI-cards */

.vit-kpi-grid
{
	display: grid;
	grid-template-columns: repeat(4, 1fr);
	gap: 20px;
	margin-bottom: 22px;
}

.vit-card
{
	background: var(--vit-card);
	/* Zonder expliciete color hier erft tekst in deze kaart de omgevende
	   body-kleur — onopgemerkt zolang die al donker is (het ingelogde
	   scherm), maar op de publieke (uitgelogde) pagina's is body.vit-public
	   juist bijna wit (feedback: "licht grijs op een witte achtergrond, dus
	   onleesbaar" — vit-online-card/.vit-formcard hierboven gebruiken deze
	   klasse, o.a. de online-vragenlijst). */
	color: var(--vit-ink);
	border: 1px solid var(--vit-border);
	border-radius: var(--vit-radius);
	box-shadow: var(--vit-shadow);
	/* Default kaart-padding. Kaarten met een specifiekere inhoud (tabel,
	   KPI-tegel, chart-panel) overschrijven dit hieronder via hun eigen
	   klasse. Dit is de enige plek waar formulier-kaarten (vit_card($form),
	   geen extra klasse) hun padding vandaan halen: het <form>-element zelf
	   krijgt van PortalFormWebForm's render() een inline
	   style="padding:0px" mee (WebForm/CKEditor-resize-mechanisme), dat
	   iedere padding-regel op .vit-formcard zelf zou verslaan. Zie ook
	   .vit-login hieronder, dat dezelfde reden heeft om de padding op de
	   buitenste div i.p.v. op <form class="vit-loginform"> te zetten. */
	padding: 22px 24px 24px;
	max-width: 100%;
}

/* Generieke waarschuwingsmelding buiten een formulier om (bv. een mislukte
   niet-veldgebonden actie — page()->addErrors() zelf wordt door de huidige
   frontend-layout nergens getoond, zie rapportages.post.php/deelnemers.
   post.php) — tot nu toe overal gebruikt zonder eigen CSS-regel, waardoor
   de melding als onopgemaakte platte tekst rendert. */
.vit-warning
{
	background: #fdf3e7;
	border: 1px solid var(--vit-warn);
	border-radius: var(--vit-radius-sm);
	color: var(--vit-ink);
	padding: 14px 18px;
	margin: 0 0 18px;
}
.vit-warning p { margin: 0; }

.vit-kpi { padding: 20px 20px 8px; position: relative; }

/* Tandwiel-/ververs-iconen op een score-tegel (feedback: alleen chart/tabel
   hadden 'm) — .vit-kpi heeft geen kopregel zoals .vit-panel-head, dus
   positioneert dit los rechtsboven op de kaart i.p.v. in een
   .vit-panel-head-icons-rij. */
.vit-kpi-icons { position: absolute; top: 14px; right: 14px; display: flex; align-items: center; gap: 8px; }
.vit-kpi-top { display: flex; align-items: flex-start; gap: 14px; }
.vit-kpi-icon
{
	width: 52px; height: 52px;
	border-radius: 14px;
	display: inline-flex; align-items: center; justify-content: center;
	color: #fff; flex: 0 0 auto;
}
.vit-kpi-icon .material-icons { font-size: 26px; }
.vit-kpi-icon.blue   { background: var(--vit-blue); }
.vit-kpi-icon.teal   { background: var(--vit-teal); }
.vit-kpi-icon.green  { background: var(--vit-green); }
.vit-kpi-icon.purple { background: var(--vit-purple); }

.vit-kpi-fig { display: flex; align-items: baseline; gap: 10px; }
.vit-kpi-value { font-size: 34px; font-weight: 800; letter-spacing: -.02em; line-height: 1; }
.vit-kpi-label { margin-top: 6px; color: var(--vit-muted); font-size: 14px; }

.vit-delta { display: inline-flex; align-items: center; gap: 2px; font-size: 14px; font-weight: 600; }
.vit-delta .material-icons { font-size: 16px; }
.vit-delta.up   { color: var(--vit-up); }
.vit-delta.down { color: var(--vit-down); }

.vit-kpi-spark { height: 46px; margin: 6px -6px -4px; }

/* --------------------------------------------------------------- Chart-panels */

.vit-panel-grid
{
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: 20px;
	margin-bottom: 22px;
}

.vit-panel { padding: 20px 22px 22px; }
.vit-panel-head
{
	display: flex; align-items: center; gap: 10px;
	margin-bottom: 6px;
}
.vit-panel-head .material-icons { color: var(--vit-muted); }
.vit-panel-head h2 { margin: 0; font-size: 16px; font-weight: 700; }
.vit-chart { width: 100%; height: 300px; }

/* --------------------------------------------------- Dynamisch dashboard
   docs/plans/dynamische-dashboard-module.md Chunk 3+: kopie van .vit-kpi-grid
   met grid-auto-flow: dense (componenten vullen gaten op i.p.v. altijd een
   nieuwe rij te starten) en expliciete grid-column/row (colspan/rowspan,
   inline via style= — geen aparte CSS-klasse per combinatie nodig). */

.vit-dashboard-tab { margin-bottom: 26px; }
.vit-dashboard-tab-titel { margin: 0 0 14px; font-size: 18px; font-weight: 700; }

.vit-dashboard-grid
{
	display: grid;
	grid-template-columns: repeat(4, 1fr);
	grid-auto-flow: dense;
	gap: 20px;
	/* --vit-dashboard-cols: door de responsive-tiers hieronder overschreven
	   (2 / 1) zodat een component se colspan (dashboard.view.php) zich daar
	   automatisch aan klemt i.p.v. een impliciete extra kolom te forceren —
	   zie de toelichting bij de eerste @media-override. */
	--vit-dashboard-cols: 4;
}

.vit-dashboard-item { min-width: 0; }

/* "Nieuwe regel starten" (dashboard.view.php) splitst het rooster in
   meerdere .vit-dashboard-grid-elementen i.p.v. één lege "break"-cel
   binnen hetzelfde rooster te forceren — zelfde 20px als de eigen `gap`
   hierboven, zodat de naad tussen twee roosters er niet anders uitziet dan
   een gewone rij-gap. */
.vit-dashboard-grid + .vit-dashboard-grid { margin-top: 20px; }
.vit-dashboard-item > .vit-card { height: 100%; }

/* Skeleton-placeholder (feedback dashboards: "1e pagina na inloggen moet
   vlot laden, terwijl juist die veel charts/tabellen kan bevatten") —
   dashboard.view.php rendert dit meteen i.p.v. een volledig component; het
   <script> onderaan die pagina vervangt elke skeleton door de echte HTML
   zodra dashboard.post.php se "component-laden"-endpoint 'm heeft
   opgehaald. min-height per componenttype benadert de echte content-hoogte
   (chart/tabel: rond .vit-chart se vaste 300px + kop/padding; score: rond
   .vit-kpi-icon se 52px + padding) om layout-shift bij het verschijnen van
   de echte content te beperken — geen bestaand precedent voor deze exacte
   waarden, een redelijke schatting. */
.vit-dashboard-skeleton { display: flex; align-items: center; justify-content: center; min-height: 110px; }
.vit-dashboard-skeleton-chart, .vit-dashboard-skeleton-tabel { min-height: 360px; }

.vit-dashboard-spinner
{
	width: 28px; height: 28px;
	border: 3px solid var(--vit-border);
	border-top-color: var(--vit-teal);
	border-radius: 50%;
	animation: vit-dashboard-spin .8s linear infinite;
}

@keyframes vit-dashboard-spin { to { transform: rotate(360deg); } }

/* Elk componenttype-deelsjabloon (uitleg/score/chart/tabel) hergebruikt
   .vit-panel-head voor titel + optionele toelichting-tooltip-icoon — dus dit
   geldt voor alle vier, niet alleen uitleg. */
.vit-dashboard-item .vit-panel-head { justify-content: space-between; }
.vit-dashboard-toelichting { font-size: 18px; cursor: help; }
.vit-dashboard-ondertitel { margin: -4px 0 10px; color: var(--vit-muted); font-size: 14px; }
.vit-dashboard-uitleg-html { font-size: 14px; line-height: 1.6; }

/* .vit-panel-head-icons: vaste tweede flex-kind naast de h2 (naast een
   optionele .vit-dashboard-toelichting), zodat .vit-panel-head's
   justify-content: space-between hierboven altijd titel-links/iconen-rechts
   oplevert, ongeacht hoeveel iconen er precies in staan. */
.vit-panel-head-icons { display: flex; align-items: center; gap: 8px; flex: 0 0 auto; }

/* Databron-popover (feedback: "?"-icoon rechtsboven op elke chart/tabel,
   zodat de getoonde cijfers te controleren zijn) — <details>/<summary> i.p.v.
   een eigen JS-toggle: native klik-open/dicht-gedrag, geen extra script
   nodig. */
/* display:flex (i.p.v. het standaard block) is de eigenlijke fix voor de
   24px-hoogte (feedback: "?"-icoon strookt niet vertikaal met het
   tandwiel) — <details> als block-element krijgt zijn hoogte van de
   grootste box op zijn "regel", en de kale witruimte tussen <details> en
   zijn <summary>-kind in de PHP-template rendert als een onzichtbare
   tekstnode met het standaard 16px/24px lettertype/regelhoogte, die de
   19px van de wél expliciet gestylede <summary> overstemt. Als flex-
   container telt die witruimte-tekstnode niet mee als flex-item, dus
   <details> krimpt terug tot exact de hoogte van zijn <summary>. De
   los-gepositioneerde .vit-dashboard-herkomst-body (hieronder,
   position:absolute) blijft ongemoeid: een absoluut gepositioneerd
   flex-kind doet niet mee aan de flex-layout. */
.vit-dashboard-herkomst { position: relative; display: flex; align-items: center; }
.vit-dashboard-herkomst > summary
{
	list-style: none;
	font-size: 18px;
	/* feedback: het icoon viel weg tegen de andere .material-icons-iconen
	   ernaast (die allemaal --vit-muted zijn) — een eigen kleur maakt het
	   duidelijk aanklikbaar i.p.v. decoratief grijs. */
	color: var(--vit-blue);
	cursor: pointer;
}
.vit-dashboard-herkomst > summary::-webkit-details-marker { display: none; }
.vit-dashboard-herkomst[open] > summary { color: var(--vit-ink); }

/* Tandwiel-deeplink naast het "?"-icoon (feedback: alleen zichtbaar met
   dashboard_beheren-recht) — zelfde muted-tot-hover-conventie als
   .vit-icon-btn, maar als kaal .material-icons-icoon i.p.v. een cirkel-
   achtergrond, zodat het naast .vit-dashboard-herkomst's "?" past. */
.vit-dashboard-beheren-link { font-size: 18px; color: var(--vit-muted); text-decoration: none; cursor: pointer; }
.vit-dashboard-beheren-link:hover { color: var(--vit-ink); }

/* Ververs-knop naast het tandwiel (feedback: data opnieuw ophalen zonder
   volledige paginaherlaad) — <button> i.p.v. <a href="#">, want dit
   navigeert nergens naartoe; reset daarom expliciet de browser-standaard
   knopopmaak naar dezelfde kale stijl als .vit-dashboard-beheren-link
   ernaast. Bewust GEEN font-family hier: de knop draagt ook de
   .material-icons-klasse (Google se eigen stylesheet, font-family:
   'Material Icons'), en een font-family:inherit hier zou die op gelijke
   specificiteit overschrijven — bevestigd live: de ligatuurtekst
   "autorenew" rendert dan als letterlijke tekst i.p.v. het icoon. */
.vit-dashboard-refresh-link
{
	font-size: 18px; color: var(--vit-muted); cursor: pointer;
	border: 0; background: none; padding: 0; margin: 0;
}
.vit-dashboard-refresh-link:hover { color: var(--vit-ink); }
.vit-dashboard-herkomst-body
{
	position: absolute; right: 0; top: calc(100% + 8px); z-index: 30;
	width: 380px; max-width: 85vw;
	max-height: 70vh;
	overflow-y: auto;
	background: var(--vit-card);
	border: 1px solid var(--vit-border);
	border-radius: var(--vit-radius-sm);
	box-shadow: 0 8px 24px rgba(0,0,0,.14);
	padding: 12px 14px;
	font-size: 13px; font-weight: 400; line-height: 1.5; color: var(--vit-ink);
	cursor: auto;
}
.vit-dashboard-herkomst-body dt { font-weight: 600; margin-top: 8px; }
.vit-dashboard-herkomst-body dt:first-child { margin-top: 0; }
.vit-dashboard-herkomst-body dd { margin: 2px 0 0; color: var(--vit-muted); }

/* Deelnemerslijst (feedback dashboards punt 2): platte, ingesprongen tekst
   i.p.v. nóg een tabel — dit is een controlemiddel voor segmentatie/filters,
   geen scherm om op te lezen. */
.vit-dashboard-herkomst-deelnemers
{
	margin: 10px 0 0;
	padding-top: 8px;
	border-top: 1px solid var(--vit-border);
	font-family: ui-monospace, "SF Mono", Consolas, monospace;
	font-size: 12px;
	line-height: 1.5;
	color: var(--vit-ink);
	white-space: pre-wrap;
	word-break: break-word;
}

/* Tabel-variant met filters (feedback dashboards punt 3): elke deelnemer met
   een groen vinkje/rood kruis (voldoet aan alle filters, ja/nee) i.p.v.
   platte tekst — VitDashboardData::formatteerDeelnemerDetailMetFilters(). */
.vit-dashboard-herkomst-deelnemers-filters { white-space: normal; }
.vit-dashboard-filter-rij { display: flex; align-items: center; gap: 6px; margin-top: 10px; }
.vit-dashboard-filter-rij:first-child { margin-top: 0; }
.vit-dashboard-filter-status .material-icons { font-size: 16px; }
.vit-dashboard-filter-status.is-ja .material-icons  { color: var(--vit-up); }
.vit-dashboard-filter-status.is-nee .material-icons { color: var(--vit-down); }
.vit-dashboard-filter-naam { font-weight: 600; }
.vit-dashboard-filter-detail { margin: 2px 0 0 22px; color: var(--vit-muted); }

.vit-muted { color: var(--vit-muted); }

/* Chunk 7-polish: echte tabbladen i.p.v. alles onder elkaar (puur
   presentationeel — geen datamodelwijziging). De "bekijk als organisatie"-/
   evenement-selects zelf hergebruiken .vit-filter-bar (verderop in dit
   bestand, feedback: dezelfde kale-select2-zonder-label-stijl als de
   filterbalken elders) i.p.v. een eigen klasse. */
.vit-dashboard-filterrow select { min-width: 220px; }
/* Actieve tab heeft een eigen evenement-select (programmakoppeling): de
   dashboardbrede evenement-select (en zijn select2-container) verbergen. */
.vit-dashboard-filterrow.is-tab-gekoppeld #vit-dashboard-evenement-select,
.vit-dashboard-filterrow.is-tab-gekoppeld #vit-dashboard-evenement-select + .select2-container { display: none; }
.vit-dashboard-tab-filterrow { margin-bottom: 16px; }
/* Evenement-select per tab: volle breedte (select2 zet inline een vaste breedte). */
.vit-dashboard-tab-filterrow select { width: 100%; }
.vit-dashboard-tab-filterrow .select2-container { width: 100% !important; flex: 1 1 100%; }

.vit-dashboard-tabnav
{
	display: flex;
	gap: 4px;
	margin: 0 4px 20px;
	border-bottom: 1px solid var(--vit-border);
	overflow-x: auto;
}
.vit-dashboard-tabbtn
{
	appearance: none;
	border: 0;
	background: transparent;
	padding: 10px 16px;
	font-size: 14px;
	font-weight: 600;
	color: var(--vit-muted);
	cursor: pointer;
	border-bottom: 2px solid transparent;
	white-space: nowrap;
}
.vit-dashboard-tabbtn:hover { color: var(--vit-ink); }
.vit-dashboard-tabbtn.is-active { color: var(--vit-teal); border-bottom-color: var(--vit-teal); }

/* ------------------------------------------------------- Template-veldenboom
   Ongestyled vendored component (forms-lib PortalFormFieldTable, templates.
   post.php) — eigen `frm_field_*`-klassen (underscore), los van de runtime
   `.frm-field`-klassen (dash) uit forms/templates/forms/forms.css. Zelfde
   visuele taal overgenomen (teal accentkleur, zachte kaartranden, chapter als
   omkaderde container), maar met de Vitalytics-designtokens i.p.v. forms.css'
   eigen kleuren, zodat dit naast de rest van de app niet uit de toon valt. */

.frm_field_tree { font-size: 14px; color: var(--vit-ink); }
.frm_field_tree.is-saving { opacity: .5; pointer-events: none; }

.frm_field_children { min-height: 4px; }
.frm_field_children[data-parent-id="0"] { display: flex; flex-direction: column; gap: 8px; }

.frm_field_node { margin-bottom: 0; }
.frm_field_node.is-chapter
{
	border: 1px solid var(--vit-border);
	border-radius: var(--vit-radius-sm);
	background: #fafbfc;
	padding: 4px;
}
.frm_field_node.is-chapter > .frm_field_children { padding: 4px 4px 4px 22px; display: flex; flex-direction: column; gap: 6px; }
.frm_field_node.is-chapter > .frm_field_children:empty { padding: 0; }

.frm_field_row
{
	display: flex; align-items: center; gap: 10px;
	padding: 9px 12px;
	border: 1px solid var(--vit-border);
	border-radius: var(--vit-radius-sm);
	background: var(--vit-card);
	cursor: pointer;
	transition: border-color .1s, box-shadow .1s;
}
.frm_field_row:hover { border-color: var(--vit-teal); box-shadow: 0 0 0 2px rgba(22,166,166,.12); }
.frm_field_node.is-chapter > .frm_field_row { background: transparent; border-color: transparent; font-weight: 700; color: var(--vit-navy-700); }
.frm_field_node.is-chapter > .frm_field_row:hover { border-color: var(--vit-teal); background: var(--vit-card); }

.frm_field_grip { color: var(--vit-faint); cursor: grab; flex: 0 0 auto; }
.frm_field_grip:active { cursor: grabbing; }

.frm_field_seq { flex: 0 0 auto; min-width: 28px; color: var(--vit-muted); font-variant-numeric: tabular-nums; font-size: 13px; }
.frm_field_title { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.frm_field_key { flex: 0 0 auto; color: var(--vit-muted); font-family: ui-monospace, "SF Mono", Consolas, monospace; font-size: 12px; }
.frm_field_type
{
	flex: 0 0 auto;
	padding: 2px 8px;
	border-radius: 999px;
	background: var(--vit-border-2);
	color: var(--vit-muted);
	font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: .03em;
}

.frm_field_placeholder
{
	border: 1px dashed var(--vit-teal);
	border-radius: var(--vit-radius-sm);
	background: rgba(22,166,166,.08);
	margin-bottom: 0;
}

.frm_field_addbar { margin-top: 10px; }
.frm_field_addbtn
{
	display: inline-flex; align-items: center; gap: 6px;
	padding: 7px 14px;
	border: 1px dashed var(--vit-border);
	border-radius: var(--vit-radius-sm);
	color: var(--vit-teal);
	font-size: 13px; font-weight: 600;
	text-decoration: none;
	transition: border-color .1s, background-color .1s;
}
.frm_field_addbtn:hover { border-color: var(--vit-teal); background: rgba(22,166,166,.06); }

/* --------------------------------------------- Dashboardbeheer-boom (Instellingen)
   Zelfde slepen/inspringen-taal als .frm_field_* hierboven, maar losse
   `vit-dbrd-*`-klassen: DashboardBeheerBoom (dashboardmove.post.php) is geen
   forms-lib-component en deelt bewust geen JS-globale/CSS-naamruimte met de
   veldenboom hierboven. */

.vit-dbrd-tree { font-size: 14px; color: var(--vit-ink); }
.vit-dbrd-tree.is-saving { opacity: .5; pointer-events: none; }

.vit-dbrd-tabs { display: flex; flex-direction: column; gap: 10px; }

.vit-dbrd-tab-node
{
	border: 1px solid var(--vit-border);
	border-radius: var(--vit-radius-sm);
	background: #fafbfc;
	padding: 6px;
}

.vit-dbrd-tab-row,
.vit-dbrd-comp-row
{
	display: flex; align-items: center; gap: 10px;
	padding: 9px 12px;
	border: 1px solid var(--vit-border);
	border-radius: var(--vit-radius-sm);
	background: var(--vit-card);
	transition: border-color .1s, box-shadow .1s;
	cursor: pointer;
}

.vit-dbrd-tab-row { font-weight: 700; color: var(--vit-navy-700); }
.vit-dbrd-tab-row:hover,
.vit-dbrd-comp-row:hover { border-color: var(--vit-teal); box-shadow: 0 0 0 2px rgba(22,166,166,.12); }

/* De dupliceren-knop moet een POST-form zijn (CSRF-token, zie
   dashboardbeheerboom.class.php) maar mag de flex-rij van .vit-dbrd-comp-row
   niet verstoren — "display:contents" laat de <form> zelf geen eigen box
   nemen, zijn <button> wordt zo gewoon een flex-item van de rij. */
.vit-dbrd-inline-form { display: contents; }

/* .vit-dbrd-grip (cursor:grab) en .vit-icon-btn (cursor:pointer, elders
   gedefinieerd) overschrijven de van de rij geërfde cursor: pointer al
   met hun eigen, specifiekere regel. */
.vit-dbrd-grip { color: var(--vit-faint); cursor: grab; flex: 0 0 auto; }
.vit-dbrd-grip:active { cursor: grabbing; }

.vit-dbrd-tab-naam,
.vit-dbrd-comp-titel { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.vit-dbrd-tab-org,
.vit-dbrd-comp-type
{
	flex: 0 0 auto;
	padding: 2px 8px;
	border-radius: 999px;
	background: var(--vit-border-2);
	color: var(--vit-muted);
	font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: .03em;
}

.vit-dbrd-comp-children { padding: 6px 4px 4px 22px; display: flex; flex-direction: column; gap: 6px; min-height: 4px; }
.vit-dbrd-comp-children:empty { padding: 0; min-height: 0; }

.vit-dbrd-tab-placeholder,
.vit-dbrd-comp-placeholder
{
	border: 1px dashed var(--vit-teal);
	border-radius: var(--vit-radius-sm);
	background: rgba(22,166,166,.08);
}

.vit-dbrd-addbar { margin-top: 12px; display: flex; gap: 10px; flex-wrap: wrap; }

/* ---------------------------------------------------------------- Filterbalk */

.vit-filter-bar
{
	display: flex;
	align-items: center;
	gap: 10px;
	margin-bottom: 16px;
}
.vit-filter-text,
.vit-filter-select
{
	height: 40px;
	box-sizing: border-box;
	padding: 0 12px;
	border: 1px solid var(--vit-border);
	border-radius: 10px;
	font-size: 14px;
	font-family: inherit;
	background: #fff;
	color: var(--vit-ink);
}
.vit-filter-text { flex: 1 1 240px; max-width: 320px; }
.vit-filter-select { flex: 0 0 auto; min-width: 180px; cursor: pointer; }
.vit-filter-text:focus, .vit-filter-select:focus
{ outline: none; border-color: var(--vit-blue); box-shadow: 0 0 0 3px rgba(31,111,196,.15); }
.vit-filter-submit
{
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 40px;
	height: 40px;
	box-sizing: border-box;
	flex: 0 0 auto;
	border: 1px solid var(--vit-border);
	border-radius: 10px;
	background: #fff;
	color: var(--vit-muted);
	cursor: pointer;
	transition: background .15s, color .15s, border-color .15s;
}
.vit-filter-submit:hover { background: var(--vit-bg); color: var(--vit-blue); border-color: var(--vit-blue); }
/* Filterbalk's <select> wordt door select2 vervangen (frontend/script.js) —
   diens eigen vaste hoogte (frontend/style.css, 42px) wijkt af van de 40px
   hierboven, dus binnen de filterbalk expliciet gelijktrekken zodat
   zoekveld/select/zoekknop precies even hoog zijn. */
.vit-filter-bar .select2-container--default .select2-selection--single
{ height: 40px; }

@media (max-width: 640px)
{
	.vit-filter-bar { flex-wrap: wrap; }
	.vit-filter-text { flex-basis: 100%; max-width: none; }
}

/* vit_filter_bar()'s "date"-veldtype (bv. historie.post.php's van/tot-
   periodefilter) — zelfde regel/knop als de rest van de filterbalk
   (feedback: alle zoekvelden op één regel, één zoekknop). */
.vit-filter-date-label
{
	display: flex; align-items: center; gap: 6px;
	font-size: 13px; color: var(--vit-muted);
}
.vit-filter-date
{
	height: 40px; box-sizing: border-box; padding: 0 10px;
	border: 1px solid var(--vit-border); border-radius: 10px;
	font-size: 14px; font-family: inherit; color: var(--vit-ink);
}

/* --------------------------------------------------------------------- Tabel */

.vit-table-card { padding: 6px; overflow-x: auto; }
/* Feedback: de titel van een tabel-component stond (via .vit-table-card's
   eigen kleine 6px-padding hierboven, nodig zodat de tabel zelf edge-to-edge
   tot de kaartrand loopt) visueel veel dichter tegen de kaartrand dan bij
   een chart/uitleg-component (.vit-panel/.vit-card se eigen 20-22px-padding,
   waar .vit-panel-head zelf geen aparte padding heeft). Extra padding hier
   (14px = 20-6, 16px = 22-6) trekt titel én ondertitel gelijk, zonder de
   tabel/paginering zelf van de kaartrand af te duwen. De ondertitel-<p>
   staat als sibling naast .vit-panel-head (niet erin) en heeft dus zijn
   eigen regel nodig — anders blijft alleen de titelrij gelijkgetrokken. */
.vit-table-card .vit-panel-head { padding: 14px 16px 0; }
.vit-table-card .vit-dashboard-ondertitel { padding: 0 16px; }
.vit-table-head
{
	display: flex; align-items: center; gap: 10px;
	padding: 16px 20px 10px;
}
.vit-table-head .material-icons { color: var(--vit-muted); }
.vit-table-head h2 { margin: 0; font-size: 16px; font-weight: 700; }

table.vit-table { width: 100%; border-collapse: collapse; font-size: 14px; }
table.vit-table thead th
{
	text-align: left;
	font-weight: 600;
	font-size: 12.5px;
	letter-spacing: .02em;
	color: #fff;
	background: var(--vit-navy);
	padding: 12px 16px;
	white-space: nowrap;
}
table.vit-table thead th:first-child { border-top-left-radius: 10px; border-bottom-left-radius: 10px; }
table.vit-table thead th:last-child  { border-top-right-radius: 10px; border-bottom-right-radius: 10px; }
/* Tabelsortering (klantwens, script.js): elke kolomkop is klikbaar, met een
   leeg (maar altijd aanwezig, voor stabiele kop-hoogte/-breedte) pijl-icoon
   dat alleen tekst krijgt in de actief gesorteerde kolom. */
table.vit-table thead th.vit-sortable { cursor: pointer; user-select: none; }
table.vit-table thead th .vit-sort-icoon { font-size: 15px; margin-left: 3px; vertical-align: -3px; }
/* Feedback: geen enters/wordwrap in cellen op smallere schermen — de tabel
   mag breder worden dan zijn kaart, .vit-table-card (hierboven) heeft daar al
   overflow-x: auto voor. table-layout blijft "auto" (default): met
   white-space: nowrap op elke cel kan de auto-layout de kolombreedtes niet
   meer laten krimpen tot onder hun inhoud, dus "width: 100%" hierboven werkt
   dan als ondergrens i.p.v. een harde breedte — de tabel groeit vanzelf
   breder dan de kaart zodra de inhoud dat vereist. */
table.vit-table tbody td { padding: 13px 16px; border-bottom: 1px solid var(--vit-border-2); white-space: nowrap; }
table.vit-table tbody tr:hover { background: #fafcfd; }
table.vit-table .num { font-variant-numeric: tabular-nums; }
table.vit-table .gemeente { display: flex; align-items: center; gap: 10px; font-weight: 600; }
table.vit-table .gemeente .material-icons { color: var(--vit-faint); font-size: 20px; }

.vit-cell-delta { font-weight: 700; }
.vit-cell-delta.up   { color: var(--vit-up); }
.vit-cell-delta.down { color: var(--vit-down); }

.vit-trend { display: inline-flex; align-items: center; gap: 3px; font-weight: 600; }
.vit-trend .material-icons { font-size: 16px; }
.vit-trend.up   { color: var(--vit-up); }
.vit-trend.down { color: var(--vit-down); }

/* font-weight heeft geen effect op Material Icons-ligaturen (vaste-gewicht
   iconfont) — de stroke/schaduw hieronder geeft het kruisje toch wat meer
   "body" zonder een tweede (variabele) iconfont te moeten laden. */
.vit-icon-remove
{
	color: var(--vit-down);
	-webkit-text-stroke: .6px currentColor;
	text-shadow: 0 0 .3px currentColor;
}

.vit-perc { display: flex; align-items: center; gap: 10px; min-width: 150px; }
.vit-perc .bar { flex: 1 1 auto; height: 8px; border-radius: 5px; background: var(--vit-border); overflow: hidden; }
.vit-perc .bar > span { display: block; height: 100%; border-radius: 5px; background: var(--vit-blue); }
.vit-perc .lbl { color: var(--vit-muted); font-size: 12.5px; min-width: 30px; }

/* Tabelpaginering (klantwens, script.js) — client-side, dus geen eigen
   PHP-tegenhanger; deze balk wordt door JS na het tabel-element ingevoegd,
   binnen dezelfde .vit-table-card. */
.vit-pagination
{
	display: flex; align-items: center; flex-wrap: wrap; gap: 10px;
	padding: 12px 14px 6px; border-top: 1px solid var(--vit-border);
	margin-top: 6px; font-size: 13.5px; color: var(--vit-muted);
}
.vit-pagination-info { margin-right: auto; }
.vit-pagination-nav, .vit-pagination-page
{
	display: inline-flex; align-items: center; justify-content: center;
	min-width: 30px; height: 30px; padding: 0 6px;
	border: 1px solid var(--vit-border); border-radius: 8px;
	background: #fff; color: var(--vit-ink); cursor: pointer;
	font-size: 13px; line-height: 1;
}
.vit-pagination-nav .material-icons { font-size: 18px; }
.vit-pagination-nav:disabled { color: var(--vit-faint); cursor: default; opacity: .6; }
.vit-pagination-page:hover { border-color: var(--vit-blue); }
.vit-pagination-page.is-active
{
	background: var(--vit-blue); border-color: var(--vit-blue); color: #fff;
	font-weight: 600; cursor: default;
}
.vit-pagination-pages { display: flex; gap: 4px; flex-wrap: wrap; }
.vit-pagination-size-label { display: inline-flex; align-items: center; gap: 6px; }
.vit-pagination-size
{
	height: 30px; padding: 0 8px; border: 1px solid var(--vit-border);
	border-radius: 8px; font-size: 13px; font-family: inherit; color: var(--vit-ink);
}

/* ----------------------------------------------------------------- Meetstation
   Punt 6/8: "oefenzaal"-achtig scherm (fysiosoft/SportZeeland-patroon) —
   links de deelnemerslijst, rechts het meetformulier van de gekozen
   deelnemer, beide altijd zichtbaar in één scherm. */

.vit-meetstation { display: flex; gap: 20px; align-items: flex-start; }
.vit-meetstation-list { flex: 0 0 300px; max-width: none; padding: 10px; }
.vit-meetstation-form { flex: 1 1 auto; min-width: 0; max-width: none; }

/* Feedback: groepskeuze (zonder groep_id op de testsessie) als select2-
   dropdown bovenaan i.p.v. een eigen kolom naast de deelnemerslijst — zelfde
   opzet als .vit-dashboard-orgfilter. */
.vit-meetstation-groepfilter { display: flex; align-items: center; gap: 10px; margin: 0 0 18px; }
.vit-meetstation-groepfilter label { font-size: 13px; font-weight: 500; color: var(--vit-muted); }
.vit-meetstation-groepfilter select { min-width: 220px; }

/* Sjablonen met hoofdstukken (forms lib mode=chapters, zie meetstation.post.php):
   de forms lib rendert .frm-chapter-nav en .frm-chapter-body al als losse
   DOM-nodes in #vit-meetformulier — hier tot een eigen hoofdstukken-kolom
   naast de vragen gemaakt. Sjablonen zonder hoofdstukken krijgen de
   .frm-mode-chapters class nooit (forms lib valt dan terug op de vlakke
   "all"-weergave), dus deze regels raken die niet. Bewust op dezelfde
   BP_STACK-grens (1100px, zie tier-overzicht bovenaan dit bestand) als
   hieronder: onder die grens (waar de deelnemerslijst al boven het
   formulier stapelt) valt de nav terug op de ingebouwde horizontale
   pil-strip van forms.css — geen extra stapel-CSS nodig. */
/* TIER: BP_STACK (desktop-kant, min-width) */
@media (min-width: 1101px)
{
	#vit-meetformulier.frm-mode-chapters { display: flex; flex-wrap: wrap; gap: 20px; align-items: flex-start; }
	.frm-mode-chapters .frm-chapter-nav
	{
		flex: 0 0 210px;
		display: flex;
		flex-direction: column;
		gap: 4px;
		margin-bottom: 0;
		padding-bottom: 0;
		border-bottom: none;
	}
	.frm-mode-chapters .frm-chapter-body { flex: 1 1 480px; min-width: 0; }
	/* .frm-save-bar wordt door forms.js na de nav/body ook rechtstreeks in
	   #vit-meetformulier gezet — zonder deze regel zou hij als 3e kolom
	   naast de hoofdstukken-nav belanden i.p.v. eronder. flex-basis:100%
	   + de flex-wrap hierboven dwingt 'm naar een eigen volledige regel. */
	.frm-mode-chapters .frm-save-bar { flex: 1 1 100%; }
}

/* Hoofdstukken-pillen herstijlen naar dezelfde visuele taal als de
   deelnemerslijst hiernaast (.vit-meetstation-item): forms.css' eigen
   opmaak (kleiner font, volledige pil-vorm, vlakke actiefkleur, dun
   unicode-vinkje) valt duidelijk uit de toon naast de rest van de app.
   Alléén hier overschreven — de gevendorde forms.css/forms.js blijven
   ongemoeid, dus andere forms-lib-consumers merken hier niets van.
   #vit-meetformulier.frm-mode-chapters geeft, net als hierboven, genoeg
   specificiteit om forms.css (dat ná deze stylesheet laadt) zonder
   !important te overrulen. Een lichte achtergrondtint op de nav-kolom
   (i.p.v. wit, zoals .frm-chapter-body) laat hem als een eigen kolom
   naast de vragen ogen in plaats van als een sub-balk erbovenop.
   Zelfde regels ook voor #vit-vragenlijst-formulier (de publieke
   online-vragenlijst, vragenlijst.post.php): die deelt hetzelfde
   forms.js-hoofdstukken-mechanisme maar viel hier nog buiten de selector,
   waardoor de actieve pil er grijs-op-wit (onleesbaar) i.p.v. met gradient
   getoond werd (feedback). */
#vit-meetformulier.frm-mode-chapters .frm-chapter-nav,
#vit-vragenlijst-formulier.frm-mode-chapters .frm-chapter-nav
{
	background: var(--vit-bg);
	border-radius: var(--vit-radius);
	padding: 10px;
}
#vit-meetformulier.frm-mode-chapters .frm-chapter-nav-item,
#vit-vragenlijst-formulier.frm-mode-chapters .frm-chapter-nav-item
{
	padding: 12px 14px;
	border: 0;
	border-radius: 10px;
	/* 14px, gelijk aan table.vit-table (klantwens: overal dezelfde
	   fontgrootte — was 16px). */
	font-size: 14px;
	color: var(--vit-ink);
	background-color: #fff;
	transition: background .15s, color .15s;
}
/* forms.css' eigen .frm-label (hoofdstuk-/vraagtitel, bv. "2.1
   Knijpkracht") staat op 13px — kleiner dan de 14px basisgrootte hierboven
   en elders in de app (klantwens: overal dezelfde fontgrootte). Alléén
   hier overschreven (#vit-meetformulier/#vit-vragenlijst-formulier), net
   als de chapter-nav-item-opmaak hierboven — de gevendorde forms.css zelf
   blijft ongemoeid. */
#vit-meetformulier .frm-label, #vit-vragenlijst-formulier .frm-label { font-size: 14px; }
#vit-meetformulier.frm-mode-chapters .frm-chapter-nav-item:hover,
#vit-vragenlijst-formulier.frm-mode-chapters .frm-chapter-nav-item:hover { background: var(--vit-border); }
#vit-meetformulier.frm-mode-chapters .frm-chapter-nav-item.is-active,
#vit-vragenlijst-formulier.frm-mode-chapters .frm-chapter-nav-item.is-active { background: var(--vit-gradient); color: #fff; }
#vit-meetformulier.frm-mode-chapters .frm-chapter-nav-item.is-complete,
#vit-vragenlijst-formulier.frm-mode-chapters .frm-chapter-nav-item.is-complete { padding-right: 34px; position: relative; }
#vit-meetformulier.frm-mode-chapters .frm-chapter-nav-item.is-complete::after,
#vit-vragenlijst-formulier.frm-mode-chapters .frm-chapter-nav-item.is-complete::after
{
	position: absolute;
	top: 50%; right: 10px;
	transform: translateY(-50%);
	font-family: "Material Icons";
	content: "check_circle";
	font-size: 18px;
	line-height: 1;
	color: var(--vit-up);
}
#vit-meetformulier.frm-mode-chapters .frm-chapter-nav-item.is-active.is-complete::after,
#vit-vragenlijst-formulier.frm-mode-chapters .frm-chapter-nav-item.is-active.is-complete::after { color: #d9fce6; }

/* Klein beetje extra witruimte tussen de hoofdstuk-balk en het (lichtgrijze)
   vragenblok eronder in de publieke online-vragenlijst (feedback) — daar
   valt de nav altijd terug op forms.css' vlakke pil-strip-weergave (de
   2-koloms-indeling hierboven is bewust #vit-meetformulier-only: op de
   smallere .vit-online-card-breedte zou de zijkolom niet passen). */
#vit-vragenlijst-formulier .frm-chapter-nav { margin-bottom: 28px; }

/* Feedback: "Opslaan" (het ingebouwde autosave-statusicoon van forms.js)
   en "Vragenlijst insturen" (vragenlijst.post.php, buiten forms.js om
   toegevoegd) naast elkaar gecentreerd i.p.v. onder elkaar/links
   uitgelijnd — de insturen-knop wordt door de inline script in
   vragenlijst.post.php in dezelfde .frm-save-bar geplaatst als de
   opslaan-knop, .frm-save-bar is al een flex-rij (forms.css), hier alleen
   de centrering + kleine witruimte ertussen toegevoegd. */
#vit-vragenlijst-formulier .frm-save-bar { justify-content: center; gap: 12px; }

.vit-meetstation-items { max-height: 74vh; overflow-y: auto; }
.vit-meetstation-item
{
	display: flex;
	align-items: center;
	gap: 10px;
	padding: 12px 14px;
	border-radius: 10px;
	text-decoration: none;
	color: var(--vit-ink);
	/* 14px, gelijk aan table.vit-table (klantwens: overal dezelfde
	   fontgrootte — anders viel de naam terug op de browser-default van
	   16px, .volgnummer/.groep waren al wel expliciet gezet). */
	font-size: 14px;
	transition: background .15s, color .15s;
}
.vit-meetstation-item:hover { background: var(--vit-bg); }
.vit-meetstation-item.is-active { background: var(--vit-gradient); color: #fff; }
.vit-meetstation-item .volgnummer { flex: 0 0 auto; color: var(--vit-faint); font-variant-numeric: tabular-nums; font-size: 12.5px; }
.vit-meetstation-item.is-active .volgnummer { color: rgba(255,255,255,.7); }
.vit-meetstation-item .naam { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* margin-left:auto i.p.v. justify-content:space-between op de rij zelf,
   zodat het AVG-schild (vóór .naam) niet ook wordt meegenomen in de
   verdeling — alleen .vit-meetstation-voortgang hoort tegen de
   rechterkant te drukken. Feedback: dit was eerder de groepsnaam
   (.groep), nu de invulstatus (grijs/oranje/groen) — de is-kleur-*
   kleuren hieronder verzorgen de icoonkleur. */
.vit-meetstation-item .vit-meetstation-voortgang { flex: 0 0 auto; margin-left: auto; display: flex; align-items: center; }
.vit-meetstation-item .vit-meetstation-voortgang .material-icons { font-size: 18px; }

.vit-meetstation-naam
{
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: 10px;
	margin-bottom: 18px;
	padding-bottom: 14px;
	border-bottom: 1px solid var(--vit-border-2);
}
/* Was ".material-icons" (elke material-icon in de kop), waardoor het
   print-icoon (ook .material-icons, in .vit-meetstation-toolbar hieronder)
   via deze regel z'n eigen .vit-print-icon-kleur overstemde (gelijke
   specificiteit, maar twee klassen i.p.v. één) en dus feloranje/blauw bleef
   i.p.v. subtiel grijs (feedback). Voortaan alleen het naam-icoontje zelf. */
.vit-meetstation-naam .vit-meetstation-person-icon { font-size: 28px; color: var(--vit-blue); }
.vit-meetstation-naam h2 { margin: 0; font-size: 18px; }
.vit-meetstation-naam .groep { color: var(--vit-muted); font-weight: 400; font-size: 14px; }
.vit-meetstation-naam .volgnummer { color: var(--vit-faint); font-weight: 400; font-size: 14px; font-variant-numeric: tabular-nums; }

/* Toolbar rechtsboven in de meetstation-kop (feedback): historie-icoon,
   print-icoon en de weergave-pill samen, rechts uitgelijnd naast de naam
   via margin-left:auto i.p.v. los achter de naam resp. los onder de kop. */
.vit-meetstation-toolbar { display: flex; align-items: center; gap: 12px; margin-left: auto; }

/* Feedback: compacte tweekleurige pill (teal/wit = actief, lichtgrijs/
   donkergrijs = inactief) i.p.v. twee losse ronde knoppen — één grijze
   buitenpil met een kleinere teal-pil erin voor de actieve keuze. */
.vit-meetstation-weergave { display: flex; gap: 2px; margin: 0; padding: 3px; border-radius: 999px; background: var(--vit-bg); }
.vit-meetstation-weergave a
{
	padding: 5px 12px;
	border-radius: 999px;
	font-size: 12.5px;
	font-weight: 600;
	color: var(--vit-muted);
	text-decoration: none;
}
.vit-meetstation-weergave a:hover { color: var(--vit-ink); }
.vit-meetstation-weergave a.is-active { color: #fff; background: var(--vit-teal); }

/* Pogingen-veldtype (vitalytics-forms.js): N invoervelden + read-only
   resultaat op een rij — zonder deze regel staan ze kris-kras tegen
   elkaar (geen spatie tussen de door jQuery aan elkaar geplakte
   elementen). Zelfde recept als forms.css' eigen .frm-number-row
   (inline-flex + gap), .frm-pogingen-output krijgt de "dit is een
   berekend/afgeleid resultaat, geen los invoerveld"-stijl van
   forms.css' .frm-calc-output. */
.frm-pogingen-row { display: inline-flex; align-items: center; flex-wrap: wrap; gap: 6px; }
/* De poging-invoervelden zijn een vitalytics-eigen class, dus forms.css'
   .frm-number-input-opmaak raakt ze niet en ze vielen terug op de kale
   browser-default (2px inset, Arial 13px, geen radius) naast de wél
   gestylede getalvelden ernaast. Zelfde opmaak/focus als .frm-number-input
   in forms.css, zodat een poging-veld niet van een getalveld te
   onderscheiden is. */
.frm-pogingen-input
{
	width: 160px; padding: 6px 10px;
	border: 1px solid #d1d5da; border-radius: 4px; background: #fff;
	font-family: inherit; font-size: 14px; color: #2a2f36;
	transition: border-color .1s, box-shadow .1s;
}
/* Bewust forms.css' eigen kleurwaarden hierboven (#d1d5da/#2a2f36) i.p.v. de
   vitalytics-tokens: doel is dat een poging-veld exact gelijk is aan het
   getalveld ernaast, en dat veld wordt door forms.css gestyled (buiten het
   bereik van deze tokens). Wijzigt .frm-number-input ooit, dan hoort dit
   blok mee te wijzigen. */
.frm-pogingen-input:focus
{ outline: none; border-color: var(--vit-blue); box-shadow: 0 0 0 3px rgba(31,111,196,.15); }
.frm-pogingen-prefix,
.frm-pogingen-suffix { font-size: 13px; color: var(--vit-muted); }
.frm-pogingen-resultaat-label { margin-left: 6px; font-size: 13px; color: var(--vit-muted); }
.frm-pogingen-output
{
	padding: 6px 10px;
	border: 1px dashed var(--vit-border);
	border-radius: 4px;
	background: var(--vit-bg);
	font-size: 14px;
	font-weight: 600;
	color: var(--vit-ink);
}

/* forms.css' eigen <select>-veld (.frm-select-input) valt met zijn kale
   4px-rand-stijl duidelijk uit de toon naast de rest van de app (feedback
   op de online vragenlijst) — zelfde radius/kleuren/focusring als een
   gewoon .vit-formcard-invoerveld (shell.css, "CRUD-schermen"-sectie).
   Onbewust (niet gescoped): forms.css' select ziet er zowel in de publieke
   vragenlijst als in het interne meetstation-scherm hetzelfde kale uit,
   dus deze fix verbetert allebei tegelijk. */
.frm-select-input
{
	padding: 10px 12px;
	border: 1px solid var(--vit-border);
	border-radius: 10px;
	font-size: 14px;
	font-family: inherit;
	background: #fff;
	color: var(--vit-ink);
	transition: border-color .1s, box-shadow .1s;
}
.frm-select-input:focus
{ outline: none; border-color: var(--vit-blue); box-shadow: 0 0 0 3px rgba(31,111,196,.15); }

/* forms.css' eigen opslaan-knop (.frm-save-button) is standaard vlak/4px-
   rand — in stijl brengen met de rest van de app's primaire knoppen
   (.vit-btn-primary, hierboven): grotere radius + gradient-achtergrond.
   Ook onbewust: geldt voor elk forms.js-scherm (publieke vragenlijst én
   het interne meetstation), niet alleen de online vragenlijst.
   Gescoped op de twee forms.js-containers (i.p.v. kaal .frm-save-button,
   zoals hierboven): forms.css laadt ná deze stylesheet (frontend/header.
   inc.php) en heeft zélf ook een kale ".frm-save-button"-regel met dezelfde
   specificiteit (radius 4px, effen kleur) — bij gelijke specificiteit wint
   de later geladen forms.css, waardoor deze override zonder de extra
   ID-specificiteit onzichtbaar bleef (feedback: "css van de save-knop is
   nog steeds anders dan de submit-knop" — de eerdere versie van deze regel
   werd dus in de praktijk nooit toegepast). Zelfde ID-scoping-truc als de
   #vit-meetformulier/#vit-vragenlijst-formulier .frm-chapter-nav-item-
   regels hierboven, om diezelfde reden. */
#vit-meetformulier .frm-save-button,
#vit-vragenlijst-formulier .frm-save-button
{
	padding: 10px 20px;
	border: 0;
	border-radius: 10px;
	background: var(--vit-gradient);
	font-weight: 600;
	box-shadow: 0 6px 16px rgba(31,111,196,.28);
	transition: box-shadow .15s, transform .1s, background .15s;
}
#vit-meetformulier .frm-save-button:hover:not(:disabled),
#vit-vragenlijst-formulier .frm-save-button:hover:not(:disabled) { background: var(--vit-gradient-hover); box-shadow: 0 8px 20px rgba(22,166,166,.35); }
#vit-meetformulier .frm-save-button:active:not(:disabled),
#vit-vragenlijst-formulier .frm-save-button:active:not(:disabled) { transform: translateY(1px); }
#vit-meetformulier .frm-save-button.is-saved,
#vit-vragenlijst-formulier .frm-save-button.is-saved { background: var(--vit-up); }
#vit-meetformulier .frm-save-button.is-error,
#vit-vragenlijst-formulier .frm-save-button.is-error { background: var(--vit-down); }

/* Waardering-veldtype (vitalytics-forms.js): alle mogelijke niveaus onder
   elkaar in oplopende volgorde, met een radio-achtig icoontje dat het
   behaalde niveau markeert — zo is naast de uitkomst ook zichtbaar waar
   die in de schaal ligt. Read-only weergave (geen <input>), vandaar een
   <ul> met icoon-spans i.p.v. echte radiobuttons. */
.frm-waardering-levels { margin: 2px 0 0; padding: 0; list-style: none; }
.frm-waardering-level
{
	display: flex; align-items: center; gap: 8px;
	padding: 2px 0; font-size: 14px; color: var(--vit-muted);
}
.frm-waardering-icon { font-size: 18px; color: var(--vit-faint); }
.frm-waardering-level.is-behaald { color: var(--vit-ink); font-weight: 600; }
.frm-waardering-level.is-behaald .frm-waardering-icon { color: var(--vit-blue); }
.frm-waardering-leeg { color: var(--vit-muted); font-size: 14px; }

/* Boolean-veldtype (vitalytics-forms.js): "Ja"/"Nee" als twee radio-opties
   op een rij — zonder deze regel staan ze (net als .frm-pogingen-row
   hierboven) zonder spatie tegen elkaar aan, omdat er geen whitespace
   tussen de door jQuery aan elkaar geplakte <label>-elementen zit. */
.frm-boolean-row { display: inline-flex; align-items: center; flex-wrap: wrap; gap: 16px; }

/* Toestemming-veldtype (vitalytics-forms.js): drie los onder elkaar getekende
   rollen (zelf/ouder/derden), elk met dezelfde .frm-boolean-row-radiogroep.
   .is-verborgen wordt door recompute() gezet zodra een rol op de (herberekende)
   leeftijd niet van toepassing is — zie vit.toestemming.class.php. */
.frm-toestemming { display: flex; flex-direction: column; gap: 20px; }
.frm-toestemming-rol.is-verborgen { display: none; }
.frm-toestemming-label { font-weight: 600; margin: 0 0 6px; }
.frm-toestemming-naam { display: block; margin-top: 10px; font-size: 0.9em; color: var(--vit-muted); }
.frm-toestemming-naam-input { display: block; margin-top: 4px; }

/* Naam-veldtype (vitalytics-forms.js): voornaam/tussenvoegsel/achternaam als
   drie los onder elkaar getekende labels+invoervelden — zelfde kolomopzet als
   .frm-toestemming hierboven. De invoervelden zelf gebruiken forms.css' eigen
   .frm-text-input (zie vitalytics-forms.js), dus alleen de label/afstand-
   opmaak hoort hier. */
/* Feedback: voornaam/tussenvoegsel/achternaam naast elkaar i.p.v. onder
   elkaar, met het tussenvoegsel-veld smaller dan de andere twee. flex-wrap
   bewust uit (nowrap): met wrap aan beslist de browser al vóór het krimpen
   (op de ongekrompen flex-basis-som) of een item naar een nieuwe regel
   gaat — bij drie velden naast elkaar in een smalle kaart sprong
   "Achternaam" daardoor toch los, terwijl krimpen ruim voldoende was.
   nowrap dwingt het krimpen af i.p.v. het wrappen. */
.frm-naam { display: flex; flex-direction: row; flex-wrap: nowrap; gap: 12px; }
/* min-width:0 overrules de standaard flex-auto-minimum (het intrinsieke
   min-content van een kaal <input>, breder dan de flex-basis) — anders
   blijven de velden te breed voor de kaart. */
.frm-naam-label { display: block; flex: 1 1 130px; min-width: 0; font-weight: 600; font-size: 0.9em; color: var(--vit-muted); }
.frm-naam-label-tussenvoegsel { flex: 0 1 90px; }
.frm-naam-label input { display: block; width: 100%; margin-top: 4px; font-weight: normal; }

/* Geslacht-veldtype als radio-weergave (vit.geslacht.class.php, props.display
   === "radio" in forms.js): standaard (forms.css) staan de opties onder
   elkaar. Feedback: naast elkaar, met genoeg ruimte tussen het label van de
   ene optie en de radio-input van de volgende. Alleen dit veldtype geraakt
   (via de generieke .frm-field-<type>-hook, forms.js) — de gedeelde
   .frm-radio-row/.frm-radio-option-stijl (forms.css) blijft voor andere
   radio-weergaven elders ongewijzigd. */
.frm-field-vit_geslacht .frm-radio-row { flex-direction: row; flex-wrap: wrap; gap: 24px; }

/* Groepselect-veldtype (vitalytics-forms.js): twee <select>-velden naast
   elkaar (groep, dan waarde binnen die groep) — zelfde naast-elkaar-met-
   gap-recept als .frm-pogingen-row/.frm-boolean-row hierboven. Beide
   selects hergebruiken forms.css' eigen .frm-select-input-klasse (zie
   shell.css' ".frm-select-input"-regel hierboven), dus alleen de
   rij-opmaak hoort hier. */
.frm-groepselect-row { display: inline-flex; align-items: center; flex-wrap: wrap; gap: 8px; }
.frm-groepselect-waarde:disabled { color: var(--vit-faint); }

/* Groepselect-eigenschappen-editor (vit.groepselect.class.php,
   VitGroepselectGroepenField): geneste groepen/waarden-lijst als divs
   i.p.v. <table> — ".vit-formcard table,tbody,tr,td,th{display:block}"
   hierboven platst élke geneste <table> binnen een admin-kaart plat (zie
   de toelichting bij table[data-no] eerder in dit bestand), en deze editor
   is twee niveaus diep genest, dus tabellen zijn hier geen optie. */
.vit-groepselect-groepen { display: flex; flex-direction: column; gap: 12px; margin-bottom: 10px; }
.vit-groepselect-groep
{
	border: 1px solid var(--vit-border); border-radius: var(--vit-radius-sm);
	background: var(--vit-bg); padding: 10px 12px;
}
.vit-groepselect-groep-header { display: flex; align-items: center; gap: 8px; }
.vit-groepselect-groep-label { flex: 1 1 auto; min-width: 0; font-weight: 600; }
.vit-groepselect-opties { display: flex; flex-direction: column; gap: 6px; margin: 10px 0 6px; padding-left: 16px; border-left: 2px solid var(--vit-border); }
.vit-groepselect-optie { display: flex; align-items: center; gap: 8px; }
.vit-groepselect-optie-waarde, .vit-groepselect-optie-label { flex: 1 1 0; min-width: 0; }
.vit-groepselect-optie-toevoegen { margin-left: 16px; }

/* ------------------------------------------- Bulk-placeholder naam-invullen */

.vit-rename-icon { cursor: pointer; font-size: 16px; color: var(--vit-muted); margin-left: 6px; vertical-align: middle; }
.vit-rename-icon:hover { color: var(--vit-blue); }

/* Historie/print-icoon in de meetstation-kop-toolbar (feedback: subtiel
   grijs i.p.v. druk/fel, en niet meer los achter de naam) — geen
   margin-left meer nodig zoals toen ze nog inline in de naamtekst stonden,
   .vit-meetstation-toolbar's eigen gap regelt de tussenruimte nu. */
.vit-print-icon, .vit-historie-icon { cursor: pointer; font-size: 20px; color: var(--vit-muted); vertical-align: middle; text-decoration: none; }
.vit-print-icon:hover, .vit-historie-icon:hover { color: var(--vit-blue); }

/* --------------------------------------------- toestemmings-kleurcodes (gedeeld) */
/* Eén 4-kleuren tri-state-conventie (2026-09-24-003, PROJECT.md §4.2), gebruikt
   door zowel het meetstation (.vit-avg-schild/.vit-delen-schild) als de
   deelnemerslijst (.vit-toestemming-status) — zie Inschrijving::
   toestemmingKleur()/toestemmingKleurDeelname()/toestemmingKleurDelen() voor
   waar deze vier kleuren vandaan komen: grijs = nog geen enkele reactie,
   groen = overal "ja", rood = minstens één expliciete "nee" (wint altijd),
   oranje = een mix van "ja"/"geen_reactie" zonder "nee" (alleen bij 16-17jr:
   ouder óf zelf, niet beide). Vervangt de losse is-ja/is-nee/is-deels
   (avg-schild) en is-geen/is-gedeeltelijk/is-volledig (overzichtskolom)
   klassensets van vóór deze feature. */
.is-kleur-grijs .material-icons  { color: var(--vit-faint); }
.is-kleur-groen .material-icons  { color: var(--vit-up); }
.is-kleur-rood .material-icons   { color: var(--vit-down); }
.is-kleur-oranje .material-icons { color: var(--vit-warn); }
/* Lichtere varianten op een actieve (geselecteerde, donkere) meetstation-
   listitem — zelfde aanpassing als voorheen per is-ja/is-nee/is-deels. */
.vit-meetstation-item.is-active .is-kleur-grijs .material-icons  { color: rgba(255,255,255,.6); }
.vit-meetstation-item.is-active .is-kleur-groen .material-icons  { color: #d9fce6; }
.vit-meetstation-item.is-active .is-kleur-rood .material-icons   { color: #ffe1e1; }
.vit-meetstation-item.is-active .is-kleur-oranje .material-icons { color: #ffe4bf; }

/* ---------------------------------------------------- AVG-toestemmingsschild */
/* Alleen de AVG-DEELNAME-toestemming (zelf/ouder, géén delen — zie
   vit_avg_schild_html()); altijd klikbaar (opent de registreer/intrekken-
   popup), vandaar geen aparte cursor-regel per kleur meer nodig. */

.vit-avg-schild { display: inline-flex; flex: 0 0 auto; cursor: pointer; }
.vit-avg-schild .material-icons { font-size: 20px; }

/* ------------------------------------------------- delen-toestemmingsschild */
/* Zelfde schild, maar voor de delen-toestemming — sinds 2026-09-24-004 zijn
   alle drie kleuren klikbaar (opent de tri-state delen-popup, zie
   meetstation.post.php), niet langer alleen het grijze ("nog geen reactie")
   icoon. */

.vit-delen-schild { display: inline-flex; flex: 0 0 auto; cursor: pointer; }
.vit-delen-schild .material-icons { font-size: 20px; }

/* ------------------------------------- gecombineerde toestemmingsstatus */
/* Deelnemersoverzicht-kolom (2026-09-24-006: Toestemming + Delen samengevoegd
   tot één kolom): shield (Inschrijving::toestemmingKleurDeelname(), ouder/
   zelf) en open_in_new (Inschrijving::toestemmingKleurDelen()) naast elkaar,
   elk met hun eigen kleur — .vit-toestemming-icon draagt de .is-kleur-*-klasse
   i.p.v. de buitenste span, zodat de twee iconen onafhankelijk kunnen kleuren.
   Beide samen blijven klikbaar: opent de tri-state quick-edit-popup
   (#vit-toestemming-modal, deelnemers.post.php). */

.vit-toestemming-status { display: inline-flex; align-items: center; gap: 6px; flex: 0 0 auto; cursor: pointer; }
.vit-toestemming-status .material-icons { font-size: 20px; }
.vit-toestemming-icon { display: inline-flex; }

/* ------------------------------------------------------- archiefbadge */
/* Archiveren op twee niveaus (Deelnemer/Inschrijving::archiveer()): een
   deelnemer of inschrijving die niet langer actief is, maar wel bewaard
   blijft — zie deelnemers.post.php "Toon ook gearchiveerde". */
.vit-archief-badge
{
	display: inline-block;
	padding: 2px 8px;
	border-radius: 999px;
	background: var(--vit-border-2);
	color: var(--vit-muted);
	font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: .03em;
}

/* ------------------------------------------------------------- historie */
/* Per-record "Historie"-sectie (PROJECT.md §16-Q, vit_historie_kaart() in
   settings.inc.php) — hertgebruikt table.vit-table voor de rijen zelf, alleen
   de kaart-titel en de wijzigingen-diff per rij zijn hier eigen. */
.vit-historie-titel { font-size: 15px; font-weight: 700; margin: 0 0 12px; color: var(--vit-ink); }
.vit-historie-leeg   { color: var(--vit-muted); margin: 0; }
.vit-historie-diff    { margin: 0; padding: 0; list-style: none; }
.vit-historie-diff li { margin: 2px 0; }
.vit-historie-verouderd { color: var(--vit-muted); font-style: italic; }

.vit-avg-modal
{
	display: none;
	position: fixed;
	inset: 0;
	background: rgba(12,35,64,.45);
	align-items: center;
	justify-content: center;
	z-index: 1000;
}
.vit-avg-modal.is-open { display: flex; }
.vit-avg-modal-box
{
	background: var(--vit-card);
	border-radius: var(--vit-radius);
	box-shadow: var(--vit-shadow);
	padding: 26px 28px;
	/* 320px -> 460px -> 520px (klantfeedback: de drie tri-state-knoppen per
	   rij pasten niet naast elkaar op 460px zonder de tekst te verdringen,
	   2026-09-24-006). */
	width: 520px;
	max-width: calc(100vw - 40px);
}
.vit-avg-modal-box h3 { margin: 0 0 6px; font-size: 17px; }
.vit-avg-modal-box p { margin: 0 0 14px; color: var(--vit-muted); }
.vit-avg-modal-box label { display: block; font-size: 13px; font-weight: 500; }
.vit-avg-modal-box select
{
	margin-top: 4px;
	width: 100%;
	padding: 8px 10px;
	border: 1px solid var(--vit-border);
	border-radius: var(--vit-radius-sm);
	font-family: inherit;
	font-size: 14px;
	background: var(--vit-card);
	color: var(--vit-ink);
}
/* 16-17jr-popup: ouder- en zelf-rij, elk met een eigen tri-state knoppenrij
   (.vit-avg-modal-tristate hieronder) — zie meetstation.post.php,
   #vit-avg-modal-dubbel, en het gelijknamige #vit-toestemming-modal in
   deelnemers.post.php. */
.vit-avg-modal-rij { margin: 0 0 12px; }
.vit-avg-modal-rij strong { font-size: 13px; }
.vit-avg-modal-rij .vit-avg-modal-status { color: var(--vit-up); font-size: 13px; margin-left: 6px; }
.vit-avg-modal-rij select
{
	margin-top: 4px;
	width: 100%;
	padding: 8px 10px;
	border: 1px solid var(--vit-border);
	border-radius: var(--vit-radius-sm);
	font-family: inherit;
	font-size: 14px;
	background: var(--vit-card);
	color: var(--vit-ink);
}
.vit-avg-modal-rij .vit-btn-primary { margin-top: 6px; width: 100%; }
.vit-avg-modal-rij input[type="text"],
.vit-avg-modal-rij input[type="date"],
.vit-avg-modal-rij input[type="email"]
{
	margin-top: 4px;
	width: 100%;
	padding: 8px 10px;
	border: 1px solid var(--vit-border);
	border-radius: var(--vit-radius-sm);
	font-family: inherit;
	font-size: 14px;
	background: var(--vit-card);
	color: var(--vit-ink);
	box-sizing: border-box;
}

/* Tri-state quick-edit-popups (2026-09-24-004, herzien 2026-09-24-005): drie
   knoppen per toepasselijke rij (Geen reactie/Wel toestemming/Geen
   toestemming), gebruikt door zowel het meetstation
   (#vit-meetstation-toestemming-modal) als de deelnemerslijst
   (#vit-toestemming-modal, deelnemers.post.php) en het bewerkscherm van een
   deelnemer — elke knop post direct naar het "toestemming-status-zetten"-
   endpoint, zie de <script>-blokken in de betreffende bestanden. De HTML
   hergebruikt om historische redenen drie verschillende knop-klassen
   (.vit-btn-neutral, .vit-btn-primary.vit-btn-save, .vit-danger-link — de
   laatste had zelfs helemaal geen eigen CSS-regel) die elk een andere
   basisstijl (kleur/rand/icoon) meebrachten zodra ze naast elkaar stonden —
   klantfeedback: "lelijk". Onderstaande regels overschrijven die drie met
   één samenhangende look: gelijke knoppen in rust, een duidelijke
   kleurgecodeerde .is-actief-status (grijs/groen/rood, zelfde kleuren als de
   schild-iconen) i.p.v. een outline. */
.vit-avg-modal-tristate { display: flex; gap: 8px; margin-top: 10px; }
.vit-avg-modal-tristate button
{
	flex: 1;
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 4px;
	padding: 10px 6px;
	border: 1.5px solid var(--vit-border);
	border-radius: var(--vit-radius-sm);
	background: var(--vit-card);
	color: var(--vit-muted);
	font-family: inherit;
	font-size: 13px;
	font-weight: 600;
	line-height: 1.3;
	white-space: nowrap;
	box-shadow: none;
	cursor: pointer;
	transition: background .15s ease, border-color .15s ease, color .15s ease;
}
/* Verwijdert het icoon-font-glyph dat .vit-btn-primary/.vit-btn-save elders
   altijd tonen (zie shell.css, .vit-btn-primary::before/.vit-btn-save::before)
   — binnen de tri-state-rij komt het status-icoontje (more_horiz/close/
   check) uit een eigen <span class="material-icons"> in de knop-HTML, niet
   uit dit ::before-glyph. */
.vit-avg-modal-tristate button::before { content: none; }
.vit-avg-modal-tristate button .material-icons { font-size: 16px; }
/* box-shadow: none overschrijft hier expliciet de .vit-btn-primary:hover-
   schaduw (shell.css, ~regel 2204) die de "Wel toestemming"-knop anders ook
   in inactieve staat op hover zou tonen — die knop hergebruikt .vit-btn-
   primary voor de kleur/typografie, maar de schaduw hoort alleen bij
   .is-actief (klantfeedback: "hoort geen schaduw te hebben, pas als hij
   actief is"). */
.vit-avg-modal-tristate button:hover:not(.is-actief) { border-color: var(--vit-faint); color: var(--vit-ink); background: var(--vit-bg); box-shadow: none; }
.vit-avg-modal-tristate button[data-status="geen_reactie"].is-actief { background: var(--vit-bg); border-color: var(--vit-faint); color: var(--vit-ink); }
.vit-avg-modal-tristate button[data-status="ja"].is-actief { background: var(--vit-up); border-color: var(--vit-up); color: #fff; }
.vit-avg-modal-tristate button[data-status="nee"].is-actief { background: var(--vit-down); border-color: var(--vit-down); color: #fff; }

.vit-avg-modal-fout { color: var(--vit-down); font-size: 13px; margin: 10px 0 0; min-height: 1em; }
.vit-avg-modal-acties { display: flex; justify-content: flex-end; gap: 10px; margin-top: 18px; }
/* Sluiten-knop van de toestemming-popups (deelnemers.post.php en
   meetstation.post.php delen deze class op hun eigen Sluiten-knop-id) — eigen
   class i.p.v. .vit-btn-primary, die knop krijgt de bestaande
   .vit-btn-primary.vit-btn-save-combinatie, zelfde patroon als "Start meten"
   op testsessies.post.php. */
.vit-avg-modal-close
{
	padding: 9px 16px;
	border-radius: var(--vit-radius-sm);
	border: 1px solid var(--vit-border);
	background: var(--vit-card);
	color: var(--vit-ink);
	font-family: inherit;
	font-size: 14px;
	cursor: pointer;
}
.vit-avg-modal-close:hover { background: var(--vit-bg); }
/* Elke tri-state-knop (Geen reactie/Wel toestemming/Geen toestemming, zie
   .vit-avg-modal-tristate hierboven) disabled zichzelf tijdens de POST — zelfde
   "even wachten"-cursor als voorheen de losse Registreren/Bevestigen-knoppen. */
.vit-avg-modal-tristate button:disabled { opacity: .6; cursor: wait; }

.vit-meetstation-empty { text-align: center; padding: 60px 20px; color: var(--vit-muted); }
.vit-meetstation-empty .material-icons { display: block; margin: 0 auto 10px; font-size: 40px; color: var(--vit-faint); }

/* Meten blokkeren zonder toestemming (PROJECT.md §4.2): staat in het
   rechterpaneel i.p.v. het meetformulier zolang de toestemmingsstatus van
   de gekozen deelnemer niet "volledig" is — zie meetstation.post.php. Het
   schild in de kop erboven blijft het klikbare oplospunt. */
.vit-toestemming-blok { text-align: center; padding: 40px 20px; color: var(--vit-warn); }
.vit-toestemming-blok .material-icons { display: block; margin: 0 auto 10px; font-size: 40px; }
.vit-toestemming-blok p { color: var(--vit-muted); max-width: 32em; margin: 0 auto; }

/* Online-testsessie (feature "vragenlijst vooraf per mail"): statusbadge in
   de deelnemerslijst, status-/antwoordenblok in het read-only rechterpaneel
   en het versturen-scherm — zie meetstation.post.php. */
.vit-online-badge { display: inline-flex; flex: 0 0 auto; margin-left: 6px; }
.vit-online-badge .material-icons { font-size: 18px; }
.vit-online-badge.is-ingevuld .material-icons { color: var(--vit-up); }
.vit-online-badge.is-open .material-icons { color: var(--vit-faint); }
.vit-online-status { display: flex; align-items: center; gap: 8px; padding: 14px 18px; border-radius: 10px; background: var(--vit-panel-alt, #f4f6f8); margin-bottom: 16px; }
.vit-online-status.is-ingevuld { color: var(--vit-up); }
.vit-online-status.is-open { color: var(--vit-muted); }
.vit-online-leeg { color: var(--vit-muted); padding: 0 18px; }
.vit-online-antwoorden { display: flex; flex-direction: column; gap: 12px; padding: 0 18px 18px; }
.vit-online-antwoord .vraag { font-weight: 600; margin-bottom: 4px; }
.vit-online-antwoord .waarde { color: var(--vit-muted); }
.vit-verzend-lijst, .vit-verzend-resultaten { list-style: none; margin: 0; padding: 0; max-height: 360px; overflow-y: auto; }
.vit-verzend-lijst li, .vit-verzend-resultaten li { padding: 6px 0; border-bottom: 1px solid var(--vit-border, #e5e9ec); }
.vit-verzend-waarschuwing { color: var(--vit-warn); font-size: 12.5px; }
.vit-verzend-resultaten li.is-ok { color: var(--vit-up); }
.vit-verzend-resultaten li.is-fout { color: var(--vit-down); }

/* Rapportages: lijst van beschikbare ROES Docs-templates voor de gekozen
   meting/deelnemer (rapportages.post.php, stap 3), rij per template met de
   "PDF genereren"-knop rechts — zelfde rij-opzet als .vit-avg-modal-rij. */
.vit-rapportages-lijst { list-style: none; margin: 0; padding: 0; }
.vit-rapportages-lijst li
{
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 16px;
	padding: 14px 4px;
	border-bottom: 1px solid var(--vit-border);
}
.vit-rapportages-lijst li:last-child { border-bottom: 0; }
.vit-rapportages-lijst .naam { font-weight: 600; color: var(--vit-ink); }

/* TIER: BP_STACK */
@media (max-width: 1100px)
{
	.vit-meetstation { flex-direction: column; }
	/* Feedback: zonder overflow liep de inhoud van deze kaart (nog steeds
	   op de 74vh van .vit-meetstation-items hierboven) over de 260px-cap
	   heen, over de vragenlijst-kaart eronder. */
	.vit-meetstation-list { flex-basis: auto; width: 100%; max-height: 260px; overflow: auto; }
}

/* -------------------------------------------------------------- Stub-pagina's */

.vit-stub
{
	text-align: center;
	padding: 60px 30px;
	color: var(--vit-muted);
}
.vit-stub .material-icons { font-size: 48px; color: var(--vit-faint); }
.vit-stub h2 { margin: 14px 0 6px; color: var(--vit-ink); font-size: 20px; }
.vit-stub p { margin: 0; }

/* ---------------------------------------------------------- CRUD-schermen ---
   Generieke reskin voor de PageTable/PageForm-componenten (WebTable/WebForm)
   die de CRUD-schermen (Klanten, Projecten, ...) opbouwen. $table->class =
   "vit-table" en $form->class = "vit-formcard" laten deze regels aanslaan
   zonder dat de componenten zelf vervangen hoeven te worden. */

table.vit-table
{
	width: 100%;
	border-collapse: collapse;
	font-size: 14px;
	background: transparent;
}
table.vit-table thead th
{
	text-align: left;
	font-weight: 600;
	font-size: 12.5px;
	letter-spacing: .02em;
	color: #fff;
	background: var(--vit-navy);
	padding: 12px 16px;
	white-space: nowrap;
	border: 0;
}
table.vit-table thead th a { color: inherit; text-decoration: none; }
table.vit-table thead th:first-child { border-top-left-radius: 10px; border-bottom-left-radius: 10px; }
table.vit-table thead th:last-child  { border-top-right-radius: 10px; border-bottom-right-radius: 10px; }
table.vit-table tbody td { padding: 13px 16px; border: 0; border-bottom: 1px solid var(--vit-border-2); }
table.vit-table tbody tr:last-child td { border-bottom: 0; }
table.vit-table tbody tr:hover { background: #fafcfd; }
table.vit-table tbody tr[onclick] { cursor: pointer; }
table.vit-table img { vertical-align: middle; opacity: .55; transition: opacity .15s; }
table.vit-table img:hover { opacity: 1; }
table.vit-table input[type="checkbox"] { display: none; }

/* Formulieren: PageForm rendert intern een <table class="table-form">-per-
   fieldset structuur; hier plat naar een gestapelde, gelabelde lay-out
   getrokken (zelfde recept als .vit-loginform hierboven). Padding/max-width
   staan bewust op de omringende .vit-card, niet hier — zie de toelichting
   bij .vit-card hierboven. */
.vit-formcard table, .vit-formcard tbody, .vit-formcard tr,
.vit-formcard td, .vit-formcard th
{ display: block; width: auto; padding: 0; border: 0; background: none; }
.vit-formcard fieldset { border: 0; margin: 0 0 18px; padding: 0; }
.vit-formcard fieldset legend
{
	font-size: 15px; font-weight: 700; margin: 0 0 12px; padding: 0;
	color: var(--vit-ink);
}

/* De witte kaart komt niet meer van een omringende vit_card($form)-div
   (form-knoppen moeten er BUITEN kunnen staan, net als "Nieuwe klant" buiten
   de tabel-kaart staat — vit_fieldset_kaart()/vit_form_acties() in
   settings.inc.php), maar rechtstreeks van de velden-fieldset zelf. De
   losse acties-fieldset (.vit-form-actions) erft gewoon de kaartloze
   .vit-formcard-fieldset-reset hierboven — geen eigen regel nodig. */
.vit-formcard fieldset.vit-fieldset-card,
.vit-formcard fieldset.frm_field_card
{
	position: relative;
	background: var(--vit-card);
	border: 1px solid var(--vit-border);
	border-radius: var(--vit-radius);
	box-shadow: var(--vit-shadow);
	padding: 56px 24px 24px;
	/* <fieldset> heeft een UA-quirk: het weigert standaard smaller te
	   worden dan de min-content-breedte van zijn inhoud, ook met expliciete
	   width:auto/100% — zonder deze reset zou een breed element diep in de
	   kaart (bv. de Niveaus-tabel, table[data-no], met zijn eigen
	   min-width/overflow-x-scrolgrens) de hele kaart en pagina breder
	   duwen i.p.v. netjes lokaal te scrollen. */
	min-width: 0;
}
/* Legend als donker-blauwe balk bovenaan de kaart, in dezelfde stijl als
   de thead-koppen van table.vit-table (zelfde font-size/weight/letter-
   spacing, zelfde 10px hoekstraal op alle 4 hoeken, en dezelfde
   6px/4px/4px marge tot de rand van het witte vlak — vergelijkbaar met,
   maar sinds .vit-table-card een uniforme 6px-padding kreeg niet meer
   gelijk aan, .vit-table-card z'n padding). De browser positioneert een
   <legend> standaard half over de fieldset-rand heen; position:absolute
   haalt 'm uit die speciale UA-layout (vandaar ook position:relative
   hierboven) zodat de balk als
   losstaand, volledig afgerond blokje binnen de kaart ligt, met de
   padding-top hierboven als ruimte voor de rest van de inhoud eronder. */
.vit-formcard fieldset.vit-fieldset-card legend,
.vit-formcard fieldset.frm_field_card legend
{
	position: absolute;
	top: 6px; left: 4px; right: 4px;
	margin: 0;
	padding: 12px 16px;
	background: var(--vit-navy);
	color: #fff;
	font-size: 12.5px;
	font-weight: 600;
	letter-spacing: .02em;
	border-radius: 10px;
}

/* FormFieldForm (forms-lib, field.form.class.php) groepeert zijn vier
   frm_field_card-fieldsets in 2 rijen van 2 via col_no 0/1 per rij.
   PageForm (rpstapestry/pageform.class.php render(), niet het
   bootstrap.mod-broertje — dát is niet wat hier draait) zet dat kolom-
   raster om in een klasseloze <table width=100%><td style="width:50%">-
   structuur, per rij een eigen <table>, telkens een direct kind van
   <form>. De brede table-platslag hierboven (regel 741, bedoeld voor
   table.table-form) treft die kolom-tabellen ook, want het is ook
   gewoon table/tbody/tr/td — vandaar dat de kaarten vóór deze regels
   allemaal onder elkaar vielen i.p.v. 2-aan-2. Specifiekere ">"-
   selectors herstellen alleen déze buitenste kolom-tabellen (rechtstreekse
   kinderen van .vit-formcard); table.table-form, genest in een fieldset
   binnen zo'n kolom-cel, wordt door deze regels niet geraakt en blijft
   dus gewoon platgeslagen zoals bedoeld. Dit is óók een "2 blokken naast
   elkaar"-layout (net als .vit-panel-grid/.vit-template-edit-grid), dus
   de table-herstelling geldt bewust alleen boven BP_STACK — eronder wint
   de brede platslag hierboven vanzelf weer (geen losse override nodig)
   en vallen de kaarten terug tot 100%-breed onder elkaar. */
/* TIER: BP_STACK (desktop-kant, min-width) */
@media (min-width: 1101px)
{
	/* table-layout: fixed — zonder dit respecteert de browser de "width:50%"-
	   inline-stijl op de td's hierboven alleen als hint, niet als harde grens:
	   bij ONGELIJKE content-breedte tussen de twee kolom-cellen (bv.
	   dashboardcomponenten.post.php se rechterkolom met de bredere kolommen-/
	   filters-repeatertabel tegenover een smalle linkerkolom met simpele
	   tekstvelden) trekt de browser de proportie dan gewoon scheef naar de
	   cel met de meeste inhoud — bevestigd live: 242px/910px i.p.v. 50/50 bij
	   twee cellen met identieke "width:50%"-stijl. table-layout:fixed maakt
	   de kolombreedte-verdeling van de EERSTE rij (de onzichtbare 1px-
	   spacer-rij, PageForm se eigen render()) bindend voor de hele tabel,
	   ongeacht de content-breedte in latere rijen — precies waar die
	   spacer-rij-truc sowieso al voor bedoeld was. */
	.vit-formcard > table { display: table; width: 100% !important; table-layout: fixed; }
	.vit-formcard > table > tbody { display: table-row-group; }
	.vit-formcard > table > tbody > tr { display: table-row; }
	.vit-formcard > table > tbody > tr > td { display: table-cell; vertical-align: top; }
	.vit-formcard > table > tbody > tr > td > fieldset.frm_field_card,
	.vit-formcard > table > tbody > tr > td > fieldset.vit-fieldset-card
	{ height: 100%; }
}

/* MultiField-tabel (Niveaus e.d., <table data-no>, vit.waardering.
   class.php — enige gebruiker van PortalFormWebMultiField in Vitalytics,
   dus deze hele sectie is veilig specifiek voor dat component).
   Eerdere aanpak (table[data-no] { display:table } + table-row-group/
   table-cell op de rest) herstelde weliswaar het uiterlijk van een tabel,
   maar Chrome bleek thead en tbody dan zichtbaar verschillende
   kolombreedtes te geven (geverifieerd met getBoundingClientRect: zelfde
   kolomindex, andere breedte per rijgroep) — de kolomkoppen stonden niet
   boven hun kolom, de rand onder de koppen liep niet door, en de ×
   (verwijderen) / + (toevoegen) iconen stonden niet in lijn.
   Flexbox-rijen lossen dat robuust op: elke rij (kop-, data- en
   toevoeg-rij) krijgt exact dezelfde positionele regels, dus kolom N is
   gegarandeerd even breed op elke rij — ongeacht of een rij 3 t/m 6
   kolommen heeft (varieert met "Aantal context-variabelen", 0 t/m 3,
   elk een eigen kolom, zie getPropertyFields()). Positioneren t.o.v.
   het EINDE van de rij (:last-child = icoon, :nth-last-child(2) =
   "Waarde vanaf", :nth-last-child(3) = "Label") werkt voor elk aantal
   kolommen, want die drie staan altijd als laatste. */
.vit-formcard table[data-no],
.vit-formcard table[data-no] thead,
.vit-formcard table[data-no] tbody,
.vit-formcard table[data-no] tfoot
{ display: block; width: 100%; }
/* De vaste kolombreedtes hieronder (34/110/130/28px) zijn getuned voor
   desktop; op smalle schermen zou de flexibele Label-kolom anders tot een
   paar px worden dichtgeknepen (onleesbaar) i.p.v. netjes af te breken —
   overflow-x hier (niet op thead/tbody/tfoot los, anders scrollen kop en
   data niet meer synchroon) + een min-width op de rij hieronder maken deze
   tabel op smalle schermen horizontaal scrollbaar i.p.v. onleesbaar smal,
   zelfde patroon als .vit-table-card voor brede data-tabellen. */
.vit-formcard table[data-no] { overflow-x: auto; }

/* !important op gap/align-items/flex-direction/margin-bottom (NIET op
   display: de verborgen sjabloon-rij hieronder — de laatste <tr> in
   <tfoot>, die de "+"-knop kloont voor een nieuw niveau — staat met een
   inline style="display:none" verborgen, en !important zou die inline
   stijl overstemmen en de sjabloon-rij zichtbaar maken): deze
   <table data-no> zit zelf genest ín een td van PageForm's eigen
   table.table-form (de gewone label/veld-rijen van dit formulier), en
   ".vit-formcard table.table-form tr" hieronder (zelfde specificiteit,
   later in dit bestand — ook zijn @media-mobiel-variant) lekt via
   afstamming dwars door die tabelgrens heen: de selector eist alleen
   érgens een table.table-form-voorouder, niet dat de tr er een direct
   kind van is. Zonder !important op de rest zou dat de rijen van déze
   tabel op mobiel zelfs naar flex-direction:column omzetten. */
.vit-formcard table[data-no] tr
{
	display: flex;
	align-items: center !important;
	flex-direction: row !important;
	gap: 0 !important;
	margin-bottom: 0 !important;
	width: 100%;
	/* Vloer onder de rijbreedte: som van de vaste kolommen (34+130+28=192,
	   +110px per contextkolom) plus ruim voldoende voor een leesbaar Label
	   (~160px). min-width wint van width:100% zodra de kaart smaller is,
	   dus de rij (en daarmee kop+data samen, want beide zitten in dezelfde
	   overflow-x:auto-tabel hierboven) schuift dan i.p.v. dichtknijpt. */
	min-width: 480px;
}

/* Volle-breedte lijn ONDER de koprij i.p.v. per kolomkop (die aanpak gaf
   de doorbroken rand): één rand op de rij zelf sluit altijd aan, ook al
   verschilt de hoogte van de koptekst per kolom niet. De rand die de
   vendored component zelf al per <td> meegeeft (inline style) wordt
   uitgezet om een dubbele/verspringende lijn te voorkomen. */
.vit-formcard table[data-no] thead tr { border-bottom: 1px solid var(--vit-border); padding-bottom: 8px; }
.vit-formcard table[data-no] th { border-bottom: 0 !important; }

.vit-formcard table[data-no] td,
.vit-formcard table[data-no] th
{
	display: flex;
	align-items: center;
	box-sizing: border-box;
	min-width: 0;
	padding: 6px 10px 6px 0;
	overflow: hidden;
}
.vit-formcard table[data-no] th { font-weight: 700; }

.vit-formcard table[data-no] tr > :first-child { flex: 0 0 34px; }
.vit-formcard table[data-no] tr > :last-child
{ flex: 0 0 28px; padding-right: 0; justify-content: flex-end; }
.vit-formcard table[data-no] tr > :nth-last-child(2) { flex: 0 0 130px; }
/* min-width hier is de eigenlijke fix voor een te brede Label-input: de
   globale "min-width: 0" op alle td/th hieronder (nodig voor de vaste-
   breedte kolommen, i.v.m. overflow:hidden) ontneemt deze flexibele kolom
   ook haar automatische flex-minimumgrootte, waardoor ze bij 2-3 context-
   kolommen (elk 130px) tot een paar px werd dichtgeknepen — de input
   binnenin (min-content breedte >0) kon daar niet in en stak zichtbaar
   uit over de "Waarde vanaf"-kolom ernaast. Met dit ondergrens blijft
   Label altijd leesbaar breed; de tabel schuift dan i.p.v. verder te
   knijpen (overflow-x: auto staat al op table[data-no] hierboven). */
.vit-formcard table[data-no] tr > :nth-last-child(3) { flex: 1 1 auto; min-width: 140px; }
/* Optionele context-kolommen ertussenin (0 t/m 3, zie "Aantal context-
   variabelen") — allemaal dezelfde vaste breedte, ruim genoeg voor zowel
   een vrije-tekstinvoer als het min/max-bereikblokje hieronder. */
.vit-formcard table[data-no] tr > :not(:first-child):not(:last-child):not(:nth-last-child(2)):not(:nth-last-child(3))
{ flex: 0 0 130px; }

/* Min/max-bereikblok (VitWaarderingRangeField, een numerieke context-
   kolom): één grijs-omrand vak met de twee inputs en het streepje erin
   i.p.v. los in de cel, zoals gevraagd. Specifieker dan de generieke
   input-reset hieronder (".vit-formcard table[data-no] input[type=text]"),
   dus geen !important nodig om de eigen breedte/rand te laten winnen.
   padding: 10px verticaal (i.p.v. de eerdere 2px) omdat dit blok anders
   maar ~30px hoog uitviel tegenover de ~44px van de <select> ernaast
   (een "select"-context-kolom, zelfde rij) — die 44px komt van de
   generieke .vit-formcard select-regel verderop (10px padding + border +
   line-height); dezelfde 10px hier trekt de twee kolommen gelijk. */
.vit-formcard table[data-no] .vit-context-range
{
	display: flex;
	align-items: center;
	gap: 4px;
	width: 100%;
	padding: 10px 6px;
	border: 1px solid var(--vit-border);
	border-radius: var(--vit-radius-sm);
	box-sizing: border-box;
}
.vit-formcard table[data-no] .vit-context-range input[type="text"]
{
	flex: 1 1 0;
	width: 0;
	min-width: 0;
	border: 0;
	padding: 0;
	text-align: center;
}
.vit-formcard table[data-no] .vit-context-range-sep { flex: 0 0 auto; color: var(--vit-muted); }

/* De onzichtbare "+"-toevoegrij (tfoot, eerste rij) wijkt af: 2 cellen
   i.p.v. de N van kop/data (een colspan-vulcel + de plus-kolom) — de
   colspan zelf telt niet mee in flex-layout, dus die vulcel moet de rest
   van de rij opvullen zodat het plusje op dezelfde plek als de ×-kolom
   uitkomt. Specifieker dan de generieke regels hierboven, dus die wint. */
.vit-formcard table[data-no] tfoot tr:first-child > td:first-child { flex: 1 1 auto; }

.vit-formcard table[data-no] td > nobr,
.vit-formcard table[data-no] th > nobr
{ display: block; width: 100%; white-space: normal; }

/* De brede input/select-reset hierboven (width:100%;max-width:420px) is
   bedoeld voor de gewone label/veld-rijen van table.table-form, maar
   raakt via afstamming ook de invoervelden bínnen deze MultiField-tabel
   — vandaar te smal en niet passend bij hun eigen (flex-)kolombreedte. */
.vit-formcard table[data-no] input[type="text"],
.vit-formcard table[data-no] select
{ max-width: none; width: 100%; }

/* vit_dashboard_repeater() (settings.inc.php, dashboardcomponenten.post.php
   se kolommen/filters): dynamisch add/remove-(sleep-)rijencomponent,
   visueel op de forms-project-conditiebuilder gemodelleerd. Zelfde platte-
   tabel-platslag-probleem als table[data-no] hierboven (".vit-formcard
   table,tbody,tr,td,th{display:block}" eerder in dit bestand) en dezelfde
   flexbox-rij-oplossing i.p.v. display:table — die laatste gaf bij
   table[data-no] al eens verschillende thead/tbody-kolombreedtes in Chrome
   (zie de toelichting daar), en deze tabel is qua vorm (kop + databody +
   iconenkolom) identiek genoeg om hetzelfde risico te lopen. */
.vit-formcard .vit-repeater-table,
.vit-formcard .vit-repeater-table thead,
.vit-formcard .vit-repeater-table tbody
{ display: block; width: 100%; }

/* Zelfde min-width-plus-overflow-x-scroltruc als table[data-no] hierboven:
   de rechterkolom van het 2-koloms formulier (feedback punt 4) is vaak
   smaller dan wat 3-4 select/tekst-kolommen + icoonkolommen prettig
   leesbaar toont — i.p.v. elke kolom daarvoor tot onleesbaar smal te
   knijpen (live bevestigd: select2 toonde noodgedwongen afgekapte "N...",
   "Hoe ..."-labels) scrolt de repeater-tabel liever lokaal horizontaal. */
.vit-formcard .vit-repeater-table { overflow-x: auto; }

.vit-formcard .vit-repeater-table tr
{
	display: flex; align-items: center; gap: 10px;
	width: 100%; min-width: 620px; margin-bottom: 0; padding: 8px 0;
	border-bottom: 1px solid var(--vit-border-2);
}
.vit-formcard .vit-repeater-table thead tr
{
	border-bottom: 1px solid var(--vit-border); padding-bottom: 8px;
	font-size: 11px; font-weight: 700; color: var(--vit-muted);
	text-transform: uppercase; letter-spacing: .03em;
}
.vit-formcard .vit-repeater-table tbody tr:last-child { border-bottom: 0; }

.vit-formcard .vit-repeater-table td,
.vit-formcard .vit-repeater-table th
{ flex: 1 1 0; min-width: 130px; }

/* Sleepgreep (alleen bij "sorteerbaar", bv. tabel-kolommen — niet bij
   filters, die kennen geen volgorde) en verwijder-kruisje: allebei een
   vaste, kleine iconenkolom i.p.v. de gelijk-verdeelde velden-kolommen
   hierboven — zelfde ":first-child"/":last-child"-vastzetpatroon als
   table[data-no]. */
.vit-formcard .vit-repeater-table tr > .vit-repeater-handle,
.vit-formcard .vit-repeater-table tr > .vit-repeater-remove
{ flex: 0 0 30px; display: flex; align-items: center; justify-content: center; padding: 0; }
.vit-formcard .vit-repeater-table thead tr > :first-child:empty,
.vit-formcard .vit-repeater-table thead tr > :last-child:empty
{ flex: 0 0 30px; }

.vit-repeater-handle { cursor: grab; color: var(--vit-muted); }
.vit-repeater-handle:active { cursor: grabbing; }
.vit-repeater-remove { cursor: pointer; color: var(--vit-muted); }
.vit-repeater-remove:hover { color: var(--vit-down); }

/* Sjabloonrij: altijd verborgen, wordt alleen gekloond (script.js
   initRepeater()) — hogere specificiteit dan de ".vit-repeater-table tr"-
   regel hierboven (extra klasse) dus geen !important nodig om te winnen. */
.vit-formcard .vit-repeater-table tr.vit-repeater-template { display: none; }

.vit-repeater-add
{
	display: inline-flex; align-items: center; gap: 6px;
	margin-top: 10px; padding: 6px 4px;
	color: var(--vit-blue); font-size: 13px; font-weight: 600;
	cursor: pointer;
}
.vit-repeater-add:hover { text-decoration: underline; }
.vit-repeater-add .material-icons { font-size: 18px; }

/* Acties-fieldset (Opslaan/Verwijderen, field.post.php): geen kaart
   (erft de kaartloze reset hierboven), gewoon naast elkaar op de
   grijze paginabg — vandaar géén losse witte kaart meer voor
   Verwijderen zoals voorheen. */
.vit-formcard fieldset.vit-form-actions { display: flex; gap: 12px; }
/* Elke knop is een losse PageForm-veldrij (eigen <tr>, colspan=2, geen
   label) binnen dezelfde table.table-form als overal — de display:flex
   hierboven op de fieldset zelf helpt niet, want die fieldset heeft maar
   één kind (de wrapper-div om de table). Zonder onderstaande regels
   stapelen Opslaan/Verwijderen daardoor onder elkaar i.p.v. naast elkaar
   met een kleine marge, zoals gevraagd. */
.vit-formcard fieldset.vit-form-actions table.table-form tbody
{ display: flex; flex-direction: row; gap: 12px; }
.vit-formcard fieldset.vit-form-actions table.table-form tr
{ margin-bottom: 0; }
/* Een acties-rij kan naast echte submit-knoppen ook een link-knop bevatten
   (a.vit-btn-primary, bv. "Vragenlijst testen" naast "Opslaan" op
   templates.post.php). button.vit-btn heeft margin-top:6px (lucht t.o.v. de
   veldrij erboven) die een <a> niet erft, waardoor de link precies die 6px
   hoger uitkwam dan de knop ernaast. Zelfde marge hier i.p.v. de marge van
   de knop weghalen: dat laatste zou elke bestaande acties-rij in het hele
   project 6px omhoog schuiven. */
.vit-formcard fieldset.vit-form-actions a.vit-btn-primary { margin-top: 6px; }
.vit-formcard fieldset.vit-form-actions button.vit-btn-danger
{
	background: #fff; color: var(--vit-down);
	border: 1px solid var(--vit-down); box-shadow: none;
}
.vit-formcard fieldset.vit-form-actions button.vit-btn-danger:hover
{ background: #fdf1f1; box-shadow: none; }
/* a.vit-btn-danger: zelfde "gevaar"-kleuren als button.vit-btn-danger
   hierboven, maar dan voor een link-knop (geen submit) — bv. "Ontkoppelen"
   naast Opslaan op projectcontact.post.php. Basisvorm (flex/padding/radius)
   van a.vit-btn-primary hergebruikt, kleuren van button.vit-btn-danger. */
.vit-formcard fieldset.vit-form-actions a.vit-btn-danger
{
	display: inline-flex; align-items: center; gap: 8px;
	margin-top: 6px;
	padding: 11px 22px 11px 18px;
	background: #fff; color: var(--vit-down);
	border: 1px solid var(--vit-down); border-radius: 10px;
	font-size: 15px; font-weight: 600; text-decoration: none;
	box-shadow: none; transition: background .15s;
}
.vit-formcard fieldset.vit-form-actions a.vit-btn-danger:hover { background: #fdf1f1; }

/* Icoon: "close" (kruisje) voor élke a.vit-btn-danger-knop, of het nu een
   verwijder-actie is (koppelingen.post.php) of een ontkoppel-actie
   (projectcontact.post.php) — feedback: geen prullenbak-icoon, overal
   hetzelfde kruisje als WebTable's eigen rij-kruisje (components/
   web.table.class.php, icon_remove). Geen aparte .vit-btn-ontkoppelen-
   modifier meer nodig nu beide acties hetzelfde icoon delen. */
.vit-formcard fieldset.vit-form-actions a.vit-btn-danger::before
{ font-family: "Material Icons"; font-size: 19px; line-height: 1; content: "close"; }

/* templates.post.php ("bewerken"): "Template bewerken"-kaart links,
   "Velden"-paneel rechts i.p.v. onder elkaar (klantwens). align-items:
   start zodat de kortere kaart niet uitrekt tot de hoogte van de vaak
   veel langere veldenboom. minmax(0, 1fr) i.p.v. kale 1fr: een "1fr"-
   kolom heeft standaard een automatische minimumbreedte gelijk aan de
   min-content-breedte van zijn inhoud, en de veldenboom rechts (lange
   vraag-/veldnamen in .frm_field_title) kan intrinsiek breder willen
   zijn dan 50% — dan groeit die kolom voorbij zijn 1fr-aandeel en wordt
   de verdeling scheef. minmax(0, 1fr) negeert die intrinsieke inhouds-
   breedte, dwingt zo een echte 50/50-verdeling af, en laat .frm_field_title
   (die al overflow:hidden/text-overflow:ellipsis heeft) daarbinnen
   afkappen i.p.v. de kolom op te rekken. */
.vit-template-edit-grid
{
	display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 20px; align-items: start;
}
/* TIER: BP_STACK */
@media (max-width: 1100px)
{
	.vit-template-edit-grid { grid-template-columns: 1fr; }
}

/* projecten.post.php (bewerken, klantwens): subkopje binnen het
   "Instellingen"-blok (AVG-grondslag/bewaartermijn vs. weergave) — geen
   eigen kaart, alleen een lichte scheiding tussen de twee subsecties van
   dat ene blok. */
.vit-instellingen-subkop
{
	font-size: 13px; font-weight: 700; margin: 0 0 12px; padding-top: 20px;
	border-top: 1px solid var(--vit-border);
	color: var(--vit-muted); text-transform: uppercase; letter-spacing: .03em;
}
.vit-instellingen-subkop:first-child { padding-top: 0; border-top: 0; }

/* Label naast het invoerveld i.p.v. erboven — alleen voor de eigenlijke
   label/invoerveld-rijen (table.table-form); de buitenste structuur-table
   van PageForm (fieldset-wrapper, geen th) blijft simpelweg gestapeld via
   de brede reset hierboven. Specifieker selector (table.table-form) wint
   van die reset zonder hem te hoeven aanpassen. */
.vit-formcard table.table-form tr
{
	display: flex;
	align-items: flex-start;
	gap: 16px;
	margin-bottom: 16px;
}
.vit-formcard table.table-form tr:last-child { margin-bottom: 0; }
.vit-formcard table.table-form th
{
	flex: 0 0 150px;
	max-width: 150px;
	text-align: left;
	font-weight: 500;
	font-size: 13px;
	color: var(--vit-muted);
	margin: 0;
	/* Invoervelden hebben padding-top 10px + 1px rand; deze padding-top
	   zet de labeltekst op dezelfde regel als de eerste tekstregel van
	   het invoerveld i.p.v. er los boven te zweven. */
	padding-top: 11px;
	line-height: 1.3;
}
.vit-formcard table.table-form td { flex: 1 1 auto; min-width: 0; }

.vit-formcard input[type="text"],
.vit-formcard input[type="number"],
.vit-formcard input[type="email"],
.vit-formcard input[type="date"],
.vit-formcard input[type="file"],
.vit-formcard select,
.vit-formcard textarea
{
	width: 100%;
	max-width: 420px;
	padding: 10px 12px;
	border: 1px solid var(--vit-border);
	border-radius: 10px;
	/* 14px, gelijk aan table.vit-table (klantwens: overal dezelfde
	   fontgrootte — was 15px, apart van de 14px die de rest van de app als
	   basis-tekstgrootte gebruikt). */
	font-size: 14px;
	font-family: inherit;
	background: #fff;
	color: var(--vit-ink);
}
.vit-formcard textarea { min-height: 90px; resize: vertical; }
.vit-formcard input:focus, .vit-formcard select:focus, .vit-formcard textarea:focus
{ outline: none; border-color: var(--vit-blue); box-shadow: 0 0 0 3px rgba(31,111,196,.15); }

/* Alleen-lezen formulier (field.post.php zodra de vragenlijst niet meer
   in concept is — de mutatie zelf is al server-side geblokkeerd, dit is
   puur de visuele indicatie): alle invoervelden krijgen dezelfde grijze
   niet-klikbare look als een disabled input, zonder dat elk FormFieldForm-
   veldtype (checkbox/select/tekst/...) individueel hoeft te weten dat het
   read-only is. Ná de algemene input-styling hierboven, want zelfde
   specificiteit (class + attribuut) — anders wint de volgorde daar. */
.vit-formcard-readonly input, .vit-formcard-readonly select,
.vit-formcard-readonly textarea
{
	pointer-events: none; background: var(--vit-bg); color: var(--vit-muted);
}
/* Vragenlijst-hoofdformulier (naam/sleutel/omschrijving): dat gebruikt
   losse readonly-inputs i.p.v. de vit-formcard-readonly-wrapper hierboven
   (de status-select ernaast moet wél bewerkbaar blijven) — zelfde grijze
   look als een disabled <select> ernaast, anders lijkt readonly per ongeluk
   nog gewoon bewerkbaar. */
.vit-formcard input[readonly], .vit-formcard textarea[readonly]
{ background: var(--vit-bg); color: var(--vit-muted); }

/* CKEditor-veld (PortalFormWebTextEditor) zodra readonly: web.texteditor.
   class.php rendert dan geen vergrendelde CKEditor-instance (eigen
   toolbar-chrome, ziet er anders uit dan de rest) maar een kale div met de
   opgeslagen HTML en deze generieke class — hier dezelfde doos-vorm/kleur
   als de losse readonly-inputs hierboven, i.p.v. de fallback-look uit
   forms-lib's field.view.php. */
.vit-formcard .frm_texteditor_readonly
{
	width: 100%; max-width: 420px; min-height: 90px; padding: 10px 12px;
	border: 1px solid var(--vit-border); border-radius: 10px;
	font-size: 14px; font-family: inherit;
	background: var(--vit-bg); color: var(--vit-muted);
}

/* Date-component (dag/maand/jaar als losse type="text"-velden binnen één
   td, zie tr_form_startdatum e.a.): de brede input[type="text"]-regel
   hierboven forceert ze anders naar width:100%, waardoor ze onder elkaar
   uitvallen i.p.v. naast elkaar op één regel. Zelfde specificiteit als die
   regel, dus alleen de latere volgorde in dit bestand beslist — vandaar
   hierna. */
.vit-formcard input.input-text-date-day,
.vit-formcard input.input-text-date-year
{ display: inline-block; width: auto; max-width: none; text-align: center; }
.vit-formcard input.input-text-date-day { width: 36px; }
.vit-formcard input.input-text-date-year { width: 58px; }
.vit-formcard input[type="submit"],
.vit-formcard input[name="command"][type="submit"],
button.vit-btn
{
	display: inline-flex; align-items: center; gap: 8px;
	margin-top: 6px;
	padding: 11px 24px;
	background: var(--vit-gradient); color: #fff; border: 0; border-radius: 10px;
	font-size: 15px; font-weight: 600; font-family: inherit; line-height: 1.5; cursor: pointer;
	box-shadow: 0 6px 16px rgba(31,111,196,.28);
	transition: box-shadow .15s, transform .1s, background .15s;
	/* Browsers geven <button>/<input type=submit> een eigen UA-default
	   line-height ("normal", ~1.15) die de geërfde line-height:1.5 van body
	   blokkeert — <a>.vit-btn-primary erft die wél. Zonder deze regel is
	   button.vit-btn daardoor een paar pixels lager dan een even grote
	   a.vit-btn-primary, ondanks identieke padding/font-size. */
	appearance: none; -webkit-appearance: none;
}
.vit-formcard input[type="submit"]:hover,
button.vit-btn:hover
{ background: var(--vit-gradient-hover); box-shadow: 0 8px 20px rgba(22,166,166,.35); }
.vit-formcard input[type="submit"]:active,
button.vit-btn:active { transform: translateY(1px); }
button.vit-btn .material-icons { font-size: 18px; }

/* -------------------------------------------------------------- E-mailveld */

.vit-email-field { position: relative; display: inline-block; width: 100%; }
.vit-formcard .vit-email-field { max-width: 420px; }
.vit-email-field input[type="text"],
.vit-email-field input[type="email"] { width: 100%; max-width: none; padding-right: 40px; }
.vit-email-icon
{
	position: absolute; top: 50%; right: 10px; transform: translateY(-50%);
	display: inline-flex; align-items: center; justify-content: center;
	color: var(--vit-muted); text-decoration: none;
}
.vit-email-icon .material-icons { font-size: 18px; }
.vit-email-icon:hover { color: var(--vit-ink); }

/* ---------------------------------------------------------- Wachtwoordveld ---
   Oog-icoon om het wachtwoord even leesbaar te maken (klantwens: tikfout-
   check). De wrapper + knop worden generiek toegevoegd door script.js (elk
   <input type="password"> dat al in de pagina staat) — geen enkele PHP-
   component hoeft hiervoor aangepast te worden, dus dit werkt ook op het
   inlogscherm (gedeelde ROES Portal Framework Password-component). Zelfde
   opzet als .vit-email-field hierboven. */
.vit-password-field { position: relative; display: inline-block; width: 100%; }
.vit-formcard .vit-password-field { max-width: 420px; }
.vit-password-field input[type="password"],
.vit-password-field input[type="text"] { width: 100%; max-width: none; padding-right: 40px; }
.vit-password-toggle
{
	position: absolute; top: 50%; right: 6px; transform: translateY(-50%);
	display: inline-flex; align-items: center; justify-content: center;
	width: 28px; height: 28px; padding: 0;
	border: none; background: none;
	color: var(--vit-muted); cursor: pointer;
}
.vit-password-toggle .material-icons { font-size: 18px; }
.vit-password-toggle:hover { color: var(--vit-ink); }

/* ---------------------------------------------- Relevantie/validatie-builder ---
   frm_condition/frm_relevance/frm_validation (lib/forms, gedeeld door de
   relevantie- en validatie-regelbouwer op field.post.php) leveren zelf géén
   CSS mee — forms.css is bewust alleen voor de eind-gebruiker-gerichte
   runtime-form (.frm-*, zie PROJECT.md §7.4), dit is een consumer-concern.
   Referentie: portlets/forms/layout/backend/header_normal.inc.php (het
   forms-portlet's eigen backend), hier overgenomen en herstijld op de
   vitalytics-tokens. De frm_*_template-regels zijn geen cosmetische keuze:
   zonder display:none renderen de JS-kloonsjablonen als een zichtbare
   extra (kapotte) groep/rij. */
.frm_relevance_intro, .frm_validation_intro { font-size: 13px; color: var(--vit-muted); margin-bottom: 10px; }
.frm_relevance_effect, .frm_relevance_text { margin-top: 8px; }
.frm_relevance_effect label, .frm_relevance_text label, .frm_validation_message label
{ display: inline-block; min-width: 80px; color: var(--vit-muted); font-size: 13px; }
.frm_relevance_effect select, .frm_relevance_text input,
.frm_validation_message input
{
	padding: 8px 10px; border: 1px solid var(--vit-border); border-radius: 8px;
	font-size: 14px; font-family: inherit; background: #fff; color: var(--vit-ink);
}

.frm_condition_group
{
	border: 1px solid var(--vit-border);
	border-radius: var(--vit-radius-sm);
	padding: 10px 16px 6px;
	margin-bottom: 14px;
	background: #fafcfd;
	position: relative;
}
.frm_condition_group + .frm_condition_group::before
{
	content: attr(data-and-label);
	position: absolute; top: -9px; left: 16px;
	background: #fafcfd; padding: 0 8px;
	font-weight: 600; color: var(--vit-muted); font-size: 11px; letter-spacing: .04em;
	border: 1px solid var(--vit-border); border-radius: 4px;
}
.frm_condition_table { width: 100%; border-collapse: collapse; background: transparent; }
.frm_condition_table th
{ text-align: left; font-size: 11px; font-weight: 600; color: var(--vit-muted); padding: 4px 8px; text-transform: uppercase; letter-spacing: .04em; }
.frm_condition_table td { padding: 4px 8px; vertical-align: middle; font-size: 13px; }
.frm_condition_table select, .frm_condition_table input[type="text"]
{
	width: 100%; padding: 8px 10px; border: 1px solid var(--vit-border); border-radius: 8px;
	font-size: 14px; font-family: inherit; background: #fff; color: var(--vit-ink);
}
.frm_condition_table tr.frm_condition_sep td
{ color: var(--vit-blue); font-size: 11px; padding: 2px 8px; letter-spacing: .04em; font-weight: 700; }
.frm_condition_table tfoot td { padding: 6px 8px 2px; }
.frm_condition_actions { text-align: right; white-space: nowrap; }

.frm_condition_btn
{
	cursor: pointer; color: var(--vit-faint);
	display: inline-flex; align-items: center; justify-content: center;
	width: 26px; height: 26px; border-radius: 7px; margin-left: 4px;
	transition: background .15s, color .15s;
}
.frm_condition_btn:hover { background: var(--vit-bg); color: var(--vit-blue); }

.frm_condition_addgroup, .frm_validation_addrule
{
	cursor: pointer; color: var(--vit-blue); font-size: 13.5px; font-weight: 600;
	padding: 6px 0 4px; display: inline-flex; align-items: center; gap: 6px;
}
.frm_condition_addgroup:hover, .frm_validation_addrule:hover { text-decoration: underline; }

.frm_validation_rule
{
	border: 1px solid var(--vit-border); border-radius: var(--vit-radius-sm);
	padding: 12px 16px 8px; margin-bottom: 14px; background: #fff;
}
.frm_validation_rule_header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px; }
.frm_validation_rule_label { font-weight: 700; color: var(--vit-ink); font-size: 12px; text-transform: uppercase; letter-spacing: .04em; }
.frm_validation_btn { cursor: pointer; color: var(--vit-faint); padding: 2px 4px; }
.frm_validation_btn:hover { color: var(--vit-down); }

.frm_condition_template, .frm_validation_template { display: none !important; }

/* ------------------------------------------------------- Formule-editor ---
   PortalFormWebFormulaEditor (lib/forms): het "Formule"-veld van een
   calculation/vit_bmi/vit_waardering-veld op field.post.php — een
   contenteditable div met een $-autocomplete. Net als de regelbouwer
   hierboven levert de lib hiervoor géén CSS mee (die staat inline in
   portlets/forms/layout/backend/header_normal.inc.php, het forms-portlet's
   eigen backend, dat Vitalytics niet laadt). Zonder deze regels is de
   autocomplete een kale <ul> met bullets die de pagina-layout opzij duwt
   i.p.v. een zwevend paneel, en zijn de {$key}-chips platte tekst.

   position:relative op de wrapper is functioneel, geen opmaak: de dropdown
   eronder is absolute en heeft die ouder nodig als positioneringscontext. */
.frm_formula_editor { position: relative; width: 100%; }
.frm_formula_input
{
	width: 100%; box-sizing: border-box; min-height: 40px; max-width: 100%;
	padding: 9px 12px;
	border: 1px solid var(--vit-border); border-radius: 8px; background: #fff;
	font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
	font-size: 13px; line-height: 1.6; color: var(--vit-ink);
	white-space: pre-wrap; overflow-wrap: anywhere; word-break: break-word;
	overflow-x: hidden; overflow-y: auto;
}
.frm_formula_input:focus
{ outline: none; border-color: var(--vit-blue); box-shadow: 0 0 0 3px rgba(31,111,196,.15); }
.frm_formula_input:empty::before { content: attr(data-placeholder); color: var(--vit-faint); }

/* .frm_chip is dezelfde pil in een CKEditor-omschrijving; zelfde opmaak. */
.frm_formula_chip,
.frm_chip
{
	display: inline-block; padding: 1px 8px; margin: 0 1px;
	background: #e8f1fb; color: var(--vit-blue);
	border: 1px solid #c3dcf5; border-radius: 10px;
	font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
	font-size: 12px; line-height: 1.5; white-space: nowrap; user-select: all;
}
.frm_formula_chip::selection,
.frm_chip::selection { background: var(--vit-blue); color: #fff; }

/* Meerregelig (Enter = newline, opgeslagen in de formule), met commentaar
   (/* ... *\/) en functienamen in eigen kleur. De live editor kleurt via de
   CSS Custom Highlight API (::highlight, raakt de DOM niet aan, dus caret en
   undo blijven intact); de read-only weergave gebruikt dezelfde kleuren via
   spans. Aparte regels per selector: een browser zonder ::highlight laat een
   gecombineerde regel anders helemaal vallen. */
.frm_formula_editor_readonly { white-space: pre-wrap; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 13px; line-height: 1.6; }
::highlight(frm-formula-comment)  { color: #5a7d4a; }
::highlight(frm-formula-function) { color: var(--vit-purple); }
.frm_formula_comment  { color: #5a7d4a; }
.frm_formula_function { color: var(--vit-purple); }

.frm_formula_dropdown
{
	position: absolute; top: 100%; left: 0; z-index: 1000;
	margin: 4px 0 0; padding: 4px 0; list-style: none;
	min-width: 240px; max-width: 100%; max-height: 240px; overflow-y: auto;
	background: #fff; border: 1px solid var(--vit-border);
	border-radius: var(--vit-radius-sm); box-shadow: var(--vit-shadow);
}
.frm_formula_option
{ padding: 7px 12px; cursor: pointer; display: flex; gap: 10px; align-items: baseline; }
.frm_formula_option.is-active,
.frm_formula_option:hover { background: var(--vit-bg); }
.frm_formula_option_key
{
	flex: 0 0 auto; color: var(--vit-blue);
	font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 13px;
}
.frm_formula_option_title
{ flex: 1; font-size: 12px; color: var(--vit-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ------------------------------------------------- Login/requestpassword extra */

.vit-loginform label
{
	display: block;
	font-size: 13px;
	font-weight: 500;
	color: var(--vit-muted);
	margin: 14px 0 6px;
}
.vit-loginlink { color: var(--vit-blue); font-size: 14px; text-decoration: none; }
.vit-loginlink:hover { text-decoration: underline; }

/* ------------------------------------------------------------------ Profiel/form */

/* layout/profiel.inc.php: links de persoonsgegevens/wachtwoord-fieldsets
   onder elkaar, rechts de TFA-fieldset ernaast i.p.v. ook onder elkaar
   (feedbackpunt) — zelfde minmax(0, 1fr)-aanpak als .vit-template-edit-grid
   hierboven, om dezelfde reden (geen kolom die breder groeit dan zijn
   aandeel). */
.vit-profile-grid
{
	display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 20px; align-items: start;
}
/* TIER: BP_STACK */
@media (max-width: 1100px)
{
	.vit-profile-grid { grid-template-columns: 1fr; }
}

.vit-form { max-width: 720px; }
.vit-form-card { padding: 20px 22px 24px; margin-bottom: 20px; }
.vit-form-card h2 { margin: 0 0 4px; font-size: 16px; font-weight: 700; }
.vit-form-help { margin: 0 0 14px; color: var(--vit-muted); font-size: 13.5px; }

.vit-form-grid
{
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: 14px 18px;
	margin-top: 14px;
}
.vit-field { display: flex; flex-direction: column; }
.vit-field.span2 { grid-column: 1 / -1; }
/* profiel.inc.php: voornaam/tussenvoegsel/achternaam op 1 regel i.p.v.
   voornaam+tussenvoegsel naast elkaar met achternaam eronder (feedbackpunt)
   — smal invoerveld voor tussenvoegsel, want dat bevat meestal maar een
   paar tekens. grid-column 1/-1 spant de volle breedte van de omringende
   .vit-form-grid (2 kolommen), net als .vit-field.span2 hierboven. */
.vit-naam-rij
{
	grid-column: 1 / -1;
	display: grid;
	grid-template-columns: 1fr 110px 1fr;
	gap: 14px 18px;
}
/* TIER: BP_STACK */
@media (max-width: 1100px)
{
	.vit-naam-rij { grid-template-columns: 1fr; }
}
.vit-field label { font-size: 13px; font-weight: 500; color: var(--vit-muted); margin-bottom: 6px; }
.vit-field-note { color: var(--vit-faint); font-weight: 400; }
/* Labelregel vóór een tri-state toestemmings-radiogroep (deelnemers.post.php,
   fieldset "Toestemming", 2026-09-24-003) — Radio zelf heeft geen ingebouwd
   groeplabel, vandaar deze losse paragraaf ervoor. */
.vit-radiogroep-label { font-size: 13px; font-weight: 600; color: var(--vit-muted); margin: 14px 0 4px; }
/* Read-only PII-veld (anonimisering, §4.5) i.p.v. een bewerkbare invoer —
   zelfde muted+italic-behandeling als .vit-historie-verouderd. */
.vit-veld-niet-zichtbaar { font-style: italic; color: var(--vit-muted); }
.vit-field input
{
	width: 100%;
	padding: 10px 12px;
	border: 1px solid var(--vit-border);
	border-radius: 10px;
	font-size: 15px;
	font-family: inherit;
}
.vit-field input:focus
{
	outline: none;
	border-color: var(--vit-blue);
	box-shadow: 0 0 0 3px rgba(31,111,196,.15);
}

.vit-form-actions { margin-top: 4px; }
.vit-btn-primary
{
	display: inline-flex;
	align-items: center;
	gap: 8px;
	padding: 11px 22px 11px 18px;
	background: var(--vit-gradient);
	color: #fff;
	border: 0;
	border-radius: 10px;
	font-size: 15px;
	font-weight: 600;
	text-decoration: none;
	cursor: pointer;
	box-shadow: 0 6px 16px rgba(31,111,196,.28);
	transition: box-shadow .15s, transform .1s, background .15s;
}
/* line-height:1, net als .material-icons hierboven: zonder expliciete
   line-height erft dit ::before-icoon de unitless line-height:1.5 van body
   en herberekent die op zíjn eigen font-size (19px * 1.5 = 28.5px) — hoger
   dan de 22.5px regelhoogte van de knoptekst, waardoor a.vit-btn-primary
   een paar pixels hoger uitviel dan button.vit-btn. */
.vit-btn-primary::before { font-family: "Material Icons"; font-size: 19px; line-height: 1; content: "add"; }
/* .vit-btn-save: zelfde stijl als .vit-btn-primary, maar dan voor een
   opslaan-actie (bv. profiel) i.p.v. "iets nieuws aanmaken" — ander icoon. */
.vit-btn-save::before { content: "check"; }
/* .vit-btn-start: zelfde stijl, maar voor "begin een activiteit"
   (bv. Testsessie -> Start meten) i.p.v. "iets nieuws aanmaken". */
.vit-btn-start::before { content: "play_arrow"; }
/* .vit-btn-rapport: zelfde stijl, maar voor "PDF genereren" (meetstation.post.php). */
.vit-btn-rapport::before { content: "picture_as_pdf"; }
/* .vit-btn-generate: zelfde stijl, voor de "Genereren"-knoppen op de
   Rapportages-kaart (Excel én PDF delen hetzelfde icoon — feedback
   2026-09-25: geen apart download-/pdf-icoon meer per formaat). */
.vit-btn-generate::before { content: "description"; }
/* .vit-btn-history: zelfde stijl, maar voor "Historie" naast Opslaan
   (bv. projecten.post.php) i.p.v. "iets nieuws aanmaken". */
.vit-btn-history::before { content: "history"; }
/* .vit-btn-import/-export/-bulk-add/-bulk-clean: zelfde stijl, voor de
   deelnemers-acties onder de tabel (feedback: allemaal knoppen naast
   elkaar i.p.v. losse links/knop). */
.vit-btn-import::before { content: "upload_file"; }
.vit-btn-export::before { content: "download"; }
.vit-btn-bulk-add::before { content: "group_add"; }
.vit-btn-bulk-clean::before { content: "delete_sweep"; }
/* .vit-btn-duplicate: zelfde stijl, maar voor "Dupliceren" (vragenlijsten.
   post.php) i.p.v. "iets nieuws aanmaken". */
.vit-btn-duplicate::before { content: "content_copy"; }
/* .vit-btn-send: zelfde stijl, voor "insturen"/"versturen" (bv. de online
   vragenlijst, vragenlijst.post.php) i.p.v. "iets nieuws aanmaken". */
.vit-btn-send::before { content: "send"; }
/* .vit-btn-afronden/-heropenen: zelfde stijl, voor het afronden (read-only
   maken) resp. heropenen van een vragenlijst-instantie (vit_instantie_knoppen_js()). */
.vit-btn-afronden::before { content: "task_alt"; }
.vit-btn-heropenen::before { content: "lock_open"; }
.vit-instantie-readonly .frm-chapter-body { opacity: .8; }
.vit-btn-primary:hover { background: var(--vit-gradient-hover); box-shadow: 0 8px 20px rgba(22,166,166,.35); }
.vit-btn-primary:active { transform: translateY(1px); }
.vit-btn-primary:visited { color: #fff; }

/* Rapportage "Gebruiken (PDF)": deelnemerkeuze als full-width select2
   tussen Opslaan en de Genereer-knop (rapportages.post.php, feedback). */
.vit-rapport-deelnemerkeuze { display: block; margin: 0 0 16px; }
.vit-rapport-deelnemerkeuze select { width: 100%; }
.vit-rapport-deelnemerkeuze .select2-container { display: block; width: 100% !important; margin-bottom: 12px; }

/* "Nieuwe X"/"Toevoegen"-knoppen onder een lijst (klantwens: toevoeg-knop
   altijd onder de tabel, niet erboven): wat lucht t.o.v. de kaart erboven. */
.vit-content > a.vit-btn-primary { margin-right: 12px; margin-top: 16px; margin-bottom: 16px; }
.vit-content > a.vit-back-link { vertical-align: middle; }
/* Twee back-links naast elkaar (bv. Importeren + Exporteren op
   deelnemers.post.php) krijgen anders geen ruimte — die volgen elkaar in de
   HTML direct op, zonder tekstnode ertussen. */
.vit-content > a.vit-back-link + a.vit-back-link { margin-left: 12px; }

/* Ruimte tussen twee los-gestapelde kaarten op hetzelfde scherm (bv.
   field.post.php's bewerk-formulier + verwijder-formulier). Bewust gescoped
   op directe kinderen van .vit-content, zodat kaarten binnen een grid
   (.vit-kpi-grid/.vit-panel-grid) hun eigen `gap` behouden i.p.v. een
   dubbele marge te krijgen. */
.vit-content > .vit-card + .vit-card { margin-top: 20px; }

/* "← Terug naar ..."-links op drill-down-schermen. */
a.vit-back-link
{
	display: inline-block;
	margin-bottom: 14px;
	color: var(--vit-muted);
	font-size: 13.5px;
	text-decoration: none;
}
a.vit-back-link:hover { color: var(--vit-ink); text-decoration: underline; }

/* koppelingen.post.php: technisch sync-verloop na "Synchroniseren" —
   voortgangsbalk + stappenlijst (incl. de JSON-ruwe-data-regel en de
   antwoorden-matchregels, feedback 2026-09-29: dit was eerst een losse
   <pre>-dump + lib_dump(), nu allemaal gewoon in deze ene lijst). Tijdelijke
   functionaliteit, dus zoveel mogelijk bestaande kaart-/knopstijlen
   hergebruikt i.p.v. een nieuw merk-breed component. */
.vit-sync-verloop { margin-top: 20px; }
.vit-sync-verloop-head
{
	display: flex; align-items: center; justify-content: space-between; gap: 12px;
	margin-bottom: 14px;
}
.vit-sync-verloop-head h2 { margin: 0; font-size: 16px; font-weight: 700; }

.vit-sync-progress
{
	background: var(--vit-bg); border: 1px solid var(--vit-border); border-radius: var(--vit-radius-sm);
	overflow: hidden; height: 30px; margin-bottom: 14px;
}
.vit-sync-progress-bar
{
	height: 100%; display: flex; align-items: center; justify-content: center;
	color: #fff; font-size: 13px; font-weight: 700; transition: width .3s ease;
}
.vit-sync-progress-bar.success { background: var(--vit-up); }
.vit-sync-progress-bar.error   { background: var(--vit-down); }

.vit-sync-stappen { list-style: none; margin: 0; padding: 0; }
.vit-sync-stappen li
{
	padding: 7px 0 7px 22px; position: relative; font-size: 13.5px; color: var(--vit-ink);
	border-top: 1px solid var(--vit-border-2);
	/* De JSON-ruwe-data-regel (feedback 2026-09-29) kan één lange, spatieloze
	   string zijn — zonder dit breekt zo'n regel uit de kaart i.p.v. netjes
	   mee te lopen zoals elke andere stap-regel. */
	overflow-wrap: anywhere;
}
.vit-sync-stappen li:first-child { border-top: 0; }
/* Material Icons-ligatuur i.p.v. een losse "›"-letter (zoals overal elders
   in dit bestand, bv. .vit-btn-primary::before hierboven) — de externe
   stylesheet-charset van shell.css (via @import, geen eigen @charset-regel)
   viel op deze omgeving terug op iets anders dan UTF-8, waardoor een kaal
   Unicode-teken hier als mojibake ("â€") rendert. Een ASCII-ligatuurnaam is
   charset-onafhankelijk. */
.vit-sync-stappen li::before
{
	content: "chevron_right"; font-family: "Material Icons"; font-size: 15px; line-height: 1;
	position: absolute; left: 4px; top: 9px; color: var(--vit-teal); font-weight: 700;
}

/* Meldingen */
.vit-alert
{
	display: flex;
	align-items: flex-start;
	gap: 10px;
	max-width: 720px;
	padding: 14px 16px;
	border-radius: var(--vit-radius-sm);
	margin-bottom: 20px;
	font-size: 14px;
}
.vit-alert .material-icons { font-size: 20px; flex: 0 0 auto; }
.vit-alert ul { margin: 6px 0 0; padding-left: 18px; }
.vit-alert.success { background: #e7f6ee; color: #1c6b3f; border: 1px solid #bfe6cf; }
.vit-alert.error   { background: #fdecec; color: #a02722; border: 1px solid #f4c9c7; }

/* ------------------------------------------------------------------ Responsive
   Zie het tier-overzicht bovenaan dit bestand (na :root) voor de volledige
   uitleg van BP_STACK (1100px) / BP_LABELS (780px) / BP_MOBILE (600px). De
   drie tiers staan hieronder bewust in aflopende volgorde van breedte: bij
   overlappende regels (bv. .vit-kpi-grid, hieronder zowel op BP_STACK als
   BP_LABELS gezet) wint anders de latere/smallere regel niet via bron-
   volgorde. */

/* TIER: BP_STACK — kaarten/panelen die naast elkaar stonden, onder elkaar. */
@media (max-width: 1100px)
{
	.vit-kpi-grid       { grid-template-columns: repeat(2, 1fr); }
	.vit-panel-grid     { grid-template-columns: 1fr; }
	.vit-form-grid      { grid-template-columns: 1fr; }
	/* Feedback: het dynamische dashboard (4 koloms, .vit-dashboard-grid
	   hierboven) zelfde 4→2→1-cascade als .vit-kpi-grid. Een component se
	   colspan (inline "grid-column: span min(N, var(--vit-dashboard-cols))",
	   dashboard.view.php) leest hier het aantal daadwerkelijk beschikbare
	   kolommen terug via de custom property hieronder — zonder deze klem
	   zou bv. een colspan-4-tabel op dit 2-koloms-tier alsnog een 2e,
	   impliciete kolom naast het 2-koloms-rooster forceren (CSS Grid klemt
	   een auto-geplaatst item NIET vanzelf aan het expliciete rooster,
	   live bevestigd: grid-template-columns:1fr + een colspan-2-item gaf
	   getComputedStyle 2 tracks i.p.v. 1). */
	.vit-dashboard-grid { grid-template-columns: repeat(2, 1fr); --vit-dashboard-cols: 2; }
}

/* TIER: BP_LABELS — labels boven het veld i.p.v. ernaast. */
@media (max-width: 780px)
{
	.vit-kpi-grid       { grid-template-columns: 1fr; }
	.vit-dashboard-grid { grid-template-columns: 1fr; --vit-dashboard-cols: 1; }
	/* Extra margin-bottom (was 16px) geeft voldoende witruimte tot het
	   volgende label zodra de rijen onder elkaar staan i.p.v. naast het
	   veld — anders lopen gestapelde rijen visueel in elkaar over
	   (testdag-tablet/telefoon, PROJECT.md §12 "testdag-bruikbaar" /
	   mobile-first). */
	.vit-formcard table.table-form tr { flex-direction: column; align-items: stretch; gap: 6px; margin-bottom: 24px; }
	.vit-formcard table.table-form th { flex: 0 0 auto; max-width: none; padding-top: 0; }
}

/* TIER: BP_MOBILE — menu verdwijnt automatisch, opent als overlay. */
@media (max-width: 600px)
{
	/* Mobiel: sidebar staat standaard buiten beeld; de hamburger (#vit-nav-
	   toggle, zie frontend/backend script.js) schuift 'm in via .nav-open,
	   als overlay bóven de content (position: fixed — de content zelf
	   verschuift niet, in tegenstelling tot de in-/uitklap-breedtetoggle op
	   desktop hieronder). Het ::after-scrim verduistert de content erachter
	   zodat zichtbaar is dat het menu er los overheen "hangt"; buiten de
	   sidebar klikken sluit 'm weer (zelfde click-handler in script.js —
	   die ziet de klik op het scrim als "klik buiten .vit-sidebar"). */
	.vit-sidebar { position: fixed; z-index: 40; transform: translateX(-100%); transition: transform .2s; }
	.vit-shell.nav-open .vit-sidebar { transform: translateX(0); }
	.vit-shell.nav-open::after
	{
		content: "";
		position: fixed;
		inset: 0;
		z-index: 39;
		background: rgba(12,35,64,.45);
		animation: vit-scrim-in .15s ease;
	}
	@keyframes vit-scrim-in { from { opacity: 0; } to { opacity: 1; } }
}

/* TIER: BP_MOBILE, desktop-kant (min-width) */
@media (min-width: 601px)
{
	/* Boven BP_MOBILE: sidebar staat standaard in beeld (neemt vaste breedte
	   in het flex-shell in); dezelfde hamburger/.nav-open-toggle schuift 'm
	   hier in-/uitklappend weg i.p.v. als overlay in — vandaar de omgekeerde
	   regel t.o.v. mobiel hierboven. --vit-side-w naar 0 laten lopen (i.p.v.
	   transform) zodat de hoofdinhoud automatisch meeschuift om de
	   vrijgekomen ruimte. */
	.vit-sidebar { transition: width .22s ease, flex-basis .22s ease, opacity .15s ease; opacity: 1; overflow: hidden; }
	.vit-shell.nav-open .vit-sidebar { width: 0; flex-basis: 0; opacity: 0; }
}
