/* ============================================================
   Motionary, demos J
   UX Patterns, retour systeme, divulgation, formulaires, listes
   ============================================================ */
/* ---------------- retour et etat systeme ---------------- */
/* Le coeur se remplit avant la reponse, a 28 pour cent. La requete
   echoue a 66, le coeur revient a 74 ET le bandeau d'erreur arrive a
   72 avec sa relance. Un retour en arriere silencieux se lit comme un
   bouton casse, c'est ce que dit la consigne du terme. */
.opt{position:relative;display:flex;flex-direction:column;align-items:center;gap:13px;width:152px}
.opt .hrt{display:block;width:30px;height:30px;border-radius:8px 8px 14px 14px;
  border:2.5px solid var(--s6);transform:rotate(-45deg);
  animation:aOpt 3.4s cubic-bezier(.2,1.4,.3,1) infinite}
.opt .cur{left:88px;top:34px;animation:aOptCur 3.4s ease infinite}
.opt .err{display:flex;align-items:center;gap:8px;width:100%;box-sizing:border-box;padding:6px 8px;
  border-radius:7px;background:rgba(var(--danger-rgb),.14);border:1px solid var(--danger);
  animation:aOptErr 3.4s ease infinite}
.opt .err .l{flex:1;height:5px;border-radius:3px;background:var(--danger);opacity:.6}
.opt .err .rt{width:28px;height:13px;border-radius:4px;background:var(--danger)}
@keyframes aOpt{0%,20%{background:transparent;border-color:var(--s6);transform:rotate(-45deg) scale(1)}
  28%{background:var(--danger);border-color:var(--danger);transform:rotate(-45deg) scale(1.22)}
  38%,66%{background:var(--danger);border-color:var(--danger);transform:rotate(-45deg) scale(1)}
  74%{background:transparent;border-color:var(--danger);transform:rotate(-45deg) scale(1.1)}
  84%,100%{background:transparent;border-color:var(--s6);transform:rotate(-45deg) scale(1)}}
@keyframes aOptCur{0%,14%{transform:translate(0,0)}24%,34%{transform:translate(-46px,-4px) scale(.7)}
  48%,100%{transform:translate(0,0)}}
@keyframes aOptErr{0%,64%{opacity:0;transform:translateY(5px)}
  72%,92%{opacity:1;transform:translateY(0)}97%,100%{opacity:0;transform:translateY(5px)}}

/* Le cycle va maintenant jusqu'au bout du geste. La ligne part a 10
   pour cent, le toast monte a 30, on appuie sur annuler a 68, la
   ligne REVIENT a 82 et le toast ne s'en va qu'apres, a 96.
   La jauge se recharge de 96 a 99, c'est a dire une fois le toast
   devenu invisible. Avant, la ligne et la jauge se teleportaient
   toutes les deux au raccord de boucle. */
.unt{position:relative;width:152px;height:88px;display:flex;flex-direction:column;gap:8px;padding-top:6px}
.unt .rowx{display:block;height:19px;border-radius:7px;background:var(--s3)}
.unt .rowx:first-child{background:var(--lime);animation:aUntRow 4s cubic-bezier(.3,.9,.3,1) infinite}
.unt .toast2{position:absolute;left:0;right:0;bottom:0;height:24px;border-radius:9px;background:var(--s1);
  border:1px solid var(--line-2);box-sizing:border-box;display:flex;align-items:center;gap:8px;
  padding:0 9px;overflow:hidden;animation:aUntT 4s cubic-bezier(.2,1.1,.3,1) infinite}
.unt .msg{flex:1;height:5px;border-radius:3px;background:var(--s5)}
.unt .undo{display:block;width:32px;height:8px;border-radius:4px;background:var(--lime);
  animation:aUntU 4s steps(1,end) infinite}
.unt .drain{position:absolute;left:0;bottom:0;height:2px;right:0;background:var(--lime);
  transform-origin:left;animation:aUntD 4s linear infinite}
@keyframes aUntRow{0%,10%{transform:translateX(0);opacity:1}
  34%,68%{transform:translateX(158px);opacity:0}
  82%,100%{transform:translateX(0);opacity:1}}
@keyframes aUntT{0%,16%{transform:translateY(32px);opacity:0}30%,86%{transform:translateY(0);opacity:1}
  96%,100%{transform:translateY(32px);opacity:0}}
@keyframes aUntD{0%,30%{transform:scaleX(1)}68%,96%{transform:scaleX(.28)}99%,100%{transform:scaleX(1)}}
@keyframes aUntU{0%,66%{opacity:.55}68%,78%{opacity:1}82%,100%{opacity:.55}}

/* Le bandeau est ancre juste au dessus du champ qu'il concerne, pas en
   haut de la page, et son emplacement est RESERVE. Rien ne bouge
   quand il arrive, il ne fait qu'apparaitre dans un espace qui
   existait deja. Animer sa hauteur pousserait le champ dont il parle,
   ce qui est le piege que le prompt nomme. */
.ial{display:flex;flex-direction:column;gap:8px;width:152px}
.ial .rowy{display:block;height:11px;border-radius:5px;background:var(--s3)}
.ial .rowy:last-child{width:68%}
.ial .slot{display:block;height:28px}
.ial .alert{display:flex;align-items:center;gap:8px;height:28px;box-sizing:border-box;
  border-radius:8px;padding:0 9px;background:rgba(var(--danger-rgb),.14);
  border-left:3px solid var(--danger);animation:aIal 3.8s cubic-bezier(.3,.9,.3,1) infinite}
.ial .alert .ic{width:9px;height:9px;border-radius:50%;background:var(--danger);flex:0 0 auto}
.ial .alert .l{flex:1;height:5px;border-radius:3px;background:var(--danger);opacity:.55}
.ial .fld{display:block;height:26px;border-radius:7px;background:var(--s1);box-sizing:border-box;
  border:1px solid var(--line-2);animation:aIalFld 3.8s ease infinite}
@keyframes aIal{0%,12%{opacity:0;transform:translateY(-6px)}30%,88%{opacity:1;transform:translateY(0)}
  96%,100%{opacity:0;transform:translateY(-6px)}}
@keyframes aIalFld{0%,12%{border-color:var(--line-2)}30%,88%{border-color:var(--danger)}
  96%,100%{border-color:var(--line-2)}}

/* Les deux valeurs sont empilees a la meme place et de meme largeur,
   elles se croisent en opacite. Rien ne change de taille, rien ne
   pousse rien, et le trait de repere a droite le prouve. Un fondu
   croise a largeur egale EST la demonstration de cette consigne.
   La pastille de rafraichissement reste petite et discrete, c'est
   une information et non un evenement. */
.swr{display:grid;place-items:center}
.swr .card5{position:relative;display:flex;align-items:center;gap:9px;padding:12px 13px;
  border-radius:11px;background:var(--s1);border:1px solid var(--line)}
.swr .dot2{position:absolute;right:8px;top:8px;width:9px;height:9px;border-radius:5px;
  border:1.5px solid var(--s2);border-top-color:var(--lime);animation:aSpin3 .9s linear infinite}
.swr .stk{position:relative;display:block;width:44px;height:32px}
.swr .stk b{position:absolute;left:0;top:0;width:44px;font:800 22px/32px var(--mono);
  font-variant-numeric:tabular-nums;color:var(--lime);text-align:left}
.swr .v1{animation:aSwrA 3.4s ease infinite}
.swr .v2{animation:aSwrB 3.4s ease infinite}
.swr .gd{display:block;width:1px;height:26px;background:repeating-linear-gradient(180deg,var(--line-2) 0 3px,transparent 3px 6px)}
.swr .lbl2{display:block;width:34px;height:6px;border-radius:3px;background:var(--s4)}
@keyframes aSpin3{to{transform:rotate(360deg)}}
@keyframes aSwrA{0%,46%{opacity:1}54%,94%{opacity:0}98%,100%{opacity:1}}
@keyframes aSwrB{0%,46%{opacity:0}54%,94%{opacity:1}98%,100%{opacity:0}}

/* Deux vides de causes opposees, donc de traitements opposes. A gauche
   il n'y a rien encore et l'action est de creer. A droite le
   chargement a echoue et l'action est de relancer. Les confondre
   pousse l'utilisateur a recreer ce qui existe deja ailleurs.
   Aucune pulsation permanente sur les boutons, la carte apparait une
   fois et se tient tranquille, comme le veut captation de l'attention. */
.emp2{display:flex;gap:13px;width:172px}
.emp2 .col{flex:1;display:flex;flex-direction:column;align-items:center;gap:7px}
.emp2 .tag{font:600 8px/1 var(--mono);color:var(--ink-3);font-style:normal}
.emp2 .tag.ko{color:var(--danger)}
.emp2 .frameE{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;
  width:100%;height:82px;box-sizing:border-box;border-radius:11px;border:1px dashed var(--s5);
  animation:aEmp2 5s ease infinite}
.emp2 .frameE.ko{border-color:rgba(var(--danger-rgb),.55)}
.emp2 .ph{display:block;width:30px;height:20px;border-radius:6px;border:1.5px dashed var(--s6)}
.emp2 .ph.ko{border-color:var(--danger);border-style:solid}
.emp2 .ln2{display:block;width:54px;height:5px;border-radius:3px;background:var(--s3)}
.emp2 .cta2{display:block;width:44px;height:16px;border-radius:7px;background:var(--lime)}
.emp2 .cta2.rt{background:transparent;border:1.5px solid var(--danger);box-sizing:border-box}
@keyframes aEmp2{0%,8%{opacity:0;transform:scale(.96)}22%,88%{opacity:1;transform:scale(1)}
  96%,100%{opacity:0;transform:scale(.96)}}

/* Les deux comptes sont annonces d'abord, quatre passes et deux
   echoues, jamais le lot entier en echec. Chaque ligne fautive porte
   SA raison, pas un message unique, et le bouton de relance ne
   reprend que ces deux la. */
.pfl{position:relative;width:160px;display:flex;flex-direction:column;gap:9px}
.pfl .sum{display:flex;align-items:center;gap:7px}
.pfl .sum b{display:block;padding:3px 7px;border-radius:5px;font:700 9px/1 var(--mono)}
.pfl .sum .ok{background:rgba(var(--accent-rgb),.2);color:var(--lime)}
.pfl .sum .ko{background:rgba(var(--danger-rgb),.2);color:var(--danger)}
.pfl .lst{display:flex;flex-direction:column;gap:5px}
.pfl .r{display:block;height:12px;border-radius:5px;background:var(--s2);
  animation:aPflOk 4s ease infinite}
.pfl .r.ko{position:relative;background:var(--s2);animation-name:aPflKo}
.pfl .r.ko em{position:absolute;left:0;right:0;top:0;bottom:0;border-radius:5px;
  background:repeating-linear-gradient(90deg,transparent 0 6px,rgba(var(--danger-rgb),.5) 6px 9px);
  animation:aPflL 4s ease infinite}
.pfl .r:nth-child(2){animation-delay:.1s}
.pfl .r:nth-child(3){animation-delay:.2s}
.pfl .r:nth-child(4){animation-delay:.3s}
.pfl .r:nth-child(5){animation-delay:.4s}
.pfl .r:nth-child(6){animation-delay:.5s}
.pfl .rt{display:block;width:78px;height:18px;border-radius:6px;background:var(--danger);
  animation:aPflRt 4s ease infinite}
@keyframes aPflOk{0%,14%{background:var(--s2)}34%,86%{background:var(--lime)}96%,100%{background:var(--s2)}}
@keyframes aPflKo{0%,14%{background:var(--s2)}34%,86%{background:rgba(var(--danger-rgb),.3)}
  96%,100%{background:var(--s2)}}
@keyframes aPflL{0%,60%{opacity:0}72%,90%{opacity:1}98%,100%{opacity:0}}
@keyframes aPflRt{0%,62%{opacity:0;transform:translateY(5px)}74%,92%{opacity:1;transform:translateY(0)}
  97%,100%{opacity:0;transform:translateY(5px)}}
/* ---------------- divulgation, focus, navigation ---------------- */
/* Le sujet est le TRI, pas l'ouverture. Trois reglages courants restent
   toujours visibles avec leurs vrais contrôles, et le declencheur porte
   le nom de ce qu'il cache plus le compte de ce qu'il y a dedans. Un
   chevron nu qui dit More ne permet pas de decider de ne pas l'ouvrir.
   Le triangle est la porte, ce terme ci est la decision editoriale, et
   c'est pour cela que la scene montre deux classes d'options et non
   un bloc qui grandit. */
.pdi{display:flex;flex-direction:column;gap:6px;width:172px}
.pdi .row{display:flex;align-items:center;gap:9px;height:20px;padding:0 9px;box-sizing:border-box;
  border-radius:6px;background:var(--s1)}
.pdi .row .l{flex:1;height:5px;border-radius:3px;background:var(--s5)}
.pdi .row .tg{position:relative;flex:0 0 auto;width:22px;height:12px;border-radius:7px;background:var(--lime)}
.pdi .row .tg i{position:absolute;top:2px;left:12px;width:8px;height:8px;border-radius:50%;background:var(--on-accent)}
.pdi .row .pill{flex:0 0 auto;width:26px;height:11px;border-radius:5px;background:var(--s4)}
.pdi .trg{display:flex;align-items:center;gap:7px;height:22px;padding:0 9px;box-sizing:border-box;
  border-radius:7px;background:var(--s0);border:1px dashed var(--line-2)}
.pdi .cv{flex:0 0 auto;width:5px;height:5px;border-right:1.5px solid var(--ink-2);
  border-bottom:1.5px solid var(--ink-2);transform:rotate(-45deg);
  animation:aPdiCv 4.4s cubic-bezier(.3,.9,.3,1) infinite}
.pdi .nm{flex:1;font:600 8px/1 var(--mono);color:var(--ink-2);font-style:normal}
.pdi .cnt{flex:0 0 auto;font:700 8px/1 var(--mono);color:var(--lime);font-style:normal}
/* emplacement reserve, la couche avancee ne pousse jamais la couche
   courante puisqu'elle occupe une place qui existait deja */
.pdi .slot{position:relative;height:42px}
.pdi .adv{position:absolute;left:0;right:0;top:0;display:flex;flex-direction:column;gap:6px;
  animation:aPdi 4.4s cubic-bezier(.3,.9,.3,1) infinite}
.pdi .adv i{display:block;height:12px;border-radius:5px;background:var(--s2)}
.pdi .adv i:nth-child(2){width:78%}
.pdi .adv i:nth-child(3){width:54%}
@keyframes aPdi{0%,16%{opacity:0;transform:translateY(-8px)}34%,84%{opacity:1;transform:translateY(0)}
  94%,100%{opacity:0;transform:translateY(-8px)}}
@keyframes aPdiCv{0%,16%{transform:rotate(-45deg)}34%,84%{transform:rotate(45deg)}
  94%,100%{transform:rotate(-45deg)}}

/* Le sujet est le CONTRÔLE. Trois choses n'existent que dans le
   mouvement, l'anneau de focus qui couvre la LIGNE ENTIÈRE et non le
   triangle de 12px, la rotation d'un seul chevron d'un quart de tour,
   et aria-expanded qui bascule avec lui. Deux icônes qui se
   remplaceraient ne montreraient aucun etat continu. */
.dtr{display:flex;flex-direction:column;gap:8px;width:172px}
.dtr .hdr{position:relative;display:flex;align-items:center;gap:9px;height:26px;padding:0 9px;
  box-sizing:border-box;border-radius:7px;background:var(--s1);
  animation:aDtrFocus 3.6s steps(1,end) infinite}
.dtr .tri{flex:0 0 auto;width:0;height:0;border-left:9px solid var(--lime);
  border-top:6px solid transparent;border-bottom:6px solid transparent;
  animation:aDtr 3.6s cubic-bezier(.3,.9,.3,1) infinite}
.dtr .ttl{flex:1;height:6px;border-radius:3px;background:var(--ink);opacity:.8}
.dtr .aria{flex:0 0 auto;font:700 7px/1 var(--mono);font-style:normal;
  animation:aDtrAria 3.6s steps(1,end) infinite}
.dtr .slot2{position:relative;height:46px}
.dtr .blk{position:absolute;left:0;right:0;top:0;display:flex;flex-direction:column;gap:6px;
  animation:aDtrB 3.6s cubic-bezier(.3,.9,.3,1) infinite}
.dtr .blk i{display:block;height:11px;border-radius:5px;background:var(--s3)}
.dtr .blk i:last-child{width:62%}
@keyframes aDtr{0%,12%{transform:rotate(0)}44%,80%{transform:rotate(90deg)}96%,100%{transform:rotate(0)}}
@keyframes aDtrB{0%,12%{opacity:0;transform:translateY(-9px)}44%,80%{opacity:1;transform:translateY(0)}
  96%,100%{opacity:0;transform:translateY(-9px)}}
@keyframes aDtrFocus{0%,6%{box-shadow:none}10%,86%{box-shadow:0 0 0 2px var(--lime)}
  92%,100%{box-shadow:none}}
@keyframes aDtrAria{0%,12%{color:var(--ink-3)}44%,80%{color:var(--lime)}96%,100%{color:var(--ink-3)}}

/* Deux affirmations opposees, cote a cote. A gauche le contrôle est
   grise mais RESTE atteignable, le focus s'y pose et sa raison
   apparait, ce qui est exactement ce que demande la consigne. A droite
   il n'y a rien, et l'espace vide est la reponse.
   La boucle du bouton se referme maintenant, avant il reapparaissait
   d'un coup au raccord. */
.dvh{display:flex;flex-direction:column;gap:13px;width:172px}
.dvh .lane{position:relative;display:flex;align-items:center;gap:10px;height:30px}
.dvh .tag{flex:0 0 auto;width:52px;font:600 8px/1 var(--mono);color:var(--ink-3);font-style:normal}
.dvh .b{position:relative;flex:0 0 auto;width:56px;height:26px;border-radius:8px;box-sizing:border-box}
.dvh .l{background:var(--s2);opacity:.45;border:1px solid var(--line-2);
  animation:aDvhFocus 4s steps(1,end) infinite}
.dvh .r{background:var(--lime);animation:aDvh 4s steps(1,end) infinite}
.dvh .gap{flex:0 0 auto;width:56px;height:26px;border-radius:8px;
  border:1px dashed var(--line);box-sizing:border-box}
.dvh .tip2{position:absolute;left:0;top:-17px;width:92px;height:14px;border-radius:5px;
  box-sizing:border-box;background:var(--s1);border:1px solid var(--line-2);
  animation:aDvhT 4s ease infinite}
@keyframes aDvh{0%,44%{opacity:1;transform:scale(1)}52%,90%{opacity:0;transform:scale(.9)}
  96%,100%{opacity:1;transform:scale(1)}}
@keyframes aDvhFocus{0%,20%{box-shadow:none}26%,82%{box-shadow:0 0 0 2px var(--lime)}
  88%,100%{box-shadow:none}}
@keyframes aDvhT{0%,22%{opacity:0;transform:translateY(4px)}32%,82%{opacity:1;transform:translateY(0)}
  90%,100%{opacity:0;transform:translateY(4px)}}

/* La requete se tape d'abord, en huit paliers de 6px pour 48px, et
   c'est ELLE qui fait tomber la liste de quatre lignes a deux. Chaque
   ligne porte son raccourci a droite, c'est cette colonne qui apprend
   les raccourcis et finit par rendre la palette inutile. */
.cpl{display:flex;flex-direction:column;gap:7px;width:172px}
.cpl .inp{display:flex;align-items:center;gap:6px;height:26px;padding:0 9px;box-sizing:border-box;
  border-radius:8px;background:var(--s1);border:1px solid var(--lime)}
.cpl .kbd{flex:0 0 auto;font:700 8px/1 var(--mono);color:var(--ink-3);font-style:normal}
.cpl .q{display:block;height:6px;border-radius:3px;background:var(--s5);width:0;
  animation:aCplQ 4s steps(8,end) infinite}
.cpl .caret{display:block;flex:0 0 auto;width:1.5px;height:13px;background:var(--lime);
  animation:aCplCr .9s steps(1,end) infinite}
.cpl .res2{display:flex;align-items:center;gap:9px;height:18px;padding:0 9px;box-sizing:border-box;
  border-radius:6px;background:var(--s1)}
.cpl .res2 .nm2{flex:1;height:5px;border-radius:3px;background:var(--s5)}
.cpl .res2 .sc{flex:0 0 auto;font:700 7px/1 var(--mono);color:var(--ink-3);font-style:normal}
.cpl .r1{animation:aCplA 4s ease infinite}
.cpl .r2,.cpl .r3{animation:aCplB 4s ease infinite}
.cpl .r3{animation-delay:.08s}
@keyframes aCplQ{0%{width:0}30%,88%{width:48px}96%,100%{width:0}}
@keyframes aCplCr{0%,50%{opacity:1}51%,100%{opacity:0}}
@keyframes aCplA{0%,30%{background:var(--s1)}44%,88%{background:rgba(var(--accent-rgb),.22)}
  96%,100%{background:var(--s1)}}
@keyframes aCplB{0%,30%{opacity:1;transform:scaleY(1)}46%,88%{opacity:0;transform:scaleY(.4)}
  96%,100%{opacity:1;transform:scaleY(1)}}

/* Trois choses bougent a la main lors d'un changement de route, et la
   scene les montre toutes les trois. Le titre du document change dans
   la barre du haut, le focus se pose sur le nouveau h1 avec un anneau
   VISIBLE, et la region live annonce. Sans elles la navigation ne
   deplace que des pixels. */
.fho{display:flex;flex-direction:column;gap:8px;width:172px}
.fho .tbb{display:flex;align-items:center;gap:7px;height:18px;padding:0 8px;box-sizing:border-box;
  border-radius:6px 6px 0 0;background:var(--panel);border:1px solid var(--line)}
.fho .tbb .dot{width:6px;height:6px;border-radius:50%;background:var(--s4);flex:0 0 auto}
.fho .tbb .t1,.fho .tbb .t2{position:absolute;height:5px;border-radius:3px;background:var(--ink-2)}
.fho .tbb .stk{position:relative;flex:1;height:5px}
.fho .tbb .t1{left:0;width:44px;animation:aFhoT1 3.6s steps(1,end) infinite}
.fho .tbb .t2{left:0;width:62px;animation:aFhoT2 3.6s steps(1,end) infinite}
.fho .vp{position:relative;height:76px;overflow:hidden;border-radius:9px}
.fho .pgx{position:absolute;inset:0;padding:12px;box-sizing:border-box}
.fho .pgx i{display:block;width:64%;height:12px;border-radius:5px;background:rgba(var(--ink-rgb),.4)}
.fho .a{background:var(--s2);animation:aFhoA 3.6s cubic-bezier(.3,.9,.3,1) infinite}
.fho .b{background:var(--s4);animation:aFhoB 3.6s cubic-bezier(.3,.9,.3,1) infinite}
.fho .b i{background:var(--lime);animation:aFhoRing 3.6s ease infinite}
.fho .live{position:absolute;right:8px;bottom:8px;width:34px;height:9px;border-radius:5px;
  background:var(--lime);animation:aFhoLive 3.6s ease infinite}
@keyframes aFhoA{0%,14%{transform:translateX(0)}46%,72%{transform:translateX(-100%)}94%,100%{transform:translateX(0)}}
@keyframes aFhoB{0%,14%{transform:translateX(100%)}46%,72%{transform:translateX(0)}94%,100%{transform:translateX(100%)}}
@keyframes aFhoRing{0%,46%{box-shadow:none}56%,84%{box-shadow:0 0 0 3px rgba(var(--accent-rgb),.4)}94%,100%{box-shadow:none}}
@keyframes aFhoT1{0%,44%{opacity:1}48%,90%{opacity:0}96%,100%{opacity:1}}
@keyframes aFhoT2{0%,44%{opacity:0}48%,90%{opacity:1}96%,100%{opacity:0}}
@keyframes aFhoLive{0%,50%{opacity:0;transform:scale(.85)}58%,70%{opacity:1;transform:scale(1)}
  80%,100%{opacity:0;transform:scale(.85)}}

/* L'asymetrie EST le design, et le repere la rend lisible. Le document
   descend de 72px, le trait pointille marque les 150px reels a 30px de
   course, et l'en-tete ne part QU'APRES l'avoir franchi, a 38 pour
   cent. Au retour il n'y a aucun seuil, le document remonte a 62 et
   l'en-tete est revenu a 64, soit 80ms plus tard. Un meme seuil dans
   les deux sens se lirait comme une panne. */
.ahh{position:relative;width:172px;height:96px;overflow:hidden;border-radius:9px;background:var(--s0)}
.ahh .hd3{position:absolute;left:0;right:0;top:0;height:20px;background:var(--lime);z-index:3;
  animation:aAhhH 4.4s cubic-bezier(.3,.9,.3,1) infinite}
.ahh .doc3{position:absolute;left:9px;right:24px;top:26px;height:168px;border-radius:6px;
  background:repeating-linear-gradient(var(--s3) 0 9px,transparent 9px 17px);
  animation:aAhhD 4.4s cubic-bezier(.3,.9,.3,1) infinite}
.ahh .gauge{position:absolute;right:7px;top:26px;bottom:8px;width:4px;border-radius:2px;background:var(--s1)}
.ahh .thumb{position:absolute;left:0;right:0;top:0;height:22px;border-radius:2px;background:var(--s5);
  animation:aAhhT 4.4s cubic-bezier(.3,.9,.3,1) infinite}
.ahh .thr{position:absolute;left:-4px;right:-4px;top:18px;height:1px;
  background:repeating-linear-gradient(90deg,var(--danger) 0 3px,transparent 3px 6px)}
.ahh .lbl3{position:absolute;right:16px;top:12px;font:700 7px/1 var(--mono);color:var(--danger);
  font-style:normal;z-index:4}
@keyframes aAhhH{0%,38%{transform:translateY(0)}52%,62%{transform:translateY(-100%)}
  64%,100%{transform:translateY(0)}}
@keyframes aAhhD{0%,10%{transform:translateY(0)}50%,62%{transform:translateY(-72px)}
  92%,100%{transform:translateY(0)}}
@keyframes aAhhT{0%,10%{transform:translateY(0)}50%,62%{transform:translateY(26px)}
  92%,100%{transform:translateY(0)}}

/* Le defilement est un EVENEMENT, pas un decalage pose au depart. La
   liste descend vraiment de 34px, on ouvre une fiche, on revient, et
   elle est toujours a 34. Le repere de position a droite ne bouge pas
   pendant l'aller retour, c'est lui qui prouve la restauration. Une
   liste deja decalee au montage ne montrerait rien du tout. */
.srt{position:relative;width:172px;height:96px;overflow:hidden;border-radius:9px;background:var(--s0)}
.srt .list{position:absolute;left:9px;right:22px;top:8px;display:flex;flex-direction:column;gap:7px;
  animation:aSrtL 5s cubic-bezier(.3,.9,.3,1) infinite}
.srt .list i{display:block;height:17px;border-radius:6px;background:var(--s3)}
.srt .hit2{background:var(--lime);animation:aSrtHit 5s ease infinite}
.srt .gauge{position:absolute;right:7px;top:8px;bottom:8px;width:4px;border-radius:2px;background:var(--s1)}
.srt .thumb{position:absolute;left:0;right:0;top:0;height:26px;border-radius:2px;background:var(--s5);
  animation:aSrtT 5s cubic-bezier(.3,.9,.3,1) infinite}
.srt .detail{position:absolute;inset:0;background:var(--s4);z-index:2;
  animation:aSrtD 5s cubic-bezier(.3,.9,.3,1) infinite}
@keyframes aSrtL{0%,10%{transform:translateY(0)}26%,94%{transform:translateY(-34px)}
  99%,100%{transform:translateY(0)}}
@keyframes aSrtT{0%,10%{transform:translateY(0)}26%,94%{transform:translateY(22px)}
  99%,100%{transform:translateY(0)}}
@keyframes aSrtD{0%,36%{transform:translateX(100%)}48%,72%{transform:translateX(0)}
  84%,100%{transform:translateX(100%)}}
@keyframes aSrtHit{0%,30%{box-shadow:none}34%,88%{box-shadow:0 0 0 2px rgba(var(--accent-rgb),.5)}
  94%,100%{box-shadow:none}}


/* ---------------- formulaires ---------------- */
/* La PAUSE est le mecanisme et elle etait invisible. La frappe
   s'arrete a 38 pour cent, la jauge du debounce ne demarre qu'a ce
   moment la et met 20 pour cent d'un cycle de 5s, soit une seconde
   exactement, avant que l'ecriture parte a 60.
   Quinze caracteres, quinze pas, largeur en ch, chaque palier tombe
   donc sur une frontiere de glyphe.
   Trois etats, jamais deux. Rien, puis enregistrement, puis enregistre
   AVEC son horodatage, parce qu'un etat sans heure laisse la meme
   question ouverte. */
.asv{display:flex;flex-direction:column;gap:11px;width:172px}
.asv .doc{display:block;padding:9px 10px;border-radius:8px;box-sizing:border-box;
  background:var(--s1);border:1px solid var(--line-2);font:600 11px/16px var(--mono)}
.asv .ln3{display:block;overflow:hidden;white-space:nowrap;color:var(--ink);width:0;
  animation:aAsvL 5s steps(15,end) infinite}
.asv .dbc{position:relative;display:block;height:3px;border-radius:2px;background:var(--s2);overflow:hidden}
.asv .dbc b{position:absolute;left:0;top:0;bottom:0;width:0;border-radius:2px;background:var(--ink-3);
  animation:aAsvDb 5s linear infinite}
.asv .st{position:relative;display:block;height:14px}
.asv .st span{position:absolute;left:0;top:0;display:flex;align-items:center;gap:6px;
  font:600 8px/14px var(--mono);font-style:normal}
.asv .s1{color:var(--ink-3);animation:aAsvS1 5s steps(1,end) infinite}
.asv .s2{color:var(--lime);animation:aAsvS2 5s steps(1,end) infinite}
.asv .s1 i{display:block;width:9px;height:9px;border-radius:50%;box-sizing:border-box;
  border:1.5px solid var(--ink-3);border-top-color:transparent;animation:aAsvSpin .8s linear infinite}
.asv .s2 i{display:block;width:9px;height:9px;border-radius:50%;background:var(--lime)}
@keyframes aAsvL{0%{width:0}38%,94%{width:15ch}98%,100%{width:0}}
@keyframes aAsvDb{0%,38%{width:0}58%{width:100%}58.001%,100%{width:0}}
@keyframes aAsvS1{0%,58%{opacity:0}60%,72%{opacity:1}74%,100%{opacity:0}}
@keyframes aAsvS2{0%,72%{opacity:0}74%,94%{opacity:1}96%,100%{opacity:0}}
@keyframes aAsvSpin{to{transform:rotate(360deg)}}

/* La garde se tient sur la SORTIE, pas dans la page. Le lien de
   navigation est clique a 40 pour cent, la page commence a partir, et
   la boite l'intercepte a 46. Trois boutons reels, enregistrer,
   abandonner, rester, parce qu'un dialogue a deux boutons oblige a
   choisir entre perdre le travail et ignorer ce que fait l'autre.
   Gele, on ne verrait qu'une boite au dessus d'un formulaire, sans
   savoir ce qui l'a declenchee ni ce qu'elle empeche. */
.ugd{position:relative;width:172px;height:104px;overflow:hidden;border-radius:9px;background:var(--s0)}
.ugd .nav{position:absolute;left:0;right:0;top:0;height:20px;display:flex;align-items:center;gap:8px;
  padding:0 9px;box-sizing:border-box;background:var(--panel);border-bottom:1px solid var(--line);z-index:2}
.ugd .nav i{display:block;height:5px;width:26px;border-radius:3px;background:var(--s4)}
.ugd .nav .go{background:var(--lime);animation:aUgdNav 4.4s steps(1,end) infinite}
.ugd .page{position:absolute;left:0;right:0;top:20px;bottom:0;padding:10px;box-sizing:border-box;
  display:flex;flex-direction:column;gap:8px;animation:aUgdPage 4.4s cubic-bezier(.4,0,.2,1) infinite}
.ugd .fld3{position:relative;display:block;height:24px;border-radius:7px;box-sizing:border-box;
  background:var(--s1);border:1px solid var(--line-2)}
.ugd .dot3{position:absolute;right:8px;top:8px;width:7px;height:7px;border-radius:4px;
  background:var(--lime);animation:aUgdDot 4.4s ease infinite}
.ugd .ln4{display:block;height:8px;border-radius:4px;background:var(--s2)}
.ugd .dlg2{position:absolute;left:12px;right:12px;top:34px;padding:9px;border-radius:9px;
  box-sizing:border-box;background:var(--card);border:1px solid var(--line-2);z-index:3;
  box-shadow:0 12px 26px rgba(var(--shadow-rgb),.55);display:flex;flex-direction:column;gap:8px;
  animation:aUgdD 4.4s cubic-bezier(.2,1.1,.3,1) infinite}
.ugd .dlg2 .t{height:6px;width:64%;border-radius:3px;background:var(--ink);opacity:.8}
.ugd .btns3{display:flex;gap:6px}
.ugd .btns3 b{display:block;flex:1;height:15px;border-radius:5px;background:var(--s3)}
.ugd .btns3 .pr{background:var(--lime)}
@keyframes aUgdDot{0%,12%{opacity:0;transform:scale(.4)}24%,92%{opacity:1;transform:scale(1)}
  98%,100%{opacity:0;transform:scale(.4)}}
@keyframes aUgdNav{0%,38%{background:var(--lime)}40%,50%{background:var(--ink)}
  54%,100%{background:var(--lime)}}
/* la page amorce son depart puis est REPOUSSEE en place, c'est le
   blocage qui se voit, pas une simple apparition de boite */
@keyframes aUgdPage{0%,40%{transform:translateX(0)}46%{transform:translateX(-9px)}
  56%,100%{transform:translateX(0)}}
@keyframes aUgdD{0%,44%{opacity:0;transform:translateY(14px) scale(.94)}
  58%,90%{opacity:1;transform:translateY(0) scale(1)}
  97%,100%{opacity:0;transform:translateY(14px) scale(.94)}}

/* Toute la regle porte sur le MOMENT. On tape de 6 a 34 pour cent et
   il ne se passe RIEN, c'est volontaire, un e-mail a moitie tape n'est
   pas une erreur. Le champ est quitte a 38 et le verdict tombe. On
   corrige a partir de 58, et cette fois la verification est directe
   jusqu'a ce que l'erreur parte a 74.
   Gele, il ne reste qu'un champ rouge qui devient vert, c'est a dire
   exactement rien du terme. */
.ivl{display:flex;flex-direction:column;gap:7px;width:172px}
.ivl .lb{height:5px;width:38px;border-radius:3px;background:var(--ink-3)}
.ivl .fld4{display:flex;align-items:center;gap:2px;height:28px;padding:0 9px;box-sizing:border-box;
  border-radius:8px;background:var(--s1);border:1.5px solid var(--line-2);
  font:600 11px/28px var(--mono);animation:aIvl 5.4s steps(1,end) infinite}
.ivl .typed{display:block;overflow:hidden;white-space:nowrap;color:var(--ink);width:0;
  animation:aIvlType 5.4s steps(9,end) infinite}
.ivl .caret{display:block;flex:0 0 auto;width:1.5px;height:14px;background:var(--lime);
  animation:aIvlCr .9s steps(1,end) infinite}
.ivl .msg{display:flex;align-items:center;gap:6px;height:12px}
.ivl .msg i{display:block;width:8px;height:8px;border-radius:50%;background:var(--danger);flex:0 0 auto}
.ivl .msg b{display:block;height:5px;width:76px;border-radius:3px;background:var(--danger);opacity:.7}
.ivl .msg{animation:aIvlM 5.4s ease infinite}
.ivl .ph{display:flex;gap:5px;height:9px}
.ivl .ph em{flex:1;height:9px;border-radius:4px;font:700 6px/9px var(--mono);text-align:center;
  color:var(--void);font-style:normal;background:var(--s2)}
.ivl .p1{animation:aIvlP1 5.4s steps(1,end) infinite}
.ivl .p2{animation:aIvlP2 5.4s steps(1,end) infinite}
.ivl .p3{animation:aIvlP3 5.4s steps(1,end) infinite}
@keyframes aIvlType{0%,4%{width:0}34%,52%{width:9ch}58%{width:6ch}74%,94%{width:12ch}
  98%,100%{width:0}}
@keyframes aIvl{0%,36%{border-color:var(--line-2)}38%,72%{border-color:var(--danger)}
  74%,94%{border-color:var(--lime)}97%,100%{border-color:var(--line-2)}}
@keyframes aIvlM{0%,36%{opacity:0}40%,72%{opacity:1}76%,100%{opacity:0}}
@keyframes aIvlP1{0%,4%{background:var(--s2)}8%,34%{background:var(--ink-3)}38%,100%{background:var(--s2)}}
@keyframes aIvlP2{0%,36%{background:var(--s2)}40%,54%{background:var(--danger)}58%,100%{background:var(--s2)}}
@keyframes aIvlP3{0%,56%{background:var(--s2)}60%,92%{background:var(--lime)}96%,100%{background:var(--s2)}}
@keyframes aIvlCr{0%,50%{opacity:1}51%,100%{opacity:0}}

/* Le saut EST le sujet, pas la liste. La soumission echoue a 22 pour
   cent, le recapitulatif prend le focus a 30, puis a 54 on active la
   deuxieme ligne et le focus part se poser sur le champ qu'elle nomme,
   en bas. Un recapitulatif qui ne ferait que lister laisserait
   l'utilisateur chercher.
   L'emplacement du bloc est reserve, il ne pousse donc pas le
   formulaire, ce qui evite d'animer une hauteur dans une boucle. */
.esm{position:relative;display:flex;flex-direction:column;gap:7px;width:172px}
.esm .slot3{position:relative;height:34px}
.esm .sum{position:absolute;left:0;right:0;top:0;display:flex;flex-direction:column;gap:5px;
  padding:7px 9px;box-sizing:border-box;border-radius:8px;background:rgba(var(--danger-rgb),.12);
  border-left:3px solid var(--danger);animation:aEsm 5s cubic-bezier(.3,.9,.3,1) infinite}
.esm .sum i{display:block;height:6px;border-radius:3px;background:var(--danger);opacity:.75}
.esm .sum i:last-child{width:66%}
.esm .sum .lnk{animation:aEsmLnk 5s steps(1,end) infinite}
.esm .rowz{display:block;height:17px;border-radius:6px;background:var(--s2)}
.esm .err{border:1.5px solid var(--danger);box-sizing:border-box;animation:aEsmE 5s ease infinite}
@keyframes aEsm{0%,22%{opacity:0;transform:translateY(-8px)}
  30%,92%{opacity:1;transform:translateY(0)}98%,100%{opacity:0;transform:translateY(-8px)}}
@keyframes aEsmLnk{0%,50%{opacity:.75;box-shadow:none}
  54%,70%{opacity:1;box-shadow:0 0 0 2px rgba(var(--danger-rgb),.5)}
  74%,100%{opacity:.75;box-shadow:none}}
@keyframes aEsmE{0%,56%{box-shadow:none}62%,90%{box-shadow:0 0 0 3px rgba(var(--danger-rgb),.35)}
  96%,100%{box-shadow:none}}

/* Le separateur n'est pas tape, il est INSERE par le champ apres le
   quatrieme chiffre, a 44 pour cent, alors que la frappe continue sans
   interruption. La pastille du bas montre ce qui part reellement, huit
   chiffres sans separateur, ce qui est la seconde moitie du terme.
   Gele, on verrait huit chiffres et un tiret, sans savoir lequel a ete
   tape et lequel a ete ajoute. */
.imk{display:flex;flex-direction:column;align-items:center;gap:11px;width:172px}
.imk .fld5{display:flex;align-items:center;gap:2px;padding:9px 11px;border-radius:9px;box-sizing:border-box;
  background:var(--s1);border:1px solid var(--line-2);font:700 13px/1 var(--mono);color:var(--lime)}
.imk b{display:block;opacity:0;animation:aImk 5s steps(1,end) infinite}
.imk b:nth-child(2){animation-delay:.28s}
.imk b:nth-child(3){animation-delay:.56s}
.imk b:nth-child(4){animation-delay:.84s}
.imk b:nth-child(6){animation-delay:1.4s}
.imk b:nth-child(7){animation-delay:1.68s}
.imk b:nth-child(8){animation-delay:1.96s}
.imk b:nth-child(9){animation-delay:2.24s}
/* le separateur arrive SEUL, sans frappe, entre le quatrieme et le
   cinquieme chiffre, et il s'ouvre en largeur pour se faire une place */
.imk .sep{display:block;width:0;height:2px;border-radius:2px;background:var(--ink-3);
  margin:0 2px;animation:aImkS 5s cubic-bezier(.3,.9,.3,1) infinite}
.imk .sent{display:flex;align-items:center;gap:7px;padding:4px 8px;border-radius:6px;
  background:var(--s0);border:1px solid var(--line)}
.imk .sent em{font:600 7px/1 var(--mono);color:var(--ink-3);font-style:normal}
.imk .sent i{display:block;height:5px;width:52px;border-radius:3px;background:var(--s4);
  animation:aImkSent 5s ease infinite}
@keyframes aImk{0%{opacity:0}3%,90%{opacity:1}94%,100%{opacity:0}}
@keyframes aImkS{0%,26%{width:0;opacity:0}30%,90%{width:9px;opacity:1}94%,100%{width:0;opacity:0}}
@keyframes aImkSent{0%,58%{opacity:0}66%,90%{opacity:1}96%,100%{opacity:0}}

/* Le sujet est le DEPART et le RETOUR, pas la progression. On avance
   jusqu'a l'etape 3, on part a 44 pour cent et l'ecran se vide
   completement, puis on revient a 62 et l'assistant se retrouve
   exactement a l'etape 3, avec les deux premieres toujours pleines.
   Gele, on ne verrait qu'une barre de progression, ce que fait
   n'importe quel formulaire multi etapes sans reprise. */
.wrz{display:flex;flex-direction:column;align-items:center;gap:12px;width:172px}
.wrz .rail4{position:relative;display:flex;gap:14px;align-items:center}
.wrz .rail4::before{content:"";position:absolute;left:5px;right:5px;top:5px;height:1.5px;background:var(--s2)}
.wrz .rail4 i{position:relative;display:block;width:11px;height:11px;border-radius:6px;background:var(--s3)}
.wrz .s1{animation:aWrz 5.4s steps(1,end) infinite}
.wrz .s2{animation:aWrz 5.4s steps(1,end) infinite;animation-delay:.3s}
.wrz .s3{animation:aWrzOn 5.4s steps(1,end) infinite}
.wrz .lbl4{font:700 8px/1 var(--mono);color:var(--ink-2);font-style:normal}
.wrz .pane2{display:block;width:120px;height:36px;border-radius:9px;background:var(--s2);
  animation:aWrzP 5.4s ease infinite}
.wrz .away{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
  font:600 8px/1 var(--mono);color:var(--ink-3);font-style:normal;
  animation:aWrzAway 5.4s ease infinite}
.wrz .wrp{position:relative;display:flex;flex-direction:column;align-items:center;gap:12px}
@keyframes aWrz{0%,4%{background:var(--s3)}10%,42%{background:var(--lime)}
  62%,90%{background:var(--lime)}96%,100%{background:var(--s3)}}
@keyframes aWrzOn{0%,20%{background:var(--s3);box-shadow:none}
  28%,42%{background:var(--lime);box-shadow:0 0 0 4px rgba(var(--accent-rgb),.22)}
  62%,90%{background:var(--lime);box-shadow:0 0 0 4px rgba(var(--accent-rgb),.22)}
  96%,100%{background:var(--s3);box-shadow:none}}
/* absence complete entre 46 et 60, c'est la que l'utilisateur est parti */
@keyframes aWrzP{0%,42%{opacity:1}48%,58%{opacity:0}64%,100%{opacity:1}}
@keyframes aWrzAway{0%,44%{opacity:0}50%,58%{opacity:1}64%,100%{opacity:0}}

/* ---------------- listes, donnees, confiance ---------------- */
/* Le compteur EST ce que le defilement infini ne sait pas donner. Il
   passe de 40 a 60 sur 312 exactement quand les deux lignes arrivent,
   et l'anneau de focus RESTE sur le bouton apres le chargement, ce
   qu'un remplacement par un spinner detruirait.
   Gele, on verrait quatre lignes et un bouton, sans le denominateur
   ni la conservation du focus, c'est a dire sans le terme. */
.lmr{display:flex;flex-direction:column;gap:7px;width:172px}
.lmr .rowv{display:block;height:16px;border-radius:6px;background:var(--s3)}
.lmr .slot5{position:relative;height:39px}
.lmr .nu{position:absolute;left:0;right:0;height:16px;border-radius:6px;background:var(--s3);
  animation:aLmrN 4.4s cubic-bezier(.3,.9,.3,1) infinite}
.lmr .n2{top:23px;animation-delay:.08s}
.lmr .ft{display:flex;align-items:center;gap:9px}
.lmr .btn3{flex:0 0 auto;width:74px;height:20px;border-radius:8px;box-sizing:border-box;
  border:1.5px solid var(--lime);animation:aLmrB 4.4s ease infinite}
.lmr .cnt{position:relative;flex:1;height:12px;font:700 9px/12px var(--mono);
  font-variant-numeric:tabular-nums;color:var(--ink-3);text-align:right}
.lmr .cnt u{position:absolute;right:0;top:0;text-decoration:none}
.lmr .c1{animation:aLmrC1 4.4s steps(1,end) infinite}
.lmr .c2{animation:aLmrC2 4.4s steps(1,end) infinite}
@keyframes aLmrN{0%,34%{opacity:0;transform:translateY(-9px)}
  52%,92%{opacity:1;transform:translateY(0)}98%,100%{opacity:0;transform:translateY(-9px)}}
/* l'anneau de focus ne quitte JAMAIS le bouton, il s'allume a la
   pression et reste jusqu'a la fin du cycle */
@keyframes aLmrB{0%,20%{background:transparent;box-shadow:none}
  26%,34%{background:rgba(var(--accent-rgb),.22);box-shadow:0 0 0 2px var(--lime)}
  40%,92%{background:transparent;box-shadow:0 0 0 2px var(--lime)}
  98%,100%{background:transparent;box-shadow:none}}
@keyframes aLmrC1{0%,46%{opacity:1}50%,94%{opacity:0}98%,100%{opacity:1}}
@keyframes aLmrC2{0%,46%{opacity:0}50%,94%{opacity:1}98%,100%{opacity:0}}

/* Les lignes en pointille sont celles qui n'EXISTENT PAS dans le DOM,
   au dessus et au dessous de la fenetre. Le curseur de defilement est
   minuscule parce que le jeu de donnees est enorme, et c'est la ce que
   les espaceurs achetent, une hauteur honnete pour des lignes absentes.
   Le compteur dit 12 rendues sur 5000, ce qui est tout le terme.
   Convention marquee pour le recyclage, contenu duplique et
   translation de -50 pour cent, donc le raccord ne se voit jamais.
   Avant, les lignes ET le curseur se teleportaient au retour. */
.vrt{display:flex;gap:11px;align-items:stretch;width:172px}
.vrt .col2{flex:1;display:flex;flex-direction:column;gap:7px}
.vrt .port{position:relative;height:86px;overflow:hidden;border-radius:7px}
.vrt .strip{position:absolute;left:0;right:0;top:0;display:flex;flex-direction:column;gap:6px;
  animation:aVrt 6s ease-in-out infinite}
.vrt .strip i{display:block;height:13px;border-radius:5px;background:var(--s3);flex:0 0 auto}
.vrt .gh{background:transparent;border:1px dashed var(--s3);box-sizing:border-box}
.vrt .cnt2{font:700 8px/1 var(--mono);color:var(--ink-3);font-style:normal}
.vrt .sbar{position:relative;flex:0 0 auto;width:7px;border-radius:4px;background:var(--s1)}
.vrt .sbar i{position:absolute;left:0;right:0;top:0;height:11px;border-radius:4px;
  background:var(--lime);display:block;animation:aVrtS 6s ease-in-out infinite}
/* Aller retour, comme un vrai utilisateur qui parcourt puis remonte.
   La bande fait 222px pour une fenetre de 86, la course de 76 reste
   donc dans le domaine, et le curseur parcourt exactement 75px, soit
   86 moins ses 11px de hauteur. Un enroulement continu ferait sauter
   le curseur en haut a chaque tour, ce qui est visible. */
@keyframes aVrt{0%,100%{transform:translateY(0)}50%{transform:translateY(-76px)}}
/* le curseur fait 11px dans une piste de 86, soit un huitieme, et il
   parcourt 75px puis revient en meme temps que la bande se raccorde */
@keyframes aVrtS{0%,100%{transform:translateY(0)}50%{transform:translateY(75px)}}

/* DEUX etapes distinctes, jamais une case ambigue. A 20 pour cent la
   case d'en-tete prend les quatre lignes visibles et le compte dit 4.
   Le bandeau propose alors l'extension EN NOMMANT son nombre reel, et
   c'est seulement a 62, apres une seconde action, que le compte passe
   a 3200.
   Gele, on verrait des cases cochees et un bandeau, sans savoir qu'il
   s'agit de deux decisions ni ce que la seconde engage. */
.sam{position:relative;display:flex;flex-direction:column;gap:7px;width:172px}
.sam .hdr2{display:flex;align-items:center;gap:9px;height:18px}
.sam .box2{flex:0 0 auto;width:12px;height:12px;border-radius:3px;box-sizing:border-box;
  border:1.5px solid var(--s5);animation:aSamBox 5.4s steps(1,end) infinite}
.sam .cnt3{position:relative;flex:1;height:12px;font:700 9px/12px var(--mono);
  font-variant-numeric:tabular-nums;text-align:right}
.sam .cnt3 u{position:absolute;right:0;top:0;text-decoration:none}
.sam .k1{color:var(--lime);animation:aSamK1 5.4s steps(1,end) infinite}
.sam .k2{color:var(--a2);animation:aSamK2 5.4s steps(1,end) infinite}
.sam .banner{display:flex;align-items:center;gap:8px;height:20px;padding:0 9px;box-sizing:border-box;
  border-radius:6px;background:rgba(var(--a2-rgb),.16);border:1px solid rgba(var(--a2-rgb),.5);
  animation:aSamB 5.4s cubic-bezier(.2,1.1,.3,1) infinite}
.sam .banner em{font:600 7px/1 var(--mono);color:var(--a2);font-style:normal}
.sam .banner b{display:block;width:34px;height:11px;border-radius:4px;background:var(--a2);
  margin-left:auto;animation:aSamBtn 5.4s steps(1,end) infinite}
.sam .ck2{display:block;height:13px;border-radius:4px;background:var(--s3);
  animation:aSam 5.4s steps(1,end) infinite}
.sam .ck2:nth-child(4){animation-delay:.08s}
.sam .ck2:nth-child(5){animation-delay:.16s}
.sam .ck2:nth-child(6){animation-delay:.24s}
@keyframes aSam{0%,16%{background:var(--s3)}22%,92%{background:var(--lime)}97%,100%{background:var(--s3)}}
@keyframes aSamBox{0%,16%{border-color:var(--s5);background:transparent}
  22%,92%{border-color:var(--lime);background:var(--lime)}
  97%,100%{border-color:var(--s5);background:transparent}}
@keyframes aSamK1{0%,16%{opacity:0}22%,58%{opacity:1}62%,100%{opacity:0}}
@keyframes aSamK2{0%,58%{opacity:0}62%,92%{opacity:1}97%,100%{opacity:0}}
@keyframes aSamB{0%,26%{opacity:0;transform:translateY(-8px)}
  38%,92%{opacity:1;transform:translateY(0)}97%,100%{opacity:0;transform:translateY(-8px)}}
@keyframes aSamBtn{0%,54%{opacity:.6}56%,64%{opacity:1}68%,100%{opacity:.6}}

/* Le compte de resultats bouge dans la MEME image que la puce qui
   disparait, et une ligne apparait dans la liste parce que l'ensemble
   s'est elargi. C'est cela qui prouve que la puce et la liste sont la
   meme chose vue deux fois.
   Gele, on verrait deux puces et trois lignes, sans savoir que l'une
   commande les autres. Les deux boucles se referment maintenant, la
   puce revient et la ligne repart. */
.fch{display:flex;flex-direction:column;gap:9px;width:172px}
.fch .tpp2{display:flex;align-items:center;gap:6px}
.fch .chps{display:flex;gap:6px}
.fch .chps i{display:block;height:17px;border-radius:9px;background:var(--s3)}
.fch .q1{width:44px}
.fch .q2{width:36px;background:var(--lime);transform-origin:left center;
  animation:aFch 4.6s cubic-bezier(.3,.9,.3,1) infinite}
.fch .cnt4{position:relative;flex:1;height:12px;text-align:right;
  font:700 9px/12px var(--mono);font-variant-numeric:tabular-nums;color:var(--ink-3)}
.fch .cnt4 u{position:absolute;right:0;top:0;text-decoration:none}
.fch .n1{animation:aFchN1 4.6s steps(1,end) infinite}
.fch .n2b{animation:aFchN2 4.6s steps(1,end) infinite}
.fch .rowsF{position:relative;display:flex;flex-direction:column;gap:6px}
.fch .rowsF b{display:block;height:14px;border-radius:5px;background:var(--s3)}
.fch .slot6{position:relative;height:14px}
.fch .nu2{position:absolute;left:0;right:0;top:0;height:14px;border-radius:5px;background:var(--lime);
  opacity:.55;animation:aFchR 4.6s cubic-bezier(.3,.9,.3,1) infinite}
.fch .cur{left:104px;top:2px;animation:aFchCur 4.6s cubic-bezier(.3,0,.2,1) infinite}
/* la puce s'efface a 46 pour cent et revient a 88, le compte suit au
   pixel de temps pres, sans quoi ce serait deux evenements separes */
@keyframes aFch{0%,44%{transform:scaleX(1);opacity:1}
  56%,84%{transform:scaleX(.2);opacity:0}
  92%,100%{transform:scaleX(1);opacity:1}}
@keyframes aFchN1{0%,44%{opacity:1}46%,86%{opacity:0}90%,100%{opacity:1}}
@keyframes aFchN2{0%,44%{opacity:0}46%,86%{opacity:1}90%,100%{opacity:0}}
@keyframes aFchR{0%,44%{opacity:0;transform:translateY(-8px)}
  58%,84%{opacity:.55;transform:translateY(0)}92%,100%{opacity:0;transform:translateY(-8px)}}
@keyframes aFchCur{0%,20%{transform:translate(12px,10px);opacity:0}
  30%{transform:translate(0,0);opacity:1}
  42%{transform:translate(0,3px);opacity:1}
  54%{transform:translate(0,0);opacity:1}
  68%{transform:translate(12px,10px);opacity:0}
  68.001%,100%{transform:translate(12px,10px);opacity:0}}

/* SEUL le remplissage vertical change. Les barres de texte gardent
   exactement la meme hauteur et la meme largeur d'un etat a l'autre,
   ce qui est la premiere consigne du terme, et le repere de gauche
   montre que la ligne du haut ne bouge pas d'un pixel.
   Gele, on verrait un tableau, sans savoir ce qui a change ni ce qui
   a ete preserve. */
.tdn{display:flex;flex-direction:column;gap:9px;width:172px}
.tdn .tg2{display:flex;align-items:center;gap:7px;align-self:flex-start;padding:3px 7px;
  border-radius:6px;background:var(--s1);border:1px solid var(--line-2)}
.tdn .tg2 b{display:block;width:22px;height:10px;border-radius:4px;background:var(--s3)}
.tdn .tg2 .on{background:var(--lime);animation:aTdnTg 4.4s steps(1,end) infinite}
.tdn .tbl{position:relative;display:flex;flex-direction:column}
.tdn .anch{position:absolute;left:-6px;top:0;width:2px;height:9px;border-radius:1px;background:var(--a2)}
.tdn .r{display:flex;align-items:center;gap:8px;padding:9px 0;
  animation:aTdn 4.4s cubic-bezier(.3,.9,.3,1) infinite}
.tdn .r i{display:block;height:6px;border-radius:3px;background:var(--s4);flex:0 0 auto}
.tdn .r .c1{width:34px}
.tdn .r .c2{width:52px;background:var(--s3)}
.tdn .r .c3{width:26px;margin-left:auto;background:var(--s3)}
/* le remplissage passe de 9 a 3, la barre de texte reste a 6 de haut */
@keyframes aTdn{0%,14%{padding-top:9px;padding-bottom:9px}
  48%,84%{padding-top:3px;padding-bottom:3px}
  98%,100%{padding-top:9px;padding-bottom:9px}}
@keyframes aTdnTg{0%,14%{transform:translateX(0)}48%,84%{transform:translateX(29px)}
  98%,100%{transform:translateX(0)}}

/* L'ordre est tout. L'ecran interne arrive a 14 pour cent, on appuie
   sur Autoriser a 42, et c'est SEULEMENT apres, a 58, que la boite
   systeme apparait. On ne depense la question couteuse que sur
   quelqu'un qui a deja dit oui.
   Gele, on verrait deux boites empilees sans savoir laquelle appelle
   l'autre, ce qui est precisement le contraire du terme. */
.pprm{position:relative;width:172px;height:104px;display:grid;place-items:center}
.pprm .soft{position:absolute;left:8px;right:8px;top:8px;padding:10px;border-radius:11px;
  box-sizing:border-box;background:var(--s1);border:1px solid rgba(var(--accent-rgb),.4);
  display:flex;flex-direction:column;gap:8px;
  animation:aPprmA 5.2s cubic-bezier(.2,1.1,.3,1) infinite}
.pprm .soft .t{height:6px;width:62%;border-radius:3px;background:var(--ink);opacity:.8}
.pprm .soft .m{height:5px;border-radius:3px;background:var(--s5)}
.pprm .soft .bt{display:flex;gap:7px}
.pprm .soft .bt b{display:block;flex:1;height:15px;border-radius:5px;background:var(--s3)}
.pprm .soft .bt .yes{background:var(--lime);animation:aPprmY 5.2s steps(1,end) infinite}
.pprm .sysd{position:absolute;left:22px;right:22px;top:32px;padding:9px;border-radius:9px;
  box-sizing:border-box;background:var(--void);border:1px solid var(--s4);z-index:3;
  box-shadow:0 14px 28px rgba(var(--shadow-rgb),.62);display:flex;flex-direction:column;gap:7px;
  animation:aPprmB 5.2s cubic-bezier(.2,1.1,.3,1) infinite}
.pprm .sysd .t{height:5px;width:70%;border-radius:3px;background:var(--ink-2)}
.pprm .sysd .bt{display:flex;gap:6px}
.pprm .sysd .bt b{display:block;flex:1;height:13px;border-radius:4px;background:var(--s3)}
@keyframes aPprmA{0%,8%{opacity:0;transform:translateY(14px)}
  20%,54%{opacity:1;transform:translateY(0)}
  64%,92%{opacity:.25;transform:scale(.96)}
  98%,100%{opacity:0;transform:translateY(14px)}}
@keyframes aPprmY{0%,40%{filter:brightness(1)}42%,50%{filter:brightness(1.35)}
  54%,100%{filter:brightness(1)}}
@keyframes aPprmB{0%,56%{opacity:0;transform:scale(.9)}
  68%,90%{opacity:1;transform:scale(1)}97%,100%{opacity:0;transform:scale(.9)}}

/* Les trois nombres ensemble, jamais un pourcentage seul. Le trait
   rouge marque les 80 pour cent et la barre change de couleur EN LE
   FRANCHISSANT, a 52 pour cent du cycle, ce qui donne une cause
   visible au changement. La pastille dit quand ça se remet a zero.
   Gele, on aurait une barre remplie sans savoir contre quoi, ni ce
   qui reste, ni quand elle se libere. */
.qmt{display:flex;flex-direction:column;gap:10px;width:172px}
.qmt .top2{display:flex;align-items:baseline;gap:6px}
.qmt .used{position:relative;width:34px;height:22px;font:800 17px/22px var(--mono);
  font-variant-numeric:tabular-nums;color:var(--lime)}
.qmt .used u{position:absolute;left:0;top:0;text-decoration:none;
  animation:aQmtU 5s steps(1,end) infinite}
.qmt .u2{animation-name:aQmtU2}
.qmt .tot{font:700 10px/22px var(--mono);color:var(--ink-3);font-style:normal}
.qmt .rst{margin-left:auto;font:600 8px/22px var(--mono);color:var(--ink-3);font-style:normal}
.qmt .mbar{position:relative;display:block;height:11px;border-radius:6px;background:var(--s2);overflow:hidden}
.qmt .mbar i{position:absolute;inset:0;background:var(--lime);transform-origin:left;
  animation:aQmt 5s cubic-bezier(.4,0,.6,1) infinite}
/* 80 pour cent de la barre, le trait et le changement de couleur
   tombent donc sur la meme abscisse */
.qmt .thr2{position:absolute;left:80%;top:-3px;bottom:-3px;width:2px;margin-left:-1px;z-index:2;
  background:repeating-linear-gradient(180deg,var(--danger) 0 3px,transparent 3px 6px)}
@keyframes aQmt{0%,6%{transform:scaleX(.42);background:var(--lime)}
  50%{transform:scaleX(.79);background:var(--lime)}
  54%,92%{transform:scaleX(.94);background:var(--danger)}
  100%{transform:scaleX(.42);background:var(--lime)}}
@keyframes aQmtU{0%,50%{opacity:1}54%,94%{opacity:0}98%,100%{opacity:1}}
@keyframes aQmtU2{0%,50%{opacity:0}54%,94%{opacity:1}98%,100%{opacity:0}}

