/* ============================================================
   Motionary, demos A
   Entrees, sequencage, transformations, transitions, scroll
   ============================================================ */

/* ---------------- entrees et sorties ---------------- */

/* fantome de cible, partage par fade, scale-in et pop-in.
   Sans lui on ne distingue pas ces trois entrees les unes des autres. */
.ghw{position:relative;display:grid;place-items:center}
.ghw .gh{position:absolute;width:34px;height:34px;border-radius:9px;border:1.5px dashed var(--s5)}
.ghw .sq{position:relative}

.d-fade .sq{animation:aFade 2.8s ease-in-out infinite}
@keyframes aFade{0%,8%{opacity:0}30%,62%{opacity:1}88%,100%{opacity:0}}

.d-slide-in .frame{width:118px;height:84px}
.d-slide-in .sq{width:28px;height:28px;top:28px;left:-32px;animation:aSlide 3s cubic-bezier(.2,.9,.25,1) infinite}
/* la sortie repart du cote d'ou l'element est venu, sinon la scene
   se lit comme un tapis roulant et non comme une entree */
@keyframes aSlide{0%{transform:translateX(0);opacity:0}18%,58%{transform:translateX(77px);opacity:1}82%,100%{transform:translateX(0);opacity:0}}

/* depart a .5 et non .3, plus proche du .92 recommande en production
   tout en restant lisible dans une vignette de 132px */
.d-scale-in .sq{animation:aScaleIn 2.8s cubic-bezier(.2,.8,.2,1) infinite}
@keyframes aScaleIn{0%,6%{transform:scale(.5);opacity:0}32%,64%{transform:scale(1);opacity:1}90%,100%{transform:scale(.5);opacity:0}}

/* depassement ramene a 1.14, la scene ne doit pas contredire sa propre
   consigne qui plafonne a 1.15 */
.d-pop-in .sq{animation:aPop 2.6s cubic-bezier(.2,.8,.2,1) infinite}
@keyframes aPop{0%,8%{transform:scale(0);opacity:0}28%{transform:scale(1.14);opacity:1}40%{transform:scale(.96)}50%,70%{transform:scale(1)}92%,100%{transform:scale(0);opacity:0}}

/* du contenu dans le bloc, sinon la scene se lit comme une barre de
   progression et non comme du contenu que l'on decouvre */
.d-reveal .rv{position:relative;width:104px;height:50px;border-radius:10px;background:var(--lime);
  display:flex;flex-direction:column;justify-content:center;gap:7px;padding:0 13px;
  animation:aReveal 3s cubic-bezier(.6,0,.2,1) infinite}
.d-reveal .rv i{display:block;height:7px;border-radius:4px;background:rgba(var(--on-accent-rgb),.45)}
.d-reveal .rv i:nth-child(2){width:76%}
.d-reveal .rv i:nth-child(3){width:52%}
@keyframes aReveal{0%,6%{clip-path:inset(0 100% 0 0)}40%,72%{clip-path:inset(0 0 0 0)}96%,100%{clip-path:inset(0 0 0 100%)}}

/* Deux animations distinctes, pas une seule jouee a l'envers. La barre
   de duree sous chaque carre rend l'asymetrie mesurable, la sortie
   tourne a environ 70 pour cent de l'entree. */
.d-enter-exit .row{gap:22px;align-items:flex-start}
.ee .c{display:flex;flex-direction:column;align-items:center;gap:9px}
.ee .lbl{font-style:normal}
.ee .dur{width:48px;height:4px;border-radius:2px;background:var(--s2);overflow:hidden}
.ee .dur b{display:block;height:100%;background:var(--accent);transform-origin:left;transform:scaleX(0)}
.d-enter-exit .in{animation:aEnter 3s cubic-bezier(.16,1,.3,1) infinite}
.d-enter-exit .out{animation:aExit 3s cubic-bezier(.5,0,.85,.4) infinite}
.ee .dur b{animation:aEeIn 3s linear infinite}
.ee .dur b.o{animation:aEeOut 3s linear infinite}
/* boucle sans couture, le cycle se termine invisible et au meme etat
   qu'il commence, le retour a zero ne se voit donc jamais */
@keyframes aEnter{0%,8%{transform:translateY(16px) scale(.86);opacity:0}30%,88%{transform:none;opacity:1}96%,100%{transform:none;opacity:0}}
@keyframes aExit{0%{transform:none;opacity:0}6%,46%{transform:none;opacity:1}61%,90%{transform:translateY(-16px) scale(.86);opacity:0}100%{transform:none;opacity:0}}
@keyframes aEeIn{0%,8%{transform:scaleX(0);opacity:1}30%,88%{transform:scaleX(1);opacity:1}96%,100%{transform:scaleX(1);opacity:0}}
@keyframes aEeOut{0%,46%{transform:scaleX(0);opacity:1}61%,88%{transform:scaleX(1);opacity:1}96%,100%{transform:scaleX(1);opacity:0}}

/* ---------------- sequencage et timing ---------------- */
/* Geometrie posee sur les CENTRES. Les jalons, le point et les
   etiquettes sont tous ramenes a leur axe par une marge negative ou
   un translate, sinon le point tombe a un ou deux pixels a cote. */
.kf{position:relative;width:158px;height:56px}
.kf .track{position:absolute;left:10px;right:10px;top:24px;height:2px;background:var(--s2);border-radius:2px}
.kf .k{position:absolute;top:17px;width:2px;height:16px;margin-left:-1px;background:var(--s5);border-radius:2px}
.kf .k1{left:10px}.kf .k3{left:148px}
/* le jalon du milieu s'allume au passage du curseur, c'est ce qui
   fait comprendre qu'un keyframe est un point d'arret declare */
.kf .k2{left:79px;animation:aKfMark 3s steps(1,end) infinite}
@keyframes aKfMark{0%,42%{background:var(--s5);height:16px;top:17px}44%,56%{background:var(--accent);height:24px;top:13px}58%,100%{background:var(--s5);height:16px;top:17px}}
.kf .dot{position:absolute;top:20px;left:10px;margin-left:-5px;animation:aKf 3s cubic-bezier(.4,0,.2,1) infinite}
.kf .lbl{position:absolute;top:38px;transform:translateX(-50%)}
.kf .l1{left:10px}.kf .l2{left:79px}.kf .l3{left:148px}
/* le curseur s'efface avant de revenir a gauche, sinon on voit un
   retour fouette qui n'a rien a voir avec le propos */
/* 0, 69 et 138 sont les ecarts exacts entre les centres des trois
   jalons places a 10, 79 et 148 */
@keyframes aKf{0%{transform:translateX(0);opacity:0}8%{opacity:1}44%,54%{transform:translateX(69px)}88%{transform:translateX(138px);opacity:1}96%,100%{transform:translateX(138px);opacity:0}}

.tw{position:relative;width:158px;height:50px}
.tw .sq{position:absolute;width:26px;height:26px;top:5px}
.tw .a{left:0;opacity:.4}.tw .b{right:0;opacity:.4}
/* nommer les deux etats declares, l'interpolation est ce qui se passe
   entre les deux et non le deplacement lui meme */
.tw .lbl{position:absolute;top:36px;font-style:normal}
.tw .la{left:0}.tw .lb2{right:0}
/* Les fantomes sont poses a des positions fixes le long du trajet et
   apparaissent au moment exact ou la tete de lecture les traverse.
   Une trainee en box-shadow serait rigide, identique a l'arret comme
   en mouvement, et pointerait dans le sens de la marche au retour. */
.tw .on{position:absolute;top:5px;width:26px;height:26px;border-radius:9px;background:var(--accent);opacity:0}
.tw .o1{left:22px;animation:aTwG1 3.4s linear infinite}
.tw .o2{left:44px;animation:aTwG2 3.4s linear infinite}
.tw .o3{left:66px;animation:aTwG3 3.4s linear infinite}
.tw .o4{left:88px;animation:aTwG4 3.4s linear infinite}
.tw .o5{left:110px;animation:aTwG5 3.4s linear infinite}
@keyframes aTwG1{0%,16%{opacity:0}21%,86%{opacity:.28}94%,100%{opacity:0}}
@keyframes aTwG2{0%,27%{opacity:0}32%,86%{opacity:.28}94%,100%{opacity:0}}
@keyframes aTwG3{0%,38%{opacity:0}43%,86%{opacity:.28}94%,100%{opacity:0}}
@keyframes aTwG4{0%,48%{opacity:0}53%,86%{opacity:.28}94%,100%{opacity:0}}
@keyframes aTwG5{0%,59%{opacity:0}64%,86%{opacity:.28}94%,100%{opacity:0}}
/* trajet lineaire, l'interpolation est le sujet, pas la courbe */
.tw .mv{left:0;z-index:2;animation:aTween 3.4s linear infinite}
@keyframes aTween{0%,6%{transform:translateX(0);opacity:0}12%{opacity:1}70%,86%{transform:translateX(132px);opacity:1}94%,100%{transform:translateX(132px);opacity:0}}

.stw{position:relative;display:flex;flex-direction:column;gap:9px;padding-bottom:16px}
.d-stagger .row{height:52px;align-items:flex-end;gap:9px}
.st i{display:block;width:12px;height:46px;border-radius:5px;background:var(--lime);transform-origin:bottom;animation:aStag 2.4s cubic-bezier(.2,.8,.2,1) infinite}
.st i:nth-child(2){animation-delay:.08s}.st i:nth-child(3){animation-delay:.16s}
.st i:nth-child(4){animation-delay:.24s}.st i:nth-child(5){animation-delay:.32s}
/* reglette de depart, les cinq points s'allument a intervalle constant,
   c'est le delta qui definit le stagger, pas la cascade elle meme */
.stw .rul{display:flex;gap:9px}
.stw .rul b{display:block;width:12px;height:4px;border-radius:2px;background:var(--s2);animation:aStagRul 2.4s steps(1,end) infinite}
.stw .rul b:nth-child(2){animation-delay:.08s}.stw .rul b:nth-child(3){animation-delay:.16s}
.stw .rul b:nth-child(4){animation-delay:.24s}.stw .rul b:nth-child(5){animation-delay:.32s}
.stw .lbl{position:absolute;left:0;bottom:0;font-style:normal;color:var(--accent);font-family:var(--mono)}
@keyframes aStag{0%,4%{transform:scaleY(.12);opacity:.3}34%,72%{transform:scaleY(1);opacity:1}96%,100%{transform:scaleY(.12);opacity:.3}}
@keyframes aStagRul{0%,3%{background:var(--s2)}5%,72%{background:var(--accent)}96%,100%{background:var(--s2)}}

/* Chaque element arrive d'une direction differente et tous se posent
   au meme instant. C'est ce qui separe l'orchestration du stagger,
   ou tout arrive du meme cote a intervalle constant. */
.orc{position:relative;width:150px;height:66px}
.orc .bar{position:absolute;left:0;width:76px;animation:aOrcBar 3s cubic-bezier(.16,1,.3,1) infinite}
.orc .b1{top:14px}
.orc .b2{top:32px;width:52px;animation:aOrcBar2 3s cubic-bezier(.16,1,.3,1) infinite;animation-delay:.07s}
.orc .sq{position:absolute;right:6px;top:12px;width:38px;height:38px;animation:aOrcSq 3s cubic-bezier(.16,1,.3,1) infinite;animation-delay:.04s}
.orc .dot{position:absolute;left:0;top:54px;animation:aOrcDot 3s cubic-bezier(.16,1,.3,1) infinite;animation-delay:.11s}
@keyframes aOrcBar{0%,8%{transform:translateX(-34px);opacity:0}32%,84%{transform:none;opacity:1}96%,100%{transform:none;opacity:0}}
@keyframes aOrcBar2{0%,8%{transform:translateX(-34px);opacity:0}32%,84%{transform:none;opacity:1}96%,100%{transform:none;opacity:0}}
@keyframes aOrcSq{0%,8%{transform:translateX(34px) scale(.7);opacity:0}32%,84%{transform:none;opacity:1}96%,100%{transform:none;opacity:0}}
@keyframes aOrcDot{0%,8%{transform:translateY(18px) scale(.4);opacity:0}32%,84%{transform:none;opacity:1}96%,100%{transform:none;opacity:0}}

.dl,.dur,.fm,.two{gap:12px}
.dl .row,.dur .row,.fm .row,.two .row{gap:9px}
.dl .track,.dur .track,.fm .track,.two .track{position:relative;display:block;width:92px;height:8px;border-radius:4px;background:var(--s2)}
.dl .track i,.dur .track i,.fm .track i,.two .track i{position:absolute;left:0;top:0;width:8px;height:8px;border-radius:4px;background:var(--lime);display:block}
/* Delai. La zone hachuree occupe exactement la portion de cycle
   pendant laquelle le second point ne bouge pas encore. */
.dl .wait{position:absolute;left:0;top:0;bottom:0;width:26px;border-radius:4px;display:block;
  background:repeating-linear-gradient(-45deg,var(--s4) 0 3px,transparent 3px 6px)}
.dl i{animation:aRunX 2.6s cubic-bezier(.3,0,.3,1) infinite}
.dl .late{animation-delay:.55s;opacity:.85}
@keyframes aRunX{0%,4%{transform:translateX(0)}46%,54%{transform:translateX(84px)}96%,100%{transform:translateX(0)}}

/* Duree. Meme cycle et meme depart pour les deux, seule la duree du
   trajet change. Deux durees d'animation differentes desynchroniseraient
   les deux points et la comparaison deviendrait illisible. */
.dur .fast{animation:aDurFast 3s cubic-bezier(.16,1,.3,1) infinite}
.dur .slow{animation:aDurSlow 3s cubic-bezier(.16,1,.3,1) infinite}
@keyframes aDurFast{0%,6%{transform:translateX(0)}26%,88%{transform:translateX(84px)}96%,100%{transform:translateX(0)}}
@keyframes aDurSlow{0%,6%{transform:translateX(0)}62%,88%{transform:translateX(84px)}96%,100%{transform:translateX(0)}}

/* Fill mode. forwards garde la derniere image, l'absence de fill
   renvoie l'element a son etat de base des la fin. */
.fm .keep{animation:aKeep 3s cubic-bezier(.2,.8,.2,1) infinite}
.fm .snap{animation:aSnap 3s cubic-bezier(.2,.8,.2,1) infinite}
@keyframes aKeep{0%{transform:translateX(0);opacity:0}8%{opacity:1}30%,88%{transform:translateX(84px);opacity:1}96%,100%{transform:translateX(84px);opacity:0}}
@keyframes aSnap{0%,6%{transform:translateX(0)}30%,60%{transform:translateX(84px)}61%,100%{transform:translateX(0)}}

/* Geometrie sur les centres. Cinq paliers a 10, 43, 76, 109 et 142,
   donc quatre bonds de 33px que steps(4) reproduit exactement. */
.stpz{position:relative;width:152px;height:44px}
.stpz .track{position:absolute;left:10px;right:10px;top:26px;height:2px;background:var(--s2)}
.stpz i{position:absolute;top:20px;width:2px;height:14px;margin-left:-1px;background:var(--s5);display:block}
.stpz i:nth-of-type(1){left:10px}.stp i:nth-of-type(2){left:43px}.stp i:nth-of-type(3){left:76px}
.stpz i:nth-of-type(4){left:109px}.stp i:nth-of-type(5){left:142px}
.stpz .dot{position:absolute;top:22px;left:10px;margin-left:-5px;animation:aStep 3s steps(4,end) infinite}
/* le point s'efface avant de revenir au premier palier, le saccade est
   voulu dans le trajet, pas dans le retour a zero */
@keyframes aStep{0%{transform:translateX(0);opacity:0}8%{transform:translateX(0);opacity:1}80%{transform:translateX(132px);opacity:1}96%,100%{transform:translateX(132px);opacity:0}}

/* ---------------- mouvement et transformations ---------------- */
/* Les deux axes sont nommes et le fantome marque l'origine, sinon on
   voit un carre qui se promene sans comprendre qu'on lit deux valeurs. */
.trs{position:relative;width:124px;height:88px}
.trs .ax{position:absolute;background:var(--s2)}
.trs .x{left:8px;right:0;bottom:12px;height:1px}
.trs .y{left:8px;top:0;bottom:12px;width:1px}
.trs .lbl{position:absolute;font-style:normal;font-family:var(--mono);color:var(--s6)}
.trs .lx{right:0;bottom:0}
.trs .ly{left:0;top:0}
.trs .gh{position:absolute;left:10px;bottom:18px;width:28px;height:28px;border-radius:8px;
  border:1.5px dashed var(--s5);display:block}
.trs .sq{position:absolute;left:10px;bottom:18px;width:28px;height:28px;animation:aTranslate 3.4s cubic-bezier(.4,0,.2,1) infinite}
@keyframes aTranslate{0%,6%{transform:translate(0,0)}28%,40%{transform:translate(70px,0)}60%,74%{transform:translate(70px,-38px)}94%,100%{transform:translate(0,0)}}

.scl{position:relative;display:grid;place-items:center;width:80px;height:80px}
.scl .ghost{position:absolute;width:64px;height:64px;border-radius:14px;border:1px dashed var(--s5)}
.scl .sq{animation:aScale 2.6s cubic-bezier(.4,0,.2,1) infinite}
@keyframes aScale{0%,100%{transform:scale(.55)}50%{transform:scale(1.85)}}

.ro{position:relative;display:grid;place-items:center}
.ro .sq{animation:aRotate 3.4s cubic-bezier(.5,0,.2,1) infinite}
.ro .dot{position:absolute;width:5px;height:5px;background:var(--on-accent)}
@keyframes aRotate{0%,8%{transform:rotate(0)}70%,100%{transform:rotate(360deg)}}

/* Le fantome donne le rectangle non cisaille et la scene revient a
   zero au repos, comme le dit sa propre consigne. */
.skw{position:relative;display:grid;place-items:center}
.skw .gh{position:absolute;width:56px;height:40px;border-radius:9px;border:1.5px dashed var(--s5);display:block}
.skw .sq{position:relative;width:56px;height:40px;animation:aSkew 3s ease-in-out infinite}
@keyframes aSkew{0%,8%{transform:skewX(0)}33%{transform:skewX(-19deg)}66%{transform:skewX(19deg)}92%,100%{transform:skewX(0)}}

/* Un vrai retournement a deux faces. Un simple basculement partageait
   ses keyframes avec Perspective, les deux cartes etaient identiques. */
.t3{perspective:460px}
.t3 .card7{position:relative;width:80px;height:58px;transform-style:preserve-3d;animation:aFlip 4.4s cubic-bezier(.4,0,.2,1) infinite}
.t3 .face{position:absolute;inset:0;border-radius:10px;backface-visibility:hidden;display:flex;flex-direction:column;justify-content:center;gap:7px;padding:0 13px}
.t3 .face.f{background:linear-gradient(150deg,var(--lime),var(--accent-2))}
.t3 .face.f i{display:block;height:7px;border-radius:4px;background:rgba(var(--on-accent-rgb),.42)}
.t3 .face.f i.short{width:56%}
.t3 .face.b{background:var(--card-2);border:1px solid var(--line-2);transform:rotateY(180deg);align-items:center}
.t3 .face.b .dot{width:14px;height:14px}
@keyframes aFlip{0%,14%{transform:rotateY(0)}56%,86%{transform:rotateY(180deg)}100%{transform:rotateY(360deg)}}

/* Meme rotation des deux cotes, seule la valeur de perspective change,
   et elle correspond enfin aux etiquettes affichees. */
.psp{gap:18px}
.pp{display:flex;flex-direction:column;align-items:center;gap:8px}
.pp .face{display:block;width:50px;height:50px;border-radius:9px;background:linear-gradient(150deg,var(--lime),var(--accent-2));animation:aPersp 4s cubic-bezier(.4,0,.2,1) infinite}
.pp.nrb{perspective:200px}.pp.far{perspective:1200px}
@keyframes aPersp{0%,100%{transform:rotateY(-34deg)}50%{transform:rotateY(34deg)}}

.tro{gap:20px}
.tlt{position:relative;display:grid;place-items:center;width:58px;height:58px}
.tlt .sq{width:30px;height:30px;animation:aScale2 2.8s cubic-bezier(.4,0,.2,1) infinite}
.tlt .pin{position:absolute;width:7px;height:7px;border-radius:50%;background:var(--ink);box-shadow:0 0 0 3px rgba(var(--ink-rgb),.2);z-index:3}
.tlt .lbl{position:absolute;bottom:-14px;white-space:nowrap}
.tlt.corner .sq{transform-origin:top left}
.tlt.corner .pin{top:14px;left:14px}
@keyframes aScale2{0%,100%{transform:scale(1)}50%{transform:scale(1.7)}}

/* Le meme popover s'ouvre alternativement depuis le bouton de gauche
   puis celui de droite, et son point d'ancrage suit. Avec un seul
   declencheur, la scene etait indistinguable d'un scale-in. */
.oa{position:relative;width:136px;height:100px}
.oa .btn{position:absolute;bottom:4px;width:44px;height:18px;border-radius:9px;background:var(--s3)}
.oa .b1{left:0;animation:aOaBtn 5s steps(1,end) infinite}
.oa .b2{right:0;animation:aOaBtn2 5s steps(1,end) infinite}
.oa .pop{position:absolute;bottom:28px;width:82px;height:50px;border-radius:11px;background:var(--lime)}
.oa .p1{left:0;transform-origin:bottom left;animation:aOaPop 5s cubic-bezier(.2,1.1,.3,1) infinite}
.oa .p2{right:0;transform-origin:bottom right;animation:aOaPop2 5s cubic-bezier(.2,1.1,.3,1) infinite}
@keyframes aOaPop{0%,4%{transform:scale(.08);opacity:0}18%,42%{transform:scale(1);opacity:1}52%,100%{transform:scale(.08);opacity:0}}
@keyframes aOaPop2{0%,54%{transform:scale(.08);opacity:0}68%,92%{transform:scale(1);opacity:1}98%,100%{transform:scale(.08);opacity:0}}
@keyframes aOaBtn{0%,2%{background:var(--s3)}4%,46%{background:var(--accent)}50%,100%{background:var(--s3)}}
@keyframes aOaBtn2{0%,52%{background:var(--s3)}54%,94%{background:var(--accent)}98%,100%{background:var(--s3)}}

/* ---------------- transitions entre etats ---------------- */
/* Les deux barres de la frise se chevauchent dans le temps. Un fade
   through, lui, ferait deux barres qui ne se touchent pas. */
.xf{position:relative;display:flex;flex-direction:column;align-items:center;gap:12px}
.xf .stack{position:relative;display:grid;place-items:center;width:58px;height:58px}
.xf .sq{position:absolute;width:52px;height:52px}
.xf .a{animation:aXfA 3s ease-in-out infinite}
.xf .b{animation:aXfB 3s ease-in-out infinite}
.xf .tl{position:relative;width:104px;height:10px}
.xf .tl i{position:absolute;top:0;height:5px;border-radius:3px;display:block}
.xf .fa{left:0;width:62px;background:var(--s5)}
.xf .fb{right:0;top:5px;width:62px;background:var(--accent)}
@keyframes aXfA{0%,20%{opacity:1}50%,70%{opacity:0}100%{opacity:1}}
@keyframes aXfB{0%,20%{opacity:0}50%,70%{opacity:1}100%{opacity:0}}

/* L'ancre du haut ne change jamais de taille, c'est elle qui relie
   l'avant et l'apres. Sans elle, la scene n'etait qu'un scale. */
.cont{display:grid;place-items:center}
.cont .box{display:flex;flex-direction:column;gap:6px;width:44px;height:44px;padding:7px;border-radius:10px;background:var(--lime);animation:aCont 3.4s cubic-bezier(.3,.8,.3,1) infinite}
.cont .anch{display:block;height:8px;width:22px;border-radius:4px;background:var(--on-accent);flex:none}
.cont .fill{display:block;flex:1;border-radius:4px;background:rgba(var(--on-accent-rgb),.3)}
@keyframes aCont{0%,10%{width:44px;height:44px}46%,72%{width:112px;height:70px}96%,100%{width:44px;height:44px}}

.mo .shape{display:block;width:52px;height:52px;background:var(--lime);animation:aMorph 4s cubic-bezier(.4,0,.2,1) infinite}
@keyframes aMorph{
  0%,8%{border-radius:10px;width:52px}
  32%,42%{border-radius:50%;width:52px}
  62%,72%{border-radius:26px;width:104px}
  94%,100%{border-radius:10px;width:52px}}

/* transform-origin top left, sinon la mise a l'echelle deplace aussi
   la boite et les 76px de translation ne tombent plus sur la cible.
   Cible a 76,8 pour une vignette partant de 0,30, donc translate(76,-22)
   et scale(74/30, 72/28). */
.se{position:relative;width:150px;height:88px}
.se .ghost{position:absolute;right:0;top:8px;width:74px;height:72px;border-radius:12px;border:1px dashed var(--s5)}
.se .thumb{position:absolute;left:0;top:30px;width:30px;height:28px;border-radius:7px;background:var(--lime);
  transform-origin:top left;animation:aShared 3.6s cubic-bezier(.3,.9,.3,1) infinite}
@keyframes aShared{0%,10%{transform:translate(0,0) scale(1);border-radius:7px}50%,74%{transform:translate(76px,-22px) scale(2.467,2.571);border-radius:4.8px}96%,100%{transform:translate(0,0) scale(1);border-radius:7px}}

/* Les deux voisins sont teintes autrement et portent un fantome de
   leur position d'origine, sinon on ne voit que la boite du milieu
   grandir et le sujet du terme, le deplacement des voisins, se perd. */
.la{position:relative;display:flex;gap:8px;align-items:center;padding-bottom:14px}
.la .sq{width:30px;height:30px}
.la .sq.g{background:var(--s4)}
.la .sq:nth-child(2){animation:aLayout 3.2s cubic-bezier(.3,.9,.3,1) infinite}
.la .sq:nth-child(3){animation:aLayoutN 3.2s cubic-bezier(.3,.9,.3,1) infinite}
.la::after{content:"";position:absolute;left:76px;bottom:0;width:30px;height:4px;border-radius:2px;
  border:1px dashed var(--s5);box-sizing:border-box}
@keyframes aLayout{0%,10%{width:30px}45%,72%{width:76px}96%,100%{width:30px}}
@keyframes aLayoutN{0%,10%{opacity:.55}45%,72%{opacity:1}96%,100%{opacity:.55}}

/* Le chevron du titre tourne, c'est le signal reel d'un accordeon
   et il distingue la scene d'une simple boite qui grandit. */
.acc{display:flex;flex-direction:column;gap:6px;width:112px}
.acc .hdd{position:relative;display:block;height:14px;border-radius:5px;background:var(--s3)}
.acc .hdd:first-child::after{content:"";position:absolute;right:5px;top:4px;width:5px;height:5px;
  border-right:1.5px solid var(--ink-2);border-bottom:1.5px solid var(--ink-2);
  transform:rotate(-45deg);animation:aAccCv 3.4s cubic-bezier(.3,.9,.3,1) infinite}
@keyframes aAccCv{0%,10%{transform:rotate(-45deg)}42%,72%{transform:rotate(45deg)}96%,100%{transform:rotate(-45deg)}}
.acc .panel{display:flex;flex-direction:column;gap:5px;overflow:hidden;height:0;animation:aAcc 3.4s cubic-bezier(.3,.9,.3,1) infinite}
.acc .panel i{display:block;height:7px;border-radius:4px;background:var(--lime);opacity:.85}
.acc .panel i:nth-child(2){width:78%}
.acc .panel i:nth-child(3){width:55%}
@keyframes aAcc{0%,10%{height:0;opacity:.2}42%,72%{height:29px;opacity:1}96%,100%{height:0;opacity:.2}}

.daw{display:flex;flex-direction:column;align-items:center;gap:11px}
.daw .arws{display:flex;gap:26px}
.daw .arws i{display:block;width:0;height:0;border-top:6px solid transparent;border-bottom:6px solid transparent}
.daw .ab{border-right:9px solid var(--s5);animation:aDaB 3.6s steps(1,end) infinite}
.daw .af{border-left:9px solid var(--s5);animation:aDaF 3.6s steps(1,end) infinite}
@keyframes aDaF{0%,12%{border-left-color:var(--s5)}14%,62%{border-left-color:var(--accent)}64%,100%{border-left-color:var(--s5)}}
@keyframes aDaB{0%,64%{border-right-color:var(--s5)}66%,96%{border-right-color:var(--accent)}98%,100%{border-right-color:var(--s5)}}
.daz{width:118px;height:82px}
.daz .pg{position:absolute;inset:0;border-radius:8px}
.daz .p1{background:var(--s3);animation:aDirA 3.6s cubic-bezier(.4,0,.2,1) infinite}
.daz .p2{background:var(--lime);animation:aDirB 3.6s cubic-bezier(.4,0,.2,1) infinite}
@keyframes aDirA{0%,12%{transform:translateX(0)}40%,62%{transform:translateX(-100%)}90%,100%{transform:translateX(0)}}
@keyframes aDirB{0%,12%{transform:translateX(100%)}40%,62%{transform:translateX(0)}90%,100%{transform:translateX(100%)}}

/* ---------------- scroll ---------------- */
/* Les blocs traversent reellement le seuil et se revelent en le
   franchissant. Avant, ils apparaissaient sur place et la ligne de
   seuil ne servait a rien. */
.srv{position:relative;width:120px;height:96px;overflow:hidden}
.srv .line{position:absolute;left:0;right:0;top:46px;height:1px;background:rgba(var(--accent-rgb),.45);z-index:3}
.srv .line::after{content:"";position:absolute;right:0;top:-4px;width:7px;height:7px;border-radius:4px;background:var(--accent)}
.srv i{position:absolute;left:8px;right:8px;display:block;height:16px;border-radius:6px;background:var(--lime);
  animation:aSrv 5s linear infinite}
.srv i:nth-of-type(1){top:96px}
.srv i:nth-of-type(2){top:120px;animation-delay:-.4s}
.srv i:nth-of-type(3){top:144px;animation-delay:-.8s}
.srv i:nth-of-type(4){top:168px;animation-delay:-1.2s}
/* le bloc est deja hors cadre en haut a la fin du cycle, l'opacite nulle
   aux deux bouts ferme la boucle sans rien changer a ce qu'on voit */
@keyframes aSrv{0%{transform:translateY(0);opacity:0}44%{opacity:0}52%,88%{opacity:1}100%{transform:translateY(-150px);opacity:0}}

.sdr{display:flex;align-items:center;gap:12px}
.sdr .frame{width:76px;height:88px}
.sdr .doc{position:absolute;left:8px;right:8px;top:6px;height:150px;border-radius:6px;background:repeating-linear-gradient(var(--s3) 0 8px,transparent 8px 15px);animation:aScrollDoc 3.4s linear infinite}
.sdr .prog{display:block;width:8px;height:78px;border-radius:4px;background:var(--s2);overflow:hidden;position:relative}
.sdr .prog i{position:absolute;left:0;right:0;top:0;height:100%;background:var(--lime);transform-origin:top;animation:aScrollProg 3.4s linear infinite}
/* Aller et retour, parce que la progression suit le scroll dans les
   deux sens. C'est ce qui separe ce terme d'une apparition au scroll,
   qui elle ne se joue qu'une fois. */
@keyframes aScrollDoc{0%,6%{transform:translateY(0)}54%,64%{transform:translateY(-72px)}96%,100%{transform:translateY(0)}}
@keyframes aScrollProg{0%,6%{transform:scaleY(.04)}54%,64%{transform:scaleY(1)}96%,100%{transform:scaleY(.04)}}

/* Parallaxe verticale, comme dans la vraie vie. Le fond parcourt 12px
   pendant que le premier plan en parcourt 34, meme duree, donc des
   vitesses differentes. */
.plx{width:124px;height:92px}
.plx .sky{position:absolute;inset:0;background:linear-gradient(var(--s1),var(--s0))}
.plx .back{position:absolute;left:6px;right:6px;top:14px;height:30px;border-radius:8px;background:var(--s3);animation:aPlxB 4.4s cubic-bezier(.4,0,.4,1) infinite}
.plx .front{position:absolute;left:16px;right:16px;top:52px;height:34px;border-radius:9px;background:var(--lime);animation:aPlxF 4.4s cubic-bezier(.4,0,.4,1) infinite}
@keyframes aPlxB{0%,8%{transform:translateY(0)}54%,64%{transform:translateY(-12px)}96%,100%{transform:translateY(0)}}
@keyframes aPlxF{0%,8%{transform:translateY(0)}54%,64%{transform:translateY(-34px)}96%,100%{transform:translateY(0)}}

/* Seule la zone centrale change. Le chrome qui reste en place est ce
   qui fait lire une navigation plutot qu'un contenu qui glisse. */
.pt{position:relative;width:124px;height:92px;display:flex;flex-direction:column}
.pt .chrome{background:var(--s4);flex:none;z-index:3}
.pt .chrome.tpp2{height:16px}
.pt .chrome.bot{height:18px;display:flex;align-items:center;justify-content:space-around}
.pt .chrome.bot i{display:block;width:12px;height:6px;border-radius:3px;background:var(--s6)}
.pt .chrome.bot i:first-child{background:var(--accent)}
.pt .win3{position:relative;flex:1;overflow:hidden}
.pt .pg{position:absolute;inset:0;padding:11px;display:flex;flex-direction:column;gap:7px}
.pt .pg i{display:block;height:9px;border-radius:4px;background:rgba(var(--ink-rgb),.25)}
.pt .pg i:last-child{width:60%}
.pt .a{background:var(--s2);animation:aPtA 3.6s cubic-bezier(.4,0,.2,1) infinite}
.pt .b{background:var(--lime);animation:aPtB 3.6s cubic-bezier(.4,0,.2,1) infinite}
.pt .b i{background:rgba(var(--on-accent-rgb),.35)}
@keyframes aPtA{0%,14%{transform:none;opacity:1}44%,66%{transform:translateX(-26%);opacity:0}92%,100%{transform:none;opacity:1}}
@keyframes aPtB{0%,14%{transform:translateX(100%);opacity:0}44%,66%{transform:none;opacity:1}92%,100%{transform:translateX(100%);opacity:0}}

/* Le navigateur croise deux captures de la page entiere, et par dessus
   il fait voyager le seul element portant un view-transition-name.
   C'est le fondu de fond qui separe ce terme d'un element partage. */
.vtz{position:relative;width:124px;height:92px;overflow:hidden}
.vtz .snap{position:absolute;inset:0;padding:10px;padding-top:40px;display:flex;flex-direction:column;gap:7px}
.vtz .snap i{display:block;height:8px;border-radius:4px;background:rgba(var(--ink-rgb),.28)}
.vtz .snap i:last-child{width:58%}
.vtz .old{background:var(--s2);animation:aVtOld 3.8s ease-in-out infinite}
.vtz .new{background:var(--s4);animation:aVtNew 3.8s ease-in-out infinite}
.vtz .fly{position:absolute;left:10px;top:10px;width:38px;height:24px;border-radius:6px;background:var(--lime);
  z-index:3;transform-origin:top left;animation:aVt 3.8s cubic-bezier(.3,.9,.3,1) infinite}
.vtz .tag{position:absolute;left:10px;top:36px;z-index:4;font:600 7.5px/1 var(--mono);color:var(--accent);font-style:normal;
  animation:aVtTag 3.8s ease infinite}
@keyframes aVtOld{0%,22%{opacity:1}52%,74%{opacity:0}100%{opacity:1}}
@keyframes aVtNew{0%,22%{opacity:0}52%,74%{opacity:1}100%{opacity:0}}
@keyframes aVt{0%,16%{transform:translate(0,0) scale(1)}54%,78%{transform:translate(56px,0) scale(1.789,1.083);border-radius:4px}96%,100%{transform:translate(0,0) scale(1)}}
@keyframes aVtTag{0%,10%{opacity:0}24%,80%{opacity:1}94%,100%{opacity:0}}
