/* ============================================================================
   VOLTYR LABS — vnext V2 · « L'OUVERTURE » (hero épinglé, logo → 3D)

   ⚠️ PIÈGES TENUS (reference-scroll-3d.md § 5) :
   1. AUCUN will-change / transform / filter / .reveal sur .ouv-scroll ni sur le
      hero épinglé lui-même : un bloc conteneur pour le position:fixed du pin
      GSAP = écran blanc pendant tout le pin (payé, aa13a8d). Les enfants du
      hero peuvent en porter (ils bougent AVEC le pin), pas le hero ni au-dessus.
   2. AUCUN mix-blend-mode : la couche 3D porte son alpha dans le shader.
   3. Au repos (p = 0) le hero doit rester PIXEL-IDENTIQUE à la V2 validée :
      tout ce qui est ajouté ici est invisible tant que le JS ne pose pas les
      classes .ouv-live / .ouv-started / .ouv-cta-on.
   ========================================================================== */

.ouv-scroll{position:relative;}

/* Le hero épinglé doit remplir l'écran : sa hauteur naturelle est 1156 px, et
   sur un viewport PLUS HAUT (vu au vrai rendu : 1270 px), la bande CTA et le
   HUD — ancrés à 100svh — sortaient du hero et son overflow:hidden les
   COUPAIT (bouton réduit à un liséré de 3 px). Sans effet sur les écrans
   ≤ 1156 px : zéro régression sur le hero validé. */
.hero.ouv-pin{min-height:100svh;}

/* --- la scène : haute d'un écran, collée au haut du hero ------------------- */
.ouv-canvas{
  position:absolute;top:0;left:0;width:100%;height:100svh;
  display:block;z-index:1;pointer-events:none;
}
/* les éclairs : canvas 2D additif AU-DESSUS de la scène (il porte son alpha,
   aucun mix-blend-mode — piège 1) */
.ouv-arcs{
  position:absolute;top:0;left:0;width:100%;height:100svh;
  display:block;z-index:1;pointer-events:none;
}
/* le contenu du hero passe DEVANT la scène */
.ouv-pin > .container{position:relative;z-index:2;}

/* --- prise de contrôle au scroll (classes posées par le JS) ---------------- */
/* Le texte principal : l'entrée .js-blurline garde la main au chargement ;
   dès que l'acte vit, c'est la progression du scrub qui pilote. */
.hero.ouv-live [data-hero-in]{
  opacity:calc(var(--ouv-txt,1)) !important;
  transform:translateY(calc((1 - var(--ouv-txt,1)) * -26px)) !important;
  filter:none !important;
  transition:none !important;
}
/* Un lien effacé ne doit être NI cliquable NI focalisable : la classe
   .ouv-txt-off suit l'EFFACEMENT lui-même (posée par le JS quand --ouv-txt
   passe sous 0,05) — pas la bande CTA, dont la fenêtre ne recouvre pas celle
   du fondu (il restait ~0,06 écran de liens invisibles mais actifs plein
   centre). visibility retire aussi du tab-order et de l'arbre d'accessibilité. */
.hero.ouv-live.ouv-txt-off [data-hero-in]{visibility:hidden;}

/* le logo 2D validé : il se fond dans son incarnation 3D */
.hero.ouv-live .dragon-stage{opacity:var(--ouv-2d,1);}

/* --- voile de lisibilité du tiers bas (entre avec la bande CTA) ------------ */
.ouv-voile{
  position:absolute;left:0;right:0;top:calc(100svh - 46svh);height:46svh;
  z-index:2;pointer-events:none;opacity:var(--ouv-cta,0);
  background:linear-gradient(180deg,transparent,rgba(8,9,12,.50) 46%,rgba(8,9,12,.88));
}

/* --- bande persistante : tagline + CTA (jamais d'écran muet) --------------- */
.ouv-bande{
  position:absolute;left:50%;top:calc(100svh - 176px);transform:translateX(-50%);
  z-index:3;display:flex;flex-direction:column;align-items:center;gap:16px;
  width:min(92vw,680px);text-align:center;
  opacity:var(--ouv-cta,0);pointer-events:none;
  /* invisible ≠ absent : sans visibility, Tab atteignait un « Réserver un
     appel » invisible dès p=0 et les lecteurs d'écran annonçaient un CTA
     dupliqué. L'opacité pilote le fondu, la visibilité pilote l'existence. */
  visibility:hidden;
}
.hero.ouv-cta-on .ouv-bande{pointer-events:auto;visibility:visible;}
.ouv-bande-tag{
  font-family:var(--font-display);font-weight:700;
  font-size:clamp(20px,2.4vw,27px);letter-spacing:-.02em;color:var(--text);
  text-shadow:0 0 24px rgba(31,143,255,.35);
}

/* --- HUD : indice de scroll puis barre de progression ---------------------- */
.ouv-hud{
  position:absolute;left:50%;top:calc(100svh - 46px);transform:translateX(-50%);
  z-index:4;display:flex;flex-direction:column;align-items:center;gap:10px;
  pointer-events:none;
}
.ouv-hint{
  font-family:var(--font-body);font-size:12.5px;letter-spacing:.05em;
  color:var(--text-faint);
  background:rgba(8,9,12,.55);border:1px solid var(--line);border-radius:999px;
  padding:6px 14px;backdrop-filter:blur(8px);
  opacity:.9;transition:opacity .4s ease;
}
.hero.ouv-started .ouv-hint{opacity:0;}
.ouv-progress{
  width:min(280px,52vw);height:2px;border-radius:2px;
  background:rgba(255,255,255,.09);overflow:hidden;
  opacity:0;transition:opacity .3s ease;
}
.hero.ouv-started .ouv-progress{opacity:1;}
.ouv-progress i{
  display:block;width:100%;height:100%;transform-origin:0 50%;transform:scaleX(0);
  background:linear-gradient(90deg,var(--electric-bright),var(--electric-deep));
  box-shadow:0 0 12px var(--glow);
}

/* --- calque de fidélité (touche O) : le logo d'origine par-dessus ---------- */
.ouv-calque{
  position:absolute;top:0;left:0;width:100%;height:100svh;z-index:5;
  opacity:0;transition:opacity .3s;pointer-events:none;
  background:url('../logo3d/logo-repli-384.webp') center/min(52vmin,480px) no-repeat;
  mix-blend-mode:normal;   /* explicitement normal : jamais de blend ici */
}
.ouv-pin.montre-silhouette .ouv-calque{opacity:.35;}

/* --- légende clavier — OUTIL DE RÉGLAGE, PAS UN ÉLÉMENT DU SITE -----------
   🔴 CACHÉE PAR DÉFAUT (Julien 02/08 : « il reste les barres de tests sur le
   site, vire les, c'est abusé »). C'est un sélecteur de développement : il
   sert à juger ce que CHAQUE couche ajoute, il n'a rien à faire devant un
   visiteur. On ne le supprime pas — on le met derrière ?debug (la classe
   `debug3d` est posée sur <html> par le module au démarrage). Le défaut
   `display:none` évite tout flash : la barre n'apparaît jamais, même une
   frame, avant que le JS ne tourne. */
.ouv-keys{ display:none; }
html.debug3d .ouv-keys{
  position:absolute;right:16px;top:calc(100svh - 54px);z-index:6;
  display:flex;flex-wrap:wrap;gap:6px 12px;align-items:center;max-width:300px;
  font-family:var(--font-body);font-size:11.5px;letter-spacing:.04em;color:var(--text-faint);
  background:rgba(8,9,12,.72);border:1px solid var(--line);border-radius:999px;
  padding:7px 15px;backdrop-filter:blur(8px);pointer-events:auto;transition:opacity .3s;
}
html.debug3d .ouv-keys kbd{
  font-family:var(--font-body);font-size:11px;color:var(--electric-bright);
  border:1px solid rgba(77,171,255,.28);border-radius:5px;padding:1px 5px;margin-right:4px;
  background:rgba(31,143,255,.10);
}
html.debug3d .ouv-keys.hidden{opacity:0;pointer-events:none;}

/* --- repli : acte coupé ou refusé → hero V2 validé, strictement ------------ */
.hero.ouv-fallback .ouv-canvas,
.hero.ouv-fallback .ouv-arcs,
.hero.ouv-fallback .ouv-voile,
.hero.ouv-fallback .ouv-bande,
.hero.ouv-fallback .ouv-hud,
.hero.ouv-fallback .ouv-keys,
.hero.ouv-fallback .ouv-calque{display:none;}

/* --- petit écran : le MINI-ACTE (GO Julien 30/07) --------------------------
   Pas de pin, pas de chorégraphie : l'emblème 3D VIVANT remplace le 2D au
   même endroit (classe .ouv-mini posée par le JS quand le profil accepte).
   Tout le reste de l'appareillage de l'acte reste masqué. `?logo2d` dans
   l'URL force l'ancien hero 2D pour comparer à l'œil. -------------------- */
@media (max-width:820px){
  .ouv-canvas,.ouv-arcs,.ouv-voile,.ouv-bande,.ouv-hud,.ouv-keys,.ouv-calque{display:none;}
  .hero.ouv-mini .ouv-canvas{display:block;}
  /* LE VOILE DE LISIBILITÉ (lot mobile 03/08). Depuis que le dragon occupe la
     largeur de l'écran au lieu d'un médaillon de 172 px, le titre et la pastille
     de conformité passent DEVANT lui. Les quatre sites de référence tiennent
     tous cette règle : le texte reste à pleine luminance sur un décor sombre —
     trionn écrit à 204-255 sur une 3D à 13/255. Nous sommes 13 fois plus
     chromatiques qu'eux : sans ce voile, un bleu à 78 % de l'écran sous un
     titre blanc devient illisible en plein soleil.
     Dégradé seulement, jamais un aplat : le dragon reste visible au travers. */
  .hero.ouv-mini::after{
    content:"";position:absolute;left:0;right:0;bottom:0;height:62%;
    background:linear-gradient(180deg,transparent 0%,rgba(6,8,12,.42) 38%,rgba(6,8,12,.82) 78%);
    pointer-events:none;z-index:1;   /* entre le canvas (z1) et le contenu (z2) */
  }
}
.hero.ouv-mini .dragon-stage{opacity:var(--ouv-2d,1);}

/* --- accessibilité : rien ne bouge, rien ne se monte ----------------------- */
@media (prefers-reduced-motion:reduce){
  .ouv-canvas,.ouv-arcs,.ouv-voile,.ouv-bande,.ouv-hud,.ouv-keys,.ouv-calque{display:none !important;}
}


/* ============================================================================
   LE FILM DU TÉLÉPHONE
   ----------------------------------------------------------------------------
   Mesuré le 03/08, profil iPhone au processeur bridé ÷4 : les QUATRE PREMIÈRES
   SECONDES d'une visite tournent à 13 images par seconde, avec un pic à
   1 136 ms. Ce n'est pas la scène 3D (elle pèse 3 % du budget d'une image),
   c'est le démarrage : analyse du HTML, trois textures, compilation des
   shaders, assemblage des ~3 700 disques du dragon 2D. Aucune optimisation du
   temps réel ne rattrape un problème de démarrage.

   Trois des quatre sites de référence de Julien font exactement ça, et c'est
   mesuré : alethia ne crée AUCUN contexte WebGL sur téléphone, armory sert
   780 images pré-rendues, dragonfly déforme deux textures dans un quad.

   Ici le téléphone ne calcule plus rien : il rejoue un film tourné depuis notre
   propre scène, à une qualité qu'aucun téléphone ne pourrait produire (budget
   de marche plein, gravure 2048, normales fines, 3 200 particules). Et il ne
   télécharge NI three.js NI les 1,44 Mo de textures du dragon : le film coûte
   moins cher que ce qu'il remplace.
   ==========================================================================*/
.ouv-film{ display:none; }
/* ⚠️ HAUT D'ÉCRAN, PAS HAUT DU HERO. Le hero fait 1 157 px de haut alors que
   l'écran en fait 844 : avec `inset:0` la vidéo était étirée sur toute la
   hauteur du bloc, donc GROSSIE et rognée, et le titre se retrouvait au milieu
   du dragon. Le film a été tourné au format exact de l'écran (390×845 points) :
   on lui donne cette boîte-là, comme au canvas 3D juste au-dessus. */
html.film-mobile .ouv-film{
  display:block;position:absolute;top:0;left:0;width:100%;height:100svh;
  object-fit:cover;z-index:0;pointer-events:none;
}
/* Le dragon 2D en particules disparaît — c'est LUI qui saccadait, et le film le
   remplace. Sa boîte reste dans le flux (visibility, pas display) : sans elle
   le titre remonterait sous la barre de navigation et se poserait sur la tête
   du dragon. Le trou de 312 px est le cadre où le film le montre. */
html.film-mobile .dragon-stage > *{ visibility:hidden; }
html.film-mobile .hero.ouv-mini .ouv-canvas{ display:none; }
/* le voile de lisibilité vaut aussi pour le film */
html.film-mobile .hero::after{
  content:"";position:absolute;left:0;right:0;top:calc(100svh - 46svh);height:46svh;
  background:linear-gradient(180deg,transparent 0%,rgba(6,8,12,.42) 38%,rgba(6,8,12,.82) 78%);
  pointer-events:none;z-index:1;
}
