/* fx-home.css · hoort bij fx-home.js · alleen op / en op demo-home.html
   Bouwt voort op fx.css (tokens --fx-inkt, --fx-doek, --fx-geel, --fx-groen,
   --fx-grijs, --fx-archivo, --fx-mono, --fx-ease, --fx-uit).
   Standaardstaat = de staat zonder JavaScript. Alles wat beweegt hangt achter
   html.fx (fx.js zet die klasse) en html:not(.rm).

   Tokens die dit bestand kent en die de pagina mag overschrijven:
     --kamer-lucht      ruimte tussen twee kamers (minimaal 96px)
     --lx --ly          de ene lichtbron, 0..1        (schrijft FX.licht)
     --v                de snelheidsbus, -1..1        (schrijft FX.snelheid)
     --fase             fase van het etmaal, 0..1     (schrijft FX.klok)
     --fx-split         rgb-splitsing in px, uit --v
     --fx-tiltx --fx-tilty   kantelhoek van de gyro
     --fx-vloer-grond   grondkleur van de inktvloer (hex, leest FX.fluid)
     --fx-vloer-inkt-1 .. -5 inktkleuren (hex, leest FX.fluid)
     --inkt-1 --inkt-2 --inkt-3   kleuren van de platte vloer-terugval
     --fx-bus-grond     grondkleur van de statusstrook (dekkend)
     --vlakb            layoutbreedte van een scherm in de wand
     --vlak-proj-b --vlak-proj-h   geprojecteerde maat van het voorste scherm
                        (schrijft FX.wand, zodat de pagina de houder kan maten)
     --straal --hoek --stap --skew --rek   de cilinder (schrijft FX.wand)
     --snelheid         tempo van een signaalbaan */

/* --- 1. tokens van de kamer --- */
:root{
  --fx-split:0px;              /* rgb-splitsing, gevoed door --v */
  --fx-tiltx:0deg;--fx-tilty:0deg;
  --lx:.5;--ly:.35;            /* de ene lichtbron, 0..1 */
  --v:0;                       /* de snelheidsbus, -1..1 */
  --fase:.5;                   /* fase van het etmaal, 0..1 */
  --kamer-lucht:clamp(96px,12vh,160px);
  --inkt-1:#0f6b41;--inkt-2:#23a96a;--inkt-3:#ffd52d;
  --fx-bus-grond:#0F0F0E;      /* dekkend, nooit doorzichtig */
}
html.fx:not(.rm){--fx-split:calc(var(--v) * 1.6px)}

/* --- 2. kamers: ruimte en diepte, beide scrollrichtingen gelijk ---
   De kamer is geen fade maar een camerabeweging: de camera dolt naar binnen
   en weer naar buiten. De tekst blijft daarbij leesbaar, want de dekking zakt
   nooit onder 0.7 en de kamer zelf staat stil; alleen het blok beweegt. */
.kamer{position:relative;padding-block:var(--kamer-lucht);min-height:44vh}
.kamer+.kamer{margin-top:var(--kamer-lucht)}
.kamer>*{position:relative;z-index:1}   /* tekst nooit op een bewegende laag */
@supports (animation-timeline: view()){
  @media (prefers-reduced-motion: no-preference){
    html.fx:not(.rm) .kamer{perspective:1000px;perspective-origin:50% 50%}
    html.fx:not(.rm) .kamer>.kamer-diep{
      animation:kamer-camera linear both;
      animation-timeline:view();
      animation-range:entry 0% exit 100%;
      transform-origin:50% 50%;
      will-change:transform,opacity}
  }
}
@keyframes kamer-camera{
  0%{opacity:.7;transform:translateZ(-60px) rotateX(3deg)}
  38%,62%{opacity:1;transform:translateZ(0) rotateX(0deg)}
  100%{opacity:.7;transform:translateZ(-60px) rotateX(-3deg)}
}
/* terugval zonder view()-timelines: FX.reveal doet het werk (symmetrisch:
   .fx-reveal blijft aan zodra hij aan is, dus terugscrollen verbergt niets) */
html.fx:not(.fx-tl) .kamer>.kamer-diep{opacity:1;transform:none}

/* --- 3. progressieve vervaging (vijf lagen) --- */
.fx-scrim{position:relative;isolation:isolate}
.fx-scrim>.fx-scrim-laag{position:absolute;inset:0;pointer-events:none;z-index:0}
.fx-scrim>*:not(.fx-scrim-laag){position:relative;z-index:1}
.fx-scrim-laag i{position:absolute;inset:0;display:block}
.fx-scrim-laag i:nth-child(1){backdrop-filter:blur(1px);-webkit-backdrop-filter:blur(1px);
  -webkit-mask-image:linear-gradient(to top,#000 0%,#000 20%,transparent 42%);
  mask-image:linear-gradient(to top,#000 0%,#000 20%,transparent 42%)}
.fx-scrim-laag i:nth-child(2){backdrop-filter:blur(2px);-webkit-backdrop-filter:blur(2px);
  -webkit-mask-image:linear-gradient(to top,#000 0%,#000 14%,transparent 34%);
  mask-image:linear-gradient(to top,#000 0%,#000 14%,transparent 34%)}
.fx-scrim-laag i:nth-child(3){backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);
  -webkit-mask-image:linear-gradient(to top,#000 0%,#000 9%,transparent 25%);
  mask-image:linear-gradient(to top,#000 0%,#000 9%,transparent 25%)}
.fx-scrim-laag i:nth-child(4){backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);
  -webkit-mask-image:linear-gradient(to top,#000 0%,#000 5%,transparent 16%);
  mask-image:linear-gradient(to top,#000 0%,#000 5%,transparent 16%)}
.fx-scrim-laag i:nth-child(5){backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);
  -webkit-mask-image:linear-gradient(to top,#000 0%,transparent 9%);
  mask-image:linear-gradient(to top,#000 0%,transparent 9%)}
/* terugval: een inkt-scrim, zodat tekst altijd op AA staat */
@supports not ((backdrop-filter: blur(2px)) or (-webkit-backdrop-filter: blur(2px))){
  .fx-scrim-laag i{backdrop-filter:none}
  .fx-scrim-laag{background:linear-gradient(to top,
    color-mix(in oklab,var(--fx-inkt) 88%,transparent) 0%,
    color-mix(in oklab,var(--fx-inkt) 66%,transparent) 46%,
    transparent 100%)}
}

/* --- 4. beeldbuis --- */
.fx-glas{position:relative;overflow:hidden;isolation:isolate;
  background:var(--fx-nacht,#0f0f0e);border-radius:10px}
.fx-glas>.fx-glas-op{position:absolute;inset:0;pointer-events:none;z-index:3;border-radius:inherit;
  background:
    radial-gradient(120% 90% at calc(var(--lx)*100%) calc(var(--ly)*100%),
      rgba(255,255,255,.16) 0%,rgba(255,255,255,0) 55%),
    radial-gradient(140% 120% at 50% 50%,rgba(0,0,0,0) 42%,rgba(0,0,0,.55) 100%),
    repeating-linear-gradient(to bottom,rgba(0,0,0,.22) 0 1px,rgba(0,0,0,0) 1px 3px);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.08)}
.fx-glas>.fx-glas-band{position:absolute;left:0;right:0;height:22%;top:-22%;z-index:4;
  pointer-events:none;opacity:.16;
  background:linear-gradient(to bottom,rgba(255,255,255,0),rgba(255,255,255,.9),rgba(255,255,255,0))}
@media (prefers-reduced-motion: no-preference){
  html.fx:not(.rm) .fx-glas>.fx-glas-band{animation:fx-band 7s linear infinite}
}
@keyframes fx-band{from{top:-22%}to{top:100%}}
/* de rand groeit met de draaisnelheid */
.fx-glas>.fx-glas-rand{position:absolute;inset:0;z-index:2;pointer-events:none;border-radius:inherit;
  box-shadow:calc(var(--v)*3px) 0 0 rgba(255,0,64,.5),calc(var(--v)*-3px) 0 0 rgba(0,255,255,.5);
  opacity:calc(min(1,abs(var(--v))*2))}
@supports not (width: abs(1px)){.fx-glas>.fx-glas-rand{opacity:.35}}
html.rm .fx-glas>.fx-glas-band{display:none}
html.rm .fx-glas>.fx-glas-rand{opacity:0}

/* --- 5. kanaalruis --- */
.fx-ruis{position:absolute;inset:0;z-index:5;pointer-events:none;opacity:0;
  background-size:180px 180px;mix-blend-mode:screen}
html.fx:not(.rm) .fx-ruis.aan{opacity:.5}
html.fx:not(.rm) .fx-ruis.aan::after{content:"";position:absolute;left:0;right:0;height:6px;
  top:calc(30% + var(--v) * 20%);background:rgba(255,255,255,.75)}

/* --- 6. de wand: strook als standaard, cilinder onder html.js --- */
.fx-wand{display:flex;gap:16px;overflow-x:auto;scroll-snap-type:x mandatory;
  -webkit-overflow-scrolling:touch;padding-bottom:8px}
.fx-wand>.fx-vlak{flex:0 0 var(--vlakb,min(86vw,520px));scroll-snap-align:center}
.fx-wand-houder{perspective:1200px;perspective-origin:50% 46%;--vlakb:min(86vw,520px);
  overflow-x:hidden;overflow-x:clip}
html.fx .fx-wand-3d{display:block;overflow:visible;scroll-snap-type:none;
  position:relative;height:var(--wand-hoogte,340px);
  transform-style:preserve-3d;touch-action:pan-y;cursor:grab;
  transform:rotateY(var(--hoek,0deg)) skewX(var(--skew,0deg)) scaleX(var(--rek,1))}
html.fx .fx-wand-3d.sleept{cursor:grabbing}
/* de schok bij het inklikken; FX.wand zet de klasse 140 ms en stuurt daarnaast
   een "fx-snap"-event met detail {index}, zodat de pagina mee kan reageren */
html.fx:not(.rm) .fx-wand-3d.snap>.fx-vlak.voor .fx-glas{animation:fx-schok .14s var(--fx-ease)}
@keyframes fx-schok{
  0%{transform:translate3d(0,0,0)}
  35%{transform:translate3d(-2px,1px,0)}
  70%{transform:translate3d(2px,-1px,0)}
  100%{transform:translate3d(0,0,0)}}
html.rm .fx-wand-3d.snap>.fx-vlak.voor .fx-glas{animation:none}
html.fx .fx-wand-3d>.fx-vlak{position:absolute;left:50%;top:0;
  width:var(--vlakb,min(86vw,520px));margin-left:calc(var(--vlakb,min(86vw,520px)) / -2);
  transform:rotateY(calc(var(--i) * var(--stap,72deg))) translateZ(var(--straal,320px));
  transition:opacity .3s var(--fx-ease);opacity:.5}
html.fx .fx-wand-3d>.fx-vlak.voor{opacity:1}
html.rm .fx-wand{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));overflow:visible}
html.rm .fx-wand>.fx-vlak{flex:none}
.fx-vanger{position:absolute;inset:0;z-index:6}
.fx-vlak iframe{border:0;width:1280px;height:800px;transform-origin:0 0;
  transform:scale(var(--schaal,.36));pointer-events:none}
.fx-poster{position:absolute;inset:0;z-index:1;transition:opacity .4s var(--fx-ease)}

/* --- 7. goo-knop (SVG-filter staat inline in de pagina, zie onder) --- */
/* De pagina zet deze markup neer, eenmalig, visueel verborgen:
   <svg class="fx-goo-def" aria-hidden="true"><filter id="fx-goo">
     <feGaussianBlur in="SourceGraphic" stdDeviation="8" result="b"/>
     <feColorMatrix in="b" mode="matrix"
       values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 20 -9" result="g"/>
     <feBlend in="SourceGraphic" in2="g"/></filter></svg>                     */
.fx-goo-def{position:absolute;width:0;height:0;overflow:hidden}
.fx-goo{position:relative;display:inline-flex;isolation:isolate}
html.fx:not(.rm) .fx-goo{filter:url(#fx-goo)}
.fx-goo .fx-blob{position:absolute;left:50%;top:50%;width:26px;height:26px;border-radius:50%;
  background:var(--fx-groen);transform:translate(-50%,-50%);pointer-events:none;z-index:-1;
  transition:transform .5s var(--fx-uit)}
html.fx:not(.rm) .fx-goo:hover .fx-blob,html.fx:not(.rm) .fx-goo:focus-within .fx-blob{
  transform:translate(calc(-50% + 34px),calc(-50% - 18px))}

/* --- 8. view transitions: latten eruit, zoom erin --- */
@property --fx-lat{syntax:"<number>";inherits:false;initial-value:1}
@media (prefers-reduced-motion: no-preference){
  html:not(.rm)::view-transition-old(root){animation:fx-latten .34s ease-in both;
    -webkit-mask-image:repeating-linear-gradient(to bottom,#000 0 calc(var(--fx-lat) * 12.5%),transparent calc(var(--fx-lat) * 12.5%) 12.5%);
    mask-image:repeating-linear-gradient(to bottom,#000 0 calc(var(--fx-lat) * 12.5%),transparent calc(var(--fx-lat) * 12.5%) 12.5%)}
  html:not(.rm)::view-transition-new(root){animation:fx-inzoom .44s var(--fx-uit) both}
}
@keyframes fx-latten{from{--fx-lat:1;opacity:1}to{--fx-lat:0;opacity:.3}}
@keyframes fx-inzoom{
  from{clip-path:inset(38% 30% 38% 30% round 14px);opacity:.25}
  to{clip-path:inset(0 0 0 0 round 0);opacity:1}}
/* de sluier vlak voor de navigatie */
html.uit body{transition:filter .24s var(--fx-ease),opacity .24s var(--fx-ease);
  filter:blur(6px) brightness(1.35);opacity:.55}
html.rm.uit body{filter:none;opacity:1;transition:none}

/* --- 9. het vizier --- */
.fx-vizier{position:fixed;left:0;top:0;z-index:9996;pointer-events:none;opacity:0;
  width:26px;height:26px;transition:opacity .25s var(--fx-ease)}
.fx-vizier.aan{opacity:1}
.fx-vizier-kader{position:absolute;inset:0;mix-blend-mode:difference}
.fx-vizier .fx-hoek{position:absolute;width:11px;height:11px;border:1.5px solid #fff}
.fx-vizier .h0{left:0;top:0;border-right:0;border-bottom:0}
.fx-vizier .h1{right:0;top:0;border-left:0;border-bottom:0}
.fx-vizier .h2{left:0;bottom:0;border-right:0;border-top:0}
.fx-vizier .h3{right:0;bottom:0;border-left:0;border-top:0}
.fx-vizier-lees{position:absolute;left:50%;top:calc(100% + 9px);transform:translateX(-50%);
  font-family:var(--fx-mono);font-size:11px;letter-spacing:.08em;text-transform:uppercase;
  white-space:nowrap;color:var(--fx-doek-op-inkt,#efece6);opacity:0;transition:opacity .25s var(--fx-ease);
  background:rgba(15,15,14,.82);padding:3px 7px;border-radius:3px}
.fx-vizier.op-doel .fx-vizier-lees{opacity:1}
.fx-sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}

/* --- 10. de ogen --- */
.fx-ogen{display:block;width:84px;max-width:26vw}
.fx-oog-svg{display:block;width:100%;height:auto;overflow:visible}
.fx-ogen .fx-wit{fill:var(--fx-doek-op-inkt,#efece6)}
.fx-ogen .fx-pupil{fill:var(--fx-inkt,#131313);transition:r .3s var(--fx-ease)}
.fx-ogen .fx-lid{fill:var(--fx-inkt,#131313);transform-origin:center top;transform:scaleY(0);
  transition:transform .12s linear}
.fx-ogen.knipper .fx-lid{transform:scaleY(1)}
.fx-ogen.knijp .fx-wit{transform:scaleY(.6);transform-origin:center;transition:transform .25s var(--fx-ease)}
.fx-ogen.wijd .fx-wit{transform:scale(1.12);transform-origin:center;transition:transform .3s var(--fx-uit)}
html.rm .fx-ogen .fx-lid{transform:scaleY(0)}

/* --- 11. koude start --- */
.fx-boot{position:fixed;inset:0;z-index:9999;background:#000;display:none;
  align-items:center;justify-content:center;flex-direction:column;gap:12px}
html.fx.boot .fx-boot{display:flex}
html.rm .fx-boot{display:none !important}
.fx-boot-lijn{display:block;width:1px;height:0;background:#fff;animation:fx-boot-lijn .34s var(--fx-uit) forwards}
@keyframes fx-boot-lijn{from{height:0;width:1px}to{height:34vh;width:1px}}
.fx-boot-lijst{list-style:none;margin:0;padding:0;font-family:var(--fx-mono);font-size:12px;
  letter-spacing:.1em;color:#efece6;text-align:center}
.fx-boot-regel{margin:.32em 0}

/* --- 12. de bus --- */
.fx-bus{position:fixed;left:0;right:0;bottom:0;z-index:60;display:flex;align-items:center;
  gap:14px;padding:7px clamp(12px,4vw,28px);font-family:var(--fx-mono);font-size:11px;
  letter-spacing:.08em;text-transform:uppercase;
  color:var(--fx-doek-op-inkt,#efece6);background:var(--fx-bus-grond,#0F0F0E);
  border-top:1px solid var(--fx-hair-op-inkt,#2b2a27);
  transform:skewX(calc(var(--v) * 1.2deg))}
.fx-bus>*{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.fx-bus-regel{flex:1 1 auto;min-width:0}
.fx-bus-teller{color:var(--fx-geel)}
/* een regel zonder tijd krijgt geen teller: dan gaat ook de eenheid weg */
.fx-bus.geen-teller .fx-bus-teller,.fx-bus.geen-teller .fx-bus-eenheid{display:none}
.fx-bus-fase{color:var(--fx-groen-fel,#23a96a)}
.fx-bus-scan{position:absolute;left:0;top:0;bottom:0;width:64px;pointer-events:none;
  background:linear-gradient(to right,rgba(255,213,45,0),rgba(255,213,45,.14),rgba(255,213,45,0))}
@media (prefers-reduced-motion: no-preference){
  html.fx:not(.rm) .fx-bus-scan{animation:fx-scan 9s linear infinite}
}
@keyframes fx-scan{from{transform:translateX(-70px)}to{transform:translateX(100vw)}}
html.rm .fx-bus{transform:none}
.fx-bus-bron{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0)}

/* --- 13. inktvloer: WebGL-canvas of de platte terugval --- */
.fx-vloer{position:absolute;inset:0;z-index:0;overflow:hidden;background:var(--fx-nacht,#0f0f0e)}
.fx-vloer canvas{display:block;width:100%;height:100%}
.fx-vloer.fx-vloer-plat{background:
  radial-gradient(60% 50% at calc(var(--lx)*100%) calc(var(--ly)*100%),var(--inkt-2) 0%,transparent 62%),
  radial-gradient(70% 60% at 18% 78%,var(--inkt-1) 0%,transparent 66%),
  radial-gradient(50% 44% at 84% 22%,var(--inkt-3) 0%,transparent 60%),
  var(--fx-nacht,#0f0f0e)}

/* --- 14. commandoregel --- */
.fx-cmd{border:0;padding:0;background:transparent;max-width:min(560px,92vw);width:100%}
.fx-cmd::backdrop{background:rgba(15,15,14,.62)}
.fx-cmd-vorm{background:var(--fx-nacht,#0f0f0e);border:1px solid var(--fx-hair-op-inkt,#2b2a27);
  border-radius:10px;overflow:hidden}
.fx-cmd-invoer{display:block;width:100%;box-sizing:border-box;border:0;outline:0;
  padding:14px 16px;font-family:var(--fx-mono);font-size:15px;
  color:var(--fx-doek-op-inkt,#efece6);background:transparent}
.fx-cmd-lijst{list-style:none;margin:0;padding:0;max-height:46vh;overflow:auto;
  border-top:1px solid var(--fx-hair-op-inkt,#2b2a27)}
.fx-cmd-regel{display:flex;justify-content:space-between;gap:14px;padding:10px 16px;
  font-family:var(--fx-mono);font-size:13px;color:var(--fx-doek-op-inkt,#efece6);cursor:pointer}
.fx-cmd-regel.aan{background:rgba(255,213,45,.14);color:var(--fx-geel)}
.fx-cmd-hint{color:var(--fx-grijs-op-inkt,#8e897d)}

/* --- 15. matrix, confetti, splitsing, thema --- */
.fx-matrix{font-family:var(--fx-mono);font-size:5px;line-height:.86;white-space:pre;
  letter-spacing:.5px;color:var(--fx-groen-fel,#23a96a);margin:0}
.fx-confetti{position:fixed;inset:0;z-index:9995;pointer-events:none}
.fx-split{text-shadow:calc(var(--fx-split) * -1) 0 rgba(255,0,64,.6),var(--fx-split) 0 rgba(0,255,255,.6)}
html[data-thema="doek"]{--fx-nacht:#f6f4f0}
html[data-thema="keur"]{--fx-nacht:#131313;--inkt-1:#8c5a1e;--inkt-2:#ffd52d;--inkt-3:#b4531e}
html.wild .fx-glas>.fx-glas-op{filter:hue-rotate(40deg) saturate(1.4)}
html.wild .fx-bus{letter-spacing:.16em}

/* --- 16. machinekamer: banen en schakelaars ---
   De pakketjes zelf horen bij de SVG van de pagina; die CSS staat daar. Wel
   hier het patroon dat de pagina moet volgen, zodat een browser zonder
   offset-path niets kwijtraakt maar ook niets kapot ziet:

     .pakket{offset-distance:0%}
     @supports (offset-path: path("M0 0 H1")){
       .pakket{offset-path:path("...de baan...");offset-rotate:auto}
       html.fx:not(.rm) .pakket{animation:pakket-loop 2.4s linear infinite;
         animation-duration:calc(2.4s / var(--snelheid,1))}
       @keyframes pakket-loop{to{offset-distance:100%}}
     }
     @supports not (offset-path: path("M0 0 H1")){
       .pakket{display:none}      -- dan blijft de streepjesbaan over
     }                                                                    */
.fx-baan{stroke-dasharray:6 10;animation:fx-loop 2.4s linear infinite;
  animation-duration:calc(2.4s / var(--snelheid,1))}
@media (prefers-reduced-motion: reduce){.fx-baan{animation:none}}
html.rm .fx-baan{animation:none}
@keyframes fx-loop{to{stroke-dashoffset:-32}}
.fx-machine:has([data-baan="1"]:hover) .baan-1,.fx-machine:has([data-baan="1"]:focus-visible) .baan-1,
.fx-machine.baan-1-aan .baan-1{--snelheid:3}
.fx-machine:has([data-baan="2"]:hover) .baan-2,.fx-machine:has([data-baan="2"]:focus-visible) .baan-2,
.fx-machine.baan-2-aan .baan-2{--snelheid:3}
.fx-machine:has([data-baan="3"]:hover) .baan-3,.fx-machine:has([data-baan="3"]:focus-visible) .baan-3,
.fx-machine.baan-3-aan .baan-3{--snelheid:3}
.fx-schakel{transform-style:preserve-3d;transform:perspective(500px) rotateX(0deg);
  transition:transform .09s var(--fx-ease)}
html.fx:not(.rm) .fx-schakel:hover,html.fx:not(.rm) .fx-schakel:focus-visible{
  transform:perspective(500px) rotateX(-18deg)}
