/* ============================================================
   Altus Conseil — design-system/altus-motion.css
   ============================================================
   Couche « Motion & Interaction » TRANSVERSALE du design system.
   À charger APRÈS colors_and_type.css et AVANT (ou avec) les CSS
   de section. Couplée à altus-motion.js.

   Philosophie — « Architecture du calme » :
     • fondu doux + translateY discret, jamais de rebond/rotation/zoom ;
     • une seule courbe d'easing posée (easeInOutCubic), easeOutCubic
       pour les entrées (déjà --altus-ease dans colors_and_type.css) ;
     • durées : 0.2s (hover/états), 0.5–0.7s (reveals) ;
     • TOUT dégrade proprement sans JS (le contenu est visible par
       défaut ; l'état caché n'est posé que si JS a marqué la page
       « prête » via html[data-altus-motion-ready]) ;
     • prefers-reduced-motion: reduce → état final immédiat, zéro anim.

   Vocabulaire data-* (voir altus-motion.js pour le comportement) :
     [data-altus-reveal]            — fondu + translateY à l'entrée du viewport
     [data-altus-reveal-stagger]    — cascade des [data-altus-reveal] enfants
        └ data-altus-reveal-step="80"   (ms ; défaut 80)
     [data-altus-reveal-words]      — gros titre révélé mot à mot (wordStagger)
        └ data-altus-reveal-step="45"   (ms/mot ; défaut 45)
     [data-altus-hairline]          — filet qui se trace (scaleX 0→1, hairlineDraw)
     [data-altus-variable-weight]   — graisse 300→500 à l'entrée (variableWeight)
     [data-altus-parallax]          — média : translateY lié au scroll (parallaxSlow)
        └ data-altus-parallax="0.08"    (amplitude ~ part de la hauteur)
     [data-altus-count="9"]         — count-up 0→valeur, format FR
        └ data-altus-count-decimals / -suffix / -prefix
     .altus-carousel[data-altus-carousel]   — carrousel accessible
     .altus-marquee                 — défilement horizontal continu (CSS pur)
     [data-altus-spy] + .altus-spy-link     — sommaire sticky + scroll-spy
     [data-altus-lift]              — micro-lift de carte au survol
     .altus-hairline / .altus-grain / .altus-surface — utilitaires de détail
   ============================================================ */

:root {
  /* easeInOutCubic — courbe unique des interactions/transitions.
     (--altus-ease = easeOutCubic, défini dans colors_and_type.css,
      reste réservé aux ENTRÉES.) */
  --altus-ease-inout:        cubic-bezier(0.645, 0.045, 0.355, 1); /* @kind other */
  --altus-motion-reveal-y:   20px;
  --altus-motion-dur:        0.6s;   /* @kind other */ /* reveals */
  --altus-motion-dur-fast:   0.2s;   /* @kind other */ /* hover / états */
  --altus-motion-stagger:    80ms;   /* @kind other */
  /* Effets de marque — déclenchés au load / à l'entrée du viewport,
     JAMAIS un détournement du scroll natif. Durées 0.5–0.9s, easing de
     marque uniquement. Dérivés de animation.$extensions.altus.effects. */
  --altus-words-dur:         0.5s;   /* @kind other */ /* reveal mot-à-mot */
  --altus-words-step:        45ms;   /* @kind other */ /* délai entre mots */
  --altus-hairline-dur:      0.65s;  /* @kind other */ /* tracé du filet */
  --altus-vweight-dur:       0.9s;   /* @kind other */ /* graisse 300→500 */
  /* Ombre de lift — très douce, basse opacité, posée bas. */
  --altus-lift-shadow:       0 18px 40px -24px rgba(20, 17, 13, 0.55);
  --altus-lift-shadow-light: 0 18px 40px -24px rgba(20, 17, 13, 0.28);
}

/* ============================================================
   1 — REVEAL AU SCROLL
   ------------------------------------------------------------
   État caché posé UNIQUEMENT quand JS a signalé sa présence
   (html[data-altus-motion-ready]). Sans JS → contenu visible.
   ============================================================ */
@media (prefers-reduced-motion: no-preference) {
  html[data-altus-motion-ready] [data-altus-reveal] {
    opacity: 0;
    transform: translateY(var(--altus-motion-reveal-y));
    transition:
      opacity   var(--altus-motion-dur) var(--altus-ease),
      transform var(--altus-motion-dur) var(--altus-ease);
    will-change: opacity, transform;
  }
  html[data-altus-motion-ready] [data-altus-reveal].is-revealed {
    opacity: 1;
    transform: none;
  }
}

/* ============================================================
   2 — COUNT-UP
   ------------------------------------------------------------
   Pas de style imposé hormis les chiffres tabulaires : on hérite
   de la typo de la section. tabular-nums déjà garanti par
   .altus … [data-altus-number] dans colors_and_type.css, on le
   redéclare ici pour l'autonomie du module.
   ============================================================ */
[data-altus-count] {
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
}

/* ============================================================
   3 — CARROUSEL ACCESSIBLE
   ------------------------------------------------------------
   scroll-snap + flèches + points + swipe tactile + clavier.
   Composant réutilisable : témoignages, portefeuilles, contenus
   liés, index blog. Couleurs héritées du contexte (currentColor)
   pour fonctionner sur fond clair ET sombre.
   ============================================================ */
.altus-carousel {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 32px;
}

.altus-carousel-viewport {
  display: flex;
  gap: clamp(20px, 2.2vw, 32px);
  overflow-x: auto;
  scroll-snap-type: x proximity;
  /* proximity (et non mandatory) : laisse les scrolls programmatiques
     animés atteindre leur cible sans re-snap parasite en cours d'anim.
     La fluidité est pilotée par scrollTo({behavior}) dans altus-motion.js. */
  /* masque la scrollbar — la nav se fait aux flèches/points/swipe */
  scrollbar-width: none;
  -ms-overflow-style: none;
  padding-bottom: 4px; /* évite le clipping des ombres de lift */
  margin-inline: -4px;
  padding-inline: 4px;
}
.altus-carousel-viewport::-webkit-scrollbar { display: none; }

.altus-carousel-slide {
  scroll-snap-align: start;
  flex: 0 0 auto;
  /* largeur par défaut — surchargée par la section hôte si besoin */
  inline-size: min(420px, 82%);
}

/* ─── Contrôles : flèches + points ─────────────────────────── */
.altus-carousel-controls {
  display: flex;
  align-items: center;
  gap: 20px;
}

.altus-carousel-arrow {
  appearance: none;
  -webkit-appearance: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: 48px;
  block-size: 48px;
  padding: 0;
  background: transparent;
  color: currentColor;
  border: 1px solid var(--altus-sep);
  border-radius: 999px; /* exception cercle, comme le bouton play media */
  cursor: pointer;
  transition:
    border-color var(--altus-motion-dur-fast) var(--altus-ease-inout),
    background    var(--altus-motion-dur-fast) var(--altus-ease-inout),
    opacity       var(--altus-motion-dur-fast) var(--altus-ease-inout);
}
.altus-carousel-arrow svg {
  inline-size: 22px;
  block-size: 22px;
  stroke: currentColor;
  stroke-width: 1;
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: transform var(--altus-motion-dur-fast) var(--altus-ease-inout);
}
.altus-carousel-arrow:hover { border-color: currentColor; }
.altus-carousel-arrow[data-altus-carousel-prev]:hover svg { transform: translateX(-3px); }
.altus-carousel-arrow[data-altus-carousel-next]:hover svg { transform: translateX(3px); }
.altus-carousel-arrow:focus-visible {
  outline: 1px solid currentColor;
  outline-offset: 3px;
}
.altus-carousel-arrow[disabled] {
  opacity: 0.32;
  cursor: default;
  pointer-events: none;
}

.altus-carousel-dots {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-inline-start: 4px;
}
.altus-carousel-dot {
  appearance: none;
  -webkit-appearance: none;
  inline-size: 8px;
  block-size: 8px;
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: currentColor;
  opacity: 0.28;
  cursor: pointer;
  transition:
    opacity   var(--altus-motion-dur-fast) var(--altus-ease-inout),
    transform var(--altus-motion-dur-fast) var(--altus-ease-inout);
}
.altus-carousel-dot:hover { opacity: 0.55; }
.altus-carousel-dot.is-active { opacity: 1; transform: scale(1.35); }
.altus-carousel-dot:focus-visible { outline: 1px solid currentColor; outline-offset: 3px; }

/* Bronze : UN seul rôle accent par section. Dans le carrousel, c'est le
   point actif qui peut le porter quand la section le décide, via la classe
   .altus-carousel-accent posée sur .altus-carousel. */
.altus-carousel-accent .altus-carousel-dot.is-active { background: var(--altus-accent); }

/* ============================================================
   4 — MARQUEE (logos, presse)
   ------------------------------------------------------------
   CSS pur, sans JS : la piste contient DEUX groupes identiques
   (le second aria-hidden) ; la translation de −50 % boucle sans
   couture. Pause au survol. reduced-motion → grille statique.
   ============================================================ */
.altus-marquee {
  position: relative;
  overflow: hidden;
  /* fondus latéraux pour une entrée/sortie douce des items */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
.altus-marquee-track {
  display: flex;
  inline-size: max-content;
  animation: altus-marquee-scroll var(--altus-marquee-dur, 42s) linear infinite;
}
.altus-marquee:hover .altus-marquee-track,
.altus-marquee:focus-within .altus-marquee-track {
  animation-play-state: paused;
}
.altus-marquee-group {
  display: flex;
  align-items: center;
  flex: 0 0 auto;
}
@keyframes altus-marquee-scroll {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}
/* Sens inverse, optionnel */
.altus-marquee[data-altus-marquee-reverse] .altus-marquee-track {
  animation-direction: reverse;
}
@media (prefers-reduced-motion: reduce) {
  .altus-marquee {
    -webkit-mask-image: none;
            mask-image: none;
    overflow-x: auto;
    scrollbar-width: none;
  }
  .altus-marquee::-webkit-scrollbar { display: none; }
  .altus-marquee-track { animation: none; }
  /* le second groupe dupliqué est superflu sans défilement */
  .altus-marquee-track .altus-marquee-group[aria-hidden="true"] { display: none; }
}

/* ============================================================
   5 — SOMMAIRE STICKY + SCROLL-SPY
   ------------------------------------------------------------
   Utilisé par le gabarit d'article (TOC). Le conteneur porte
   [data-altus-spy] et liste des .altus-spy-link (href="#ancre").
   ============================================================ */
[data-altus-spy] {
  position: sticky;
  top: calc(88px + 24px); /* header fixe ~88px + respiration */
  align-self: start;
}
.altus-spy-link {
  display: block;
  color: var(--altus-fg2);
  text-decoration: none;
  border-left: 1px solid var(--altus-sep);
  padding: 6px 0 6px 16px;
  transition:
    color       var(--altus-motion-dur-fast) var(--altus-ease-inout),
    border-color var(--altus-motion-dur-fast) var(--altus-ease-inout);
}
.altus-spy-link:hover { color: var(--altus-fg1); }
.altus-spy-link.is-active {
  color: var(--altus-fg1);
  border-left-color: var(--altus-accent); /* le seul bronze du sommaire */
}
.altus-section-inverse .altus-spy-link { color: var(--altus-fg2-inverse); }
.altus-section-inverse .altus-spy-link:hover,
.altus-section-inverse .altus-spy-link.is-active { color: var(--altus-fg1-inverse); }

/* ============================================================
   6 — MICRO-INTERACTIONS (0.2s)
   ------------------------------------------------------------
   Lift de carte : translateY −2px + ombre très douce, basse
   opacité, posée bas. Couleur d'ombre adaptée au fond.
   ============================================================ */
@media (prefers-reduced-motion: no-preference) {
  [data-altus-lift] {
    transition:
      transform  var(--altus-motion-dur-fast) var(--altus-ease-inout),
      box-shadow var(--altus-motion-dur-fast) var(--altus-ease-inout),
      border-color var(--altus-motion-dur-fast) var(--altus-ease-inout);
  }
  [data-altus-lift]:hover {
    transform: translateY(-2px);
    box-shadow: var(--altus-lift-shadow);
  }
  .altus-section-inverse [data-altus-lift]:hover {
    box-shadow: var(--altus-lift-shadow-light);
  }
}

/* Souligné de lien « glissant » — utilitaire optionnel pour les liens
   in-prose et les liens de carte. Le trait pousse de gauche à droite. */
.altus-underline {
  text-decoration: none;
  background-image: linear-gradient(currentColor, currentColor);
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 0% 1px;
  transition: background-size var(--altus-motion-dur-fast) var(--altus-ease-inout);
  padding-bottom: 2px;
}
.altus-underline:hover,
.altus-underline:focus-visible { background-size: 100% 1px; }

/* Flèche de lien/CTA qui glisse — réutilise le pattern de cta.css. */
[data-altus-arrow] svg {
  transition: transform var(--altus-motion-dur-fast) var(--altus-ease-inout);
}
[data-altus-arrow]:hover svg,
[data-altus-arrow]:focus-visible svg { transform: translateX(4px); }

/* ============================================================
   7 — WORD STAGGER (gros titres)
   ------------------------------------------------------------
   altus-motion.js découpe le titre en mots (<span class="altus-word">).
   Chaque mot entre en fondu + translateY, échelonné (~45ms/mot).
   Réservé aux GROS titres (hero) — subtil, une seule fois.
   (effet wordStagger : perWordDelay 4f / durée 12f, easeOutCubic)
   ============================================================ */
.altus-word { display: inline-block; will-change: opacity, transform; }
@media (prefers-reduced-motion: no-preference) {
  html[data-altus-motion-ready] [data-altus-reveal-words] .altus-word {
    opacity: 0;
    transform: translateY(var(--altus-motion-reveal-y));
    transition:
      opacity   var(--altus-words-dur) var(--altus-ease),
      transform var(--altus-words-dur) var(--altus-ease);
  }
  html[data-altus-motion-ready] [data-altus-reveal-words].is-revealed .altus-word {
    opacity: 1;
    transform: none;
  }
}

/* ============================================================
   8 — HAIRLINE QUI SE TRACE
   ------------------------------------------------------------
   .altus-hairline = le filet 1px (largeur réglable via
   --altus-hairline-w). [data-altus-hairline] = le TRACÉ à
   l'entrée (scaleX 0→1, origine gauche). Combiner les deux.
   Le filet porte le RÔLE BRONZE unique de la section.
   (effet hairlineDraw : 15f, easeInOutCubic, origin left)
   ============================================================ */
.altus-hairline {
  display: block;
  block-size: 1px;
  inline-size: var(--altus-hairline-w, 100%);
  background: var(--altus-accent);
  border: 0;
}
@media (prefers-reduced-motion: no-preference) {
  html[data-altus-motion-ready] [data-altus-hairline] {
    transform: scaleX(0);
    transform-origin: left center;
    transition: transform var(--altus-hairline-dur) var(--altus-ease-inout);
    will-change: transform;
  }
  html[data-altus-motion-ready] [data-altus-hairline].is-drawn {
    transform: scaleX(1);
  }
}

/* ============================================================
   9 — POIDS VARIABLE (300→500 à l'entrée)
   ------------------------------------------------------------
   Un mot/segment dont la graisse se RÉSOUT de Light vers Medium.
   Nécessite Albert Sans en axe variable (chargée 100..900).
   Sans JS / reduced-motion : Medium 500 d'emblée (état final).
   (effet variableWeight : 300→500 ; on borne l'easing à la marque)
   ============================================================ */
[data-altus-variable-weight] {
  font-weight: var(--altus-w-medium); /* repli = état final */
}
@media (prefers-reduced-motion: no-preference) {
  html[data-altus-motion-ready] [data-altus-variable-weight] {
    font-weight: var(--altus-w-light);
    font-variation-settings: "wght" 300;
    transition:
      font-variation-settings var(--altus-vweight-dur) var(--altus-ease-inout),
      font-weight             var(--altus-vweight-dur) var(--altus-ease-inout);
    will-change: font-variation-settings;
  }
  html[data-altus-motion-ready] [data-altus-variable-weight].is-weighted {
    font-weight: var(--altus-w-medium);
    font-variation-settings: "wght" 500;
  }
}

/* ============================================================
   10 — PARALLAX MÉDIA
   ------------------------------------------------------------
   translateY subtil lié au scroll, piloté par le rAF de
   altus-motion.js (amplitude ~ ±8% de la hauteur du média,
   réglable via data-altus-parallax="0.08"). Le média est
   SUR-CADRÉ dans un .altus-parallax-frame (overflow:hidden)
   pour ne révéler aucun bord pendant le déplacement.
   (effet parallaxSlow : amplitude faible, jamais spectaculaire)
   ============================================================ */
.altus-parallax-frame { position: relative; overflow: hidden; }
@media (prefers-reduced-motion: no-preference) {
  [data-altus-parallax] { will-change: transform; }
}

/* ============================================================
   11 — UTILITAIRES DE DÉTAIL
   ============================================================ */
/* Grain — reprise du feTurbulence du DS (fonds B/C/D). Élément
   overlay : parent en position:relative, déposer
   <div class="altus-grain" aria-hidden="true"></div>. Texture, jamais un plat. */
.altus-grain {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  opacity: 0.22;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='320' height='320'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' seed='5' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.7 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
  background-size: 320px 320px;
}

/* Surface basse densité — tuile qui « accroche la lumière » SANS
   ombre lourde. currentColor → marche sur fond clair ET sombre. */
.altus-surface {
  background: color-mix(in srgb, currentColor 4%, transparent);
  border: 1px solid color-mix(in srgb, currentColor 10%, transparent);
}
