/* ==========================================================================
   WEEKS FX v1 — bibliothèque d'effets pour weeks.one
   Zéro dépendance · aucune librairie · fonctionne sans build
   Respecte prefers-reduced-motion · allégée automatiquement sur mobile
   À poser dans : public/assets/front/css/weeks-fx.css
   ========================================================================== */

:root {
  --wfx-teal: #0097B2;
  --wfx-cyan: #29B6D8;
  --wfx-navy: #06094F;
  --wfx-ink: #090A2D;

  /* Même teinte que --wfx-teal, mais en canaux R,V,B : indispensable pour
     les rgba() (lueur, pastille, spinner, curseur). Sans cette variable ces
     effets écrivaient le teal EN DUR et échappaient à la surcharge navy des
     pages Weeks Pro — le teal y est strictement interdit. */
  --wfx-teal-rgb: 0, 151, 178;

  /* Courbes reprises du site (provider-v2.css) */
  --wfx-e: cubic-bezier(.22, 1, .36, 1);
  --wfx-e-back: cubic-bezier(.34, 1.4, .5, 1);

  /* Réglages globaux : baisse --wfx-dur pour tout accélérer d'un coup */
  --wfx-dur: .62s;
  --wfx-shift: 28px;
  --wfx-lift: -6px;
}

/* --------------------------------------------------------------------------
   1. APPARITION  (au chargement ET au scroll — même système)
   .wfx-up .wfx-down .wfx-left .wfx-right .wfx-zoom .wfx-blur .wfx-mask
   Options : data-wfx-delay="200"  data-wfx-repeat  data-wfx-step="80"
   -------------------------------------------------------------------------- */

/* Le masquage n'existe QUE si le JS a démarré (.wfx posé sur <html>).
   Sans JS : le contenu s'affiche normalement, rien n'est jamais invisible. */
.wfx .wfx-up,
.wfx .wfx-down,
.wfx .wfx-left,
.wfx .wfx-right,
.wfx .wfx-zoom,
.wfx .wfx-blur,
.wfx .wfx-mask {
  opacity: 0;
  transition:
    opacity var(--wfx-dur) var(--wfx-e),
    transform var(--wfx-dur) var(--wfx-e),
    filter var(--wfx-dur) var(--wfx-e),
    box-shadow .28s var(--wfx-e),
    -webkit-clip-path var(--wfx-dur) var(--wfx-e),
    clip-path var(--wfx-dur) var(--wfx-e);
}

.wfx .wfx-up    { transform: translateY(var(--wfx-shift)); }
.wfx .wfx-down  { transform: translateY(calc(var(--wfx-shift) * -1)); }
.wfx .wfx-left  { transform: translateX(calc(var(--wfx-shift) * -1)); }
.wfx .wfx-right { transform: translateX(var(--wfx-shift)); }
.wfx .wfx-zoom  { transform: scale(.9); }
.wfx .wfx-blur  { filter: blur(14px); transform: scale(1.03); }
.wfx .wfx-mask  { -webkit-clip-path: inset(100% 0 0 0); clip-path: inset(100% 0 0 0); transform: translateY(14px); }

/* État révélé. Chaque propriété n'est remise à zéro QUE sur l'effet qui l'a
   posée : un `transform:none` / `filter:none` / `clip-path` global écraserait
   les transform et filtres propres au site sur les mêmes éléments.
   Spécificité volontairement laissée à 0-2-0 (pas de préfixe `.wfx `) pour que
   `.wfx-lift:hover` (0-2-0, plus bas dans le fichier) puisse encore soulever
   la carte une fois celle-ci révélée. */
.wfx .wfx-up.wfx-on,
.wfx .wfx-down.wfx-on,
.wfx .wfx-left.wfx-on,
.wfx .wfx-right.wfx-on,
.wfx .wfx-zoom.wfx-on,
.wfx .wfx-blur.wfx-on,
.wfx .wfx-mask.wfx-on { opacity: 1; }

.wfx-up.wfx-on,
.wfx-down.wfx-on,
.wfx-left.wfx-on,
.wfx-right.wfx-on,
.wfx-zoom.wfx-on,
.wfx-mask.wfx-on { transform: none; }

.wfx-blur.wfx-on { filter: none; transform: none; }

/* Le clip-path n'appartient qu'à l'effet « masque ». Il découpe l'élément à sa
   border-box : laissé en place il rognait les box-shadow (cartes du site) et
   tout descendant qui déborde. On l'ouvre le temps de l'animation, puis le JS
   pose .wfx-unclip pour le retirer complètement. */
.wfx-mask.wfx-on { -webkit-clip-path: inset(0 0 0 0); clip-path: inset(0 0 0 0); }
.wfx-mask.wfx-unclip { -webkit-clip-path: none; clip-path: none; }

/* Cascade : le parent porte la classe, les enfants sortent l'un après l'autre */
.wfx .wfx-stagger > * {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity var(--wfx-dur) var(--wfx-e), transform var(--wfx-dur) var(--wfx-e);
}
.wfx .wfx-stagger.wfx-on > * { opacity: 1; transform: none; }

/* Titre découpé mot par mot (le JS pose les <span>) */
.wfx .wfx-split .wfx-w {
  display: inline-block;
  overflow: hidden;
  vertical-align: bottom;
  padding-bottom: .12em;
  margin-bottom: -.12em;
}
.wfx .wfx-split .wfx-w > i {
  display: inline-block;
  font-style: inherit;
  transform: translateY(115%);
  transition: transform .9s var(--wfx-e);
}
.wfx .wfx-split.wfx-on .wfx-w > i { transform: none; }

/* --------------------------------------------------------------------------
   2. SURVOL  (cartes, boutons, liens, images)
   -------------------------------------------------------------------------- */

/* Carte qui se soulève */
.wfx-lift {
  transition: transform .28s var(--wfx-e), box-shadow .28s var(--wfx-e);
}
@media (hover: hover) and (pointer: fine) {
  .wfx-lift:hover {
    transform: translateY(var(--wfx-lift));
    box-shadow: 0 18px 34px rgba(9, 10, 45, .16);
  }
}
.wfx-lift:active { transform: translateY(-2px) scale(.995); }

/* Reflet qui balaie (le « sheen » déjà utilisé sur le hero Weeks Pro) */
.wfx-sheen { position: relative; overflow: hidden; }
.wfx-sheen::after {
  content: "";
  position: absolute;
  top: -60%; left: 0;
  width: 42%; height: 220%;
  pointer-events: none;
  background: linear-gradient(75deg, transparent 38%, rgba(255, 255, 255, .55) 50%, transparent 62%);
  transform: translateX(-160%) skewX(-12deg);
  transition: transform .9s var(--wfx-e);
}
@media (hover: hover) and (pointer: fine) {
  .wfx-sheen:hover::after { transform: translateX(420%) skewX(-12deg); }
}
/* Version automatique, en boucle lente (héros, carte mise en avant) */
.wfx-sheen-auto::after { animation: wfx-sheen 7s ease-in-out 1.2s infinite; }
@keyframes wfx-sheen {
  0%   { transform: translateX(-160%) skewX(-12deg); }
  22%  { transform: translateX(420%) skewX(-12deg); }
  100% { transform: translateX(420%) skewX(-12deg); }
}

/* Lueur teal qui suit le curseur dans la carte */
.wfx-glow { position: relative; overflow: hidden; isolation: isolate; }
.wfx-glow::before {
  content: "";
  position: absolute;
  z-index: -1;
  width: 300px; height: 300px;
  left: var(--wfx-gx, 50%); top: var(--wfx-gy, 50%);
  margin: -150px 0 0 -150px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(var(--wfx-teal-rgb), .22), rgba(var(--wfx-teal-rgb), 0) 68%);
  opacity: 0;
  transition: opacity .3s ease;
  pointer-events: none;
}
.wfx-glow.wfx-glow-on::before { opacity: 1; }

/* Inclinaison 3D au pointeur (le JS écrit le transform) */
.wfx-tilt { transition: transform .25s var(--wfx-e); transform-style: preserve-3d; }

/* Bouton magnétique : il vient vers le curseur */
.wfx-magnet { transition: transform .28s var(--wfx-e); }

/* Soulignement qui se dessine */
.wfx-link { position: relative; text-decoration: none; }
.wfx-link::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -2px;
  height: 2px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: right center;
  transition: transform .4s var(--wfx-e);
}
@media (hover: hover) and (pointer: fine) {
  .wfx-link:hover::after { transform: scaleX(1); transform-origin: left center; }
}

/* Image qui zoome doucement dans son cadre */
.wfx-zoomimg { overflow: hidden; }
.wfx-zoomimg img,
.wfx-zoomimg .wfx-bg { transition: transform .9s var(--wfx-e); display: block; }
@media (hover: hover) and (pointer: fine) {
  .wfx-zoomimg:hover img,
  .wfx-zoomimg:hover .wfx-bg { transform: scale(1.07); }
}

/* Enfoncement au clic / au doigt (le feedback des apps Weeks) */
/* Classe doublée volontairement (spécificité 0-2-0) : certains boutons du site
   déclarent `transition: 1s all ease` via un sélecteur descendant (0-1-1) qui
   l'emportait sur un simple `.wfx-press`, transformant l'enfoncement en
   déformation molle d'une seconde. */
.wfx-press.wfx-press {
  transition: transform .14s var(--wfx-e-back);
  -webkit-tap-highlight-color: transparent;
}
.wfx-press.wfx-press:active { transform: scale(.955); }

/* Onde au clic */
.wfx-ripple { position: relative; overflow: hidden; -webkit-tap-highlight-color: transparent; }
.wfx-ripple > .wfx-rip {
  position: absolute;
  border-radius: 50%;
  background: currentColor;
  opacity: .22;
  transform: scale(0);
  pointer-events: none;
  animation: wfx-rip .62s var(--wfx-e) forwards;
}
@keyframes wfx-rip { to { transform: scale(1); opacity: 0; } }

/* --------------------------------------------------------------------------
   3. AU SCROLL  (parallaxe, compteurs, barres, en-tête, jauge de lecture)
   -------------------------------------------------------------------------- */

.wfx-parallax { will-change: transform; }

.wfx-bar { overflow: hidden; }
.wfx-bar > i {
  display: block;
  height: 100%;
  width: 0;
  border-radius: inherit;
  background: linear-gradient(90deg, var(--wfx-teal), var(--wfx-cyan));
  transition: width 1.1s var(--wfx-e);
}

#wfx-progress {
  position: fixed;
  top: 0; left: 0;
  height: 3px; width: 100%;
  transform: scaleX(0);
  transform-origin: 0 50%;
  background: linear-gradient(90deg, var(--wfx-teal), var(--wfx-cyan));
  /* Au-dessus des en-têtes (9 et 200) mais SOUS le menu mobile (999), les
     modales Bootstrap (1055) et les popovers de l'inscription pro (9999) :
     à 9999 la barre passait par-dessus les 3 px hauts de ces surcouches. */
  z-index: 300;
  pointer-events: none;
}

[data-wfx-header] {
  transition: transform .4s var(--wfx-e), box-shadow .3s ease, background-color .3s ease;
}
[data-wfx-header].wfx-hide  { transform: translateY(-102%); }
[data-wfx-header].wfx-stuck { box-shadow: 0 6px 22px rgba(9, 10, 45, .10); }

/* --------------------------------------------------------------------------
   4. CHARGEMENT & MICRO-RETOURS
   -------------------------------------------------------------------------- */

.wfx-skeleton {
  position: relative;
  overflow: hidden;
  background: #E7ECF2;
  border-radius: 10px;
  color: transparent !important;
}
.wfx-skeleton * { visibility: hidden; }
.wfx-skeleton::after {
  content: "";
  position: absolute;
  top: 0; left: 0;
  width: 100%; height: 100%;
  background: linear-gradient(90deg, rgba(255, 255, 255, 0), rgba(255, 255, 255, .9), rgba(255, 255, 255, 0));
  transform: translateX(-100%);
  animation: wfx-shim 1.4s infinite;
}
@keyframes wfx-shim { to { transform: translateX(100%); } }

.wfx-spin {
  display: inline-block;
  width: 22px; height: 22px;
  border-radius: 50%;
  border: 2.5px solid rgba(var(--wfx-teal-rgb), .22);
  border-top-color: var(--wfx-teal);
  animation: wfx-spin .7s linear infinite;
}
@keyframes wfx-spin { to { transform: rotate(360deg); } }

/* Bouton qui passe en « chargement » : WeeksFX.loading(btn, true) */
.wfx-load { position: relative; }
.wfx-load[data-wfx-loading] { pointer-events: none; color: transparent !important; }
.wfx-load[data-wfx-loading] > * { visibility: hidden; }
.wfx-load[data-wfx-loading]::after {
  content: "";
  position: absolute;
  top: 50%; left: 50%;
  width: 20px; height: 20px;
  margin: -10px 0 0 -10px;
  border-radius: 50%;
  border: 2.5px solid rgba(255, 255, 255, .35);
  border-top-color: #fff;
  animation: wfx-spin .7s linear infinite;
}

/* Pastille « en direct » (créneau libre, message reçu) */
.wfx-pulse { position: relative; }
.wfx-pulse::after {
  content: "";
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;
  border-radius: inherit;
  pointer-events: none;
  box-shadow: 0 0 0 0 rgba(var(--wfx-teal-rgb), .55);
  animation: wfx-pulse 2.2s infinite;
}
@keyframes wfx-pulse {
  0%   { box-shadow: 0 0 0 0 rgba(var(--wfx-teal-rgb), .55); }
  70%  { box-shadow: 0 0 0 10px rgba(var(--wfx-teal-rgb), 0); }
  100% { box-shadow: 0 0 0 0 rgba(var(--wfx-teal-rgb), 0); }
}

/* Erreur de formulaire : WeeksFX.shake(champ) */
.wfx-shaking { animation: wfx-shake .45s cubic-bezier(.36, .07, .19, .97) both; }
@keyframes wfx-shake {
  10%, 90% { transform: translateX(-2px); }
  20%, 80% { transform: translateX(4px); }
  30%, 50%, 70% { transform: translateX(-7px); }
  40%, 60% { transform: translateX(7px); }
}

/* Succès : WeeksFX.pop(el) — petit rebond de confirmation */
.wfx-popping { animation: wfx-pop .5s var(--wfx-e-back) both; }
@keyframes wfx-pop {
  0% { transform: scale(1); }
  38% { transform: scale(1.22); }
  100% { transform: scale(1); }
}

/* Favori : WeeksFX.heart(bouton) — envol de cœurs (comme dans l'app) */
.wfx-heart-p {
  position: absolute;
  pointer-events: none;
  font-size: 13px;
  line-height: 1;
  color: #E0245E;
  animation: wfx-heart .9s var(--wfx-e) forwards;
  z-index: 3;
}
@keyframes wfx-heart {
  0%   { opacity: 0; transform: translate(0, 0) scale(.4); }
  18%  { opacity: 1; }
  100% { opacity: 0; transform: translate(var(--wfx-dx, 0), -46px) scale(1.15); }
}

/* --------------------------------------------------------------------------
   5. TRANSITIONS DE PAGE  (<body data-wfx-page>)
   -------------------------------------------------------------------------- */

.wfx [data-wfx-page] { animation: wfx-pagein .5s var(--wfx-e) both; }
@keyframes wfx-pagein {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}
.wfx.wfx-leaving [data-wfx-page] {
  opacity: 0;
  transform: translateY(-8px);
  transition: opacity .26s ease, transform .26s var(--wfx-e);
  animation: none;
}

/* --------------------------------------------------------------------------
   6. EFFET SIGNATURE — héros cinématique
   .wfx-hero > .wfx-hero-layer (data-wfx-speed) + .wfx-hero-veil + contenu
   -------------------------------------------------------------------------- */

.wfx-hero { position: relative; overflow: hidden; isolation: isolate; }
.wfx-hero-layer {
  position: absolute;
  top: -9%; left: -5%;
  width: 110%; height: 120%;
  background-size: cover;
  background-position: center;
  will-change: transform;
  z-index: -2;
}
.wfx-hero-veil {
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;
  z-index: -1;
  background: linear-gradient(180deg, rgba(6, 9, 79, .12) 0%, rgba(6, 9, 79, .30) 45%, rgba(6, 9, 79, .82) 100%);
}
.wfx-hero-grain::before {
  content: "";
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;
  z-index: 0;
  pointer-events: none;
  opacity: .07;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* Curseur personnalisé (desktop uniquement) */
#wfx-cursor {
  position: fixed;
  top: 0; left: 0;
  width: 32px; height: 32px;
  margin: -16px 0 0 -16px;
  border-radius: 50%;
  border: 1.5px solid rgba(var(--wfx-teal-rgb), .85);
  background: rgba(var(--wfx-teal-rgb), .06);
  pointer-events: none;
  z-index: 9998;
  opacity: 0;
  transition: width .22s var(--wfx-e), height .22s var(--wfx-e), margin .22s var(--wfx-e),
              background-color .22s ease, opacity .22s ease, border-color .22s ease;
}
#wfx-cursor.wfx-c-big {
  width: 62px; height: 62px; margin: -31px 0 0 -31px;
  background: rgba(var(--wfx-teal-rgb), .14);
  border-color: rgba(var(--wfx-teal-rgb), .4);
}

/* Bandeau défilant infini */
.wfx-marquee { overflow: hidden; display: flex; }
.wfx-marquee > * {
  display: flex;
  flex: none;
  align-items: center;
  gap: inherit;
  padding-right: inherit;
  animation: wfx-march 30s linear infinite;
}
.wfx-marquee:hover > * { animation-play-state: paused; }
@keyframes wfx-march { to { transform: translateX(-100%); } }

/* --------------------------------------------------------------------------
   7. ALLÈGEMENT MOBILE  +  ACCESSIBILITÉ
   -------------------------------------------------------------------------- */

@media (max-width: 760px) {
  :root { --wfx-dur: .5s; --wfx-shift: 20px; }
  .wfx-hero-grain::before { display: none; }
  .wfx-glow::before { display: none; }
}

/* « Réduire les animations » activé sur l'appareil : tout est neutralisé,
   et surtout aucun élément ne reste invisible. */
@media (prefers-reduced-motion: reduce) {
  .wfx .wfx-up, .wfx .wfx-down, .wfx .wfx-left, .wfx .wfx-right,
  .wfx .wfx-zoom, .wfx .wfx-blur, .wfx .wfx-mask,
  .wfx .wfx-stagger > *, .wfx .wfx-split .wfx-w > i {
    opacity: 1 !important;
    transform: none !important;
    filter: none !important;
    -webkit-clip-path: none !important;
    clip-path: none !important;
    transition: none !important;
  }
  .wfx-mask.wfx-on, .wfx-mask.wfx-unclip { -webkit-clip-path: none !important; clip-path: none !important; }
  /* #wfx-progress était le SEUL élément que le mode automatique ajoutait sur
     toutes les pages, et il n'était neutralisé nulle part. */
  .wfx-sheen::after, .wfx-glow::before, .wfx-hero-grain::before,
  #wfx-cursor, #wfx-progress { display: none !important; }
  .wfx-pulse::after, .wfx-skeleton::after, .wfx-marquee > *, .wfx [data-wfx-page],
  .wfx-spin, .wfx-load[data-wfx-loading]::after { animation: none !important; }
  .wfx-bar > i { transition: none !important; }
  .wfx-lift, .wfx-press, .wfx-press.wfx-press, .wfx-magnet, .wfx-tilt, .wfx-zoomimg img,
  [data-wfx-header] { transition: none !important; transform: none !important; }
  html { scroll-behavior: auto !important; }
}

/* Impression / « Enregistrer en PDF » : rien ne doit manquer sur le papier.
   Sans ce bloc, tout ce qui n'avait jamais été amené à l'écran s'imprimait en
   blanc, puisque l'apparition n'est déclenchée qu'à l'entrée dans le viewport. */
@media print {
  .wfx .wfx-up, .wfx .wfx-down, .wfx .wfx-left, .wfx .wfx-right,
  .wfx .wfx-zoom, .wfx .wfx-blur, .wfx .wfx-mask,
  .wfx .wfx-stagger > *, .wfx .wfx-split .wfx-w > i {
    opacity: 1 !important;
    transform: none !important;
    filter: none !important;
    -webkit-clip-path: none !important;
    clip-path: none !important;
    transition: none !important;
    animation: none !important;
  }
  #wfx-progress, #wfx-cursor { display: none !important; }
}
