/* =========================================================================
   KARIBOOK BETA — SYSTÈME DE MOUVEMENT
   =========================================================================

   POURQUOI UN FICHIER SÉPARÉ

   Tout ce qui bouge sur le site est ici, et nulle part ailleurs. Si une
   animation dérange un jour, il suffit de retirer ce fichier (ou le filtre
   `karibook_beta_enable_motion`) : le site retrouve exactement son
   apparence d'avant, sans qu'aucune règle de mise en page n'ait été
   touchée. Les animations sont un vernis, jamais une dépendance.

   LA RÈGLE DE SÉCURITÉ QUI GOUVERNE TOUT CE FICHIER

   Aucun contenu n'est masqué par la feuille de style seule. Les états de
   départ (opacité 0) sont TOUS conditionnés à `html.kb-motion`, une classe
   posée par JavaScript. Sans JavaScript, avec un JavaScript en erreur, ou
   pour un visiteur qui a demandé moins d'animations, la classe n'existe
   pas : rien n'est masqué, tout s'affiche normalement. C'est le contraire
   du piège classique où une animation ratée laisse une page blanche.

   L'INTENTION

   Karibook, ce sont les Antilles : le mouvement est fluide et sans
   précipitation, pas nerveux. Les apparitions sont longues et douces
   (620 ms), comme une vague qui arrive. Le rebond n'est utilisé qu'aux
   endroits où il confirme une action de l'utilisateur — un cœur ajouté aux
   favoris, une catégorie choisie — jamais pour de la décoration.
   ========================================================================= */

:root {
  /* Courbes. `out` pour tout ce qui arrive à l'écran (décélération
     naturelle), `spring` uniquement pour les confirmations d'action. */
  --kb-ease-out: cubic-bezier(.22, .61, .36, 1);
  --kb-ease-spring: cubic-bezier(.34, 1.3, .64, 1);
  --kb-ease-smooth: cubic-bezier(.4, 0, .2, 1);

  --kb-dur-fast: 160ms;
  --kb-dur-base: 340ms;
  --kb-dur-slow: 620ms;

  --kb-reveal-shift: 16px;
  --kb-stagger: 70ms;
}

/* =========================================================================
   1. APPARITION AU DÉFILEMENT
   =========================================================================
   Le JavaScript marque les éléments avec `data-kb-reveal` puis leur ajoute
   `is-revealed` quand ils entrent dans la fenêtre. La variable `--kb-i`
   porte le rang de l'élément dans son groupe : c'est ce qui produit le
   décalage en cascade d'une grille de fiches, sans écrire une règle par
   position. */

html.kb-motion [data-kb-reveal] {
  opacity: 0;
  transition:
    opacity var(--kb-dur-slow) var(--kb-ease-out),
    transform var(--kb-dur-slow) var(--kb-ease-out);
  transition-delay: calc(var(--kb-i, 0) * var(--kb-stagger));
}

html.kb-motion [data-kb-reveal="up"]    { transform: translate3d(0, var(--kb-reveal-shift), 0); }
html.kb-motion [data-kb-reveal="right"] { transform: translate3d(calc(var(--kb-reveal-shift) * -1.4), 0, 0); }
html.kb-motion [data-kb-reveal="left"]  { transform: translate3d(calc(var(--kb-reveal-shift) * 1.4), 0, 0); }
html.kb-motion [data-kb-reveal="zoom"]  { transform: scale(.965); }
html.kb-motion [data-kb-reveal="fade"]  { transform: none; }

html.kb-motion [data-kb-reveal].is-revealed {
  opacity: 1;
  transform: none;
}

/* Une fois l'apparition jouée, l'élément redevient un élément ordinaire :
   plus de couche de composition retenue par le navigateur, et surtout plus
   de `transform` sur l'ancêtre — un `transform` actif casse `position:
   fixed` chez les descendants (menus, panneaux, cartes). */
html.kb-motion [data-kb-reveal].is-motion-done {
  transition: none;
  transform: none;
  will-change: auto;
}

/* =========================================================================
   2. HERO — ENTRÉE EN SCÈNE
   =========================================================================
   Au-dessus de la ligne de flottaison, on n'attend pas le défilement :
   la séquence se joue au chargement. L'ordre suit la lecture — on annonce
   (surtitre), on affirme (titre), on précise (accroche), on propose
   d'agir (recherche). */

@keyframes kbHeroIn {
  from { opacity: 0; transform: translate3d(0, 22px, 0); }
  to   { opacity: 1; transform: none; }
}

html.kb-motion .kb-hero__eyebrow,
html.kb-motion .kb-hero h1,
html.kb-motion .kb-hero__lead,
html.kb-motion .kb-hero .kb-search {
  opacity: 0;
  animation: kbHeroIn 760ms var(--kb-ease-out) forwards;
}

html.kb-motion .kb-hero__eyebrow  { animation-delay: 80ms; }
html.kb-motion .kb-hero h1        { animation-delay: 200ms; }
html.kb-motion .kb-hero__lead     { animation-delay: 320ms; }
html.kb-motion .kb-hero .kb-search { animation-delay: 440ms; }

/* Respiration du fond vidéo : 28 secondes pour un aller, autant pour le
   retour. À cette lenteur, on ne « voit » pas l'animation — on perçoit
   juste que l'image est vivante. Volontairement très faible amplitude
   pour ne pas donner le mal de mer sur un grand écran. */
@keyframes kbHeroBreathe {
  from { transform: scale(1); }
  to   { transform: scale(1.06); }
}

html.kb-motion .kb-hero__video {
  animation: kbHeroBreathe 28s var(--kb-ease-smooth) infinite alternate;
}

/* =========================================================================
   3. EN-TÊTE
   =========================================================================
   Le liseret de marque n'est plus un trait figé : le dégradé dérive
   lentement d'un bord à l'autre. 14 secondes par cycle — c'est à la limite
   du perceptible, ce qui est exactement le but : un détail qu'on remarque
   à la deuxième visite. */

@keyframes kbLiseretDrift {
  from { background-position: 0% 50%; }
  to   { background-position: 200% 50%; }
}

html.kb-motion .kb-header::after {
  background: linear-gradient(
    90deg,
    var(--kb-turquoise) 0%,
    var(--kb-lagoon) 25%,
    var(--kb-coral) 50%,
    var(--kb-lagoon) 75%,
    var(--kb-turquoise) 100%
  );
  background-size: 200% 100%;
  animation: kbLiseretDrift 14s linear infinite;
}

/* Au défilement, l'en-tête se resserre et se détache de la page. Le
   changement est petit (16 px → 11 px de respiration) mais il donne la
   sensation d'une barre qui « se met en position de travail ». */
.kb-header {
  transition:
    box-shadow var(--kb-dur-base) var(--kb-ease-out),
    background-color var(--kb-dur-base) var(--kb-ease-out);
}

.kb-header__bar {
  transition: padding-block var(--kb-dur-base) var(--kb-ease-out);
}

.kb-header.is-scrolled {
  box-shadow: 0 6px 26px rgba(0, 0, 0, .26);
}

@media (min-width: 900px) {
  .kb-header.is-scrolled .kb-header__bar { padding-block: 11px; }
}

/* Le liseret s'épaissit légèrement une fois la page défilée : la
   séparation doit être plus franche quand du contenu passe dessous. */
.kb-header::after { transition: height var(--kb-dur-base) var(--kb-ease-out); }
.kb-header.is-scrolled::after { height: 4px; }

/* =========================================================================
   4. FICHES PROFESSIONNELLES
   =========================================================================
   Deux traitements distincts, parce que ce sont deux objets différents :
   une photo de couverture supporte un léger zoom (elle est cadrée pour
   remplir), un logo non — il est affiché entier, le zoomer le sortirait de
   son cadre. Le logo réagit donc par la lumière de son fond, pas par
   l'échelle. */

.kb-provider-card {
  transition:
    box-shadow var(--kb-dur-base) var(--kb-ease-out),
    border-color var(--kb-dur-base) var(--kb-ease-out),
    transform var(--kb-dur-base) var(--kb-ease-out);
}

@media (hover: hover) and (min-width: 900px) {
  .kb-provider-card:hover {
    transform: translate3d(0, -5px, 0);
    box-shadow: var(--kb-shadow-card-hover);
  }
}

.kb-provider-card__media img {
  transition: transform 720ms var(--kb-ease-out);
}

@media (hover: hover) {
  .kb-provider-card:hover .kb-provider-card__media--photo img,
  .kb-provider-card__media--photo:hover img {
    transform: scale(1.055);
  }

  /* Le fond du cadre logo s'éclaircit au survol : le repère de marque
     ressort sans que le logo lui-même ne bouge d'un pixel. */
  .kb-provider-card__media--mark {
    transition: filter var(--kb-dur-base) var(--kb-ease-out);
  }
  .kb-provider-card:hover .kb-provider-card__media--mark {
    filter: brightness(1.18) saturate(1.1);
  }
}

/* La flèche des liens « voir plus » avance au survol — un geste de lecture,
   pas une décoration. */
.kb-link-more::after,
.krdv-actualite-readmore::after {
  transition: transform var(--kb-dur-base) var(--kb-ease-out);
}
.kb-link-more:hover::after,
.krdv-actualite-readmore:hover::after {
  transform: translateX(5px);
}

/* =========================================================================
   5. BOUTONS
   =========================================================================
   Deux choses seulement : un retour tactile à l'appui (le bouton
   s'enfonce), et un reflet qui balaie les boutons d'action principale au
   survol. Le reflet est dessiné dans un ::after en `pointer-events: none`
   pour ne jamais intercepter le clic. */

/* La feuille principale déclare `.karibook-beta .kb-btn` : à spécificité
   inférieure, ces règles seraient purement décoratives. On s'aligne donc
   sur la même spécificité, et c'est l'ordre de chargement qui tranche. */
.karibook-beta .kb-btn {
  position: relative;
  overflow: hidden;
  transition:
    background var(--kb-dur-fast) var(--kb-ease-out),
    color var(--kb-dur-fast) var(--kb-ease-out),
    box-shadow var(--kb-dur-base) var(--kb-ease-out),
    transform 140ms var(--kb-ease-out);
}

.karibook-beta .kb-btn:active { transform: scale(.965); }

html.kb-motion .kb-btn--coral::after,
html.kb-motion .kb-btn--primary::after {
  content: "";
  position: absolute;
  inset: 0 auto 0 -60%;
  width: 45%;
  pointer-events: none;
  background: linear-gradient(
    100deg,
    rgba(255, 255, 255, 0) 0%,
    rgba(255, 255, 255, .38) 50%,
    rgba(255, 255, 255, 0) 100%
  );
  transform: skewX(-18deg);
  transition: left 620ms var(--kb-ease-out);
}

@media (hover: hover) {
  html.kb-motion .kb-btn--coral:hover::after,
  html.kb-motion .kb-btn--primary:hover::after { left: 115%; }

  .kb-btn--coral:hover,
  .kb-btn--primary:hover { box-shadow: 0 8px 22px rgba(221, 78, 48, .28); }
}

/* =========================================================================
   6. CATÉGORIES (rail de pastilles)
   ========================================================================= */

.kb-category-chip {
  transition:
    background var(--kb-dur-fast) var(--kb-ease-out),
    color var(--kb-dur-fast) var(--kb-ease-out),
    border-color var(--kb-dur-fast) var(--kb-ease-out),
    box-shadow var(--kb-dur-base) var(--kb-ease-out),
    transform var(--kb-dur-base) var(--kb-ease-spring);
}

@media (hover: hover) {
  .kb-category-chip:hover {
    transform: translate3d(0, -3px, 0);
    box-shadow: var(--kb-shadow-card);
  }
}

.kb-category-chip:active { transform: scale(.96); }

/* =========================================================================
   7. FAVORIS — CONFIRMATION D'ACTION
   =========================================================================
   Le seul endroit du site où un rebond est justifié : l'utilisateur vient
   d'agir, l'animation lui répond. Elle est courte (460 ms) et ne se joue
   qu'au moment de l'ajout, jamais au chargement de la page. */

@keyframes kbHeartPop {
  0%   { transform: scale(1); }
  32%  { transform: scale(.82); }
  62%  { transform: scale(1.24); }
  100% { transform: scale(1); }
}

html.kb-motion .kb-fav-btn.is-animating,
html.kb-motion .kb-provider-card__fav.is-animating {
  animation: kbHeartPop 460ms var(--kb-ease-spring);
}

/* =========================================================================
   8. BARRE DE PROGRESSION DE NAVIGATION
   =========================================================================
   L'annuaire filtre côté serveur : chaque changement de filtre est un
   rechargement de page. Entre le clic et la nouvelle page, le navigateur
   ne montre presque rien, et l'utilisateur croit que son clic n'a pas été
   pris. Ce fil de 3 px comble ce vide.

   Il ne ment pas sur l'avancement : il progresse vite jusqu'à 80 %, puis
   ralentit et attend — parce que personne ne sait combien de temps le
   serveur va prendre. Une barre qui atteindrait 100 % avant l'arrivée de
   la page serait un mensonge visuel. */

.kb-progress {
  position: fixed;
  top: 0; left: 0;
  height: 3px;
  width: 0;
  z-index: 100000;
  background: var(--kb-gradient-brand);
  box-shadow: 0 0 12px rgba(31, 182, 201, .55);
  opacity: 0;
  transition: width 640ms var(--kb-ease-out), opacity 200ms linear;
  pointer-events: none;
}

.kb-progress.is-active { opacity: 1; }

/* =========================================================================
   9. SQUELETTES DE CHARGEMENT
   =========================================================================
   Utilisés là où du contenu arrive après la page (carte de l'annuaire).
   Un bloc gris qui pulse dit « ça arrive » ; un vide dit « c'est cassé ». */

@keyframes kbShimmer {
  from { background-position: -140% 0; }
  to   { background-position: 240% 0; }
}

html.kb-motion .kb-skeleton {
  background: linear-gradient(
    90deg,
    var(--kb-gray-100) 0%,
    var(--kb-gray-50) 45%,
    var(--kb-gray-100) 90%
  );
  background-size: 220% 100%;
  animation: kbShimmer 1.5s linear infinite;
  border-radius: var(--kb-radius-sm);
  color: transparent;
}

/* =========================================================================
   10. PANNEAUX ET ACCORDÉONS
   ========================================================================= */

html.kb-motion .kb-filters-sheet.is-open,
html.kb-motion [data-kb-filters-sheet].is-open {
  animation: none; /* le glissement est déjà géré par la feuille principale */
}

@keyframes kbPanelIn {
  from { opacity: 0; transform: translate3d(0, -8px, 0); }
  to   { opacity: 1; transform: none; }
}

html.kb-motion details[open] > *:not(summary) {
  animation: kbPanelIn 260ms var(--kb-ease-out);
}

/* Le chevron d'un accordéon tourne au lieu de sauter d'un état à l'autre. */
.kb-accordion__chevron,
[data-kb-chevron] { transition: transform var(--kb-dur-base) var(--kb-ease-out); }
details[open] > summary .kb-accordion__chevron,
details[open] > summary [data-kb-chevron] { transform: rotate(180deg); }

/* =========================================================================
   11. NAVIGATION PRINCIPALE
   =========================================================================
   PAS DE SOULIGNEMENT ANIMÉ ICI, ET C'EST DÉLIBÉRÉ.

   Le réflexe serait d'ajouter un trait qui se déplie au survol via
   `.kb-header__nav a::after`. Ce pseudo-élément est déjà pris : il dessine
   le chevron des entrées à sous-menu (feuille principale, « li
   .menu-item-has-children > a::after »), et `::before` porte le marqueur de
   la page courante. Le redéfinir remplacerait le chevron par un trait —
   une régression fonctionnelle payée pour un effet décoratif.

   Le survol est déjà signalé par un changement de fond dans la feuille
   principale ; on se contente de le rendre progressif. */

.kb-header__nav a {
  transition:
    color var(--kb-dur-fast) var(--kb-ease-out),
    background-color var(--kb-dur-fast) var(--kb-ease-out);
}

/* =========================================================================
   12. FOCUS CLAVIER
   =========================================================================
   Le contour de focus ne doit jamais être animé au point de retarder son
   apparition : une personne qui navigue au clavier a besoin de savoir
   IMMÉDIATEMENT où elle se trouve. On anime donc l'anneau extérieur, pas
   la visibilité. */

.karibook-beta :focus-visible {
  outline: 3px solid var(--kb-lagoon);
  outline-offset: 2px;
}

/* =========================================================================
   13. RESPECT DE « MOINS D'ANIMATIONS »
   =========================================================================
   Le JavaScript ne pose déjà pas la classe `kb-motion` dans ce cas, donc
   presque rien de ce fichier ne s'applique. Cette section neutralise en
   plus les animations qui ne dépendent pas de la classe (survols, appuis),
   et sert de filet si la préférence système change en cours de visite. */

@media (prefers-reduced-motion: reduce) {
  html.kb-motion [data-kb-reveal],
  html.kb-motion .kb-hero__eyebrow,
  html.kb-motion .kb-hero h1,
  html.kb-motion .kb-hero__lead,
  html.kb-motion .kb-hero .kb-search {
    opacity: 1 !important;
    transform: none !important;
    animation: none !important;
    transition: none !important;
  }

  html.kb-motion .kb-hero__video,
  html.kb-motion .kb-header::after,
  html.kb-motion .kb-skeleton,
  html.kb-motion details[open] > *:not(summary),
  html.kb-motion .kb-fav-btn.is-animating,
  html.kb-motion .kb-provider-card__fav.is-animating {
    animation: none !important;
  }

  .kb-provider-card:hover,
  .kb-category-chip:hover,
  .kb-btn:active,
  .kb-category-chip:active {
    transform: none !important;
  }

  .kb-provider-card__media img { transition: none !important; }
  .kb-progress { display: none !important; }
}
