/* Efficient Schoon — stylesheet
   Uitgesplitst uit efficient-schoon-app.html op 2026-08-10 (optimalisatieslag,
   punt 5: single-file/CSS-split). Reden: deze CSS verandert veel minder vaak
   dan de JS-logica in het HTML-bestand, en kan als apart bestand door de
   browser gecachet worden — bij een refresh/nieuwe sessie hoeft de styling
   dan niet elke keer opnieuw gedownload te worden, alleen het HTML-bestand.

   BELANGRIJK bij deployen/updaten: dit bestand hoort NAAST
   efficient-schoon-app.html te staan, met exact deze bestandsnaam
   (efficient-schoon-app.css) — het HTML-bestand verwijst ernaar met
   <link rel="stylesheet" href="efficient-schoon-app.css">. Bij het uploaden
   van een nieuwe versie van de app dus VOORTAAN ALTIJD BEIDE bestanden
   samen kopiëren/uploaden, anders mist de gestylede app zijn opmaak. */

  /* Opmaak-opschoning (2026-08-26, op verzoek van Jose, "diepe scan" vervolg):
     10 plekken die letterlijk background:#fff schreven zijn hier vervangen
     door var(--card) — zelfde waarde (--card is #ffffff), maar nu via het
     bestaande variabelen-systeem, zodat een latere aanpassing van de
     kaart-/oppervlaktekleur (bv. een donker thema) hier ook wordt opgepikt.
     Bewust NIET aangepakt: de losse #fff's die wit als TEKST-/icoonkleur op
     een gekleurde achtergrond gebruiken (bv. color:#fff op de topbar/actieve
     tab/knoppen) — dat is een ander concept dan --card (oppervlaktekleur) en
     zou door var(--card) te hergebruiken juist verwarrend worden. Ook bewust
     ongemoeid: de status-tintkleuren bij .badge/.card.alert/.caution/.clear
     (bv. #fef3c7, #dcfce7, #f0fdf4) — die zijn per plek bewust verschillende
     tinten van dezelfde status (zie de toelichting bij .card.alert hierboven),
     geen echte duplicaten, dus geen zinvolle centralisatie zonder de tinten
     zelf te veranderen. */
  :root{
    --primary:#3b6fb6;
    --primary-dark:#2f5a95;
    --primary-light:#dce8f7;
    --bg:#f4f6f7;
    --card:#ffffff;
    --text:#1f2937;
    --muted:#6b7280;
    --border:#e5e7eb;
    --danger:#dc2626;
    --warn:#d97706;
    --caution:#ca8a04;
    --ok:#16a34a;
    --overdue:#7c3aed;
    --waiting:#0284c7;
    --radius:12px;
  }
  *{box-sizing:border-box;-webkit-tap-highlight-color:transparent;}
  html{-webkit-text-size-adjust:100%;}
  body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;background:var(--bg);color:var(--text);overflow-x:hidden;}
  #app{max-width:1100px;margin:0 auto;min-height:100vh;min-height:100dvh;display:flex;flex-direction:column;}

  header.topbar{background:var(--primary);color:#fff;padding:12px 14px;display:flex;align-items:center;justify-content:space-between;gap:10px;flex-wrap:wrap;position:sticky;top:0;z-index:20;box-shadow:0 2px 6px rgba(0,0,0,.12);}
  header.topbar .brand{display:flex;align-items:center;gap:10px;font-weight:700;font-size:17px;min-width:0;flex-shrink:0;}
  header.topbar .brand .logo{width:32px;height:32px;background:var(--card);border-radius:8px;display:flex;align-items:center;justify-content:center;color:var(--primary);font-size:18px;}
  header.topbar .brand img.brand-logo{height:28px;width:auto;max-width:140px;object-fit:contain;display:block;}
  header.topbar .user-info{display:flex;align-items:center;gap:8px;font-size:13px;min-width:0;}
  header.topbar .user-info span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:38vw;}
  header.topbar button.logout{background:rgba(255,255,255,.15);border:none;color:#fff;padding:9px 12px;border-radius:8px;cursor:pointer;font-size:13px;flex-shrink:0;touch-action:manipulation;}
  header.topbar button.logout:hover{background:rgba(255,255,255,.28);}

  nav.tabs{position:relative;display:flex;gap:4px;background:var(--card);padding:6px;margin:14px 16px 0;border-radius:var(--radius);box-shadow:0 1px 3px rgba(0,0,0,.06);overflow-x:auto;-webkit-overflow-scrolling:touch;}
  nav.tabs button{flex:1;white-space:nowrap;padding:12px 14px;border:none;background:transparent;border-radius:8px;cursor:pointer;font-size:14px;font-weight:600;color:var(--muted);touch-action:manipulation;}
  nav.tabs button.active{background:var(--primary);color:#fff;}
  /* NIEUW: tweede rij (subtabs) onder de actieve hoofdgroep — iets compacter en
     losstaand van de hoofdnavigatie, zodat duidelijk is dat dit een subniveau is. */
  nav.tabs.subtabs{margin:8px 16px 0;padding:4px;background:transparent;box-shadow:none;}
  nav.tabs.subtabs button{padding:8px 12px;font-size:13px;font-weight:500;background:var(--card);color:var(--text);box-shadow:0 1px 2px rgba(0,0,0,.05);}
  nav.tabs.subtabs button.active{background:var(--primary);color:#fff;box-shadow:none;}
  /* Scroll-indicator (2026-08-10): als de tabbalk breder is dan het scherm (bv. bij
     directie met veel tabbladen op mobiel), krijgt hij een vage rand aan de kant(en)
     waar nog meer tabs verborgen zitten — anders viel niet op dat je kon scrollen.
     De klassen .has-overflow/.at-start/.at-end worden door JS gezet (zie
     attachHandlers, "Scroll-indicator tabbalk") op basis van de daadwerkelijke
     scrollpositie, dus de vage rand verschijnt/verdwijnt precies wanneer nodig. */
  nav.tabs.has-overflow::after{content:"";position:absolute;top:6px;bottom:6px;right:0;width:28px;border-radius:0 var(--radius) var(--radius) 0;background:linear-gradient(to right, rgba(255,255,255,0), var(--card) 85%);pointer-events:none;opacity:1;transition:opacity .15s;}
  nav.tabs.has-overflow.at-end::after{opacity:0;}
  nav.tabs.subtabs.has-overflow::after{background:linear-gradient(to right, rgba(255,255,255,0), var(--bg) 85%);}

  main{padding:16px;flex:1;}
  .card{background:var(--card);border-radius:var(--radius);padding:18px;margin-bottom:16px;box-shadow:0 1px 3px rgba(0,0,0,.06);}
  .card h2{margin:0 0 14px;font-size:16px;color:var(--text);}
  .card h3{margin:0 0 10px;font-size:14px;color:var(--muted);text-transform:uppercase;letter-spacing:.03em;}
  /* Visuele prioriteit (2026-08-18, op verzoek van Jose: "rood = nu oplossen,
     oranje = vandaag, geel = binnenkort, groen = geen actie" — kaarten
     stonden er allemaal ongeveer even "zwaar" bij, alleen het emoji in de
     titel verschilde). .alert/.error bestonden al (dunne gekleurde rand,
     o.a. gebruikt op het Dashboard) — hier verstevigd met een lichte
     achtergrondtint zodat het verschil in urgentie ook in de kaart zelf
     meteen opvalt, niet pas bij het lezen van de tekst. .caution (geel) en
     .clear (groen) zijn nieuw, zelfde patroon, voor "binnenkort" en "geen
     actie nodig". Bewust GEEN volle gekleurde achtergrond (te druk/alarmerend
     voor een zakelijke kantoor-app) — een duidelijke rand + subtiele tint is
     genoeg om in één oogopslag urgent van rustig te onderscheiden. */
  .card.alert{border:1px solid var(--warn);background:#fff7ed;}
  .card.alert h2{color:var(--warn);}
  .card.error{border:1px solid var(--danger);background:#fef2f2;}
  .card.error h2{color:var(--danger);}
  .card.caution{border:1px solid var(--caution);background:#fefce8;}
  .card.caution h2{color:var(--caution);}
  .card.clear{border:1px solid var(--ok);background:#f0fdf4;}
  .card.clear h2{color:var(--ok);}
  /* "Te laat"/"Wacht op klant" (2026-09-02, op verzoek van Jose: eigen
     filter/categorie in het Vandaag-scherm i.p.v. vermengd met Urgent/
     Vandaag) — zelfde patroon als hierboven (dunne gekleurde rand + lichte
     tint), twee nieuwe, nog ongebruikte tinten zodat ze visueel niet
     samenvallen met de bestaande vier. .overdue (paars) staat qua ernst
     tussen Urgent (rood) en Vandaag (oranje) in; .waiting (blauw) is bewust
     NEUTRAAL, niet alarmerend — een "wacht op klant"-item is geen falen van
     kantoor, alleen een blokkade buiten hun handen om. */
  .card.overdue{border:1px solid var(--overdue);background:#f5f3ff;}
  .card.overdue h2{color:var(--overdue);}
  .card.waiting{border:1px solid var(--waiting);background:#f0f9ff;}
  .card.waiting h2{color:var(--waiting);}

  .grid-stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:12px;margin-bottom:16px;}
  .stat{background:var(--card);border-radius:var(--radius);padding:16px;box-shadow:0 1px 3px rgba(0,0,0,.06);}
  .stat .num{font-size:26px;font-weight:800;color:var(--primary);}
  .stat .label{font-size:12px;color:var(--muted);margin-top:2px;}

  /* Trends-tab (2026-08-18, schaalbaarheid): eenvoudige, afhankelijkheidsvrije
     staafdiagrammen in pure CSS/HTML — bewust geen externe grafiekbibliotheek
     (Chart.js e.d.), want deze app is een offline-werkende PWA; een CDN-
     afhankelijkheid zou de grafieken laten breken zodra iemand de Trends-tab
     zonder internet opent. Zie trendBarsHtml()/trendStackedBarsHtml() in de app. */
  .trend-chart{display:flex;align-items:flex-end;gap:6px;height:170px;margin:14px 0 4px;}
  .trend-bar-col{flex:1;min-width:0;display:flex;flex-direction:column;align-items:center;height:100%;}
  .trend-bar-val{font-size:10px;color:var(--muted);margin-bottom:3px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%;}
  .trend-bar-track{flex:1;width:100%;max-width:26px;display:flex;flex-direction:column-reverse;background:rgba(0,0,0,.04);border-radius:4px;overflow:hidden;}
  .trend-bar-fill{width:100%;min-height:2px;}
  .trend-bar-month{font-size:10px;color:var(--muted);margin-top:4px;white-space:nowrap;}

  table{width:100%;border-collapse:collapse;font-size:14px;}
  th,td{padding:9px 10px;text-align:left;border-bottom:1px solid var(--border);}
  th{color:var(--muted);font-weight:600;font-size:12px;text-transform:uppercase;letter-spacing:.02em;}
  tr:last-child td{border-bottom:none;}
  .table-wrap{overflow-x:auto;}

  input,select,textarea{width:100%;padding:11px;border:1px solid var(--border);border-radius:8px;font-size:16px;font-family:inherit;background:var(--card);color:var(--text);}
  input:focus,select:focus,textarea:focus{outline:2px solid var(--primary-light);border-color:var(--primary);}
  /* Checkboxen (2026-08-11): de algemene input-regel hierboven zet width:100%,
     wat ook een checkbox z'n klikvlak over de volle breedte van z'n container
     trekt — daardoor stond het vinkje niet meer direct naast het bijbehorende
     tekstje maar er los van. Checkboxen krijgen daarom hun natuurlijke,
     kleine formaat terug en geen padding/border/achtergrond (die zijn voor
     tekstvelden bedoeld, niet voor een vinkje). */
  input[type="checkbox"]{width:auto;flex:0 0 auto;padding:0;border:none;background:none;}
  label{display:block;font-size:12px;font-weight:600;color:var(--muted);margin-bottom:4px;}
  .field{margin-bottom:12px;}
  .row{display:flex;gap:10px;flex-wrap:wrap;}
  .row > .field{flex:1;min-width:130px;}

  button.btn{background:var(--primary);color:#fff;border:none;padding:11px 16px;border-radius:8px;font-size:14px;font-weight:600;cursor:pointer;touch-action:manipulation;}
  button.btn:hover{background:var(--primary-dark);}
  button.btn.secondary{background:var(--card);color:var(--primary);border:1px solid var(--primary);}
  button.btn.danger{background:var(--card);color:var(--danger);border:1px solid var(--danger);}
  button.btn.danger:hover{background:#fef2f2;}
  button.btn.warn{background:var(--warn);}
  button.btn.big{width:100%;padding:16px;font-size:16px;border-radius:12px;}
  button.btn:disabled{opacity:.5;cursor:not-allowed;}
  button.icon-btn{background:transparent;border:none;cursor:pointer;color:var(--muted);font-size:16px;padding:10px;min-width:40px;min-height:40px;touch-action:manipulation;}
  button.icon-btn:hover{color:var(--danger);}
  tr[data-line-row].dragging{opacity:.4;}
  tr[data-line-row]:hover td:first-child{color:var(--primary);}

  .badge{display:inline-block;padding:3px 9px;border-radius:999px;font-size:12px;font-weight:600;}
  .badge.ok{background:#dcfce7;color:var(--ok);}
  .badge.warn{background:#fef3c7;color:var(--warn);}
  .badge.caution{background:#fef9c3;color:var(--caution);} /* geel — zie .card.caution hierboven */
  .badge.muted{background:#f3f4f6;color:var(--muted);}
  .badge.danger{background:#fee2e2;color:var(--danger);}

  /* contract-room-suggested (2026-09-01, efficiëntie-ronde Bijlage 1B): licht
     amber/geel op een leeg Bijlage-1B-veld dat nog een computer-suggestie als
     placeholder toont, zodat kantoorpersoneel in één oogopslag ziet welke
     velden nog gecontroleerd/bevestigd moeten worden -- zelfde kleurtaal als
     .badge.warn/.shift-chip.conflict hierboven, geen nieuwe kleur nodig.
     select.contract-room-suggested (2026-09-02, ruimte-frequentie-redesign):
     zelfde highlight, nu ook op de nieuwe frequentie-type-<select> toegepast
     (een suggestie kan daar niet als placeholder-tekst getoond worden zoals
     bij een <input>, dus de select zelf krijgt de amber-highlight + een
     apart tekstregeltje met de suggestie eronder). */
  input.contract-room-suggested, select.contract-room-suggested{background:#fef3c7;}

  .empty{color:var(--muted);font-size:14px;padding:20px 0;text-align:center;}
  .sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0;}

  .seg{display:inline-flex;background:#f3f4f6;border-radius:10px;padding:4px;gap:4px;}
  .seg button{border:none;background:transparent;padding:8px 16px;border-radius:8px;font-size:13px;font-weight:600;color:var(--muted);cursor:pointer;touch-action:manipulation;}
  .seg button.active{background:var(--card);color:var(--primary);box-shadow:0 1px 2px rgba(0,0,0,.08);}

  /* Login */
  .login-wrap{display:flex;align-items:center;justify-content:center;min-height:100vh;padding:20px;}
  .login-card{background:var(--card);border-radius:16px;padding:36px 30px;max-width:400px;width:100%;box-shadow:0 8px 24px rgba(0,0,0,.1);text-align:center;}
  .login-card .logo-big{width:64px;height:64px;background:var(--primary);border-radius:16px;display:flex;align-items:center;justify-content:center;color:#fff;font-size:30px;margin:0 auto 14px;}
  .login-card .logo-big.has-img{width:auto;height:auto;background:transparent;border-radius:0;margin:0 auto 16px;}
  .login-card .logo-big img.brand-logo{max-width:230px;max-height:82px;object-fit:contain;display:block;margin:0 auto;}
  .login-card h1{font-size:20px;margin:0 0 4px;}
  .login-card p.sub{color:var(--muted);font-size:13px;margin:0 0 22px;}
  .login-card .linkbtn{background:none;border:none;color:var(--primary);font-size:13px;cursor:pointer;margin-top:12px;text-decoration:underline;padding:8px;}
  .linkbtn{background:none;border:none;color:var(--primary);font-size:13px;cursor:pointer;text-decoration:underline;padding:10px;touch-action:manipulation;}

  /* Weekly planner */
  .week-nav{display:flex;align-items:center;justify-content:space-between;margin-bottom:14px;gap:10px;}
  .week-nav .label{font-weight:700;font-size:15px;}
  .day-col{background:#fafafa;border-radius:10px;padding:8px 6px;min-height:90px;border:1px solid var(--border);}
  .day-col .day-title{font-size:12px;font-weight:700;color:var(--muted);margin-bottom:8px;display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:4px;}
  /* Minimaal 96px per dag (was 120px, 2026-10-03): 7 x 120 + 6 x 8 = 888px
     paste niet in de roosterkaart naast het zijpaneel, waardoor zondag rechts
     afviel. Lange namen breken nu af binnen de kaart (zie .shift-chip). */
  .week-grid{display:grid;grid-template-columns:repeat(7,minmax(96px,1fr));gap:6px;overflow-x:auto;}
  .shift-chip{background:var(--primary-light);border-left:3px solid var(--primary);border-radius:6px;padding:6px 7px;margin-bottom:6px;font-size:12px;line-height:1.35;cursor:pointer;touch-action:pan-y;user-select:none;position:relative;}
  .shift-chip .who{font-weight:700;}
  .shift-chip.conflict{background:#fef3c7;border-left-color:var(--warn);}
  .shift-chip.completed{background:#dcfce7;border-left-color:var(--ok);}
  .shift-chip.completed:hover{background:#c3f0d1;}
  /* Open dienst (2026-08-18, "Planning groter en centraler"): een dienst zonder
     toegewezen medewerker krijgt een eigen, herkenbare stijl (paars/gestippeld)
     i.p.v. op te vallen als een gewone dienst met "Onbekend" als naam — zelfde
     kleur als het "Open diensten"-paneeltje ernaast, zodat de kalender en het
     zijpaneel duidelijk bij elkaar horen. Bewust een andere kleur dan de
     rood/oranje/geel/groen-prioriteitsschaal elders in de app: dit is geen
     urgentie-signaal maar een neutrale "nog te doen"-status. */
  .shift-chip.open{background:#f3e8ff;border-left-color:#9333ea;border-left-style:dashed;}
  .shift-chip.open:hover{background:#e9d5ff;}
  .shift-chip:hover{background:#c9dcf2;}
  .shift-chip .swipe-hint{position:absolute;top:0;bottom:0;display:flex;align-items:center;font-size:16px;opacity:0;pointer-events:none;color:var(--primary-dark);}
  .shift-chip .swipe-hint.left{left:6px;}
  .shift-chip .swipe-hint.right{right:6px;}
  .add-shift-btn{width:100%;background:transparent;border:1px dashed var(--border);border-radius:6px;padding:10px 6px;font-size:12px;color:var(--muted);cursor:pointer;touch-action:manipulation;}
  .add-shift-btn:hover{border-color:var(--primary);color:var(--primary);}

  /* Planning groter/centraler (2026-08-18): kalender + zijpaneel (filters/open
     diensten/ziekte-vervanging) naast elkaar op een breed scherm. Zelfde
     "display:contents tenzij breed genoeg"-patroon als .shell-body/
     .shell-content hierboven — op mobiel/smal scherm dus gewoon alles onder
     elkaar in document-volgorde (kalender eerst, dan de 3 paneelkaarten),
     geen enkel risico op regressie daar. */
  .planning-layout, .planning-main, .planning-side{display:contents;}
  /* Naast elkaar pas vanaf 1400px (was 1100px, 2026-10-03). Daaronder
     paste het rooster met zeven dagen niet meer naast een zijpaneel van
     280px en viel zondag af; nu staan de panelen dan onder het rooster
     en krijgt de week de volle breedte. */
  @media (min-width:1400px){
    .planning-layout{display:flex;align-items:flex-start;gap:16px;}
    /* display:block is hier essentieel (gecorrigeerd 2026-10-03). Zonder
       bleef .planning-main op display:contents staan, de basisregel hierboven.
       Dan bestaat de kolom niet: de Week/Maand-knoppen en het rooster werden
       twee losse flexkolommen naast elkaar, het rooster kon niet krimpen
       (min-width:0 werkt niet op een contents-element) en het zijpaneel werd
       buiten beeld geduwd -- een pagina van 1906px in een venster van 1505px. */
    .planning-main{display:block;flex:1;min-width:0;}
    .planning-side{flex:0 0 280px;min-width:0;display:flex;flex-direction:column;gap:16px;position:sticky;top:14px;}
    .planning-side .card{margin-bottom:0;}
    /* Selects en knoppen in het zijpaneel mogen het paneel nooit breder maken
       dan zijn 280px. */
    .planning-side select, .planning-side input{width:100%;max-width:100%;box-sizing:border-box;}
  }
  /* Lange straatnamen ("Van Oldenbarneveldstraat", "Gildermeesterplein") liepen
     buiten de dienstkaart: een woord zonder spatie breekt standaard niet af.
     overflow-wrap:anywhere breekt alleen als het woord anders niet past. */
  .day-col{min-width:0;}
  /* hyphens:auto (lang="nl" op <html>) breekt bij voorkeur op een
     lettergreep: "Oldenbarne-veldstraat" i.p.v. "Oldenbarnevel|dstraat".
     overflow-wrap blijft het vangnet voor wat daarna nog niet past. */
  .shift-chip{overflow-wrap:anywhere;word-break:break-word;hyphens:auto;-webkit-hyphens:auto;min-width:0;}

  /* Modal */
  .modal-overlay{position:fixed;inset:0;background:rgba(17,24,39,.5);display:flex;align-items:center;justify-content:center;z-index:100;padding:16px;}
  .modal{background:var(--card);border-radius:14px;padding:22px;max-width:420px;width:100%;max-height:90vh;overflow-y:auto;}
  .modal h3{margin:0 0 16px;font-size:16px;}
  .modal .actions{display:flex;gap:10px;justify-content:flex-end;margin-top:18px;flex-wrap:wrap;}

  /* Klant-/objectdossier (2026-08-17) — beduidend meer inhoud/tabellen dan een
     gewoon formuliermodal, vandaar breder dan de standaard 420px. Alleen deze
     2 nieuwe schermen gebruiken 'm (class="modal modal-wide"), alle overige
     modals blijven ongewijzigd op 420px.
     FASE 10 (§1/§2/§3, 2026-08-21, "voelt aan als een echte werkpagina"):
     breder en start bovenaan i.p.v. verticaal gecentreerd — .modal-overlay-page
     staat ALLEEN op de overlay van deze 2 schermen (zie renderModal()), dus
     elke andere modal in de app blijft precies zoals hij was. */
  .modal-overlay.modal-overlay-page{align-items:flex-start;padding:24px 16px;}
  .modal.modal-wide{max-width:1180px;}
  @media (min-width:900px){ .modal.modal-wide{padding:26px 30px;} }

  /* Contract-wizard vol scherm (2026-09-01, op verzoek van Jose: "kan je het
     niet makkelijker en beter pagina maken om een contract op te stellen en
     niet als popup"). Zelfde modal-mechaniek als hierboven (geen nieuwe
     route/scherm-type), maar met bijna het hele beeldscherm i.p.v. de
     gebruikelijke 1180px — de omringende dossier-chrome (breadcrumb,
     statistiekbalk, tabknoppen) wordt in de render tegelijk vervangen door
     een compacte kop (zie wizardFullScreen in renderModal()), zodat de
     wizard zelf voelt als een eigen, ruime pagina i.p.v. een klein venster.
     .modal-overlay-tight verkleint de buitenmarge van .modal-overlay-page op
     datzelfde moment, zodat het venster ook echt tot de randen loopt. */
  .modal-overlay.modal-overlay-tight{padding:10px;}
  .modal.modal-wide.modal-fullscreen{max-width:min(1500px,97vw);width:100%;max-height:97vh;}
  .wizard-page-header{display:flex;align-items:center;gap:14px;margin-bottom:16px;flex-wrap:wrap;}
  .wizard-page-header h3{margin:0;font-size:17px;}
  .dossier-stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(130px,1fr));gap:10px;margin-bottom:16px;}
  .dossier-stat{border:1px solid var(--border);border-radius:10px;padding:8px 10px;}
  .dossier-stat .num{font-size:18px;font-weight:700;line-height:1.2;}
  .dossier-stat .label{font-size:11px;color:var(--muted);margin-top:2px;}
  .dossier-tabs{display:flex;gap:6px;flex-wrap:wrap;margin-bottom:16px;border-bottom:1px solid var(--border);padding-bottom:10px;}
  .dossier-tabs button{border:1px solid var(--border);background:var(--card);border-radius:20px;padding:6px 12px;font-size:12px;cursor:pointer;}
  .dossier-tabs button.active{background:var(--primary);border-color:var(--primary);color:#fff;}

  /* Klantdossier-tabgroepering (2026-09-01, op verzoek van Jose: "overzichtelijker
     maken qua efficient werken en workflows") — het klantdossier heeft 12
     tabbladen, het drukste scherm van de app. Puur visuele groepering: elke
     groep is nog steeds één klik weg, er komt geen ingeklapte subnavigatie
     bij (zie customerDossier in renderModal()). Alleen .dossier-tabs-grouped
     krijgt dit gedrag; het gewone .dossier-tabs (bv. objectdossier) blijft
     ongewijzigd. */
  .dossier-tabs-grouped{gap:0;row-gap:8px;}
  .dossier-tab-group{display:flex;align-items:center;gap:6px;flex-wrap:wrap;padding:0 12px;}
  .dossier-tab-group:first-child{padding-left:0;}
  .dossier-tab-group:not(:first-child){border-left:1px solid var(--border);}
  .dossier-tab-group-label{font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.02em;color:var(--muted);margin-right:2px;white-space:nowrap;}

  /* Kruimelpad (FASE 10, §1-3, 2026-08-21) — bovenaan het klant-/objectdossier,
     en herbruikbaar overal waar Jose later een duidelijke "waar ben ik"-lijn
     wil (zie dossierBreadcrumbHtml() in de app). Bewust plat/tekstueel, geen
     eigen kaart — dit is navigatie, geen inhoud. */
  .breadcrumb{display:flex;align-items:center;gap:5px;flex-wrap:wrap;font-size:12.5px;color:var(--muted);margin:0 0 10px;}
  .breadcrumb button{background:none;border:none;padding:2px 3px;margin:0;font-size:12.5px;color:var(--primary);cursor:pointer;touch-action:manipulation;}
  .breadcrumb button:hover{text-decoration:underline;}
  .breadcrumb .sep{color:var(--border);}
  .breadcrumb .current{color:var(--text);font-weight:600;padding:2px 3px;}

  /* Filterlabel "context behouden" (FASE 10, §4, 2026-08-21) — chip boven een
     overzicht dat vanuit een dossier gefilterd is geopend (Planning/Uren/
     Meldingen/Kwaliteit/Offertes/Facturen). Zelfde bedoeling als de losse
     "Filter wissen"-linkjes die al her en der bestonden, nu als herkenbaar,
     consistent element (zie filterChipHtml() in de app). */
  .filter-chip{display:inline-flex;align-items:center;gap:8px;background:var(--primary-light);color:var(--primary-dark);border-radius:999px;padding:6px 8px 6px 14px;font-size:12.5px;font-weight:600;margin:0 0 12px;}
  .filter-chip button{background:rgba(255,255,255,.6);border:none;color:var(--primary-dark);border-radius:999px;width:20px;height:20px;line-height:20px;text-align:center;padding:0;font-size:12px;cursor:pointer;touch-action:manipulation;}
  .filter-chip button:hover{background:var(--card);}

  /* Dossier quick actions (FASE 10, §6, 2026-08-21) — rij snelknoppen direct
     onder de kruimelpad/titel van een klant-/objectdossier, boven de
     dossier-stats. Kleiner/secundair van gewicht (dit zijn shortcuts, geen
     hoofdactie van het scherm), horizontaal scrollbaar op smal scherm i.p.v.
     wrappend zodat de layout niet springt. */
  .dossier-quickactions{display:flex;gap:8px;margin:0 0 14px;overflow-x:auto;-webkit-overflow-scrolling:touch;padding-bottom:2px;}
  .dossier-quickactions button{flex:0 0 auto;background:var(--card);border:1px solid var(--border);color:var(--text);border-radius:20px;padding:7px 14px;font-size:12.5px;font-weight:600;cursor:pointer;white-space:nowrap;touch-action:manipulation;}
  .dossier-quickactions button:hover{border-color:var(--primary);color:var(--primary);}

  /* Generieke lege-staat met call-to-action (FASE 10, §20, 2026-08-21) — .empty
     bestond al (platte grijze tekst); dit is de rijkere variant mét knop, voor
     plekken waar "Nog geen X" ook meteen een zinnige eerste actie heeft. */
  .empty-state{text-align:center;color:var(--muted);font-size:13.5px;padding:28px 16px;}
  .empty-state .empty-state-icon{font-size:26px;margin-bottom:8px;opacity:.6;}
  .empty-state p{margin:0 0 14px;}
  .empty-state .btn{display:inline-flex;}

  /* Verbeterronde (2026-08-21, scanrapport §"CSS-centralisatie"): de meest
     herhaalde inline-style-combinaties (honderden keren letterlijk gedupliceerd
     door het bestand) als centrale classes — additief, bestaande inline styles
     elders blijven gewoon staan (geen mass-refactor), maar nieuwe/vervangen
     plekken gebruiken voortaan deze klassen zodat een toekomstige aanpassing
     (bv. een andere grijstint) nog maar op één plek hoeft. */
  .hint-text{font-size:12px;color:var(--muted);margin:-4px 0 12px;}
  .hint-text-sm{font-size:13px;color:var(--muted);margin:-6px 0 12px;}
  .hint-text-tight{font-size:12px;color:var(--muted);margin:-4px 0 10px;}
  .field-note{font-size:12px;color:var(--muted);margin:6px 0 0;}
  /* Overzichtelijkheidsronde (2026-09-03): visuele subkopjes binnen een lang
     formulier (bv. "Wie & waar" / "Wanneer" / "Notities" in het dienst-
     bewerkscherm) -- puur presentatie, verplaatst/verwijdert geen velden. */
  .form-subhead{font-weight:700;font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:.03em;margin:16px 0 6px;border-top:1px solid var(--border);padding-top:12px;}
  .form-subhead:first-child{border-top:none;padding-top:0;margin-top:0;}
  .error-text{color:var(--danger);font-size:13px;}
  .cell-actions{text-align:right;white-space:nowrap;}

  /* Opmaak-opschoning fase 1 (2026-08-26, op verzoek van Jose, "diepe scan"
     vervolg): losse, atomaire utility-classes voor de meest letterlijk
     herhaalde ÉÉN-op-ÉÉN-EIGENSCHAP inline-stylecombinaties (honderden keren
     exact hetzelfde geschreven door het bestand — text-align:right,
     color:var(--muted), losse font-sizes, margin:0, width:100%,
     position:relative). Bewust klein en samenstelbaar (bv. class="u-fs12
     u-muted" i.p.v. één nieuwe class per exacte combinatie) zodat toekomstige
     vergelijkbare combinaties er ook mee gedekt worden, zonder de
     class-lijst blijvend te laten groeien. Dit is FASE 1 van een gefaseerde
     opschoning (1.617 inline styles in totaal) — de rest blijft bewust
     ongemoeid tot een volgende ronde, om het risico van deze wijziging
     behapbaar en goed te verifiëren te houden. */
  .u-muted{color:var(--muted);}
  .u-right{text-align:right;}
  .u-relative{position:relative;}
  .u-m0{margin:0;}
  .u-mt0{margin-top:0;}
  .u-w100{width:100%;}
  .u-fs12{font-size:12px;}
  .u-fs13{font-size:13px;}
  .u-fs14{font-size:14px;}

  /* Generieke bevestigingsdialoog (2026-08-16, showConfirm()) — vervangt
     window.confirm(). Hogere z-index dan .modal-overlay zodat 'm ook boven
     een al openstaande modal kan stapelen (veel bevestigingen gebeuren
     vanuit een knop binnen een modal, bv. "notitie verwijderen"). */
  .confirm-dialog-overlay{position:fixed;inset:0;background:rgba(17,24,39,.6);display:flex;align-items:center;justify-content:center;z-index:200;padding:16px;}
  .confirm-dialog{background:var(--card);border-radius:14px;padding:22px;max-width:380px;width:100%;box-shadow:0 10px 40px rgba(0,0,0,.3);}
  .confirm-dialog p{margin:0 0 18px;color:var(--text);white-space:pre-line;line-height:1.45;}
  .confirm-dialog .actions{display:flex;gap:10px;justify-content:flex-end;flex-wrap:wrap;}

  /* Clock */
  .clock-display{text-align:center;padding:24px 0;}
  .clock-display .time{font-size:44px;font-weight:800;color:var(--primary);letter-spacing:.02em;}
  .clock-display .status{font-size:14px;color:var(--muted);margin-top:6px;}

  footer.hint{padding:14px 18px;text-align:center;color:var(--muted);font-size:12px;}
  @media (max-width:640px){
    .week-grid{grid-template-columns:repeat(7,150px);}
    /* Locatietabel in de klantkaart (Klanten-tab, 2026-08-13): op een telefoon
       moesten alle 7 kolommen horizontaal gescrold worden. De Bijzonderheden-
       kolom is het minst kritiek voor een snelle blik onderweg — die verbergen
       we hier, en de rest krijgt iets minder padding zodat er meer past zonder
       te hoeven scrollen. Alleen deze specifieke tabel (.table-locations), niet
       alle tabellen in de app. */
    .table-locations .col-notes{display:none;}
    .table-locations th, .table-locations td{padding:6px 8px;font-size:12.5px;}
  }
  @media print{
    body *{visibility:hidden;}
    #printArea, #printArea *, #printAreaReports, #printAreaReports *{visibility:visible;}
    #printArea, #printAreaReports{position:absolute;left:0;top:0;width:100%;color:#000;}
    #printArea .print-title, #printAreaReports .print-title{display:block !important;font-size:18px;font-weight:700;margin-bottom:16px;}
    .no-print{display:none !important;}
    @page{size:A4;margin:14mm;}
    /* Printen vanuit een modal (2026-08-16, zie printWithTitle() in
       efficient-schoon-app.html): de onderliggende pagina blijft anders
       volledig (onzichtbaar) meetellen voor het aantal pagina's — bij een
       lange lijst achter de modal leverde dat overbodige lege pagina's op.
       #printArea zelf staat los hiervan (absoluut gepositioneerd t.o.v. de
       modal-overlay), dus dit weglaten is veilig. */
    body.printing-modal header.topbar,
    body.printing-modal nav.tabs,
    body.printing-modal main{display:none !important;}
  }
  @media (max-width:420px){
    main{padding:12px;}
    .card{padding:14px;}
    .login-card{padding:28px 20px;}
    .grid-stats{gap:8px;}
    .stat{padding:12px;}
    .stat .num{font-size:22px;}
    header.topbar .user-info span{max-width:32vw;}
  }

  /* Vaste linkerzijbalk op desktop (2026-08-18, op verzoek van Jose: "vaste
     linkerzijbalk op desktop i.p.v. alleen horizontale tabs, op mobiel hou
     het horizontaal"; alleen voor directie/planner — medewerker/klanten­
     portaal hebben te weinig tabbladen om er baat bij te hebben en blijven
     altijd horizontaal, vandaar de "body.nav-sidebar"-klasse-voorwaarde
     hieronder, gezet in renderInner() alleen als state.role admin/planner is).

     HERZIEN (2026-08-18): de eerste versie gebruikte CSS Grid met nav.tabs
     over meerdere rijen gespannen (grid-row:2/-1) om 'm als zijbalk te laten
     werken. Bleek in de praktijk stuk te gaan op tabbladen met weinig inhoud
     (bv. Vandaag met maar 1 rij): de zijbalk's eigen (grotere) hoogtebehoefte
     werd dan over de andere, verder lege rijen verdeeld, wat extra witruimte
     bovenin toevoegde en de hele pagina liet "springen" t.o.v. een tabblad
     met wél genoeg inhoud (door Jose gemeld met 2 screenshots die dat verschil
     lieten zien). Vervangen door gewone flexbox — geen rij-overspanning meer,
     dus geen enkele kans meer dat de zijbalk meer ruimte claimt dan er is:
     `.shell-body` (nieuwe wrapper-div in shell(), rond nav.tabs + de rest)
     wordt op desktop een flex-rij; nav.tabs is daarin een niet-krimpende,
     sticky kolom van 220px, en `.shell-content` (2e nieuwe wrapper-div, rond
     nav.tabs.subtabs + main) is de resterende kolom die alles er normaal
     onder blijft stapelen. Op mobiel/standaard hebben beide wrappers
     `display:contents` (zie de basisregels hieronder, buiten de media query)
     — daardoor doen ze op kleine schermen HELEMAAL NIETS en gedraagt alles
     zich exact als vóór deze wrappers bestonden (geen enkel risico voor
     mobiel/medewerker/klantenportaal). Drempel 900px: ruim boven de
     bestaande mobiele media-queries (640px/420px hierboven). */
  .shell-body, .shell-content{display:contents;}
  @media (min-width:900px){
    body.nav-sidebar #app{max-width:1300px;}
    body.nav-sidebar .shell-body{
      display:flex;
      flex-direction:row;
      align-items:flex-start;
      gap:16px;
      padding:0 16px;
    }
    body.nav-sidebar .shell-content{
      display:flex;
      flex-direction:column;
      flex:1;
      min-width:0;
    }
    body.nav-sidebar nav.tabs:not(.subtabs){
      flex:0 0 220px;
      flex-direction:column;
      align-items:stretch;
      gap:2px;
      position:sticky;
      top:14px;
      max-height:calc(100dvh - 28px);
      overflow-y:auto;
      margin:14px 0;
    }
    body.nav-sidebar nav.tabs:not(.subtabs) button{flex:none;width:100%;text-align:left;white-space:normal;}
    /* De horizontale-scroll-schaduw (zie hoger, .has-overflow/.at-end) slaat
       nergens meer op zodra de balk verticaal is — hier uitgezet. */
    body.nav-sidebar nav.tabs:not(.subtabs).has-overflow::after{display:none;}
    body.nav-sidebar nav.tabs.subtabs{margin-left:0;margin-right:0;}
  }
  /* "Groter en centraler" (2026-08-18, zie WIDE_TABS/"wide-tab"-class in de
     app): op tabbladen die daar baat bij hebben (nu: Planning — kalender +
     nieuw zijpaneel) mag #app breder dan de standaard 1300px, zodat de
     7-koloms-kalender niet meteen tegen het zijpaneel aan hoeft te dringen.
     Pas vanaf 1650px viewport-breedte (ruim boven een normaal laptopscherm) —
     daaronder blijft #app gewoon 1300px zoals op elk ander tabblad. */
  /* Vanaf 1400px (gecorrigeerd 2026-10-03, was 1650px) mag het rooster de
     schermbreedte benutten, met 16px marge aan beide kanten. Op een gangbaar
     laptopscherm van ~1500px kreeg het rooster anders maar 1300px, met de
     zijbalk en het zijpaneel daar nog van af. */
  @media (min-width:1400px){
    body.nav-sidebar.wide-tab #app{max-width:min(1560px, calc(100vw - 32px));}
  }

  /* Begroeting bovenaan het startscherm (2026-08-22, "netjes gegroet
     worden"): gedeelde gradient-stijl voor de "Goedemorgen/-middag/-avond,
     naam"-kaart, zowel op het medewerker-startscherm ("Mijn rooster") als op
     het kantoor-/directie-startscherm ("Vandaag") — zelfde visuele taal als
     de klantenportaal-hero hieronder, maar bewust een EIGEN klasse i.p.v.
     .portal-hero zelf te hergebruiken: die blijft, zoals de toelichting
     hieronder al zegt, bewust geïsoleerd voor het klantenportaal. */
  .greeting-hero{background:linear-gradient(135deg,var(--primary) 0%,var(--primary-dark) 100%);color:#fff;padding:12px 18px;margin-bottom:12px;}
  .greeting-hero h2{margin:0;color:#fff;font-size:17px;}

  /* Klantenportaal: Start-tab (2026-08-13, professioneler herontwerp) —
     bewust eigen .portal-*-klassen, zodat dit nergens anders in de app
     (medewerker-/beheerderschermen, die dezelfde .card/.stat/.grid-stats
     hergebruiken) onbedoeld meeverandert. Zakelijke, rustige uitstraling op
     verzoek van Jose: gradient-welkomskaart, een uitgelicht datumblok bij het
     eerstvolgende bezoek, en icoon-cirkels bij de statistiekkaarten i.p.v.
     kale cijfers. */
  .portal-hero{background:linear-gradient(135deg,var(--primary) 0%,var(--primary-dark) 100%);color:#fff;}
  .portal-hero-eyebrow{font-size:11px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;opacity:.75;margin-bottom:6px;}
  .portal-hero h2{margin:0;color:#fff;font-size:20px;}
  .portal-hero-sub{margin:6px 0 0;font-size:14px;color:#fff;opacity:.92;}

  .portal-section-label{margin:0 0 14px;font-size:12px;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.04em;}

  .portal-nextvisit-row{display:flex;align-items:center;gap:16px;flex-wrap:wrap;}
  .portal-date-block{background:var(--primary-light);border-radius:10px;padding:10px 18px;text-align:center;min-width:76px;flex-shrink:0;}
  .portal-date-day{font-size:26px;font-weight:800;color:var(--primary-dark);line-height:1;}
  .portal-date-month{font-size:11px;font-weight:700;color:var(--primary-dark);text-transform:uppercase;letter-spacing:.05em;margin-top:3px;}
  .portal-nextvisit-info{min-width:0;}
  .portal-nextvisit-dayname{font-size:15px;font-weight:700;color:var(--text);}
  .portal-nextvisit-time{font-size:13px;color:var(--muted);margin-top:2px;}
  .portal-nextvisit-extra{font-size:12px;color:var(--primary);font-weight:600;margin-top:6px;}

  .portal-quickactions{display:flex;gap:10px;flex-wrap:wrap;margin-bottom:16px;}
  .portal-quickactions .btn{flex:1;min-width:170px;}

  .portal-empty-nextvisit{text-align:center;padding:14px 10px 6px;}
  .portal-empty-icon{font-size:26px;margin-bottom:8px;opacity:.6;}
  .portal-empty-text{color:var(--muted);font-size:13px;margin:0 0 14px;}

  .portal-stats{margin:0 0 16px;}
  .portal-stat{display:flex;align-items:center;gap:12px;cursor:pointer;box-shadow:none;border:1px solid var(--border);}
  .portal-stat:hover{border-color:var(--primary);}
  .portal-stat-icon{width:38px;height:38px;border-radius:10px;background:var(--primary-light);display:flex;align-items:center;justify-content:center;font-size:18px;flex-shrink:0;}
  .portal-stat-body{min-width:0;}
  .portal-stat-body .num{font-size:22px;font-weight:800;color:var(--primary);line-height:1.1;}
  .portal-stat-body .label{font-size:12px;color:var(--muted);margin-top:2px;}

  @media (max-width:640px){
    .portal-quickactions{flex-direction:column;}
    .portal-quickactions .btn{width:100%;}
  }

  /* ---------- Maandoverzicht planning (2026-09-29) ----------
     Eén regel per locatie of medewerker, één smal vakje per dag. Rustige
     kleuren voor "gedekt" en opvallende voor een gat of een open dienst: het
     oog moet naar de uitzondering springen, niet naar de 300 vakjes die goed
     staan. Eerste kolom blijft staan bij horizontaal scrollen, anders weet je
     halverwege de maand niet meer wiens regel je leest. */
  /* [hidden] moet het altijd winnen: de weekkaart wordt in de maandstand zo
     verborgen, en een .card-regel met display erin zou dat stil breken. */
  [hidden]{display:none !important;}
  .month-overview-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch;border:1px solid var(--border);border-radius:10px;}
  /* Maandoverzicht past zonder schuifbalk (2026-10-03): vaste tabelopmaak
     verdeelt de breedte gelijk over alle dagen. Pas onder ~760px (telefoon)
     verschijnt de schuifbalk weer -- 31 kolommen passen daar niet leesbaar. */
  table.month-overview{border-collapse:separate;border-spacing:0;font-size:11px;width:100%;min-width:760px;table-layout:fixed;}
  table.month-overview th,table.month-overview td{padding:0;margin:0;}
  table.month-overview thead th{position:sticky;top:0;z-index:2;background:var(--card);color:var(--muted);font-weight:600;text-align:center;line-height:1.15;padding:4px 0 5px;overflow:hidden;border-bottom:1px solid var(--border);}
  table.month-overview thead th span{font-size:9px;text-transform:uppercase;letter-spacing:.03em;}
  table.month-overview th.mo-head{position:sticky;left:0;z-index:3;background:var(--card);text-align:left;font-weight:600;color:var(--text);width:170px;padding:4px 8px 4px 10px;border-right:1px solid var(--border);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
  table.month-overview tbody th.mo-head{border-bottom:1px solid var(--border);font-size:12px;}
  table.month-overview .mo-sub{display:block;font-size:10px;font-weight:400;color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
  table.month-overview td.mo-total,table.month-overview th.mo-total{text-align:right;padding:0 10px;color:var(--muted);white-space:nowrap;border-left:1px solid var(--border);border-bottom:1px solid var(--border);font-size:11px;}
  table.month-overview thead th.mo-total{border-bottom:1px solid var(--border);width:52px;padding:0 6px;}
  table.month-overview td.mo-total{padding:0 6px;}
  table.month-overview td.mo-cell{border-bottom:1px solid var(--border);border-right:1px solid rgba(0,0,0,.04);}
  table.month-overview td.mo-cell button{display:block;width:100%;height:26px;border:none;background:transparent;font:inherit;font-weight:700;color:var(--muted);cursor:pointer;padding:0;touch-action:manipulation;min-width:0;}
  table.month-overview td.mo-cell button:hover{outline:2px solid var(--primary);outline-offset:-2px;}
  table.month-overview td.weekend,table.month-overview thead th.weekend{background:#f6f7f9;}
  table.month-overview td.mo-cell.leeg button{color:transparent;}
  table.month-overview td.mo-cell.ok{background:#eefaf2;}
  table.month-overview td.mo-cell.ok button{color:#15803d;font-weight:600;}
  table.month-overview td.mo-cell.open{background:#fef3c7;}
  table.month-overview td.mo-cell.open button{color:#b45309;}
  table.month-overview td.mo-cell.gat{background:#fee2e2;}
  table.month-overview td.mo-cell.gat button{color:var(--danger);}
  table.month-overview td.mo-cell.verlof{background:repeating-linear-gradient(45deg,#f1f5f9,#f1f5f9 3px,#e2e8f0 3px,#e2e8f0 6px);}
  table.month-overview td.mo-cell.feestdag{box-shadow:inset 0 -3px 0 #cbd5e1;}
  table.month-overview td.mo-cell.vandaag,table.month-overview thead th.vandaag{box-shadow:inset 2px 0 0 var(--primary),inset -2px 0 0 var(--primary);}
  table.month-overview thead th.vandaag{color:var(--primary);font-weight:800;}
  table.month-overview tr.mo-open-row th.mo-head{color:#b45309;}
  .mo-key{display:inline-block;width:10px;height:10px;border-radius:2px;vertical-align:-1px;border:1px solid rgba(0,0,0,.12);}
  .mo-key.gat{background:#fee2e2;}
  .mo-key.open{background:#fef3c7;}
  .mo-key.ok{background:#eefaf2;}
  .mo-key.verlof{background:repeating-linear-gradient(45deg,#f1f5f9,#f1f5f9 3px,#e2e8f0 3px,#e2e8f0 6px);}

/* ---- Kantooragenda (2026-10-02) ---- */
.oa-tabel { width:100%; border-collapse:collapse; table-layout:fixed; }
.oa-tabel th, .oa-tabel td { border:1px solid var(--line, #C7D3DD); padding:0; vertical-align:top; }
.oa-tabel th { background:#EAF3F7; font-size:12px; padding:5px 6px; text-align:left; font-weight:600; }
.oa-tabel th.oa-vandaag { background:#D6E9F5; }
.oa-naam { width:150px; text-transform:none; letter-spacing:normal; }
.oa-rol { font-weight:400; font-size:11px; color:var(--muted, #5B6B7B); }
.oa-jij { font-weight:400; font-size:11px; color:var(--muted, #5B6B7B); }
.oa-telling { font-weight:400; font-size:10px; color:var(--muted, #5B6B7B); line-height:1.3; margin-top:2px; }
.oa-td { padding:2px; }
.oa-klikbaar { cursor:pointer; }
.oa-klikbaar:hover .oa-cel { outline:2px solid var(--accent, #2563EB); outline-offset:-2px; }
.oa-cel { display:flex; flex-direction:column; gap:1px; min-height:40px; }
.oa-half { flex:1; display:flex; align-items:center; gap:3px; padding:2px 4px; border-radius:3px;
           color:#fff; font-size:11px; line-height:1.2; overflow:hidden; }
.oa-half.oa-leeg { background:transparent; border:1px dashed var(--line, #C7D3DD); }
.oa-icon { flex:none; }
.oa-tekst { white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.oa-notitie { font-size:10px; color:var(--muted, #5B6B7B); padding:1px 4px;
              white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.oa-legenda { display:flex; flex-wrap:wrap; gap:10px; margin:0 0 12px; font-size:12px; }
.oa-legenda-item { display:inline-flex; align-items:center; gap:4px; }
.oa-stip { width:10px; height:10px; border-radius:50%; display:inline-block; }
.oa-keuzes { display:flex; flex-wrap:wrap; gap:6px; }
.oa-keuze { font-size:12px; padding:5px 9px; border:1px solid var(--line, #C7D3DD);
            background:#fff; border-radius:6px; cursor:pointer; }
.oa-keuze-actief { font-weight:600; }
/* Op een telefoon past een weektabel van zeven kolommen niet; horizontaal
   scrollen is daar beter dan alles onleesbaar klein maken. */
@media (max-width: 760px) {
  .oa-tabel { min-width:700px; }
  .oa-naam { width:110px; }
  .oa-tekst { display:none; }
}
.oa-dag { display:flex; flex-direction:column; gap:12px; }
.oa-groep-kop { display:flex; align-items:center; gap:6px; font-size:13px; }
.oa-groep-lijst { margin:4px 0 0 20px; padding:0; font-size:13px; line-height:1.6; }
.oa-klant { font-size:10px; color:var(--muted, #5B6B7B); padding:1px 4px;
            white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.oa-verslag { display:block; width:calc(100% - 4px); margin:2px; font-size:10px; padding:2px 4px;
              border:1px solid var(--line, #C7D3DD); background:#fff; border-radius:4px; cursor:pointer; }
.oa-groep-lijst .oa-verslag { display:inline-block; width:auto; margin:0 0 0 6px; }
.oa-status { display:flex; flex-wrap:wrap; gap:18px; margin-top:10px; font-size:13px; }
.oa-status > div { min-width:160px; }
.oa-feest { font-size:10px; font-weight:400; color:#B45309; }
.oa-feestdag { background:#FDF0D5 !important; }
