/* VGR Food — gedeelde app-header (laag 1) + app-subnavigatie (laag 2).
   Vervangt .topbar (styles.css), .pp-top (planning.css), .an-header (analyse.css) en
   .admin-topbar (admin.css). Ontwerp: mockups/header-opties.html §02 + §04.

   Elke pagina heeft zijn eigen kolombreedte en -padding, en zet daarvoor --vgr-top-max /
   --vgr-top-pad. Die twee krijgen hun default NIET hier in :root maar als var()-fallback op
   de plek van gebruik. Reden: niet elke pagina laadt dit bestand op dezelfde positie —
   productie laadt appheader.css vóór styles.css, analyse erna. Met een :root-default zou de
   winnaar dus per pagina verschillen en zou de pagina-waarde soms stil worden overruled;
   een var()-fallback springt alleen bij als de pagina de variabele helemaal niet zet. */
:root {
  --vgr-navy: #1e2a44;
  --vgr-blauw: #2f5fe0;
  --vgr-sans: "IBM Plex Sans", system-ui, -apple-system, "Segoe UI", sans-serif;
  --vgr-mono: "IBM Plex Mono", ui-monospace, "SFMono-Regular", Consolas, monospace;
  /* De hoogte van de balk. Vier plekken moeten dit getal kennen -- de balk zelf, zijn
     min-height, de sluier die er precies ONDER begint en het paneel dat eronder hangt.
     Als variabele, want met vier losse 60'jes verschijnt er bij een wijziging stilletjes
     een naad tussen balk en sluier, zonder foutmelding. */
  --vgr-top-h: 60px;
  /* De zijmarge van de BALK en de subnav — bewust één vast getal, niet de per-pagina
     --vgr-top-pad. Zie het blok "WAAROM DE BALK DE PAGINAKOLOM NIET MEER VOLGT" hieronder. */
  --vgr-top-rand: 32px;
}

/* WAAROM DE BALK DE PAGINAKOLOM NIET MEER VOLGT (besluit Bart 21-08-2026: "uitlijning wil ik
   overal hetzelfde"). Tot nu droeg .vgr-top-binnen de max-width en padding van de pagina
   eronder, zodat balk en inhoud uitlijnden. Gevolg: de Portaal-knop stond op elke pagina ergens
   anders, want elke pagina heeft een andere kolom — op 1920px gemeten 32px (planning, volle
   breedte), 68px (artikelen 1840), 156px (productie/expeditie/analyse 1680) en 504px (beheer
   960). Dat viel pas op toen het logo naar het midden van het SCHERM ging terwijl de knoppen in
   de kolom bleven zitten. De balk is het frame van de app en niet van één pagina, dus hij houdt
   nu overal dezelfde afstand tot de schermrand (--vgr-top-rand); de subnav eronder volgt 'm,
   anders staan twee chrome-lagen met verschillende linkerranden boven elkaar.
   #vgrInhoud houdt zijn eigen kolom — dáár hoort de paginabreedte wél thuis. */

/* ---------- de pagina-kolom ---------- */
/* Elke dashboardpagina hangt zijn inhoud aan #vgrInhoud. Breedte en zijpadding komen uit
   --vgr-top-max/--vgr-top-pad, zodat het getal maar op één plek per pagina staat. (De balk
   gebruikte diezelfde twee tot 21-08-2026; zie het blok hierboven.) Verticale padding blijft van de pagina zelf
   (die verschilt echt: 28/90 op productie, 14/28 op analyse).
   :where() = specificiteit 0, dus een pagina-regel (bv. de mobiele padding:16px op
   .pp-main) wint gewoon; dit is een default, geen dwang. */
:where(#vgrInhoud) {
  max-width: var(--vgr-top-max, none);
  margin-inline: auto;
  padding-inline: var(--vgr-top-pad, 32px);
}

/* ---------- splash + geen-toegang ---------- */
/* Splash: volvlak in de headerkleur met het witte VGR-logo + spinner, tot de auth-sessie
   hersteld is. .out zet opacity 0 → daarna .hidden. Geen-toegang: sessie geldig, maar geen
   tegel-recht op dit dashboard.
   Stond identiek in styles.css én planning.css (zelfde markup, zelfde shared/splash.js,
   alleen de keyframe hernoemd). Eén implementatie hier; de defaults zijn de tokens van de
   nieuwere pagina's, de oudere familie (styles.css) zet zijn eigen waarden. */
#splash { position:fixed; inset:0; z-index:50; display:flex; flex-direction:column;
          align-items:center; justify-content:center; gap:26px;
          background:var(--vgr-splash-bg, var(--vgr-navy));
          transition:opacity .4s ease; }
#splash.out { opacity:0; }
.splash-logo { width:200px; height:auto; }
.splash-spin { width:34px; height:34px; border-radius:50%;
               border:3px solid rgba(255,255,255,.22); border-top-color:#fff;
               animation:vgr-splash-rot .8s linear infinite; }
.splash-sub { margin:0; font-size:13px; letter-spacing:.02em; color:#c2cbe0; }
@keyframes vgr-splash-rot { to { transform:rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .splash-spin { animation:none; } }

/* ---------- skelet-shimmer (gedeeld) ---------- */
/* De sweep stond identiek in styles.css (.pd-skel), analyse.css (.an-skel) en planning.css
   (.pp-skel) — drie kopieën van dezelfde gradient + keyframes (audit 29-08). De basisvorm
   (maat, achtergrondtint) blijft van de pagina; alleen de beweging staat hier één keer. */
.pd-skel::after, .an-skel::after, .pp-skel::after {
  content:""; position:absolute; inset:0; transform:translateX(-100%);
  background:linear-gradient(90deg,transparent,rgba(148,163,184,.28),transparent);
  animation:vgr-skel-sweep 1.3s ease-in-out infinite;
}
@keyframes vgr-skel-sweep { to { transform:translateX(100%); } }
@media (prefers-reduced-motion:reduce) {
  .pd-skel::after, .an-skel::after, .pp-skel::after { animation:none; }
}

#geenToegang { min-height:100vh; display:flex; align-items:center; justify-content:center; padding:16px; }
.loginCard { background:var(--vgr-kaart-bg, #fff); border:1px solid var(--vgr-kaart-lijn, #e5e7eb);
             border-radius:16px; box-shadow:var(--vgr-kaart-schaduw, 0 1px 2px rgba(15,23,42,.04));
             width:23rem; padding:2rem; }
.loginCard h1 { margin:0 0 .3rem; font-size:1.3rem; }
.loginCard .sub { color:var(--vgr-kaart-sub, #6b7280); font-size:.85rem; margin:0 0 1.4rem; }
.loginCard .backlink { display:inline-flex; align-items:center; gap:.4rem; margin-top:.4rem;
                       color:var(--vgr-kaart-link, var(--vgr-blauw)); font-weight:700; text-decoration:none; }
.loginCard .backlink:hover { text-decoration:underline; }

/* ---------- splash bij een sprong binnen het platform ---------- */
/* De inline <script> in de head zet .vgr-warm zodra deze tab het platform al binnen is.
   Deze regel moet dus vóór de eerste paint gelden — vandaar in dit render-blocking
   stylesheet en niet in JS. */
html.vgr-warm #splash { display: none !important; }

/* ---------- laag 1: de donkere balk ---------- */
/* Twee lagen, net als de oude .topbar/.topbar-inner: de balk is FULL-BLEED (navy over de
   volle schermbreedte) en alleen de binnenlaag draagt de max-width van de pagina-kolom.
   Zet je de max-width op de balk zelf, dan zweeft hij op een breed scherm in het midden
   met de pagina-achtergrond ernaast. */
/* De klasse staat STATISCH in de HTML (niet pas door JS): alleen dan bestaat de
   view-transition-name al op het moment dat de browser de nieuwe pagina vastlegt, en heeft
   de balk vanaf de eerste paint zijn kleur. min-height reserveert de hoogte zolang hij nog
   leeg is — anders springt de inhoud eronder alsnog omlaag zodra de balk gevuld wordt. */
/* position+z-index (niet enkel view-transition-name): `view-transition-name` maakt van
   .vgr-top/.vgr-subnav zelf al een stacking-context (CSS View Transitions-spec), maar zonder
   een EIGEN expliciete z-index concurreert die context op wortelniveau alsnog op DOM-volgorde
   met de rest van de pagina -- en verliest, want #appHeader/#appSubnav staan vóór #vgrInhoud.
   Gemeten (Taak 3.1, 20-08-2026): op Bezetting viel de hele drawer (incl. .vgr-drawer's eigen
   z-index:45) zichtbaar ACHTER de witte subnav-strook (#appSubnav komt ná #appHeader in de
   DOM); op Analyse ving een gewone (position:relative, z-index:auto) chart-bucket de sluier-
   klik af, want ook de sluier (z-index:38) telt alleen ROND #appHeader mee, niet op wortel-
   niveau. Elke expliciete positieve z-index hier lost het op (promoveert de hele balk naar
   stacking-laag 7, boven alle gewone z-index:auto/0-elementen); 6/5 houdt de balk nog netjes
   ONDER echte modals (bv. planning .pp-modal-detail:100) en sleep-tooltips (9999+). */
.vgr-top {
  position: relative;
  z-index: 6;
  background: var(--vgr-navy);
  color: #fff;
  font-family: var(--vgr-sans);
  font-size: 13.5px;
  min-height: var(--vgr-top-h);
}
.vgr-top-binnen {
  height: var(--vgr-top-h);
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 0 var(--vgr-top-rand);
  position: relative;
}

/* ?hal=N op Productie opent een schone hal-weergave zonder balk (app.js applyDeepLink).
   Die regel stond op .topbar; hij moet mee, anders blijft de balk daar staan. */
body.tvmode .vgr-top,
body.tvmode .vgr-subnav { display: none; }

/* Het merk staat LOS uit de flex-flow. Zou het gewoon meelopen, dan bepaalt de breedte van
   links en rechts waar het uitkomt en staat het nooit echt in het midden.
   pointer-events uit: het vangt geen klikken af van wat eronder ligt.
   Bewust GEEN link: de weg terug loopt via één knop, niet via twee dingen. */
.vgr-merk {
  position: absolute; left: 50%; top: 0; height: 100%; transform: translateX(-50%);
  display: flex; align-items: center; pointer-events: none; z-index: 1;
}
.vgr-merk img { height: 28px; width: auto; display: block; }

/* De twee flanken mogen het merk nooit raken: elk hooguit tot net voor het midden. Zonder
   deze grens schuiven de menu-items bij een smal venster onder het logo door. */
.vgr-links, .vgr-rechts {
  display: flex; align-items: center; gap: 10px; min-width: 0;
  max-width: calc(50% - 90px); z-index: 2;
}
.vgr-links { flex: 1 1 auto; }
.vgr-rechts { margin-left: auto; justify-content: flex-end; flex: 0 0 auto; gap: 14px; }

/* ---------- de drawer-knop ---------- */
.vgr-drw {
  display: inline-flex; align-items: center; gap: 8px; flex: none; cursor: pointer; font-family: inherit;
  color: #dfe6f2; background: rgba(255, 255, 255, 0.08); border: 1px solid rgba(255, 255, 255, 0.22);
  border-radius: 10px; padding: 8px 11px; font: 500 13px var(--vgr-sans);
}
.vgr-drw:hover { background: rgba(255, 255, 255, 0.18); color: #fff; }
.vgr-drw[aria-expanded="true"] { background: #fff; color: var(--vgr-navy); border-color: #fff; }
.vgr-drw [data-lucide] { width: 18px; height: 18px; }
.vgr-drw .caret { width: 14px; height: 14px; opacity: 0.75; transition: transform 0.15s ease; }
.vgr-drw[aria-expanded="true"] .caret { transform: rotate(180deg); }

.vgr-streep { width: 1px; height: 24px; background: rgba(255, 255, 255, 0.16); flex: none; }

/* ---------- de menu-items: de apps van jouw categorie ----------
   Geen rand, geen vulling: een rij woorden, niet een rij knoppen. Het icoon blijft staan maar
   is gedempt -- het label draagt de betekenis, het icoon helpt alleen herkennen. */
/* Het item van de pagina waar je NU staat is geen <a> maar een <span class="nu"> (appheader.js:
   klikken op je eigen pagina wiste de querystring). Elke regel die de vorm van een item bepaalt
   selecteert daarom op :is(a, .nu) -- de hover-regels bewust niet, want dat item is niet
   klikbaar. */
.vgr-nav { display: flex; align-items: center; gap: 2px; min-width: 0; overflow: hidden; height: 100%; }
.vgr-nav :is(a, .nu) {
  display: inline-flex; align-items: center; gap: 9px; white-space: nowrap; flex: none;
  text-decoration: none; color: #9fb0cd; font: 400 14px var(--vgr-sans);
  padding: 8px 13px; border-radius: 8px;
}
.vgr-nav a:hover { color: #fff; background: rgba(255, 255, 255, 0.09); }
.vgr-nav [data-lucide] { width: 16px; height: 16px; flex: none; color: #7587a8; }
.vgr-nav a:hover [data-lucide] { color: #cdd9ee; }

/* ACTIEF — zachte vulling zonder rand. Duidelijk genoeg om op afstand te zien welk scherm je
   voor je hebt, maar het blijft een markering achter het woord en geen omlijnde knop.
   LET OP: [aria-current="page"] MET waarde. Een kale [aria-current] matcht ook
   aria-current="false" — en dat patroon staat al in de repo (artikelen.js schrijft
   aria-selected="${aan}"). Zonder de waarde lichten álle items op. */
.vgr-nav :is(a, .nu)[aria-current="page"] { color: #fff; font-weight: 600; background: rgba(255, 255, 255, 0.15); }
.vgr-nav :is(a, .nu)[aria-current="page"] [data-lucide] { color: #8fb4ff; }

/* GEEN VERSCHUIVING BIJ HET WISSELEN (Taak 1.2).
   De actieve staat is vetgedrukt en vet is breder dan normaal, wat alles rechts van het
   actieve item deed opschuiven zodra je van pagina wisselde. Elk label reserveert daarom
   altijd zijn VETTE breedte -- een onzichtbare kopie van dezelfde tekst op gewicht 600, als
   blok met hoogte 0, dus zonder eigen ruimte in de balk. */
.vgr-nav :is(a, .nu) > span { display: inline-block; }
.vgr-nav :is(a, .nu) > span::after {
  content: attr(data-tekst); display: block; height: 0; overflow: hidden;
  visibility: hidden; font-weight: 600; pointer-events: none;
}

/* ---------- "waar ben ik", alleen als de menu-items wegvallen ---------- */
.vgr-hier {
  display: none; align-items: center; gap: 8px; flex: none;
  color: #fff; font-weight: 600; font-size: 13.5px; white-space: nowrap;
}
.vgr-hier [data-lucide] { width: 16px; height: 16px; color: #8fb0ff; }

/* Status-slot: de pagina vult 'm (live-sync, data t/m, stamdata). Staat bewust BUITEN de
   <nav> — een statusmelding is geen navigatie. Leeg = neemt geen ruimte in. */
.vgr-status {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 12.5px; color: #aab6cc; white-space: nowrap;
}
.vgr-status:empty { display: none; }
.vgr-status [data-lucide] { width: 14px; height: 14px; }
.vgr-status .ok { color: #4ade80; }
/* Twee schrijfwijzen: app.js/expeditie.js zetten de klasse op het <i>, analyse.js op de
   wrapper zelf. Beide moeten amber worden. */
.vgr-status .warn, .vgr-status .stale { color: #fbbf24; }
.vgr-status.stale [data-lucide], .vgr-status.warn [data-lucide] { color: #fbbf24; }
/* Rust: de sync staat buiten zijn venster stil. Klopt, dus geen amber — gewoon de kleur van
   de omringende tekst, zodat het icoon meldt zonder aandacht op te eisen. Alleen op het icoon:
   anders dan bij stale zet geen enkel dashboard deze stand op de wrapper. */
.vgr-status .rust { color: #aab6cc; }
.vgr-status b { color: #fff; font: 500 12.5px var(--vgr-mono); }

/* ---------- avatar (web/shared/avatar.js) ----------
   Gedeeld met de activiteitslog op het planbord, zodat je jezelf daar herkent aan de kleur die
   hier rechtsboven staat. Kleur komt binnen als --ava-bg/--ava-ink; die staan vast per persoon
   in portal.profiel.avatar_kleur. */
.vgr-ava {
  display: inline-grid; place-items: center; flex: none;
  width: 32px; height: 32px; border-radius: 999px;
  font: 700 12px/1 var(--vgr-sans); letter-spacing: 0.01em;
  -webkit-user-select: none; user-select: none;
  background: var(--ava-bg, #dfe4ee); color: var(--ava-ink, #3a4763);
}
/* Geen persoon (import/cron/migratie): neutraal, met een glyph in plaats van initialen. */
.vgr-ava-sys { background: #eceef2; color: #6b7280; }
.vgr-ava-sys [data-lucide] { width: 14px; height: 14px; }
/* Een bronsysteem met een eigen merk (avatar.js#MERK). Witte schijf met een dunne rand: het merk
   draagt zelf al kleur, dus een gekleurde vulling eronder zou ermee vechten — en op grijs verliest
   het rood z'n contrast. Het teken staat op ~55% van de schijf, dezelfde optische maat als de
   initialen ernaast, zodat een lijst met beide niet gaat hobbelen. */
.vgr-ava-merk { background: #fff; box-shadow: inset 0 0 0 1px #e2e6ee; }
.vgr-ava-merk svg { width: 55%; height: 55%; display: block; }
/* In de navy balk: kleiner, en een dunne lichte rand zodat de schijf niet in de balk oplost. */
.vgr-ava-kop {
  width: 22px; height: 22px; font-size: 10px;
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.28);
}

/* ---------- accountmenu ---------- */
.vgr-acc { position: relative; flex: none; }
.vgr-acc-knop {
  display: inline-flex; align-items: center; gap: 8px;
  color: #fff; background: rgba(255, 255, 255, 0.09);
  border: 1px solid rgba(255, 255, 255, 0.2); border-radius: 9px;
  padding: 6px 11px; font: 500 13px var(--vgr-sans); cursor: pointer;
}
.vgr-acc-knop:hover { background: rgba(255, 255, 255, 0.18); }
.vgr-acc-knop [data-lucide] { width: 16px; height: 16px; }
.vgr-caret { width: 14px; height: 14px; color: #a9b5cb; transition: transform 0.15s ease; }
.vgr-acc-knop[aria-expanded="true"] .vgr-caret { transform: rotate(180deg); }

.vgr-acc-menu {
  position: absolute; top: calc(100% + 8px); right: 0; min-width: 216px; z-index: 60;
  background: #fff; border: 1px solid #e2e8f0; border-radius: 12px; padding: 6px;
  box-shadow: 0 14px 38px rgba(15, 23, 42, 0.22);
}
.vgr-acc-menu.hidden { display: none; }
.vgr-acc-item {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 9px 11px; border-radius: 8px; border: 0; background: none;
  color: #0f172a; text-decoration: none; font: 400 14px var(--vgr-sans);
  cursor: pointer; text-align: left;
}
.vgr-acc-item:hover { background: #eff3f9; }
.vgr-acc-item [data-lucide] { width: 16px; height: 16px; color: #94a3b8; }
.vgr-acc-item--uit { color: #b91c1c; }
.vgr-acc-item--uit [data-lucide] { color: #dc2626; }

/* ---------- de drawer — icoonraster per categorie (Taak 2.1) ---------- */
/* De sluier begint ÓNDER de balk (--vgr-top-h = .vgr-top-binnen's hoogte), niet op inset:0.
   In de mockup zijn sluier en paneel body-broers ónder een balk met z-index 40; hier zijn het
   kinderen van #appHeader, en een kind kan nooit onder de ACHTERGROND van zijn ouder schilderen
   — een z-index op .vgr-top-binnen zou dus wel de knoppen vrijmaken maar de navy ertussen
   gedimd laten. Gemeten (review R.1, 20-08-2026): met inset:0 gaf elementFromPoint op de
   drawer-knop, op elk nav-item én op de accountknop alle vier DIV.vgr-sluier — een tweede klik
   op de knop sloot de drawer dus niet (aria-expanded bleef "true") — en de balk was meetbaar
   gedimd (navy [30,42,68] -> [24,35,58]). Alles onder de balk blijft gewoon gedekt, dus een
   klik naast het paneel sluit nog steeds. */
.vgr-sluier {
  position: fixed; inset: var(--vgr-top-h) 0 0; z-index: 38; background: rgba(15, 23, 42, 0.34);
  opacity: 0; pointer-events: none; transition: opacity 0.16s ease;
}
.vgr-sluier.aan { opacity: 1; pointer-events: auto; }

/* `left` wordt bij het openen door koppelDrawer() gezet (het paneel hangt aan de KNOP, niet aan
   de viewport — zie de uitleg daar); de waarde hier is alleen de stand vóór de eerste opening.
   visibility hoort bij opacity: alleen `opacity:0` liet de dichte drawer in de tabvolgorde én in
   de a11y-boom staan (gemeten: Tab#5 t/m #13 landden op alle 9 drawer-links, en de aria-snapshot
   van de dichte drawer was identiek aan die van de open drawer). `visibility` is wél
   transitionbaar (`display` niet), dus de fade-out blijft intact: hidden treedt pas ná de
   transitie in. Zelfde oplossing als het accountmenu, dat het al goed deed. */
.vgr-drawer {
  position: fixed; top: calc(var(--vgr-top-h) + 6px); left: var(--vgr-top-rand); z-index: 45;
  width: 352px; max-height: calc(100vh - 80px); overflow: auto; padding: 8px;
  background: #fff; border: 1px solid #dde4ee; border-radius: 14px;
  /* Eigen tekstkleur, want het paneel is een wit vlak binnen een balk die `color:#fff` zet.
     Zonder deze regel erft alles wat zijn kleur niet zelf zet dat wit — en dat overkwam de
     vetgedrukte "Alle tegels" (de regel eronder en de tegelnamen zetten hun kleur wél zelf,
     dus die bleven zichtbaar en verborgen het probleem). */
  color: #0f172a;
  box-shadow: 0 22px 60px rgba(15, 23, 42, 0.28);
  opacity: 0; transform: translateY(-6px) scale(0.985); pointer-events: none; visibility: hidden;
  transform-origin: top left;
  transition: opacity 0.15s ease, transform 0.15s ease, visibility 0.15s;
}
.vgr-drawer.aan { opacity: 1; transform: none; pointer-events: auto; visibility: visible; }

/* De bovenste rij wijst naar het portaal op "/". De KNOP heet al "Portaal", dus dat woord kan
   hier niet nog een keer: de knop opent een lade, deze rij brengt je ergens naartoe. */
.vgr-drawer .portaalrij {
  display: flex; align-items: center; gap: 12px; text-decoration: none; color: inherit;
  padding: 11px 12px; border-radius: 11px; background: #f3f6fc; border: 1px solid #e2eaf7;
}
.vgr-drawer .portaalrij:hover { background: #e9effb; }
.vgr-drawer .portaalrij .vak {
  width: 36px; height: 36px; border-radius: 10px; background: var(--vgr-navy); color: #fff;
  display: grid; place-items: center; flex: none;
}
.vgr-drawer .portaalrij .vak [data-lucide] { width: 19px; height: 19px; }
.vgr-drawer .portaalrij b { display: block; font-size: 14px; font-weight: 600; }
.vgr-drawer .portaalrij em { display: block; font-style: normal; font-size: 12.5px; color: #475569; line-height: 1.35; }

.vgr-drawer .kop {
  display: block; font: 600 10.5px/1 var(--vgr-mono); letter-spacing: 0.15em;
  text-transform: uppercase; color: #8d9bb4; padding: 15px 12px 7px;
}
.vgr-drawer .raster { display: grid; grid-template-columns: repeat(3, 1fr); gap: 2px; }
/* min-height houdt de tegels op één hoogte, ook als een naam over twee regels loopt
   ("Comscale E-wegers"). Zonder die hoogte hobbelt de rij. */
.vgr-drawer .tegel {
  position: relative; display: flex; flex-direction: column; align-items: center; gap: 8px;
  min-height: 96px; padding: 13px 6px 12px; border-radius: 11px;
  text-decoration: none; color: #0f172a; text-align: center; cursor: pointer;
  border: 0; background: none; font-family: inherit;
}
.vgr-drawer .tegel:hover { background: #f1f5fb; }
.vgr-drawer .tegel .vak {
  width: 40px; height: 40px; border-radius: 12px; display: grid; place-items: center;
  background: #eef2f9; color: #41506b; flex: none;
}
.vgr-drawer .tegel .vak [data-lucide] { width: 20px; height: 20px; }
/* Tegels met een eigen logo (Exact Online, Carenet) i.p.v. een Lucide-icoon. Ruimer dan de
   20px van een icoon, want een logo draagt zijn eigen witruimte al mee; `contain` houdt een
   liggend logo onvervormd binnen het vierkante vak. */
.vgr-drawer .tegel .vak img { width: 27px; height: 27px; object-fit: contain; }
.vgr-drawer .tegel .naam { font-size: 12.5px; font-weight: 500; line-height: 1.25; }
.vgr-drawer .tegel[aria-current="page"] .vak { background: var(--vgr-blauw); color: #fff; }
.vgr-drawer .tegel[aria-current="page"] .naam { color: var(--vgr-blauw); font-weight: 600; }
/* Externe koppelingen openen in een nieuw tabblad; dat hoort zichtbaar te zijn vóór je klikt. */
.vgr-drawer .tegel .ext { position: absolute; top: 9px; right: 9px; width: 12px; height: 12px; color: #a9b5c9; }

/* ---------- laag 2: subnavigatie binnen de app ---------- */
/* z-index lager dan .vgr-top (zie de uitleg daar): moet zelf ook boven gewone pagina-inhoud
   uitkomen, maar altijd ONDER de balk blijven, anders wint de subnav het van de drawer. */
.vgr-subnav {
  position: relative;
  z-index: 5;
  background: #fff; border-bottom: 1px solid #e2e8f0;
  font-family: var(--vgr-sans);
  min-height: 40px;
}
/* Zonder klasse = deze pagina heeft geen subnav; dan ook geen gereserveerde hoogte. */
#appSubnav:not(.vgr-subnav) { min-height: 0; }
.vgr-subnav-binnen {
  display: flex; align-items: center; gap: 2px; height: 40px;
  padding: 0 var(--vgr-top-rand);
}
/* Link (andere pagina) en knop (andere weergave binnen de pagina) zien er identiek uit —
   voor de gebruiker is dat verschil niet interessant. */
.vgr-subnav a,
.vgr-subnav button {
  display: inline-flex; align-items: center; gap: 8px; height: 100%; padding: 0 14px;
  color: #475569; text-decoration: none; font: 400 14px var(--vgr-sans);
  border: 0; border-bottom: 2px solid transparent; margin-bottom: -1px;
  background: none; cursor: pointer;
}
.vgr-subnav a:hover,
.vgr-subnav button:hover { color: #0f172a; }
.vgr-subnav a[aria-current="page"],
.vgr-subnav button[aria-current="page"] { color: var(--vgr-blauw); font-weight: 600; border-bottom-color: var(--vgr-blauw); }
.vgr-subnav [data-lucide] { width: 16px; height: 16px; }
/* Laadicoon op de aangeklikte tab zelf (renderSubnav `bezig`). Hergebruikt de keyframes van de
   splash-spinner hierboven -- geen tweede rotatie-animatie in dit bestand. */
.vgr-subnav .spin { animation: vgr-splash-rot 0.8s linear infinite; }
@media (prefers-reduced-motion: reduce) { .vgr-subnav .spin { animation-duration: 1.6s; } }

/* ---------- focus ---------- */
/* Wit met offset: het blauw uit admin.css (#4f86ff) is op navy te zwak om als
   focusindicator te dienen. In de witte subnav juist wél blauw. */
.vgr-top a:focus-visible,
.vgr-top button:focus-visible { outline: 2px solid #fff; outline-offset: 2px; border-radius: 8px; }
.vgr-acc-menu a:focus-visible,
.vgr-acc-menu button:focus-visible,
.vgr-subnav a:focus-visible,
.vgr-subnav button:focus-visible,
.vgr-drawer a:focus-visible,
.vgr-drawer button:focus-visible { outline: 2px solid var(--vgr-blauw); outline-offset: -2px; border-radius: 6px; }

/* Skip-link: er staan nu N+2 tabstops vóór de inhoud, dus die is de moeite waard. */
.vgr-skip {
  position: absolute; left: 8px; top: -60px; z-index: 70;
  background: #fff; color: var(--vgr-navy); font: 600 13px var(--vgr-sans);
  padding: 8px 14px; border-radius: 8px; text-decoration: none;
  transition: top 0.15s ease;
}
.vgr-skip:focus { top: 8px; }

/* ---------- smal scherm ---------- */
/* Taak 1.3 (20-08-2026): opnieuw gemeten met Playwright op de ECHTE pagina's (niet de
   mockup), sweep 1600->340px in stappen van 10px, per pagina met zijn eigen --vgr-top-pad/
   --vgr-top-max en zijn eigen (langste realistische) statustekst. LET OP: sinds 21-08-2026
   volgt de balk die paginakolom niet meer (hij loopt overal over de volle breedte), dus op de
   pagina's die een max-width hadden is er nu MEER ruimte dan toen gemeten — deze getallen zijn
   daar een veilige bovengrens geworden, geen scherpe meting meer. Twee dingen zijn getoetst:
   afkapping (.vgr-nav scrollWidth > clientWidth) en overlap (rechterrand .vgr-links / linker-
   rand .vgr-rechts die het gecentreerde logo raakt). Methode per breekpunt: het bundel-effect
   met !important uitzetten (dus doen alsof het nog niet had geschakeld) en dan zoeken naar de
   breedte waar het écht misgaat -- dat is de krapste correcte waarde, maatgevend is de
   pagina/categorie die het eerst faalt. Scriptharnas: scratchpad (Playwright-inlogpatroon uit
   Taak 1.2, zie .agent/MEMORY.md [header-drawer]).
     - 1220->1200: Dashboards (Productie/Expeditie/Analyse, 3 menu-items) faalt bij 1200px
       (nav scrollWidth 333 > clientWidth 331); Plannen/Stamdata faalden pas bij 950px of
       nooit. Dashboards is dus maatgevend.
     - 1180->980: alleen Artikelen (langste statustekst: aantal + Exact/Carenet-ouderdom)
       faalt, bij 980px (rechts-rand 510.3 < merk-rechts 513.6). Productie/Expeditie/Analyse
       (kortere statustekst) faalden nergens in de hele sweep -- 1180 was dus veel te vroeg.
     - 780->760: bundelt vier dingen tegelijk (logo static, nav weg, "waar ben ik" aan,
       padding 16px); alle vier tegelijk teruggedraaid getest (anders test je een combinatie
       die nooit bestaat) gaf 640px als overlap-drempel (links-rand 285.8 > merk-links 281.4)
       -- maar de volle sweep met dat getal ingebouwd liet een TWEEDE, eerder gemiste faalvorm
       zien: tussen 1200 en 640 toont de nav nog altijd het ene actieve item, en dat item past
       zelf niet meer zodra .vgr-links (calc(50% - 90px), krimpt mee met het viewport) te smal
       wordt -- pure afkapping, geen overlap. Maatgevend Productie: scrollWidth 114 > client-
       Width 111 bij 760px, schoon vanaf 770px. 760 dekt dus beide faalvormen.
     - 470: ongewijzigd. Met .vgr-hier geforceerd zichtbaar tot 340px trad er op GEEN enkele
       pagina afkapping of overlap op (onder 780px is het logo al static, dus "overlap met het
       logo" is daar sowieso geen vraag meer) -- er is geen bewijs voor een ander getal binnen
       het gemeten bereik, dus dit blijft de mockup-waarde.
   Bevestigd: volle sweep met deze vier getallen, alle 8 pagina's (productie/expeditie/analyse/
   planning/bezetting/artikelen/medewerkers/admin) x 127 breedtes = 0 afkappingen, 0 overlaps. */
@media (max-width: 980px) { .vgr-status { display: none; } }

@media (max-width: 1200px) {
  .vgr-top-binnen { gap: 9px; }
  .vgr-nav a:not([aria-current="page"]) { display: none; }
  /* Alleen de naam weg, niet de avatar (Taak 1.4): avatarHtml() rendert die als
     <span class="vgr-ava">, een kaal ">span" laat 'm dus meeverdwijnen. */
  .vgr-acc-knop > span:not(.vgr-ava) { display: none; }
}

@media (max-width: 760px) {
  :root { --vgr-top-rand: 16px; }
  .vgr-merk { position: static; transform: none; order: -1; }
  .vgr-links, .vgr-rechts { max-width: none; }
  .vgr-nav { display: none; }
  .vgr-hier { display: inline-flex; }
  .vgr-drawer { width: min(352px, calc(100vw - 32px)); }
  .vgr-drawer .raster { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 470px) { .vgr-hier { display: none; } }

@media (prefers-reduced-motion: reduce) {
  .vgr-drawer, .vgr-sluier, .vgr-drw .caret { transition: none; }
}

/* ---------- printen ---------- */
/* Navigatie hoort niet op papier. Stond alleen in bezetting.css (op .pp-top bij naam);
   planning.css/styles.css/analyse.css hadden helemaal geen printregel, dus die printten
   hun balk gewoon mee. Eén regel hier dekt alle pagina's. */
@media print {
  .vgr-top, .vgr-subnav, .vgr-skip { display: none !important; }
}

/* ---------- toast (gedeeld, web/shared/toast.js) ---------- */
/* Admin heeft een eigen #toast in zijn shell mét eigen (donkere) styling; die wint daar via
   admin.css. Deze regels dekken de pagina's die zelf geen toast-markup hebben — de helper
   maakt het element dan aan met de klasse .vgr-toast. */
.vgr-toast {
  position: fixed; right: 24px; bottom: 24px; z-index: 80;
  display: flex; align-items: center; gap: 8px;
  padding: 0.75rem 1.1rem; border-radius: 11px;
  background: var(--vgr-navy); color: #fff;
  font: 500 13.5px var(--vgr-sans);
  box-shadow: 0 12px 30px rgba(15, 23, 42, 0.28);
  opacity: 0; transform: translateY(8px); pointer-events: none;
  transition: opacity 0.18s ease, transform 0.18s ease;
}
.vgr-toast.show { opacity: 1; transform: translateY(0); pointer-events: auto; }
/* Groen past bij de vaste check-icoon-toast (admin/import). Het planbord stuurt per actie een
   eigen icoon mee (lock, trash-2, ban); daar zou groen liegen, dus dat zet currentColor. */
.vgr-toast [data-lucide] { width: 17px; height: 17px; color: var(--vgr-toast-icoon, #6ee7a0); }
.vgr-toast--fout [data-lucide] { color: #fca5a5; }
@media (prefers-reduced-motion: reduce) { .vgr-toast { transition: none; } }

/* ---------- de balk blijft staan tijdens het schakelen ---------- */
/* Elke sprong binnen het platform is een echte paginanavigatie, dus de balk wordt opnieuw
   opgebouwd. Met de cache staat hij er binnen ~60 ms, maar in dat venster is hij even wég —
   en dat leest als "de header herlaadt". Cross-document view transitions lossen precies dit
   op: de browser houdt het oude beeld vast tot de nieuwe pagina klaar is en morpht de
   elementen met dezelfde `view-transition-name` in elkaar. Omdat de balk op beide pagina's
   identiek van vorm en plaats is, zie je hem simpelweg staan blijven.
   Browsers zonder ondersteuning (Firefox/Safari) negeren dit en navigeren gewoon. */
@view-transition { navigation: auto; }

.vgr-top { view-transition-name: vgr-top; }
.vgr-subnav { view-transition-name: vgr-subnav; }

/* De inhoud eronder mag kort overvloeien, maar kort: een trage crossfade voelt als
   vertraging, terwijl de winst juist zit in het uitblijven van de flits. */
::view-transition-old(root),
::view-transition-new(root) { animation-duration: 90ms; }
/* De balk zelf niet laten faden — hij hoort onbeweeglijk te lijken. */
::view-transition-group(vgr-top),
::view-transition-group(vgr-subnav) { animation-duration: 0s; }

/* Wie beweging uitzet wil ook de vertraging niet die een transitie meebrengt: dan helemaal
   geen view transition, niet alleen de crossfade eruit. */
@media (prefers-reduced-motion: reduce) {
  @view-transition { navigation: none; }
}
