/* ============================================================
   Motionary, demos G
   Collection AI Interfaces
   ============================================================ */


.sms .lane{display:flex;align-items:center;gap:8px}
.sms .lb{font:600 9px/1 var(--mono);color:var(--ink-3);width:44px;text-align:right;font-style:normal}
.sms .tk{position:relative;display:block;width:76px;height:8px;border-radius:4px;background:var(--s2);overflow:hidden}
.sms .tk b{position:absolute;left:0;top:0;bottom:0;right:0;background:var(--lime);transform-origin:left;display:block}

/* ---------------- streaming et generation ---------------- */
/* Le rythme est INEGAL, et c est le terme. Les huit ticks du haut sont les
   arrivees, a 8, 14, 30, 34, 38, 56, 68 et 80 pour cent, donc des ecarts
   de 6, 16, 4, 4, 18, 12 et 12. Le texte grandit par SAUTS a ces instants
   exactement, jamais entre.
   La version precedente faisait croitre trois lignes regulierement, ce qui
   est precisement le rythme que le reseau n a pas.
   Le bloc du bas est une cloture markdown. Les ticks de 56 et 68 arrivent
   et rien n apparait, parce qu on attend le token de fermeture, et le bloc
   sort d un seul coup a 80. C est la consigne de tamponner une cloture
   non fermee.
   Les ticks se remettent a zero a 92, la boucle revient donc a son point
   de depart.
   Gele, on verrait du texte et un bloc, sans le rythme. */
.tks{position:relative;width:158px;height:104px;display:flex;flex-direction:column;gap:10px}
.tks .trace{position:relative;display:block;height:10px;border-radius:3px;background:var(--s1);
  flex:0 0 auto}
.tks .trace i{position:absolute;top:0;display:block;width:2px;height:10px;border-radius:1px;
  background:var(--s3)}
/* positions proportionnelles aux instants d arrivee, sur 134 */
.tks .k1{left:11px;animation:aTksK1 5s steps(1,end) infinite}
.tks .k2{left:19px;animation:aTksK2 5s steps(1,end) infinite}
.tks .k3{left:40px;animation:aTksK3 5s steps(1,end) infinite}
.tks .k4{left:46px;animation:aTksK4 5s steps(1,end) infinite}
.tks .k5{left:51px;animation:aTksK5 5s steps(1,end) infinite}
.tks .k6{left:75px;animation:aTksK6 5s steps(1,end) infinite}
.tks .k7{left:91px;animation:aTksK7 5s steps(1,end) infinite}
.tks .k8{left:107px;animation:aTksK8 5s steps(1,end) infinite}
.tks .lines{display:flex;flex-direction:column;gap:7px;flex:0 0 auto}
.tks .lines b{display:block;width:0;height:9px;border-radius:5px;background:var(--lime)}
.tks .l1{animation:aTksL1 5s steps(1,end) infinite}
.tks .l2{animation:aTksL2 5s steps(1,end) infinite}
/* la cloture, retenue de 56 a 80 puis sortie d un coup */
.tks .fence{display:flex;flex-direction:column;gap:5px;padding:7px;box-sizing:border-box;
  border-radius:6px;background:var(--s1);opacity:0;animation:aTksFence 5s steps(1,end) infinite}
.tks .fence i{display:block;height:6px;border-radius:3px;background:var(--a2)}
.tks .fence i:last-child{width:58%}
.tks .note{font:600 6px/1 var(--mono);color:var(--ink-3);font-style:normal;letter-spacing:0;
  text-transform:none;margin-top:auto}
@keyframes aTksK1{0%,7%{background:var(--s3)}8%,91%{background:var(--lime)}92%,100%{background:var(--s3)}}
@keyframes aTksK2{0%,13%{background:var(--s3)}14%,91%{background:var(--lime)}92%,100%{background:var(--s3)}}
@keyframes aTksK3{0%,29%{background:var(--s3)}30%,91%{background:var(--lime)}92%,100%{background:var(--s3)}}
@keyframes aTksK4{0%,33%{background:var(--s3)}34%,91%{background:var(--lime)}92%,100%{background:var(--s3)}}
@keyframes aTksK5{0%,37%{background:var(--s3)}38%,91%{background:var(--lime)}92%,100%{background:var(--s3)}}
@keyframes aTksK6{0%,55%{background:var(--s3)}56%,91%{background:var(--a2)}92%,100%{background:var(--s3)}}
@keyframes aTksK7{0%,67%{background:var(--s3)}68%,91%{background:var(--a2)}92%,100%{background:var(--s3)}}
@keyframes aTksK8{0%,79%{background:var(--s3)}80%,91%{background:var(--a2)}92%,100%{background:var(--s3)}}
/* les memes instants, en sauts */
@keyframes aTksL1{0%,7%{width:0}8%,13%{width:12px}14%,29%{width:22px}30%,33%{width:58px}
  34%,37%{width:66px}38%,91%{width:74px}92%,100%{width:0}}
@keyframes aTksL2{0%,29%{width:0}30%,33%{width:18px}34%,37%{width:34px}38%,91%{width:52px}
  92%,100%{width:0}}
/* les tokens arrivent a 56 et 68, le bloc ne sort qu a 80 */
@keyframes aTksFence{0%,79%{opacity:0}80%,91%{opacity:1}92%,100%{opacity:0}}

/* Le TAMPON est l instrument propre a cette fiche, et il explique le
   cout. La piste du haut saute aux instants d arrivee, celle du milieu
   monte a cadence constante, et celle du bas est la difference entre les
   deux, ce qui est exactement le contenu retenu.
   Le brut finit a 80 pour cent, le lisse a 92. Ces douze pour cent sont la
   latence AJOUTEE, et c est le compromis que le terme decrit.
   Le tampon monte a 19 au plus fort, puis se vide a zero a la fin du flux,
   ce que la consigne demande explicitement.
   Gele, on verrait trois barres a des longueurs differentes, sans savoir
   laquelle paie pour l autre. */
.sms{width:158px;height:104px;display:flex;flex-direction:column;gap:14px;justify-content:center}
.sms .jerk{animation:aJerk 5s steps(1,end) infinite}
.sms .even{animation:aEven 5s linear infinite}
.sms .buf{background:var(--a4);animation:aBuf 5s linear infinite}
/* les instants d arrivee, en sauts */
@keyframes aJerk{0%,7%{transform:scaleX(.02)}8%,13%{transform:scaleX(.09)}
  14%,29%{transform:scaleX(.16)}30%,33%{transform:scaleX(.43)}
  34%,37%{transform:scaleX(.49)}38%,55%{transform:scaleX(.55)}
  56%,67%{transform:scaleX(.7)}68%,79%{transform:scaleX(.85)}
  80%,94%{transform:scaleX(1)}100%{transform:scaleX(.02)}}
/* cadence constante, elle finit a 92, douze pour cent apres le brut */
@keyframes aEven{0%,8%{transform:scaleX(.02)}92%,94%{transform:scaleX(1)}
  100%{transform:scaleX(.02)}}
/* la difference entre les deux, et elle se vide a la fin du flux */
@keyframes aBuf{0%,8%{transform:scaleX(.02)}
  14%{transform:scaleX(.09)}30%{transform:scaleX(.17)}38%{transform:scaleX(.19)}
  56%{transform:scaleX(.13)}68%{transform:scaleX(.14)}80%{transform:scaleX(.14)}
  92%,94%{transform:scaleX(.02)}100%{transform:scaleX(.02)}}

/* Il PASSE A LA LIGNE avec le texte, et il est RETIRE a la fin, pas
   fondu. Le curseur suit la fin de la premiere ligne, puis se retrouve au
   debut de la seconde quand le texte y passe, ce qui est le comportement
   d un element au fil du texte et non d un coin fixe.
   A 84 pour cent la generation s arrete et le curseur disparait d un coup.
   Un fondu se lirait comme un caractere de plus qui arrive, et le lecteur
   attendrait pour rien.
   Le clignotement est a 1Hz, en tout ou rien, comme tous les curseurs de
   texte que le lecteur a jamais vus.
   Gele, on verrait deux lignes de texte et peut etre un bloc au bout. */
.gcr{position:relative;width:158px;height:100px;display:flex;flex-direction:column;gap:9px;
  justify-content:center}
.gcr .ln{display:flex;align-items:center;gap:3px;height:15px}
.gcr .tx{display:block;width:0;height:11px;border-radius:5px;background:var(--s4)}
.gcr .l1 .tx{animation:aGcrL1 4.4s steps(1,end) infinite}
.gcr .l2 .tx{animation:aGcrL2 4.4s steps(1,end) infinite}
.gcr .car{display:block;width:7px;height:15px;border-radius:1px;background:var(--lime)}
/* il vit sur la premiere ligne, puis passe sur la seconde, puis disparait */
.gcr .c1{animation:aGcrBlink .9s steps(1,end) infinite,aGcrC1 4.4s steps(1,end) infinite}
.gcr .l2 .car{animation:aGcrBlink .9s steps(1,end) infinite,aGcrC2 4.4s steps(1,end) infinite}
.gcr .note{font:600 6px/1 var(--mono);color:var(--ink-3);font-style:normal;letter-spacing:0;
  text-transform:none}
@keyframes aGcrBlink{0%,49%{opacity:1}50%,100%{opacity:0}}
@keyframes aGcrL1{0%,4%{width:8px}20%{width:52px}36%,88%{width:96px}96%,100%{width:8px}}
@keyframes aGcrL2{0%,38%{width:0}52%{width:34px}68%,88%{width:62px}96%,100%{width:0}}
/* present sur la premiere ligne jusqu a 36, puis plus jamais, et il
   revient au tout dernier pour cent pour la generation suivante */
@keyframes aGcrC1{0%,36%{visibility:visible}38%,97%{visibility:hidden}
  98%,100%{visibility:visible}}
/* present sur la seconde de 38 a 84, RETIRE d un coup a 84 */
@keyframes aGcrC2{0%,37%{visibility:hidden}38%,83%{visibility:visible}
  84%,100%{visibility:hidden}}

/* Le SWAP est la fin du travail, et il n etait pas montre. Le balayage
   passe sur l etiquette d attente jusqu a 58 pour cent, puis il S ARRETE
   et le vrai contenu prend sa place. Il ne porte aucune progression,
   puisqu il n y en a pas a rapporter, et il ne cede pas la place a une
   roue qui tourne mais a du texte.
   Le balayage fait 38 de large et traverse 158, la course vaut donc 196,
   soit de -46 a 150.
   Gele, on verrait soit une etiquette pale soit du texte, mais pas le
   moment ou l attente se termine. */
.tsh{position:relative;width:158px;height:96px;display:grid;place-items:center}
.tsh .ph{position:relative;display:flex;gap:7px;overflow:hidden;padding:5px;
  animation:aTshPh 4.6s steps(1,end) infinite}
.tsh .ph .w{display:block;width:58px;height:12px;border-radius:6px;background:var(--s3)}
.tsh .ph .w.s{width:28px}
.tsh .sheen2{position:absolute;top:0;bottom:0;left:0;display:block;width:38px;
  background:linear-gradient(90deg,transparent,rgba(var(--ink-rgb),.22),transparent);
  animation:aTsh 3.8s linear infinite,aTshStop 4.6s steps(1,end) infinite}
/* le vrai contenu, il prend la place a 58 */
.tsh .real{position:absolute;left:0;right:0;display:flex;flex-direction:column;gap:8px;opacity:0;
  animation:aTshReal 4.6s ease infinite}
.tsh .real b{display:block;height:9px;border-radius:5px;background:var(--lime)}
.tsh .real b.s{width:56%}
/* aller retour, 1.9s par passage, ce qui est la cadence de la consigne et
   ce qui laisse la boucle revenir a son point de depart */
@keyframes aTsh{0%,100%{transform:translateX(-46px)}50%{transform:translateX(150px)}}
/* le balayage s arrete net au premier token */
@keyframes aTshStop{0%,57%{opacity:1}58%,94%{opacity:0}96%,100%{opacity:1}}
@keyframes aTshPh{0%,57%{opacity:1}58%,94%{opacity:0}96%,100%{opacity:1}}
@keyframes aTshReal{0%,58%{opacity:0}70%,94%{opacity:1}96%,100%{opacity:0}}

/* Ce qui SURVIT est toute la question. Le bouton d envoi est REMPLACE par
   stop pendant le flux, a la meme place. A 46 pour cent l appui est
   accuse par un etat intermediaire, avant que le flux s arrete vraiment a
   54, parce que l aller retour reseau est plus lent que les 200ms
   demandes.
   Et surtout, le texte partiel RESTE. Il ne disparait pas, il recoit son
   cadre de modification a 60 pour cent, parce qu arreter est une decision
   et non une annulation.
   La version precedente montrait un anneau avec un dasharray code en dur a
   120 pour un cercle de 119.38 de perimetre. Il n y a plus d anneau.
   Gele, on verrait un message et un bouton, sans savoir ce qui a ete
   garde. */
.stgz{position:relative;width:158px;height:104px;display:flex;flex-direction:column;gap:12px;
  justify-content:center}
.stgz .msg{position:relative;display:flex;flex-direction:column;gap:8px;padding:10px;
  box-sizing:border-box;border-radius:8px;background:var(--s1)}
.stgz .msg b{display:block;height:9px;border-radius:5px;background:var(--s4)}
.stgz .t1{animation:aStgT1 4.8s steps(1,end) infinite}
.stgz .t2{animation:aStgT2 4.8s steps(1,end) infinite}
/* le cadre de modification, le partiel est utilisable */
.stgz .edit{position:absolute;inset:0;display:block;border-radius:8px;box-sizing:border-box;
  border:1.5px solid var(--lime);opacity:0;animation:aStgEdit 4.8s steps(1,end) infinite}
.stgz .ctl{position:relative;display:block;height:26px}
.stgz .ctl i{position:absolute;left:0;top:0;display:grid;place-items:center;width:56px;height:26px;
  border-radius:8px;opacity:0}
/* envoyer, puis stop, puis l accuse de reception, puis envoyer */
.stgz .send{background:var(--lime);animation:aStgSend 4.8s steps(1,end) infinite}
.stgz .stop{background:var(--a4);animation:aStgStop 4.8s steps(1,end) infinite}
.stgz .wait{background:var(--s3);animation:aStgWait 4.8s steps(1,end) infinite}
@keyframes aStgT1{0%,7%{width:0}22%{width:70%}38%,94%{width:100%}96%,100%{width:0}}
@keyframes aStgT2{0%,29%{width:0}46%,94%{width:52%}96%,100%{width:0}}
@keyframes aStgSend{0%,7%{opacity:1}8%,93%{opacity:0}94%,100%{opacity:1}}
@keyframes aStgStop{0%,7%{opacity:0}8%,45%{opacity:1}46%,100%{opacity:0}}
/* l accuse de reception dure de 46 a 54, avant l arret reel */
@keyframes aStgWait{0%,45%{opacity:0}46%,53%{opacity:1}54%,100%{opacity:0}}
@keyframes aStgEdit{0%,59%{opacity:0}60%,94%{opacity:1}96%,100%{opacity:0}}

/* Le RELACHEMENT est toute la conception, et il lui faut une cause. A 52
   pour cent le pointeur remonte, la vue se detache, la puce apparait, et
   ensuite la vue NE BOUGE PLUS alors que le contenu continue d arriver,
   ce qui se voit sur la derniere ligne qui pulse dans le vide.
   Entre 8 et 18 le lecteur redescend de lui meme, la vue se raccroche et
   la puce disparait, parce que l etat est toujours une consequence de la
   position.
   La colonne fait 146 dans une fenetre de 88, la course utile vaut donc
   58. Le suivi va de -40 a -58, le relachement remonte a -20.
   Gele, on verrait un fil et peut etre une puce, sans savoir si la vue
   suit. */
.s2b{position:relative;width:158px;height:104px}
.s2b .vp{position:absolute;left:0;right:0;top:0;height:88px;overflow:hidden;border-radius:9px;
  background:var(--s0)}
.s2b .col2{position:absolute;left:9px;right:9px;top:0;display:flex;flex-direction:column;gap:7px;
  animation:aS2b 5.4s cubic-bezier(.4,0,.4,1) infinite}
.s2b .col2 i{display:block;height:10px;border-radius:5px;background:var(--s3);flex:0 0 auto}
/* la derniere ligne pulse, le contenu arrive toujours */
.s2b .col2 i:last-child{background:var(--lime);animation:aS2bNew 1.1s ease-in-out infinite}
.s2b .jump{position:absolute;left:50%;margin-left:-18px;bottom:2px;display:block;width:36px;
  height:16px;border-radius:8px;background:var(--lime);animation:aS2bJ 5.4s ease infinite}
.s2b .cur{left:112px;top:40px;animation:aS2bCur 5.4s cubic-bezier(.4,0,.4,1) infinite}
/* detache a -20, raccroche a -40 puis suit jusqu a -58, puis relache */
@keyframes aS2b{0%,8%{transform:translateY(-20px)}
  18%{transform:translateY(-40px)}
  52%{transform:translateY(-58px)}
  58%,100%{transform:translateY(-20px)}}
@keyframes aS2bNew{0%,100%{opacity:.55}50%{opacity:1}}
/* la puce vit quand la vue est detachee */
@keyframes aS2bJ{0%,16%{opacity:1;transform:translateY(0)}
  20%,50%{opacity:0;transform:translateY(8px)}
  58%,100%{opacity:1;transform:translateY(0)}}
/* il redescend a 10, il remonte a 52, c est lui la cause */
@keyframes aS2bCur{0%,8%{transform:translateY(0);opacity:1}
  16%{transform:translateY(22px);opacity:1}
  22%,46%{transform:translateY(22px);opacity:0}
  50%{transform:translateY(22px);opacity:1}
  56%{transform:translateY(-6px);opacity:1}
  62%,100%{transform:translateY(0);opacity:1}}


/* La definition nomme DEUX sorties, Tab qui accepte et la frappe qui
   ecarte, la scene doit donc en montrer deux. Elle les montre dans cet
   ordre, apparition, frappe, apparition, Tab.
   La preuve que le fantome n est PAS dans le document est arithmetique. A
   40 pour cent l utilisateur continue de taper, le fantome disparait et le
   texte reel passe de 34 a 42, soit UN caractere de 8. Il ne passe pas a
   34 plus 40 plus 8. Rien n a ete insere, il n y a rien a annuler.
   La preuve des metriques identiques est qu a 76 pour cent Tab ne change
   QUE l opacite, de 0,45 a 1. Aucune largeur, aucune position ne bouge, le
   texte accepte tombe exactement ou le fantome etait.
   Le caret est place AVANT le fantome, parce que le point d insertion est
   la et que la suggestion est dessinee apres lui.
   Gele, un fantome et un texte reel se ressemblent trop pour qu on sache
   lequel est dans le document. */
.gtx{display:flex;flex-direction:column;gap:10px;width:124px}
.gtx .row{display:flex;align-items:center;gap:0}
.gtx .real{display:block;height:11px;border-radius:3px;background:var(--ink-3);width:34px;
  animation:aGtxR 6s steps(1,end) infinite}
.gtx .car{display:block;width:2px;height:13px;margin:0 1px;border-radius:1px;background:var(--a2);
  flex:0 0 auto}
/* le fantome, meme hauteur et meme rythme que le texte reel */
.gtx .gh{display:block;height:11px;border-radius:3px;background:var(--ink-3);width:0;opacity:.45;
  animation:aGtxG 6s steps(1,end) infinite,aGtxO 6s steps(1,end) infinite}
.gtx .keys{display:flex;gap:6px}
.gtx .keys em{display:block;padding:2px 5px;border-radius:4px;background:var(--s2);
  font:700 6px/8px var(--mono);color:var(--ink-2);font-style:normal;letter-spacing:0;
  text-transform:none;opacity:.25}
.gtx .k1{animation:aGtxK1 6s steps(1,end) infinite}
.gtx .k2{animation:aGtxK2 6s steps(1,end) infinite}
/* 34 puis 42, un seul caractere de 8 ajoute */
@keyframes aGtxR{0%,11%{width:34px}40%,95%{width:42px}97%,100%{width:34px}}
@keyframes aGtxG{0%,11%{width:0}12%,39%{width:40px}40%,59%{width:0}60%,95%{width:40px}
  97%,100%{width:0}}
/* Tab ne touche QUE l opacite, la geometrie ne bouge pas d un pixel */
@keyframes aGtxO{0%,75%{opacity:.45}76%,95%{opacity:1}97%,100%{opacity:.45}}
@keyframes aGtxK1{0%,59%{opacity:.25}60%,80%{opacity:1}81%,100%{opacity:.25}}
@keyframes aGtxK2{0%,11%{opacity:.25}12%,44%{opacity:1}45%,100%{opacity:.25}}

/* La consigne interdit height auto et demande une valeur en pixels mesuree.
   Les deux panneaux ont les MEMES etapes, 0 puis 34 puis 14, mais celui de
   gauche interpole et celui de droite est en steps 1, ce qui est exactement
   ce que fait auto, aucune valeur intermediaire n existe. Le panneau de
   droite s ouvre donc en une image.
   Le repli est AUTOMATIQUE et il est cause par la reponse. La barre de
   reponse part a 62, le repli commence a 63, la cause precede l effet.
   Trois lignes de 6 et deux ecarts de 4 font 26, plus 8 de padding, soit 34
   ouvert. Replie, une ligne de 6 plus 8 de padding, soit 14.
   Gele, on ne verrait pas la difference entre les deux, et c est bien le
   probleme, auto ne se voit qu en mouvement. */
.rtr{display:grid;grid-template-columns:52px 52px;gap:8px;width:112px}
.rtr .one{display:flex;flex-direction:column;gap:4px}
.rtr em{font:600 6px/7px var(--mono);font-style:normal;letter-spacing:0;text-transform:none}
.rtr .px em{color:var(--lime)}
.rtr .au em{color:var(--a4)}
.rtr .pan{display:flex;flex-direction:column;gap:4px;height:0;overflow:hidden;padding:0 4px;
  border-radius:5px;background:var(--s1);box-sizing:border-box}
/* il interpole, la hauteur passe par toutes les valeurs */
.rtr .px .pan{animation:aRtrP 5s cubic-bezier(.3,0,.2,1) infinite}
/* il saute, comme auto, aucune valeur intermediaire */
.rtr .au .pan{animation:aRtrP 5s steps(1,end) infinite}
.rtr .pan i{display:block;height:6px;border-radius:3px;background:var(--s4);flex:0 0 auto;opacity:0}
.rtr .pan i:nth-child(1){width:44px;animation:aRtrL1 5s ease infinite}
.rtr .pan i:nth-child(2){width:36px;animation:aRtrL2 5s ease infinite}
.rtr .pan i:nth-child(3){width:40px;animation:aRtrL3 5s ease infinite}
.rtr .ans{grid-column:1/-1;display:block;height:7px;border-radius:4px;background:var(--ink-3);width:0;
  animation:aRtrA 5s cubic-bezier(.3,0,.2,1) infinite}
/* 34 ouvert, 14 replie en resume d une ligne */
@keyframes aRtrP{0%,10%{height:0;padding-top:0;padding-bottom:0}
  22%,62%{height:34px;padding-top:4px;padding-bottom:4px}
  63%,94%{height:14px;padding-top:4px;padding-bottom:4px}
  96%,100%{height:0;padding-top:0;padding-bottom:0}}
@keyframes aRtrL1{0%,24%{opacity:0}28%,94%{opacity:1}96%,100%{opacity:0}}
@keyframes aRtrL2{0%,36%{opacity:0}40%,94%{opacity:1}96%,100%{opacity:0}}
@keyframes aRtrL3{0%,48%{opacity:0}52%,94%{opacity:1}96%,100%{opacity:0}}
/* la reponse part a 62, le repli suit a 63 */
@keyframes aRtrA{0%,61%{width:0}80%,94%{width:100px}96%,100%{width:0}}

/* La consigne dit de ne changer les mots que sur un VRAI changement d etat,
   jamais sur une minuterie. La preuve est geometrique.
   La frise du haut donne les trois phases avec leur DUREE reelle, 16 puis
   46 puis 24 points, d ou des largeurs de 15, 44 et 23 sur 86. La rangee du
   haut change de mot exactement aux frontieres, en 16 et en 62.
   Les traits du bas sont une minuterie reguliere, tous les 28 points, donc
   en 0, 28 et 56. La rangee du bas les suit. Elle est donc EN RETARD de 12
   pixels a la premiere frontiere, et EN AVANCE de 6 a la seconde. Elle dit
   Reading quand le systeme cherche deja, puis Writing quand il cherche
   encore. Une minuterie n a aucun rapport avec la verite.
   Les mots sont empiles au meme endroit et se fondent, la rangee ne
   glisse jamais, ce que la consigne demande aussi.
   Gele, il n y aurait qu un mot et aucune phase. */
.snr{display:flex;flex-direction:column;gap:5px;width:96px}
.snr .ph{display:flex;gap:2px}
.snr .ph i{display:block;height:6px;border-radius:3px;background:var(--lime);opacity:.2}
/* la largeur EST la duree de la phase */
.snr .p1{width:15px;animation:aSnrP1 5s steps(1,end) infinite}
.snr .p2{width:44px;animation:aSnrP2 5s steps(1,end) infinite}
.snr .p3{width:23px;animation:aSnrP3 5s steps(1,end) infinite}
.snr .one{position:relative;display:block;width:96px;height:10px;margin-top:3px}
.snr .one em{position:absolute;left:0;top:0;font:700 8px/10px var(--mono);font-style:normal;
  letter-spacing:0;text-transform:none;opacity:0;white-space:nowrap}
.snr .ok em{color:var(--lime)}
.snr .ko em{color:var(--a4)}
.snr .w1{animation:aSnrW1 5s ease infinite}
.snr .w2{animation:aSnrW2 5s ease infinite}
.snr .w3{animation:aSnrW3 5s ease infinite}
.snr .v1{animation:aSnrV1 5s ease infinite}
.snr .v2{animation:aSnrV2 5s ease infinite}
.snr .v3{animation:aSnrV3 5s ease infinite}
/* la minuterie, fixe par construction, elle ne doit pas bouger */
.snr .ticks{position:relative;display:block;width:86px;height:5px;margin-top:4px}
.snr .ticks i{position:absolute;top:0;display:block;width:1.5px;height:5px;background:var(--a4)}
.snr .ticks i:nth-child(1){left:0}
.snr .ticks i:nth-child(2){left:28px}
.snr .ticks i:nth-child(3){left:56px}
@keyframes aSnrP1{0%,5%{opacity:.2}6%,21%{opacity:1}22%,100%{opacity:.2}}
@keyframes aSnrP2{0%,21%{opacity:.2}22%,67%{opacity:1}68%,100%{opacity:.2}}
@keyframes aSnrP3{0%,67%{opacity:.2}68%,91%{opacity:1}92%,100%{opacity:.2}}
/* fondu enchaine sur place, aux vraies frontieres */
@keyframes aSnrW1{0%,5%{opacity:0}9%,19%{opacity:1}23%,100%{opacity:0}}
@keyframes aSnrW2{0%,21%{opacity:0}25%,65%{opacity:1}69%,100%{opacity:0}}
@keyframes aSnrW3{0%,67%{opacity:0}71%,90%{opacity:1}94%,100%{opacity:0}}
/* fondu enchaine sur place, mais aux instants d une minuterie */
@keyframes aSnrV1{0%,5%{opacity:0}9%,31%{opacity:1}35%,100%{opacity:0}}
@keyframes aSnrV2{0%,33%{opacity:0}37%,59%{opacity:1}63%,100%{opacity:0}}
@keyframes aSnrV3{0%,61%{opacity:0}65%,90%{opacity:1}94%,100%{opacity:0}}

/* Deux consignes se demontrent ici. La puce se STABILISE en marque de
   succes ou d erreur, et elle RESTE dans la transcription.
   La premiere puce reussit a 34, la seconde echoue a 58, ce sont deux
   sorties distinctes et il en faut deux. L anneau qui respire dit l etat en
   cours, et il s eteint exactement a l instant ou la marque apparait, ce
   qui montre que la marque REMPLACE l etat en cours.
   La troisieme rangee est une notification passagere, en pointille. Elle
   disparait a 46 et ne laisse aucune trace. A 70 la reponse arrive, les
   deux puces sont toujours la et la notification n est plus consultable.
   C est la seule facon de montrer ce que la persistance achete.
   L anneau porte deux animations qui ne se croisent pas, l une sur le
   scale, l autre sur l opacite.
   Gele, on ne saurait pas si l outil tourne encore ou s il a fini. */
.tcc{display:flex;flex-direction:column;gap:6px;width:104px}
.tcc .chp{position:relative;display:flex;align-items:center;gap:5px;padding:4px 5px;
  border-radius:6px;background:var(--s1);box-sizing:border-box;width:104px;opacity:0}
.tcc .c1{animation:aTccC1 5s cubic-bezier(.2,1,.3,1) infinite}
.tcc .c2{animation:aTccC2 5s cubic-bezier(.2,1,.3,1) infinite}
/* passagere, elle ne laisse aucune trace */
.tcc .tst{background:none;border:1px dashed var(--line-2);animation:aTccT 5s ease infinite}
.tcc .ic{display:block;width:9px;height:9px;border-radius:3px;background:var(--s4);flex:0 0 auto}
.tcc .run{position:absolute;left:4px;top:3px;display:block;width:11px;height:11px;border-radius:6px;
  box-sizing:border-box;border:1.5px solid var(--a2);opacity:0}
.tcc .c1 .run{animation:aTccRing .8s ease-in-out infinite,aTccW1 5s steps(1,end) infinite}
.tcc .c2 .run{animation:aTccRing .8s ease-in-out infinite,aTccW2 5s steps(1,end) infinite}
.tcc em{font:600 6px/9px var(--mono);color:var(--ink-2);font-style:normal;letter-spacing:0;
  text-transform:none;flex:1 1 auto}
.tcc .mk{display:block;width:9px;height:9px;flex:0 0 auto;opacity:0}
/* succes, un bloc plein. erreur, une barre en biais. Forme ET couleur. */
.tcc .c1 .mk{border-radius:3px;background:var(--lime);animation:aTccMk1 5s cubic-bezier(.2,1.4,.3,1) infinite}
.tcc .c2 .mk{border-radius:1px;background:var(--a4);height:2px;margin:3.5px 0;
  animation:aTccMk2 5s cubic-bezier(.2,1.4,.3,1) infinite}
.tcc .ans{display:block;height:7px;border-radius:4px;background:var(--ink-3);width:0;margin-top:3px;
  animation:aTccA 5s cubic-bezier(.3,0,.2,1) infinite}
@keyframes aTccC1{0%,9%{opacity:0;transform:translateY(4px)}14%,94%{opacity:1;transform:translateY(0)}
  96%,100%{opacity:0;transform:translateY(4px)}}
@keyframes aTccC2{0%,29%{opacity:0;transform:translateY(4px)}34%,94%{opacity:1;transform:translateY(0)}
  96%,100%{opacity:0;transform:translateY(4px)}}
@keyframes aTccT{0%,19%{opacity:0}22%,44%{opacity:1}46%,100%{opacity:0}}
/* il respire, il ne balaie pas, les deux bouts sont identiques */
@keyframes aTccRing{0%,100%{transform:scale(.62)}55%{transform:scale(1.35)}}
/* il s eteint a l instant ou la marque arrive */
@keyframes aTccW1{0%,9%{opacity:0}10%,33%{opacity:1}34%,100%{opacity:0}}
@keyframes aTccW2{0%,29%{opacity:0}30%,57%{opacity:1}58%,100%{opacity:0}}
@keyframes aTccMk1{0%,33%{opacity:0;transform:scale(.4)}40%,94%{opacity:1;transform:scale(1)}
  96%,100%{opacity:0;transform:scale(.4)}}
@keyframes aTccMk2{0%,57%{opacity:0;transform:scale(.4) rotate(-45deg)}
  64%,94%{opacity:1;transform:scale(1) rotate(-45deg)}
  96%,100%{opacity:0;transform:scale(.4) rotate(-45deg)}}
@keyframes aTccA{0%,69%{width:0}86%,94%{width:96px}96%,100%{width:0}}

/* La consigne dit d AJOUTER les etapes et de ne jamais les reordonner. La
   colonne de droite fait l erreur courante, elle place la plus recente en
   haut, ce qui pousse toutes les autres vers le bas d un pas de 15 a chaque
   arrivee. Quatre etapes, donc 15 puis 30 puis 45 de descente.
   Le repere lime est FIXE dans les deux colonnes, parce qu il represente ou
   l oeil du lecteur se trouve, et un oeil ne suit pas une ligne qui fuit.
   A gauche il designe encore l etape 1 a la fin. A droite il designe
   l etape 4, que le lecteur n a jamais choisie. Il n a aucune animation,
   c est le voisin inerte qui sert de referentiel.
   La consigne dit aussi qu une SEULE etape est en cours. Les quatre pastilles
   ont trois etats, a venir en creux, en cours en lime, terminee en gris, et
   a chaque instant une seule est lime. La definition nomme ces trois etats,
   la scene en montre trois.
   Gele, on ne verrait pas quelle etape tourne, ni que l ordre a change. */
.ats{display:flex;gap:10px;justify-content:center}
.ats .col{display:flex;flex-direction:column;gap:5px}
.ats em{font:600 6px/7px var(--mono);font-style:normal;letter-spacing:0;text-transform:none;
  padding-left:6px}
.ats .ok em{color:var(--lime)}
.ats .ko em{color:var(--a4)}
.ats .lst{position:relative;display:block;width:62px;height:60px}
.ats .rw{position:absolute;left:6px;display:flex;align-items:center;gap:5px;height:11px;opacity:0}
/* a gauche chaque etape a sa place et n en bouge plus */
.ats .ok .r1{top:0}
.ats .ok .r2{top:15px}
.ats .ok .r3{top:30px}
.ats .ok .r4{top:45px}
/* a droite tout est empile en haut, la plus recente occupe le premier rang */
.ats .ko .rw{top:0}
.ats .ok .r1{animation:aAtsRw1 5s ease infinite}
.ats .ok .r2{animation:aAtsRw2 5s ease infinite}
.ats .ok .r3{animation:aAtsRw3 5s ease infinite}
.ats .ok .r4{animation:aAtsRw4 5s ease infinite}
.ats .ko .r1{animation:aAtsRw1 5s ease infinite,aAtsSh1 5s cubic-bezier(.3,0,.2,1) infinite}
.ats .ko .r2{animation:aAtsRw2 5s ease infinite,aAtsSh2 5s cubic-bezier(.3,0,.2,1) infinite}
.ats .ko .r3{animation:aAtsRw3 5s ease infinite,aAtsSh3 5s cubic-bezier(.3,0,.2,1) infinite}
.ats .ko .r4{animation:aAtsRw4 5s ease infinite}
.ats .d{display:block;width:7px;height:7px;border-radius:4px;box-sizing:border-box;
  border:1.5px solid var(--s4);flex:0 0 auto}
.ats .r1 .d{animation:aAtsD1 5s steps(1,end) infinite}
.ats .r2 .d{animation:aAtsD2 5s steps(1,end) infinite}
.ats .r3 .d{animation:aAtsD3 5s steps(1,end) infinite}
.ats .r4 .d{animation:aAtsD4 5s steps(1,end) infinite}
.ats .t{display:block;height:6px;border-radius:3px;background:var(--s4)}
.ats .r1 .t{width:42px}
.ats .r2 .t{width:36px}
.ats .r3 .t{width:40px}
.ats .r4 .t{width:32px}
/* ou l oeil du lecteur se trouve. Aucune animation, c est le referentiel. */
.ats .mrq{position:absolute;left:0;top:0;display:block;width:3px;height:11px;border-radius:2px;
  background:var(--lime)}
@keyframes aAtsRw1{0%,5%{opacity:0}9%,94%{opacity:1}96%,100%{opacity:0}}
@keyframes aAtsRw2{0%,25%{opacity:0}29%,94%{opacity:1}96%,100%{opacity:0}}
@keyframes aAtsRw3{0%,49%{opacity:0}53%,94%{opacity:1}96%,100%{opacity:0}}
@keyframes aAtsRw4{0%,73%{opacity:0}77%,94%{opacity:1}96%,100%{opacity:0}}
/* chaque arrivee pousse les anciennes d un pas de 15 */
@keyframes aAtsSh1{0%,25%{transform:translateY(0)}30%,49%{transform:translateY(15px)}
  54%,73%{transform:translateY(30px)}78%,94%{transform:translateY(45px)}
  96%,100%{transform:translateY(0)}}
@keyframes aAtsSh2{0%,49%{transform:translateY(0)}54%,73%{transform:translateY(15px)}
  78%,94%{transform:translateY(30px)}96%,100%{transform:translateY(0)}}
@keyframes aAtsSh3{0%,73%{transform:translateY(0)}78%,94%{transform:translateY(15px)}
  96%,100%{transform:translateY(0)}}
/* a venir en creux, en cours en lime, terminee en gris plein */
@keyframes aAtsD1{0%,5%{border-color:var(--s4);background:none}
  6%,25%{border-color:var(--lime);background:var(--lime)}
  26%,94%{border-color:var(--s4);background:var(--s4)}
  96%,100%{border-color:var(--s4);background:none}}
@keyframes aAtsD2{0%,25%{border-color:var(--s4);background:none}
  26%,49%{border-color:var(--lime);background:var(--lime)}
  50%,94%{border-color:var(--s4);background:var(--s4)}
  96%,100%{border-color:var(--s4);background:none}}
@keyframes aAtsD3{0%,49%{border-color:var(--s4);background:none}
  50%,73%{border-color:var(--lime);background:var(--lime)}
  74%,94%{border-color:var(--s4);background:var(--s4)}
  96%,100%{border-color:var(--s4);background:none}}
@keyframes aAtsD4{0%,73%{border-color:var(--s4);background:none}
  74%,90%{border-color:var(--lime);background:var(--lime)}
  91%,94%{border-color:var(--s4);background:var(--s4)}
  96%,100%{border-color:var(--s4);background:none}}

/* La consigne dit d attacher le NUMERO pendant le flux et de resoudre la
   source APRES. La rangee du haut le fait, le numero arrive a 41, a
   l instant ou l affirmation se termine. La carte de source n arrive qu a
   66, et seulement parce que le pointeur a atteint la puce a 62. La cause
   precede l effet.
   La rangee du bas attend la source avant d afficher quoi que ce soit, sa
   puce n arrive qu a 74. La regle du bas mesure ce retard, 74 moins 41
   font 33 points, soit 1,65 seconde sur un cycle de 5, pendant lesquelles
   l affirmation est a l ecran SANS aucune marque de source. Le lecteur l a
   deja lue et il est passe a autre chose.
   La regle fait 100 de large pour 100 points, un point vaut donc un pixel,
   le crochet va de 41 a 74.
   Gele, on ne saurait pas dans quel ordre le numero et la source arrivent,
   et c est tout le sujet. */
.icc{position:relative;display:flex;flex-direction:column;gap:6px;width:104px;padding-top:8px}
.icc .one{display:flex;align-items:center;gap:4px;height:11px}
.icc .cl{display:block;height:7px;border-radius:4px;background:var(--ink-3);width:0;
  animation:aIccCl 5s cubic-bezier(.3,0,.2,1) infinite}
.icc .num{display:block;width:11px;height:11px;border-radius:3px;background:var(--a2);
  font:700 6px/11px var(--mono);color:var(--s0);text-align:center;flex:0 0 auto;opacity:0;
  font-style:normal;letter-spacing:0;text-transform:none}
.icc .ok .num{animation:aIccN1 5s cubic-bezier(.2,1.4,.3,1) infinite}
.icc .ko .num{animation:aIccN2 5s cubic-bezier(.2,1.4,.3,1) infinite}
.icc .crd{display:flex;flex-direction:column;gap:4px;width:78px;padding:5px;border-radius:6px;
  background:var(--s1);box-sizing:border-box;opacity:0;animation:aIccCd 5s ease infinite}
.icc .crd i{display:block;height:5px;border-radius:3px;background:var(--s4)}
.icc .ti{width:56px}
.icc .dm{width:34px;background:var(--a2)}
/* la regle mesure le retard, un point vaut un pixel */
.icc .ruler{position:relative;display:block;width:100px;height:8px;margin-top:2px;
  border-top:1px solid var(--line)}
.icc .gap{position:absolute;left:41px;top:2px;display:block;width:33px;height:4px;
  background:var(--a4);opacity:.35}
.icc .t1{position:absolute;left:41px;top:0;display:block;width:1.5px;height:8px;background:var(--lime)}
.icc .t2{position:absolute;left:74px;top:0;display:block;width:1.5px;height:8px;background:var(--a4)}
/* la puce commence a 70 plus 4, son centre est donc a 79,5 et 13,5. Le
   curseur fait 14, son coin doit atteindre 72,5 et 6,5. */
.icc .cur{left:88px;top:54px;animation:aIccCur 5s cubic-bezier(.3,0,.2,1) infinite}
@keyframes aIccCl{0%,7%{width:0}40%,94%{width:70px}96%,100%{width:0}}
/* le numero part avec l affirmation, sans attendre la source */
@keyframes aIccN1{0%,40%{opacity:0;transform:scale(.5)}45%,94%{opacity:1;transform:scale(1)}
  96%,100%{opacity:0;transform:scale(.5)}}
/* il attend la source, il arrive 33 points trop tard */
@keyframes aIccN2{0%,73%{opacity:0;transform:scale(.5)}78%,94%{opacity:1;transform:scale(1)}
  96%,100%{opacity:0;transform:scale(.5)}}
@keyframes aIccCd{0%,65%{opacity:0}70%,94%{opacity:1}96%,100%{opacity:0}}
/* il atteint la puce a 62, la carte ouvre a 66 */
@keyframes aIccCur{0%,48%{transform:translate(0,0)}62%,88%{transform:translate(-15px,-47px)}
  96%,100%{transform:translate(0,0)}}

/* La consigne dit TROIS bandes au maximum, en langage clair, a COTE de
   l affirmation, et une bande basse appariee a une action de verification.
   Les trois etiquettes sont donc des mots, pas une jauge, et elles ne
   bougent plus une fois posees. Seule la ligne basse fait pousser une
   action, a 80, et c est la seule chose que la bande basse declenche.
   Le pied de page est ce que le terme REMPLACE. Il donne 87,3 puis 86,9
   puis 87,4 pour cent. Le nombre change trois fois sans qu aucune
   affirmation ait change, il bouge donc sans informer. Une precision
   fausse est instable par nature, et c est ce qu on voit.
   Trois rangees de 11 et deux ecarts de 7 font 47, plus 9 et 9, soit 65.
   Gele, on garderait les trois bandes, ce qui est normal, elles sont un
   etat et non un mouvement. Ce qu on perdrait c est l instabilite du
   pourcentage, la seule chose ici qui doive bouger pour se denoncer. */
.cfb{display:flex;flex-direction:column;gap:7px;width:112px}
.cfb .rw{display:flex;align-items:center;gap:5px;height:11px}
.cfb .cl{display:block;height:7px;border-radius:4px;background:var(--ink-3);width:0}
.cfb .r1 .cl{animation:aCfbC1 5s cubic-bezier(.3,0,.2,1) infinite}
.cfb .r2 .cl{animation:aCfbC2 5s cubic-bezier(.3,0,.2,1) infinite}
.cfb .r3 .cl{animation:aCfbC3 5s cubic-bezier(.3,0,.2,1) infinite}
.cfb .bd{display:block;padding:2px 4px;border-radius:4px;font:700 6px/7px var(--mono);
  font-style:normal;letter-spacing:0;text-transform:none;flex:0 0 auto;opacity:0}
.cfb .hi{background:var(--lime);color:var(--s0);animation:aCfbB1 5s ease infinite}
.cfb .mx{background:var(--a2);color:var(--s0);animation:aCfbB2 5s ease infinite}
.cfb .lo{background:var(--a4);color:var(--s0);animation:aCfbB3 5s ease infinite}
/* la bande basse est la seule a faire pousser une action */
.cfb .vf{display:block;width:0;height:11px;border-radius:4px;background:none;box-sizing:border-box;
  border:0 solid var(--a4);flex:0 0 auto;overflow:hidden;
  animation:aCfbV 5s cubic-bezier(.2,1,.3,1) infinite}
.cfb .ftr{position:relative;display:block;height:9px;margin-top:2px}
.cfb .ftr em{position:absolute;left:0;top:0;font:700 7px/9px var(--mono);color:var(--s4);
  font-style:normal;letter-spacing:0;text-transform:none;opacity:0}
.cfb .p1{animation:aCfbP1 5s ease infinite}
.cfb .p2{animation:aCfbP2 5s ease infinite}
.cfb .p3{animation:aCfbP3 5s ease infinite}
@keyframes aCfbC1{0%,5%{width:0}30%,94%{width:52px}96%,100%{width:0}}
@keyframes aCfbC2{0%,29%{width:0}52%,94%{width:44px}96%,100%{width:0}}
@keyframes aCfbC3{0%,51%{width:0}74%,94%{width:48px}96%,100%{width:0}}
@keyframes aCfbB1{0%,31%{opacity:0}35%,94%{opacity:1}96%,100%{opacity:0}}
@keyframes aCfbB2{0%,53%{opacity:0}57%,94%{opacity:1}96%,100%{opacity:0}}
@keyframes aCfbB3{0%,75%{opacity:0}79%,94%{opacity:1}96%,100%{opacity:0}}
/* la bordure part de zero aussi, sinon un liseré de 2 resterait visible
   avant que l action n existe */
@keyframes aCfbV{0%,79%{width:0;border-width:0}86%,94%{width:22px;border-width:1px}
  96%,100%{width:0;border-width:0}}
/* trois valeurs pour une seule realite, la precision fausse est instable */
@keyframes aCfbP1{0%,4%{opacity:0}8%,18%{opacity:1}22%,100%{opacity:0}}
@keyframes aCfbP2{0%,20%{opacity:0}24%,42%{opacity:1}46%,100%{opacity:0}}
@keyframes aCfbP3{0%,44%{opacity:0}48%,92%{opacity:1}96%,100%{opacity:0}}

/* La consigne interdit d animer les chiffres par jeton et impose deux mises
   a jour par seconde au maximum. L ancienne scene faisait defiler un
   rouleau de chiffres, soit exactement le piege.
   Les deux jauges arrivent a la MEME valeur finale, 84. Ce qui differe est
   la CADENCE des mises a jour, et elle se lit sur les deux regles.
   En haut, huit relevés reguliers, tous les 12,5 points, donc a 0 12 23 35
   46 58 69 et 81 pixels sur 92. En bas, une mise a jour par jeton, aux
   instants reels du reseau, 8 14 30 34 38 56 68 et 80, donc a 7 13 28 31
   35 52 63 et 74. Les trois traits 28 31 35 sont a 3 pixels l un de
   l autre, c est trois repeints en 160 millisecondes, illisible.
   Le seuil est DECLARE a 64, soit 70 pour cent de 92. La couleur change a
   l instant exact du franchissement et pas avant, jamais en degrade. La
   jauge du haut franchit a son sixieme releve, en 62,5 pour cent, celle du
   bas a son sixieme jeton, en 56. Chacune bascule a son propre
   franchissement, ce qui est le seul comportement honnete.
   Les valeurs viennent des jetons cumules 12 22 58 66 74 104 118 130,
   ramenes a 84 pixels, soit 8 14 38 43 48 67 76 et 84.
   La tete de lecture relie chaque trait a la marche correspondante. Elle
   est a opacite nulle aux deux bouts, elle ne se rembobine donc pas a vue.
   Gele, les deux jauges seraient identiques. */
.rmt{position:relative;display:flex;flex-direction:column;gap:4px;width:128px}
.rmt .one{display:flex;align-items:center;gap:6px}
.rmt em{font:600 6px/8px var(--mono);font-style:normal;letter-spacing:0;text-transform:none;
  width:30px;flex:0 0 auto}
.rmt .ok em{color:var(--lime)}
.rmt .ko em{color:var(--a4)}
.rmt .tk{position:relative;display:block;width:92px;height:8px;border-radius:4px;background:var(--s2)}
.rmt .bar{display:block;height:8px;border-radius:4px;background:var(--lime);width:0}
.rmt .ok .bar{animation:aRmtG 4s steps(1,end) infinite}
.rmt .ko .bar{animation:aRmtB 4s steps(1,end) infinite}
/* le seuil est declare, il ne bouge pas */
.rmt .thr{position:absolute;left:64px;top:-2px;display:block;width:1.5px;height:12px;
  background:var(--s5)}
.rmt .tr{position:relative;display:block;width:92px;height:6px;margin:0 0 5px 36px}
.rmt .tr i{position:absolute;top:0;display:block;width:1.5px;height:6px;border-radius:1px}
.rmt .ok i{background:var(--lime)}
.rmt .ko i{background:var(--a4)}
.rmt .g1{left:0}
.rmt .g2{left:12px}
.rmt .g3{left:23px}
.rmt .g4{left:35px}
.rmt .g5{left:46px}
.rmt .g6{left:58px}
.rmt .g7{left:69px}
.rmt .g8{left:81px}
.rmt .b1{left:7px}
.rmt .b2{left:13px}
.rmt .b3{left:28px}
.rmt .b4{left:31px}
.rmt .b5{left:35px}
.rmt .b6{left:52px}
.rmt .b7{left:63px}
.rmt .b8{left:74px}
.rmt .ph{position:absolute;left:36px;top:0;bottom:5px;display:block;width:1.5px;background:var(--a2);
  opacity:0;animation:aRmtPh 4s linear infinite}
/* huit relevés reguliers, la couleur bascule au sixieme, en 62,5 */
@keyframes aRmtG{0%{width:0;background:var(--lime)}
  12.5%{width:8px}25%{width:14px}37.5%{width:43px}50%{width:48px}
  62.5%{width:67px;background:var(--a4)}75%{width:76px;background:var(--a4)}
  87.5%,95%{width:84px;background:var(--a4)}
  97%,100%{width:0;background:var(--lime)}}
/* une mise a jour par jeton, la couleur bascule au sixieme, en 56 */
@keyframes aRmtB{0%{width:0;background:var(--lime)}
  8%{width:8px}14%{width:14px}30%{width:38px}34%{width:43px}38%{width:48px}
  56%{width:67px;background:var(--a4)}68%{width:76px;background:var(--a4)}
  80%,95%{width:84px;background:var(--a4)}
  97%,100%{width:0;background:var(--lime)}}
/* opacite nulle aux deux bouts, le retour a zero ne se voit pas */
@keyframes aRmtPh{0%{transform:translateX(0);opacity:0}3%{opacity:1}
  93%{opacity:1}100%{transform:translateX(92px);opacity:0}}


/* ---------------- controle agentique ---------------- */
/* La consigne dit trois choses et la scene precedente en ratait deux. Les
   boutons faisaient 34 et 46, alors que la consigne exige un POIDS EGAL, et
   il n y en avait que deux quand la definition en nomme trois, valider,
   modifier, refuser.
   Les trois font donc 30, et 3 fois 30 plus 2 fois 6 font 102. La carte
   fait donc 120, parce que 120 moins 16 de padding moins 2 de bordure
   donnent exactement ces 102 utiles. A 118 les boutons debordaient.
   La preuve la plus forte est le compte a rebours. Il se vide entierement a
   60 pour cent, et ENSUITE RIEN NE SE PASSE. La carte reste bloquee de 60 a
   78, dix huit points pendant lesquels un delai expire ne vaut pas un
   accord. C est la seule facon de montrer une regle qui dit de ne pas faire
   quelque chose.
   A 78 le pointeur choisit le bouton du MILIEU, modifier, et non le
   dernier. La carte nomme aussi le verbe et l objet separement, et se
   declare reversible.
   Gele, on ne verrait pas que le delai expire sans consequence. */
.apc{position:relative;width:128px;height:92px;display:grid;place-items:center}
.apc .crd{display:flex;flex-direction:column;gap:6px;width:120px;padding:8px;border-radius:10px;
  background:var(--s1);border:1px solid var(--line-2);box-sizing:border-box;
  animation:aApcIn 5.5s cubic-bezier(.2,1,.3,1) infinite}
.apc .hd{display:flex;align-items:center;gap:5px;height:8px}
/* le verbe et l objet, deux choses nommees separement */
.apc .verb{display:block;width:30px;height:8px;border-radius:3px;background:var(--ink-3)}
.apc .obj{display:block;width:58px;height:8px;border-radius:3px;background:var(--a2)}
.apc .rev{display:block;font:600 6px/8px var(--mono);color:var(--lime);font-style:normal;
  letter-spacing:0;text-transform:none}
.apc .btns{display:flex;gap:6px}
/* poids egal, 30 chacun, 3 fois 30 plus 2 fois 6 font 102 */
.apc .b{display:block;width:30px;height:16px;border-radius:5px;background:var(--s3);flex:0 0 auto}
.apc .b2{animation:aApcB2 5.5s steps(1,end) infinite}
.apc .to{display:block;width:102px;height:5px;border-radius:3px;background:var(--s2);overflow:hidden}
.apc .to b{display:block;width:102px;height:5px;border-radius:3px;background:var(--a4);
  transform-origin:0 50%;animation:aApcTo 5.5s linear infinite}
/* la carte de 120 est centree dans 128, son bord est donc a 4. Le bouton
   du milieu est a 4 plus 1 plus 8 plus 36, soit 49, son centre a
   64, et la rangee a son centre en 54,5. Le coin du pointeur doit donc
   atteindre 57 et 47,5. */
.apc .cur{left:100px;top:84px;animation:aApcCur 5.5s cubic-bezier(.3,0,.2,1) infinite}
@keyframes aApcIn{0%,5%{opacity:0;transform:translateY(6px)}14%,94%{opacity:1;transform:translateY(0)}
  96%,100%{opacity:0;transform:translateY(6px)}}
/* il se vide a 60 et il ne declenche rien */
@keyframes aApcTo{0%,13%{transform:scaleX(1)}60%,94%{transform:scaleX(0)}97%,100%{transform:scaleX(1)}}
/* modifier, choisi a 78, dix huit points apres l expiration */
@keyframes aApcB2{0%,77%{background:var(--s3)}78%,94%{background:var(--lime)}
  96%,100%{background:var(--s3)}}
@keyframes aApcCur{0%,64%{transform:translate(0,0)}78%,92%{transform:translate(-43px,-36px)}
  96%,100%{transform:translate(0,0)}}

/* La consigne demande que la POSITION DE LECTURE reste stable quand un bloc
   se resout, et c est la seule des trois consignes qui ne se voit qu en
   mouvement.
   Les lignes font 7 avec 4 d ecart, le pas vaut donc 11. A 46 pour cent la
   ligne supprimee tombe a hauteur nulle et sa marge avec, le contenu perd
   donc 11.
   A gauche la colonne descend de 11 pour compenser, la quatrieme ligne
   reste sous le guide. A droite il n y a pas de compensation, elle remonte
   de 11 et quitte le guide. Le guide est une reference d ECRAN, il ne bouge
   jamais, c est le voisin inerte.
   Le diff est en place, l ajout et la suppression sont dans la colonne et
   non dans un panneau separe. Les deux commandes du bloc disparaissent
   quand il est resolu.
   Gele, les deux colonnes seraient identiques. */
.sdf{display:flex;flex-direction:column;gap:8px;width:124px}
.sdf .one{display:flex;align-items:flex-start;gap:8px}
.sdf em{font:600 6px/7px var(--mono);font-style:normal;letter-spacing:0;text-transform:none;
  width:26px;flex:0 0 auto;padding-top:2px}
.sdf .ok em{color:var(--lime)}
.sdf .ko em{color:var(--a4)}
.sdf .vp{position:relative;display:block;width:82px;height:40px;overflow:hidden;flex:0 0 auto}
.sdf .col{position:absolute;left:0;top:0;display:flex;flex-direction:column;gap:4px;width:82px}
/* elle descend de 11 pour garder la ligne de lecture en place */
.sdf .ok .col{animation:aSdfComp 5s cubic-bezier(.3,0,.2,1) infinite}
.sdf .ln{display:block;width:100%;height:7px;border-radius:3px;background:var(--s3);flex:0 0 auto}
.sdf .add{background:var(--lime);width:70px}
/* la ligne supprimee, hauteur ET marge partent vers zero */
.sdf .del{background:var(--a4);width:58px;animation:aSdfDel 5s cubic-bezier(.3,0,.2,1) infinite}
/* reference d ecran, aucune animation */
.sdf .guide{position:absolute;left:0;right:0;top:37px;display:block;height:1.5px;
  background:var(--a2)}
.sdf .hk{display:flex;gap:5px;padding-left:34px}
.sdf .hk i{display:block;width:10px;height:10px;border-radius:3px}
.sdf .hk .y{background:var(--lime);animation:aSdfHk 5s steps(1,end) infinite}
.sdf .hk .n{background:var(--a4);animation:aSdfHk 5s steps(1,end) infinite}
/* 11 de moins, un pas de ligne entier */
@keyframes aSdfDel{0%,45%{height:7px;margin-bottom:0}
  52%,94%{height:0;margin-bottom:-4px}96%,100%{height:7px;margin-bottom:0}}
@keyframes aSdfComp{0%,45%{transform:translateY(0)}52%,94%{transform:translateY(11px)}
  96%,100%{transform:translateY(0)}}
/* les commandes du bloc disparaissent quand il est resolu */
@keyframes aSdfHk{0%,45%{opacity:1}46%,94%{opacity:0}96%,100%{opacity:1}}

/* La definition nomme TROIS sorties, une fois, toujours, refuser, et la
   scene precedente n en montrait que deux. Elles font 30 chacune, 3 fois 30
   plus 2 fois 6 donnent les 102 utiles du dialogue.
   La consigne exige aussi que toujours autoriser soit REVOCABLE depuis un
   endroit visible. C est ce qui separe ce terme de la carte de validation,
   qui decide UNE action et n a rien a revoquer. La bande du bas apparait
   donc a 58, apres le choix, et elle RESTE. Sans elle, toujours autoriser
   serait une porte sans serrure.
   Le dialogue nomme l outil et sa cible sur deux lignes distinctes, parce
   que la consigne demande les deux.
   La page derriere est assombrie tant que le dialogue est la, et elle
   s eclaircit a 52. La demande est bloquante, pas une notification.
   Le dialogue fait 120 et non 110, parce que 120 moins 16 de padding moins
   2 de bordure donnent les 102 utiles des trois boutons.
   Le bouton du milieu est a 3 plus 1 plus 8 plus 36, soit 48, son centre a
   63, et la rangee a son centre en 47. Le coin du pointeur doit atteindre
   56 et 40.
   Gele, on ne saurait pas que toujours autoriser laisse une trace. */
.tpp{position:relative;width:126px;height:92px}
.tpp .pg{position:absolute;left:0;right:0;top:6px;display:flex;flex-direction:column;gap:6px;
  animation:aTppPg 5.5s ease infinite}
.tpp .pg i{display:block;height:7px;border-radius:3px;background:var(--s3)}
.tpp .pg i:nth-child(1){width:112px}
.tpp .pg i:nth-child(2){width:88px}
.tpp .pg i:nth-child(3){width:100px}
.tpp .dlg{position:absolute;left:3px;top:8px;display:flex;flex-direction:column;gap:5px;width:120px;
  padding:8px;border-radius:10px;background:var(--s1);border:1px solid var(--line-2);
  box-sizing:border-box;animation:aTppDlg 5.5s cubic-bezier(.2,1,.3,1) infinite}
/* l outil et sa cible, deux lignes distinctes */
.tpp .tool{display:block;width:52px;height:7px;border-radius:3px;background:var(--ink-3)}
.tpp .tgt{display:block;width:80px;height:7px;border-radius:3px;background:var(--a2)}
.tpp .btns{display:flex;gap:6px;margin-top:3px}
/* poids egal, aucune des trois n est enterree */
.tpp .b{display:block;width:30px;height:16px;border-radius:5px;background:var(--s3);flex:0 0 auto}
.tpp .b2{animation:aTppB2 5.5s steps(1,end) infinite}
/* la revocation, elle n existe qu apres toujours autoriser, et elle reste */
.tpp .set{position:absolute;left:0;right:0;bottom:4px;display:flex;justify-content:flex-end;
  padding:4px 6px;border-radius:7px;background:var(--s2);box-sizing:border-box;opacity:0;
  animation:aTppSet 5.5s cubic-bezier(.2,1,.3,1) infinite}
.tpp .set em{font:700 6px/8px var(--mono);color:var(--a4);font-style:normal;letter-spacing:0;
  text-transform:none}
.tpp .cur{left:104px;top:80px;animation:aTppCur 5.5s cubic-bezier(.3,0,.2,1) infinite}
/* assombrie tant que la demande bloque, eclaircie a 52 */
@keyframes aTppPg{0%,7%{opacity:1}12%,51%{opacity:.28}56%,100%{opacity:1}}
@keyframes aTppDlg{0%,7%{opacity:0;transform:translateY(6px)}
  14%,51%{opacity:1;transform:translateY(0)}56%,100%{opacity:0;transform:translateY(6px)}}
@keyframes aTppB2{0%,47%{background:var(--s3)}48%,51%{background:var(--lime)}
  52%,100%{background:var(--s3)}}
@keyframes aTppSet{0%,57%{opacity:0;transform:translateY(5px)}
  64%,94%{opacity:1;transform:translateY(0)}96%,100%{opacity:0;transform:translateY(5px)}}
@keyframes aTppCur{0%,34%{transform:translate(0,0)}48%,60%{transform:translate(-48px,-40px)}
  74%,100%{transform:translate(0,0)}}

/* Trois consignes, trois preuves.
   Le curseur du bas est le voisin INERTE. Il est fige avec son centre pile
   sur la frontiere entre proposer et confirmer, a 33 moins 4,5 soit 28,5.
   Il ne designe donc AUCUN des deux, et c est exactement ce qu un reglage
   continu vaut ici. Il ne bouge pas parce qu il n a rien a dire.
   La pastille du haut, elle, est toujours sur un nom. Les trois segments
   font 33, ses positions sont donc 0, 33 et 66.
   A 40 et 58 deux echecs sont marques. A 62 la pastille DESCEND d elle meme
   de 66 a 33, soit 33 de course, et le badge passe de execute a confirm. La
   cause precede l effet, deux echecs puis la chute.
   Le badge reste visible pendant toute l execution, ce qui est la deuxieme
   consigne, et il dit toujours le niveau courant.
   Gele, on ne verrait pas que le systeme se retrograde tout seul. */
.aly{display:flex;flex-direction:column;align-items:center;gap:9px}
.aly .sgm{position:relative;display:flex;padding:2px;border-radius:7px;background:var(--s2)}
.aly .sgm b{position:relative;display:block;width:33px;font:700 6px/16px var(--mono);
  color:var(--ink-2);text-align:center;letter-spacing:0;text-transform:none}
/* elle est toujours sur un nom, jamais entre deux */
/* un contour et non un fond, sans quoi le libelle passerait sous le lime */
.aly .pill{position:absolute;left:2px;top:2px;display:block;width:33px;height:16px;border-radius:5px;
  box-sizing:border-box;border:1.5px solid var(--lime);
  animation:aAlyPill 5.5s cubic-bezier(.2,1,.3,1) infinite}
/* reglage continu, fige avec son centre sur la frontiere, il ne nomme rien */
.aly .sl{position:relative;display:block;width:99px;height:5px;border-radius:3px;background:var(--s2)}
.aly .sl .kn{position:absolute;left:28.5px;top:-2px;display:block;width:9px;height:9px;
  border-radius:5px;background:var(--s4)}
.aly .run{position:relative;display:flex;align-items:center;gap:5px;height:9px;width:60px}
.aly .run .d{display:block;width:6px;height:6px;border-radius:4px;background:var(--lime);
  flex:0 0 auto}
.aly .run em{position:absolute;left:11px;top:0;font:700 7px/9px var(--mono);color:var(--lime);
  font-style:normal;letter-spacing:0;text-transform:none;opacity:0}
.aly .lv1{animation:aAlyL1 5.5s ease infinite}
.aly .lv2{animation:aAlyL2 5.5s ease infinite}
.aly .fails{display:flex;gap:8px}
.aly .fails i{display:block;width:9px;height:9px;border-radius:3px;background:var(--a4);opacity:0}
.aly .f1{animation:aAlyF1 5.5s steps(1,end) infinite}
.aly .f2{animation:aAlyF2 5.5s steps(1,end) infinite}
/* 66 puis 33, une course de 33, soit exactement un segment */
@keyframes aAlyPill{0%,61%{transform:translateX(66px)}68%,94%{transform:translateX(33px)}
  96%,100%{transform:translateX(66px)}}
@keyframes aAlyL1{0%,60%{opacity:1}66%,96%{opacity:0}98%,100%{opacity:1}}
@keyframes aAlyL2{0%,61%{opacity:0}67%,94%{opacity:1}97%,100%{opacity:0}}
/* deux echecs, puis la chute */
@keyframes aAlyF1{0%,39%{opacity:0}40%,94%{opacity:1}96%,100%{opacity:0}}
@keyframes aAlyF2{0%,57%{opacity:0}58%,94%{opacity:1}96%,100%{opacity:0}}

/* La consigne dit de REVOQUER et d annuler, et surtout de ne pas se
   contenter de cacher l interface. La rangee du bas fait exactement cette
   faute et c est la seule facon de montrer ce que la regle interdit.
   Quatre appels sont en file. Deux se terminent normalement, a 14 et a 26.
   A 40 le coupe circuit est presse.
   En haut les deux appels restants DISPARAISSENT a 42 et le jeton
   d identification se barre. En bas rien ne change dans la file, et les
   appels 3 et 4 se terminent quand meme, a 54 et a 68, apres l arret. La
   fenetre etait fermee, le travail continuait.
   Le bouton est a une position fixe et present du premier au dernier
   pour cent, parce que la consigne demande qu il soit joignable depuis
   n importe ou. Il ne bouge pas, c est la reference.
   La file fait 4 fois 16 plus 3 fois 4, soit 76.
   Gele, les deux rangees seraient identiques et la faute invisible. */
.ksw{position:relative;display:flex;flex-direction:column;gap:10px;width:132px;padding-bottom:24px}
.ksw .one{display:flex;align-items:center;gap:6px}
.ksw em{font:600 6px/8px var(--mono);font-style:normal;letter-spacing:0;text-transform:none;
  width:22px;flex:0 0 auto}
.ksw .ok em{color:var(--lime)}
.ksw .ko em{color:var(--a4)}
.ksw .q{display:flex;gap:4px}
.ksw .q i{display:block;width:16px;height:12px;border-radius:4px;background:var(--a2);flex:0 0 auto}
/* les deux premiers se terminent normalement, dans les deux rangees */
.ksw .q1{animation:aKswDone1 5.5s steps(1,end) infinite}
.ksw .q2{animation:aKswDone2 5.5s steps(1,end) infinite}
/* en haut ils sont annules a 42, en bas ils se terminent quand meme */
.ksw .ok .q3{animation:aKswCut 5.5s steps(1,end) infinite}
.ksw .ok .q4{animation:aKswCut 5.5s steps(1,end) infinite}
.ksw .ko .q3{animation:aKswDone3 5.5s steps(1,end) infinite}
.ksw .ko .q4{animation:aKswDone4 5.5s steps(1,end) infinite}
.ksw .cred{display:block;width:14px;height:12px;border-radius:3px;
  background:var(--s4);flex:0 0 auto}
/* seul le vrai arret barre le jeton */
.ksw .ok .cred{animation:aKswCred 5.5s steps(1,end) infinite}
/* toujours joignable, position fixe, aucune animation */
.ksw .btn{position:absolute;right:0;bottom:0;display:block;width:22px;height:22px;border-radius:11px;
  background:var(--a4)}
/* le bouton fait 22 et occupe le coin bas droit, son centre est donc a 121
   et 47. Le coin du pointeur doit atteindre 114 et 40. */
.ksw .cur{left:88px;top:66px;animation:aKswCur 5.5s cubic-bezier(.3,0,.2,1) infinite}
@keyframes aKswDone1{0%,13%{background:var(--a2)}14%,94%{background:var(--s3)}
  96%,100%{background:var(--a2)}}
@keyframes aKswDone2{0%,25%{background:var(--a2)}26%,94%{background:var(--s3)}
  96%,100%{background:var(--a2)}}
/* apres l arret, ils se terminent quand meme */
@keyframes aKswDone3{0%,53%{background:var(--a2)}54%,94%{background:var(--s3)}
  96%,100%{background:var(--a2)}}
@keyframes aKswDone4{0%,67%{background:var(--a2)}68%,94%{background:var(--s3)}
  96%,100%{background:var(--a2)}}
/* annules, ils cessent d exister */
@keyframes aKswCut{0%,41%{opacity:1;transform:scale(1)}44%,94%{opacity:0;transform:scale(.5)}
  96%,100%{opacity:1;transform:scale(1)}}
@keyframes aKswCred{0%,41%{background:var(--s4)}42%,94%{background:var(--line)}
  96%,100%{background:var(--s4)}}
@keyframes aKswCur{0%,28%{transform:translate(0,0)}40%,60%{transform:translate(26px,-26px)}
  96%,100%{transform:translate(0,0)}}

/* La consigne dit de creer un point AVANT chaque ecriture, et de restaurer
   le code et la conversation SEPAREMENT. La scene le montre par l ordre et
   par la difference de comportement des trois voies.
   Les quatre points naissent a 4, 20, 36 et 52, et les quatre ecritures a
   8, 24, 40 et 56. Chaque point precede son ecriture de quatre points de
   cycle, la cause avant l effet.
   A 66 le pointeur choisit le deuxieme point. Seule la voie code revient a
   son etat 2, les etats 3 et 4 s eteignent. La voie chat garde ses quatre
   etats, parce qu elle se restaure separement et qu on ne l a pas demandee.
   La voie du bas est en pointille, hors suivi, et elle ne pourrait revenir
   en aucun cas. C est la troisieme consigne, dire ce qui echappe au suivi.
   Les etats font 18 avec 4 d ecart, le pas vaut 22, et la piste 4 fois 22
   moins 4, soit 84. Le deuxieme point est donc a 36 plus 22, soit 58, son
   centre a 62 et 12 avec le padding du haut. Le coin du pointeur doit
   atteindre 55 et 5.
   Gele, on ne verrait ni l ordre ni le fait que les voies sont
   independantes. */
.ckr{position:relative;display:flex;flex-direction:column;gap:6px;width:126px;padding-top:8px}
.ckr .rail{position:relative;display:block;height:8px;margin-left:36px;width:84px}
.ckr .rail i{position:absolute;top:0;display:block;width:8px;height:8px;border-radius:3px;
  background:var(--a2);opacity:0}
/* chaque point nait quatre points de cycle avant son ecriture */
.ckr .k1{left:0;animation:aCkrK1 5.5s ease infinite}
.ckr .k2{left:22px;animation:aCkrK2 5.5s ease infinite}
.ckr .k3{left:44px;animation:aCkrK3 5.5s ease infinite}
.ckr .k4{left:66px;animation:aCkrK4 5.5s ease infinite}
.ckr .lane{display:flex;align-items:center;gap:6px;height:12px}
.ckr em{font:600 6px/8px var(--mono);font-style:normal;letter-spacing:0;text-transform:none;
  width:30px;flex:0 0 auto}
.ckr .code em{color:var(--lime)}
.ckr .chat em{color:var(--a2)}
.ckr .out em{color:var(--s4)}
.ckr .tr{display:flex;gap:4px}
.ckr .tr i{display:block;width:18px;height:12px;border-radius:4px;box-sizing:border-box;
  background:var(--s2);flex:0 0 auto}
/* hors suivi, jamais restaurable, en pointille */
.ckr .out .tr i{background:none;border:1px dashed var(--line-2)}
.ckr .code .s1,.ckr .chat .s1{animation:aCkrS1 5.5s steps(1,end) infinite}
.ckr .code .s2,.ckr .chat .s2{animation:aCkrS2 5.5s steps(1,end) infinite}
/* dans la voie code, les etats 3 et 4 s eteignent au retour */
.ckr .code .s3{animation:aCkrBack3 5.5s steps(1,end) infinite}
.ckr .code .s4{animation:aCkrBack4 5.5s steps(1,end) infinite}
/* dans les autres voies, ils restent, la restauration est separee */
.ckr .chat .s3{animation:aCkrS3 5.5s steps(1,end) infinite}
.ckr .chat .s4{animation:aCkrS4 5.5s steps(1,end) infinite}
/* la voie hors suivi se remplit aussi, le travail a bien eu lieu, mais par
   la couleur de son pointille et non par un fond, et elle ne revient jamais */
.ckr .out .s1{animation:aCkrO1 5.5s steps(1,end) infinite}
.ckr .out .s2{animation:aCkrO2 5.5s steps(1,end) infinite}
.ckr .out .s3{animation:aCkrO3 5.5s steps(1,end) infinite}
.ckr .out .s4{animation:aCkrO4 5.5s steps(1,end) infinite}
.ckr .cur{left:108px;top:78px;animation:aCkrCur 5.5s cubic-bezier(.3,0,.2,1) infinite}
@keyframes aCkrK1{0%,3%{opacity:0}5%,94%{opacity:1}96%,100%{opacity:0}}
@keyframes aCkrK2{0%,19%{opacity:0}21%,94%{opacity:1}96%,100%{opacity:0}}
@keyframes aCkrK3{0%,35%{opacity:0}37%,94%{opacity:1}96%,100%{opacity:0}}
@keyframes aCkrK4{0%,51%{opacity:0}53%,94%{opacity:1}96%,100%{opacity:0}}
@keyframes aCkrS1{0%,7%{background:var(--s2)}8%,94%{background:var(--lime)}
  96%,100%{background:var(--s2)}}
@keyframes aCkrS2{0%,23%{background:var(--s2)}24%,94%{background:var(--lime)}
  96%,100%{background:var(--s2)}}
@keyframes aCkrS3{0%,39%{background:var(--s2)}40%,94%{background:var(--a2)}
  96%,100%{background:var(--s2)}}
@keyframes aCkrS4{0%,55%{background:var(--s2)}56%,94%{background:var(--a2)}
  96%,100%{background:var(--s2)}}
/* ecrits a 40 et 56, defaits a 66 */
@keyframes aCkrBack3{0%,39%{background:var(--s2)}40%,65%{background:var(--lime)}
  66%,100%{background:var(--s2)}}
@keyframes aCkrBack4{0%,55%{background:var(--s2)}56%,65%{background:var(--lime)}
  66%,100%{background:var(--s2)}}
@keyframes aCkrO1{0%,7%{border-color:var(--line-2)}8%,94%{border-color:var(--s4)}
  96%,100%{border-color:var(--line-2)}}
@keyframes aCkrO2{0%,23%{border-color:var(--line-2)}24%,94%{border-color:var(--s4)}
  96%,100%{border-color:var(--line-2)}}
@keyframes aCkrO3{0%,39%{border-color:var(--line-2)}40%,94%{border-color:var(--s4)}
  96%,100%{border-color:var(--line-2)}}
@keyframes aCkrO4{0%,55%{border-color:var(--line-2)}56%,94%{border-color:var(--s4)}
  96%,100%{border-color:var(--line-2)}}
@keyframes aCkrCur{0%,52%{transform:translate(0,0)}66%,90%{transform:translate(-53px,-73px)}
  96%,100%{transform:translate(0,0)}}

/* ---------------- surfaces generees, saisie, presence ---------------- */

/* La consigne dit de RESERVER la boite finale avant le premier jeton. La
   colonne de droite ne la reserve pas, sa fente passe de 0 a 34 a 40 pour
   cent, et le pied de page tombe donc de 34 d un coup. A gauche la fente
   fait 34 depuis le debut et le pied ne bouge JAMAIS d un pixel. C est la
   mesure exacte de ce que la reservation achete.
   Le squelette epouse la grille interne du composant. Ses trois barres sont
   aux memes x et aux memes largeurs que les barres reelles, 12 de large et
   8 d ecart, soit 3 fois 12 plus 2 fois 8, exactement les 52 de la fente.
   Seules les hauteurs changent, uniformes a 20 pour le squelette, 26 14 et
   32 pour le reel, ce qui est la seule chose qu un squelette ne peut pas
   savoir.
   L echange est un FONDU, pas un glissement. Il dure de 40 a 44, soit 4
   points sur un cycle de 4,6 secondes, ce qui vaut 184 millisecondes et
   respecte la limite de 200.
   Gele, la colonne de droite paraitrait normale, son defaut est un
   deplacement. */
.skm{display:flex;gap:10px;justify-content:center}
.skm .one{display:flex;flex-direction:column;align-items:flex-start;gap:6px}
.skm em{font:600 6px/7px var(--mono);font-style:normal;letter-spacing:0;text-transform:none}
.skm .ok em{color:var(--lime)}
.skm .ko em{color:var(--a4)}
/* a gauche la boite est reservee des le depart */
.skm .ok .slot{position:relative;display:block;width:52px;height:34px}
/* a droite elle grandit, et tout ce qui suit descend */
.skm .ko .slot{position:relative;display:block;width:52px;height:0;overflow:hidden;
  animation:aSkmSlot 4.6s cubic-bezier(.3,0,.2,1) infinite}
.skm .sk,.skm .rl{position:absolute;left:0;bottom:0;display:flex;align-items:flex-end;gap:8px;
  height:34px}
.skm .sk i{display:block;width:12px;height:20px;border-radius:3px;background:var(--s3)}
.skm .rl i{display:block;width:12px;border-radius:3px;background:var(--lime)}
.skm .r1{height:26px}
.skm .r2{height:14px}
.skm .r3{height:32px}
/* fondu de 40 a 44, soit 184 millisecondes sur 4,6 secondes */
.skm .sk{animation:aSkmSk 4.6s linear infinite}
.skm .ok .rl{opacity:0;animation:aSkmRl 4.6s linear infinite}
.skm .ft{display:block;width:52px;height:7px;border-radius:4px;background:var(--ink-3)}
@keyframes aSkmSlot{0%,39%{height:0}44%,94%{height:34px}96%,100%{height:0}}
@keyframes aSkmSk{0%,40%{opacity:1}44%,94%{opacity:0}96%,100%{opacity:1}}
@keyframes aSkmRl{0%,40%{opacity:0}44%,94%{opacity:1}96%,100%{opacity:0}}

/* La consigne dit que les puces PASSENT A LA LIGNE et que le champ grandit
   VERS LE HAUT. Le composeur est donc ancre sur le bas, et le retour a la
   ligne est un vrai flex-wrap, pas une mise en scene.
   Les puces font 26 avec 5 d ecart. Le composeur fait 124 moins 12 de
   padding moins 2 de bordure, soit 110 utiles. Trois puces tiennent, 3 fois
   26 plus 2 fois 5 font 88. Une quatrieme demanderait 119, elle passe donc
   a la ligne d elle meme, par flex-wrap et non par une mise en scene.
   Le composeur fait 42 avec une rangee et 59 avec deux, sa hauteur monte
   donc de 17, soit une rangee de 12 plus son ecart de 5. Comme il est ancre
   en bas, c est son BORD DU HAUT qui monte de 36 a 19, et le champ de
   saisie ne bouge pas. Le trait de reference le prouve, il est immobile.
   Chaque puce porte sa propre commande de retrait. A 70 le pointeur retire
   la deuxieme, les autres se recomposent, la quatrieme remonte en premiere
   rangee et le composeur redescend.
   Les deux declencheurs de la consigne sont dans le champ, la barre oblique
   et l arobase.
   Gele, on ne verrait pas de quel cote le champ grandit. */
.ccc{position:relative;display:block;width:124px;height:78px}
/* ancre sur le bas, c est ce qui fait grandir vers le haut */
.ccc .cmp{position:absolute;left:0;right:0;bottom:0;display:flex;flex-direction:column;gap:6px;
  padding:6px;border-radius:9px;background:var(--s1);border:1px solid var(--line-2);
  box-sizing:border-box}
.ccc .chips{display:flex;flex-wrap:wrap;gap:5px}
.ccc .chips i{display:flex;align-items:center;justify-content:flex-end;width:26px;flex:0 0 auto;
  height:12px;padding-right:3px;border-radius:4px;background:var(--s3);box-sizing:border-box}
/* la commande de retrait, une par puce */
.ccc .chips i b{display:block;width:5px;height:5px;border-radius:3px;background:var(--a4)}
.ccc .c1{animation:aCccC1 5.5s cubic-bezier(.2,1,.3,1) infinite}
.ccc .c2{animation:aCccC2 5.5s cubic-bezier(.2,1,.3,1) infinite}
.ccc .c3{animation:aCccC3 5.5s cubic-bezier(.2,1,.3,1) infinite}
.ccc .c4{animation:aCccC4 5.5s cubic-bezier(.2,1,.3,1) infinite}
.ccc .fld{display:flex;align-items:center;gap:5px;height:10px}
.ccc .fld i{display:block;font:700 7px/10px var(--mono);color:var(--a2);font-style:normal;
  letter-spacing:0;text-transform:none}
/* reference immobile, le champ de saisie ne doit jamais la quitter */
.ccc .ref{position:absolute;left:0;right:0;bottom:17px;display:block;height:1.5px;
  background:var(--lime);opacity:.4}
.ccc .cur{left:108px;top:68px;animation:aCccCur 5.5s cubic-bezier(.3,0,.2,1) infinite}
/* largeur ET marge partent de zero, sinon la place resterait prise */
@keyframes aCccC1{0%,9%{width:0;margin-right:-5px;opacity:0}
  14%,94%{width:26px;margin-right:0;opacity:1}96%,100%{width:0;margin-right:-5px;opacity:0}}
@keyframes aCccC2{0%,23%{width:0;margin-right:-5px;opacity:0}
  28%,69%{width:26px;margin-right:0;opacity:1}
  76%,100%{width:0;margin-right:-5px;opacity:0}}
@keyframes aCccC3{0%,37%{width:0;margin-right:-5px;opacity:0}
  42%,94%{width:26px;margin-right:0;opacity:1}96%,100%{width:0;margin-right:-5px;opacity:0}}
@keyframes aCccC4{0%,51%{width:0;margin-right:-5px;opacity:0}
  56%,94%{width:26px;margin-right:0;opacity:1}96%,100%{width:0;margin-right:-5px;opacity:0}}
@keyframes aCccCur{0%,58%{transform:translate(0,0)}70%,88%{transform:translate(-56px,-42px)}
  96%,100%{transform:translate(0,0)}}


/* La consigne interdit une boucle prefabriquee, et c est exactement ce que
   faisait la scene precedente, cinq barres sur une meme keyframe avec des
   animation-delay decales. La rangee du bas garde ce montage, elle sert
   maintenant de contre exemple.
   La rangee du haut suit une enveloppe. Les cinq barres partagent les MEMES
   instants, 6 14 22 30 et 38, et chacune a son propre facteur de bande,
   0,7 puis 1 puis 0,85 puis 0,55 puis 0,4. La hauteur vaut 3 plus
   l enveloppe fois le facteur fois 31.
   La preuve est le SILENCE, de 46 a 62. En haut tout retombe a plat, en bas
   la boucle prefabriquee continue d onduler alors que personne ne parle.
   C est la seule facon de distinguer un visualiseur d une decoration.
   De 70 a 92 le systeme PARLE. Les barres passent en hauteur uniforme et
   changent de couleur, parce qu une sortie synthetisee n a pas d amplitude
   mesuree, et la consigne demande ce changement de forme.
   La frise du bas marque les deux fenetres. Elle fait 64 pour 100 points,
   soit 0,64 par point, le silence est donc a 29 sur 10 de large et la parole
   a 45 sur 14. Elle ne bouge pas, c est la reference.
   Gele, les deux rangees se ressembleraient, et le silence ne se verrait
   pas du tout. */
.vwf{display:flex;flex-direction:column;gap:8px;width:100px}
.vwf .one{display:flex;align-items:flex-end;gap:6px;height:34px}
.vwf em{font:600 6px/8px var(--mono);font-style:normal;letter-spacing:0;text-transform:none;
  width:30px;flex:0 0 auto}
.vwf .ok em{color:var(--lime)}
.vwf .ko em{color:var(--a4)}
.vwf .bars{display:flex;align-items:flex-end;gap:6px;height:34px}
.vwf .bars i{display:block;width:8px;height:3px;border-radius:4px;background:var(--lime);
  flex:0 0 auto}
/* memes instants pour les cinq, chacune son facteur de bande */
.vwf .ok .b1{animation:aVwfB1 4.4s ease-in-out infinite}
.vwf .ok .b2{animation:aVwfB2 4.4s ease-in-out infinite}
.vwf .ok .b3{animation:aVwfB3 4.4s ease-in-out infinite}
.vwf .ok .b4{animation:aVwfB4 4.4s ease-in-out infinite}
.vwf .ok .b5{animation:aVwfB5 4.4s ease-in-out infinite}
/* la boucle prefabriquee que la consigne interdit, une seule keyframe et des
   retards, elle ne sait rien du micro et elle ne s arrete jamais */
.vwf .ko .bars i{background:var(--a4);animation:aVwfCanned 1.3s ease-in-out infinite}
.vwf .ko .b2{animation-delay:.26s}
.vwf .ko .b3{animation-delay:.52s}
.vwf .ko .b4{animation-delay:.13s}
.vwf .ko .b5{animation-delay:.39s}
/* les deux fenetres, fixes par construction */
.vwf .tl{position:relative;display:block;width:64px;height:5px;margin-left:36px;
  border-top:1px solid var(--line)}
.vwf .tl i{position:absolute;top:1px;display:block;height:4px;border-radius:2px}
.vwf .sil{left:29px;width:10px;background:var(--s4)}
.vwf .spk{left:45px;width:14px;background:var(--a2)}
@keyframes aVwfB1{0%,3%{height:3px;background:var(--lime)}
  6%{height:13px}14%{height:21px}22%{height:16px}30%{height:25px}38%{height:15px}
  46%,62%{height:3px}
  70%,92%{height:12px;background:var(--a2)}
  96%,100%{height:3px;background:var(--lime)}}
@keyframes aVwfB2{0%,3%{height:3px;background:var(--lime)}
  6%{height:17px}14%{height:29px}22%{height:22px}30%{height:34px}38%{height:20px}
  46%,62%{height:3px}
  70%,92%{height:12px;background:var(--a2)}
  96%,100%{height:3px;background:var(--lime)}}
@keyframes aVwfB3{0%,3%{height:3px;background:var(--lime)}
  6%{height:15px}14%{height:25px}22%{height:19px}30%{height:29px}38%{height:17px}
  46%,62%{height:3px}
  70%,92%{height:12px;background:var(--a2)}
  96%,100%{height:3px;background:var(--lime)}}
@keyframes aVwfB4{0%,3%{height:3px;background:var(--lime)}
  6%{height:11px}14%{height:18px}22%{height:14px}30%{height:20px}38%{height:12px}
  46%,62%{height:3px}
  70%,92%{height:12px;background:var(--a2)}
  96%,100%{height:3px;background:var(--lime)}}
@keyframes aVwfB5{0%,3%{height:3px;background:var(--lime)}
  6%{height:9px}14%{height:14px}22%{height:11px}30%{height:15px}38%{height:10px}
  46%,62%{height:3px}
  70%,92%{height:12px;background:var(--a2)}
  96%,100%{height:3px;background:var(--lime)}}
@keyframes aVwfCanned{0%,100%{height:6px}50%{height:28px}}

/* Le nombre de la consigne est 60 millisecondes. Sur un cycle de 4,4
   secondes cela vaut 1,4 point, donc moins de deux pixels sur une piste de
   80. Il est impossible de le DESSINER, la scene montre donc ce qui compte,
   la difference avec un systeme qui rate le budget.
   La parole de l assistant demarre a 8. L attaque de l utilisateur est a 40.
   En haut l assistant se coupe a 41, l instant suivant, ce qui vaut 44
   millisecondes et tient sous le budget. En bas il se coupe a 60, soit 880
   millisecondes, quinze fois le budget.
   La barre du haut fait donc 41 moins 8, soit 33 points, ce qui vaut 26 sur
   80. Celle du bas fait 52 points, soit 42. Le depassement se lit comme 16
   pixels de parole en trop, par-dessus la voix de l utilisateur.
   La barre change de couleur a l instant de la coupure, ce qui est le
   passage en mode entree que demande la consigne. En haut il tombe avec
   l attaque, en bas bien plus tard.
   La reponse tronquee RESTE dans la transcription, elle ne s efface pas.
   Le trait de l attaque est fixe, a 40 pour cent de 80, soit 32.
   Gele, on ne verrait pas laquelle des deux coupures est a l heure. */
.bgi{display:flex;flex-direction:column;gap:6px;width:116px}
/* l attaque, instant fixe, reference des deux rangees */
.bgi .tl{position:relative;display:block;width:80px;height:6px;margin-left:36px}
.bgi .onset{position:absolute;left:32px;top:0;display:block;width:1.5px;height:6px;
  background:var(--lime)}
.bgi .one{display:flex;align-items:center;gap:6px}
.bgi em{font:600 6px/8px var(--mono);font-style:normal;letter-spacing:0;text-transform:none;
  width:30px;flex:0 0 auto}
.bgi .ok em{color:var(--lime)}
.bgi .ko em{color:var(--a4)}
.bgi .au{display:block;width:80px;height:8px;border-radius:4px;background:var(--s2)}
.bgi .au b{display:block;height:8px;border-radius:4px;background:var(--a2);width:0}
/* coupe a l instant suivant l attaque */
.bgi .ok .au b{animation:aBgiOk 4.4s steps(1,end) infinite}
/* coupe 880 millisecondes trop tard */
.bgi .ko .au b{animation:aBgiKo 4.4s steps(1,end) infinite}
.bgi .tr{display:flex;flex-direction:column;gap:5px;margin-top:2px;margin-left:36px}
.bgi .tr b{display:block;height:6px;border-radius:3px;width:0}
/* tronquee, et conservee */
.bgi .asst{background:var(--a2);animation:aBgiAs 4.4s cubic-bezier(.3,0,.2,1) infinite}
.bgi .user{background:var(--lime);animation:aBgiUs 4.4s cubic-bezier(.3,0,.2,1) infinite}
/* 33 points de 80, soit 26 */
@keyframes aBgiOk{0%,7%{width:0;background:var(--a2)}
  8%,40%{width:26px;background:var(--a2)}
  41%,94%{width:26px;background:var(--lime)}
  96%,100%{width:0;background:var(--a2)}}
/* 52 points de 80, soit 42, dont 16 apres l attaque */
@keyframes aBgiKo{0%,7%{width:0;background:var(--a2)}
  8%,59%{width:42px;background:var(--a2)}
  60%,94%{width:42px;background:var(--lime)}
  96%,100%{width:0;background:var(--a2)}}
/* 26, la meme longueur que la parole coupee, ce qui dit que le texte garde
   est exactement ce qui a ete prononce */
@keyframes aBgiAs{0%,7%{width:0}30%,94%{width:26px}96%,100%{width:0}}
@keyframes aBgiUs{0%,45%{width:0}62%,94%{width:58px}96%,100%{width:0}}

/* La consigne dit DERRIERE le contenu et jamais par-dessus le texte. La
   seule difference entre les deux panneaux est l ORDRE DU DOM. En haut le
   halo est le premier enfant, il passe donc dessous. En bas il est le
   dernier, il passe dessus, et le texte devient sale. Aucune propriete ne
   change, c est la position dans le document qui fait la faute, et c est
   pour cela qu on la commet si facilement.
   La respiration fait 2 secondes, litteralement, comme la consigne le
   demande. Elle porte sur le scale et rien d autre.
   Le fondu de sortie va de 88 a 95, soit 7 points sur un cycle de 4
   secondes, ce qui vaut 280 millisecondes et tient sous la limite de 300.
   Il porte sur l opacite et rien d autre, sans quoi il ecraserait la
   respiration.
   La rotation de teinte se fait entre deux couleurs de la palette et non par
   un filtre, pour rester dans les tokens du projet. Elle porte sur le
   background.
   Le contraste reste bas, l opacite ne depasse jamais 0,5 et le flou fait 9.
   Gele, on ne saurait pas si le modele travaille encore. */
.apg{display:flex;flex-direction:column;gap:12px;width:108px}
/* trois lignes de 6, deux ecarts de 5 et 10 de padding font 38 */
.apg .one{position:relative;display:block;width:108px;height:38px}
.apg .tx{position:relative;display:flex;flex-direction:column;gap:5px;padding:5px 6px}
.apg .tx i{display:block;height:6px;border-radius:3px;background:var(--ink-3)}
.apg .tx i:nth-child(1){width:94px}
.apg .tx i:nth-child(2){width:72px}
.apg .tx i:nth-child(3){width:84px}
/* trois animations, trois proprietes distinctes, aucune ne se marche dessus */
.apg .halo{position:absolute;inset:-6px;border-radius:14px;background:var(--lime);
  filter:blur(9px);opacity:0;
  animation:aApgBreath 2s ease-in-out infinite,aApgWin 4s linear infinite,
  aApgHue 2.6s ease-in-out infinite}
@keyframes aApgBreath{0%,100%{transform:scale(.94)}50%{transform:scale(1.06)}}
/* fondu de sortie de 88 a 95, soit 280 millisecondes */
@keyframes aApgWin{0%,4%{opacity:0}12%,88%{opacity:.5}95%,100%{opacity:0}}
@keyframes aApgHue{0%,100%{background:var(--lime)}50%{background:var(--a2)}}

/* La consigne dit d attacher le marqueur a l ARTEFACT et de le garder quand
   le contenu est copie. La scene le prouve par la copie elle meme.
   En haut le badge est sur l image. A 52 une copie sort de l image, et elle
   emporte SON badge, parce que le badge fait partie de l artefact.
   En bas la mention est sur la PAGE, dans un bandeau au-dessus. L image n en
   porte rien. La copie sort a 52 elle aussi, et elle sort NUE. Le bandeau
   est reste sur la page, la provenance a ete perdue au premier
   copier-coller.
   Le badge n a aucune animation d entree, il est la du premier au dernier
   pour cent, parce que la consigne dit persistant. C est un etat, pas un
   evenement, et c est ce qui le distingue d une notification.
   L image fait 46, la copie 46, avec 10 d ecart la rangee fait 102. La copie
   part de moins 30 et arrive a zero, soit 30 de course.
   Gele, les deux rangees auraient l air correctes, et c est la copie qui
   revele la faute. */
.prv{display:flex;flex-direction:column;gap:10px;width:116px}
.prv .one{display:flex;align-items:flex-start;gap:10px}
.prv .art{position:relative;display:block;width:46px;height:30px;border-radius:7px;
  background:linear-gradient(135deg,var(--s3),var(--s1))}
/* persistant, aucune animation, c est un etat */
.prv .bd{position:absolute;right:3px;top:3px;display:block;width:12px;height:12px;
  border-radius:7px;background:var(--a2)}
.prv .cp{position:relative;display:block;width:46px;height:30px;border-radius:7px;
  background:linear-gradient(135deg,var(--s3),var(--s1));opacity:0;
  animation:aPrvCp 4.4s cubic-bezier(.2,1,.3,1) infinite}
/* la mention est sur la page et non sur l image, elle ne partira pas */
.prv .pg{display:flex;flex-direction:column;gap:4px;width:58px;padding:4px;border-radius:9px;
  background:var(--s1);border:1px dashed var(--line-2);box-sizing:border-box}
.prv .pg em{display:block;font:700 6px/8px var(--mono);color:var(--a4);font-style:normal;
  letter-spacing:0;text-transform:none}
.prv .pg .art{width:48px;height:30px}
/* 30 de course, la copie sort de sous l original */
@keyframes aPrvCp{0%,51%{opacity:0;transform:translateX(-30px)}
  60%,94%{opacity:1;transform:translateX(0)}
  96%,100%{opacity:0;transform:translateX(-30px)}}
