/* ==========================================================================
   EXPLORATION VISUELLE — fx.css

   Direction "lumiere de tournage" : fond ambiant genere (canvas), sequence
   d'apparition orchestree, profondeur et reactions au survol. Tout ce qui
   releve de l'exploration vit ICI et dans scripts/fx.js — supprimer ces
   deux fichiers et leurs lignes d'appel ramene exactement le site sobre.

   Garde-fous :
   - prefers-reduced-motion: reduce => AUCUNE animation (les blocs animes
     sont gates par la media query, et fx.js ne cache jamais rien dans ce cas).
   - Petit ecran => pas de canvas (degrade statique), pas d'animations
     infinies, pas de tilt.
   - Les classes fx-* sont posees par fx.js : sans JS, cette feuille ne
     cache rien et ne casse rien.
   - Aucun effet sur brands.html au-dela de transitions calmes : le brief
     impose la sobriete maximale sur cette page.
   ========================================================================== */

/* ==========================================================================
   1. Fond ambiant
   Le canvas est cree par fx.js (accueil + shop, grand ecran uniquement).
   Il vit derriere tout le contenu ; le grain de base.css reste au-dessus.
   ========================================================================== */

.fx-canvas {
  position: fixed;
  inset: 0;
  z-index: -1;
  width: 100%;
  height: 100%;
  display: block;
  pointer-events: none;
}

/* Degrade statique quand le canvas est absent (petit ecran, mouvement
   reduit) : la meme lumiere, figee. Zero cout en batterie. */
html.fx-static.fx-home body {
  background-image:
    radial-gradient(56rem 56rem at 88% -12%, rgba(74, 108, 247, 0.12), transparent 60%),
    radial-gradient(44rem 44rem at -18% 68%, rgba(123, 63, 228, 0.10), transparent 60%),
    radial-gradient(36rem 36rem at 108% 108%, rgba(245, 158, 11, 0.07), transparent 60%);
}

html.fx-static.fx-shop body {
  background-image:
    radial-gradient(50rem 50rem at 85% -10%, rgba(123, 63, 228, 0.14), transparent 60%),
    radial-gradient(44rem 44rem at -15% 55%, rgba(74, 108, 247, 0.10), transparent 60%);
}

/* ==========================================================================
   2. Sequence d'apparition
   fx.js pose .fx-reveal sur les blocs concernes puis .fx-in quand ils
   entrent dans le champ. Le delai (--fx-d) orchestre l'ouverture.

   Tout est gate par prefers-reduced-motion: no-preference : en mouvement
   reduit, rien n'est jamais cache. Deux filets supplementaires :
   - :focus-within revele un bloc des qu'il recoit le clavier ;
   - fx.js revele tout si l'observation n'a pas demarre au bout de 1,2 s.
   ========================================================================== */

@media (prefers-reduced-motion: no-preference) {
  html.fx .fx-reveal {
    opacity: 0;
    transform: translateY(16px);
    transition:
      opacity 0.7s ease var(--fx-d, 0ms),
      transform 0.7s cubic-bezier(0.22, 1, 0.36, 1) var(--fx-d, 0ms);
  }

  html.fx .fx-reveal.fx-in,
  html.fx .fx-reveal:focus-within {
    opacity: 1;
    transform: none;
  }

  /* Brands : la meme entree, mais plus lente et presque sans deplacement.
     La page respire, elle ne surgit pas. */
  html.fx-brands .fx-reveal {
    transform: translateY(8px);
    transition-duration: 1.1s, 1.1s;
  }

  /* Portfolio et Contact restent neutres : fondu discret et court. */
  html.fx-portfolio .fx-reveal,
  html.fx-contact .fx-reveal {
    transform: translateY(8px);
    transition-duration: 0.5s, 0.5s;
  }
}

/* ==========================================================================
   3. Titres — apparition mot a mot (accueil + shop)
   fx.js decoupe le titre en mots ; chacun monte et se nettoie de son flou,
   comme une mise au point. La copie finale est identique au caractere pres.
   ========================================================================== */

@media (prefers-reduced-motion: no-preference) {
  html.fx .fx-w {
    display: inline-block;
    opacity: 0;
    transform: translateY(0.35em);
    filter: blur(8px);
    animation: fx-word 0.9s cubic-bezier(0.22, 1, 0.36, 1) forwards;
    animation-delay: calc(120ms + var(--fx-i, 0) * 60ms);
  }

  @keyframes fx-word {
    to { opacity: 1; transform: translateY(0); filter: blur(0); }
  }
}

/* Filet : fx.js pose fx-w-done sur le titre 2,6 s apres le decoupage.
   Si l'animation n'a pas tourne (navigateur ancien), le titre s'affiche. */
html.fx .fx-w-done .fx-w {
  animation: none;
  opacity: 1;
  transform: none;
  filter: none;
}

/* ==========================================================================
   4. Volets d'ouverture (accueil, une fois par session)
   Deux caches noirs s'ecartent comme un obturateur. La classe est posee
   puis RETIREE par fx.js apres 1,3 s : meme si l'animation ne tourne pas,
   les volets disparaissent.
   ========================================================================== */

@media (prefers-reduced-motion: no-preference) {
  html.fx-cine::before,
  html.fx-cine::after {
    content: "";
    position: fixed;
    left: 0;
    right: 0;
    height: 50.5vh;
    z-index: 3000; /* au-dessus du grain (2000) */
    background: #050506;
    pointer-events: none;
    animation: fx-shutter 0.9s cubic-bezier(0.65, 0, 0.35, 1) 0.15s forwards;
  }

  html.fx-cine::before { top: 0; transform-origin: top; }
  html.fx-cine::after { bottom: 0; transform-origin: bottom; }

  @keyframes fx-shutter {
    from { transform: scaleY(1); }
    to { transform: scaleY(0); }
  }
}

/* ==========================================================================
   5. Halo au curseur + tilt (souris fine uniquement)
   fx.js pose .fx-glow et alimente --fx-mx / --fx-my. Le halo prend la
   couleur d'accent de la carte : chaque porte annonce sa section.
   ========================================================================== */

html.fx .fx-glow { position: relative; }

html.fx .fx-glow::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.35s ease;
  background: radial-gradient(
    var(--fx-gr, 15rem) circle at var(--fx-mx, 50%) var(--fx-my, 50%),
    color-mix(in srgb, var(--accent, var(--fg)) 13%, transparent),
    transparent 70%
  );
}

html.fx .fx-glow:hover::after,
html.fx .fx-glow:focus-within::after { opacity: 1; }

/* Halo plus resserre sur les petites lignes de palier. */
html.fx .tiers .fx-glow::after { --fx-gr: 8rem; }

/* Tilt 3D des cartes-portails : la carte s'incline vers le curseur.
   Quelques degres seulement — une reaction, pas un manege. */
@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
  html.fx-home .portal {
    transition: border-color 0.2s ease, transform 0.18s ease-out, background 0.2s ease;
  }

  html.fx-home .portal:hover,
  html.fx-home .portal:focus-within {
    transform:
      perspective(56rem)
      rotateX(var(--fx-rx, 0deg))
      rotateY(var(--fx-ry, 0deg))
      translateY(-3px);
  }
}

/* ==========================================================================
   6. Shop — la section energie
   Halo conique qui tourne autour du pack selectionne, respiration du glow,
   transitions entre paliers et entre tournages, balayage sur les boutons.
   Les animations infinies sont reservees au grand ecran : au telephone,
   elles coutent en batterie plus qu'elles ne rapportent.
   ========================================================================== */

@property --fx-a {
  syntax: "<angle>";
  initial-value: 0deg;
  inherits: false;
}

@media (min-width: 48rem) and (prefers-reduced-motion: no-preference) {
  /* Lisere lumineux qui parcourt le bord du pack selectionne. Le ::before
     de .slide__media est libre (::after est pris par l'icone RAW). */
  .theme-shop .slide[aria-selected="true"]:not(.slide--upcoming) .slide__media::before {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: inherit;
    padding: 1.5px;
    pointer-events: none;
    background: conic-gradient(
      from var(--fx-a),
      transparent 0deg,
      transparent 250deg,
      color-mix(in srgb, var(--accent) 85%, #fff) 305deg,
      #fff 322deg,
      color-mix(in srgb, var(--accent) 85%, #fff) 339deg,
      transparent 360deg
    );
    -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    -webkit-mask-composite: xor;
    mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    mask-composite: exclude;
    animation: fx-ring 5s linear infinite;
  }

  @keyframes fx-ring {
    to { --fx-a: 360deg; }
  }

  /* Le glow du pack selectionne respire lentement. */
  .theme-shop .slide[aria-selected="true"]:not(.slide--upcoming) .slide__media {
    animation: fx-breathe 4.5s ease-in-out infinite;
  }

  @keyframes fx-breathe {
    0%, 100% { box-shadow: 0 20px 60px -24px color-mix(in srgb, var(--accent) 85%, transparent); }
    50% { box-shadow: 0 22px 78px -18px color-mix(in srgb, var(--accent) 100%, transparent); }
  }
}

/* Changer de tournage ou de palier fait entrer le panneau en fondu monte.
   L'animation rejoue a chaque affichage (display: none -> visible), sans
   toucher a la logique de shop.js. Courte : elle accompagne, elle ne
   retarde pas la lecture. */
@media (prefers-reduced-motion: no-preference) {
  .theme-shop .detail { animation: fx-panel 0.5s cubic-bezier(0.22, 1, 0.36, 1); }
  .theme-shop .tier-body { animation: fx-panel 0.4s cubic-bezier(0.22, 1, 0.36, 1); }

  @keyframes fx-panel {
    from { opacity: 0; transform: translateY(12px); }
  }
}

/* Balayage lumineux sur les boutons d'achat, au survol seulement. */
@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
  .theme-shop .btn {
    position: relative;
    overflow: hidden;
  }

  .theme-shop .btn::after {
    content: "";
    position: absolute;
    top: 0;
    bottom: 0;
    left: -45%;
    width: 40%;
    transform: skewX(-20deg);
    background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.35), transparent);
    pointer-events: none;
  }

  .theme-shop .btn:hover::after {
    animation: fx-shine 0.6s ease;
  }

  @keyframes fx-shine {
    from { transform: translateX(0) skewX(-20deg); }
    to { transform: translateX(400%) skewX(-20deg); }
  }
}

/* ==========================================================================
   7. Filets d'accent qui se tracent a l'apparition (Brands + Prestations)
   La fine ligne d'accent des visuels s'etire de gauche a droite quand le
   bloc se revele. Un seul passage, puis plus rien ne bouge — c'est le
   maximum admis sur Brands.
   ========================================================================== */

@media (prefers-reduced-motion: no-preference) {
  html.fx .case__media::after,
  html.fx-presta .offer__media::after {
    transform-origin: left;
    transition: transform 1.1s cubic-bezier(0.22, 1, 0.36, 1) 0.35s;
  }

  html.fx .fx-reveal:not(.fx-in) .case__media::after,
  html.fx-presta .fx-reveal:not(.fx-in) .offer__media::after {
    transform: scaleX(0);
  }
}

/* Brands, survol d'un cas : l'image s'eclaire a peine. Pas de deplacement,
   pas de glow — la page reste immobile. */
@media (hover: hover) and (pointer: fine) {
  .theme-brands .case__media {
    transition: border-color 0.6s ease, filter 0.6s ease;
  }

  .theme-brands .case:hover .case__media {
    border-color: color-mix(in srgb, var(--accent) 30%, var(--border));
    filter: brightness(1.08);
  }
}

/* Prestations, survol d'une offre : la vignette se souleve, le filet ambre
   s'affirme. Ton terrain : franc mais sans lumiere qui tourne. */
@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
  .theme-presta .offer__media {
    transition: transform 0.35s cubic-bezier(0.22, 1, 0.36, 1), border-color 0.3s ease;
  }

  .theme-presta .offer:hover .offer__media {
    transform: translateY(-5px);
    border-color: color-mix(in srgb, var(--accent) 40%, var(--border));
  }
}

/* Halo ambre statique derriere le titre de Prestations : la chaleur de la
   section, sans animation. Meme geometrie que le halo du Shop : il deborde
   a GAUCHE uniquement — un debordement a droite elargirait la page au
   telephone (piege deja documente dans shop.css). */
.theme-presta .presta-hero { position: relative; }

.theme-presta .presta-hero::before {
  content: "";
  position: absolute;
  top: -10rem;
  left: -16rem;
  width: min(40rem, 110vw);
  height: min(40rem, 110vw);
  background: radial-gradient(circle, rgba(245, 158, 11, 0.11) 0%, transparent 62%);
  pointer-events: none;
  z-index: -1;
}
