/* ============================================================
   RÉGLAGES DU MOUVEMENT
   Tous les rythmes sont ici. Pour rendre le site plus calme ou plus
   vif, il suffit de modifier ces quatre valeurs — rien d'autre.
   ============================================================ */
:root {
  --duree-texte:  1.7s;   /* montée des textes */
  --duree-image:  2.6s;   /* resserrement d'une image à son entrée */
  --duree-trait:  1.7s;   /* traits de section qui se déploient */
  --derive-image: 5;      /* amplitude de la dérive au défilement, en % */
}

/* Animations d'apparition au défilement.
   Principe : discrètes. Sur une marque haut de gamme, l'effet doit se
   remarquer sans se voir — on accompagne la lecture, on ne la théâtralise pas.

   Deux garde-fous :
   - tout est conditionné à la classe .js, posée par le script. Sans
     JavaScript, le contenu s'affiche normalement, jamais invisible.
   - prefers-reduced-motion coupe tout : certaines personnes ont des
     vertiges avec les animations, ce n'est pas une préférence esthétique. */

/* Les apparitions ne concernent plus QUE le texte, et brièvement.
   Une image qui se dévoile progressivement donne l'impression d'un
   site qui n'en finit pas de charger : elles arrivent donc d'un bloc,
   sans effet. */
.js [data-anim] {
  opacity: 0;
  transition:
    opacity   var(--duree-texte) ease-out,
    transform var(--duree-texte) cubic-bezier(.22,.61,.36,1);
  will-change: opacity, transform;
}

.js [data-anim="montee"]        { transform: translateY(14px); }
.js [data-anim="descente"]      { transform: translateY(-12px); }
.js [data-anim="gauche"]        { transform: translateX(-18px); }
.js [data-anim="droite"]        { transform: translateX(18px); }

.js [data-anim="voile"]         { transform: none; }
/* « cadre » ne masque RIEN : il sert uniquement à savoir qu'un élément
   est entré dans le champ, pour déclencher un mouvement d'image. */
.js [data-anim="cadre"] { opacity: 1; transform: none; transition: none; }


.js [data-anim].vu {
  opacity: 1;
  transform: none;
}


/* ---------- Hero ---------- */
/* Très lent zoom arrière : donne de la profondeur sans distraire. */
/* La mise en page de .hero-fond vit dans site.css : elle ne doit JAMAIS
   dépendre du JavaScript. Ici, uniquement le mouvement. */



.js .hero-contenu > * {
  opacity: 0; transform: translateY(12px);
  transition: opacity 1.7s ease, transform 1.7s cubic-bezier(.22,.61,.36,1);
}
.js .hero.pret .hero-contenu > *          { opacity: 1; transform: none; }
.js .hero.pret .hero-contenu > *:nth-child(2) { transition-delay: .45s; }
.js .hero.pret .hero-contenu > *:nth-child(3) { transition-delay: .9s; }

/* ---------- En-tête ---------- */
.entete { transition: box-shadow .3s ease, background .3s ease; }
.entete.defile { box-shadow: 0 2px 18px rgba(90,74,66,.09); }

/* ---------- Liens de navigation ---------- */
/* Un trait qui se déploie depuis la gauche, dans le sable de la marque. */
.nav a:not(.panier-lien) { position: relative; }
.nav a:not(.panier-lien)::after {
  content: ""; position: absolute; left: 0; bottom: -5px;
  width: 100%; height: 1px; background: var(--sable);
  transform: scaleX(0); transform-origin: left;
  transition: transform .32s cubic-bezier(.22,.61,.36,1);
}
.nav a:not(.panier-lien):hover::after { transform: scaleX(1); }
.nav a:hover { text-decoration: none; }

/* ---------- Cartes ---------- */
.carte { transition: transform .35s cubic-bezier(.22,.61,.36,1), box-shadow .35s ease; }
.carte .carte-image img { transition: transform 1s cubic-bezier(.22,.61,.36,1); }
.carte:hover .carte-image img { transform: scale(1.05); }

/* ---------- Boutons ---------- */
/* Un remplissage qui monte, plutôt qu'un simple changement de couleur. */
.btn { position: relative; overflow: hidden; z-index: 0; }
.btn::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: var(--accent-fonce);
  transform: translateY(101%);
  transition: transform .38s cubic-bezier(.22,.61,.36,1);
}
.btn:hover::before { transform: translateY(0); }
.btn-clair::before { background: var(--texte); }

/* ---------- Galerie produit ---------- */
.galerie-principale img { transition: opacity .35s ease; }
.galerie-principale img.change { opacity: 0; }

/* ---------- Respect des préférences système ---------- */
@media (prefers-reduced-motion: reduce) {
  .js [data-anim],
  .js [data-anim="rideau"],
  .js .hero-contenu > * {
    opacity: 1 !important;
    transform: none !important;
    clip-path: none !important;
    transition: none !important;
  }
  .js .hero-fond { transform: none !important; transition: none !important; }
  .btn::before { display: none; }
  .carte:hover .carte-image img { transform: none; }
}

/* ---------- Titres révélés ligne par ligne (proposition C) ---------- */
.ligne-masque { display: block; overflow: hidden; }
.ligne {
  display: block;
  transform: translateY(105%);
  transition: transform 1.05s cubic-bezier(.19,1,.22,1);
}
.hero.pret .ligne, .vu .ligne, [data-lignes].vu .ligne { transform: translateY(0); }
/* Tant que le découpage n'a pas eu lieu, le titre reste lisible. */
[data-lignes]:not(.lignes-pretes) { opacity: 1; }

/* Le fond en parallaxe ne doit jamais laisser voir de bord. */
[data-parallaxe] { will-change: transform; }

/* Aucune image n'est jamais masquée en attente d'une animation.

   Une exception, et une seule : les vues empilées d'un hero qui en fait
   défiler plusieurs. Là, l'opacité N'EST PAS un effet d'entrée — c'est
   le mécanisme lui-même, et cette règle l'écrasait, laissant les trois
   photographies superposées à pleine opacité.

   La promesse tient quand même : la première vue porte « est-vu » dans
   le HTML servi, pas ajouté par le script. Sans script, elle s'affiche ;
   et les suivantes n'ont aucune image à montrer, puisque c'est le script
   qui les charge. Rien ne peut rester coincé sur un écran vide. */
   DEUXIÈME EXCEPTION, de la même famille : les photographies empilées
   d'une carte qui propose ses coloris. Là encore l'opacité est le
   mécanisme, et « .js img » l'écrasait — les deux teintes se
   superposaient à pleine opacité, celle du dessus l'emportait, et
   cliquer une pastille ne changeait rien. La carte restait en lavande
   quoi qu'on fasse.

   La promesse tient là aussi : la photographie montrée porte « actif »
   dans le HTML servi. Sans script, on en voit une — la bonne. */
.js img:not(.visuel-coloris img), .js picture,
.js .hero:not([data-fondu]) .hero-fond,
.js .pleine-fond, .js .maison-fond {
  opacity: 1 !important;
  clip-path: none !important;
}


/* ============================================================
   MOUVEMENT, JAMAIS APPARITION
   Règle unique : une image est TOUJOURS visible et à sa taille
   normale par défaut. Le mouvement est une animation d'ENTRÉE, pas
   un état de départ. Conséquence : si le repère d'entrée n'arrive
   jamais — script bloqué, onglet en arrière-plan, capture d'écran —
   l'image reste simplement normale. Rien ne peut rester coincé.
   ============================================================ */
@keyframes resserrer {
  from { transform: scale(1.06); }
  to   { transform: scale(1); }
}

.js [data-anim="cadre"].vu .produit-carte img,
.js .produit-carte[data-anim="cadre"].vu img,
.js .collection-carte[data-anim="cadre"].vu img,
.js .vu .produit-carte img {
  /* Pas de fill-mode : hors animation, l'image reprend sa taille
     normale d'elle-même. Un onglet en arrière-plan suspend les
     animations ; sans cette précaution, l'image y resterait figée
     légèrement agrandie. */
  animation: resserrer var(--duree-image) cubic-bezier(.22,.61,.36,1);
}

/* Le survol reprend la main, sans lutter avec l'animation d'entrée.
   Les images à dérive sont pilotées image par image par le script :
   pas de transition dessus, sinon le mouvement traîne. */
.produit-carte img, .collection-carte img {
  transition: transform 1s cubic-bezier(.22,.61,.36,1);
}
.carte-image img, .trio-visuel img, .galerie-item img, .matiere img,
.manifeste-media img, .recit-media img, .duo-media img, .ti-media img {
  transition: none;
}
.produit-carte:hover img,
.collection-carte:hover img,
.carte:hover .carte-image img,
a.trio-carte:hover .trio-visuel img,
.galerie-item:hover img,
.matiere:hover img { animation: none; transform: scale(1.04); }

/* ---------- Traits qui se déploient ---------- */
.js .oeil-trait::after {
  transform: scaleX(0); transform-origin: left;
  transition: transform var(--duree-trait) cubic-bezier(.22,.61,.36,1) .1s;
}
.js .oeil-trait.vu::after, .js .vu .oeil-trait::after { transform: scaleX(1); }

/* ---------- Micro-mouvements ---------- */
.puce, .option-btn {
  transition: transform .25s cubic-bezier(.22,.61,.36,1),
              border-color .25s, background .25s, color .25s;
}
.puce:hover, .option-btn:hover:not(:disabled) { transform: translateY(-2px); }

/* Un trait se trace sous le nom d'un produit au survol de sa carte. */
.produit-carte .nom, .carte-corps h3 a, .trio-titre {
  background-image: linear-gradient(currentColor, currentColor);
  background-size: 0% 1px; background-repeat: no-repeat; background-position: 0 100%;
  transition: background-size .6s cubic-bezier(.22,.61,.36,1);
}
a:hover .nom, .carte-corps h3 a:hover, a.trio-carte:hover .trio-titre { background-size: 100% 1px; }

/* ---------- Bande de matières : on peut la tirer ---------- */
.matieres { cursor: grab; }
.matieres.tire { cursor: grabbing; scroll-behavior: auto; }
.matieres.tire * { pointer-events: none; }

@media (prefers-reduced-motion: reduce) {
  .js [data-anim="cadre"].vu img,
  .js .vu .produit-carte img,
  .js .vu .carte-image img { animation: none; }
  .produit-carte:hover img, .collection-carte:hover img,
  .carte:hover .carte-image img, .galerie-item:hover img,
  .matiere:hover img { transform: none; }
  .js .oeil-trait::after { transform: scaleX(1); }
}

/* Les cadres des images à dérive retiennent le débordement.
   « .matiere-visuel » et non « .matiere » : la figure contient aussi la
   légende, et l'image agrandie venait la recouvrir. */
.trio-visuel, .galerie-item, .manifeste-media, .recit-media,
.duo-media, .ti-media, .matiere-visuel, .media-visuel,
.carte-image { overflow: hidden; }

@media (prefers-reduced-motion: reduce) {
  .trio-visuel img, .galerie-item img, .manifeste-media img, .recit-media img,
  .duo-media img, .ti-media img, .matiere-visuel img, .carte-image img {
    transform: none !important;
  }
}

/* ============================================================
   DÉRIVE DES IMAGES — VERSION NATIVE
   Les navigateurs récents savent lier une animation au défilement,
   sans une ligne de JavaScript : animation-timeline: view().
   C'est plus fluide, ça survit à un script bloqué, et ça fonctionne
   sur téléphone où les événements de défilement sont capricieux
   pendant l'inertie.
   Le script reste en secours pour les navigateurs qui ne savent pas
   encore le faire (Safari notamment).
   ============================================================ */
@keyframes deriver {
  from { transform: scale(1.14) translateY(calc(var(--derive-image) * -1%)); }
  to   { transform: scale(1.14) translateY(calc(var(--derive-image) * 1%)); }
}

@supports (animation-timeline: view()) {
  .trio-visuel img, .galerie-item img, .media-visuel img,
  .recit-media img, .duo-media img, .ti-media img,
  .matiere-visuel img, .carte-image img {
    animation: deriver linear both;
    animation-timeline: view();
    animation-range: entry 0% exit 100%;
  }
  /* Le survol garde la priorité. */
  .carte:hover .carte-image img,
  a.trio-carte:hover .trio-visuel img,
  .galerie-item:hover img,
  .matiere:hover img { animation-play-state: paused; }
/* Une légende sur deux lignes ne doit pas décaler la vignette voisine :
   c'est la grille qui aligne, pas la hauteur du texte. */
.matiere { align-self: start; }
}

@media (prefers-reduced-motion: reduce) {
  @supports (animation-timeline: view()) {
    .trio-visuel img, .galerie-item img, .manifeste-media img,
    .recit-media img, .duo-media img, .ti-media img,
    .matiere img, .carte-image img { animation: none; transform: none; }
  }
}
