/* =========================================================================
   Campy Loader -- 21/10/2026
   Un randonneur marche vers la foret pendant que la page travaille.

   Pourquoi une scene et pas un spinner : un spinner dit « ca tourne »,
   il ne dit pas « ou on en est ». Ici la scene avance, le message change
   a chaque etape reelle (CampyLoader.step()), et l'arrivee se joue quand
   la reponse est la. L'attente devient lisible.

   Tout est en CSS/SVG : aucune dependance, aucune image a telecharger,
   et le squelette rendu par PHP s'anime avant meme que le JS arrive.
   ========================================================================= */

.cy-loader{
  --cyl-ink:#1f3d2a;
  --cyl-brand:#244d31;
  --cyl-accent:#e07a35;
  --cyl-line:#dfe6dd;
  --cyl-sky-a:#eaf3ec;
  --cyl-sky-b:#f8fbf8;
  --cyl-far:#cfe0d2;
  --cyl-mid:#9dc1a6;
  --cyl-near:#4e7a59;
  --cyl-ground:#2f5b3c;
  display:flex;flex-direction:column;align-items:center;gap:16px;
  width:100%;margin:0 auto;padding:26px 18px;box-sizing:border-box;
  text-align:center;color:var(--cyl-ink);
}

/* --- La scene ----------------------------------------------------------- */
.cy-loader__scene{
  display:block;width:100%;max-width:320px;height:auto;
  border-radius:16px;overflow:hidden;
  box-shadow:0 10px 30px rgba(31,61,42,.10);
}
.cy-loader__scene svg{display:block;width:100%;height:auto}

/* Defilement : chaque calque contient DEUX copies cote a cote (largeur 240
   chacune), on translate de -240 puis on recommence -> boucle invisible.
   Vitesses differentes = parallaxe = sensation de profondeur. */
@keyframes cy-scroll{from{transform:translateX(0)}to{transform:translateX(-240px)}}
.cy-l-far{animation:cy-scroll 22s linear infinite}
.cy-l-mid{animation:cy-scroll 11s linear infinite}
.cy-l-near{animation:cy-scroll 5.5s linear infinite}
.cy-l-ground{animation:cy-scroll 3.2s linear infinite}

/* Le randonneur reste au centre : c'est le decor qui defile.
   transform-box:fill-box -> transform-origin exprime dans la boite de la
   forme elle-meme, sinon l'origine serait celle du viewBox entier. */
.cy-l-walker{transform-box:view-box;transform-origin:118px 100px;
  animation:cy-bob .46s ease-in-out infinite}
@keyframes cy-bob{0%,100%{transform:translateY(0)}50%{transform:translateY(-1.6px)}}

.cy-l-leg{transform-box:view-box;transform-origin:118px 84px}
.cy-l-leg--a{animation:cy-leg-a .92s ease-in-out infinite}
.cy-l-leg--b{animation:cy-leg-b .92s ease-in-out infinite}
@keyframes cy-leg-a{0%,100%{transform:rotate(24deg)}50%{transform:rotate(-24deg)}}
@keyframes cy-leg-b{0%,100%{transform:rotate(-24deg)}50%{transform:rotate(24deg)}}

.cy-l-arm{transform-box:view-box;transform-origin:118px 72px;
  animation:cy-leg-b .92s ease-in-out infinite}
.cy-l-arm--back{animation-name:cy-leg-a}

/* Le sac a dos encaisse le pas avec un temps de retard : c'est ce decalage
   qui fait lire « charge » plutot que « bloc colle au dos ». */
.cy-l-pack{transform-box:view-box;transform-origin:114px 74px;
  animation:cy-pack .46s ease-in-out infinite .06s}
@keyframes cy-pack{0%,100%{transform:translateY(0) rotate(0)}50%{transform:translateY(.9px) rotate(-1.4deg)}}

.cy-l-sun{transform-box:view-box;transform-origin:196px 26px;
  animation:cy-sun 4s ease-in-out infinite}
@keyframes cy-sun{0%,100%{transform:scale(1);opacity:.9}50%{transform:scale(1.06);opacity:1}}

.cy-l-bird{transform-box:view-box;
  animation:cy-bird 9s linear infinite}
.cy-l-bird--2{animation-duration:12s;animation-delay:-4s}
@keyframes cy-bird{
  from{transform:translate(250px,0)}
  to{transform:translate(-40px,-10px)}
}

.cy-l-dust{animation:cy-dust 1.1s ease-out infinite}
@keyframes cy-dust{0%{opacity:.55;transform:translate(0,0) scale(.6)}100%{opacity:0;transform:translate(-16px,-3px) scale(1.5)}}

/* --- Arrivee : la scene se pose, la tente apparait ----------------------- */
.cy-loader.is-arrived .cy-l-far,
.cy-loader.is-arrived .cy-l-mid,
.cy-loader.is-arrived .cy-l-near,
.cy-loader.is-arrived .cy-l-ground{animation-play-state:paused}
.cy-loader.is-arrived .cy-l-leg,
.cy-loader.is-arrived .cy-l-arm,
.cy-loader.is-arrived .cy-l-walker,
.cy-loader.is-arrived .cy-l-pack,
.cy-loader.is-arrived .cy-l-dust{animation:none;transform:none}
.cy-l-camp{opacity:0;transform-box:view-box;transform-origin:176px 100px}
.cy-loader.is-arrived .cy-l-camp{animation:cy-camp .5s cubic-bezier(.2,1.3,.4,1) forwards}
@keyframes cy-camp{from{opacity:0;transform:translateY(6px) scale(.7)}to{opacity:1;transform:none}}

/* --- Textes ------------------------------------------------------------- */
.cy-loader__title{margin:0;font-size:17px;font-weight:700;letter-spacing:-.2px;color:var(--cyl-ink)}
.cy-loader__msg{margin:0;min-height:20px;font-size:14px;line-height:1.5;color:#5d6d60}
.cy-loader__msg b{font-weight:600;color:var(--cyl-brand)}
/* Le message glisse au lieu de sauter : on voit qu'une etape a change. */
.cy-loader__msg span{display:inline-block;animation:cy-msg .42s ease-out}
@keyframes cy-msg{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}

/* --- Progression -------------------------------------------------------- */
.cy-loader__bar{
  width:100%;max-width:280px;height:5px;border-radius:999px;
  background:var(--cyl-line);overflow:hidden;
}
.cy-loader__bar i{
  display:block;height:100%;width:100%;border-radius:999px;
  background:linear-gradient(90deg,var(--cyl-brand),#49885c);
  transform:scaleX(var(--cyl-progress,.06));transform-origin:left center;
  transition:transform .6s cubic-bezier(.3,.8,.3,1);
}
.cy-loader.is-arrived .cy-loader__bar i{background:linear-gradient(90deg,var(--cyl-brand),var(--cyl-accent))}

/* --- Variante « inline » : dans un bouton, une ligne, une carte --------- */
.cy-loader--inline{
  flex-direction:row;gap:12px;padding:10px 0;text-align:left;justify-content:flex-start;
}
.cy-loader--inline .cy-loader__scene{width:72px;flex:0 0 72px;border-radius:10px;box-shadow:none}
.cy-loader--inline .cy-loader__title{font-size:14px}
.cy-loader--inline .cy-loader__msg{font-size:13px;min-height:0}
.cy-loader--inline .cy-loader__bar{max-width:160px;height:3px}

/* --- Variante « overlay » : par-dessus un bloc qui se recalcule --------- */
.cy-loader--overlay{
  position:absolute;inset:0;z-index:5;justify-content:center;
  background:rgba(255,255,255,.86);backdrop-filter:blur(3px);
  border-radius:inherit;animation:cy-fade .25s ease-out;
  padding:14px;gap:10px;overflow:hidden;
}
.cy-loader--overlay .cy-loader__scene{max-width:210px;box-shadow:none}
.cy-loader--overlay .cy-loader__title{font-size:15px}
.cy-loader--overlay .cy-loader__msg{font-size:13px}
@keyframes cy-fade{from{opacity:0}to{opacity:1}}
.cy-loader-host{position:relative}

@media(max-width:600px){
  .cy-loader{padding:20px 14px;gap:13px}
  .cy-loader__scene{max-width:240px}
  .cy-loader__title{font-size:15px}
  .cy-loader__msg{font-size:13px}
  .cy-loader--inline .cy-loader__scene{width:56px;flex-basis:56px}
}

/* --- Mouvement reduit : la scene reste, le mouvement part --------------- */
@media(prefers-reduced-motion:reduce){
  .cy-loader *{animation:none!important;transition:none!important}
  .cy-loader__bar i{transform:scaleX(1);opacity:.5}
  .cy-l-camp{opacity:1}
}


/* =========================================================================
   Scenes « sur mesure » -- une par etape reelle du parcours.
   Chaque scene partage l horizon et la palette : l enchainement doit lire
   comme un seul film, pas comme cinq illustrations differentes.
   ========================================================================= */

.cy-loader__body{display:flex;flex-direction:column;gap:8px;align-items:center;width:100%}
.cy-loader--inline .cy-loader__body{align-items:flex-start;gap:4px}

/* Transition d une scene a l autre : la nouvelle arrive, l ancienne s efface.
   Jamais de coupe seche -- une coupe se lit comme un bug. */
.cy-loader__scene{position:relative}
.cy-loader__scene>svg{display:block;width:100%;height:auto}
.cy-loader__scene>svg.is-leaving{position:absolute;inset:0;animation:cy-scene-out .4s ease-in forwards}
.cy-loader__scene>svg.is-entering{animation:cy-scene-in .4s ease-out}
@keyframes cy-scene-out{to{opacity:0;transform:scale(1.04)}}
@keyframes cy-scene-in{from{opacity:0;transform:scale(.97)}}

/* --- Scene « pack » : le sac se remplit -------------------------------- */
/* Le niveau suit --cyl-progress : ce n est pas une boucle decorative, c est
   l avancement reel. Le client voit son sac se remplir. */
.cy-s-fill{
  transform-box:view-box;transform-origin:0 99px;
  transform:scaleY(calc(.1 + var(--cyl-progress,0) * .9));
  transition:transform .7s cubic-bezier(.3,.8,.3,1);
}
/* L objet tombe et passe DERRIERE la paroi du sac : il disparait dedans, il
   ne s efface pas dans le vide. C est l ordre de dessin qui fait l effet. */
.cy-s-item{
  transform-box:view-box;transform-origin:120px 60px;opacity:0;
  animation:cy-item 3.6s cubic-bezier(.4,0,.8,.55) infinite;
}
@keyframes cy-item{
  0%{transform:translateY(-44px) rotate(-20deg);opacity:0}
  9%{opacity:1}
  52%{transform:translateY(12px) rotate(8deg);opacity:1}
  64%,100%{transform:translateY(22px) rotate(11deg);opacity:1}
}
.cy-s-flap{transform-box:view-box;transform-origin:120px 74px;animation:cy-flap 3.6s ease-in-out infinite}
@keyframes cy-flap{0%,100%{transform:rotate(0)}45%{transform:rotate(-5deg)}}

/* --- Scene « map » : on cherche ---------------------------------------- */
.cy-s-route{animation:cy-ants 1.1s linear infinite}
@keyframes cy-ants{to{stroke-dashoffset:-14}}
.cy-s-pin{transform-box:view-box;transform-origin:center;animation:cy-pin 1.8s ease-out infinite;opacity:.25}
@keyframes cy-pin{0%{opacity:.25}12%{opacity:1}40%{opacity:1}70%,100%{opacity:.25}}
.cy-s-lens{transform-box:view-box;animation:cy-lens 3.4s ease-in-out infinite}
@keyframes cy-lens{
  0%{transform:translate(110px,78px)}
  35%{transform:translate(132px,60px)}
  70%{transform:translate(152px,66px)}
  100%{transform:translate(110px,78px)}
}
.cy-s-point{transform-box:view-box;transform-origin:77px 72px;animation:cy-point 3.4s ease-in-out infinite}
@keyframes cy-point{0%,100%{transform:rotate(4deg)}50%{transform:rotate(-7deg)}}

/* --- Scene « camp » : c est fait ---------------------------------------- */
.cy-s-star{animation:cy-star 3.2s ease-in-out infinite}
@keyframes cy-star{0%,100%{opacity:.25}50%{opacity:.95}}
.cy-s-flame{transform-box:view-box;transform-origin:169px 96px}
.cy-s-flame--1{animation:cy-flame .62s ease-in-out infinite}
.cy-s-flame--2{animation:cy-flame .48s ease-in-out infinite reverse}
@keyframes cy-flame{
  0%,100%{transform:scale(1,1) skewX(0)}
  30%{transform:scale(.9,1.15) skewX(5deg)}
  65%{transform:scale(1.08,.92) skewX(-5deg)}
}
/* La colonne d etincelles penche avec le courant d air ; chaque etincelle
   monte en plus a son propre rythme. Deux mouvements, pas un. */
.cy-s-sparks{transform-box:view-box;animation:cy-draught 6s ease-in-out infinite}
@keyframes cy-draught{0%,100%{transform:translateX(0)}50%{transform:translateX(3.5px)}}
.cy-s-spark{transform-box:view-box;opacity:0;animation:cy-spark 2.2s ease-out infinite}
@keyframes cy-spark{
  0%{transform:translate(0,0) scale(1);opacity:0}
  12%{opacity:.95}
  100%{transform:translate(-6px,-34px) scale(.3);opacity:0}
}

/* --- Scene « lantern » : quelqu un reflechit ---------------------------- */
.cy-s-lantern{transform-box:view-box;transform-origin:132px 28px;animation:cy-swing 3.6s ease-in-out infinite}
@keyframes cy-swing{0%,100%{transform:rotate(3.2deg)}50%{transform:rotate(-3.2deg)}}
.cy-s-glow{transform-box:view-box;transform-origin:132px 48px;animation:cy-glow 2.4s ease-in-out infinite}
@keyframes cy-glow{0%,100%{opacity:.12;transform:scale(.92)}50%{opacity:.26;transform:scale(1.06)}}
.cy-s-fly{transform-box:view-box;animation:cy-fly 6s ease-in-out infinite}
@keyframes cy-fly{
  0%{transform:translate(0,0);opacity:0}
  15%{opacity:.9}
  35%{transform:translate(10px,-9px)}
  60%{transform:translate(-6px,-18px);opacity:.75}
  85%{transform:translate(8px,-26px);opacity:.25}
  100%{transform:translate(0,-32px);opacity:0}
}

/* Echec : la scene se fige et vire au gris -- on ne fait pas semblant. */
.cy-loader.is-failed .cy-loader__scene{filter:grayscale(.75);opacity:.6}
.cy-loader.is-failed *{animation-play-state:paused!important}
.cy-loader.is-failed .cy-loader__msg{color:#9a4d3a}
.cy-loader.is-failed .cy-loader__bar i{background:#c47a66}


/* --- Scene « list » : on recompte, ligne a ligne ------------------------ */
.cy-s-check{stroke-dasharray:12;stroke-dashoffset:12;animation:cy-check 4s ease-out infinite}
@keyframes cy-check{0%{stroke-dashoffset:12}10%,78%{stroke-dashoffset:0}88%,100%{stroke-dashoffset:12}}

/* --- Scene « calendar » : les nuits s allument, le ciel bascule --------- */
.cy-s-night{opacity:.25;animation:cy-night 3.4s ease-out infinite}
@keyframes cy-night{0%{opacity:.25}14%,74%{opacity:1}88%,100%{opacity:.25}}
.cy-s-day{animation:cy-orb 5.4s ease-in-out infinite}
.cy-s-night-orb{opacity:0;animation:cy-orb 5.4s ease-in-out infinite reverse}
@keyframes cy-orb{0%,38%{opacity:1}50%,88%{opacity:0}100%{opacity:1}}

/* --- Scene « jeep » : la piste n est pas lisse ------------------------- */
.cy-s-rig{transform-box:view-box;animation:cy-rig .5s ease-in-out infinite}
@keyframes cy-rig{0%,100%{transform:translateY(0) rotate(0)}50%{transform:translateY(-.9px) rotate(-.4deg)}}
.cy-s-wheel{transform-box:view-box;transform-origin:var(--cx) var(--cy);animation:cy-spin .55s linear infinite}
/* Les deux roues ne passent pas sur la meme pierre au meme instant. */
.cy-s-wheel--2{animation-delay:-.18s}
@keyframes cy-spin{to{transform:rotate(360deg)}}
.cy-s-dustpuff{transform-box:view-box;opacity:0;animation:cy-puff 1.3s ease-out infinite}
@keyframes cy-puff{0%{opacity:.5;transform:translate(0,0) scale(.5)}100%{opacity:0;transform:translate(-20px,-5px) scale(1.7)}}

/* --- Scene « boat » : l eau bouge, la rame suit ------------------------ */
.cy-s-wave{animation:cy-wave 3.4s linear infinite}
@keyframes cy-wave{from{transform:translateX(0)}to{transform:translateX(-48px)}}
.cy-s-boat{transform-box:view-box;transform-origin:120px 96px;animation:cy-float 2.6s ease-in-out infinite}
@keyframes cy-float{0%,100%{transform:translateY(0) rotate(-1.4deg)}50%{transform:translateY(-2.2px) rotate(1.4deg)}}
.cy-s-oar{transform-box:view-box;transform-origin:118px 84px;animation:cy-row 1.6s ease-in-out infinite}
@keyframes cy-row{0%,100%{transform:rotate(-16deg)}50%{transform:rotate(16deg)}}

/* --- Scene « friends » : chacun arrive, puis chacun parle -------------- */
.cy-s-buddy{transform-box:view-box;animation:cy-buddy 2.4s ease-in-out infinite}
@keyframes cy-buddy{0%,100%{transform:translateY(0)}50%{transform:translateY(-1.8px)}}
.cy-s-bubble{transform-box:view-box;opacity:0;animation:cy-bubble 3.6s ease-out infinite}
@keyframes cy-bubble{
  0%{opacity:0;transform:translateY(5px) scale(.7)}
  10%{opacity:1;transform:translateY(0) scale(1)}
  62%{opacity:1}
  76%,100%{opacity:0;transform:translateY(-4px) scale(.9)}
}

/* --- Scene « fire » : la marmite frissonne ----------------------------- */
.cy-s-pot{transform-box:view-box;transform-origin:120px 54px;animation:cy-swing 4.4s ease-in-out infinite}

/* --- Scene « summit » : le drapeau tient, le bras se leve -------------- */
.cy-s-flag{transform-box:view-box;transform-origin:139px 32px;animation:cy-wavef 1.9s ease-in-out infinite}
@keyframes cy-wavef{0%,100%{transform:skewY(0) scaleX(1)}35%{transform:skewY(5deg) scaleX(.94)}70%{transform:skewY(-4deg) scaleX(1.03)}}
.cy-s-raise{transform-box:view-box;transform-origin:120px 10px;animation:cy-raise 2.6s ease-in-out infinite}
@keyframes cy-raise{0%,100%{transform:rotate(0)}50%{transform:rotate(-16deg)}}

/* --- Scene « id » : la barre de scan descend, le tampon tombe ---------- */
.cy-s-scan{transform-box:view-box;animation:cy-scan 2.8s cubic-bezier(.5,0,.5,1) infinite}
@keyframes cy-scan{0%{transform:translateY(0)}50%{transform:translateY(39px)}100%{transform:translateY(0)}}
.cy-s-stamp{transform-box:view-box;transform-origin:146px 84px;opacity:0;animation:cy-stamp 2.8s ease-out infinite}
@keyframes cy-stamp{0%,55%{opacity:0;transform:scale(.4)}70%{opacity:1;transform:scale(1.15)}78%{transform:scale(1)}92%,100%{opacity:0;transform:scale(1)}}


/* --- Variante « fixed » : l envoi de la demande ------------------------- */
.cy-loader--fixed{
  position:fixed;inset:0;z-index:9999;justify-content:center;
  background:rgba(247,250,247,.95);backdrop-filter:blur(5px);
  animation:cy-fade .3s ease-out;
}
.cy-loader--fixed .cy-loader__scene{max-width:360px}
.cy-loader--fixed .cy-loader__title{font-size:21px}
.cy-loader--fixed .cy-loader__msg{font-size:15px}
@media(max-width:600px){.cy-loader--fixed .cy-loader__scene{max-width:280px}}
