/* ============================================================
   Motionary, demos B
   Feedback, easing, springs, boucles
   ============================================================ */

/* ---------------- feedback et interaction ---------------- */
.hv,.prs,.rp{position:relative;width:124px;height:64px;display:grid;place-items:center}
.hv .btn,.prs .btn,.rp .btn{display:block;width:82px;height:32px;border-radius:9px;background:var(--s3)}
/* L'entree est plus rapide que la sortie, comme le dit la consigne.
   Le survol s'installe en 18 pour cent du cycle et se retire en 26. */
.hv .btn{animation:aHoverBtn 3.4s infinite}
.hv .cur{left:14px;top:52px;animation:aHoverCur 3.4s cubic-bezier(.3,0,.2,1) infinite}
@keyframes aHoverBtn{
  0%,26%{background:var(--s3);transform:none;animation-timing-function:cubic-bezier(.16,1,.3,1)}
  44%,70%{background:var(--lime);transform:translateY(-3px);animation-timing-function:cubic-bezier(.4,0,.4,1)}
  96%,100%{background:var(--s3);transform:none}}
@keyframes aHoverCur{0%,12%{transform:translate(0,0)}40%,70%{transform:translate(46px,-26px)}96%,100%{transform:translate(0,0)}}

.prs .btn{animation:aPressBtn 2.6s cubic-bezier(.2,.8,.2,1) infinite}
.prs .cur{left:52px;top:26px;animation:aPressCur 2.6s ease-out infinite}
@keyframes aPressBtn{0%,34%{transform:scale(1);background:var(--s3)}46%,56%{transform:scale(.9);background:var(--lime)}74%,100%{transform:scale(1);background:var(--s3)}}
@keyframes aPressCur{0%,34%{transform:scale(1)}46%,56%{transform:scale(.7)}74%,100%{transform:scale(1)}}

.hc{position:relative;display:grid;place-items:center;width:70px;height:70px}
.hc .ring{width:62px;height:62px}
.hc .ring .bg{stroke:var(--s2);stroke-width:4}
/* Ici le maintien va jusqu'au bout et l'action se declenche, marquee
   par la coche. Le relachement anticipe est montre par Hold to delete,
   les deux scenes se completent au lieu de se repeter. */
.hc .ring .fg{stroke:var(--lime);stroke-width:4;stroke-dasharray:120;stroke-dashoffset:120;stroke-linecap:round;transform:rotate(-90deg);transform-origin:center;animation:aHold 3.6s cubic-bezier(.4,0,.6,1) infinite}
.hc .ok2{position:absolute;width:0;height:0;border-left:3px solid transparent;border-bottom:3px solid var(--accent);
  border-right:3px solid var(--accent);border-top:3px solid transparent;border-radius:2px;
  transform:rotate(45deg);opacity:0;animation:aHoldOk 3.6s cubic-bezier(.2,1.4,.3,1) infinite}
.hc .cur{left:22px;top:22px;animation:aHoldCur 3.6s ease-out infinite}
@keyframes aHold{0%,12%{stroke-dashoffset:120}58%,84%{stroke-dashoffset:0}94%,100%{stroke-dashoffset:120}}
@keyframes aHoldOk{0%,58%{opacity:0;width:0;height:0}68%,84%{opacity:1;width:9px;height:16px}92%,100%{opacity:0;width:0;height:0}}
@keyframes aHoldCur{0%,8%{transform:scale(1);opacity:.55}16%,58%{transform:scale(.72);opacity:1}66%,100%{transform:scale(1);opacity:.55}}

.dg{position:relative;width:132px;height:64px}
.dg .sq{position:absolute;left:6px;top:16px;animation:aDrag 3.4s cubic-bezier(.25,.6,.25,1) infinite}
.dg .cur{left:20px;top:30px;animation:aDragCur 3.4s cubic-bezier(.25,.6,.25,1) infinite}
/* apres le relachement a 52 pour cent, le carre continue seul, c'est
   l'inertie. Le curseur part invisible et revient invisible. */
@keyframes aDrag{0%,10%{transform:translate(0,0)}52%{transform:translate(66px,14px)}70%,84%{transform:translate(84px,18px)}96%,100%{transform:translate(0,0)}}
@keyframes aDragCur{0%{transform:translate(0,0);opacity:0}8%,10%{opacity:1}52%{transform:translate(66px,14px);opacity:1}62%{opacity:0}96%,100%{transform:translate(0,0);opacity:0}}

.dro{position:relative;width:112px;height:62px}
.dro .bar{position:absolute;left:0;right:0;height:14px;border-radius:6px;background:var(--s3)}
.dro .r1{top:2px}.dro .r2{top:24px}.dro .r3{top:46px}
.dro .lift{background:var(--lime);z-index:2;animation:aReorder 3.4s cubic-bezier(.3,.9,.3,1) infinite}
.dro .r3{animation:aReorderSib 3.4s cubic-bezier(.3,.9,.3,1) infinite}
/* aller puis retour, on peut reordonner dans les deux sens et la
   boucle se referme sur son etat de depart */
@keyframes aReorder{0%,10%{transform:none;box-shadow:none}20%{transform:scale(1.04);box-shadow:0 6px 14px rgba(var(--shadow-rgb),.45)}42%,58%{transform:translateY(22px) scale(1.04);box-shadow:0 6px 14px rgba(var(--shadow-rgb),.45)}80%,100%{transform:none;box-shadow:none}}
@keyframes aReorderSib{0%,20%{transform:none}42%,58%{transform:translateY(-22px)}80%,100%{transform:none}}

.swd{position:relative;width:140px;height:64px;display:grid;place-items:center;overflow:hidden}
.swd .card2{display:block;width:84px;height:38px;border-radius:10px;background:var(--lime);animation:aSwipe 4.6s cubic-bezier(.3,.8,.3,1) infinite}
.swd .cur{left:44px;top:22px;animation:aSwipeCur 4.6s cubic-bezier(.3,.8,.3,1) infinite}
/* Deux gestes. Le premier n'atteint pas le seuil et la carte revient,
   le second le franchit et la carte part. Sans le premier, le seuil
   n'existe nulle part dans la scene alors qu'il est tout le sujet. */
.swd .thr{position:absolute;top:8px;bottom:8px;left:78px;width:1.5px;border-radius:2px;
  background:repeating-linear-gradient(var(--s6) 0 4px,transparent 4px 8px)}
@keyframes aSwipe{0%{transform:translateX(0);opacity:0}6%,14%{transform:translateX(0);opacity:1}26%{transform:translateX(26px)}40%,48%{transform:translateX(0);opacity:1}72%{transform:translateX(60px);opacity:1}90%,100%{transform:translateX(130px);opacity:0}}
@keyframes aSwipeCur{0%{transform:translateX(0);opacity:0}6%{opacity:1}26%{transform:translateX(26px)}40%{transform:translateX(0)}48%{opacity:1}72%{transform:translateX(60px);opacity:1}78%,100%{transform:translateX(60px);opacity:0}}

/* Le curseur descend regulierement, 12px puis 12px puis 12px. Le
   contenu suit de 12, puis 7, puis 3. La resistance est ce rapport
   qui diminue, et on ne peut la voir qu'en comparant les deux. */
.rbz{position:relative;width:108px;height:96px;align-items:flex-start;padding:10px 8px 8px}
.rbz .edge{position:absolute;left:0;right:0;top:10px;height:1.5px;background:repeating-linear-gradient(90deg,var(--s6) 0 4px,transparent 4px 8px);z-index:3}
.rbz .col{width:100%;gap:6px;animation:aRubber 3.8s cubic-bezier(.3,.8,.3,1) infinite}
.rbz .col i{display:block;height:14px;border-radius:5px;background:var(--s3)}
.rbz .col i:first-child{background:var(--lime)}
.rbz .cur{right:-2px;top:22px;animation:aRubberCur 3.8s cubic-bezier(.3,.8,.3,1) infinite}
@keyframes aRubber{0%,8%{transform:translateY(0)}26%{transform:translateY(12px)}42%{transform:translateY(19px)}56%{transform:translateY(22px)}70%{transform:translateY(-3px)}82%,100%{transform:translateY(0)}}
@keyframes aRubberCur{0%{transform:translateY(0);opacity:0}6%,8%{opacity:1}26%{transform:translateY(12px)}42%{transform:translateY(24px)}56%{transform:translateY(36px);opacity:1}62%{opacity:0}82%,100%{transform:translateY(0);opacity:0}}

.shk{display:flex;flex-direction:column;gap:9px;align-items:flex-start}
.shk .field{display:block;width:112px;height:34px;border-radius:9px;background:var(--s1);border:1.5px solid var(--s4);animation:aShake 3.2s ease-in-out infinite}
.shk .msg2{display:block;width:82px;height:6px;border-radius:3px;background:var(--danger);opacity:0;
  animation:aShakeMsg 3.2s ease infinite}
@keyframes aShake{0%,52%{transform:translateX(0);border-color:var(--s4)}56%{transform:translateX(-7px);border-color:var(--danger)}60%{transform:translateX(7px)}64%{transform:translateX(-5px)}68%{transform:translateX(5px)}72%{transform:translateX(-2px)}76%,92%{transform:translateX(0);border-color:var(--danger)}98%,100%{transform:translateX(0);border-color:var(--s4)}}
@keyframes aShakeMsg{0%,54%{opacity:0}62%,92%{opacity:1}98%,100%{opacity:0}}

.rp .btn{position:relative;overflow:hidden}
/* L'onde part exactement du point de contact. Le bouton fait 82x32 et
   il est centre dans une scene de 124x64, donc son coin est a 21,16.
   Le curseur de 14px pose a left 47 top 32 a son centre a 54,39, soit
   33,23 dans le repere du bouton. L'onde part de la. */
.rp .btn i{position:absolute;left:33px;top:23px;width:8px;height:8px;margin:-4px 0 0 -4px;border-radius:50%;background:rgba(var(--accent-rgb),.55);animation:aRipple 2.6s cubic-bezier(.2,.7,.3,1) infinite}
.rp .cur{left:47px;top:32px;animation:aPressCur 2.6s ease-out infinite}
@keyframes aRipple{0%,34%{transform:scale(0);opacity:.8}80%,100%{transform:scale(22);opacity:0}}

/* ---------------- easing ---------------- */
.esz{position:relative;display:flex;flex-direction:column;align-items:center;gap:9px;width:120px}
.esz .curve{width:112px;height:60px}
.esz .curve .gri{stroke:var(--s3);stroke-width:1.5}
.esz .curve .c{stroke:var(--lime);stroke-width:2.6}
.esz .curve .h{stroke:var(--s6);stroke-width:1.2;stroke-dasharray:3 3}
.esz .curve .cp{fill:var(--ink);stroke:none}
.esz .track{position:relative;display:block;width:104px;height:8px;border-radius:4px;background:var(--s2)}
.esz .track .dot{position:absolute;left:0;top:-1px}
/* le temoin gris avance a vitesse constante sur toutes les cartes,
   c'est lui qui rend la courbe lisible */
.esz .ref{background:var(--s6);opacity:.6;animation:aTrack 2.6s linear infinite}
.d-easing .rider{fill:var(--accent);stroke:none;
  offset-path:path("M2 58C40 58 55 2 98 2");
  animation:aEaseRide 2.6s cubic-bezier(.2,.9,.25,1) infinite}
.d-easing .lbl{font-style:normal;color:var(--ink-3)}
@keyframes aEaseRide{0%,6%{offset-distance:0%;opacity:0}12%{opacity:1}62%,88%{offset-distance:100%;opacity:1}96%,100%{offset-distance:100%;opacity:0}}
@keyframes aTrack{0%,6%{transform:translateX(0)}48%,58%{transform:translateX(94px)}96%,100%{transform:translateX(0)}}
.eo .ez{animation:aTrack 2.6s cubic-bezier(.16,1,.3,1) infinite}
.ei .ez{animation:aTrack 2.6s cubic-bezier(.7,0,.84,0) infinite}
.eio .ez{animation:aTrack 2.6s cubic-bezier(.65,0,.35,1) infinite}
.lin .ez{animation:aTrack 2.6s linear infinite}
/* Les poignees restent fixes et exactes plutot que de bouger sans que
   la courbe suive. Le point mobile utilise litteralement la valeur
   affichee, donc la carte ne peut plus mentir. */
.esz .lbl{font-style:normal;font-family:var(--mono);letter-spacing:0;color:var(--ink-3);font-size:8.5px}
.cb .ez{animation:aTrack 2.6s cubic-bezier(.25,.1,.25,1) infinite}
.asy .ez{animation:aTrack 2.8s cubic-bezier(.05,.9,.1,1) infinite}

/* ---------------- springs ---------------- */
.spz{position:relative;width:150px;height:66px}
.spz .lbl{position:absolute;left:0;bottom:0;font-style:normal;font-family:var(--mono);color:var(--ink-3);font-size:8px}
.spz .goal{position:absolute;right:8px;top:9px;width:34px;height:34px;border-radius:9px;border:1px dashed var(--s5)}
.spz .sq{position:absolute;left:8px;top:9px;animation:aSpring 3s cubic-bezier(.2,1.6,.3,1) infinite}
@keyframes aSpring{0%,14%{transform:translateX(0)}70%,86%{transform:translateX(90px)}100%{transform:translateX(0)}}

.two .soft{animation:aSpringT 3s cubic-bezier(.2,1.3,.5,1) infinite}
.two .hard{animation:aSpringT 3s cubic-bezier(.1,2.2,.3,1) infinite}
@keyframes aSpringT{0%,12%{transform:translateX(0)}62%,84%{transform:translateX(84px)}100%{transform:translateX(0)}}
/* Meme duree de cycle pour les deux, sinon ils se desynchronisent et
   la comparaison devient illisible. Seul le profil change, la masse
   lourde part plus mollement et depasse moins. */
.mss .light{animation:aMassL 3.4s cubic-bezier(.15,1.8,.3,1) infinite}
.mss .heavy{animation:aMassH 3.4s cubic-bezier(.45,.9,.5,1) infinite}
@keyframes aMassL{0%,10%{transform:translateX(0)}52%,86%{transform:translateX(84px)}100%{transform:translateX(0)}}
@keyframes aMassH{0%,10%{transform:translateX(0)}76%,86%{transform:translateX(84px)}100%{transform:translateX(0)}}

/* Amortissement faible a gauche, fort a droite, meme cible et meme
   cycle. Un amortissement seul ne veut rien dire, il se lit par
   comparaison comme une courbe d'easing. */
.dmp{position:relative;width:140px;height:78px;display:flex;justify-content:space-around;align-items:center}
.dmp .wave{position:absolute;left:0;right:0;top:50%;height:1px;background:var(--s3)}
.dmp .side{position:relative;display:flex;flex-direction:column;align-items:center;gap:8px;z-index:2}
.dmp .side i{font:600 9px/1 var(--mono);color:var(--ink-3);font-style:normal;position:absolute;bottom:-16px}
.dmp .sq{width:28px;height:28px}
.dmp .low{animation:aDampLow 3.6s cubic-bezier(.4,0,.4,1) infinite}
.dmp .high{animation:aDampHigh 3.6s cubic-bezier(.4,0,.4,1) infinite}
@keyframes aDampLow{0%,8%{transform:translateY(-26px)}28%{transform:translateY(21px)}44%{transform:translateY(-14px)}57%{transform:translateY(9px)}68%{transform:translateY(-5px)}78%{transform:translateY(2px)}88%,92%{transform:translateY(0)}100%{transform:translateY(-26px)}}
@keyframes aDampHigh{0%,8%{transform:translateY(-26px)}34%{transform:translateY(2px)}44%,92%{transform:translateY(0)}100%{transform:translateY(-26px)}}

/* 100px de haut, pas 84. La balle monte de 46px et s'etire de 18 pour
   cent vers le haut depuis son point de contact, il faut donc de la
   place au dessus sinon le sommet est rogne au plus haut du rebond. */
.ss{position:relative;width:110px;height:100px}
.ss .floor{position:absolute;left:8px;right:8px;bottom:10px;height:2px;background:var(--s3);border-radius:2px}
.ss .ball{position:absolute;left:50%;margin-left:-16px;bottom:12px;width:32px;height:32px;border-radius:50%;background:var(--lime)}

/* La ligne de cible rend le depassement mesurable. Sans elle, un
   rebond ressemble a n'importe quel mouvement un peu vif. */
.bnc{position:relative;width:132px;height:74px;display:grid;place-items:center}
.bnc .goal3{position:absolute;left:50%;top:8px;bottom:22px;width:1.5px;margin-left:20px;
  background:repeating-linear-gradient(var(--s6) 0 4px,transparent 4px 8px)}
.bnc .sq{position:relative;animation:aBounce 3s cubic-bezier(.2,1.55,.3,1) infinite}
.bnc .lbl{position:absolute;left:50%;margin-left:24px;bottom:4px;font-style:normal;font-family:var(--mono);color:var(--ink-3)}
@keyframes aBounce{0%,12%{transform:translateX(-58px)}66%,88%{transform:translateX(20px)}100%{transform:translateX(-58px)}}

.pd{position:relative;width:150px;height:74px}
.pd .sq{position:absolute;left:6px;top:8px;animation:aPercep 3.6s cubic-bezier(.2,1.5,.3,1) infinite}
.pd .lbl{position:absolute;left:6px;white-space:nowrap}
.pd .done{top:48px;color:var(--lime);animation:aLbl 3.6s ease infinite}
.pd .settle{top:62px;animation:aLbl2 3.6s ease infinite}
@keyframes aPercep{0%,8%{transform:translateX(0)}44%{transform:translateX(100px)}56%{transform:translateX(96px)}68%{transform:translateX(99px)}80%{transform:translateX(98px)}92%,100%{transform:translateX(0)}}
@keyframes aLbl{0%,38%{opacity:0}46%,88%{opacity:1}94%,100%{opacity:0}}
@keyframes aLbl2{0%,52%{opacity:0}60%,88%{opacity:.55}94%,100%{opacity:0}}

/* Trois jalons poses apres le lacher, a 34, 58 et 70px. Les ecarts
   valent 34, 24 puis 12, la friction mange la vitesse et ca se voit. */
.mom{position:relative;width:150px;height:60px}
.mom .rel{position:absolute;left:40px;top:4px;bottom:16px;width:1.5px;background:var(--s6)}
.mom i{position:absolute;top:44px;width:1.5px;height:8px;background:var(--s5);display:block}
.mom .t1{left:74px}.mom .t2{left:98px}.mom .t3{left:110px}
.mom .sq{position:absolute;left:6px;top:10px;animation:aMomentum 3.8s cubic-bezier(.05,.85,.2,1) infinite}
.mom .cur{left:20px;top:24px;animation:aMomCur 3.8s cubic-bezier(.4,0,.6,1) infinite}
@keyframes aMomentum{0%,8%{transform:translateX(0)}24%{transform:translateX(34px)}76%,90%{transform:translateX(104px)}100%{transform:translateX(0)}}
@keyframes aMomCur{0%{transform:translateX(0);opacity:0}6%,8%{opacity:1}24%{transform:translateX(34px);opacity:1}32%,100%{transform:translateX(44px);opacity:0}}

/* Le vecteur porte la vitesse instantanee dans sa longueur ET la
   direction dans son sens. Une trainee de taille fixe ne dit rien
   d'une vitesse, elle reste identique a l'arret. */
.vel{position:relative;width:150px;height:56px}
.vel .sq{position:absolute;left:6px;top:11px;animation:aVel 3.2s cubic-bezier(.3,0,.7,1) infinite}
.vel .vec{position:absolute;left:44px;top:26px;height:3px;border-radius:2px;background:var(--lime);
  transform-origin:left center;width:44px;animation:aVelVec 3.2s cubic-bezier(.3,0,.7,1) infinite}
.vel .vec::after{content:"";position:absolute;right:-2px;top:-4px;width:10px;height:10px;
  border-top:3px solid var(--lime);border-right:3px solid var(--lime);transform:rotate(45deg)}
@keyframes aVel{0%,6%{transform:translateX(0)}54%,64%{transform:translateX(80px)}98%,100%{transform:translateX(0)}}
@keyframes aVelVec{0%,6%{transform:translateX(0) scaleX(.08);opacity:0}14%{opacity:1}30%{transform:translateX(40px) scaleX(1)}54%,64%{transform:translateX(80px) scaleX(.08);opacity:1}70%{opacity:0}98%,100%{transform:translateX(0) scaleX(.08);opacity:0}}

/* Le fantome gris fait ce que ferait une animation non interruptible,
   il retourne au depart avant de repartir. Le carre vert, lui, repart
   de la ou il est. */
.itr{position:relative;width:150px;height:70px}
.itr .goal{position:absolute;width:34px;height:34px;border-radius:9px;border:1px dashed var(--s5)}
.itr .goal.a{right:8px;top:2px}
.itr .goal.b{right:8px;bottom:2px}
.itr .ghost4{position:absolute;left:8px;top:2px;width:34px;height:34px;border-radius:9px;background:var(--s4);
  opacity:.5;animation:aItrGhost 4s cubic-bezier(.4,0,.2,1) infinite}
.itr .sq{position:absolute;left:8px;top:2px;animation:aInterrupt 4s cubic-bezier(.2,1.4,.3,1) infinite}
.itr .cur{left:62px;top:28px;animation:aInterruptCur 4s ease infinite}
@keyframes aInterrupt{0%,8%{transform:translate(0,0)}32%{transform:translate(58px,0)}70%,88%{transform:translate(108px,34px)}100%{transform:translate(0,0)}}
@keyframes aItrGhost{0%,8%{transform:translate(0,0)}32%{transform:translate(58px,0)}44%{transform:translate(0,0)}70%,88%{transform:translate(108px,34px)}100%{transform:translate(0,0)}}
@keyframes aInterruptCur{0%,24%{opacity:0;transform:scale(1)}32%{opacity:1;transform:scale(.7)}48%{opacity:1;transform:scale(1)}56%,100%{opacity:0}}

/* ---------------- boucles et ambiance ---------------- */
.mqw{display:flex;flex-direction:column;gap:11px;width:100%;align-items:flex-start}
.mqw .lbl{font-style:normal;font-family:var(--mono);color:var(--ink-3);font-size:8px;padding-left:2px}
.mq{width:100%;overflow:hidden;-webkit-mask-image:linear-gradient(90deg,transparent,#000 14%,#000 86%,transparent);mask-image:linear-gradient(90deg,transparent,#000 14%,#000 86%,transparent)}
.mq .strip{display:inline-block;white-space:nowrap;font:800 20px/1 var(--font);letter-spacing:.06em;color:var(--lime);animation:aMarquee 9s linear infinite}
@keyframes aMarquee{from{transform:translateX(0)}to{transform:translateX(-50%)}}

/* Trois tours puis une pause, et le compteur suit. Une etiquette qui
   annonce 3x sur une animation infinie est une contradiction. */
.lp{position:relative;display:flex;flex-direction:column;align-items:center;gap:10px;padding-bottom:16px}
.lp .sq{animation:aLoopSq 4.5s cubic-bezier(.4,0,.2,1) infinite}
.lp .win{height:26px;overflow:hidden;width:18px;display:grid}
.lp .reel{display:flex;flex-direction:column;font:800 19px/26px var(--mono);color:var(--accent);text-align:center;
  animation:aLoopN 4.5s steps(3,end) infinite}
.lp .reel b{height:26px}
.lp .n{position:absolute;bottom:0;font-style:normal;font-family:var(--mono);color:var(--ink-3)}
@keyframes aLoopSq{0%{transform:rotate(0)}20%{transform:rotate(360deg)}40%{transform:rotate(720deg)}60%,88%{transform:rotate(1080deg)}100%{transform:rotate(1080deg)}}
/* le compteur s'efface avant de revenir a 1, la remise a zero d'un
   compteur d'iterations n'a rien a montrer */
.lp .win{animation:aLoopWin 4.5s ease-in-out infinite}
@keyframes aLoopN{0%{transform:translateY(0)}66%,100%{transform:translateY(-78px)}}
@keyframes aLoopWin{0%,4%{opacity:0}10%,88%{opacity:1}96%,100%{opacity:0}}

.alt{position:relative;width:140px;height:60px}
.alt .track{position:absolute;left:0;right:0;top:16px;height:2px;background:var(--s2)}
.alt .track.b{top:44px}
.alt .dot{position:absolute;left:0}
.alt .yo{top:12px;animation:aYoyo 2.4s ease-in-out infinite alternate}
.alt .jp{top:40px;opacity:.5;animation:aJump 2.4s ease-in-out infinite}
@keyframes aYoyo{from{transform:translateX(0)}to{transform:translateX(130px)}}
@keyframes aJump{0%{transform:translateX(0)}100%{transform:translateX(130px)}}

.orb{position:relative;width:92px;height:92px;display:grid;place-items:center}
.orb .sun{width:26px;height:26px;border-radius:8px;background:var(--s3);display:block}
.orb .path{position:absolute;inset:8px;border-radius:50%;border:1px dashed var(--s3)}
.orb .moon{position:absolute;inset:8px;animation:aOrbit 3.4s linear infinite}
.orb .moon::after{content:"";position:absolute;top:-6px;left:50%;margin-left:-6px;width:12px;height:12px;border-radius:50%;background:var(--lime)}
@keyframes aOrbit{from{transform:rotate(0)}to{transform:rotate(360deg)}}

.pls{position:relative;display:grid;place-items:center;width:80px;height:80px}
.pls .core{width:22px;height:22px;border-radius:50%;background:var(--lime);display:block;animation:aPulseCore 2.2s ease-in-out infinite}
.pls .ring{position:absolute;width:22px;height:22px;border-radius:50%;border:2px solid var(--lime);animation:aPulseRing 2.2s cubic-bezier(.2,.7,.3,1) infinite}
.pls .r2{animation-delay:.7s}
@keyframes aPulseCore{0%,100%{transform:scale(1)}50%{transform:scale(1.14)}}
/* l'anneau part invisible et finit invisible, la boucle est fermee et
   on ne voit jamais un anneau reapparaitre d'un coup au centre */
@keyframes aPulseRing{0%{transform:scale(1);opacity:0}12%{opacity:.7}100%{transform:scale(3.2);opacity:0}}

.flt{position:relative;width:80px;height:88px;display:grid;place-items:center}
.flt .sq{animation:aFloat 3.4s ease-in-out infinite}
.flt .shadow{position:absolute;bottom:10px;width:34px;height:8px;border-radius:50%;background:rgba(var(--shadow-rgb),.45);filter:blur(3px);animation:aFloatSh 3.4s ease-in-out infinite}
@keyframes aFloat{0%,100%{transform:translateY(-4px)}50%{transform:translateY(-20px)}}
@keyframes aFloatSh{0%,100%{transform:scale(1);opacity:.5}50%{transform:scale(.72);opacity:.28}}

/* La piste sous le bouton rend l'attente visible. Elle se remplit
   pendant les 84 pour cent ou il ne se passe rien, puis repart de zero
   au moment exact ou le bouton se signale. Sans elle on ne voit qu'un
   bouton qui tressaille de temps en temps, et le silence, qui est le
   mecanisme du terme, ne se lit pas. Meme duree pour les deux. */
.idl{position:relative;display:flex;flex-direction:column;align-items:center;gap:13px}
.idl .btn{position:relative;display:grid;place-items:center;width:88px;height:34px;border-radius:9px;background:var(--lime);animation:aIdle 4s ease-in-out infinite}
.idl .btn i{display:block;width:40px;height:6px;border-radius:3px;background:rgba(var(--on-accent-rgb),.4)}
.idl .track{position:relative;width:88px;height:3px;border-radius:2px;background:var(--s2);overflow:hidden}
.idl .track b{position:absolute;left:0;top:0;bottom:0;width:0;border-radius:2px;background:var(--ink-3);animation:aIdleWait 4s linear infinite}
@keyframes aIdle{0%,84%,100%{transform:scale(1) rotate(0)}88%{transform:scale(1.05) rotate(-1.2deg)}92%{transform:scale(1.03) rotate(1.2deg)}96%{transform:scale(1) rotate(0)}}
@keyframes aIdleWait{0%{width:0}84%{width:100%}84.001%,100%{width:0}}
