/* =============================================================================
   Tigre Bois — css/motion.css
   États d'animation : apparitions au défilement, cascades, parallaxe, barres.
   Pilotés par js/motion.js. Aucune couleur ici : uniquement du mouvement.

   ---------------------------------------------------------------------------
   RÈGLE DE SÛRETÉ — le contenu ne disparaît jamais à cause du CSS
   ---------------------------------------------------------------------------
   Aucune règle de cette feuille ne pose `opacity:0` sans être préfixée par
   `html.tb-js`. Cette classe est écrite par `js/motion.js` dès l'évaluation du
   module, et retirée par son garde-fou si aucune initialisation n'a lieu.
   Donc : pas de JS → pas de classe → tout le contenu est visible et lisible.

   Les états animés sont en plus conditionnés à un marqueur posé par le JS :
     • les mots d'un titre ne sont masqués que si le conteneur porte
       [data-cascade-prete], donc seulement si le découpage a réellement eu lieu ;
     • une barre n'est à zéro que sous `html.tb-js`, et sa largeur cible vit dans
       la propriété `--tb-barre` que le JS écrit au moment de l'armement.

   ---------------------------------------------------------------------------
   PROPRIÉTÉS PERSONNALISÉES ÉCRITES PAR LE JS
   ---------------------------------------------------------------------------
     --tb-retard            retard de cascade d'un élément révélé (héritée par
                            ses descendants, ce qui synchronise les barres de
                            points sur la ligne de tableau qui les contient)
     --tb-retard-mot        retard d'un mot dans un titre en cascade
     --tb-barre             largeur cible d'une barre de points, en %
     --tb-parallaxe-marge   surdimensionnement d'une couche de parallaxe, en px

   ---------------------------------------------------------------------------
   RÉGLAGES SURCHARGEABLES PAR LES FEUILLES DE PAGE
   ---------------------------------------------------------------------------
     --tb-reveal-montee     distance verticale d'apparition (défaut 24px)
     --tb-reveal-glisse     distance horizontale des variantes gauche/droite
     --tb-reveal-duree      durée du déplacement (défaut --tb-d3)
     --tb-reveal-fondu      durée du fondu (défaut --tb-d2)
     --tb-barre-duree       durée de remplissage d'une barre (défaut --tb-d3)

   Les valeurs de repli entre parenthèses reprennent `css/tokens.css` : si les
   jetons manquent, le mouvement reste correct.
   ============================================================================= */


/* ═════════════════════════════════════════════════════════════════════════════
   1. Apparitions — [data-reveal]
   ═════════════════════════════════════════════════════════════════════════════
   L'élément monte de quelques dizaines de pixels en s'opacifiant. Le fondu est
   court, le déplacement long et très décéléré : c'est ce décalage qui donne le
   calme des pages produit du Google Store.

   Le déplacement s'exprime par trois propriétés personnalisées composées dans un
   seul `transform`. Les propriétés personnalisées ne s'interpolent pas, mais la
   valeur résolue de `transform`, elle, se transitionne normalement.

   À savoir : `transform` n'a aucun effet sur une boîte `display:inline`.
   Poser [data-reveal] sur un bloc, une grille, une cellule ou un inline-block.
   ───────────────────────────────────────────────────────────────────────────── */

html.tb-js [data-reveal]{
  /* Remise à zéro : un [data-reveal] imbriqué n'hérite pas du retard de son
     parent révélé, alors qu'une barre de points, elle, doit en hériter. */
  --tb-retard: 0ms;

  --tb-mv-x: 0px;
  --tb-mv-y: var(--tb-reveal-montee, 24px);
  --tb-mv-e: 1;

  opacity: 0;
  transform: translate3d(var(--tb-mv-x), var(--tb-mv-y), 0) scale(var(--tb-mv-e));
  will-change: opacity, transform;
  transition:
    opacity   var(--tb-reveal-fondu, var(--tb-d2, 420ms)) var(--tb-ease, cubic-bezier(.2,.7,.2,1))      var(--tb-retard, 0ms),
    transform var(--tb-reveal-duree, var(--tb-d3, 720ms)) var(--tb-ease-sort, cubic-bezier(.16,1,.3,1)) var(--tb-retard, 0ms);
}

/* Variantes de direction. Défaut : « bas » — l'élément monte. */
html.tb-js [data-reveal="haut"]{
  --tb-mv-y: calc(var(--tb-reveal-montee, 24px) * -1);
}
html.tb-js [data-reveal="gauche"]{
  --tb-mv-x: calc(var(--tb-reveal-glisse, 28px) * -1);
  --tb-mv-y: 0px;
}
html.tb-js [data-reveal="droite"]{
  --tb-mv-x: var(--tb-reveal-glisse, 28px);
  --tb-mv-y: 0px;
}
/* « echelle » : très légère mise à l'échelle, jamais un zoom brutal. */
html.tb-js [data-reveal="echelle"]{
  --tb-mv-y: 12px;
  --tb-mv-e: .965;
}

/* État révélé, commun à toutes les variantes. */
html.tb-js [data-reveal].tb-vu{
  opacity: 1;
  --tb-mv-x: 0px;
  --tb-mv-y: 0px;
  --tb-mv-e: 1;
  will-change: auto;
}

/* Un conteneur de cascade n'est jamais masqué lui-même : seuls ses enfants
   directs le sont, chacun recevant son propre [data-reveal] depuis le JS. */
html.tb-js [data-reveal-group]:not([data-reveal]){
  opacity: 1;
  transform: none;
}


/* ═════════════════════════════════════════════════════════════════════════════
   2. Titres en cascade — [data-titre-cascade]
   ═════════════════════════════════════════════════════════════════════════════
   Chaque mot monte de 0.6em avec 45 ms de décalage. Pas de masque en
   `overflow:hidden` : il rognerait les jambages et les accents des capitales.
   ───────────────────────────────────────────────────────────────────────────── */

[data-titre-cascade] .tb-mot{
  display: inline-block;
}

html.tb-js [data-titre-cascade][data-cascade-prete] .tb-mot{
  opacity: 0;
  transform: translate3d(0, .6em, 0);
  will-change: opacity, transform;
  transition:
    opacity   var(--tb-reveal-fondu, var(--tb-d2, 420ms)) var(--tb-ease, cubic-bezier(.2,.7,.2,1))      var(--tb-retard-mot, 0ms),
    transform var(--tb-reveal-duree, var(--tb-d3, 720ms)) var(--tb-ease-sort, cubic-bezier(.16,1,.3,1)) var(--tb-retard-mot, 0ms);
}

html.tb-js [data-titre-cascade][data-cascade-prete].tb-vu .tb-mot{
  opacity: 1;
  transform: none;
  will-change: auto;
}

/* Copie du texte réservée aux lecteurs d'écran, ajoutée par le JS quand le
   conteneur ne peut pas porter d'aria-label utile (ni titre, ni lien, ni rôle). */
.tb-mot-lecture{
  position: absolute !important;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}


/* ═════════════════════════════════════════════════════════════════════════════
   3. Compteurs chiffrés — [data-count-to]
   ═════════════════════════════════════════════════════════════════════════════
   Chiffres tabulaires obligatoires : sans eux la largeur du nombre saute à
   chaque image et toute la ligne tremble pendant le comptage.
   ───────────────────────────────────────────────────────────────────────────── */

[data-count-to]{
  font-variant-numeric: tabular-nums;
  font-feature-settings: 'tnum' 1;
  /* Réserve la place du nombre final : aucune bousculade de mise en page. */
  white-space: nowrap;
}


/* ═════════════════════════════════════════════════════════════════════════════
   4. Barres de points — [data-barre]
   ═════════════════════════════════════════════════════════════════════════════
   Sans JS, la barre affiche directement `--tb-barre` si un composant l'a posée
   en style en ligne ; sinon elle est simplement absente, ce qui est sans
   conséquence : c'est un décor de fond de ligne, jamais une information seule.
   Le retard `--tb-retard` est hérité de la ligne de tableau : la barre se
   remplit exactement dans le tempo de la cascade du groupe.
   ───────────────────────────────────────────────────────────────────────────── */

[data-barre]{
  width: var(--tb-barre, 0%);
}

html.tb-js [data-barre]{
  width: 0;
  transition: width
    var(--tb-barre-duree, var(--tb-d3, 720ms))
    var(--tb-ease-sort, cubic-bezier(.16,1,.3,1))
    var(--tb-retard, 0ms);
}

html.tb-js [data-barre].tb-barre-pleine{
  width: var(--tb-barre, 0%);
}


/* ═════════════════════════════════════════════════════════════════════════════
   5. Parallaxe — .tb-parallaxe > [data-parallax]
   ═════════════════════════════════════════════════════════════════════════════
   Markup attendu :

     <div class="tb-parallaxe">
       <picture data-parallax="0.18"> … </picture>   ← couche mobile, enfant direct
       <div class="tb-parallaxe__contenu"> … </div>  ← ce qui reste immobile
     </div>

   AUCUN BORD VIDE, PAR CONSTRUCTION : js/motion.js calcule l'amplitude maximale
   que la couche parcourra sur toute la traversée de l'écran, l'écrit dans
   `--tb-parallaxe-marge`, et les règles ci-dessous surdimensionnent la couche
   de cette marge en haut ET en bas. Le déplacement appliqué est en outre borné
   à cette même marge. La couche ne peut donc jamais découvrir le fond.

   Sans JS, `--tb-parallaxe-marge` vaut 0 : la couche remplit exactement son
   conteneur, immobile. C'est un état parfaitement valable.
   ───────────────────────────────────────────────────────────────────────────── */

.tb-parallaxe{
  position: relative;
  overflow: hidden;
  isolation: isolate;
}

.tb-parallaxe > [data-parallax]{
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
  object-position: center;
  pointer-events: none;
  z-index: 0;
}

/* <picture> ne se recadre pas lui-même : c'est son <img> qui porte object-fit. */
.tb-parallaxe > [data-parallax] img{
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}

html.tb-js .tb-parallaxe > [data-parallax]{
  top: calc(var(--tb-parallaxe-marge, 0px) * -1);
  height: calc(100% + var(--tb-parallaxe-marge, 0px) * 2);
  will-change: transform;
  backface-visibility: hidden;
}

/* Tout ce qui doit rester net et immobile par-dessus la couche. */
.tb-parallaxe__contenu{
  position: relative;
  z-index: 1;
}


/* ═════════════════════════════════════════════════════════════════════════════
   6. Défilement des ancres
   ═════════════════════════════════════════════════════════════════════════════ */

html{
  /* L'en-tête collant ne doit pas recouvrir la cible d'une ancre. */
  scroll-padding-top: calc(var(--tb-header-h, 68px) + var(--tb-e5, 20px));
}

@media (prefers-reduced-motion: no-preference){
  html{ scroll-behavior: smooth; }
}


/* ═════════════════════════════════════════════════════════════════════════════
   7. Mouvement réduit — tout à l'état final, immédiatement
   ═════════════════════════════════════════════════════════════════════════════
   Les sélecteurs ci-dessous ne dépendent NI de `html.tb-js`, NI de `.tb-vu`,
   NI de [data-cascade-prete] : ils couvrent donc aussi les éléments que
   l'observateur n'a jamais vus, ceux injectés après coup et ceux dont le JS
   n'a pas eu le temps de s'occuper.
   ───────────────────────────────────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce){

  html [data-reveal],
  html [data-reveal].tb-vu,
  html [data-titre-cascade] .tb-mot{
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
    animation: none !important;
    will-change: auto !important;
  }

  html [data-barre],
  html [data-barre].tb-barre-pleine{
    width: var(--tb-barre, 0%) !important;
    transition: none !important;
  }

  html [data-parallax]{
    transform: none !important;
    transition: none !important;
  }
  html.tb-js .tb-parallaxe > [data-parallax]{
    top: 0 !important;
    height: 100% !important;
    will-change: auto !important;
  }

  html{ scroll-behavior: auto !important; }
}


/* ═════════════════════════════════════════════════════════════════════════════
   8. Impression — rien de masqué sur le papier
   ═════════════════════════════════════════════════════════════════════════════ */

@media print{

  html [data-reveal],
  html [data-titre-cascade] .tb-mot{
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
    animation: none !important;
  }

  html [data-barre]{
    width: var(--tb-barre, 0%) !important;
    transition: none !important;
  }

  html [data-parallax]{ transform: none !important; }
  html.tb-js .tb-parallaxe > [data-parallax]{ top: 0 !important; height: 100% !important; }
}
