/* ==========================================================================
   LA VALLÉE DYR — Curseur husky
   Remplace le curseur système par une mascotte animée (SVG vectoriel).

   Activé uniquement par `js/cursor.js`, et seulement sur les appareils à
   pointeur fin (souris / trackpad) : la classe `.husky-cursor` est posée sur
   <html>. Sans JS, ou sur mobile, le curseur natif reste en place.

   SOMMAIRE
   01. Masquage du curseur natif
   02. Conteneur & point d'accroche
   03. États (marche / assis / clic)
   04. Animations des poses
   05. Empreintes de pattes
   06. Mouvement réduit
   ========================================================================== */


/* ==========================================================================
   01. MASQUAGE DU CURSEUR NATIF
   ========================================================================== */
html.husky-cursor,
html.husky-cursor * { cursor: none; }

/* Champs de saisie : on rend le curseur natif, sinon on perd le repère du
   point d'insertion. Le husky s'efface au-dessus (état « text »). */
html.husky-cursor input:not([type="button"]):not([type="submit"]):not([type="reset"]):not([type="checkbox"]):not([type="radio"]),
html.husky-cursor textarea { cursor: text; }

html.husky-cursor dialog,
html.husky-cursor dialog * { cursor: auto; }
html.husky-cursor dialog a,
html.husky-cursor dialog button { cursor: pointer; }
body.modal-open .husky,
body.modal-open .husky-paw { visibility: hidden; }


/* ==========================================================================
   02. CONTENEUR & POINT D'ACCROCHE
   ========================================================================== */
.husky {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 2147483000;   /* au-dessus de tout, header et menu compris */
  width: 72px;
  height: 72px;
  pointer-events: none;  /* ne doit jamais intercepter un clic */
  opacity: 0;
  transition: opacity 180ms ease;
  will-change: transform;
}
.husky.is-visible { opacity: 1; }

/* Décalage du dessin pour que le point actif (celui qui suit réellement la
   souris) tombe au centre du cadre de 72×72 px, donc au milieu visuel de la
   mascotte plutôt que sur un de ses bords : on sait ainsi précisément où
   l'on clique. */
.husky__hot {
  position: absolute;
  inset: 0;
  transform: translate(-36px, -36px);
}

/* Retournement horizontal : le husky marche face à sa direction.
   L'origine est le centre de la tête (62,46 dans un viewBox de 130), soit
   47.7% / 35.4% de la boîte — ainsi la tête ne bouge pas au retournement. */
.husky__flip {
  position: absolute;
  inset: 0;
  transform-origin: 47.7% 35.4%;
  transition: transform 200ms cubic-bezier(.22, .61, .36, 1);
  /* Détache la mascotte des photos chargées (hero, galerie) sans l'alourdir. */
  filter: drop-shadow(0 2px 3px rgba(0, 0, 0, .28));
}
/* Uniquement en marche : assis ou en clic (donc sur un CTA), la mascotte
   garde toujours la même orientation — la queue reste du même côté quel
   que soit le sens d'où l'on est venu. */
.husky.is-left[data-state="walk"] .husky__flip { transform: scaleX(-1); }


/* ==========================================================================
   03. ÉTATS
   ========================================================================== */
.husky__pose {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;     /* la queue et le museau débordent du viewBox */
  opacity: 0;
  transform: scale(.86);
  transition: opacity 160ms ease, transform 220ms cubic-bezier(.34, 1.56, .64, 1);
}
.husky__pose.is-on {
  opacity: 1;
  transform: scale(1);
}

/* Le clic « pope » un peu plus fort que les autres poses. */
.husky[data-state="click"] .husky__pose.is-on { transform: scale(1.08); }

/* Au-dessus d'un champ de saisie, la mascotte s'efface entièrement. */
.husky[data-state="text"] { opacity: 0; }


/* ==========================================================================
   04. ANIMATIONS DES POSES
   Les pièces animées utilisent `transform-box: fill-box` : l'origine de
   rotation se lit alors en pourcentage de la boîte englobante de la pièce
   elle-même. Chaque pivot est donc calé sur un bord ou un coin de cette boîte
   (haut-centre pour une patte, bas-gauche pour l'épaule, etc.), ce qui reste
   juste quel que soit le viewBox de la pose.
   ========================================================================== */
.hk-anim { transform-box: fill-box; }

/* --- Marche : pattes alternées, corps qui rebondit, queue qui bat --- */
.husky[data-state="walk"] .hk-legFrontA { animation: hk-step 480ms linear infinite; }
.husky[data-state="walk"] .hk-legFrontB { animation: hk-step 480ms linear infinite; animation-delay: -240ms; }
.husky[data-state="walk"] .hk-legBackA  { animation: hk-step 480ms linear infinite; animation-delay: -240ms; }
.husky[data-state="walk"] .hk-legBackB  { animation: hk-step 480ms linear infinite; }
.husky[data-state="walk"] .hk-walkBody  { animation: hk-bob 480ms ease-in-out infinite; }
.husky[data-state="walk"] .hk-walkTail  { animation: hk-wag 380ms ease-in-out infinite alternate; }

@keyframes hk-step {
  0%   { transform: rotate(15deg); }
  50%  { transform: rotate(-15deg); }
  100% { transform: rotate(15deg); }
}
@keyframes hk-bob {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-2.5px); }
}
@keyframes hk-wag {
  from { transform: rotate(-9deg); }
  to   { transform: rotate(9deg); }
}

/* --- Assis : survol d'un lien/bouton, juste avant un clic éventuel ---
   Respiration lente + queue qui balaie : une pause avant l'action, pas un
   état d'inactivité générale (cf. « walk » qui reste actif à l'arrêt). */
.husky[data-state="sit"] .hk-sitAll  { animation: hk-breathe 2.6s ease-in-out infinite; }
.husky[data-state="sit"] .hk-sitTail { animation: hk-wag 620ms ease-in-out infinite alternate; }
.husky[data-state="sit"] .hk-eyes    { animation: hk-blink 4.2s ease-in-out infinite; }

@keyframes hk-breathe {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.022); }
}
@keyframes hk-blink {
  0%, 92%, 100% { transform: scaleY(1); }
  95%           { transform: scaleY(.12); }
}

/* --- Clic : la langue tressaute --- */
.husky[data-state="click"] .hk-tongue { animation: hk-tongue 420ms ease-out; }
@keyframes hk-tongue {
  0%   { transform: translateY(-4px) scaleY(.7); }
  60%  { transform: translateY(1.5px) scaleY(1.06); }
  100% { transform: translateY(0) scaleY(1); }
}


/* ==========================================================================
   05. EMPREINTES DE PATTES
   Semées derrière le husky pendant la marche. Les éléments sont recyclés
   depuis une réserve fixe (cf. `js/cursor.js`) : aucune création de nœud
   pendant le déplacement de la souris.
   ========================================================================== */
.husky-paw {
  --paw-rot: rotate(0deg);   /* réécrit par le JS à chaque empreinte */
  position: fixed;
  top: 0;
  left: 0;
  z-index: 2147482999;   /* juste sous la mascotte */
  width: 15px;
  height: 15px;
  margin: -7.5px 0 0 -7.5px;
  pointer-events: none;
  opacity: 0;
  color: rgba(46, 31, 18, .28);   /* brun de la charte, très atténué */
}
.husky-paw.is-running { animation: hk-paw 1100ms ease-out forwards; }

@keyframes hk-paw {
  0%   { opacity: 0;   transform: var(--paw-rot) scale(.5); }
  18%  { opacity: .95; transform: var(--paw-rot) scale(1); }
  100% { opacity: 0;   transform: var(--paw-rot) scale(.92); }
}


/* ==========================================================================
   06. MOUVEMENT RÉDUIT
   Le suivi de la souris est piloté par l'utilisateur : on le conserve.
   En revanche toutes les animations « décoratives » (pattes, queue,
   respiration, empreintes) sont coupées.
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  .husky__pose,
  .husky__flip { transition: none; }
  .husky .hk-anim { animation: none !important; }
  .husky-paw { display: none; }
}
