/* ==========================================================================
   Docteur High Tech — couche de mouvement et de photographie
   --------------------------------------------------------------------------
   Chargée APRÈS style.css. Contient uniquement ce qui bouge et ce qui montre
   des photos : aucune règle de couleur, d'espacement ou de typographie n'est
   redéfinie ici. Supprimer ce fichier (et animations.js) rend le site
   parfaitement statique, sans rien casser.

   Trois garde-fous respectés partout :
   1. Rien n'est masqué par défaut. Les animations d'apparition ne s'activent
      que si `html.anim` est posé par animations.js : si le JavaScript échoue
      ou est coupé, tout le contenu reste visible.
   2. Les éléments concernés sont SOUS la ligne de flottaison, donc jamais vus
      dans leur état masqué : pas de clignotement au chargement.
   3. style.css neutralise déjà animations et transitions quand le visiteur
      demande « mouvement réduit » (prefers-reduced-motion). On complète ici
      pour les cas qui laisseraient un élément décalé ou illisible.
   ========================================================================== */

:root {
  --mv-entree: cubic-bezier(0.22, 0.7, 0.24, 1);
  --mv-duree: 620ms;
  --mv-courte: 260ms;
}

/* ==========================================================================
   1. APPARITION À L'ENTRÉE DE LA PAGE (au-dessus de la ligne de flottaison)
   Pures animations CSS : elles démarrent seules, sans attendre le JavaScript.
   ========================================================================== */

@keyframes mvMonte {
  from {
    opacity: 0;
    transform: translateY(18px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

@keyframes mvGlisse {
  from {
    opacity: 0;
    transform: translateX(26px) rotate(1.2deg);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

@keyframes mvTrace {
  from {
    stroke-dashoffset: 1400;
  }
  to {
    stroke-dashoffset: 0;
  }
}

@keyframes mvSceau {
  0% {
    opacity: 0;
    transform: scale(1.35) rotate(-8deg);
  }
  62% {
    opacity: 1;
    transform: scale(0.97) rotate(-2deg);
  }
  100% {
    opacity: 1;
    transform: none;
  }
}

/* Le hero : chaque bloc entre l'un après l'autre. */
.hero h1,
.hero .lead,
.hero .btn-row,
.hero .hero__facts {
  animation: mvMonte 700ms var(--mv-entree) both;
}

.hero .lead {
  animation-delay: 90ms;
}

.hero .btn-row {
  animation-delay: 170ms;
}

.hero .hero__facts {
  animation-delay: 240ms;
}

.hero .eyebrow {
  animation: mvMonte 520ms var(--mv-entree) both;
}

/* Le bordereau arrive en glissant, comme une feuille posée sur le comptoir. */
.hero .ordo {
  animation: mvGlisse 820ms var(--mv-entree) 120ms both;
}

/* Le tracé d'électrocardiogramme se dessine, puis bat lentement. */
.trace path {
  stroke-dasharray: 1400;
  stroke-dashoffset: 1400;
  animation: mvTrace 2.1s var(--mv-entree) 380ms forwards, mvBattement 4.5s ease-in-out 2.5s infinite;
}

@keyframes mvBattement {
  0%,
  100% {
    opacity: 0.55;
  }
  50% {
    opacity: 1;
  }
}

/* La pastille du sceau se pose comme un tampon. */
.hero .ordo__no,
.hero .box--done {
  animation: mvSceau 560ms var(--mv-entree) 760ms both;
}

/* ==========================================================================
   2. APPARITION AU DÉFILEMENT (sous la ligne de flottaison)
   Ne s'active que si html.anim existe — jamais de contenu perdu sans JS.
   ========================================================================== */

html.anim .reveal {
  opacity: 0;
  transform: translateY(16px);
  transition:
    opacity var(--mv-duree) var(--mv-entree),
    transform var(--mv-duree) var(--mv-entree);
  transition-delay: var(--mv-retard, 0ms);
  will-change: opacity, transform;
}

html.anim .reveal.is-visible {
  opacity: 1;
  transform: none;
  will-change: auto;
}

/* Une fois l'entrée jouée, on rend la main : plus de couche de composition. */
html.anim .reveal.is-visible:not(:hover) {
  will-change: auto;
}

/* Décalage en cascade des grilles : chaque enfant part un peu après le précédent. */
html.anim .grid .reveal:nth-child(2) {
  --mv-retard: 90ms;
}

html.anim .grid .reveal:nth-child(3) {
  --mv-retard: 180ms;
}

html.anim .grid .reveal:nth-child(4) {
  --mv-retard: 270ms;
}

html.anim .grid .reveal:nth-child(5) {
  --mv-retard: 360ms;
}

html.anim .grid .reveal:nth-child(6) {
  --mv-retard: 450ms;
}

/* ==========================================================================
   3. PHOTOGRAPHIES
   ========================================================================== */

.photo {
  margin: 0;
  position: relative;
  overflow: hidden;
  background: var(--petrol);
  border-radius: 4px;
}

.photo__img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Léger excès de netteté : les photos de matériel gagnent en présence. */
  transition: transform var(--mv-duree) var(--mv-entree);
}

/* Cadre des cartes d'appareils : hauteur constante, donc grilles alignées. */
.photo--carte {
  aspect-ratio: 4 / 3;
}

/* Bandeau large, pour l'accueil et le haut des pages de service. */
.photo--bandeau {
  aspect-ratio: 21 / 9;
  max-height: 420px;
}

.photo--carre {
  aspect-ratio: 1 / 1;
}

.photo--portrait {
  aspect-ratio: 4 / 5;
}

/* Survol : très léger agrandissement, et un voile bleu qui s'efface. */
.photo:hover .photo__img,
a:hover > .photo .photo__img,
.card--photo:hover .photo__img {
  transform: scale(1.035);
}

.photo::after {
  content: '';
  position: absolute;
  inset: 0;
  /* Dégradé volontairement opaque en bas : le texte blanc des légendes doit
     rester lisible sur n'importe quelle photo (seuil AA). */
  background: linear-gradient(
    180deg,
    rgba(6, 26, 51, 0) 38%,
    rgba(6, 26, 51, 0.55) 72%,
    rgba(6, 26, 51, 0.92) 100%
  );
  opacity: 1;
  transition: opacity var(--mv-courte) ease;
  pointer-events: none;
}

.photo--sans-voile::after {
  content: none;
}

/* Légende toujours lisible : pas de texte tronqué, rien à découvrir au survol. */
.photo__legende {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1;
  padding: 12px 14px;
  color: #fff;
  font-size: 0.82rem;
  line-height: 1.35;
}

.photo__legende b {
  display: block;
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #93c0f5;
  margin-bottom: 3px;
}

/* Mention obligatoire de provenance, en très petit, sous l'image. */
.photo__credit {
  font-size: 0.68rem;
  color: var(--muted);
  margin: 6px 0 0;
}

.photo__credit a {
  color: inherit;
}

/* Le composant de repli : si le fichier photo n'existe pas encore, on affiche
   une illustration vectorielle du même gabarit. Aucune case vide, jamais. */
.photo__repli {
  display: block;
  width: 100%;
  height: 100%;
  background: linear-gradient(150deg, var(--petrol) 0%, var(--petrol-2) 100%);
}

.photo__repli svg {
  display: block;
  width: 100%;
  height: 100%;
}

/* Carte « appareil » de l'accueil : photo + texte qui suit. */
.card--photo {
  display: flex;
  flex-direction: column;
  padding: 0;
  overflow: hidden;
}

.card--photo .photo {
  border-radius: 0;
}

.card--photo__corps {
  padding: 16px 18px 18px;
}

.card--photo h3 {
  margin: 10px 0 6px;
}

/* ==========================================================================
   4. GALERIE DE L'ATELIER
   ========================================================================== */

.galerie {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: 14px;
}

.galerie > * {
  grid-column: span 3;
}

/* Variante : une grande image sur deux colonnes de tuiles. */
.galerie > .galerie__large {
  grid-column: span 6;
}

@media (max-width: 880px) {
  .galerie > *,
  .galerie > .galerie__large {
    grid-column: span 6;
  }
}

@media (max-width: 620px) {
  .galerie {
    gap: 10px;
  }

  .galerie > *,
  .galerie > .galerie__large {
    grid-column: span 12;
  }
}

/* ==========================================================================
   5. LE TRAJET DU COLIS — animation signature de la réparation par envoi
   Un colis part de chez le client, passe à l'atelier, revient réparé.
   ========================================================================== */

.journey {
  margin: 22px 0 6px;
  padding: 18px 16px 12px;
  border: 1px solid var(--line);
  border-radius: 4px;
  background: var(--paper, #fff);
}

.journey__piste {
  position: relative;
  height: 92px;
}

.journey__piste svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
}

.journey__ligne {
  fill: none;
  stroke: var(--line-strong);
  stroke-width: 2;
  stroke-dasharray: 6 7;
}

/* Le colis suit la piste en pourcentages : il s'adapte à toutes les largeurs
   d'écran, sans offset-path (support inégal selon les navigateurs). Les points
   de passage correspondent exactement au tracé du svg ci-dessus. */
.journey__colis {
  position: absolute;
  width: 26px;
  height: 22px;
  margin: -11px 0 0 -13px;
  color: var(--signal);
  animation: mvTrajet 9s cubic-bezier(0.45, 0, 0.55, 1) infinite;
}

@keyframes mvTrajet {
  0% {
    left: 4%;
    top: 65%;
    opacity: 0;
  }
  4% {
    opacity: 1;
  }
  46% {
    left: 50%;
    top: 65%;
  }
  54% {
    left: 50%;
    top: 33%;
  }
  96% {
    left: 96%;
    top: 33%;
    opacity: 1;
  }
  100% {
    left: 96%;
    top: 33%;
    opacity: 0;
  }
}

.journey__jalons {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
  margin-top: 8px;
  text-align: center;
}

.journey__jalon {
  font-size: 0.78rem;
  color: var(--muted);
}

.journey__jalon b {
  display: block;
  color: var(--text);
  font-size: 0.84rem;
}

.journey__jalon--actif {
  color: var(--signal);
}

/* Survol : le colis s'arrête, le temps de lire les trois étapes. */
.journey--pause .journey__colis {
  animation-play-state: paused;
}

/* ==========================================================================
   6. LA LIGNE DES QUATRE ÉTAPES SE REMPLIT AU DÉFILEMENT
   ========================================================================== */

.steps {
  position: relative;
}

.steps__barre {
  position: absolute;
  left: 0;
  right: 0;
  /* Posée exactement sur les filets supérieurs des étapes : la progression
     recouvre les filets gris au fur et à mesure, au lieu de faire doublon. */
  top: 0;
  height: 2px;
  background: var(--line);
  overflow: hidden;
  z-index: 2;
}

.steps__barre i {
  display: block;
  height: 100%;
  width: 100%;
  background: var(--signal);
  transform: scaleX(var(--mv-progres, 0));
  transform-origin: left center;
  transition: transform 180ms linear;
}

.steps .step {
  position: relative;
  z-index: 1;
  background: inherit;
}

/* Les numéros passent au-dessus de la barre : leur fond masque le trait. */
.steps .step__n {
  z-index: 3;
}

@media (max-width: 880px) {
  .steps__barre {
    display: none;
  }
}

/* ==========================================================================
   7. MICRO-MOUVEMENTS D'INTERFACE
   ========================================================================== */

/* Les pastilles d'état « en atelier » respirent, pour signaler une action. */
.pill--action::before,
.pill--work::before {
  animation: mvPouls 2.6s ease-in-out infinite;
}

@keyframes mvPouls {
  0%,
  100% {
    opacity: 1;
    transform: scale(1);
  }
  50% {
    opacity: 0.45;
    transform: scale(1.35);
  }
}

/* Le bouton principal laisse passer un reflet au survol. */
.btn--primary {
  position: relative;
  overflow: hidden;
}

.btn--primary::after {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  width: 38%;
  left: -45%;
  background: linear-gradient(100deg, transparent, rgba(255, 255, 255, 0.32), transparent);
  transform: skewX(-18deg);
  pointer-events: none;
}

.btn--primary:hover::after,
.btn--primary:focus-visible::after {
  animation: mvReflet 700ms ease-out;
}

@keyframes mvReflet {
  to {
    left: 115%;
  }
}

/* La flèche des liens s'avance légèrement. */
.card__foot svg,
a:hover .lien__fleche {
  transition: transform var(--mv-courte) var(--mv-entree);
}

a:hover .card__foot svg {
  transform: translateX(4px);
}

/* L'en-tête se détache du contenu dès qu'on défile. */
.site-header {
  transition:
    box-shadow var(--mv-courte) ease,
    background-color var(--mv-courte) ease;
}

html.anim .site-header.is-scrolled {
  box-shadow: 0 6px 22px rgba(6, 26, 51, 0.18);
}

/* ==========================================================================
   8. FINITIONS
   ========================================================================== */

/* ── La fiche d'admission se remplit, en boucle ─────────────────────────────
   Une seule durée pour toutes les pièces (12 s) : c'est ce qui les garde
   synchronisées, donc ce qui donne l'impression d'une fiche qu'on renseigne
   plutôt que d'éléments qui clignotent chacun dans leur coin. Le cycle finit par
   un effacement court, puis reprend. */
@keyframes mvLigne {
  0%,
  2% {
    opacity: 0;
    transform: translateY(7px);
  }
  6%,
  92% {
    opacity: 1;
    transform: none;
  }
  97%,
  100% {
    opacity: 0;
    transform: translateY(7px);
  }
}

/* Chaque ligne reprend le même dessin, décalé : 3 % du cycle par ligne. */
.hero .ordo__row {
  animation: mvLigne 12s ease-in-out infinite;
}

.hero .ordo__row:nth-child(2) {
  animation-delay: 0.36s;
}

.hero .ordo__row:nth-child(3) {
  animation-delay: 0.72s;
}

.hero .ordo__row:nth-child(4) {
  animation-delay: 1.08s;
}

/* Les deux cases se cochent après le remplissage des lignes. */
@keyframes mvCocher {
  0%,
  34% {
    opacity: 0;
    transform: scale(0.6);
  }
  39%,
  93% {
    opacity: 1;
    transform: scale(1);
  }
  97%,
  100% {
    opacity: 0;
    transform: scale(0.6);
  }
}

.hero .ordo__check {
  animation: mvCocher 12s ease-out infinite;
}

/* La seconde case suit la première de peu. */
.hero .ordo__check + .ordo__check {
  animation-delay: 0.6s;
}

/* Le code-barres se dessine en dernier : la fiche est complète. */
@keyframes mvImprimer {
  0%,
  46% {
    opacity: 0;
    clip-path: inset(0 100% 0 0);
  }
  54%,
  93% {
    opacity: 1;
    clip-path: inset(0 0 0 0);
  }
  97%,
  100% {
    opacity: 0;
    clip-path: inset(0 100% 0 0);
  }
}

.hero .ordo__barcode {
  animation: mvImprimer 12s ease-out infinite;
}

/* La liste des engagements suit le même rythme. */
.hero__facts li {
  animation: mvMonte 460ms var(--mv-entree) both;
}

.hero__facts li:nth-child(1) {
  animation-delay: 300ms;
}

.hero__facts li:nth-child(2) {
  animation-delay: 360ms;
}

.hero__facts li:nth-child(3) {
  animation-delay: 420ms;
}

.hero__facts li:nth-child(4) {
  animation-delay: 480ms;
}

/* Les illustrations respirant doucement : la trace de mesure bat comme sur un
   appareil en cours d'examen. C'est ce qui remplace une photo sans en avoir
   l'air figé. */
@keyframes mvMonitor {
  0%,
  100% {
    opacity: 0.5;
  }
  50% {
    opacity: 1;
  }
}

.photo__repli path[stroke='#1E73BE'] {
  animation: mvMonitor 3.6s ease-in-out infinite;
}

.photo__repli path[stroke='#1E73BE']:nth-of-type(2) {
  animation-delay: 900ms;
}

/* Un balayage lumineux parcourt la trace de monitoring toutes les cinq
   secondes, la seconde fois que la page se charge. La courbe se dessine une
   fois, puis le balayage rappelle qu'un appareil est sous surveillance — sans
   jamais attirer l'œil sur ce détail. */
@keyframes mvBalayage {
  from {
    stroke-dashoffset: 2460;
  }
  to {
    stroke-dashoffset: -46;
  }
}

.trace .trace__balayage {
  stroke: #d6e7fd;
  stroke-width: 2.6;
  stroke-dasharray: 46 2400;
  stroke-dashoffset: 2460;
  opacity: 0.85;
  animation: mvBalayage 5.6s linear 3.8s infinite;
}

/* Les cartes se soulèvent légèrement au survol : trois pixels suffisent à
   donner du relief sans faire sauter la grille. */
.card--link,
.card--photo,
.card--ink {
  transition:
    transform var(--mv-courte) var(--mv-entree),
    box-shadow var(--mv-courte) ease;
}

.card--link:hover,
.card--photo:hover {
  transform: translateY(-3px);
  box-shadow: 0 10px 26px rgba(6, 26, 51, 0.1);
}

/* ==========================================================================
   8 bis. LE TITRE DE L'ACCUEIL — LE DERNIER MOT DÉFILE (carte t_1c0dd404)
   Le titre dit « Votre appareil entre en consultation. » : le dernier mot
   tourne parmi quatre. Même technique que la fiche d'admission ci-dessus —
   UNE SEULE durée partagée par les quatre mots (16 s) et des décalages
   calculés. Quatre mots, quatre temps égaux de 4 s : les décalages sont donc
   des multiples exacts du quart du cycle (0 s, -12 s, -8 s, -4 s), ce qui les
   fait s'enchaîner sans trou et sans que deux mots se superposent.
   ========================================================================== */

/* ── Une seule case pour les quatre mots ───────────────────────────────────
   C'est ce qui rend l'animation invisible à la mise en page : les mots sont
   empilés dans la même case de grille, dimensionnée une fois pour toutes par
   le mot le plus long. Mesuré aux trois largeurs : le plus long est
   « consultation », le mot servi — la mise en page est donc exactement celle
   d'avant l'animation, à l'identique. (Une case qui grandirait avec le mot
   affiché décalerait le titre à chaque changement : « examen » fait les deux
   tiers de « réanimation ».) Le point final voyage DANS chaque mot pour la
   même raison : resté dehors, il se retrouverait planté au large des mots
   courts, à l'autre bout de la case.

   `display: block` l'emporte sur le `display: none` que le navigateur applique
   à l'attribut `hidden` des mots décoratifs : c'est la feuille qui les montre,
   et son absence — ou un moteur sans @keyframes — laisse le titre lisible sur
   « consultation », qui part, lui, de `opacity: 1`. */
@keyframes mvMotTitre {
  /* Un mot est pleinement lisible 3,4 s sur les 4 s de son tour, puis il
     s'efface en 0,3 s tandis que le suivant monte : le fondu est croisé (0,5
     au plus pour le partant, 0,25 pour l'arrivant), si bien que la case n'est
     jamais vide et que deux mots ne sont jamais franchement visibles
     ensemble. Les 0 % et 100 % sont le MILIEU de ce passage : la fin d'un
     tour et le début du suivant s'y raccordent sans à-coup. */
  0% {
    opacity: 0.5;
    transform: translateY(0.14em);
  }
  1.875% {
    opacity: 1;
    transform: none;
  }
  23.125% {
    opacity: 1;
    transform: none;
  }
  25% {
    opacity: 0;
    transform: translateY(-0.28em);
  }
  98.125% {
    opacity: 0;
    transform: translateY(0.28em);
  }
  100% {
    opacity: 0.5;
    transform: translateY(0.14em);
  }
}

.titre-mot {
  /* `inline-grid` garde la case dans le fil du texte : le titre se replie
     comme avant, et la case s'aligne sur la ligne de base du titre.
     `justify-items: start` colle chaque mot au bord gauche de la case : les
     mots sont ainsi à la même place les uns que les autres, quelle que soit
     leur longueur — et quel que soit l'alignement du titre. */
  display: inline-grid;
  justify-items: start;
}

.titre-mot__mot,
.titre-mot__mot[hidden] {
  display: block;
  grid-area: 1 / 1;
  white-space: nowrap;
  /* Déclarations LONGUES, jamais le raccourci `animation` : le raccourci remet
     `animation-delay` à zéro, et ce sélecteur (qui porte l'attribut `hidden`,
     donc plus spécifique) l'emporterait sur le décalage de chaque mot — les
     quatre mots repartiraient ensemble du début du cycle. */
  animation-name: mvMotTitre;
  animation-duration: 16s;
  animation-timing-function: var(--mv-entree);
  animation-iteration-count: infinite;
}

/* Les trois mots décoratifs : invisibles tant que rien n'est joué. */
.titre-mot__mot--decor {
  opacity: 0;
}

/* Le tour de chaque mot dans le cycle — examen → réparation → réanimation →
   consultation, puis on reprend. Un décalage NÉGATIF le place d'emblée dans son
   tour : au chargement, le cycle est déjà à l'image et le titre n'est jamais
   vide. */
.titre-mot__mot--examen {
  animation-delay: 0s;
}

.titre-mot__mot--reparation {
  animation-delay: -12s;
}

.titre-mot__mot--reanimation {
  animation-delay: -8s;
}

.titre-mot__mot--consultation {
  animation-delay: -4s;
}

/* ==========================================================================
   9. MOUVEMENT RÉDUIT ET IMPRESSION
   style.css neutralise déjà durées et itérations ; on remet ici en état les
   éléments qui, sinon, resteraient décalés ou invisibles.
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  html.anim .reveal {
    opacity: 1 !important;
    transform: none !important;
  }

  .hero .ordo,
  .hero h1,
  .hero .lead,
  .hero .btn-row,
  .hero .hero__facts,
  .hero .eyebrow,
  .hero .ordo__no,
  .hero .box--done {
    opacity: 1 !important;
    transform: none !important;
  }

  .trace path {
    stroke-dashoffset: 0 !important;
  }

  .journey__colis {
    opacity: 1 !important;
  }

  .photo__legende {
    transform: none !important;
  }

  .photo:hover .photo__img,
  .card--photo:hover .photo__img {
    transform: none !important;
  }

  .steps__barre i {
    transform: scaleX(1);
  }

  /* Finitions : tout arrive d'un coup, sans déplacement ni pulsation. */
  .hero .ordo__row,
  .hero .ordo__check,
  .hero .ordo__barcode,
  .hero__facts li {
    opacity: 1 !important;
    transform: none !important;
    animation: none !important;
  }

  /* Le titre de l'accueil reste sur le mot de la marque : les trois variantes
     ne sont plus rendues du tout, et « consultation » ne bouge plus. Le titre
     est alors exactement celui du <h1> servi, entièrement lisible. */
  .titre-mot__mot {
    animation: none !important;
    opacity: 1 !important;
    transform: none !important;
  }

  .titre-mot__mot--decor {
    display: none !important;
  }

  .photo__repli path[stroke='#1E73BE'] {
    animation: none !important;
    opacity: 1;
  }

  /* Le balayage de la trace ne doit pas tourner : on ne garde que la courbe. */
  .trace .trace__balayage {
    display: none;
  }

  .card--link:hover,
  .card--photo:hover {
    transform: none !important;
    box-shadow: none !important;
  }
}

@media print {
  html.anim .reveal,
  .hero .ordo,
  .hero h1,
  .hero .lead,
  .hero .btn-row,
  .hero .hero__facts,
  .hero .eyebrow,
  .hero .ordo__no,
  .hero .box--done {
    opacity: 1 !important;
    transform: none !important;
  }

  .journey,
  .trace,
  .photo {
    display: none !important;
  }

  /* Sur une feuille imprimée, le titre ne peut pas tourner : c'est le mot de la
     marque qui part sur le papier, comme dans le <h1> servi. */
  .titre-mot__mot {
    opacity: 1 !important;
    transform: none !important;
  }

  .titre-mot__mot--decor {
    display: none !important;
  }
}
