/* ============================================================
   site-motion.css — couche d'animation du portfolio public (2026-10-11).
   Pilotée par assets/js/site-motion.js, chargée après site-v3.css.
   Esprit : sobre et maîtrisé — les textes sortent du flou mot par mot, les
   blocs arrivent en fondu flouté, les cartes suivent le curseur (halo +
   légère inclinaison), les boutons sont « aimantés ».
   Tout est coupé sous prefers-reduced-motion et sous le mode « Stopper les
   animations » de la console d'accessibilité (body.a11y-stop) : le JS ne
   s'exécute pas, et les états initiaux masqués ne sont jamais posés.
   ============================================================ */

body.ng-site:not(.ng-admin) {
  --m-ease: cubic-bezier(.16, 1, .3, 1);       /* sortie longue, très douce */
  --m-ease-soft: cubic-bezier(.2, .7, .2, 1);
  --m-spot: rgba(47, 76, 240, .09);
  --m-spot-edge: rgba(47, 76, 240, .22);
}
html:not(.light) body.ng-site:not(.ng-admin) {
  --m-spot: rgba(120, 140, 255, .10);
  --m-spot-edge: rgba(147, 163, 255, .28);
}

/* ── 1. Entrées de page : fondu + flou au lieu du simple glissé ── */
@keyframes mBlurUp {
  from { opacity: 0; filter: blur(14px); transform: translateY(18px); }
  to   { opacity: 1; filter: none; transform: none; }
}
html.m-on body.ng-site:not(.ng-admin) .ng-fade-up { animation-name: mBlurUp; animation-duration: 1.1s; animation-timing-function: var(--m-ease); }

/* ── 2. Apparition au défilement ([data-reveal], scroll-reveal.js) ── */
html.m-on body.ng-site:not(.ng-admin) [data-reveal] {
  filter: blur(10px);
  transform: translateY(28px) scale(.985);
  transition: opacity 1s var(--m-ease), transform 1.1s var(--m-ease), filter 1s var(--m-ease), background .25s;
}
html.m-on body.ng-site:not(.ng-admin) [data-reveal].ng-reveal-in { filter: none; }

/* ── 3. Titres : mots qui sortent du flou ([data-split], auto sur les titres) ── */
.m-split .m-w { display: inline-block; white-space: pre; }
html.m-on .m-split .m-w {
  opacity: 0; filter: blur(12px); transform: translateY(.32em) rotate(1.5deg);
  transition: opacity .9s var(--m-ease), filter .9s var(--m-ease), transform 1.1s var(--m-ease);
  transition-delay: calc(var(--m-base, 0ms) + var(--i, 0) * 55ms);
}
html.m-on .m-split.m-in .m-w { opacity: 1; filter: none; transform: none; }
/* Le titre découpé porte sa propre animation : on retire le fondu global */
html.m-on body.ng-site .ng-fade-up.m-split { animation: none; opacity: 1; }

/* Paragraphe « lu au défilement » : les mots s'allument au fil du scroll */
html.m-on .m-scrub .m-w { opacity: .16; filter: blur(1.5px); transition: opacity .35s ease, filter .35s ease; transition-delay: 0s; transform: none; }
html.m-on .m-scrub .m-w.m-lit { opacity: 1; filter: none; }

/* Le trait des sur-titres se dessine à l'apparition */
html.m-on .v3-kicker::after { width: 0; transition: width 1.1s var(--m-ease) .2s; }
html.m-on .v3-kicker.m-in::after { width: 40px; }

/* ── 4. Barre de progression de lecture ── */
.m-progress {
  position: fixed; top: 0; left: 0; right: 0; height: 2px; z-index: 10010; pointer-events: none;
  transform-origin: 0 50%; transform: scaleX(0);
  background: linear-gradient(90deg, var(--v3-blue, #2f4cf0), #8f7bff 60%, #3ddc97);
}

/* ── 5. Halo qui suit le curseur dans le hero ── */
#hero { position: relative; }
#hero > :not(.m-aura) { position: relative; z-index: 1; }
.m-aura {
  position: absolute; z-index: 0; top: 0; left: 0; width: 560px; height: 560px; margin: -280px 0 0 -280px;
  border-radius: 50%; pointer-events: none; opacity: 0; transition: opacity .8s ease;
  background: radial-gradient(circle, rgba(47,76,240,.16), rgba(143,123,255,.08) 40%, transparent 68%);
  filter: blur(20px); will-change: transform;
}
html:not(.light) .m-aura { background: radial-gradient(circle, rgba(77,107,255,.22), rgba(143,123,255,.08) 40%, transparent 68%); }
#hero.m-aura-on .m-aura { opacity: 1; }

/* Visuel du hero : inclinaison 3D + profondeur des pastilles */
html.m-on .v3-visual { transform: perspective(1100px) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg)); transition: transform .9s var(--m-ease); will-change: transform; }
html.m-on .v3-visual.m-tilting { transition: transform .15s linear; }
html.m-on .v3-visual-portrait { translate: calc(var(--px, 0) * -10px) calc(var(--py, 0) * -6px); transition: translate .9s var(--m-ease); }
html.m-on .v3-visual-chip, html.m-on .v3-visual-card { translate: calc(var(--px, 0) * 16px) calc(var(--py, 0) * 12px); transition: translate .9s var(--m-ease); }
html.m-on .v3-visual-glow { translate: calc(var(--px, 0) * 24px) calc(var(--py, 0) * 18px); transition: translate 1.2s var(--m-ease); }
/* Le visuel entre en scène comme une carte qu'on pose */
@keyframes mVisualIn {
  from { opacity: 0; filter: blur(18px); transform: perspective(1100px) rotateX(8deg) translateY(40px) scale(.96); }
  to   { opacity: 1; filter: none; transform: perspective(1100px) rotateX(0) rotateY(0); }
}
html.m-on .v3-visual.m-enter { animation: mVisualIn 1.4s var(--m-ease) .25s both; }
@keyframes mChipIn { from { opacity: 0; filter: blur(8px); transform: translateY(10px) scale(.9); } to { opacity: 1; filter: none; transform: none; } }
html.m-on .v3-visual.m-enter .v3-visual-chip { animation: mChipIn .9s var(--m-ease) both; }
html.m-on .v3-visual.m-enter .v3-visual-chip.c1 { animation-delay: 1s; }
html.m-on .v3-visual.m-enter .v3-visual-chip.c2 { animation-delay: 1.15s; }
html.m-on .v3-visual.m-enter .v3-visual-card { animation: mChipIn 1s var(--m-ease) 1.3s both; }

/* ── 6. Halo sous le curseur sur les cartes ── */
html.m-on .m-spot { position: relative; }
html.m-on body.ng-site .m-spot:hover {
  background-image: radial-gradient(420px circle at var(--mx, 50%) var(--my, 50%), var(--m-spot), transparent 45%);
}
html.m-on .m-spot::before {
  content: ''; position: absolute; inset: 0; border-radius: inherit; pointer-events: none; z-index: 2;
  padding: 1px; opacity: 0; transition: opacity .4s ease;
  background: radial-gradient(260px circle at var(--mx, 50%) var(--my, 50%), var(--m-spot-edge), transparent 60%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor; mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
}
html.m-on .m-spot:hover::before { opacity: 1; }
/* .v3-metric utilise déjà ::before (séparateur) : pas de liseré sur la bande */
html.m-on .v3-metrics.m-spot::before { display: none; }

/* Cartes projet : l'image se dévoile (zoom arrière + net) à l'apparition */
html.m-on .v3-project[data-reveal] .v3-project-media img { transform: scale(1.14); filter: blur(6px) saturate(.7); transition: transform 1.6s var(--m-ease), filter 1.2s var(--m-ease); }
html.m-on .v3-project[data-reveal].ng-reveal-in .v3-project-media img { transform: none; filter: none; }
html.m-on .v3-project[data-reveal].ng-reveal-in:hover .v3-project-media img { transform: scale(1.05); }

/* ── 7. Boutons aimantés + reflet ── */
html.m-on .m-mag { translate: var(--mgx, 0) var(--mgy, 0); transition-property: transform, opacity, box-shadow, background, translate; transition-duration: .2s, .2s, .2s, .2s, .5s; transition-timing-function: cubic-bezier(.34,1.56,.64,1), ease, ease, ease, var(--m-ease); }
html.m-on .m-mag.m-mag-live { transition-duration: .2s, .2s, .2s, .2s, .12s; }
html.m-on body.ng-site .ng-btn-primary { position: relative; overflow: hidden; isolation: isolate; }
html.m-on body.ng-site .ng-btn-primary::after {
  content: ''; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background: linear-gradient(110deg, transparent 30%, rgba(255,255,255,.28) 50%, transparent 70%);
  transform: translateX(-120%); transition: transform .8s var(--m-ease);
}
html.light.m-on body.ng-site .ng-btn-primary::after { background: linear-gradient(110deg, transparent 30%, rgba(255,255,255,.22) 50%, transparent 70%); }
html.m-on body.ng-site .ng-btn-primary:hover::after { transform: translateX(120%); }

/* Liens « Voir tout » : trait qui se dessine */
html.m-on .v3-link { position: relative; }
html.m-on .v3-link::after { content: ''; position: absolute; left: 0; right: 22px; bottom: 6px; height: 1px; background: currentColor; transform: scaleX(0); transform-origin: right; transition: transform .5s var(--m-ease); }
html.m-on .v3-link:hover::after { transform: scaleX(1); transform-origin: left; }

/* ── 8. Bandeau défilant de la stack (accueil) ── */
.m-marquee {
  position: relative; margin-top: clamp(40px, 6vw, 72px); overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
}
.m-marquee-track { display: flex; width: max-content; gap: 0; animation: mMarquee var(--m-dur, 60s) linear infinite; }
.m-marquee:hover .m-marquee-track { animation-play-state: paused; }
.m-marquee ul { display: flex; gap: 10px; margin: 0; padding: 4px 5px; list-style: none; }
.m-marquee li {
  display: inline-flex; align-items: center; gap: 9px; padding: 10px 16px; border-radius: 999px; white-space: nowrap;
  background: var(--v3-s1); box-shadow: var(--v3-shadow); font-size: 14px; font-weight: 500; color: var(--ng-t65);
  transition: color .25s, transform .35s var(--m-ease);
}
.m-marquee li i { width: 7px; height: 7px; border-radius: 2px; background: var(--c, var(--v3-blue)); }
.m-marquee li:hover { color: var(--ng-heading); transform: translateY(-2px); }
@keyframes mMarquee { to { transform: translateX(-50%); } }

/* ── 9. Mouvement réduit / animations stoppées : tout s'affiche, rien ne bouge ── */
@media (prefers-reduced-motion: reduce) {
  .m-marquee-track { animation: none; flex-wrap: wrap; width: auto; }
  .m-marquee ul[aria-hidden] { display: none; }
  .m-marquee ul { flex-wrap: wrap; justify-content: center; }
  .m-marquee { -webkit-mask-image: none; mask-image: none; }
  .m-progress, .m-aura { display: none; }
}
body.a11y-stop .m-marquee-track { animation: none; }
body.a11y-stop .m-progress, body.a11y-stop .m-aura { display: none; }
body.a11y-stop .m-split .m-w, body.a11y-stop .m-scrub .m-w { opacity: 1 !important; filter: none !important; transform: none !important; }
body.a11y-stop [data-reveal] { filter: none !important; }
body.a11y-stop .v3-visual { transform: none !important; animation: none !important; }

/* ── 8b. Logos « Ils m'ont fait confiance » en défilement continu ──
   Même mécanique que le bandeau de la stack ; fondu plus large sur les
   côtés pour que les logos semblent apparaître puis s'effacer. Le padding
   laisse respirer les ombres et le soulèvement au survol (overflow:hidden). */
.m-marquee { padding-block: 10px 28px; }
.m-marquee-trust {
  margin-top: 8px; padding-block: 14px 36px;
  -webkit-mask-image: linear-gradient(90deg, transparent 0, rgba(0,0,0,.25) 8%, #000 24%, #000 76%, rgba(0,0,0,.25) 92%, transparent 100%);
  mask-image: linear-gradient(90deg, transparent 0, rgba(0,0,0,.25) 8%, #000 24%, #000 76%, rgba(0,0,0,.25) 92%, transparent 100%);
}
.m-marquee-trust .v3-trust { flex-wrap: nowrap; justify-content: flex-start; gap: 14px; padding-inline: 7px; }
.m-marquee-trust .v3-trust a { flex: none; white-space: nowrap; padding: 14px 22px 14px 14px; border-radius: 18px; }
.m-marquee-trust .v3-trust img { width: 44px; height: 44px; }
.m-marquee:focus-within .m-marquee-track { animation-play-state: paused; }
@media (prefers-reduced-motion: reduce) {
  .m-marquee-trust .v3-trust[aria-hidden] { display: none; }
  .m-marquee-trust .v3-trust { flex-wrap: wrap; justify-content: center; }
  .m-marquee-trust { -webkit-mask-image: none; mask-image: none; }
}
body.a11y-stop .m-marquee-trust .v3-trust[aria-hidden] { display: none; }
body.a11y-stop .m-marquee-trust .m-marquee-track { flex-wrap: wrap; width: auto; justify-content: center; }
body.a11y-stop .m-marquee-trust .v3-trust { flex-wrap: wrap; justify-content: center; }
body.a11y-stop .m-marquee-trust { -webkit-mask-image: none; mask-image: none; }
