/* ============================================================
   Motionary, demos I
   Hero Animations, craft scroll, pointeur, texture, page
   ============================================================ */

/* ---------------- scroll craft ---------------- */
/* La page LOCK, c'est le sujet. Trois temps, la page descend jusqu'a
   26 pour cent, elle se fige de 26 a 72 pendant que les trois etapes
   internes avancent, puis elle repart. La jauge de droite montre que
   le defilement continue d'arriver pendant le gel, c'est lui qui est
   depense sur les etapes.
   Gele, on verrait une boite fixe devant un fil qui defile, ce qui est
   du position fixed et pas du pinning. */
.spn{position:relative;width:172px;height:104px;overflow:hidden;border-radius:9px;background:var(--s0)}
.spn .feed{position:absolute;left:9px;right:22px;top:0;display:flex;flex-direction:column;gap:8px;
  animation:aSpn 5.6s cubic-bezier(.4,0,.4,1) infinite}
.spn .feed i{display:block;height:24px;border-radius:7px;background:var(--s2);flex:0 0 auto}
.spn .sct{display:flex;flex-direction:column;gap:6px;padding:9px;border-radius:9px;box-sizing:border-box;
  background:var(--s1);border:1px solid var(--lime);flex:0 0 auto}
.spn .sct b{display:block;height:9px;border-radius:4px;background:var(--s3)}
.spn .sct .st{animation:aSpnStep 5.6s steps(1,end) infinite}
.spn .sct .s2{animation-delay:.9s}
.spn .sct .s3{animation-delay:1.8s}
.spn .gauge{position:absolute;right:7px;top:8px;bottom:8px;width:4px;border-radius:2px;background:var(--s1)}
.spn .thumb{position:absolute;left:0;right:0;top:0;height:24px;border-radius:2px;background:var(--s5);
  animation:aSpnT 5.6s linear infinite}
/* le fil s'arrete completement de 26 a 72 pour cent, c'est le pin */
/* Aller retour, la page descend, se fige, repart, puis remonte. Le
   gel est bien de 22 a 56 pour cent. La jauge de droite, elle, ne
   s arrete JAMAIS, elle descend et remonte lineairement, ce qui montre
   que le defilement continue d arriver pendant que la page est bloquee. */
@keyframes aSpn{0%,4%{transform:translateY(0)}
  22%,56%{transform:translateY(-58px)}
  74%{transform:translateY(-116px)}
  88%{transform:translateY(-58px)}
  100%{transform:translateY(0)}}
/* la jauge, elle, ne s'arrete jamais, le defilement continue d'arriver */
@keyframes aSpnT{0%,100%{transform:translateY(0)}50%{transform:translateY(64px)}}
@keyframes aSpnStep{0%,28%{background:var(--s3)}34%,68%{background:var(--lime)}74%,100%{background:var(--s3)}}

/* Decalages CROISSANTS, 0 puis 9 puis 18. C'est ce decalage qui laisse
   voir le bord de chaque carte et donne sa profondeur au jeu. Avec des
   decalages identiques les cartes tomberaient exactement l'une sur
   l'autre et la pile se lirait comme une seule carte qui clignote.
   Les cartes couvertes retrecissent et s'assombrissent, sinon rien ne
   dit laquelle est devant. */
.sstk{position:relative;width:150px;height:96px}
.sstk i{position:absolute;left:0;right:0;display:block;height:44px;border-radius:11px;box-sizing:border-box;
  border:1px solid var(--line-2)}
.sstk .k1{top:0;background:var(--s2);animation:aSstkCov 5s cubic-bezier(.3,.9,.3,1) infinite}
.sstk .k2{top:9px;background:var(--s4);animation:aSstk 5s cubic-bezier(.3,.9,.3,1) infinite}
.sstk .k3{top:18px;background:var(--lime);animation:aSstk 5s cubic-bezier(.3,.9,.3,1) infinite;
  animation-delay:.55s}
@keyframes aSstk{0%,10%{transform:translateY(76px)}46%,88%{transform:translateY(0)}
  100%{transform:translateY(76px)}}
/* la carte du dessous recule quand elle est recouverte */
@keyframes aSstkCov{0%,14%{transform:scale(1);opacity:1}
  50%,86%{transform:scale(.96);opacity:.6}100%{transform:scale(1);opacity:1}}

/* L'echange d'AXE est le motif. La jauge de droite descend, verticale,
   pendant que le rail va lateralement. Sans elle on ne verrait qu'un
   carrousel, et c'est la surprise du motif qui disparaitrait.
   La barre du bas dit jusqu'ou va la section, sans quoi un rail qui
   glisse encore se lit comme un piege. */
.hsec{position:relative;width:172px;height:96px;overflow:hidden;border-radius:9px;background:var(--s0)}
.hsec .rail3{position:absolute;left:9px;top:12px;display:flex;gap:9px;
  animation:aHsec 5s cubic-bezier(.4,0,.4,1) infinite}
.hsec .rail3 i{display:block;flex:0 0 auto;width:52px;height:46px;border-radius:9px;background:var(--s3)}
.hsec .rail3 i:first-child{background:var(--lime)}
.hsec .vg{position:absolute;right:7px;top:10px;bottom:24px;width:4px;border-radius:2px;background:var(--s1)}
.hsec .vt{position:absolute;left:0;right:0;top:0;height:18px;border-radius:2px;background:var(--s5);
  animation:aHsecV 5s cubic-bezier(.4,0,.4,1) infinite}
.hsec .prg{position:absolute;left:9px;right:20px;bottom:10px;height:3px;border-radius:2px;background:var(--s1)}
.hsec .prg b{position:absolute;left:0;top:0;bottom:0;width:0;border-radius:2px;background:var(--lime);
  animation:aHsecP 5s cubic-bezier(.4,0,.4,1) infinite}
@keyframes aHsec{0%,10%{transform:translateX(0)}62%,90%{transform:translateX(-122px)}
  100%{transform:translateX(0)}}
@keyframes aHsecV{0%,10%{transform:translateY(0)}62%,90%{transform:translateY(44px)}
  100%{transform:translateY(0)}}
@keyframes aHsecP{0%,10%{width:0}62%,90%{width:100%}100%{width:0}}

/* Le GLISSEMENT APRES l'arret est tout le sujet, et il etait invisible.
   La molette pousse de 8 a 44 pour cent puis S'ARRETE. La colonne
   brute s'arrete avec elle, la colonne lissee continue jusqu'a 62.
   Cet ecart est a la fois l'effet et son cout, de la latence entre le
   geste et l'ecran.
   Gele, on aurait deux tubes remplis, sans savoir lequel a continue. */
.smsc{display:flex;gap:16px;align-items:flex-end;width:172px}
.smsc .col3{display:flex;flex-direction:column;align-items:center;gap:8px}
.smsc .lb{font:600 9px/1 var(--mono);color:var(--ink-3);font-style:normal}
.smsc .tube{position:relative;display:block;width:10px;height:66px;border-radius:5px;
  background:var(--s2);overflow:hidden}
.smsc .tube b{position:absolute;left:0;right:0;top:0;height:18px;border-radius:5px;
  background:var(--lime);display:block}
.smsc .hard{animation:aSmscH 4s steps(5,end) infinite}
.smsc .soft2{animation:aSmscS 4s cubic-bezier(.2,0,.15,1) infinite}
/* la molette, temoin de l'entree, elle s'arrete a 44 pour cent */
.smsc .whl{display:flex;flex-direction:column;align-items:center;gap:6px;margin-left:auto}
.smsc .whl em{font:600 8px/1 var(--mono);color:var(--ink-3);font-style:normal}
.smsc .whl span{position:relative;display:block;width:11px;height:20px;border-radius:6px;
  box-sizing:border-box;border:1.5px solid var(--s5)}
.smsc .whl span i{position:absolute;left:50%;top:3px;width:2px;height:5px;margin-left:-1px;
  border-radius:1px;background:var(--lime);animation:aSmscW 4s steps(1,end) infinite}
/* La molette pousse de 8 a 44 puis S ARRETE. La colonne brute s arrete
   avec elle, la lissee continue jusqu a 62. Les deux reviennent
   ensuite, sinon la boucle se teleporterait. */
@keyframes aSmscH{0%,8%{transform:translateY(0)}44%,64%{transform:translateY(48px)}90%,100%{transform:translateY(0)}}
@keyframes aSmscS{0%,8%{transform:translateY(0)}62%,72%{transform:translateY(48px)}94%,100%{transform:translateY(0)}}
@keyframes aSmscW{0%,8%{opacity:0}12%,42%{opacity:1}46%,100%{opacity:0}}

/* Le skew doit etre PROPORTIONNEL a la vitesse, sinon il affirme une
   vitesse qui n'existe pas. La jauge du bas lit la vitesse instantanee
   et les barres se deforment exactement avec elle, maximum a 8 degres
   quand la jauge est pleine, zero quand elle est vide.
   Gele, on verrait trois barres inclinees sans savoir de combien ni
   pourquoi. */
.vsk{position:relative;display:flex;flex-direction:column;gap:9px;width:150px;padding-bottom:16px}
.vsk .bar{display:block;height:16px;border-radius:6px;background:var(--lime);
  animation:aVsk 3.2s cubic-bezier(.4,0,.3,1) infinite}
.vsk .bar:nth-child(2){animation-delay:.04s;opacity:.8}
.vsk .bar:nth-child(3){animation-delay:.08s;opacity:.6}
.vsk .vg2{position:absolute;left:0;right:0;bottom:0;height:4px;border-radius:2px;background:var(--s2)}
.vsk .vg2 b{position:absolute;left:0;top:0;bottom:0;width:0;border-radius:2px;background:var(--a2);
  animation:aVskV 3.2s cubic-bezier(.4,0,.3,1) infinite}
/* meme cycle, meme courbe, la deformation suit la jauge au palier pres */
@keyframes aVsk{0%,8%{transform:translateY(0) skewY(0)}
  30%{transform:translateY(-14px) skewY(-8deg)}
  54%{transform:translateY(-24px) skewY(-3deg)}
  74%,92%{transform:translateY(-28px) skewY(0)}
  100%{transform:translateY(0) skewY(0)}}
@keyframes aVskV{0%,8%{width:0}30%{width:100%}54%{width:38%}74%,92%{width:0}100%{width:0}}

/* Le visuel est IMMOBILE, c'est lui le point fixe. Le texte defile a
   cote et le visuel ne change d'etat qu'au passage d'une frontiere
   d'etape, marquee par le trait pointille. Un visuel qui se
   transformerait en continu ne serait jamais stable assez longtemps
   pour etre lu.
   Gele, on verrait une forme et deux lignes, sans la relation. */
.sty{position:relative;display:flex;align-items:center;gap:14px;width:172px;height:96px}
.sty .viz{display:block;flex:0 0 auto;width:60px;height:60px;background:var(--lime);
  animation:aStyV 6s steps(1,end) infinite}
.sty .col4{position:relative;flex:1;height:96px;overflow:hidden}
.sty .txts{position:absolute;left:0;right:0;top:0;display:flex;flex-direction:column;gap:20px;
  animation:aStyScroll 6s linear infinite}
.sty .txts .stp{display:flex;flex-direction:column;gap:6px;height:44px;flex:0 0 auto}
.sty .txts .stp i{display:block;height:8px;border-radius:4px;background:var(--s4)}
.sty .txts .stp i:last-child{width:66%}
/* la frontiere, le visuel bascule exactement quand une etape la croise */
.sty .bnd{position:absolute;left:-14px;right:0;top:42px;height:1px;z-index:2;
  background:repeating-linear-gradient(90deg,var(--a2) 0 3px,transparent 3px 6px)}
/* Aller retour, comme un lecteur qui parcourt puis revient. Trois
   etapes de 44 avec 20 d ecart font 172, la course de 152 les fait
   donc toutes passer la frontiere. */
@keyframes aStyScroll{0%,100%{transform:translateY(30px)}50%{transform:translateY(-122px)}}
@keyframes aStyV{0%,30%{border-radius:12px;transform:rotate(0)}
  34%,64%{border-radius:50%;transform:rotate(0)}
  68%,96%{border-radius:12px;transform:rotate(45deg)}
  100%{border-radius:12px;transform:rotate(0)}}


/* La DUPLICATION est le mecanisme. Le motif de couleur a une periode de
   quatre tuiles, lime en 2 et 6, ambre en 4 et 8, donc les tuiles 5 a 8
   sont la copie des tuiles 1 a 4. Le trait pointille marque la couture
   entre les deux copies, il traverse la fenetre une fois par cycle et
   rien ne bouge quand le decalage retombe a zero.
   Le pas vaut 36 plus 8, soit 44, la ceinture 8 pas donc 352, et la
   course exacte d une copie vaut 176, c est a dire -50 pour cent. Le
   gap est porte par margin-bottom et non par gap, sans quoi la ceinture
   ferait 344 et la moitie tomberait a 172, quatre pixels avant le pas.
   Gele, on verrait une colonne de tuiles, sans la periode ni la
   couture. */
.ilp{position:relative;width:74px;height:88px;overflow:hidden;border-radius:8px}
.ilp .belt{position:absolute;left:0;right:0;top:0;animation:aIlp 5s linear infinite}
.ilp .belt i{display:block;height:36px;margin-bottom:8px;border-radius:9px;background:var(--s3)}
.ilp .belt i:nth-child(2),.ilp .belt i:nth-child(6){background:var(--lime)}
.ilp .belt i:nth-child(4),.ilp .belt i:nth-child(8){background:var(--a2)}
.ilp .seam{position:absolute;left:0;right:0;top:172px;height:1px;
  background:repeating-linear-gradient(90deg,var(--ink-3) 0 3px,transparent 3px 6px)}
@keyframes aIlp{from{transform:translateY(0)}to{transform:translateY(-50%)}}

/* ---------- pointeur ---------- */
/* Le RAYON est le sujet, et il etait absent. L ellipse pointillee fait
   100 sur 44, soit 1.5 fois la pastille de 66 sur 28, la valeur de la
   consigne. Elle s allume quand le pointeur entre, a 18 pour cent, et
   s eteint quand il sort, a 78.
   L attraction est PROPORTIONNELLE au decalage. Le centre est a 75, le
   pointeur passe par 25, 50, 75, 100 puis 125, donc les decalages valent
   -50, -25, 0, +25, +50 et le corps suit a 0.20 pres, soit -10, -5, 0,
   +5, +10. Le libelle suit a 0.28, soit -14, -7, 0, +7, +14, et ce
   petit ecart est la parallaxe demandee.
   Au centre l attraction vaut ZERO, ce qui est le point que rate un
   decalage fixe.
   Gele, on verrait une pastille decalee sans savoir de quoi elle
   s approche ni pourquoi. */
.mgb{position:relative;width:150px;height:72px}
.mgb .ring{position:absolute;left:25px;top:14px;width:100px;height:44px;border-radius:50%;
  box-sizing:border-box;border:1px dashed var(--line-2);animation:aMgbRing 4s steps(1,end) infinite}
.mgb .pill2{position:absolute;left:42px;top:22px;width:66px;height:28px;border-radius:14px;
  background:var(--lime);display:grid;place-items:center;
  animation:aMgbBody 4s cubic-bezier(.2,1.4,.3,1) infinite}
.mgb .lbl{display:block;width:26px;height:5px;border-radius:3px;background:var(--on-accent);opacity:.8;
  animation:aMgbLabel 4s cubic-bezier(.2,1.4,.3,1) infinite}
.mgb .cur{left:1px;top:29px;animation:aMgbCur 4s linear infinite}
@keyframes aMgbRing{0%,17%{border-color:var(--line-2)}18%,77%{border-color:var(--lime)}
  78%,100%{border-color:var(--line-2)}}
/* le pointeur s eteint aux deux bouts, la boucle ne saute donc pas */
@keyframes aMgbCur{0%{transform:translateX(0);opacity:0}
  6%{transform:translateX(0);opacity:1}
  20%{transform:translateX(17px)}34%{transform:translateX(42px)}48%{transform:translateX(67px)}
  62%{transform:translateX(92px)}76%{transform:translateX(117px)}84%{transform:translateX(126px)}
  94%{transform:translateX(134px);opacity:1}
  100%{transform:translateX(134px);opacity:0}}
@keyframes aMgbBody{0%,18%{transform:translateX(0)}
  23%{transform:translateX(-10px)}34%{transform:translateX(-5px)}48%{transform:translateX(0)}
  62%{transform:translateX(5px)}76%{transform:translateX(10px)}
  84%,100%{transform:translateX(0)}}
@keyframes aMgbLabel{0%,18%{transform:translateX(0)}
  23%{transform:translateX(-14px)}34%{transform:translateX(-7px)}48%{transform:translateX(0)}
  62%{transform:translateX(7px)}76%{transform:translateX(14px)}
  84%,100%{transform:translateX(0)}}

/* Il faut du CONTENU sous la bille, sinon la difference n a rien a
   inverser. Trois lignes de texte traversent la coupure sombre et
   claire, la bille les rend claires sur le sombre et sombres sur le
   clair sans jamais savoir ce qu elle survole.
   Elle grossit de 1 a 1.9 sur le lien, la seule affordance qui reste
   quand la fleche native est cachee.
   Gele, on verrait une bille posee sur un fond, sans l inversion ni la
   reaction au lien. */
.bcu{position:relative;width:136px;height:92px;overflow:hidden;border-radius:9px}
.bcu .half{position:absolute;inset:0;background:linear-gradient(90deg,var(--void) 0 50%,var(--ink) 50% 100%)}
.bcu .rows{position:absolute;left:11px;right:11px;top:12px;display:flex;flex-direction:column;gap:8px}
.bcu .rows i{display:block;height:6px;border-radius:3px;background:var(--s5)}
.bcu .rows i:last-child{width:54%}
.bcu .link{position:absolute;left:82px;top:60px;width:42px;height:14px;border-radius:7px;
  box-sizing:border-box;border:1px solid var(--lime)}
.bcu .ball2{position:absolute;left:8px;top:14px;width:26px;height:26px;border-radius:50%;
  background:var(--ink);mix-blend-mode:difference;animation:aBcu 4.4s cubic-bezier(.4,0,.4,1) infinite}
/* centre de la bille 21 et 27, centre du lien 103 et 67, donc 82 et 40 */
@keyframes aBcu{0%,8%{transform:translate(0,0) scale(1)}
  40%{transform:translate(48px,8px) scale(1)}
  62%,74%{transform:translate(82px,40px) scale(1.9)}
  94%,100%{transform:translate(0,0) scale(1)}}

/* Les vignettes sont ESTAMPEES et ne bougent plus. C est la difference
   avec une trainee de points, qui elle poursuit le pointeur. Chacune
   nait a l instant ou le pointeur atteint son point, puis s efface et
   retrecit SUR PLACE, et la forme laissee en l air est la trace du
   chemin deja parcouru.
   Six points, cycle de 3.6s, donc une estampe toutes les 0.6s pour une
   duree de vie de 1.8s, soit le rapport un pour trois de la vraie
   implementation, trois vignettes vivantes a la fois.
   Gele, on verrait six vignettes posees, sans savoir dans quel ordre ni
   qu elles s effacent. */
.itr2{position:relative;width:136px;height:86px}
.itr2 i{position:absolute;display:block;width:26px;height:20px;border-radius:6px;
  background:linear-gradient(135deg,var(--lime),var(--accent-2));opacity:0;
  animation:aItrDrop 3.6s ease-out infinite}
.itr2 .d1{left:1px;top:6px}
.itr2 .d2{left:39px;top:0;animation-delay:.6s}
.itr2 .d3{left:79px;top:14px;animation-delay:1.2s}
.itr2 .d4{left:101px;top:42px;animation-delay:1.8s}
.itr2 .d5{left:61px;top:58px;animation-delay:2.4s}
.itr2 .d6{left:19px;top:44px;animation-delay:3s}
.itr2 .cur{left:7px;top:9px;animation:aItrCur 3.6s linear infinite}
/* trajet ferme, six segments de 16.67 pour cent, le pointeur revient
   exactement a son point de depart */
@keyframes aItrCur{0%{transform:translate(0,0)}
  16.67%{transform:translate(38px,-6px)}33.33%{transform:translate(78px,8px)}
  50%{transform:translate(100px,36px)}66.67%{transform:translate(60px,52px)}
  83.33%{transform:translate(18px,38px)}100%{transform:translate(0,0)}}
@keyframes aItrDrop{0%{opacity:0;transform:scale(.55)}
  5%{opacity:1;transform:scale(1)}
  50%{opacity:0;transform:scale(.82)}
  100%{opacity:0;transform:scale(.55)}}

/* La CARTE est le sujet, pas la deformation. La bande de gris a droite
   est la carte de displacement, et chaque rangee est poussee d une
   quantite lue dans la case de gris qui lui fait face, 4, 22, 10, 22,
   4, 16, 10 puis 16 pixels. Clair pousse loin, sombre pousse peu, la
   preuve du lien est donc a l ecran et pas dans le commentaire.
   La jauge du bas est l intensite. Elle vaut zero aux deux bouts et au
   milieu, quand l image B est propre, et elle culmine exactement aux
   deux instants ou le fondu est a moitie.
   Huit rangees de 11 font 88, la hauteur exacte du cadre.
   Gele, on verrait une image decoupee, sans savoir d ou viennent les
   decalages ni qu ils reviennent a zero. */
.hdp{position:relative;width:118px;height:98px}
.hdp .pic{position:absolute;left:0;top:0;width:96px;height:88px;overflow:hidden;border-radius:8px;
  background:var(--s0)}
.hdp .pic i{position:relative;display:block;height:11px;overflow:hidden;
  background:linear-gradient(90deg,var(--lime),var(--accent-2))}
.hdp .pic i b{position:absolute;inset:0;opacity:0;
  background:linear-gradient(90deg,var(--a2),var(--accent-deep));
  animation:aHdpFade 5.2s ease-in-out infinite}
.hdp .r1,.hdp .r5{animation:aHdpA 5.2s cubic-bezier(.4,0,.3,1) infinite}
.hdp .r3,.hdp .r7{animation:aHdpB 5.2s cubic-bezier(.4,0,.3,1) infinite}
.hdp .r6,.hdp .r8{animation:aHdpC 5.2s cubic-bezier(.4,0,.3,1) infinite}
.hdp .r2,.hdp .r4{animation:aHdpD 5.2s cubic-bezier(.4,0,.3,1) infinite}
.hdp .map{position:absolute;left:102px;top:0;width:12px;height:88px;overflow:hidden;border-radius:4px}
.hdp .map b{display:block;height:11px}
.hdp .m1,.hdp .m5{background:var(--s2)}
.hdp .m3,.hdp .m7{background:var(--s4)}
.hdp .m6,.hdp .m8{background:var(--s6)}
.hdp .m2,.hdp .m4{background:var(--ink)}
.hdp .str{position:absolute;left:0;right:0;bottom:0;height:4px;border-radius:2px;background:var(--s2)}
.hdp .str b{position:absolute;left:0;top:0;bottom:0;width:0;border-radius:2px;background:var(--a2);
  animation:aHdpStr 5.2s cubic-bezier(.4,0,.3,1) infinite}
@keyframes aHdpA{0%,6%{transform:translateX(0)}30%{transform:translateX(4px)}
  50%,58%{transform:translateX(0)}80%{transform:translateX(4px)}96%,100%{transform:translateX(0)}}
@keyframes aHdpB{0%,6%{transform:translateX(0)}30%{transform:translateX(10px)}
  50%,58%{transform:translateX(0)}80%{transform:translateX(10px)}96%,100%{transform:translateX(0)}}
@keyframes aHdpC{0%,6%{transform:translateX(0)}30%{transform:translateX(16px)}
  50%,58%{transform:translateX(0)}80%{transform:translateX(16px)}96%,100%{transform:translateX(0)}}
@keyframes aHdpD{0%,6%{transform:translateX(0)}30%{transform:translateX(22px)}
  50%,58%{transform:translateX(0)}80%{transform:translateX(22px)}96%,100%{transform:translateX(0)}}
@keyframes aHdpFade{0%,8%{opacity:0}30%{opacity:.5}50%,60%{opacity:1}80%{opacity:.5}
  96%,100%{opacity:0}}
@keyframes aHdpStr{0%,6%{width:0}30%{width:100%}50%,58%{width:0}80%{width:100%}96%,100%{width:0}}

/* ---------- type et texture ---------- */
/* Ce sont des GLYPHES, pas des couleurs. Chaque emplacement garde sa
   place et fait defiler une bobine de seize signes, quatre tires au
   hasard puis quatre fois la vraie lettre, le tout ecrit deux fois. La
   bobine fait 16 fois 22, soit 352, et la course d une periode vaut
   donc exactement -50 pour cent.
   steps(8) donne huit images par cycle, quatre brouillees puis quatre
   verrouillees, soit moitie moitie. Le trait sous l emplacement passe
   au lime pendant la moitie verrouillee, et il s eteint au dernier pour
   cent, quand la bobine repart brouiller.
   Le decalage de 0.14s par emplacement fait que la resolution va de
   GAUCHE A DROITE, ce qui est la moitie du terme.
   Gele, on verrait un mot, sans savoir qu il vient d etre faux. */
.tsc2{display:flex;gap:4px}
.tsc2 .sl{position:relative;display:block;width:12px;height:22px;overflow:hidden;
  box-shadow:inset 0 -2px 0 var(--s3);animation:aTscLock 3.2s linear infinite}
.tsc2 .reel{display:block;animation:aTscReel 3.2s steps(8,end) infinite}
.tsc2 .reel b{display:block;height:22px;text-align:center;
  font:700 15px/22px var(--mono);color:var(--lime)}
.tsc2 .sl:nth-child(2),.tsc2 .sl:nth-child(2) .reel{animation-delay:.14s}
.tsc2 .sl:nth-child(3),.tsc2 .sl:nth-child(3) .reel{animation-delay:.28s}
.tsc2 .sl:nth-child(4),.tsc2 .sl:nth-child(4) .reel{animation-delay:.42s}
.tsc2 .sl:nth-child(5),.tsc2 .sl:nth-child(5) .reel{animation-delay:.56s}
.tsc2 .sl:nth-child(6),.tsc2 .sl:nth-child(6) .reel{animation-delay:.7s}
@keyframes aTscReel{from{transform:translateY(0)}to{transform:translateY(-50%)}}
@keyframes aTscLock{0%,49%{box-shadow:inset 0 -2px 0 var(--s3)}
  50%,99%{box-shadow:inset 0 -2px 0 var(--lime)}100%{box-shadow:inset 0 -2px 0 var(--s3)}}

/* L axe REDESSINE la lettre, il ne l etire pas, et c est exactement ce
   qui se voit ici. Le cadre pointille est le fantome de ce que ferait
   une mise a l echelle, il s etire de 0.78 a 1.32 pendant que la lettre
   epaissit sans changer de largeur. Le curseur de l axe dit ou en est
   la valeur, de 200 a 900.
   La piste fait 70 et le curseur 8, la course vaut donc 62.
   Gele, on verrait une lettre grasse, sans savoir si elle a ete
   redessinee ou simplement grossie. */
.vfa{display:flex;flex-direction:column;align-items:center;gap:11px;width:124px}
.vfa .glyph{position:relative;width:100%;height:48px;display:grid;place-items:center}
.vfa .ghost{position:absolute;left:50%;top:1px;width:58px;height:46px;margin-left:-29px;
  box-sizing:border-box;border:1px dashed var(--ink-3);border-radius:5px;opacity:.5;
  animation:aVfaGhost 3.6s ease-in-out infinite}
.vfa b{position:relative;z-index:2;font:200 38px/48px var(--font);color:var(--lime);
  letter-spacing:-.02em;animation:aVfaWght 3.6s ease-in-out infinite}
.vfa .axis{display:flex;align-items:center;gap:7px}
.vfa .axis em{font:600 8px/1 var(--mono);color:var(--ink-3);font-style:normal}
.vfa .trk{position:relative;display:block;width:70px;height:4px;border-radius:2px;background:var(--s2)}
.vfa .trk i{position:absolute;left:0;top:-2px;width:8px;height:8px;border-radius:50%;
  background:var(--a2);animation:aVfaThumb 3.6s ease-in-out infinite}
@keyframes aVfaWght{0%,100%{font-weight:200}50%{font-weight:900}}
@keyframes aVfaGhost{0%,100%{transform:scaleX(.78)}50%{transform:scaleX(1.32)}}
@keyframes aVfaThumb{0%,100%{transform:translateX(0)}50%{transform:translateX(62px)}}

/* Le CHANGEMENT DE SENS est le terme, et il manquait. La jauge du bas
   est signee, elle part du centre, a droite pour l avant et a gauche
   pour l arriere. Le bandeau la suit exactement.
   Les positions sont 0, -3, -28, -35, -38, -38, -30, -30, -46 puis -50
   pour cent aux temps 0, 10, 28, 40, 52, 55, 69, 72, 88 et 100. La
   cadence entre 69 et 55 est donc NEGATIVE, le bandeau repart en
   arriere, et la cadence de fin, 0.33 par unite, retrouve celle du
   debut, 0.30, donc le raccord ne se voit pas non plus en vitesse.
   Le contenu est ecrit huit fois et la course vaut -50 pour cent, soit
   quatre motifs, le raccord tombe donc sur un point identique.
   Gele, on verrait un bandeau de texte, sans la vitesse ni le sens. */
.vmq{width:100%;display:flex;flex-direction:column;gap:10px}
.vmq .win{overflow:hidden;
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 12%,#000 88%,transparent);
  mask-image:linear-gradient(90deg,transparent,#000 12%,#000 88%,transparent)}
.vmq .strip3{display:inline-block;white-space:nowrap;font:800 18px/26px var(--font);
  letter-spacing:.05em;color:var(--lime);animation:aVmq 7s linear infinite}
.vmq .vg{position:relative;height:5px;border-radius:3px;background:var(--s2)}
.vmq .vg b{position:absolute;top:0;bottom:0;width:50%;border-radius:3px}
.vmq .pos{left:50%;transform-origin:left;transform:scaleX(0);background:var(--a2);
  animation:aVmqPos 7s linear infinite}
.vmq .neg{left:0;transform-origin:right;transform:scaleX(0);background:var(--a4);
  animation:aVmqNeg 7s linear infinite}
.vmq .zero{position:absolute;left:50%;top:-3px;width:1px;height:11px;background:var(--ink-3)}
@keyframes aVmq{0%{transform:translateX(0)}10%{transform:translateX(-3%)}
  28%{transform:translateX(-28%)}40%{transform:translateX(-35%)}
  52%{transform:translateX(-38%)}55%{transform:translateX(-38%)}
  69%{transform:translateX(-30%)}72%{transform:translateX(-30%)}
  88%{transform:translateX(-46%)}100%{transform:translateX(-50%)}}
/* cadences normalisees sur le maximum, 1.39 par unite de temps */
@keyframes aVmqPos{0%,10%{transform:scaleX(.22)}28%{transform:scaleX(1)}40%{transform:scaleX(.42)}
  52%{transform:scaleX(.18)}55%,69%{transform:scaleX(0)}72%{transform:scaleX(.22)}
  88%{transform:scaleX(.72)}100%{transform:scaleX(.22)}}
@keyframes aVmqNeg{0%,52%{transform:scaleX(0)}62%{transform:scaleX(.41)}
  69%,100%{transform:scaleX(0)}}


/* Le TRACE est le sujet, pas le badge. Le cercle pointille reste
   immobile et c est le texte qui avance dessus. Faire tourner tout le
   SVG, ce que faisait la version precedente, donnait exactement la meme
   image en vignette mais racontait le contraire, un badge qui pivote au
   lieu de glyphes qui parcourent une courbe. Le guide fixe est ce qui
   rend la difference lisible.
   Sur un cercle, tourner le seul element text autour du centre est
   l equivalent exact d un startOffset qui avance, la consigne du spec.
   Gele, on verrait un sceau, sans savoir ce qui bouge. */
.tpath{position:relative;display:grid;place-items:center;width:104px;height:104px}
.tpath svg{width:104px;height:104px}
.tpath .guide{fill:none;stroke:var(--s3);stroke-width:1;stroke-dasharray:3 4}
.tpath text{font:700 11.5px var(--mono);fill:var(--lime);stroke:none;letter-spacing:1.4px;
  transform-box:view-box;transform-origin:50px 50px;animation:aTpath 9s linear infinite}
.tpath .core2{position:absolute;width:26px;height:26px;border-radius:8px;background:var(--s3)}
@keyframes aTpath{to{transform:rotate(360deg)}}

/* ---------- type et texture ---------- */
/* Le grain n a de sens que CONTRE quelque chose. Les deux moities
   portent le meme degrade a paliers durs, cinq bandes franches. A
   gauche on voit le banding, a droite le grain le dissout. Le cote off
   ne bouge jamais, c est lui qui prouve que le voile fait quelque
   chose.
   Le bruit se decale de deux ou trois pixels quatre fois par demi
   seconde, assez pour casser les paliers sans devenir un scintillement.
   Gele, on aurait deux degrades identiques, et le terme entier
   disparait. */
.grn{position:relative;width:132px;height:80px;border-radius:9px;overflow:hidden;display:flex}
.grn .side{position:relative;flex:1;overflow:hidden;
  background:linear-gradient(160deg,var(--lime) 0 18%,var(--a3) 18% 38%,
    var(--accent-2) 38% 58%,var(--a2) 58% 78%,var(--accent-deep) 78% 100%)}
.grn .on{box-shadow:inset 1px 0 0 rgba(var(--void-rgb),.35)}
.grn em{position:absolute;left:6px;bottom:5px;z-index:2;font:700 7px/1 var(--mono);
  color:var(--void);opacity:.6;font-style:normal}
.grn .noise{position:absolute;inset:-40px;opacity:.5;
  background-image:radial-gradient(var(--ink) .6px,transparent .7px),
    radial-gradient(var(--void) .6px,transparent .7px);
  background-size:3px 3px,4px 4px;background-position:0 0,1px 2px;
  animation:aGrn .5s steps(4,end) infinite}
@keyframes aGrn{0%{transform:translate(0,0)}25%{transform:translate(-2px,1px)}
  50%{transform:translate(1px,-2px)}75%{transform:translate(2px,2px)}
  100%{transform:translate(0,0)}}

/* Ce sont trois CANAUX de la meme forme, pas trois formes. Les trois
   copies sont en mix-blend-mode screen, elles redonnent du blanc la ou
   elles se superposent et ne laissent de couleur que sur les bords, ce
   qui est exactement une frange chromatique.
   Le decalage CROIT depuis le centre, la consigne que la version
   precedente ignorait. Zero au centre, 1.6 pixel aux reperes
   intermediaires, 3 pixels aux extremes. Le repere central ne recoit
   aucune animation, c est le temoin.
   Gele, on verrait des rectangles colores, sans le bord franc au
   centre qui est toute la demonstration. */
.chab{position:relative;width:144px;height:64px;display:flex;align-items:center;
  justify-content:space-between;padding:0 9px;box-sizing:border-box}
.chab .ax{position:absolute;left:50%;top:6px;bottom:6px;width:1px;background:var(--s3)}
.chab .m{position:relative;display:block;width:18px;height:34px;flex:0 0 auto}
.chab .m span{position:absolute;inset:0;border-radius:5px;mix-blend-mode:screen}
.chab .m .r{background:var(--a4)}
.chab .m .g{background:var(--lime)}
.chab .m .c{background:var(--a2)}
.chab .far .r{animation:aChabFarR 2.6s ease-in-out infinite}
.chab .far .c{animation:aChabFarC 2.6s ease-in-out infinite}
.chab .mid .r{animation:aChabMidR 2.6s ease-in-out infinite}
.chab .mid .c{animation:aChabMidC 2.6s ease-in-out infinite}
@keyframes aChabFarR{0%,100%{transform:translateX(0)}50%{transform:translateX(-3px)}}
@keyframes aChabFarC{0%,100%{transform:translateX(0)}50%{transform:translateX(3px)}}
@keyframes aChabMidR{0%,100%{transform:translateX(0)}50%{transform:translateX(-1.6px)}}
@keyframes aChabMidC{0%,100%{transform:translateX(0)}50%{transform:translateX(1.6px)}}

/* Il faut du CONTENU a corrompre. Une carte complete, visuel et deux
   lignes, est dessinee quatre fois, la base plus trois copies decoupees
   en bandes INEGALES de 12, 14 et 22 pour cent. Trois bandes egales de
   couleur plate, ce que faisait la version precedente, se lisaient
   comme trois barres qui glissent, pas comme un signal casse.
   La rafale ne dure que de 78 a 84 pour cent d un cycle de 6s, soit
   360ms toutes les six secondes, ce qui est la rarete demandee. Une
   rafale toutes les 2.6s en faisait un decor.
   Le decalage RVB accompagne les memes trois images, magenta sur la
   bande haute et cyan sur la bande basse.
   Gele, on aurait une carte propre, et on ne saurait meme pas qu il se
   passe quelque chose. */
.gli{position:relative;width:120px;height:74px;border-radius:9px;overflow:hidden;background:var(--s0)}
.gli .lay{position:absolute;inset:0;padding:9px;box-sizing:border-box;display:flex;
  flex-direction:column;gap:7px}
.gli .lay .im{display:block;height:32px;border-radius:6px;
  background:linear-gradient(135deg,var(--lime),var(--accent-2))}
.gli .lay .t{display:block;height:6px;border-radius:3px;background:var(--s5)}
.gli .lay .t2{width:62%}
.gli .b1{clip-path:inset(14% 0 74% 0);animation:aGli1 6s steps(1,end) infinite}
.gli .b2{clip-path:inset(46% 0 40% 0);animation:aGli2 6s steps(1,end) infinite}
.gli .b3{clip-path:inset(70% 0 8% 0);animation:aGli3 6s steps(1,end) infinite}
.gli .tr,.gli .tc{position:absolute;inset:0;mix-blend-mode:screen;opacity:0}
.gli .tr{background:var(--a4);clip-path:inset(14% 0 74% 0);animation:aGliTr 6s steps(1,end) infinite}
.gli .tc{background:var(--a2);clip-path:inset(70% 0 8% 0);animation:aGliTc 6s steps(1,end) infinite}
@keyframes aGli1{0%,77%{transform:translateX(0)}78%{transform:translateX(-11px)}
  80%{transform:translateX(5px)}82%,100%{transform:translateX(0)}}
@keyframes aGli2{0%,77%{transform:translateX(0)}79%{transform:translateX(9px)}
  81%{transform:translateX(-4px)}83%,100%{transform:translateX(0)}}
@keyframes aGli3{0%,77%{transform:translateX(0)}78%{transform:translateX(-6px)}
  81%{transform:translateX(7px)}84%,100%{transform:translateX(0)}}
@keyframes aGliTr{0%,77%{opacity:0}78%,81%{opacity:.55}82%,100%{opacity:0}}
@keyframes aGliTc{0%,77%{opacity:0}78%,83%{opacity:.5}84%,100%{opacity:0}}

/* De VRAIS blocs plats, pas une grille de traits posee sur une image
   qui reste nette. La version precedente dessinait un quadrillage par
   dessus un degrade lisse, ce qui ne retire aucun detail et n est donc
   pas de la pixelisation.
   Deux mosaiques reelles, 4 sur 3 en cellules de 28 puis 8 sur 6 en
   cellules de 14, chaque cellule d une seule opacite lue au centre de
   sa case. La taille de bloc est divisee par deux a chaque palier,
   c est la consigne des puissances de deux. Les paliers 28, 18, 11 et 6
   de la version precedente ne respectaient aucun rapport.
   Gele, on verrait une mosaique, sans la resolution progressive. */
.pxl{position:relative;width:112px;height:84px;border-radius:8px;overflow:hidden;
  background:var(--accent-deep)}
.pxl .smooth{position:absolute;inset:0;
  background:linear-gradient(135deg,var(--accent-deep),var(--lime));
  animation:aPxlC 4.4s steps(1,end) infinite}
.pxl .mo{position:absolute;inset:0;display:grid}
.pxl .mo i{display:block;background:var(--lime)}
.pxl .a{grid-template-columns:repeat(4,1fr);grid-template-rows:repeat(3,1fr);
  animation:aPxlA 4.4s steps(1,end) infinite}
.pxl .b{grid-template-columns:repeat(8,1fr);grid-template-rows:repeat(6,1fr);
  animation:aPxlB 4.4s steps(1,end) infinite}
/* aller retour, 28 puis 14 puis lisse puis 14 puis 28 */
@keyframes aPxlA{0%,20%{opacity:1}21%,79%{opacity:0}80%,100%{opacity:1}}
@keyframes aPxlB{0%,20%{opacity:0}21%,40%{opacity:1}41%,59%{opacity:0}
  60%,79%{opacity:1}80%,100%{opacity:0}}
@keyframes aPxlC{0%,40%{opacity:0}41%,59%{opacity:1}60%,100%{opacity:0}}

/* Des GLYPHES, et une source visible a cote. Chaque cellule fait
   defiler la rampe de densite, point, plus, diese, arobase, et la bande
   claire qui descend sur la source declenche le changement rangee par
   rangee. Les quatre rangees sont decalees de 0.7s sur un cycle de
   2.8s, soit exactement le temps que met la bande a franchir une
   rangee, la correspondance luminance vers glyphe est donc a l ecran et
   pas seulement dans la definition.
   La version precedente animait des carres qui changeaient de taille,
   avec une opacite fixe par rangee. Un decor fixe qui pretendait
   mesurer une luminosite.
   La bobine fait 8 fois 13, soit 104, et la course d une periode vaut
   donc exactement -50 pour cent.
   Gele, on verrait une grille de signes, sans le lien avec la source. */
.asc{display:flex;align-items:center;gap:11px}
.asc .src{position:relative;width:40px;height:52px;border-radius:6px;overflow:hidden;
  background:linear-gradient(180deg,var(--accent-deep),var(--s1))}
.asc .band{position:absolute;left:0;right:0;top:0;height:13px;
  background:linear-gradient(180deg,transparent,var(--lime),transparent);
  animation:aAscBand 2.8s linear infinite}
.asc .gri{display:grid;grid-template-columns:repeat(6,9px);grid-auto-rows:13px}
.asc .cl{display:block;width:9px;height:13px;overflow:hidden}
.asc .reel{display:block;animation:aAscReel 2.8s steps(4,end) infinite}
.asc .reel b{display:block;height:13px;text-align:center;font:700 10px/13px var(--mono);
  color:var(--lime)}
.asc .q1 .reel{animation-delay:.7s}
.asc .q2 .reel{animation-delay:1.4s}
.asc .q3 .reel{animation-delay:2.1s}
@keyframes aAscReel{from{transform:translateY(0)}to{transform:translateY(-50%)}}
@keyframes aAscBand{0%{transform:translateY(0);opacity:0}
  8%{opacity:1}92%{opacity:1}
  100%{transform:translateY(52px);opacity:0}}

/* La MAILLE EST VERROUILLEE a 4 pixels partout, et c est ce que la
   version precedente violait en animant background-size, exactement le
   swimming que la consigne interdit.
   Le ton n est plus rendu par un degrade mais par le RAYON du point,
   de 1.7 a 0.3 pixel sur huit colonnes, avec deux couleurs seulement.
   C est cela, tramer, approcher un ton continu avec une palette
   reduite.
   La frontiere balaye la scene et laisse voir le degrade lisse de
   l autre cote, la comparaison est donc dans la scene. Huit colonnes de
   16 font 128, la largeur exacte du cadre.
   Gele, on verrait une image tramee, sans son original. */
.dth{position:relative;width:128px;height:76px;border-radius:8px;overflow:hidden}
.dth .grad{position:absolute;inset:0;background:linear-gradient(90deg,var(--lime),var(--accent-deep))}
.dth .dit{position:absolute;inset:0;display:flex;animation:aDthWipe 5s ease-in-out infinite}
.dth .dit i{display:block;flex:1;background-color:var(--accent-deep);background-size:4px 4px}
.dth .c0{background-image:radial-gradient(var(--lime) 1.7px,transparent 1.8px)}
.dth .c1{background-image:radial-gradient(var(--lime) 1.5px,transparent 1.6px)}
.dth .c2{background-image:radial-gradient(var(--lime) 1.3px,transparent 1.4px)}
.dth .c3{background-image:radial-gradient(var(--lime) 1.1px,transparent 1.2px)}
.dth .c4{background-image:radial-gradient(var(--lime) .9px,transparent 1px)}
.dth .c5{background-image:radial-gradient(var(--lime) .7px,transparent .8px)}
.dth .c6{background-image:radial-gradient(var(--lime) .5px,transparent .6px)}
.dth .c7{background-image:radial-gradient(var(--lime) .3px,transparent .4px)}
.dth .edge{position:absolute;top:0;bottom:0;left:0;width:1px;z-index:3;background:var(--ink-3);
  animation:aDthEdge 5s ease-in-out infinite}
@keyframes aDthWipe{0%,100%{clip-path:inset(0 100% 0 0)}50%{clip-path:inset(0 0 0 0)}}
@keyframes aDthEdge{0%,100%{transform:translateX(0)}50%{transform:translateX(127px)}}

/* La tete de lecture PILOTE l image, et elle repart en arriere. La
   version precedente allumait les vignettes sur des delais fixes, donc
   la sequence se jouait toute seule et ne revenait jamais sur ses pas,
   ce qui est precisement la difference entre un scrub et un autoplay.
   Ici une seule course commande les deux, le cadre saute d une vignette
   a l autre en steps pendant que la tete glisse, et au retour tout
   repasse dans l autre sens.
   La pellicule fait 6 fois 21 avec 3 de gouttiere, soit 141, et la tete
   parcourt 5 fois 24, soit 120. Les bascules sont posees a mi chemin
   entre deux vignettes, a 5, 15, 25, 35 et 45 pour cent, sans quoi le
   cadre affiche une image et la tete en designe une autre.
   Gele, on verrait une pellicule et un cadre, sans savoir lequel
   commande l autre. */
.vsc{display:flex;flex-direction:column;align-items:center;gap:9px;width:150px}
.vsc .vp{position:relative;width:60px;height:36px;overflow:hidden;border-radius:6px;background:var(--s1)}
.vsc .strip{position:absolute;left:0;top:0;display:flex;animation:aVscStrip 5.6s steps(1,end) infinite}
.vsc .fr{position:relative;display:block;width:60px;height:36px;flex:0 0 auto;
  background:linear-gradient(180deg,var(--s2),var(--s1))}
.vsc .fr .f{position:absolute;top:50%;left:var(--x);width:12px;height:12px;margin:-6px 0 0 -6px;
  border-radius:4px;background:var(--lime)}
.vsc .film{position:relative;display:flex;gap:3px}
.vsc .mn{position:relative;display:block;width:21px;height:26px;border-radius:4px;overflow:hidden;
  background:var(--s2);flex:0 0 auto}
.vsc .mn .f{position:absolute;top:50%;left:var(--x);width:7px;height:7px;margin:-3.5px 0 0 -3.5px;
  border-radius:2px;background:var(--lime);opacity:.7}
.vsc .hdd{position:absolute;left:-2px;top:-2px;width:25px;height:30px;border-radius:6px;
  box-sizing:border-box;border:1.5px solid var(--lime);
  animation:aVscHead 5.6s linear infinite}
.vsc .lb{font:600 8px/1 var(--mono);color:var(--ink-3);font-style:normal}
@keyframes aVscHead{0%,100%{transform:translateX(0)}50%{transform:translateX(120px)}}
@keyframes aVscStrip{0%,4.9%{transform:translateX(0)}
  5%,14.9%{transform:translateX(-60px)}
  15%,24.9%{transform:translateX(-120px)}
  25%,34.9%{transform:translateX(-180px)}
  35%,44.9%{transform:translateX(-240px)}
  45%,55%{transform:translateX(-300px)}
  55.1%,65%{transform:translateX(-240px)}
  65.1%,75%{transform:translateX(-180px)}
  75.1%,85%{transform:translateX(-120px)}
  85.1%,95%{transform:translateX(-60px)}
  95.1%,100%{transform:translateX(0)}}


/* ---------------- page et physique ---------------- */
/* Le nombre doit dire quelque chose de REEL. Les cinq pastilles sont
   les ressources, elles s allument a 12, 24, 36, 48 et 60 pour cent, et
   la barre franchit un cinquieme aux MEMES instants. La preuve du lien
   est donc a l ecran, on voit la barre attendre la ressource.
   La version precedente faisait defiler un compteur a chiffres, ce qui
   la rendait indiscernable d un odometre et n avancait aucune preuve.
   Le rouleau appartient a odometer, pas ici.
   L ecran sort de 60 a 74 pour cent, la premiere vue entre de 66 a 80,
   les deux se CHEVAUCHENT, ce qui est la consigne d une seule
   chronologie. Elle demande 100 a 200ms, la demo est ralentie.
   Le retour se fait sous couvert. La vue est remise a son etat de
   depart a 30 pour cent, pendant que l ecran couvre encore tout, donc
   personne ne le voit.
   Gele, on verrait un ecran d attente, sans savoir ce qu il attend. */
.prl{position:relative;width:120px;height:88px;border-radius:9px;overflow:hidden;background:var(--stage)}
.prl .hero6{position:absolute;inset:0;padding:10px;box-sizing:border-box;display:flex;
  flex-direction:column;gap:7px;animation:aPrlHero 4.2s cubic-bezier(.2,.8,.3,1) infinite}
.prl .hero6 .im{display:block;height:40px;border-radius:7px;
  background:linear-gradient(135deg,var(--lime),var(--accent-2))}
.prl .hero6 .t{display:block;height:6px;border-radius:3px;background:var(--s5)}
.prl .hero6 .t2{width:58%}
.prl .veil{position:absolute;inset:0;background:var(--s0);display:flex;flex-direction:column;
  align-items:center;justify-content:center;gap:11px;animation:aPrlV 4.2s cubic-bezier(.6,0,.2,1) infinite}
.prl .q{display:flex;gap:5px}
.prl .q i{display:block;width:12px;height:12px;border-radius:4px;background:var(--s3)}
.prl .bar6{position:relative;display:block;width:86px;height:5px;border-radius:3px;
  background:var(--s2);overflow:hidden}
.prl .bar6 i{position:absolute;left:0;top:0;bottom:0;width:0;border-radius:3px;background:var(--lime);
  animation:aPrlBar 4.2s steps(1,end) infinite}
/* une keyframe par pastille, un delai partagé ferait deborder la remise
   a zero de la derniere au dela du cycle */
.prl .q1{animation:aPrlQ1 4.2s steps(1,end) infinite}
.prl .q2{animation:aPrlQ2 4.2s steps(1,end) infinite}
.prl .q3{animation:aPrlQ3 4.2s steps(1,end) infinite}
.prl .q4{animation:aPrlQ4 4.2s steps(1,end) infinite}
.prl .q5{animation:aPrlQ5 4.2s steps(1,end) infinite}
@keyframes aPrlQ1{0%,10%{background:var(--s3)}12%,90%{background:var(--lime)}92%,100%{background:var(--s3)}}
@keyframes aPrlQ2{0%,22%{background:var(--s3)}24%,90%{background:var(--lime)}92%,100%{background:var(--s3)}}
@keyframes aPrlQ3{0%,34%{background:var(--s3)}36%,90%{background:var(--lime)}92%,100%{background:var(--s3)}}
@keyframes aPrlQ4{0%,46%{background:var(--s3)}48%,90%{background:var(--lime)}92%,100%{background:var(--s3)}}
@keyframes aPrlQ5{0%,58%{background:var(--s3)}60%,90%{background:var(--lime)}92%,100%{background:var(--s3)}}
/* memes instants que les pastilles, un cinquieme par ressource */
@keyframes aPrlBar{0%,11%{width:0}12%,23%{width:20%}24%,35%{width:40%}36%,47%{width:60%}
  48%,59%{width:80%}60%,90%{width:100%}92%,100%{width:0}}
/* invisible aux deux bouts, la remise en place se fait hors cadre */
@keyframes aPrlV{0%{transform:translateY(0);opacity:0}
  1%,60%{transform:translateY(0);opacity:1}
  74%{transform:translateY(-100%);opacity:1}
  77%{transform:translateY(-100%);opacity:0}
  78%,100%{transform:translateY(0);opacity:0}}
/* remise a l etat de depart a 30 pour cent, sous couvert */
@keyframes aPrlHero{0%{transform:translateY(0);opacity:1}
  20%{transform:translateY(0);opacity:1}
  30%,66%{transform:translateY(14px);opacity:0}
  80%,100%{transform:translateY(0);opacity:1}}

/* Il faut DEUX pages, sinon rien ne dit qu un echange a eu lieu. La
   page B monte en opacite a 29 pour cent, pendant que le rideau couvre
   tout de 24 a 34, et la page A revient a 79, pendant la seconde
   couverture. Deux balayages par cycle, c est ce qui permet a la boucle
   de revenir a son point de depart sans qu on voie l echange.
   La pastille de chargement se remplit PENDANT la couverture et finit
   juste avant que le rideau reparte, ce qui est la consigne de precharger
   derriere le panneau.
   Le rideau entre par le bas et sort par le haut, puis se replace en bas
   hors cadre a 56.1 pour cent. Les deux bouts valent plus ou moins 100
   pour cent, la convention de boite de decoupe, la boucle est donc
   propre.
   Le cycle complet doit tenir sous 900ms, la demo est ralentie.
   Gele, on verrait un panneau sur une page. */
.ctn{position:relative;width:124px;height:86px;border-radius:9px;overflow:hidden;background:var(--s0)}
.ctn .pg{position:absolute;inset:0;padding:10px;box-sizing:border-box;display:flex;
  flex-direction:column;gap:7px}
.ctn .pg .im{display:block;height:38px;border-radius:7px}
.ctn .pg .t{display:block;height:6px;border-radius:3px}
.ctn .pg .t2{width:56%}
.ctn .pgA .im{background:linear-gradient(135deg,var(--lime),var(--accent-2))}
.ctn .pgA .t{background:var(--s5)}
.ctn .pgB{opacity:0;animation:aCtnB 5.6s steps(1,end) infinite}
.ctn .pgB .im{background:linear-gradient(135deg,var(--a2),var(--accent-deep))}
.ctn .pgB .t{background:var(--s4)}
.ctn .curtain{position:absolute;inset:0;background:var(--void);display:grid;place-items:center;
  animation:aCtnC 5.6s cubic-bezier(.6,0,.2,1) infinite}
.ctn .pip{display:block;width:44px;height:4px;border-radius:2px;background:rgba(var(--ink-rgb),.2);
  overflow:hidden}
.ctn .pip b{display:block;height:4px;border-radius:2px;background:var(--lime);transform-origin:left;
  transform:scaleX(0);animation:aCtnPip 5.6s cubic-bezier(.3,0,.3,1) infinite}
@keyframes aCtnC{0%,6%{transform:translateY(100%)}
  24%,34%{transform:translateY(0)}
  46%,56%{transform:translateY(-100%)}
  56.1%{transform:translateY(100%)}
  74%,84%{transform:translateY(0)}
  96%,100%{transform:translateY(-100%)}}
@keyframes aCtnB{0%,27%{opacity:0}29%,77%{opacity:1}79%,100%{opacity:0}}
@keyframes aCtnPip{0%,22%{transform:scaleX(0)}32%,34%{transform:scaleX(1)}
  36%,72%{transform:scaleX(0)}82%,84%{transform:scaleX(1)}86%,100%{transform:scaleX(0)}}

/* Le footer ne bouge PAS. C est le contenu qui le quitte, et la jauge
   de droite arrive en butee exactement au moment ou la decouverte se
   termine, ce qui dit que cela se passe en FIN de scroll et pas
   n importe quand.
   Le footer fait 46 et la course vaut 46, la consigne d accorder la
   distance a la hauteur. Un pixel de plus laisserait du scroll une fois
   le footer entierement ouvert.
   Le footer porte un logo et trois liens, sinon deux blocs plats ne
   permettent pas de dire lequel etait deja la.
   Gele, on verrait deux blocs superposes, sans savoir lequel voyage. */
.sfr{position:relative;width:132px;height:92px}
.sfr .foot2{position:absolute;left:0;right:14px;bottom:0;height:46px;border-radius:0 0 9px 9px;
  background:var(--lime);padding:9px;box-sizing:border-box;display:flex;flex-direction:column;
  justify-content:space-between}
.sfr .foot2 .lg{display:block;width:16px;height:16px;border-radius:5px;
  background:rgba(var(--on-accent-rgb),.75)}
.sfr .lk{display:flex;gap:6px}
.sfr .lk i{display:block;width:22px;height:4px;border-radius:2px;
  background:rgba(var(--on-accent-rgb),.45)}
.sfr .main2{position:absolute;left:0;right:14px;top:0;bottom:0;border-radius:9px;background:var(--s1);
  padding:10px;box-sizing:border-box;display:flex;flex-direction:column;gap:8px;
  animation:aSfr 4.4s cubic-bezier(.4,0,.3,1) infinite}
.sfr .main2 i{display:block;height:6px;border-radius:3px;background:var(--s4)}
.sfr .main2 .h{height:10px;width:64%;border-radius:5px;background:var(--ink);opacity:.85}
.sfr .gg{position:absolute;right:0;top:6px;bottom:6px;width:4px;border-radius:2px;background:var(--s1)}
.sfr .gg i{position:absolute;left:0;right:0;top:0;height:22px;border-radius:2px;background:var(--s5);
  animation:aSfrG 4.4s cubic-bezier(.4,0,.3,1) infinite}
/* footer de 46, course de 46, ni plus ni moins */
@keyframes aSfr{0%,12%{transform:translateY(0)}56%,88%{transform:translateY(-46px)}
  100%{transform:translateY(0)}}
/* la jauge fait 80 et le curseur 22, la course vaut donc 58, et elle
   arrive en butee au meme instant que la decouverte, a 56 pour cent */
@keyframes aSfrG{0%,12%{transform:translateY(0)}56%,88%{transform:translateY(58px)}
  100%{transform:translateY(0)}}

/* Les colonnes ne parcourent PAS la meme distance, et c est tout le
   terme. Pour aller de 0 a 274, les centaines avancent de 2 crans, les
   dizaines de 7, les unites de 24, soit deux tours complets plus 4. La
   version precedente faisait avancer les deux colonnes de 4 crans, ce
   qui se lisait comme une rangee de rouleaux de machine a sous.
   La bobine des unites porte donc trois series de dix, 30 crans de 34,
   soit 1020, pour une course de 24 fois 34 egale a 816.
   Le compte monte puis redescend. Un odometre ne se rembobine pas, mais
   il descend quand la valeur descend, alors qu un retour brutal a zero
   se lirait comme une panne.
   Decalage de 60ms par rang depuis la gauche, les unites se posent donc
   en dernier, et elles sont aussi celles qui vont le plus loin.
   Gele, on verrait trois chiffres. */
.odo{display:flex;gap:4px}
.odo .win{display:block;width:22px;height:34px;overflow:hidden;border-radius:6px;background:var(--s1)}
.odo .reel{display:block;font:800 23px/34px var(--mono);color:var(--lime);text-align:center}
.odo .reel b{display:block;height:34px}
.odo .rh{animation:aOdoH 4.4s cubic-bezier(.25,.9,.3,1) infinite}
.odo .rt{animation:aOdoT 4.4s cubic-bezier(.25,.9,.3,1) infinite;animation-delay:.06s}
.odo .ru{animation:aOdoU 4.4s cubic-bezier(.25,.9,.3,1) infinite;animation-delay:.12s}
@keyframes aOdoH{0%,6%{transform:translateY(0)}42%,56%{transform:translateY(-68px)}
  96%,100%{transform:translateY(0)}}
@keyframes aOdoT{0%,6%{transform:translateY(0)}42%,56%{transform:translateY(-238px)}
  96%,100%{transform:translateY(0)}}
@keyframes aOdoU{0%,6%{transform:translateY(0)}42%,56%{transform:translateY(-816px)}
  96%,100%{transform:translateY(0)}}

/* Le meme mouvement, DEUX FOIS, une fois filtre et une fois nu. La
   paire du bas se contente de se recouvrir, celle du haut developpe un
   col puis fusionne. Rien ne les separe que le filtre, la demonstration
   est donc dans la scene et pas dans la definition.
   Le filtre est pose sur le GROUPE, jamais sur chaque forme, sans quoi
   chacune serait floutee et recontrastee dans son coin et rien ne
   pourrait fusionner.
   Le contraste CSS seuille le RVB et non l alpha, il lui faut donc un
   fond opaque, d ou le void sous les deux groupes.
   Blous de 6 pour des formes de 28, la consigne dit 10 pour 40 a 60, le
   rapport est tenu.
   Gele, on verrait deux paires de cercles identiques. */
.goo{display:flex;flex-direction:column;gap:8px;width:132px}
.goo .grp{position:relative;display:block;height:40px;border-radius:8px;overflow:hidden;
  background:var(--void)}
.goo .f{filter:blur(6px) contrast(18)}
.goo .grp i{position:absolute;top:50%;left:50%;width:28px;height:28px;margin:-14px 0 0 -14px;
  border-radius:50%;background:var(--lime)}
.goo .b1{animation:aGoo1 3s ease-in-out infinite}
.goo .b2{animation:aGoo2 3s ease-in-out infinite}
@keyframes aGoo1{0%,100%{transform:translateX(-32px)}50%{transform:translateX(-9px)}}
@keyframes aGoo2{0%,100%{transform:translateX(32px)}50%{transform:translateX(9px)}}

/* Les corps se POSENT LES UNS SUR LES AUTRES, ce que la version
   precedente ne faisait pas. Quatre chutes en couloirs paralleles vers
   une meme ligne de sol auraient pu etre quatre animations
   independantes, et rien n aurait prouve qu un moteur les resout
   ensemble.
   Le sol est a 85, les corps font 15, les deux premiers reposent donc a
   70 et les deux suivants a 55, exactement sur le dessus des premiers.
   Ceux du dessus arrivent en retard et prennent une legere rotation, ce
   qui est ce que fait un corps qui touche hors de son axe.
   Les murs ont une EPAISSEUR, la consigne le demande, un mur sans
   largeur laisse passer un corps rapide entre deux images.
   Chaque corps est invisible aux deux bouts, la remontee ne se voit
   donc pas.
   Gele, on verrait une pile, sans savoir dans quel ordre elle s est
   faite. */
.phy{position:relative;width:120px;height:92px}
.phy .wl{position:absolute;top:0;bottom:6px;width:3px;border-radius:2px;background:var(--s2)}
.phy .left{left:0}
.phy .right{right:0}
.phy .ground{position:absolute;left:0;right:0;bottom:4px;height:3px;border-radius:2px;background:var(--s3)}
.phy .bd{position:absolute;display:block;width:30px;height:15px;border-radius:7px;background:var(--lime);
  opacity:0}
.phy .p1{left:14px;top:70px;animation:aPhyFloor 3.8s cubic-bezier(.4,0,.7,1) infinite}
.phy .p2{left:62px;top:70px;animation:aPhyFloor 3.8s cubic-bezier(.4,0,.7,1) infinite;
  animation-delay:.22s}
.phy .p3{left:16px;top:55px;animation:aPhyStackA 3.8s cubic-bezier(.4,0,.7,1) infinite;
  animation-delay:.5s}
.phy .p4{left:60px;top:55px;animation:aPhyStackB 3.8s cubic-bezier(.4,0,.7,1) infinite;
  animation-delay:.74s}
@keyframes aPhyFloor{0%{transform:translateY(-52px);opacity:0}
  6%{transform:translateY(-52px);opacity:1}
  44%{transform:translateY(0)}
  50%{transform:translateY(-5px)}
  58%,92%{transform:translateY(0)}
  95%{transform:translateY(0);opacity:0}
  100%{transform:translateY(-52px);opacity:0}}
@keyframes aPhyStackA{0%{transform:translateY(-44px) rotate(0);opacity:0}
  6%{transform:translateY(-44px) rotate(0);opacity:1}
  44%{transform:translateY(0) rotate(-6deg)}
  50%{transform:translateY(-4px) rotate(-3deg)}
  58%,92%{transform:translateY(0) rotate(-4deg)}
  95%{transform:translateY(0) rotate(-4deg);opacity:0}
  100%{transform:translateY(-44px) rotate(0);opacity:0}}
@keyframes aPhyStackB{0%{transform:translateY(-44px) rotate(0);opacity:0}
  6%{transform:translateY(-44px) rotate(0);opacity:1}
  44%{transform:translateY(0) rotate(5deg)}
  50%{transform:translateY(-4px) rotate(2deg)}
  58%,92%{transform:translateY(0) rotate(3deg)}
  95%{transform:translateY(0) rotate(3deg);opacity:0}
  100%{transform:translateY(-44px) rotate(0);opacity:0}}

