/* ===========================================================================
   Ōmata chat, gedeelde component. Opmaak.

   Los bestand omdat de knop en het venster op elke pagina komen. Het palet
   komt uit de tokens van de pagina; de donkere waarden hieronder zijn daaruit
   afgeleid en staan gescopeerd op .omata-chat, zodat de pagina zelf licht
   blijft en er niets buiten dit paneel verandert.

   Donker paneel op een lichte pagina is een bewust contrast: de chat is een
   ander soort oppervlak dan de pagina, en dat mag je zien.

   Alle waarden hieronder zijn nagemeten, niet geschat. Titel en mededeling
   14,72:1, bericht van de assistent 13,24:1, bericht van de bezoeker 14,16:1,
   invoertekst 13,24:1, de placeholder in het veld 5,62:1 en de verzendpijl
   3,80:1 tegen een norm van 3 voor een icoon.
   =========================================================================== */

.omata-chat-launcher {
  position: fixed;
  right: var(--gutter);
  bottom: var(--gutter);
  z-index: 60;
}
.omata-chat-launcher .pill {
  box-shadow: 0 6px 24px rgba(27, 25, 24, 0.18);
}

/* ---------------------------------------------------------------------------
   Het venster
--------------------------------------------------------------------------- */
/* De donkere waarden van dit oppervlak.

   Ze stonden in .omata-chat zelf, samen met de layout van het paneel. Sinds
   10 september 2026 staan ze in een eigen regel, want de chatbalk in de hero
   (onderaan dit bestand) is hetzelfde materiaal en hoort dus dezelfde
   waarden te gebruiken. Ze hier twee keer neerzetten zou betekenen dat een
   wijziging aan het ene oppervlak het andere stil laat afwijken. */
.omata-chat,
.heroballk,
/* En op de html-tag zolang er een schermvullend venster open staat: de
   achtergrond van het wortelelement is dan het oppervlak van de chat (zie
   deel 19), en die regel hoort dezelfde waarde te gebruiken en niet een
   tweede keer #171514 te bevatten. */
html[data-omata-chat-open="true"] {
  --chat-surface: #171514;                      /* dieper dan sumi-deep */
  --chat-raised: #221f1e;                       /* bericht en invoerveld */
  --chat-text: var(--washi);
  --chat-dim: #9d968e;                          /* washi 60% op raised, 5,62:1 */
  /* Vast en niet uit het palet: "online" is een status en geen merkkleur,
     dus dit bolletje blijft hetzelfde groen ook op de paletten waar shu
     oranje of iets anders is. Tegen --chat-surface (#171514) ruim zichtbaar
     als groen zonder neon te worden. */
  --chat-online: #4f9e6f;
  --chat-line: rgba(239, 230, 216, 0.14);
  --chat-radius: 18px;

  /* De gewone breedte van het venster, in de hoek rechtsonder.

     Als variabele en niet als getal in de width hieronder, omdat motief.js
     hem uitleest om de brede stand naar deze maat toe te laten krimpen (zie
     paneelMeet in deel 7 daar). Zou dat getal daar ook staan, dan zou een
     wijziging hier het venster stil op een andere maat laten uitkomen dan
     waar het in rust op staat. */
  --chat-klein: 400px;
}

.omata-chat {
  position: fixed;
  right: var(--gutter);
  bottom: var(--gutter);
  z-index: 70;
  width: min(var(--chat-klein), calc(100vw - var(--gutter) * 2));
  max-height: min(620px, calc(100vh - var(--gutter) * 2));
  display: flex;
  flex-direction: column;
  border-radius: var(--chat-radius);
  color: var(--chat-text);
  font-family: var(--font-sans);

  /* Geen achtergrond en geen overflow: hidden op het paneel zelf.

     Beide zijn nodig voor het lijntje. Dat zit in een svg-laag die 12 pixels
     buiten het paneel uitsteekt; met overflow: hidden werd die afgesneden en
     zag je er niets van. De achtergrond zit daarom op de drie kinderen, die
     samen het hele paneel vullen en de binnenhelft van de streek afdekken. Zo
     blijft alleen de buitenhelft over, en dat is de lijn die je ziet. */
  background: transparent;

  /* box-shadow en niet filter: drop-shadow.

     Een filter geldt voor het element én al zijn afstammelingen, dus ook voor
     het gloed-pseudo-element: dat zou een donkere schaduw op de gloed zelf
     zetten en die extra keer laten renderen. Een box-shadow raakt alleen dit
     element, en werkt ook prima op een doorzichtige achtergrond, want hij
     wordt vanaf de border-box getekend en volgt de afronding. */
  box-shadow: 0 18px 44px rgba(27, 25, 24, 0.34);
}

.omata-chat[hidden] { display: none; }

/* ---------------------------------------------------------------------------
   Het lijntje rond het kader.

   Eén doorlopende lijn die langs de omtrek van het paneel loopt en naar
   achteren geleidelijk lichter wordt, tot hij weg is. Geen gloed, geen halo,
   geen streepjes: een lijn met een verloop erin. Hij versnelt, wordt langer
   en donkerder zodra er iets in het gesprek gebeurt.

   Waarom een gestreepte svg-omtrek, en niet opnieuw een van de eerdere
   pogingen uit die reeks:

   - Een conische gradient (poging 4) verdeelt licht over hóeken en niet over
     omtrek. Op de hoeken van het paneel beslaat dezelfde hoekstap 3,4 keer
     zoveel pixels als op het midden van een lange zijde, dus de kop schiet
     door de hoeken en kruipt langs de zijden. Onbruikbaar voor iets dat als
     één lijn met één snelheid moet lezen. Dat geldt ook als je hem alleen als
     masker voor het verloop gebruikt: dan verandert de lengte van de staart
     terwijl hij ronddraait.
   - Een element over offset-path (poging 5) is stijf: een streep van 200
     pixels kan een hoek met een radius van 18 niet volgen en steekt eruit.
   - Hier beweegt geen enkel element. Wat beweegt is het streeppatroon ín de
     streek van de omtrek zelf, via stroke-dashoffset. Die volgt de bocht per
     definitie, want de streek ís het pad, en stroke-dasharray rekent in
     booglengte en niet in hoek. Constante snelheid, ook in de hoeken.

   Het verloop.

   Er is in svg geen manier om de dekking van één streek langs zijn eigen pad
   te laten verlopen. Een lineaire gradient loopt over het vlak en niet over
   de lijn, en op een gesloten lus heeft dat geen richting. Daarom bestaat de
   lijn uit een stapel van 32 volledige, doorlopende streken die allemaal
   dezelfde kop hebben en steeds verder naar achteren doorlopen: de kortste
   dekt alleen de voorste 1,4 procent, de langste de hele lijn. Waar veel
   lagen elkaar overlappen is de lijn donker, waar er één overblijft bijna
   weg. Zie glowProfile in chat.js voor de lengte en de dekking per laag.

   Dat is met opzet zo en niet met een reeks losse stukjes naast elkaar, zoals
   in poging 8. Daar had elk stukje zijn eigen dekking en overlapten de ronde
   uiteinden, wat samen 1 min (1 min a) in het kwadraat oplevert: bij a = 0,5
   werd elke naad 64 van 255 lichter, en dat was zichtbaar als een
   stippelpatroon. Hier is elke laag over zijn hele lengte doorlopend, dus er
   is nergens een naad. De enige overgang is een sprong in dekking op het
   eindpunt van een laag, en die is voor alle 32 lagen exact gelijk en
   nagerekend op 4,14 van 255 in het groenkanaal.

   Hier stond eerder een versie met drie geblurde lagen en een staart die
   uitdoofde in dichtheid in plaats van in dekking. Die leest als een
   stippellijn, en op de hoeken viel er soms een gat precies op de bocht,
   waardoor je twee rechte stukken zag die je oog tot een rechte hoek maakte.
   Weg, en de blur eromheen ook.

   Alle maten staan hier, niet in het script. Het script meet de omtrek van
   het paneel, integreert de positie, en rekent de dekking per laag uit.
--------------------------------------------------------------------------- */
.omata-chat {
  /* Per stand. Snelheid in pixels per seconde, lengte van het verloop als
     deel van de omtrek, en de dekking van de kop.

     Hier stond eerst een sprong van factor 2 op de snelheid tussen rust en
     typen, met als redenering dat je een standwissel dan uit je ooghoek
     opmerkt. Dat klopte, maar het voelde tijdens het typen zelf gejaagd aan:
     precies terwijl iemand nog aan het formuleren is, versnelt het venster
     eromheen. Dat is het tegenovergestelde van rustig. De sprong naar de
     stand "denken" hieronder blijft wel groot: daar wacht je, en dan mag het
     venster laten zien dat er iets gebeurt. Het script glijdt er in 0,14
     seconde naartoe, dus je ziet versnellen en geen sprong. */
  --glow-speed: 165;
  --glow-comet: 0.13;
  --glow-bright: 1;

  /* De lijn zelf.

     #8a2010 haalt 7,40:1 tegen washi #efe6d8. Dat is nodig, want de pagina is
     licht: een lichtere lijn komt dichter bij de achtergrond te liggen en
     niet verder ervan af. Nagemeten liggen shu #d1401f op 3,80:1 en het
     lichtoranje #ffb08a op 1,44:1, dus lichter dan het papier. Een lijn die
     naar de kop toe lichter wordt is op deze pagina niet zichtbaar te maken;
     donkerder wel. Vandaar dat het verloop van donker naar niets gaat en niet
     van licht naar donker.

     --glow-peak is de dekking van de kop in rust en wordt met --glow-bright
     vermenigvuldigd: 0,68 in rust, 0,85 tijdens typen en 1,0 tijdens denken,
     waar 1,054 door de browser wordt afgeklemd. Nagemeten geeft dat 2,43:1 in
     rust en 7,40:1 op vol, en dat verschil is het signaal. */
  /* Volgt het palet als er een gekozen is, en valt anders terug op de
     waarde die hier stond. Zo verandert er niets zonder data-palet. */
  --glow-ink: var(--palet-glow, #8a2010);
  /* 3 breed, waarvan 2,4 te zien is. Zie de uitleg bij .omata-chat__glow:
     de binnenste 0,6 valt met opzet achter het paneel. */
  --glow-width: 3;
  --glow-peak: 0.68;

  /* De veegstreep onder de kop, schermvullend op een telefoon. Stond in rood
     terwijl het palet salie is; de opmerking eronder beweerde "zelfde kleur"
     en dat was het niet meer.

     Als kanaalwaarden en niet als hex, want de streek is een verloop met vier
     stops in rgba. Gemeten tegen de kop #171514: shu-core #589166 haalt
     4,90:1 en shu-ink #6e9179 5,19:1, waar het oude #d1401f op 3,87 lag en
     #f2551f op 5,28. Dus dezelfde verhouding tussen de twee stops, en beide
     boven de 3 die voor een grafisch element geldt.

     Hier en niet uit het palet gerekend: css kan een hex niet in kanalen
     splitsen. Wijzigt data-palet naar een van de rode paletten, dan hoort dit
     paar mee te wijzigen. */
  --chat-sweep:      88, 145, 102;
  --chat-sweep-hoog: 110, 145, 121;
}

/* Jij typt. Het lijntje reageert terwijl je nog aan het formuleren bent, maar
   zacht: dit is geen wachtstand en hoeft dus niet aan te voelen als één.
   Was 330 / 0,17 / 1,25 (factor 2 op de snelheid); dat las als opgejaagd
   terwijl je nog aan het schrijven was. Nu een derde sneller dan rust in
   plaats van dubbel zo snel. */
.omata-chat[data-omata-glow="typing"] {
  --glow-speed: 220;
  --glow-comet: 0.145;
  --glow-bright: 1.1;
}

/* De assistent is bezig. Snelst, langst en donkerst; dit is de stand waarin
   het venster zegt dat er gewacht wordt en dat het wachten ergens op is. */
.omata-chat[data-omata-glow="thinking"] {
  --glow-speed: 545;
  --glow-comet: 0.24;
  --glow-bright: 1.55;
}

/* De laag met de lijn.

   De lijn sluit aan op de rand van het paneel, en dat is een rekensommetje en
   geen kwestie van proberen. z-index -1 zet de laag achter de drie vlakken
   die het paneel vullen, dus alles wat binnen de rand valt is niet te zien.
   Een streek staat gecentreerd op zijn pad, dus met een breedte W en een hart
   op OUT buiten de rand loopt hij van OUT min W/2 tot OUT plus W/2, en is de
   zichtbare dikte OUT plus W/2 zolang OUT niet groter is dan W/2.

     nu       W = 3    OUT = 0,9   van -0,6 tot 2,4   dikte 2,4, sluit aan
     eerder   W = 1,6  OUT = 2,0   van  1,2 tot 2,8   dikte 1,6, gat van 1,2

   Dat gat van 1,2 pixel was wat je zag. De binnenste 0,6 valt nu met opzet
   achter het paneel: precies op de rand uitkomen zou twee tegen elkaar
   aanliggende gladgestreken randen geven, en dan blijft er in de bochten een
   lichte haarlijn tussen staan. Een halve pixel eronder schuiven kost niets,
   want dat deel is toch bedekt.

   12 pixels uitsteek rondom is ruim: de streek komt tot 2,4 buiten de rand.
   Hier stond eerder 64, nodig voor de blur van de halo, maar die halo is er
   niet meer.

   Het pad is een rechthoek met een radius van 18,9, en dat is geen keuze maar
   een gevolg: het paneel is afgerond op 18, en een rechthoek die je 0,9 pixel
   naar buiten opschuift houdt zijn hoekvorm alleen als de radius met dezelfde
   0,9 meegroeit. De lijn loopt dus overal exact parallel aan de rand, ook in
   de hoeken. */
.omata-chat__glow {
  position: absolute;
  inset: -12px;
  z-index: -1;
  overflow: visible;
  pointer-events: none;
  opacity: calc(var(--glow-peak) * var(--glow-bright));
  /* Traag genoeg om als oplichten te lezen en niet als omschakelen. */
  transition: opacity 260ms linear;
}

.omata-chat__glow rect {
  fill: none;
  stroke: var(--glow-ink);
  stroke-width: var(--glow-width);
  /* Ronde uiteinden, zodat de kop een punt heeft en niet een afgesneden
     blokje. Bij 3 breed steekt die 1,5 pixel uit. De naden uit poging 8
     kunnen hier niet optreden: de lagen overlappen elkaar volledig in plaats
     van tegen elkaar aan te liggen. */
  stroke-linecap: round;
}

/* ---------------------------------------------------------------------------
   Vrij slepen naar de gewenste grootte.

   Hier stond een knop met twee standen, klein en groot (760x860 in plaats
   van 400x620). Dat waren maar twee vaste maten; wie iets daartussenin of
   groter wilde, kon dat niet. Vervangen door een sleephoek linksboven
   (.omata-chat__resize hieronder) die het venster naar elke grootte tussen
   een minimum en het scherm kan brengen. chat.js zet de maten daarbij als
   inline style; hier staat alleen nog de standaardmaat waarmee het venster
   opent, en het minimum waar chat.js niet onder mag gaan (RESIZE_MIN_W/H).

   Het paneel hangt vast aan right/bottom (zie .omata-chat hierboven), dus
   breder of hoger maken schuift vanzelf de linker- en bovenkant naar buiten
   en niet de rechter- of onderkant: precies wat je wil van een hoek
   linksboven, en de reden dat er geen expliciete transform-origin nodig is.

   Het gloedlijntje hoeft hier niets extra's voor: measureGlow() in chat.js
   leest bij elke frame clientWidth/clientHeight van het paneel en herbouwt
   de streek zodra die veranderen, ongeacht of dat door css komt of door een
   sleepbeweging. Zie de uitleg daar. */
.omata-chat__actions { display: flex; align-items: center; gap: 8px; margin-left: auto; }

/* De drie vlakken die samen het paneel vullen en de gloed vanbinnen dekken.
   De hoeken zitten hier en niet op het paneel, want het paneel mag niets
   afsnijden. */
.omata-chat__head,
.omata-chat__log,
.omata-chat__form { background: var(--chat-surface); position: relative; }

.omata-chat__head {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  /* Links ruimer dan rechts (32 tegen 14): de sleephoek (.omata-chat__resize
     hieronder) is 28 pixels breed en staat los in dezelfde ronde hoek, boven
     op deze padding. Zonder deze marge liep de titel er middenin, met de
     hoek half over de eerste letters heen. 32 geeft 4 pixel lucht na de
     hoek. 16 boven in plaats van 14, zodat de eerste regel niet strak tegen
     de hoek aan komt te staan. */
  padding: 16px 14px 12px 32px;
  border-bottom: 1px solid var(--chat-line);
  border-radius: var(--chat-radius) var(--chat-radius) 0 0;
}

.omata-chat__title {
  margin: 0;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--chat-text);
}

/* Wie er online is. Gedempt (--chat-dim, dezelfde toon als de placeholder,
   5,62:1) en niet op --chat-text: dit is bijzaak naast de titel en de
   verplichte mededeling eronder, geen derde regel die om evenveel aandacht
   vraagt. Het bolletje draagt de status niet alleen via kleur, de tekst
   zegt het ook. */
.omata-chat__status {
  display: flex;
  align-items: center;
  gap: 6px;
  /* 6 in plaats van 3: op 3 stond dit bijna tegen de titel aan, en dat
     versterkte het te-krappe gevoel van de hele kop. */
  margin: 6px 0 0;
  font-size: 12.5px;
  line-height: 1.3;
  color: var(--chat-dim);
}
.omata-chat__dot {
  flex: 0 0 auto;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--chat-online);
}

/* De mededeling dat je met een AI praat. Klein, maar op volle kleur: dit is
   een verplichte mededeling en die hoort niet gedempt te zijn. 14,72:1. */
.omata-chat__notice {
  /* 6 in plaats van 4, gelijk aan de marge boven de statusregel hierboven:
     zo krijgen titel, status en mededeling dezelfde tussenruimte in plaats
     van drie verschillende maten die elk voor zich krap ogen. */
  margin: 6px 0 0;
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--chat-text);
}

.omata-chat__close {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border: 1px solid var(--chat-line);
  border-radius: 999px;
  background: transparent;
  color: var(--chat-text);
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}
.omata-chat__close:hover { background: rgba(239, 230, 216, 0.10); }
.omata-chat__close:focus-visible { outline: 3px solid var(--shu-ink); outline-offset: 2px; }

/* Zelfde vorm als de sluitknop, opnieuw begonnen in plaats van vergroten. */
.omata-chat__refresh {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border: 1px solid var(--chat-line);
  border-radius: 999px;
  background: transparent;
  color: var(--chat-text);
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}
.omata-chat__refresh:hover { background: rgba(239, 230, 216, 0.10); }
.omata-chat__refresh:focus-visible { outline: 3px solid var(--shu-ink); outline-offset: 2px; }

/* --- De sleephoek --------------------------------------------------------
   Linksboven en niet ergens los in de kop: dat is de hoek die tegenover het
   vaste right/bottom-anker ligt, dus de hoek die daadwerkelijk verschuift
   als je het paneel groter of kleiner maakt.

   28px is ruim voor een muis, krap genoeg om niet over de titel heen te
   vallen: de kop begint pas op 14px vanaf boven en 18px vanaf links, dus de
   hoek deelt alleen het lege stukje bovenin de ronde hoek van het paneel
   zelf met niets anders. Pierre: dit is met de lat en niet met het oog
   bepaald, dus even nakijken of dat ook zo oogt.

   touch-action: none, anders probeert een telefoon de pagina te scrollen
   zodra je hier met je vinger beweegt in plaats van het paneel te
   verslepen. */
.omata-chat__resize {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  border: 0;
  /* Vult alleen de ronde hoek van het paneel, niet een eigen losse vorm
     erbovenop: op border-radius 18px snijdt dit exact de hoek van het
     paneel mee. */
  border-radius: var(--chat-radius) 0 0 0;
  background: transparent;
  color: var(--chat-dim);
  cursor: nwse-resize;
  touch-action: none;
  -webkit-appearance: none;
  appearance: none;
}
.omata-chat__resize:hover { background: rgba(239, 230, 216, 0.10); color: var(--chat-text); }
.omata-chat__resize:focus-visible { outline: 3px solid var(--shu-ink); outline-offset: -3px; }
.omata-chat__resize svg { width: 15px; height: 15px; }

/* Gezet op html zolang er gesleept wordt (chat.js, bindResize). Twee dingen:
   de cursor blijft nwse-resize tonen ook als de muis even voor het paneel
   uit loopt, en de pagina eromheen selecteert geen tekst terwijl je over
   hem heen sleept. */
html.omata-chat-resizing { cursor: nwse-resize; user-select: none; }

/* ---------------------------------------------------------------------------
   Het gesprek
--------------------------------------------------------------------------- */
.omata-chat__log {
  flex: 1 1 auto;
  min-height: 140px;
  overflow-y: auto;
  overscroll-behavior: contain;   /* scrollen in de chat trekt de pagina niet mee */
  padding: 16px 18px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.omata-msg {
  max-width: 84%;
  padding: 10px 14px;
  border-radius: 16px;
  font-size: 15px;
  line-height: 1.5;
  white-space: pre-wrap;   /* regeleindes van de bezoeker blijven staan */
  overflow-wrap: break-word;
}

/* Bezoeker en assistent zijn op drie manieren onderscheiden, niet alleen op
   kleur: kant, kleur en de vorm van de hoek. Alleen kleur zou onvoldoende
   zijn voor wie die niet ziet. */
.omata-msg--visitor {
  align-self: flex-end;
  background: var(--washi);
  color: var(--sumi-deep);
  border-bottom-right-radius: 6px;
}
.omata-msg--agent {
  align-self: flex-start;
  background: var(--chat-raised);
  color: var(--chat-text);
  border: 1px solid var(--chat-line);
  border-bottom-left-radius: 6px;
}

/* De afzender staat er ook uitgeschreven, alleen voor schermlezers, zodat de
   kant en de kleur niet de enige aanduiding zijn. */
.omata-msg__who {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}

/* ---------------------------------------------------------------------------
   Invoer
--------------------------------------------------------------------------- */
.omata-chat__form {
  display: flex;
  align-items: flex-end;
  gap: 8px;
  padding: 12px;
  border-top: 1px solid var(--chat-line);
  border-radius: 0 0 var(--chat-radius) var(--chat-radius);
}

.omata-chat__input {
  flex: 1 1 auto;
  resize: none;
  max-height: 120px;
  padding: 10px 12px;
  border: 1px solid var(--chat-line);
  border-radius: 12px;
  background: var(--chat-raised);
  color: var(--chat-text);
  font-family: inherit;
  font-size: 15px;
  line-height: 1.45;
}
.omata-chat__input::placeholder { color: var(--chat-dim); opacity: 1; }

/* De knop om de mededeling in te klappen staat alleen op een telefoon in
   beeld; zie de toelichting in de mediaquery onderaan dit bestand. */
.omata-chat__mededeling { display: none; }

/* ZESTIEN PIXELS OP EEN AANRAAKSCHERM, EN DAT IS GEEN SMAAKKEUZE.

   Safari op iOS zoomt de pagina in zodra je een invoerveld aantikt waarvan de
   letter kleiner is dan 16px. Dat is geen voorkeur die je kan uitzetten (de
   enige andere weg is maximum-scale in de viewport-tag, en dat neemt de
   bezoeker het zoomen áf — dat doen we niet).

   WAT DIE ZOOM AANRICHTTE, 16 september 2026. Het chatveld stond op 15px. Bij
   het aantikken zoomde Safari dus in: de zichtbare laag werd kleiner dan de
   pagina en verschoof mee. Het paneel hangt op visualViewport.height en die
   is in de maat van díé gezoomde laag, dus stond het niet meer over het
   scherm: de sluitknop en de verstuurknop liepen rechts buiten beeld, en
   onder de balk bleef een reep pagina staan tussen de balk en het
   toetsenbord. Dat was het gat dat twee rondes niet te vinden was — het zat
   niet in de meting maar in de zoom die de meting scheef zette.

   Dezelfde regel gold al voor .heroballk__invoer (16px) en
   .omata-login__input (16px); dit veld was de uitzondering. (pointer: coarse)
   en niet een breedte: een iPad zoomt even hard als een telefoon, en daar is
   het paneel niet schermvullend. controle.py bewaakt de drie sinds vandaag. */
@media (pointer: coarse) {
  .omata-chat__input { font-size: 16px; }
}
.omata-chat__input:focus-visible {
  outline: 2px solid var(--shu-ink);
  outline-offset: 1px;
  border-color: transparent;
}

.omata-chat__send {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border: 0;
  border-radius: 999px;
  background: var(--shu);
  color: var(--washi);
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}
.omata-chat__send:hover { background: var(--shu-deep); }
.omata-chat__send:focus-visible { outline: 3px solid var(--washi); outline-offset: 2px; }
.omata-chat__send[disabled] { opacity: 0.45; cursor: default; }

/* ---------------------------------------------------------------------------
   Mobiel: het venster vult het scherm.

   8 september 2026: op een telefoon voelde typen in dit venster niet goed
   aan: het toetsenbord, de ingetypte tekst en al verzonden berichten waren
   niet goed te zien terwijl je typte. De oorzaak lag niet hier, maar in de
   meta viewport-tag van de pagina (index.html, na-het-afsluiten/index.html,
   dossier/index.html): zonder `interactive-widget=resizes-content` daarin
   krimpt `dvh` in de meeste browsers NIET mee met het toetsenbord (Chrome's
   standaardgedrag is dan "resizes-visual": de lay-outviewport, en dus deze
   100dvh, blijft de volledige schermhoogte, en het toetsenbord schuift dan
   gewoon over het onderste stuk heen — precies waar het invoerveld staat).
   Met die tag erbij krimpt 100dvh wél mee: het paneel wordt dan echt kleiner
   zodra het toetsenbord opent, met het invoerveld nog steeds onderaan maar
   nu boven het toetsenbord, en .omata-chat__log (flex: 1 1 auto) neemt vanzelf
   de rest van de overgebleven hoogte. Geen wijziging hier nodig gebleken;
   deze regel stond al goed.

   8 september 2026, ronde 5: die meta-tag alleen bleek in de praktijk niet
   overal genoeg (niet elke browser kent hem), dus chat.js zet er sindsdien
   een tweede, robuustere laag boven op: syncViewportHeight() in chat.js
   meet via window.visualViewport rechtstreeks hoeveel scherm er nog vrij is
   en zet dat als inline height/top op dit paneel. Een inline style wint
   altijd van deze regel, dus 100dvh hieronder is nu het vangnet voor de
   browsers zonder visualViewport (zeer zeldzaam) en niet meer de enige
   laag. Zie de uitleg bij syncViewportHeight() in chat.js. */
@media (max-width: 720px) {
  /* ZWART, EN NIETS VAN DE PAGINA, zodra het venster open staat. Op verzoek,
     16 september 2026: op een telefoon hoort de site niet naast of door het
     chatvenster te schemeren.

     TWEE REGELS, EN GEEN LAAG MET EEN Z-INDEX. Dat was de eerste poging (een
     ::before op de html-tag, vast gepositioneerd, boven de pagina) en die is
     hier niet goed genoeg: een vast gepositioneerde laag dekt de layoutlaag,
     en die krimpt met het toetsenbord mee — wat eronder valt, en wat door de
     doorschijnende balken van iOS en Safari schemert, blijft dan de pagina.

     Nu:
       1. De achtergrond op de html-tag. De achtergrond van het wortelelement
          wordt over het hele doek geschilderd, niet over de layoutlaag. Ze
          dekt dus ook het stuk achter het toetsenbord, en er is geen
          z-index waarmee iets erboven kan komen.
       2. Alles wat in body staat behalve het venster zelf op display: none.
          Geen z-index, geen stapelvolgorde, geen uitzondering die erboven kan
          kruipen: wat er niet is, is er niet. Een schermlezer leest de pagina
          ook niet meer, wat bij een modaal venster hoort.

          DIT WAS visibility: hidden, EN DAT WAS DE OORZAAK VAN TRAAGHEID.
          Onzichtbaar is niet hetzelfde als weg: de pagina hield haar plaats
          in de opmaak, dus haar lagen bleven bestaan en — erger — de drie
          animaties erop bleven op volle snelheid doorlopen achter een venster
          waar niets van te zien was. Het motief in het hero (motief.js en
          motiefkern.js) en de mockupspeler (hero-mockup.js) tekenen elk per
          frame, en ze stoppen zichzelf via een IntersectionObserver zodra hun
          element niet meer in beeld is. visibility: hidden telt daarvoor niet
          mee, display: none wel. Eén woord hier zet dus drie tekenlussen stil
          zolang je zit te typen, en dat is op een telefoon het verschil
          tussen vlot en stroperig.

          De reden dat er eerst visibility stond, was de scrollstand: met
          display: none klapt de pagina in en gaat die stand verloren. Dat
          wordt sinds 16 september 2026 in chat.js bewaard en bij het sluiten
          teruggezet (zie state.scrollY daar), dus die reden is weg.

     Alleen onder 720px, want alleen daar is het venster schermvullend; op een
     muisscherm is het een venster in de hoek en hoort de pagina eromheen
     gewoon te blijven staan. */
  /* HET OPPERVLAK VAN DE CHAT EN NIET ZWART, sinds 16 september 2026.

     Hier stond #000. Dat dekte de pagina wel af, maar het maakte elke pixel
     die het paneel níet vult tot een zichtbare zwarte band — en op een iPhone
     zijn dat er af en toe een paar, omdat iOS de maten van de zichtbare laag
     met vertraging bijwerkt (zie syncViewportHeight in chat.js). Op de derde
     schermopname was dat een zwart kader boven de kop.

     In dezelfde kleur als het paneel valt zo'n strook niet meer op: je ziet
     het oppervlak van de chat doorlopen tot de rand van het scherm. Het dekt
     de pagina even goed af — het is een dekkende kleur — en het blijft de
     achtergrond van het wortelelement, dus ze wordt over het hele doek
     geschilderd, ook achter het toetsenbord en achter de doorschijnende
     balken van Safari. */
  html[data-omata-chat-open="true"],
  html[data-omata-chat-open="true"] body { background: var(--chat-surface); }
  html[data-omata-chat-open="true"] body > *:not(.omata-chat) { display: none; }

  /* EN DE PAGINA ERACHTER BLIJFT STAAN WAAR ZE STOND.

     Het paneel is vast gepositioneerd, maar de pagina eronder is nog altijd
     het scrollvlak van het toestel: elke veeg over de kop, over de balk of
     over de rand van het paneel schoof de pagina erachter mee. Je merkte dat
     niet zolang het venster open stond — de pagina is onzichtbaar — maar wél
     bij het sluiten: je stond dan honderden pixels verder dan waar je het
     venster opende, en op de hoofdpagina sprong de hero-balk mee naar de
     stand die bij die nieuwe scrollpositie hoort. Alles verspringt.

     pinch-zoom en niet none: vegen om de pagina te verschuiven kan niet meer,
     maar knijpen om in te zoomen blijft. Dat is een toegankelijkheidsmiddel
     en hoort niet weg voor een scrollprobleem.

     Het gesprek zelf scrollt gewoon door: voor een veeg binnen .omata-chat__log
     is dat vlak zelf het scrollvlak, en dan kijkt de browser alleen naar de
     touch-action van het aangeraakte element tot en met dat vlak — niet naar
     het paneel erboven. Datzelfde geldt voor het invoerveld dat over meer
     regels loopt. overscroll-behavior: contain op het gesprek (zie daar)
     dekte al af dat het dóórscrollen aan het einde de pagina niet meetrekt;
     dit dekt de veeg af die nooit in het gesprek begon. */
  .omata-chat { touch-action: pinch-zoom; }

  /* EN DE PAGINA KAN NIET MEER SCROLLEN. Dit is de regel die het verspringen
     oplost, en hij is gevonden met een meting op het toestel zelf (16
     september 2026, zie site/_meting.js).

     WAT ER GEBEURDE. Tik het veld aan, en iOS schoof het document naar
     onderen om dat veld boven het toetsenbord te houden — `scrollY` sprong
     van 0 naar 103, en soms naar 435. Dat zou niets mogen betekenen voor een
     venster dat `position: fixed` staat, maar op iOS hangt een vast
     gepositioneerd element tijdens een open toetsenbord aan het document en
     niet aan het venster. De gemeten bovenrand van het paneel liep dus mee:
     -103, en in het ergste geval -435. Het venster stond boven het scherm,
     en dat is het verspringen dat drie opnames lang niet te vatten was.

     Dat de pagina eronder al onzichtbaar is en geen hoogte meer heeft (zie
     de regel hierboven) was niet genoeg: iOS mag voor een veld dat onder het
     toetsenbord dreigt te vallen ook voorbij de onderrand van een pagina
     scrollen. En de bezoeker kon het met een veeg ook zelf.

     Een body die zelf `position: fixed` staat heeft geen scroll meer — niet
     voor iOS en niet voor een vinger. Daarmee kan scrollY niet meer
     veranderen zolang het venster open staat, en kan het paneel dus niet meer
     wegschuiven. Dit is de klassieke sluiting voor een modaal scherm op iOS;
     de reden dat ze hier niet stond, is dat ze de scrollstand van de pagina
     weggooit — en die bewaren we sinds vandaag zelf (state.scrollY in
     chat.js).

     `position: fixed` op body maakt geen nieuw ankerpunt voor vast
     gepositioneerde kinderen (alleen transform, filter en contain doen dat),
     dus het paneel blijft aan het venster hangen zoals het hoort. */
  html[data-omata-chat-open="true"] body {
    position: fixed;
    inset: 0;
    overflow: hidden;
  }

  .omata-chat {
    inset: 0;
    right: 0;
    bottom: 0;
    width: 100%;
    max-height: none;
    height: 100%;
    height: 100dvh;   /* dvh, want de adresbalk van een telefoon krimpt mee */
    border-radius: 0;
    box-shadow: none;
    /* EN HET PANEEL ZELF DEKKEND, alleen hier. Op een telefoon vult het het
       hele scherm en is de gloed eromheen toch buiten beeld (zie de regels
       hieronder), dus er is geen reden meer om het paneel doorzichtig te
       laten. Het is wel een reden om het dekkend te máken: zou de gemeten
       hoogte een frame achterlopen op het toetsenbord, dan staat daar het
       oppervlak van de chat en niet een reep pagina die erdoorheen kijkt.
       Het gat zelf hoort er niet te zijn — dat is wat vvVolgen() in chat.js
       afdekt — maar een gat waar je niets van ziet, is er bijna geen. */
    background: var(--chat-surface);
  }
  .omata-chat__head { border-radius: 0; }
  /* DE VEILIGE ZONE ONDERAAN, sinds 18 september 2026. Op een telefoon vult
     dit venster het hele scherm, en de invoerrij staat dus tegen de onderrand.
     Op een iPhone zonder thuisknop loopt daar de home-indicator over: de
     onderste twaalf pixels padding vielen eronder, en het veld en de
     verstuurknop kwamen tegen die balk aan.

     env(safe-area-inset-bottom) is nul op elk toestel dat die balk niet heeft,
     en nul zolang het toetsenbord open staat (dan dekt het toetsenbord die
     zone). Er verandert dus niets behalve precies daar waar het nodig is. Dit
     was het enige env(safe-area-inset-*) in de hele css. */
  .omata-chat__form {
    border-radius: 0;
    padding-bottom: calc(12px + env(safe-area-inset-bottom, 0px));
  }

  /* MINDER KOP, MEER GESPREK. Op verzoek, 16 september 2026: de kop nam op
     een telefoon 129 van de 812 pixels, en met het toetsenbord open is dat
     bijna een derde van wat er overblijft.

     Wat er NIET gebeurt: de mededeling inkorten of wegklappen. "U praat met
     een AI-assistent…" staat er letterlijk zoals aangeleverd en hoort vast en
     zichtbaar te blijven — dat is de transparantieplicht (EU AI Act art. 50),
     geen opmaakkeuze. Ook de lettergrootte blijft: 12,5px is de ondergrens
     die hier al gekozen was.

     Wat wél: de titel en de stand op één regel in plaats van twee, en de
     lucht eromheen strakker. Dat is ruim veertig pixels, en die gaan naar het
     gesprek — ongeveer één bericht meer in beeld. Past de stand er in een
     taal niet naast (het Frans is langer), dan wikkelt hij naar de tweede
     regel en staat het zoals het hiervoor stond. */
  .omata-chat__head { padding: 10px 14px 8px 18px; }

  /* DE MEDEDELING IN- EN UITKLAPPEN, alleen hier. Op een breed scherm is het
     venster 620 pixels hoog en kost die mededeling niets; daar zou de knop
     alleen rommel zijn.

     INGEKLAPT IS ÉÉN REGEL EN NIET WEG: -webkit-line-clamp: 1 laat de eerste
     regel staan met drie punten erachter, en "U praat met een AI-assistent."
     past daar helemaal op — in het Nederlands, het Frans en het Engels
     nagemeten. Dat iemand met een AI praat, hoort hij te zien zonder ergens op
     te duwen (EU AI Act art. 50); wat wegklapt is de rest van de zin.
     display: none op deze regel is dus fout, en controle.py houdt dat tegen.

     Het scheelt 32 pixels: de kop gaat van 105 naar 73 en het berichtenvak
     groeit even hard mee. */
  .omata-chat__mededeling {
    display: flex; align-items: center; justify-content: center;
    flex: none; width: 34px; height: 34px; padding: 0;
    border: 0; border-radius: 999px; cursor: pointer;
    background: transparent; color: inherit;
    transition: background-color 160ms ease, transform 200ms ease;
  }
  .omata-chat__mededeling:hover { background: rgba(232, 238, 225, 0.10); }
  .omata-chat__mededeling:focus-visible { outline: 2px solid var(--chat-text); outline-offset: 2px; }
  .omata-chat__mededeling svg { display: block; }
  /* De pijl wijst naar wat er gebeurt: omlaag om open te klappen, omhoog om
     in te klappen. */
  .omata-chat[data-mededeling="open"] .omata-chat__mededeling svg { transform: rotate(180deg); }

  .omata-chat[data-mededeling="dicht"] .omata-chat__notice {
    display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 1;
    overflow: hidden;
  }
  .omata-chat__head > div:first-child {
    display: flex; flex-wrap: wrap; align-items: baseline; column-gap: 10px;
  }
  .omata-chat__head .omata-chat__status { margin-top: 0; }
  .omata-chat__head .omata-chat__notice {
    flex-basis: 100%; margin-top: 4px; line-height: 1.3;
  }
  /* En de berichten zelf iets ruimer in het vak: acht pixels lucht eruit,
     links en rechts twee, zonder aan de tekst of aan de afstand tussen twee
     berichten te raken. */
  .omata-chat__log { padding: 12px 16px; }

  /* Schermvullend valt de gloed rond het paneel buiten beeld: er is geen
     buitenkant meer om op te lichten. Daarom hier hetzelfde signaal als een
     dunne lijn die onder de kop doorloopt. Zelfde gedachte, zelfde tempo,
     en de kleur volgt nu het palet. */
  /* Schermvullend is er niets te verslepen: het venster is al zo groot als
     het scherm, en chat.js haalt de inline maten van een eerdere sleepbeurt
     er hier zelf af (syncModal, zie de uitleg bij clearCustomSize). Zonder
     dat zou een venster dat op desktop breder gesleept was, hier alsnog op
     die breedte blijven staan in plaats van het scherm te vullen: een
     inline style wint altijd van de width/height hierboven. */
  .omata-chat__resize { display: none; }
  /* De sleephoek is hierboven verborgen, dus is de extra linkermarge ervoor
     (.omata-chat__head hierboven) hier ook niet meer nodig. */
  .omata-chat__head { padding-left: 18px; }

  /* Schermvullend is er geen buitenkant meer te zien, dus een lijn rondom
     heeft geen zin. In plaats daarvan een veegstreep onder de kop. */
  .omata-chat__glow { display: none; }
  .omata-chat__head::after {
    content: '';
    position: absolute;
    left: 0; right: 0; bottom: -1px;
    height: 2px;
    background: linear-gradient(90deg,
      rgba(var(--chat-sweep), 0) 0%,
      rgba(var(--chat-sweep), 0.9) 22%,
      rgba(var(--chat-sweep-hoog), 0.5) 38%,
      rgba(var(--chat-sweep), 0) 60%,
      rgba(var(--chat-sweep), 0) 100%);
    background-size: 220% 100%;
    animation: omata-glow-sweep 14s linear infinite;
  }
  @keyframes omata-glow-sweep {
    from { background-position: -60% 0; }
    to   { background-position: 160% 0; }
  }
  .omata-msg { max-width: 88%; }

  /* De starter zou onder het schermvullende venster blijven staan en met de
     tab-toets nog bereikbaar zijn.

     Op het attribuut geselecteerd en niet op een klasse, want de knop die de
     chat opent hoeft niet van deze component te zijn: op deze pagina is dat
     .dock, die zijn eigen zichtbaarheidslogica heeft. chat.js zet het
     attribuut op wat er via registerLauncher is aangemeld, wat dat ook is. */
  [data-omata-behind="true"] { display: none; }
}

/* ---------------------------------------------------------------------------
   Bewegingsvoorkeur.

   De gloed verdwijnt niet, hij staat stil. Een statische rode uitstraling
   rond het paneel is nog steeds het signaal dat het ding leeft; het is de
   beweging die hinderlijk kan zijn, niet de kleur.
--------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .omata-chat__head::after { animation: none; }
  /* Het script start zijn lus hier niet op en zet het lijntje één keer neer.
     Wat je dan ziet is een stilstaande lichtboog op de linkerbovenhoek, niet
     een lijn die halverwege bleef hangen: de kometlengte staat voor deze
     stand op een halve omtrek en de standen wisselen niet meer. */
  .omata-chat { --glow-comet: 0.5; --glow-bright: 0.9; }
  .omata-chat[data-omata-glow="typing"],
  .omata-chat[data-omata-glow="thinking"] { --glow-comet: 0.5; --glow-bright: 0.9; }
}

@media (prefers-reduced-motion: no-preference) {
  .omata-chat { animation: omata-chat-in 220ms cubic-bezier(0.22, 0.61, 0.36, 1); }
  @keyframes omata-chat-in {
    from { opacity: 0; transform: translateY(10px) scale(0.99); }
    to   { opacity: 1; transform: none; }
  }
}

/* ---------------------------------------------------------------------------
   Bestanden meesturen.

   De echte file-invoer staat buiten beeld en niet op display: none: dat
   laatste haalt hem bij sommige browsers ook uit het bereik van .click(), en
   dan doet de knop niets.
--------------------------------------------------------------------------- */
.omata-chat__bestand-invoer {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px; border: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
}

.omata-chat__klem {
  flex: none;
  display: flex; align-items: center; justify-content: center;
  /* 44 bij 44, het minimum voor iets dat je met een vinger raakt. */
  height: 44px; width: 44px;
  border: 0; border-radius: 999px;
  background: transparent;
  color: var(--chat-text-dim, rgba(239, 230, 216, 0.72));
  cursor: pointer;
  -webkit-appearance: none; appearance: none;
  transition: color 200ms var(--ease), background-color 200ms var(--ease);
}
.omata-chat__klem:hover { color: var(--chat-text, #efe6d8); background: rgba(239, 230, 216, 0.08); }
.omata-chat__klem:focus-visible { outline: 2px solid var(--shu-ink); outline-offset: 2px; }

.omata-chat__bestanden {
  display: flex; flex-wrap: wrap; gap: 6px;
  padding: 0 14px 10px;
  /* Zelfde vlak als de kop, het gesprek en het formulier. Zonder dit is deze
     strook doorzichtig en kijk je door het paneel heen naar de pagina. */
  background: var(--chat-surface);
}
/* display: flex hierboven verslaat het hidden-attribuut, want dat is niets
   meer dan display: none uit de standaardstijl van de browser. Zonder deze
   regel bleef er een lege strook staan tussen het gesprek en het invoerveld,
   en die was doorzichtig. */
.omata-chat__bestanden[hidden] { display: none; }
.omata-chat__bestand {
  display: inline-flex; align-items: center; gap: 8px;
  max-width: 100%;
  padding: 6px 6px 6px 12px;
  border-radius: 999px;
  border: 1px solid var(--chat-line, rgba(239, 230, 216, 0.14));
  background: rgba(239, 230, 216, 0.06);
  font-size: 13px;
  color: var(--chat-text, #efe6d8);
}
/* De miniatuur in de chip. Vierkant en bijgesneden, zodat vijf foto's van vijf verhoudingen
   één rij blijven in plaats van een trap. Zo groot als de chip hoog is en niet groter: dit is
   een bevestiging dat je de juiste koos, geen weergave van de foto. */
.omata-chat__bestand-kijkje {
  flex: none;
  width: 28px; height: 28px;
  object-fit: cover;
  border-radius: 6px;
  margin-left: -6px;
}
.omata-chat__bestand-naam {
  /* Afkappen en niet laten afbreken: een chip met een naam over twee regels
     duwt het invoerveld weg. */
  max-width: 22ch;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.omata-chat__bestand-maat { opacity: 0.62; flex: none; }
.omata-chat__bestand-weg {
  flex: none;
  display: flex; align-items: center; justify-content: center;
  height: 28px; width: 28px;
  border: 0; border-radius: 999px;
  background: transparent;
  color: inherit;
  cursor: pointer;
  -webkit-appearance: none; appearance: none;
}
.omata-chat__bestand-weg:hover { background: rgba(239, 230, 216, 0.12); }
.omata-chat__bestand-weg:focus-visible { outline: 2px solid var(--shu-ink); outline-offset: 1px; }

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

/* ===========================================================================
   De chatbalk in de hero, en de knop rechtsonder als dezelfde vorm.
   10 september 2026.

   WAT DIT IS

   In de hero stond een knop "Start uw aanvraag" die het chatvenster opende.
   Die knop is nu een balk waarin je meteen kan typen. Scroll je naar beneden
   zonder iets te typen, dan schuift die balk naar de hoek rechtsonder en
   wordt hij onderweg weer de knop die er altijd stond. Scroll je terug naar
   boven, dan gebeurt precies het omgekeerde.

   ÉÉN ELEMENT, GEEN TWEE

   Balk en knop zijn hetzelfde element (#heroBalk). Dat is de hele reden dat
   de overgang als één beweging leest: er wordt niets weggehaald en niets
   neergezet, er verandert alleen een rechthoek van maat en plaats terwijl
   twee vullingen over elkaar heen wisselen.

   Twee knoppen die elkaar op het juiste moment aflossen was het alternatief,
   en dat was het niet: dan moet je op de wissel twee posities exact laten
   samenvallen, en op het moment dat het dan tóch een pixel scheelt zie je
   het element springen. Nu is er geen wissel.

   De maat en de plaats komen per frame uit motief.js (deel 7) als inline
   left/top/width/height. Daar staat ook waarom dat inline gebeurt en niet
   met een css-transition: de beweging hangt aan de scrollpositie en niet aan
   de klok, dus ze moet ook achteruit kunnen lopen zodra de bezoeker
   terugscrollt. Een transition kan dat niet.

   WAAROM DE HOEKEN NIET MEEBEWEGEN

   Beide standen zijn volledig rond (border-radius: 999px), dus er is geen
   hoekvorm om te animeren. Dat is niet toevallig zo uitgekomen: de vraag was
   een balk met dezelfde vormtaal als de knop, en de knop is een pil.
   =========================================================================== */

.heroballk {
  position: fixed;
  /* left/top/width/height komen uit het script. Deze vier staan hier alleen
     zodat het element vóór het eerste frame niet linksboven op het scherm
     verschijnt. */
  left: 0;
  top: -200px;
  width: 320px;
  height: 64px;
  /* 44 en niet 60, sinds 14 september 2026. De balk stond boven de vaste kop
     (z-index 50) en dus ook boven het uitklapmenu "Verzekeringen" dat eronder
     hangt: je las de productenlijst met een chatbalk er dwars doorheen. Een
     balk die over de navigatie valt is op geen enkele pagina goed, dus hij
     gaat eronder. Boven de pagina-inhoud blijft hij staan (die zit op 10 en
     lager), en de schermen die er wél overheen horen — het chatvenster (70),
     het informatie- en inlogscherm (80) — stonden al hoger.
     Zelfde waarde bij zijn tegenhanger: .lp-balk in landing.css doet hetzelfde op de landingspagina's. */
  z-index: 44;
  /* Het element zelf vangt niets: de vlakken en de inhoud eronder doen dat,
     en die zetten hun eigen pointer-events aan zodra ze aan de beurt zijn.
     Zo is er nooit een onzichtbaar doel dat de hero afdekt. */
  pointer-events: none;
  /* Geen transition op opacity: die waarde komt per frame uit de reveal in
     motief.js en moet exact volgen. */
  opacity: 0;
  visibility: hidden;
}

/* De doos die alles draagt. Bestaat apart van .heroballk omdat er twee
   soorten verdwijnen zijn die elkaar niet in de weg mogen zitten:

   - de reveal en de scroll zetten opacity op .heroballk, per frame, zonder
     transition;
   - opengaan van het chatvenster zet .is-weg op deze doos, mét transition,
     want dat is een gebeurtenis en geen scrollpositie.

   Op één element zouden die twee elkaar overschrijven. */
.heroballk__doos {
  position: absolute;
  inset: 0;
  opacity: 1;
  transform: none;
  transition: opacity 180ms var(--ease),
              transform 180ms var(--ease);
}
/* Het chatvenster staat open: de balk hoort er dan niet ook nog te staan.
   Het venster heeft het gesprek en het invoerveld overgenomen.

   Alleen opacity en transform, geen visibility. Dat is met opzet: visibility
   is een geërfde eigenschap, en het script zet hem al op .heroballk zelf om
   de balk buiten de reveal en buiten beeld te houden. Zou hij hier óók
   staan, dan zou een van de twee de ander stil overschrijven, in beide
   richtingen. Wat een doorzichtige balk uit de tab-orde houdt, is dat het
   script de knoppen en het veld op `disabled` zet zolang het venster open
   staat; zie balkBereikbaar in deel 7 van motief.js. */
.heroballk__doos.is-weg {
  opacity: 0;
  transform: scale(0.96);
}

/* --- De twee vullingen ---------------------------------------------------
   Beide dekken de hele doos en wisselen over elkaar heen. De dekking komt
   per frame uit het script; hier staat alleen hoe ze eruitzien.
------------------------------------------------------------------------- */
.heroballk__vlak {
  position: absolute;
  inset: 0;
  border-radius: 999px;
  pointer-events: none;
}

/* De balk. Een ruit en geen vlak: --balk-vlak staat op transparant (zie de
   toelichting bij dat token in pagina.css).

   Hier stond --chat-surface, hetzelfde dekkende oppervlak als het chatvenster,
   met als reden dat het hetzelfde gesprek is en dus hetzelfde materiaal. Dat
   klopt nog voor het venster; de balk staat alleen op het bogenmotief en moet
   dat laten zien.

   De blur is nieuw en hoort erbij: zonder hem is dit geen ruit maar een gat.
   Verzadiging en straal zijn die van de rest van de site, uit glas.css. De
   slagschaduw is van 0,38 naar 0,22: een vlak zonder vulling werpt geen zware
   schaduw, dat leest als twee objecten in plaats van één. */
.heroballk__vlak--balk {
  background: var(--balk-vlak);
  border: 1px solid var(--chat-line);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.20),
              0 14px 40px rgba(27, 25, 24, 0.22);
  backdrop-filter: blur(var(--glas-blur, 18px)) saturate(140%);
  -webkit-backdrop-filter: blur(var(--glas-blur, 18px)) saturate(140%);
}

/* De knop rechtsonder. Dezelfde waarden als .pill in pagina.css buiten de
   hero: donker vlak, lichte tekst. Niet de lichte hero-pil, want deze staat
   op de pagina en niet op het donkere hero. */
.heroballk__vlak--pil {
  background: var(--btn-bg);
  box-shadow: 0 6px 24px rgba(27, 25, 24, 0.18);
}

/* --- Het invoerveld ----------------------------------------------------- */
.heroballk__balk {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 10px 10px 8px;
  /* Zodat de ronde hoeken van het veld en de knop binnen de pil blijven bij
     de smalste maten die tijdens de beweging voorbijkomen. */
  overflow: hidden;
}

.heroballk__invoer {
  flex: 1 1 auto;
  resize: none;
  /* Groeit mee tot deze hoogte; het script rekent de hoogte van de balk
     daarop uit, zodat de balk zelf meegroeit en de tekst niet wegvalt. */
  max-height: 96px;
  /* Eén regel is 46 hoog. Staat hier én als BALK_MIN_INVOER in motief.js:
     het script zet de hoogte zelf, en zonder deze regel zou het veld vóór
     het eerste frame op de standaardhoogte van een textarea staan. */
  min-height: 46px;
  box-sizing: border-box;
  padding: 11px 16px;
  border: 1px solid var(--chat-line);
  border-radius: 999px;
  /* Ook doorzichtig. Stond op --chat-raised, en dat is het blok dat je in de
     balk zag zitten. */
  background: var(--balk-vlak);
  color: var(--chat-text);
  font-family: inherit;
  font-size: 16px;
  line-height: 1.4;
  /* Geen eigen schuifbalk in een veld van één regel: de hoogte volgt de
     inhoud, dus er valt niets te schuiven zolang de tekst past. */
  overflow-y: auto;
}
.heroballk__invoer::placeholder { color: var(--chat-dim); opacity: 1; }
/* Op een telefoon vier pixels minder marge aan weerszijden van de tekst. De
   letter blijft 16px — onder die maat zoomt Safari op iOS in zodra je het
   veld aanraakt — en de plaatshouder krijgt de ruimte die hij nodig heeft om
   op één regel te blijven. Zie ook de korte plaatshouder in pagina.js. */
@media (max-width: 420px) {
  /* En de plaatshouder zelf een maat kleiner. Dat mag wél: Safari op iOS
     kijkt naar de letterhoogte van het VELD om te beslissen of het inzoomt,
     en die blijft 16. Wat je typt staat dus nog altijd op 16px; alleen de
     grijze zin die er staat zolang het veld leeg is, is 14.

     Gemeten op 390 breed: binnenwerks is er 200 pixels, en de korte zin
     heeft er op 14px 190 nodig. Op 16 was dat 217 en werd hij afgekapt. */
  .heroballk__invoer::placeholder { font-size: 14px; }
}
.heroballk__invoer:focus-visible {
  outline: 2px solid var(--shu-ink);
  outline-offset: 1px;
  border-color: transparent;
}

.heroballk__klem,
.heroballk__send {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 0;
  border-radius: 999px;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
  -webkit-tap-highlight-color: transparent;
}

/* 44 bij 44, het minimum voor iets dat je met een vinger raakt. Zelfde maat
   en zelfde gedrag als de klem in het chatvenster. */
.heroballk__klem {
  height: 44px;
  width: 44px;
  background: transparent;
  color: rgba(239, 230, 216, 0.72);
  transition: color 200ms var(--ease), background-color 200ms var(--ease);
}
.heroballk__klem:hover {
  color: var(--chat-text);
  background: rgba(239, 230, 216, 0.08);
}
.heroballk__klem:focus-visible { outline: 2px solid var(--shu-ink); outline-offset: 2px; }

.heroballk__send {
  height: 44px;
  width: 44px;
  background: var(--shu);
  color: var(--washi);
  transition: background-color 200ms var(--ease);
}
.heroballk__send:hover { background: var(--shu-deep); }
.heroballk__send:focus-visible { outline: 3px solid var(--washi); outline-offset: 2px; }
.heroballk__send[disabled] { opacity: 0.45; cursor: default; }

/* --- De knop -------------------------------------------------------------
   Exact de maatvoering van .pill uit pagina.css, maar absoluut over de doos
   in plaats van in de tekststroom. Het script zet de doos in deze stand op
   de gemeten maat van de echte pil (#dock), dus deze twee vallen samen.
------------------------------------------------------------------------- */
.heroballk__pil {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  /* center en niet space-between. Op het eindpunt maakt het geen verschil:
     de doos staat dan op de gemeten maat van de echte pil, dus label plus
     schijf plus padding vullen hem exact en er is geen vrije ruimte om te
     verdelen. Onderweg wél: met space-between staan het label en de schijf
     aan weerszijden van een doos die nog 380 pixels breed is en kruipen ze
     naar elkaar toe. Met center blijven ze als één groepje bij elkaar en
     krimpt alleen de vorm eromheen. Dat is de beweging die bedoeld is. */
  justify-content: center;
  gap: 12px;
  padding: 8px 8px 8px 24px;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: var(--text-invert);
  font-family: inherit;
  font-size: var(--size-btn);
  font-weight: 500;
  line-height: 1.2;
  white-space: nowrap;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
  -webkit-tap-highlight-color: transparent;
}
.heroballk__pil:focus-visible { outline: 3px solid var(--washi); outline-offset: 3px; }
.heroballk__pil .knob {
  display: flex;
  flex: 0 0 auto;
  height: 40px;
  width: 40px;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  background: var(--btn-accent);
  color: var(--btn-bg);
  transition: background-color 0.3s var(--ease);
}
.heroballk__pil:hover .knob { background: var(--washi-dim); }

/* Welke van de twee inhouden aan de beurt is.

   visibility en niet display: display: none haalt het element uit de layout
   en dan is er niets meer te meten of te animeren. visibility haalt het uit
   de tab-orde en uit het bereik van de muis, en laat de maat staan.

   Alleen de stand die NIET aan de beurt is krijgt hier een waarde. De andere
   krijgt met opzet géén `visibility: visible`: visibility is een geërfde
   eigenschap, en een expliciete visible op een kind wint van een hidden op
   de ouder. Het script zet die hidden op .heroballk zelf zodra de balk
   buiten beeld of buiten de reveal valt; met een visible hieronder zou het
   invoerveld dan blijven staan terwijl de balk eromheen al weg is. */
.heroballk[data-stand="balk"] .heroballk__balk { pointer-events: auto; }
.heroballk[data-stand="balk"] .heroballk__pil  { visibility: hidden; pointer-events: none; }
.heroballk[data-stand="pil"]  .heroballk__balk { visibility: hidden; pointer-events: none; }
.heroballk[data-stand="pil"]  .heroballk__pil  { pointer-events: auto; }
/* Onderweg is geen van de twee aan te klikken: je bent aan het scrollen. */
.heroballk[data-stand="onderweg"] .heroballk__balk,
.heroballk[data-stand="onderweg"] .heroballk__pil { pointer-events: none; }

/* Op een smal scherm is er geen ruimte voor "Start uw aanvraag" plus de
   schijf naast een balk van 44 hoog. De maten volgen die van .pill onder
   768px in pagina.css, zodat de knop rechtsonder er hetzelfde uitziet als
   voor deze wijziging. */
@media (max-width: 768px) {
  .heroballk__pil { gap: 10px; padding: 6px 6px 6px 18px; font-size: 16px; }
  .heroballk__pil .knob { height: 34px; width: 34px; }
  .heroballk__pil .knob svg { width: 18px; height: 18px; }
  /* De ruimte rond het veld blijft 10, ook hier: dat getal staat ook in
     motief.js (BALK_PAD) en in de hoogte van de plaatshouder. Wijzig je het
     hier, dan hoort het daar mee te wijzigen, en dat is precies het soort
     stille afwijking dat het niet waard is voor twee pixels op een
     telefoon. */
  /* Horizontaal van 14 naar 12 op 14 september 2026: die vier pixels zijn
     precies wat de plaatshouder nodig heeft om op 390 breed op één regel te
     blijven. De 10 verticaal blijft, want die staat ook in motief.js
     (BALK_PAD) en in de hoogte van de plaatshouder. */
  .heroballk__invoer { padding: 10px 12px; }
}

@media (prefers-reduced-motion: reduce) {
  .heroballk__doos { transition: none; }
  .heroballk__klem, .heroballk__send, .heroballk__pil .knob { transition: none; }
}

/* ===========================================================================
   Het chatvenster in de brede stand.

   Zolang het gesprek boven aan de pagina staat, is het venster zo breed als
   de pagina zelf; scroll je naar beneden, dan krimpt het naar de gewone
   maat in de hoek rechtsonder. Ook dat is scrollgestuurd en dus zonder
   transition: de breedte komt per frame uit motief.js.

   Alleen de BREEDTE beweegt. De hoogte volgt de inhoud en heeft zijn eigen
   max-height uit het blok hierboven, en dat is met opzet: een breed venster
   is voor dezelfde berichten vanzelf lager dan een smal venster, want de
   regels wrappen minder. De hoogte doet dus al het juiste zonder dat er
   iets aan gerekend hoeft te worden, en het gesprek hoeft nooit te
   verspringen omdat een gerekende hoogte niet bij de inhoud paste.
   =========================================================================== */
/* Het paneel hangt aan right/bottom, dus een grotere breedte duwt vanzelf de
   linkerkant naar buiten. Precies de kant die moet bewegen, en daarom hoeft
   er hier niets aan de positie te gebeuren.

   Wat er wél moet gebeuren: de berichten smal houden. .omata-msg staat op
   84 procent van het paneel, en op een breed scherm is dat een regel van
   meer dan duizend pixels. Dat leest niet. 62 tekens is de bovengrens die
   voor de rest van deze site ook geldt (--max-sub en --max-head zijn van
   dezelfde orde), en het is meteen ook de reden dat een breed venster niet
   raar aanvoelt: de berichten blijven staan waar ze stonden, er komt alleen
   ruimte naast. */
.omata-chat[data-omata-breed="ja"] .omata-msg {
  max-width: min(84%, 62ch);
}

/* ---------------------------------------------------------------------------
   De plaatshouder in het hero.

   Bezet de ruimte waar de balk staat, zodat de kolom in het hero niet
   verspringt en de reveal en de dockberekening in motief.js iets hebben om
   aan te meten. Onzichtbaar, maar wel aanwezig: met display: none zou er
   niets te meten zijn.

   De breedte staat hier en niet in het script, want dit is opmaak. 620 is
   de maat waarop de balk naast de kop in het hero nog als één blok leest;
   breder werd het een strook over de hele pagina en dan verliest de kop het.
   Het script leest deze breedte uit (balkRechthoek in deel 7), dus dit is de
   enige plek waar ze staat.

   66 hoog is 46 voor het veld met één regel plus twee keer 10 ruimte
   eromheen; die twee getallen staan ook in het script, dat de balk laat
   meegroeien zodra de tekst over twee regels loopt.
--------------------------------------------------------------------------- */
.hero-chatslot {
  /* Het token staat in pagina.css, bij de hero-maten: de kanaalknoppen onder
     de balk lijnen erop uit en die twee horen dezelfde maat te houden. De
     waarde erachter is de oude, voor het geval dit bestand ooit zonder
     pagina.css geladen wordt. */
  width: var(--herobalk-breed, min(620px, calc(100vw - var(--gutter) * 2)));
  height: 66px;
  visibility: hidden;
}
